Camel, CXF and JMS by example

November 15th, 2009 by Silvester van der Bijl Leave a reply »

While working on a typical customer SOA/ESB integration project we ran into some complex communication issues. It’s required that all communication between the different services and ESB is done using SOAP over JMS. CXF already has embedded support for JMS, but apart from a complex setup, this also caused that our services were no longer available using plain HTTP (used for our FitNesse functional tests). As it took quite some time to figure out how to properly hookup CXF and Camel, and exposing them via various protocols (even email if you’d like to) I wanted to share with you how we implemented this via an example project.

About Camel and CXF

Apache CXF is a popular webservices framework which we’ll be using to provide the SOAP support. It provides support for the HTTP transport out of the box (and JMS, but I wouldn’t recommend this setup), but we’ll be replacing the default transport with a Camel one (basically making Camel responsible for the transport, and delegating only the SOAP handling to CXF).

When I first came across Apache Camel it felt like a tiny ESB (or rather, perhaps how an ESB should actually work). This seems to fit pretty well with their own description:

Apache Camel is a powerful open source integration framework based on known Enterprise Integration Patterns with powerful Bean Integration.

A quick scan of the components overview will show all the various “transports” supported by Camel. One of these is CXF, providing Camel with the ability to talk to CXF components. Another is JMS, providing us with the ability to configure our JMS setup as we like. In Camel we can integrate these two by establishing a route within a CamelContext.

The example application

The application used for demonstrating SOAP over JMS is a simple web application, which contains a single POJO service, the EchoService. We want to expose this service via SOAP/JMS and SOAP/HTTP. Download details are at the bottom of the post. I’m not going to explain the entire Spring configuration, but instead I’ll focus on the bean definitions which hookup CXF to Camel, and expose the service over the various protocols.

Ok, a small summary of what we want to achieve. We want Camel to listen to a JMS queue (or topic), and relay any messages (which are expected to be in SOAP format) to CXF. The (optional) reply should be sent to the JMS Reply-To header in the original message. Sounds complex? Not really, once you know how!

Integrating Apache Camel and CXF

Before being able to call out to CXF from Camel we need to make the Camel transport available to CXF. This will allow Camel to relay incoming messages (from any source) to CXF (and CXF beans can be registered on a camel:// address, instead of http://, etc.). Configuring the Camel CXF transport can be done using the following bean definition:

1
2
3
4
5
6
7
8
9
<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>

Ok, so now Camel and CXF are aware of each other, it’s time to tell Camel where messages are coming from, and how it should route them. This couldn’t be easier with Camel (omitting much of the XML here, see example application for details):

1
2
3
4
5
6
7
8
9
10
11
12
13
<camel:camelContext trace="true">
  <camel:route>
    <!-- Handle HTTP requests through JMS -->
    <camel:from uri="servlet:///echoService" />
    <camel:to uri="jms://echo.internal.entry" />
  </camel:route>
 
  <!-- EchoService processing -->
  <camel:route>
    <camel:from uri="jms://echo.internal.entry" />
    <camel:to uri="direct://echoService" />
  </camel:route>
</camel:camelContext>

What we’ve done using the Camel routes above is to instruct Camel that any messages arriving on the servlet transport, at the echoService URI should be forwarded to a JMS queue. Of course, we don’t really need to put messages on the queue, but for the purposes of this demo I’ll just keep it in.

Next thing we’ve done is to tell Camel to listen to a queue and consume any message arriving on it using CXF. Camel itself is smart enough to determine whether this is a request reply scenario, so it will wait for the CXF response which will be send back over JMS to the reply-to destination specified in the original incoming message (and in the case of routing over HTTP, back to the calling party).

Basically, all that’s missing is the declaration of the CXF service itself. The code for the service is included in the sample application, but it’s not very complex (hint it echoes ;-) ):

1
2
3
4
5
6
7
8
9
<jaxws:endpoint implementor="#echoService" 
  address="camel://direct:echoService" serviceName="echo:echo"
  id="echoService.camel"
  implementorClass="cameldemo.services.EchoService" 
  xmlns:echo="http://cameldemo/echoservice/v1">
  <jaxws:properties>
    <entry key="schema-validation-enabled" value="true" />
  </jaxws:properties>
</jaxws:endpoint>

Conclusion

This example demonstrates how to use JMS in combination with CXF, something we needed, but there’s nothing preventing you from using this in combination with XMPP, or Email (if performance allows)! The amount of code required to implement this yourself would be overwhelming, hard to test and certainly not a easy to swap out.

The example application can be downloaded here. Most of it will speak for itself. Running the application can be done using mvn jetty:run. The generated WSDL can be found in target/generated. Importing this WSDL into SoapUI will list the wrong endpoint address, it should be http://localhost:8080/echoService.

I realize I may have left out a few too many details. If you have any questions, please let me know! Hope this is useful to you!

Advertisement

17 comments

  1. Claus Ibsen says:

    Hi Silvester

    Great blog. Yeah CXF has many moving parts and it does take some time to learn it and in particular how to configure it in the XML files.

    I have added a link to your blog post from the Camel articles page at:
    http://camel.apache.org/articles.html

    Will take some hours to sync.

  2. @Claus Ibsen
    Thanks Claus! I think CXF is a great framework when you need webservices of some form, but handling of different protocols is better left to Camel.

  3. Frank says:

    Hi,

    I would like download the example but the link no works!!! (or i do something wrong)

    Could you fix the link?

    Thanks. Great article

Leave a Reply