JBossWS-CXF supports JMS Transport to transfer SOAP messages. There is a testcase in the codebase to demonstrate this ability, available here. In this tutorial, we will use a wsdl first web service example to show you how to enable this feature in JBossWS.
WSDL
<wsdl:definitions name="OrganizationJMSEndpointService" targetNamespace="http://org.jboss.ws/samples/jmstransport" xmlns:jms="http://cxf.apache.org/transports/jms" xmlns:ns1="http://schemas.xmlsoap.org/wsdl/soap/http" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://org.jboss.ws/samples/jmstransport" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <wsdl:message name="getContactInfoResponse"> <wsdl:part name="return" type="xsd:string"> </wsdl:part> </wsdl:message> <wsdl:message name="getContactInfo"> <wsdl:part name="arg0" type="xsd:string"> </wsdl:part> </wsdl:message> <wsdl:portType name="Organization"> <wsdl:operation name="getContactInfo"> <wsdl:input message="tns:getContactInfo" name="getContactInfo"> </wsdl:input> <wsdl:output message="tns:getContactInfoResponse" name="getContactInfoResponse"> </wsdl:output> </wsdl:operation> </wsdl:portType> <wsdl:binding name="HTTPSoapBinding" type="tns:Organization"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getContactInfo"> <soap:operation soapAction="" style="rpc"/> <wsdl:input name="getContactInfo"> <soap:body namespace="http://org.jboss.ws/samples/jmstransport" use="literal"/> </wsdl:input> <wsdl:output name="getContactInfoResponse"> <soap:body namespace="http://org.jboss.ws/samples/jmstransport" use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:binding name="JMSSoapBinding" type="tns:Organization"> <soap:binding style="rpc" transport="http://cxf.apache.org/transports/jms"/> <wsdl:operation name="getContactInfo"> <soap:operation soapAction="" style="rpc"/> <wsdl:input name="getContactInfo"> <soap:body namespace="http://org.jboss.ws/samples/jmstransport" use="literal"/> </wsdl:input> <wsdl:output name="getContactInfoResponse"> <soap:body namespace="http://org.jboss.ws/samples/jmstransport" use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="OrganizationService"> <wsdl:port binding='tns:HTTPSoapBinding' name='HttpEndpointPort'> <soap:address location='http://@jboss.bind.address@:8080/jaxws-samples-jmstransport'/> </wsdl:port> <wsdl:port binding="tns:JMSSoapBinding" name="JmsEndpointPort"> <jms:address destinationStyle="queue" jndiConnectionFactoryName="ConnectionFactory" jndiDestinationName="queue/RequestQueue" jndiReplyDestinationName="queue/ResponseQueue"> > </jms:address> </wsdl:port> </wsdl:service> </wsdl:definitions>
Apache CXF defines the jms wsdl extension, so the jms queue name or other information about jms in wsdl port can be parsed to send or receive jms message. Check this wiki page to see what jms attributes you can defined in WSDL. In this wsdl, we define two queues to send and receive the soap message. CXF uses JNDI to look up the jms ConnectionFactory, so we may also need to provide the JNDI properties as the following example :
<jms:address destinationStyle="queue" jndiConnectionFactoryName="ConnectionFactory" jndiDestinationName="queue/RequestQueue" jndiReplyDestinationName="queue/ResponseQueue" > <jms:JMSNamingProperty name="java.naming.factory.initial" value="org.jnp.interfaces.NamingContextFactory"/> <jms:JMSNamingProperty name="java.naming.provider.url" value="jnp://localhost:1099"/> </jms:address>
Service Implementation
After generated code from this wsdl , we wrote two class to implement this interface for this two ports . We annotate the portName in annotation to tell web service stack
which transport this service uses :
@WebService (serviceName="OrganizationService", portName="HttpEndpointPort",wsdlLocation = "WEB-INF/wsdl/jmstransport.wsdl",targetNamespace = "http://org.jboss.ws/samples/jmstransport", endpointInterface="org.jboss.test.ws.jaxws.samples.jmstransport.Organization") @SOAPBinding(style = SOAPBinding.Style.RPC) public class OrganizationHttpEndpoint implements Organization { @WebMethod public String getContactInfo(String organization) { return "The '" + organization + "' boss is currently out of office, please call again."; } }
@WebService (serviceName="OrganizationService",portName="JmsEndpointPort", wsdlLocation = "WEB-INF/wsdl/jmstransport.wsdl", targetNamespace = "http://org.jboss.ws/samples/jmstransport", endpointInterface="org.jboss.test.ws.jaxws.samples.jmstransport.Organization") @SOAPBinding(style = SOAPBinding.Style.RPC) public class OrganizationJmsEndpoint implements Organization { @WebMethod public String getContactInfo(String organization) { return "The '" + organization + "' boss is currently out of office, please call again."; } }
web.xml
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <servlet> <servlet-name>OrganizationService</servlet-name> <servlet-class>org.jboss.test.ws.jaxws.samples.jmstransport.OrganizationHttpEndpoint</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>OrganizationService</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
It is almost the same as the usual web.xml to deploy a web service except the <load-on-startup> servlet initialize
parameter. This is for jms service start ready when deployment, no need to wait until the first servlet request to
start the jms endpoint.
jbossws-cxf.xml
In addition to web.xml, the jbossws-cxf.xml is needed to actually pass in cxf to start this two port.
<beans xmlns='http://www.springframework.org/schema/beans' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:beans='http://www.springframework.org/schema/beans' xmlns:jms="http://cxf.apache.org/transports/jms" xmlns:jaxws='http://cxf.apache.org/jaxws' xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.w3.org/2006/07/ws-policy http://www.w3.org/2006/07/ws-policy.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/transports/jms http://cxf.apache.org/schemas/configuration/jms.xsd'> <import resource="classpath:META-INF/cxf/cxf-extension-jms.xml"/> <jaxws:endpoint id='SOAPQueryService' implementor='org.jboss.test.ws.jaxws.samples.jmstransport.OrganizationHttpEndpoint' > <jaxws:invoker> <bean class='org.jboss.wsf.stack.cxf.InvokerJSE'/> </jaxws:invoker> </jaxws:endpoint> <jaxws:endpoint id='JMSQueryService' implementor='org.jboss.test.ws.jaxws.samples.jmstransport.OrganizationJmsEndpoint' transportId="http://cxf.apache.org/transports/jms"> </jaxws:endpoint> </beans>
Note: the import resource is the JmsTransportFactory configuration . It is required to jms transport enablement .
Below gives the war file directory structure to make it more clear what inside :
|-- jmstransport-sample.war `-- WEB-INF |-- classes | `-- org | `-- jboss | `-- test | `-- ws | `-- jaxws | `-- samples | `-- jmstransport | |-- JMSTransportTestCase$ResponseListener.class | |-- JMSTransportTestCase.class | |-- Organization.class | |-- OrganizationHttpEndpoint.class | `-- OrganizationJmsEndpoint.class |-- jboss-web.xml |-- jbossws-cxf.xml |-- web.xml `-- wsdl `-- jmstransport.wsdl
Comments