Logo Computer scientist,
engineer, and educator
• Articles • Articles about computing • Articles about software development • Apache integration software

Specifying a Camel route using Spring XML and the Maven camel runner

This example demonstrates how to define a Camel route using Spring XML, and run it using the Maven Camel runner. The route will use XPath expressions to parse and route the incoming messages.

This article assumes at least rudimentary knowledge of Camel and of Maven, and at least the ability to understand a Spring XML file. The Maven Camel runner accepts Spring XML files that are located in the project directory in the same location as would typically be used when creating a Camel application for deployment as an OSGi bundle or a WAR file; so while the Camel runner might not be an appropriate way to execute an application in full production, it can be used to test Camel routes outside of the framework that will eventually host them. It is, at least, a convenient way to experiment with Spring-based Camel routing.

The full source code is available from the Downloads section at the end of this article; the steps listed have been tested on a Linux system, but should work on any platform, provided a means can be found to sent HTTP POST requests containing XML payloads.

The Camel route

The simple Camel route will create an HTTP server (using the camel-jetty component) that accepts XML messages the represent orders. In each order there is a division element that takes the values "UK" or "DE". Depending on the value of this element, the route will write the incoming message (unchanged) into one of two directories, uk-orders and de-orders. The HTTP client will receive some text according to whether the order was accepted or not.

Here is an example of an XML input message:

<order>
  <productid>100</productid>
  <quantity>1</quantity>
  <account>100</account>
  <division>UK</division>
</order>
Note that for the purposes of the test application, the only XML elements that matter are order and division.
Note:
The source code bundle contains some example XML files that can be used for testing

Structuring the Maven project

The pom.xml file needed to build this simple application is pretty ordinary (please see the soure code bundle for the full source). What might be unfamiliar is the specification of the Camel runner plug-in:
   <plugin>
     <groupId>org.apache.camel</groupId>
     <artifactId>camel-maven-plugin</artifactId>
     <version>${camel-version}</version>
   </plugin>
With this plug-in in place, it will be possible to run Camel routes by running mvn camel:run.

At runtime, the Camel runner will look for XML files in the directory META-INF/spring on the class search path. This location is pretty typical for Spring-based applications. To get the XML files into the right place, put them in the directory src/main/resources/META-INF/spring in the project source.

Coding the route

The use of the Spring Camel DSL ("domain-specific language") is reasonably well-described in the Apache Camel documentation. If you aren't using Camel-specific tooling to create the XML, however, it can be a bit fiddly to get the correct XML boilerplate (namespace URIs, etc). I hope that the comments in the code below make it reasonably clear how the route will work.
<!-- Define XML namespaces for Spring and camel-spring -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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">

  <!-- There can be multiple routes within a specific camelContext;
       here there is only one -->
  <camelContext xmlns="http://camel.apache.org/schema/spring">
    <route>
      <!-- Accept an incoming HTTP request using camel-jetty -->
      <from uri="jetty:http://0.0.0.0:9000/orders"/>
      <choice>
        <!-- Use choice-when to take action according to the XPath
             expression -->
        <when>
          <xpath>order/division='UK'</xpath>
          <to uri="file:uk-orders"/>
          <to uri="log://camelspringtest?level=INFO"/>
          <!-- Set the message body : this is the text that the 
               HTTP client will see -->
          <setBody><constant>Accepted UK order</constant></setBody>
        </when>
        <when>
          <xpath>order/division='DE'</xpath>
          <to uri="file:de-orders"/>
          <to uri="log://camelspringtest?level=INFO"/>
          <setBody><constant>Accepted DE order</constant></setBody>
        </when>
        <otherwise>
          <!-- Some sort of error handling, for cases where the 
               supplied data is invalid -->
          <setBody><constant>Error: unknown division code</constant></setBody>
          <to uri="log://camelspringtest?level=ERROR"/>
        </otherwise>
      </choice>
    </route>
  </camelContext>
</beans>
A note on the use of XPath might be in order: because the XML input has a division element within an order element, the value of that element is extracted using the expression order/division. A subtlety that does not affect this simple route, but can be problematic in real applications, is that the XML data enters the choice as a data stream, not as a Java primitive. The XML can therefore only be parsed once as the stream is read. Nested choices and similar complexities can therefore be difficult to implement. In such a case, look in the Camel documentation for 'stream caching.' Or, for small payloads, simply use convertBodyTo to convert the payload to a String.

Running Camel

To use the Maven Camel runner, just do:
$ mvn compile camel:run
Note:
The full source code has a logging configuration (log4j.properties
that suppresses log messages from Camel, to make those from the application more obvious. You might want to change this if troubleshooting is necessary)

Testing the route

To test the route, post some valid XML data to port 9000. On Linux, and probably other platforms, you can use curl to do this:
$ curl --header "Content-Type:application/xml" --data @test-uk.xml  http://localhost:9000/orders
Accepted UK order
Note:
Setting the Content-Type header is essential here — without it, curl will set the content type incorrectly to indicate encoded content. Camel will respect the Content-Type header and assume encoded data, when this data is simply raw XML
You should see each POST creating a new, numbered file in the uk-orders or de-orders directories.

Summary

The Maven Camel runner is a useful way to test a Camel route that is specified as Spring XML files, and is broadly compatible with Maven projects that build Camel routes into J2EE applications and OSGi bundles.

Downloads

Source code bundle

Copyright © 1994-2015 Kevin Boone. Updated Jan 17 2016