my file src / main / resources / META-INF / persistence.xml is:
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="todo" transaction-type="RESOURCE_LOCAL">
<class>com.testJPA.classes.Voiture</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:mem:todos" />
<property name="javax.persistence.jdbc.user" value="sa" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
<property name="openjpa.RuntimeUnenhancedClasses" value="supported"/>
</properties>
</persistence-unit>
my main class is:
package com.testJPA.classes;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
public class Main {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.print("Hello");
EntityManagerFactory emf = Persistence
.createEntityManagerFactory("todo");
EntityManager em = emf.createEntityManager();
for (int i = 0; i < 10; i++) {
Voiture car = new Voiture("a", "b", "c");
em.persist(car);
}
em.getTransaction().commit();
// Find the number of Point objects in the database:
Query q1 = em.createQuery("SELECT COUNT(v) FROM Voiture v");
System.out.println("Le nombre d'enregistrement: "
+ q1.getSingleResult());
}
}
and my clase "Voiture" is :
package com.testJPA.classes;
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class Voiture {
#Id private String matricule;
String position;
String vitesse;
public Voiture(String matricule, String position, String vitesse) {
this.matricule = matricule;
this.position = position;
this.vitesse = vitesse;
}
public Voiture() {
this.matricule = "";
this.position = "";
this.vitesse = "";
}
public String getMatricule() {
return matricule;
}
public void setMatricule(String matricule) {
this.matricule = matricule;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}
public String getVitesse() {
return vitesse;
}
public void setVitesse(String vitesse) {
this.vitesse = vitesse;
}
}
i have this error : No persistence providers available for "todo" after trying the following discovered implementations
sorry i am begineer in JAva EE
This is a classpath issue. You need to have the META-INF directory in the root of your compiled classes directory.
target / classes /
/ com / testJPA / classes / Main.class
/ META-INF / persistence.xml
After you fix this problem, you need to get rid of the openjpa.RuntimeUnenhancedClasses property. That is an evil property that will cause you no end of headaches. Please read this documentation and this documentation on how to properly enhance your Entities.
If JPA is used standalone , you have to specify <provider> in the persistence.xml according to the JPA implementation that you used
For OpenJPA, it is org.apache.openjpa.persistence.PersistenceProviderImpl :
<persistence-unit name="todo" transaction-type="RESOURCE_LOCAL">
<class>com.testJPA.classes.Voiture</class>
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl/provider>
.......................................................
</persistence-unit>
Related
after upgrading the Java implementation of Camel from 2.13.0 to 2.17.2 (and cxf-rt-frontend-jaxrs from 2.7.10 to 3.1.5, and spring framework from 3.2.8 to 4.3.2), the webapp that is serving as a proxy stopped working correctly.
The app is supposed to intercept a webservice request, modify fields that are defined in a properties file throught the ContextManager class, and forward the request to the correct endpoint.
After the upgrade, the app is unable to set the missing fields in the original request, thus returning the following message: "REQUEST_MESSAGE_NOT_COMPLIANT_WITH_SCHEMA - Your request message does not comply to the web service schema".
This is of course expected since the missing fields are not being set.
Any help would be greatly appreciated.
UPDATE:
The problem seems to be coming from the xpath method which in the previous version returned the correct node where some information needs to be set and now is returning null.
My Camel route definition is as follows:
CreditLimitRequestServiceRoute.class
public class CreditLimitRequestServiceRoute extends AbstractEHRoute {
#Autowired
private ContextManager contextManager;
#Override
public void configure() throws Exception {
Namespaces ns = new Namespaces("ns1", "http://ehsmartlink/commonError");
onException(SoapFault.class)
.to("consoleflux:message?level=ERROR&text=${exception.message}&content=${exception.detail}")
.setHeader("soapFaultDetail", simple("${exception.detail}"))
.choice()
.when(and(header("soapFaultDetail").isNotNull(), xpath("//ns1:commonError/errorType/text() = 'BusinessError'", ns, "soapFaultDetail")))
.to("consoleflux:finish?ignoreContent=true")
.otherwise()
.to("consoleflux:error?ignoreContent=true");
onException(Exception.class)
.to("consoleflux:error");
from("cxf:bean:creditLimitRequestServiceProxy?dataFormat=PAYLOAD").routeId("creditLimitRequestServiceRoute")
.log(LoggingLevel.INFO, "Invocation du WS").streamCaching()
.to("consoleflux:start?source=SOA&dest=EH&type=CREDIT_LIMIT")
.to("consoleflux:message?ignoreContent=true&text=Affectation du Contexte EH")
.setHeader("context").xpath("//context")
.bean(contextManager, "setContext")
.to("consoleflux:message?ignoreContent=true&text=Invocation du WS EH ${headers.operationName}")
.to("cxf:bean:creditLimitRequestService?dataFormat=PAYLOAD")
.to("consoleflux:finish");
}
}
AbstractEHRoute.class
public abstract class AbstractEHRoute extends RouteBuilder {
protected XPathBuilder xpath(String text, Namespaces namespaces, String headerName) {
XPathBuilder xpath = XPathBuilder.xpath(text).namespaces(namespaces);
xpath.setHeaderName(headerName);
return xpath;
}
}
ContextManager
package com.stef.soa.eh.integration.beans;
import static com.google.common.base.Objects.firstNonNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import java.util.Map;
import java.util.UUID;
import org.apache.camel.Header;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
#Component
public class ContextManager {
private static final String USER_NAME = "userName";
private static final String USER_PASSWORD = "userPassword";
private static final String LANGUAGE_TEXT_IDENTIFIER = "languageTextIdentifier";
private static final String TRANSACTION_IDENTIFIER = "transactionIdentifier";
private static final String POLICIY_IDENTIFIER = "policyIdentifier";
private static final String POLICY_EXTENSION_IDENTIFIER = "policyExtensionIdentifier";
private static final String POLICY_EHBU_IDENTIFIER = "policyEHBUIdentifier";
private static final String IP_ADRESS = "ipAdress";
#Value("${eh.context.userName}")
private String userName;
#Value("${eh.context.userPassword}")
private String userPassword;
#Value("${eh.context.languageTextIdentifier}")
private String languageTextIdentifier;
#Value("${eh.context.policyIdentifier}")
private String policyIdentifier;
#Value("${eh.context.policyExtensionIdentifier}")
private String policyExtensionIdentifier;
#Value("${eh.context.policyEHBUIdentifier}")
private String policyEHBUIdentifier;
#Value("${eh.context.ipAdress}")
private String ipAdress;
public void setContext(#Header("context") Node context) {
Preconditions.checkNotNull(context, "Le contexte doit ĂȘtre renseignĂ©");
// Suppression des noeuds enfants avec sauvegarde les valeurs courantes dans une map
Map<String, String> currentValues = Maps.newHashMap();
NodeList list = context.getChildNodes();
for (int i = list.getLength() - 1; i >= 0; i--) {
Node child = list.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE && !isNullOrEmpty(child.getTextContent())) {
currentValues.put(child.getNodeName(), child.getTextContent());
}
context.removeChild(child);
}
// Ajout des noeuds enfants
appendChild(context, USER_NAME, userName, currentValues);
appendChild(context, USER_PASSWORD, userPassword, currentValues);
appendChild(context, LANGUAGE_TEXT_IDENTIFIER, languageTextIdentifier, currentValues);
appendChild(context, TRANSACTION_IDENTIFIER, UUID.randomUUID().toString(), currentValues);
appendChild(context, POLICIY_IDENTIFIER, policyIdentifier, currentValues);
appendChild(context, POLICY_EXTENSION_IDENTIFIER, policyExtensionIdentifier, currentValues);
appendChild(context, POLICY_EHBU_IDENTIFIER, policyEHBUIdentifier, currentValues);
appendChild(context, IP_ADRESS, ipAdress, currentValues);
}
private void appendChild(Node node, String name, String value, Map<String, String> currentValues) {
Document document = node.getOwnerDocument();
Element child = document.createElement(name);
child.setTextContent(firstNonNull(currentValues.get(name), value));
node.appendChild(child);
}
}
context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:eh.properties, file:///${eh.home}/conf/eh.properties"
ignore-resource-not-found="true" system-properties-mode="OVERRIDE" />
<context:component-scan base-package="com.stef.soa.eh" />
<context:annotation-config />
<import resource="classpath:META-INF/eh/spring/broker.xml" />
<import resource="classpath:META-INF/eh/spring/camel.xml" />
<import resource="classpath:META-INF/eh/spring/cxf.xml" />
<import resource="classpath:META-INF/soa-console-flux-client/spring/context.xml"/>
</beans>
camel.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:http="http://cxf.apache.org/transports/http/configuration"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd
http://cxf.apache.org/transports/http/configuration
http://cxf.apache.org/schemas/configuration/http-conf.xsd" >
<!-- Camel Context -->
<camelContext xmlns="http://camel.apache.org/schema/spring" id="ehContext">
<properties>
<property key="org.apache.camel.xmlconverter.output.indent" value="yes"/>
<property key="org.apache.camel.xmlconverter.output.{http://xml.apache.org/xslt}indent-amount" value="4"/>
</properties>
<package>com.stef.soa.eh.integration</package>
</camelContext>
</beans>
cxf.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cxf="http://camel.apache.org/schema/cxf"
xmlns:http="http://cxf.apache.org/transports/http/configuration"
xmlns:sec="http://cxf.apache.org/configuration/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/cxf
http://camel.apache.org/schema/cxf/camel-cxf.xsd
http://cxf.apache.org/transports/http/configuration
http://cxf.apache.org/schemas/configuration/http-conf.xsd" >
<!-- Serveur Proxy, Certificat -->
<http:conduit name="*.http-conduit">
<http:client ProxyServer="${proxy.host}" ProxyServerPort="${proxy.port}"
ConnectionTimeout="${http.client.connectionTimeout}" ReceiveTimeout="${http.client.receiveTimeout}" />
<http:proxyAuthorization>
<sec:UserName>${proxy.username}</sec:UserName>
<sec:Password>${proxy.password}</sec:Password>
</http:proxyAuthorization>
<http:tlsClientParameters>
<sec:keyManagers keyPassword="${eh.keyStore.password}">
<sec:keyStore type="pkcs12" password="${eh.keyStore.password}" file="${eh.home}/${eh.keyStore.file}" />
</sec:keyManagers>
</http:tlsClientParameters>
</http:conduit>
<!-- Services Proxy et Cible -->
<cxf:cxfEndpoint
id="creditLimitRequestServiceProxy"
address="/creditLimitRequestService"
wsdlURL="META-INF/eh/wsdl/CreditLimitRequestService/EH_SMARTLINK_CreditLimitRequestServiceV4.wsdl"
serviceName="ns:CreditLimitRequestServiceV4"
endpointName="ns:CreditLimitRequestServiceV4"
xmlns:ns="http://ehsmartlink/CreditLimitRequestService/v4"
/>
<cxf:cxfEndpoint
id="creditLimitRequestService"
address="${eh.creditLimitRequestService.url}"
wsdlURL="META-INF/eh/wsdl/CreditLimitRequestService/EH_SMARTLINK_CreditLimitRequestServiceV4.wsdl"
serviceName="ns:CreditLimitRequestServiceV4"
endpointName="ns:CreditLimitRequestServiceV4"
xmlns:ns="http://ehsmartlink/CreditLimitRequestService/v4"
loggingFeatureEnabled="true"
/>
<cxf:cxfEndpoint
id="customerListRetrieveServiceProxy"
address="/customerListRetrieveService"
wsdlURL="META-INF/eh/wsdl/CustomerListRetrieveService/CustomerListRetrieveV2.wsdl"
serviceName="ns:CustomerListRetrieveServiceV2"
endpointName="ns:CustomerListRetrieveServiceV2"
xmlns:ns="http://ehsmartlink/CustomerListRetrieve/v2"
/>
<cxf:cxfEndpoint
id="customerListRetrieveService"
address="${eh.customerListRetrieveService.url}"
wsdlURL="META-INF/eh/wsdl/CustomerListRetrieveService/CustomerListRetrieveV2.wsdl"
serviceName="ns:CustomerListRetrieveServiceV2"
endpointName="ns:CustomerListRetrieveServiceV2"
xmlns:ns="http://ehsmartlink/CustomerListRetrieve/v2"
loggingFeatureEnabled="true"
/>
<cxf:cxfEndpoint
id="firstEuroListRepertoireReadServiceProxy"
address="/firstEuroListRepertoireReadService"
wsdlURL="META-INF/eh/wsdl/FirstEuroListRepertoireReadService/EH_SMARTLINK_FirstEuroListRepertoireReadService-v1.wsdl"
serviceName="ns:FirstEuroListRepertoireReadService-v1"
endpointName="ns:FirstEuroListRepertoireReadServicePort-v1_soap11"
xmlns:ns="http://eulerhermes.com/SMARTLINK/services/FirstEuroListRepertoireReadService/v1"
/>
<cxf:cxfEndpoint
id="firstEuroListRepertoireReadService"
address="${eh.firstEuroListRepertoireReadService.url}"
wsdlURL="META-INF/eh/wsdl/FirstEuroListRepertoireReadService/EH_SMARTLINK_FirstEuroListRepertoireReadService-v1.wsdl"
serviceName="ns:FirstEuroListRepertoireReadService-v1"
endpointName="ns:FirstEuroListRepertoireReadServicePort-v1_soap11"
xmlns:ns="http://eulerhermes.com/SMARTLINK/services/FirstEuroListRepertoireReadService/v1"
loggingFeatureEnabled="true"
/>
<cxf:cxfEndpoint
id="firstEuroListRepertoireUpdateServiceProxy"
address="/firstEuroListRepertoireUpdateService"
wsdlURL="META-INF/eh/wsdl/FirstEuroListRepertoireUpdateService/EH_SMARTLINK_FirstEuroListRepertoireUpdateService-v1.wsdl"
serviceName="ns:FirstEuroListRepertoireUpdateService-v1"
endpointName="ns:FirstEuroListRepertoireUpdateServicePort-v1"
xmlns:ns="http://eulerhermes.com/SMARTLINK/services/FirstEuroListRepertoireUpdateService/v1"
/>
<cxf:cxfEndpoint
id="firstEuroListRepertoireUpdateService"
address="${eh.firstEuroListRepertoireUpdateService.url}"
wsdlURL="META-INF/eh/wsdl/FirstEuroListRepertoireUpdateService/EH_SMARTLINK_FirstEuroListRepertoireUpdateService-v1.wsdl"
serviceName="ns:FirstEuroListRepertoireUpdateService-v1"
endpointName="ns:FirstEuroListRepertoireUpdateServicePort-v1"
xmlns:ns="http://eulerhermes.com/SMARTLINK/services/FirstEuroListRepertoireUpdateService/v1"
loggingFeatureEnabled="true"
/>
<cxf:cxfEndpoint
id="limitDetailReadServiceProxy"
address="/limitDetailReadService"
wsdlURL="META-INF/eh/wsdl/LimitDetailReadService/EH_SMARTLINK_LimitDetailReadService-v2.wsdl"
serviceName="ns:LimitDetailReadService-v2"
endpointName="ns:LimitDetailReadServicePort-v2"
xmlns:ns="http://eulerhermes.com/SMARTLINK/services/LimitDetailReadService/v2"
/>
<cxf:cxfEndpoint
id="limitDetailReadService"
address="${eh.limitDetailReadService.url}"
wsdlURL="META-INF/eh/wsdl/LimitDetailReadService/EH_SMARTLINK_LimitDetailReadService-v2.wsdl"
serviceName="ns:LimitDetailReadService-v2"
endpointName="ns:LimitDetailReadServicePort-v2"
xmlns:ns="http://eulerhermes.com/SMARTLINK/services/LimitDetailReadService/v2"
loggingFeatureEnabled="true"
/>
</beans>
I've published JAX-WS web services with Endpoint.publish during development. Is there any such utility class exists (in JAX-RS) for publishing REST web services in jersey? I referred couple of articles, and majority of them are based on publishing the web services in some containers like Jetty, Grizzly etc.
Jersey-Grizzly has a very simple solution. From https://github.com/jesperfj/jax-rs-heroku:
package embedded.rest.server;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.sun.grizzly.http.SelectorThread;
import com.sun.jersey.api.container.grizzly.GrizzlyWebContainerFactory;
#Path("/hello")
public class Main {
public static void main(String[] args) {
final String baseUri = "http://localhost:7080/";
final Map<String, String> initParams = new HashMap<String, String>();
// Register the package that contains your javax.ws.rs-annotated beans here
initParams.put("com.sun.jersey.config.property.packages","embedded.rest.server");
System.out.println("Starting grizzly...");
try {
SelectorThread threadSelector =
GrizzlyWebContainerFactory.create(baseUri, initParams);
System.out.println(String.format("Jersey started with WADL "
+ "available at %sapplication.wadl.", baseUri));
}
catch(Exception e) {
e.printStackTrace();
}
}
#GET
#Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "Well, this was easy!";
}
}
If you're using Maven, you'll need the following three dependencies:
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-grizzly</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-bundle</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>com.sun.grizzly</groupId>
<artifactId>grizzly-servlet-webserver</artifactId>
<version>1.9.18-i</version>
</dependency>
To test it, just open http://localhost:7080/hello in a browser.
I think you can use Provider interface to publishing a RESTful Web Service with JAX-WS.
The example class:
#WebServiceProvider
#BindingType(value=HTTPBinding.HTTP_BINDING)
public class AddNumbersImpl implements Provider {
#Resource
protected WebServiceContext wsContext;
public Source invoke(Source source) {
try {
MessageContext mc = wsContext.getMessageContext();
// check for a PATH_INFO request
String path = (String)mc.get(MessageContext.PATH_INFO);
if (path != null && path.contains("/num1") &&
path.contains("/num2")) {
return createResultSource(path);
}
String query = (String)mc.get(MessageContext.QUERY_STRING);
System.out.println("Query String = "+query);
ServletRequest req = (ServletRequest)mc.get(MessageContext.SERVLET_REQUEST);
int num1 = Integer.parseInt(req.getParameter("num1"));
int num2 = Integer.parseInt(req.getParameter("num2"));
return createResultSource(num1+num2);
} catch(Exception e) {
e.printStackTrace();
throw new HTTPException(500);
}
}
private Source createResultSource(String str) {
StringTokenizer st = new StringTokenizer(str, "=&/");
String token = st.nextToken();
int number1 = Integer.parseInt(st.nextToken());
st.nextToken();
int number2 = Integer.parseInt(st.nextToken());
int sum = number1+number2;
return createResultSource(sum);
}
private Source createResultSource(int sum) {
String body =
"<ns:addNumbersResponse xmlns:ns="http://java.duke.org"><ns:return>"
+sum
+"</ns:return></ns:addNumbersResponse>";
Source source = new StreamSource(
new ByteArrayInputStream(body.getBytes()));
return source;
}
}
To deploy our endpoint on a servlet container running with the JAX-WS
RI we need to create a WAR file.
The adjusted web.xml:
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee">
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener
</listener>
<servlet>
<servlet-name>restful-addnumbers</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>restful-addnumbers</servlet-name>
<url-pattern>/addnumbers/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>
and need to add sun-jaxws.xml deployment descriptor to the WAR file.
<endpoints
xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
version="2.0">
<endpoint
name="restful-addnumbers"
implementation="restful.server.AddNumbersImpl"
wsdl="WEB-INF/wsdl/AddNumbers.wsdl"
url-pattern="/addnumbers/*" />
</endpoints>
Or could be create simple HttpServer
import java.io.IOException;
import com.sun.jersey.api.container.httpserver.HttpServerFactory;
import com.sun.net.httpserver.HttpServer;
public class YourREST {
static final String BASE_URI = "http://localhost:9999/yourrest/";
public static void main(String[] args) {
try {
HttpServer server = HttpServerFactory.create(BASE_URI);
server.start();
System.out.println("Press Enter to stop the server. ");
System.in.read();
server.stop(0);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I receive a message from AAA nested children. I want every child BBB replace the value of CCC. Then send the modified message on AAA
<AAA>
<BBB>
<CCC>test1</CCC>
<DDD>testing</DDD>
</BBB>
<BBB>
<CCC>test2</CCC>
<DDD>testing</DDD>
</BBB>
<BBB>
<CCC>test3</CCC>
<DDD>testing</DDD>
</BBB>
<BBB>
<CCC>test4</CCC>
<DDD>testing</DDD>
</BBB>
<BBB>
<CCC>test5</CCC>
<DDD>testing</DDD>
</BBB>
</AAA>
I do it:
<iterate continueParent="true" expression="/AAA/BBB">
<target>
<sequence>
<property name="newValue" value="chang testing" scope="default" type="STRING"/>
<enrich>
<source clone="false" type="custom" xpath="get-property('newValue')"/>
<target action="replace" type="custom" xpath="//DDD"/>
</enrich>
</sequence>
</target>
</iterate>
But changing the message is not stored on
If you use iterate mediator you have to aggregate the results to get the modified message. How ever this can be achieved by using xslt mediator. Sample proxy configuration would be look like follows
<proxy name="yourpproxy" transports="https http" startOnLoad="true" trace="disable">
<description/>
<target>
<inSequence>
<xslt key="yourxsltkey"/>
<send/>
</inSequence>
<outSequence>
<send/>
</outSequence>
</target>
</proxy>
where yourxsltkey is the key to your xslt definition. This can be either declare as local entry or in registry. As an sample here i have defined as a local entry.
<localEntry key="yourxsltkey">
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<AAA xmlns="http://ws.apache.org/ns/synapse">
<xsl:for-each select="AAA/BBB">
<BBB><xsl:value-of select="CCC"/></BBB>
</xsl:for-each>
</AAA>
</xsl:template>
</xsl:stylesheet>
</localEntry>
I wrote my mediator and use it for this purpose
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.impl.dom.NamespaceImpl;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axis2.AxisFault;
import org.apache.synapse.Mediator;
import org.apache.synapse.MessageContext;
import org.apache.synapse.mediators.AbstractMediator;
import org.apache.synapse.mediators.eip.EIPUtils;
import org.apache.synapse.util.MessageHelper;
import org.apache.synapse.util.xpath.SynapseXPath;
import org.jaxen.JaxenException;
import java.util.List;
public class SplitMediator extends AbstractMediator {
private String sequenceRef = null;
private String xpathString = null;
private String attachPathString = null;
private String uri = null;
private String prefix = null;
public boolean mediate(MessageContext synCtx) {
if (sequenceRef == null || xpathString == null || attachPathString == null) {
handleException("Error creating a mediate due to sequenceRef or xpathString attachPathString is null", synCtx);
return false;
}
try {
SOAPEnvelope envelope = synCtx.getEnvelope();
Mediator sequenceMediator = synCtx.getSequence(sequenceRef);
SynapseXPath expression = new SynapseXPath(xpathString);
if (uri != null && prefix != null)
expression.addNamespace(new NamespaceImpl(uri, prefix));
SynapseXPath attachPath = new SynapseXPath(attachPathString);
if (uri != null && prefix != null)
attachPath.addNamespace(new NamespaceImpl(uri, prefix));
List<OMNode> splitElements = EIPUtils.getDetachedMatchingElements(envelope, synCtx, expression);
MessageContext templateMessageContext = MessageHelper.cloneMessageContext(synCtx);
OMElement omElement = getOMElementByXPath(attachPath, envelope, synCtx);
for (OMNode o : splitElements) {
MessageContext changeCtx = getNewMessageContextToSequence(templateMessageContext, o, attachPath);
sequenceMediator.mediate(changeCtx);
List elementList = EIPUtils.getMatchingElements(changeCtx.getEnvelope(), expression);
OMNode changeElement = (OMNode) elementList.get(0);
omElement.addChild(changeElement);
}
} catch (JaxenException e) {
handleException("Error evaluating split XPath expression : " + xpathString, e, synCtx);
} catch (AxisFault af) {
handleException("Error creating an iterated copy of the message", af, synCtx);
}
return true;
}
private MessageContext getNewMessageContextToSequence(MessageContext templateMessageContext, OMNode o, SynapseXPath attachPath) throws AxisFault, JaxenException {
MessageContext synCtx = MessageHelper.cloneMessageContext(templateMessageContext);
SOAPEnvelope envelope = synCtx.getEnvelope();
OMElement omElement = getOMElementByXPath(attachPath, envelope, synCtx);
omElement.addChild(o);
return synCtx;
}
private OMElement getOMElementByXPath(SynapseXPath attachPath, SOAPEnvelope envelope, MessageContext synCtx) {
Object attachElem = attachPath.evaluate(envelope, synCtx);
if (attachElem != null &&
attachElem instanceof List && !((List) attachElem).isEmpty()) {
attachElem = ((List) attachElem).get(0);
}
// for the moment attaching element should be an OMElement
if (attachElem != null && attachElem instanceof OMElement) {
return ((OMElement) attachElem);
} else {
handleException("Error in attaching the splitted elements :: " +
"Unable to get the attach path specified by the expression " +
attachPath, synCtx);
}
return null;
}
///////////////////////////////////////////////////////////////////////////////////////
// Getters and Setters //
///////////////////////////////////////////////////////////////////////////////////////
public String getXpathString() {
return xpathString;
}
public void setXpathString(String xpathString) {
this.xpathString = xpathString;
}
public String getAttachPathString() {
return attachPathString;
}
public void setAttachPathString(String attachPathString) {
this.attachPathString = attachPathString;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSequenceRef() {
return sequenceRef;
}
public void setSequenceRef(String sequenceRef) {
this.sequenceRef = sequenceRef;
}
}
How do you create a POJO containing a list that the container has attributes?
Typically when creating a POJO of a list you do it the following way:
To represent the following XML structure:
<folder>
<messages>
<message>
<subject>XXXX</subject>
...
</message>
<message>
<subject>XXXX</subject>
...
</message>
</messages>
</folder>
#XmlRootElement(name = "folder")
public class Folder {
#XmlElement
private List<Message> messages;
...
}
#XmlRootElement(name = "message")
public class Message {
#XmlElement
private String subject;
...
}
But how do you represent a POJO when there are attributes at the messages tag? i.e.
<folder>
<messages total="45" start="3">
<message>
<subject>XXXX</subject>
...
</message>
<message>
<subject>XXXX</subject>
...
</message>
</messages>
</folder>
Do you create a POJO specifically for messages and then map a List of Message with an annotation of #XmlValue or something along those lines?
Thanks for your help guys.
The following approach could be used with any JAXB (JSR-222) implementation.
Messages
Using just the standard JAXB (JSR-222) APIs you will need to introduce a Messages class to your model.
import java.util.List;
import javax.xml.bind.annotation.*;
public class Messages {
#XmlElement(name="message")
private List<Message> messages;
#XmlAttribute
private int start;
#XmlAttribute
public int getTotal() {
if(null == messages) {
return 0;
} else {
return messages.size();
}
}
}
Folder
Then you will need to modify your Folder class to reference the new Messages class.
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Folder {
private Messages messages;
}
Message
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class Message {
private String subject;
}
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group
If you use MOXy as your JAXB provider then you could leverage the #XmlPath extension and do the following.
Folder
import java.util.List;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Folder {
#XmlElementWrapper
#XmlElement(name="message")
private List<Message> messages;
#XmlPath("messages/#start")
private int start;
#XmlPath("messages/#total")
public int getTotal() {
if(null == messages) {
return 0;
} else {
return messages.size();
}
}
}
Message
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class Message {
private String subject;
}
jaxb.properties
To specify MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Folder.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum14372107/input.xml");
Folder folder = (Folder) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(folder, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<folder>
<messages start="1" total="2">
<message>
<subject>XXXX</subject>
</message>
<message>
<subject>YYYY</subject>
</message>
</messages>
</folder>
For More Information
http://blog.bdoughan.com/2010/07/xpath-based-mapping.html
http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html
http://blog.bdoughan.com/2010/09/jaxb-collection-properties.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
I'm new to Spring-WS and I have defined an endpoint based off a schema generated from JAXB annotated classes. However, when I try to access the endpoint via soapUI, I get the following error along with a 404 response code:
No endpoint mapping found for [SaajSoapMessage {clip}clipClaimRequest]
Any ideas as to what I'm doing wrong? Thanks for any help given.
The endpoint class:
#Endpoint
public class TestEndpoint {
#PayloadRoot(localPart = "clipClaimRequest", namespace = "clip")
#ResponsePayload
public CLIPClaimResponse registerClaim(#RequestPayload CLIPClaimRequest request) {
return new CLIPClaimResponse("Success", "test success");
}
}
The request/response classes (marshalled/unmarshalled via JAXB):
#XmlRootElement(name = "clipClaimRequest")
#XmlType(name = "CLIPClaimRequest")
public class CLIPClaimRequest {
private Claim claim;
#XmlElement(required = true)
public Claim getClaim() {
return claim;
}
public void setClaim(Claim claim) {
this.claim = claim;
}
}
And:
#XmlRootElement(name = "clipClaimResponse")
#XmlType(name = "CLIPClaimResponse")
public class CLIPClaimResponse {
private String code;
private String description;
public CLIPClaimResponse() {
}
public CLIPClaimResponse(String code, String desc) {
setCode(code);
setDescription(desc);
}
#XmlElement(required = true)
public String getCode() {
return code;
}
#XmlElement(required = true)
public String getDescription() {
return description;
}
public void setCode(String code) {
this.code = code;
}
public void setDescription(String description) {
this.description = description;
}
}
web.xml servlet configuration:
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<description>This is used by SpringWS to dynamically convert WSDL urls</description>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/clipClaimService/*</url-pattern>
</servlet-mapping>
spring-ws-servlet.xml configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<context:annotation-config />
<sws:annotation-driven />
<sws:dynamic-wsdl id="claimRegistration" portTypeName="CLIPClaimPort"
locationUri="/clipClaimService/" targetNamespace="clip">
<sws:xsd location="/WEB-INF/CLIP_Poc.xsd" />
</sws:dynamic-wsdl>
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<!-- list of classes... -->
</list>
</property>
<property name="schema" value="/WEB-INF/CLIP_PoC.xsd" />
</bean>
<bean id="marshallingPayloadMethodProcessor"
class="org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor">
<constructor-arg ref="jaxb2Marshaller" />
<constructor-arg ref="jaxb2Marshaller" />
</bean>
<bean id="defaultMethodEndpointAdapter"
class="org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter">
<property name="methodArgumentResolvers">
<list>
<ref bean="marshallingPayloadMethodProcessor" />
</list>
</property>
<property name="methodReturnValueHandlers">
<list>
<ref bean="marshallingPayloadMethodProcessor" />
</list>
</property>
</bean>
</beans>
And finally, CLIP_PoC.xsd, the schema from which the WSDL was generated:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="clip" targetNamespace="clip" version="1.0">
<xs:element name="clipClaimRequest" type="CLIPClaimRequest"/>
<xs:element name="clipClaimResponse" type="CLIPClaimResponse"/>
<!-- type definitions for all the complex elements used... -->
</xs:schema>
I figured it out. I had forgotten to put: <context:component-scan base-package="my.base.package"/> in my spring-ws-servlet.xml file. This fixed it somehow.