SOAP over JMS offers an alternative messaging mechanism to SOAP over HTTP. SOAP over JMS offers more reliable and scalable messaging support than SOAP over HTTP.
SOAP over JMS specification is aimed at a set of standards for the transport of SOAP messages over JMS. The main purpose is to ensure interoperability between the implementations of different Web services vendors. CXF supports SOAP over JMS specification, and is compliant with the specification.
What's new compare to the old CXF JMS Transport
SOAP over JMS transport supports the most configuration of JMS Transport and does some extension to support the SOAP over JMS specification. Such as jms:address, SOAP over JMS Transport uses JMS URI to describe the JMS address information and use new WSDL extension for the configuration of JMS.
SOAP over JMS Namespace
WSDL Namespace
The WSDL extensions for defining a JMS endpoint are using this namespace http://www.w3.org/2008/07/soap/bindings/JMS/. In order to use this JMS WSDL extensions you will need to add the namespace definition shown below to the definitions element of your contract.
JMS Extension Namespace
xmlns:soapjms="http://www.w3.org/2008/07/soap/bindings/JMS/"
JMS URI
JMS endpoints need to know the address information about how to establish a connection to the proper destination. SOAP over JMS implements the URI Scheme for Java Message Service 1.0.
This URI scheme starts with "jms:jndi:" plus a JNDI name for a Destination. Since interaction with some resources may require JNDI contextual information or JMS header fields and properties to be specified as well, the "jndi" variant of the "jms" URI scheme includes support for supplying this additional JNDI information as query parameters.
CXF supports three variants, "jndi", "queue", and "topic".
For example:
jms:jndi:SomeJndiNameForDestination?jndiInitialContextFactory=com.example.jndi.JndiFactory&priority=3 jms:queue:ExampleQueueName?timeToLive=1000
Properties are as follows:
Property |
DefaultVaule |
Description |
---|---|---|
deliveryMode |
PERSISTENT |
NON_PERSISTENT messages will only be kept in memory |
jndiConnectionFactoryName |
|
Specifies the JNDI name bound to the JMS connection factory to use when connecting to the JMS destination. |
jndiInitialContextFactory |
|
Specifies the fully qualified Java class name of the "InitialContextFactory" implementation class to use. |
jndiURL |
|
Specifies the JNDI provider URL |
replyToName |
|
Specifies the JNDI name bound to the JMS destinations where replies are sent. |
priority |
4 |
Priority for the messages. See your JMS provider doc for details |
timeToLive |
0 |
After this time the message will be discarded by the jms provider |
Additional JNDI Parameters |
|
Additional parameters for a JNDI provider. A custom parameter name must start with the prefix "jndi-". |
For more details about what information to use in these attributes, please check out the JMS URI specification.
WSDL Extension
Various JMS properties may be set in three places in the WSDL — the binding, the service, and the port. Values specified at the service will propagate to all ports. Values specified at the binding will propagate to all ports using that binding.
For example, the jndiInitialContextFactory may be indicated for a service, and it is then implied for all of the contained port elements.
Field |
DefaultVaule |
Description |
---|---|---|
deliveryMode |
PERSISTENT |
NON_PERSISTENT messages will only be kept in memory |
jndiConnectionFactoryName |
|
Specifies the JNDI name bound to the JMS connection factory to use when connecting to the JMS destination. |
jndiInitialContextFactory |
|
Specifies the fully qualified Java class name of the "InitialContextFactory" implementation class to use. |
jndiURL |
|
Specifies the JNDI provider URL |
replyToName |
|
Specifies the JNDI name bound to the JMS destinations where replies are sent. |
priority |
4 |
Priority for the messages. See your JMS provider doc for details |
timeToLive |
0 |
After this time the message will be discarded by the jms provider |
jndiContextParameter |
|
Additional parameters for a JNDI provider. |
An example is as follows:
<wsdl11:binding name="exampleBinding"> <soapjms:jndiContextParameter name="name" value="value" /> <soapjms:jndiConnectionFactoryName>ConnectionFactory </soapjms:jndiConnectionFactoryName> <soapjms:jndiInitialContextFactory> org.apache.activemq.jndi.ActiveMQInitialContextFactory </soapjms:jndiInitialContextFactory> <soapjms:jndiURL>tcp://localhost:61616 </soapjms:jndiURL> <soapjms:deliveryMode>PERSISTENT</soapjms:deliveryMode> <soapjms:priority>5</soapjms:priority> <soapjms:timeToLive>200</soapjms:timeToLive> </wsdl11:binding> <wsdl11:service name="exampleService"> <soapjms:jndiInitialContextFactory> com.example.jndi.InitialContextFactory </soapjms:jndiInitialContextFactory> <soapjms:timeTolive>100</soapjms:timeToLive> ... <wsdl11:port name="quickPort" binding="tns:exampleBinding"> ... <soapjms:timeToLive>10</soapjms:timeToLive> </wsdl11:port> <wsdl11:port name="slowPort" binding="tns:exampleBinding"> ... </wsdl11:port> </wsdl11:service>
If a property is specified at multiple levels, the most specific setting takes precedence (port first, then service, then binding). In the above example, notice the timeToLive property — for the quickPort port, the value will be 10 (specified at the port level). For the slowPort port, the value will be 100 (specified at the service level). The setting in the binding is, in this example, always overridden.
WSDL Usage
The example is as follows:
<wsdl:definitions name="JMSGreeterService" <wsdl:binding name="JMSGreeterPortBinding" type="tns:JMSGreeterPortType"> <soap:binding style="document" transport="http://www.w3.org/2008/07/soap/bindings/JMS/" /> <soapjms:jndiContextParameter name="name" value="value" /> <soapjms:jndiConnectionFactoryName>ConnectionFactory </soapjms:jndiConnectionFactoryName> <soapjms:jndiInitialContextFactory> org.apache.activemq.jndi.ActiveMQInitialContextFactory </soapjms:jndiInitialContextFactory> <soapjms:jndiURL>tcp://localhost:61616 </soapjms:jndiURL> <soapjms:deliveryMode>PERSISTENT</soapjms:deliveryMode> <soapjms:priority>5</soapjms:priority> <soapjms:timeToLive>1000</soapjms:timeToLive> <wsdl:operation name="greetMe"> <soap:operation soapAction="test" style="document" /> <wsdl:input name="greetMeRequest"> <soap:body use="literal" /> </wsdl:input> <wsdl:output name="greetMeResponse"> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="JMSGreeterService"> <wsdl:port binding="tns:JMSGreeterPortBinding" name="GreeterPort"> <soap:address location="jms:jndi:dynamicQueues/test.cxf.jmstransport.queue" /> </wsdl:port> </wsdl:service> </wsdl:definitions>
- The transport URI in <soap:binding>. It is http://www.w3.org/2008/07/soap/bindings/JMS/.
- The jms: URI in the <soap:address>
- The extension properties in the <soap:binding>
Publishing an service with the JAVA API
Some user who doesn't want to get touch with any WSDL stuff could also publish the endpoint with CXF SOAP over JMS. First you could write as follows.
// You just need to set the address with JMS URI String address = "jms:jndi:dynamicQueues/test.cxf.jmstransport.queue3" + "?jndiInitialContextFactory" + "=org.apache.activemq.jndi.ActiveMQInitialContextFactory" + "&jndiConnectionFactoryName=ConnectionFactory&jndiURL=tcp://localhost:61500"; Hello implementor = new HelloImpl(); JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean(); svrFactory.setServiceClass(Hello.class); svrFactory.setAddress(address); // And specify the transport ID with SOAP over JMS specification svrFactory.setTransportId(JMSSpecConstants.SOAP_JMS_SPECIFICIATION_TRANSPORTID); svrFactory.setServiceBean(implementor); svrFactory.create();
Consume the service with the API
The code how to consumer the service with the SOAP over JMS transport is as follows:
public void invoke() throws Exception { // You just need to set the address with JMS URI String address = "jms:jndi:dynamicQueues/test.cxf.jmstransport.queue3" + "?jndiInitialContextFactory" + "=org.apache.activemq.jndi.ActiveMQInitialContextFactory" + "&jndiConnectionFactoryName=ConnectionFactory&jndiURL=tcp://localhost:61500"; JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); // And specify the transport ID with SOAP over JMS specification factory.setTransportId(JMSSpecConstants.SOAP_JMS_SPECIFICIATION_TRANSPORTID); factory.setServiceClass(Hello.class); factory.setAddress(address); Hello client = (Hello)factory.create(); String reply = client.sayHi(" HI"); System.out.println(reply); }
The Difference between the SOAP over JMS and the CXF old JMS transport implementation
There are some differences between the SOAP over JMS and the CXF old JMS transport implementation.
- The JMS Messages sent by SOAP over JMS transport implementation are in accord with the SOAP over JMS specification. Then CXF can interoperate with other SOAP over JMS implementation.
- You can use new method for configuration about SOAP over JMS, and it is accord with the SOAP over JMS specification.
- SOAP over JMS provides more sophisticated error-handling for the message of SOAP/JMS.