You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

Configuring JMS in Apache CXF is possible but not really easy or nice. This article shows how to use Apache Camel to provide a better JMS Transport for CXF.
The original post is from Christian Schneider´s blog and can be found here

Why not simply use JMS Features of Apache CXF

JMS configuration in Apache CXF is possible but the configuration is not very flexible and quite error prone. In CXF you have to configure a JMSConduit or a JMSDestination for each webservice. The connection between Conduit and the Service proxy is the endpoint name which looks like "{http://service.test\}HelloWorldPort.jms-conduit". As this name is never explicitly configured elsewhere it is quite probable that you misspell the name. If this happens then the JMS Transport just does not work. There is no good error reporting to show you what you did wrong. The next thing is that you have to use JNDI for the connectionFactory and the queue name. This is something that beginners with JMS have many problems with.

Why is using Apache Camel better in the JMS Transport layer

In apache camel you can simply reference the ConnectionFactory as a spring bean. This means you can either define it directly in a spring bean what is the ideal way to start or you can use spring´s JNDI binding to retrieve it from your application server for production use.
The next nice thing is that you can configure all JMS options like Receive Timeout or username / password in a central location, the JMSComponent and then share this config for several services. On the other hand you can easily configure different JMS providers.
The last thing that I do not need right now but is nice to have is that you have the full power of Camel´s routing config. So if you want to do additional things from simply calling the service it is easy.

So how to connect Apache Camel and CXF

The best way to connect Camel and CXF is using the Camel transport for CXF. This is a camel module that registers with camel as a new transport. It is quite easy to configure.

<bean class="org.apache.camel.component.cxf.transport.CamelTransportFactory">
  <property name="bus" ref="cxf" />
  <property name="camelContext" ref="camelContext" />
  <property name="transportIds">
    <list>
      <value>http://cxf.apache.org/transports/camel</value>
    </list>
  </property>
</bean>

That is all. This bean registers with cxf and provides a new transport prefix camel:// that can be used in CXF address configurations. The bean references a bean cxf. You do not have to explicitly configure this bean as cxf does this on it´s own. The other thing the CamelTransportFactory needs is a reference to a camel context. We will later define this bean to provide the routing config.

How is JMS configured in Camel

In camel you need two things to configure JMS. A ConnectionFactory and a JMSComponent. The connectionFactory is just the normal Factory your JMS provider offers or it can bind a JNDI connectionFactory. In this example we use the ConnectionFactory provided by ActiveMQ. The connectionFactory is the place to set username and password.

<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
  <property name="brokerURL" value="tcp://localhost:61616" />
</bean>

Then we set up the JMSComponent. It offers a new tranport prefix to camel that we simply call jms. If we need several JMSComponents we can differentiate them by their name.

<bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
  <property name="connectionFactory" ref="jmsConnectionFactory" />
  <property name="useMessageIDAsCorrelationID" value="true" />
</bean>

You can find more details about the JMSComponent at http://activemq.apache.org/camel/jms.html. For example you find the complete configuration options and a JNDI sample there.

Setting up the CXF client

We will configure a simple CXF webservice client. It will use stub code generated from a wsdl. I will show how to do the stub generation later. The webservice client will not be configured to use JMS directly instead we let it communicate on a camel direct endpoint that will later be routed to a JMS queue.

<client id="CustomerService" xmlns="http://cxf.apache.org/jaxws" xmlns:customer="http://customerservice.example.com/"
  serviceName="customer:CustomerServiceService"
  endpointName="customer:CustomerServiceEndpoint"
  address="camel://direct:CustomerService"
  serviceClass="com.example.customerservice.CustomerService">
</client>

We explicitly configure serviceName and endpointName so they are not read from the wsdl. The names we use are arbitrary and have no further function but we set them to look nice. The serviceclass points to the service interface that was generated from the wsdl. Now the important thing is address. Here we tell cxf to use the camel transport and register a direct endpoint named CustomerService.

Routing the client to the jms queue

The last step we have to do is routing Exchanges the cxf client sends to the direct endpoint from there to a JMS queue or topic. This is done in the camelContext bean.

<camelContext id="camelContext" xmlns="http://activemq.apache.org/camel/schema/spring">
  <route>
    <from uri="direct:CustomerService" />
    <to uri="jms://net.enbw.services.etg.examples.CustomerService" />
  </route>
</camelContext>

Running the Example

Conclusion

As you have seen in this example you can use Camel to dramatically ease JMS configuration compared with CXFs native JMS Transport. For me this is of course only a workaround. We should work on the native JMS config for CXF to make it at least as good as Camel´s. As CXF and Camel are two projects that have very good connections between them it is perhaps even possible to have a common transport layer for CXF and camel.

When I announced this Howto on the camel mailing list James Strachan told me that it is also possible to make your webservices transactional by using Spring declarative transactions. I will write a spearate article that focuses on how to do this.

Thanks

Many thanks to Eduard Hildebrandt http://www.family-hildebrandt.com who helped a lot in making this example work by debugging all the problems we initially had and providing patches for the issues.

  • No labels