Apache Camel: Integration Nirvana
• Pluggable data formats and type converters for easy message transformation between Artix Data Services, CSV, EDI, Flatpack, HL7, JAXB, JSON, XmlBeans, XStream, Zip, Camel-bindy, etc.
• Pluggable languages to create expressions or predicates for use in the DSL. Some of these languages include: EL, JXPath, Mvel, OGNL, BeanShell, JavaScript, Groovy, Python, PHP, Ruby, SQL, XPath, XQuery, etc.
• Support for the integration of beans and POJOs in various places in Camel.
• Excellent support for testing distributed and asynchronous systems using a messaging approach
• and much more...
Example
A motorcycle parts business, Rider Auto Parts, supplies parts to motorcycle manufacturers. Over the years they've changed the way they receive orders several times. Initially, orders were placed by uploading CSV files to an FTP server. The message format was later changed to XML. Currently they provide a web site to submit orders as XML messages over HTTP. All of these messages are converted to an internal POJO format before processing.
Rider Auto Parts states to any new customers to use the web interface to place orders. However, because of existing agreements with customers, they must keep all the old message formats and interfaces up and running.
Solution using EIPs
Rider Auto Parts faces a pretty common problem; over years of operation businesses acquire software baggage in the form of transports/data formats that are popular at the time. Using patterns from the EIP book we can envision the solution as something like Figure 2.
Figure 2: This shows the solution to Rider Auto Parts integration problem using notation from the Enterprise Integration Patterns book.
So we have several patterns in use here.
1. There are two Message Endpoints; one for FTP connectivity and another for HTTP.
2. Messages from these endpoints are fed into the incomingOrderQueue Message Channel
3. The messages are consumed from the incomingOrderQueue and routed by a Content-Based Router to one of two Message Translators. As the EIP name implies, the routing destination depends on the content of the message. In this case we need to route based on whether the content is a CSV or XML file.
4. Both Message Translators convert the message content into a POJO, which is fed into the orderQueue Message Channel.
The whole section that uses a Content-Based Router and several Message Translators is referred to as a Normalizer. This composite pattern has a unique graphic to depict it but was left out here in favor of its sub-patterns to make things clearer.
Implementation using Camel
As mentioned before, Camel has a small core set of components included by default. The rest of the components exist as separate modules. In applications that require many types of connectivity it is useful to figure out what Camel modules to include. Listing 1 shows the dependencies using Apache Maven for the Camel implementation of the Rider Auto Parts example. Of course, you don't need to use Apache Maven for dependencies - it is just the easiest way to rapidly add new dependencies to your applications. The list of dependencies includes support for core Camel, ActiveMQ, JAXB marshaling, CSV marshaling, and HTTP. To make the example easier to try out, I've opted to use the File endpoint instead of the FTP. If we were using the FTP endpoint we would need to add a dependency on the camel-ftp module as well.
Listing 1: Maven dependencies for the Camel implementation
<dependencies>
<!-- Core Camel support -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>${camel-version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring</artifactId>
<version>${camel-version}</version>
</dependency>
<!-- ActiveMQ connectivity for Camel -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-camel</artifactId>
<version>${activemq-version}</version>
</dependency>
<!-- Add support for JAXB marshaling -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jaxb</artifactId>
<version>${camel-version}</version>
</dependency>
<!-- Add support for CSV marshaling -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-csv</artifactId>
<version>${camel-version}</version>
</dependency>
<!-- Add support for HTTP -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jetty</artifactId>
<version>${camel-version}</version>
</dependency>
<!-- Embedded ActiveMQ broker -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
<version>${activemq-version}</version>
</dependency>
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>${xbean-spring-version}</version>
</dependency>
</dependencies>
| Attachment | Size |
|---|---|
| camelArch1.jpg | 47.49 KB |
| riderAutoEips1.jpg | 25.64 KB |
| DZone_Camel_Article_JonathanAnstey.pdf | 647.95 KB |
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)











Comments
Craig replied on Tue, 2009/03/24 - 4:37am
James Strachan replied on Tue, 2009/03/24 - 4:58am
davsclaus replied on Tue, 2009/03/24 - 6:09am
janstey replied on Tue, 2009/03/24 - 7:04am
in response to: jstrachan
janstey replied on Tue, 2009/03/24 - 7:06am
in response to: davsclaus
janstey replied on Tue, 2009/03/24 - 7:49am
in response to: codecraig
Craig,
I just uploaded a PDF version of this article. Enjoy!
http://architects.dzone.com/sites/all/files/DZone_Camel_Article_JonathanAnstey.pdf
java developer replied on Tue, 2009/03/24 - 10:29am
janstey replied on Tue, 2009/03/24 - 12:08pm
in response to: an114162
To handle large messages you could do a couple of things...
1. Make sure you use input streams instead of loading messages into memory. For the HTTP endpoint example, the message is streamed by default. However, you may need to tune your route for these kinds of messages. For instance, in Listing 3 the convertBodyTo(String.class) method is used to convert the incoming stream into a String so that we can do things like JAXB unmarshalling on it. This will of course load the message into memory so we may have to do something else here to handle the large message.
2. Use the Claim Check EIP (http://camel.apache.org/claim-check.html) to store the larger portion of your message for retrieval later.
For other Camel capabilities, you can take a peek at the online documentation, Camel User Guide, and FUSE Mediation Router documentation. For specific inquires, you can alway find help on the Apache and FUSE forums.
Scott Stanlick replied on Thu, 2009/03/26 - 7:26am
janstey replied on Thu, 2009/04/02 - 1:26pm
in response to: stanlick
Glad you enjoyed it! Yeah, Mule is the other competitor with a few years under the belt like Camel. Two new projects that implement EIPs are Spring Integration and Project Fuji.
I should also mention ServiceMix here which has had support for EIPs since before Camel was started. The latest version of ServiceMix supports EIPs through Camel in favour of the old EIP component.
Charles Moulliard replied on Tue, 2009/03/31 - 5:47am
Hi John,
Congratulations for this awesome article. You have described in a 4 pages document the "quintessence" of what Camel is.
BTW : May I suggest that you add also in your dataformat section : Camel-bindy which is a new DataFormat component who allows you to map CSV file directly to your pojo (using Java Annotation), Fix messages format, and more in the future.
remark : I will publish soon a tutorial on Camel with Bindy, OSGI, CXF and ServiceMix4
Regards,
Charles
janstey replied on Tue, 2009/03/31 - 7:36am
in response to: charliem
Charles,
Just added it to the list. I actually wanted to use camel-bindy in the example but it is a new feature in Camel 2.0, which is not released yet (I'm using Camel 1.6). To give readers a tease, with camel-bindy you can add annotations for CSV to POJO mapping just like we did for the XML to POJO mapping. The Order class would have extra annotations like
and then in our OrderRouter we can simplify the CSV transformation as follows
public class OrderRouter extends RouteBuilder {@Override
public void configure() throws Exception {
JaxbDataFormat jaxb = new JaxbDataFormat("org.fusesource.camel");
BindyCsvDataFormat csv = new BindyCsvDataFormat("org.fusesource.camel");
...
from("jms:incomingOrderQueue")
.convertBodyTo(String.class)
.choice()
.when().method("orderHelper", "isXml")
.unmarshal(jaxb)
.to("jms:orderQueue")
.when().method("orderHelper", "isCsv")
.unmarshal(csv)
.to("jms:orderQueue");
}
}
Notice how we have added a new bindy DataFormat and used it instead of the default CSV unmarshaller. In this case we have also elimintaed the need for the OrderNormalizer bean as the bindy DataFormat handles all of the CSV to POJO transformation.
petitstream replied on Tue, 2009/03/31 - 1:17pm
janstey replied on Tue, 2009/03/31 - 2:18pm
in response to: petitstream
I used the Microsoft Visio scencil from the EIP books website
http://www.enterpriseintegrationpatterns.com/download/EIP_Visio_stencil.zip
Of course, I added a lot of extra beautification too, which just takes time :)
petitstream replied on Tue, 2009/03/31 - 4:24pm
in response to: janstey
davsclaus replied on Fri, 2009/04/03 - 8:12am
Link to blog entry: eip-patterns-in-omnigraffle