Apache Camel: Integration Nirvana
Take any integration project and you have multiple applications talking over multiple transports on multiple platforms. As you can imagine, in large enterprise applications this can get complex very fast. Much of the complexity stems from two issues:
1. dealing with the specifics of applications and transports, and
2. coming up with good solutions to integration problems.
Making your applications speak transports and APIs is relatively easy on its own. I'm sure everyone knows how to send JMS messages to their broker of choice; though it still requires in depth knowledge of the JMS specification, which many developers may not have. On top of that, what happens when you want to route that JMS message to another application? You then have to take care of mapping the JMS message to the application plus handle any new concepts related to the application. Add a dozen other applications into the mix and you've got quite a headache on your hands.
Ignoring the mechanics of how to connect with multiple transports and APIs, we can focus on the high level design of how applications interact. Fortunately, most solutions to enterprise integration problems have been formalized already. Gregor Hohpe and Bobby Woolfe's book, Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions, boils down years of experience from enterprise architects into a set of sixty five Enterprise Integration Patterns (EIPs). This is great but we still have to hand code all parts of these patterns; these are not packaged solutions, only recommendations.
Apache Camel was created with the intention of addressing these two issues. In this article I'll show you how it actually does this.
What is Camel?
Apache Camel is an open source Java framework that focuses on making integration easier and more accessible to developers. It does this by providing:
• concrete implementations of all the widely used EIPs
• connectivity to a great variety of transports and APIs
• easy to use Domain Specific Language (DSL) to wire EIPs and transports together
Figure 1 shows how these three items actually map to Camel concepts. To give you a good understanding of how Camel is organized, we will discuss Components, Endpoints, Processors, and the Domain Specific Language (DSL). There is of course a lot more going on here under the hood but we'll leave that for another discussion.
Figure 1: High level view of Camel's architecture.
Components are the extension point in Camel to add connectivity to other systems. The core of Camel is very small to keep dependencies low, promote embeddability, etc. and as a result contains only 12 essential components. There are over 60 components outside the core. To expose these systems to the rest of Camel, Components provide an Endpoint interface. By using URIs, you can send or receive messages on Endpoints in a uniform way. For instance, to receive messages from a JMS queue aQueue and send them to a file system directory "c:/tmp", you could use URIs like "jms:aQueue" and "file:c:\tmp".
Processors are used to manipulate and mediate messages in between Endpoints. All of the EIPs are defined as Processors or sets of Processors. As of writing, Camel supports 41 patterns from the EIP book, 6 other integration patterns, and many other useful Processors.
To wire Processors and Endpoints together, Camel defines a Java DSL. The term DSL is used a bit loosely here as it usually implies the involvement of a compiler or interpreter that can process keywords specific to a particular domain. In Camel, DSL means a fluent Java API that contains methods named like terms from the EIP book. Its best explained with an example
from("jms:aQueue")
.filter().xpath("/person[@name='Jon']")
.to("file:c:\tmp");
Here we define a routing rule in a single Java statement that will consume messages from the "jms:aQueue" Endpoint, send them through a Message Filter Processor, which will then send on messages passing the XPath condition to the "file:c:\tmp" endpoint. Messages failing the condition will be dropped.
You can also configure your routes in a XML-based Spring configuration file. This configuration file is a lot more verbose and less auto complete friendly than the Java DSL; many prefer it though because of its direct access to Spring concepts and no requirement for compilation after changes. Here is what the earlier example would look like in Spring:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="jms:aQueue"/>
<filter>
<xpath>/person[@name='Jon']</xpath>
<to uri="file:c:\tmp"/>
</filter>
</route>
</camelContext>
| 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 Wickesser replied on Tue, 2009/03/24 - 4:37am
James Strachan replied on Tue, 2009/03/24 - 4:58am
Claus Ibsen replied on Tue, 2009/03/24 - 6:09am
Jonathan Anstey replied on Tue, 2009/03/24 - 7:04am
in response to:
James Strachan
Jonathan Anstey replied on Tue, 2009/03/24 - 7:06am
in response to:
Claus Ibsen
Jonathan Anstey replied on Tue, 2009/03/24 - 7:49am
in response to:
Craig Wickesser
Craig,
I just uploaded a PDF version of this article. Enjoy!
http://architects.dzone.com/sites/all/files/DZone_Camel_Article_JonathanAnstey.pdf
Javadevel Javad... replied on Tue, 2009/03/24 - 10:29am
Jonathan Anstey replied on Tue, 2009/03/24 - 12:08pm
in response to:
Javadevel Javadevelva
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
Jonathan Anstey replied on Thu, 2009/04/02 - 1:26pm
in response to:
Scott 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
Jonathan Anstey replied on Tue, 2009/03/31 - 7:36am
in response to:
Charles Moulliard
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.
Ben slim replied on Tue, 2009/03/31 - 1:17pm
Jonathan Anstey replied on Tue, 2009/03/31 - 2:18pm
in response to:
Ben slim
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 :)
Ben slim replied on Tue, 2009/03/31 - 4:24pm
in response to:
Jonathan Anstey
Claus Ibsen replied on Fri, 2009/04/03 - 8:12am
Link to blog entry: eip-patterns-in-omnigraffle
Kai Wähner replied on Tue, 2011/01/04 - 11:22am
Raj Kapoor replied on Mon, 2011/03/14 - 12:58pm
Jonathan Anstey replied on Thu, 2011/05/19 - 7:56am
Manish Chowdhary replied on Mon, 2012/04/02 - 7:44pm
Jemmi John replied on Thu, 2012/04/19 - 12:02am
Mike Lurset replied on Fri, 2013/05/17 - 10:25am
I did get some errors when I tried to run this using Maven. Simply adding some repositories and plugin repositories to the POM.xml file solved my problems. driversedguy.tumblr.com
Mike Lurset replied on Sun, 2013/05/19 - 3:30am