Apache Camel is a versatile open-source integration framework based on known Enterprise Integration Patterns
In order to understand what Apache Camel is, you need to understand what Enterprise Integration Patterns are. Much like the Gang of Four, Gregor Hope and Bobby Woolf authored the book Enterprise Integration Patterns (EIP) in which they described and documented a set of new patterns on how we design large component-based systems, where components can be running on the same process or in a different machines. Basic propose says systems should be message oriented, where components communicate with each others using messages and absolutely nothing else. They show us a complete set of patterns that we may choose from and implement in our different components that will together form the whole system.
Basics
Apache Camel is java library and engine that offers you the interfaces for the EIPs, the base objects, commonly needed implementations, debugging tools, a configuration system. It’s a complete production-ready framework for people who want to implement their solution to follow the EIPs. Apache Camel is a programmer tool for mediation and integration problems. Let’s understand it by looking at the entities.
Camel Objects
Lets’ start by basic Camel object: Message and Exchange.
Message
At the core there is a org.apache.camel.Message
. This object contains the data being carried and routed in Camel. Massages has a set following elements:
- Unique Identifier (
java.lang.String
) - Headers.
- The body (
java.lang.Object
). - The fault flag
Body could be any object. It means that its up to you to make sure that the receiver can understand the content of the message. When the sender and receiver use different body formats you can use a number of camel mechanisms to transform the data into an specific format. In many cases the conversion can happen automatically with pre-defined type converters.
Its a bit special thing to distinguish between normal and fault returns as defined by some Standards (e.g. WSDL).
Headers are organized as name-value pairs. The name is a unique, case-insensitive string, and the value is of type java.lang.Object.
Exchange
The org.apache.camel.Exchange
is abstraction for an exchange of messages as part of a “conversation”. Let’s make this abstraction more comprehensive by listing whats inside:
- ExchangeId
- MEP - a particular Message Exchange Pattern like
InOnly
orInOut
. - Exception, when it occurs at any time during routing.
- Properties are similar to message headers, but they last for the duration of the entire exchange also camel may add some properties to a particular exchange.
- IN-Message or request message is mandatory.
- OUT-Message or replay message exists if the MEP is defined as
InOut
.
Camel Context
Now let’s look on the big picture. We see different architectural pieces connecting to each other and the glue between them is actually Camel Context. Its a kind of a container that puts everything together, sometimes its synonym for Camel-Run-time.
Endpoint
A fundamental concept in Camel, Endpoint as the endpoint of a channel through out a system can send or receive messages. In Camel, endpoints are configured by URIs. At run-time Camel will look up an endpoint based on the URI notation. Let’s look at some examples:
//Pooling on data/inbox every 2 seconds
file:data/inbox?delay=2000
//JMS queueing with name order
jms:queue:order
//Run's external Application with output.txt as parameter.
exec:archiver.exe?output.txt
Component
Components are associated with The Endpoints URI, they are connected by Schema (like file:
, jms:
) and act as a factory of endpoints. There are over 80 Camel Componets currently (2012) and of course one can build custom component. Start by extending org.apache.camel.impl.DefaultComponent
.
Route
Route defines a path or a channel how a Message actually moves through the system. The routing engine self isn’t exposed to the developer, but the developer defines routes and trusts the engine for all the heavy lifting work (and boilerplate coding). Each route has a unique identifier that can be used for logging, debugging, monitoring, and starting and stopping routes.
Routes also have exactly one input source for messages, therefore they’re effectively tied to an input endpoint. Routes a defined in a domain-specific language (DSL). Camel provides java, scala, and XML-based Route-DSL.
//simple route.
from("file:data/inbox").to("jms:queue:order")
routing can get very flexible and defined by filters, multicasting, recipient lists, parallelism, and more. Since I want this article to be a short introduction I give you just some more commented examples. One of the interesting connection solutions is the usage of “direct:” schema, which provides direct, synchronous invocation of any consumers when receives a call from the producer.
//Every 10 seconds timer sends an Exchange to direct:prepare
from("timer://foo?fixedRate=true&period=10000").to("direct:prepare");
// Another Routes can begin from "direct:prepare"
// This now depends on timer, logging and putting a message to the queue.
from(direct:prepare).to("log:com.mycompany.order?level=DEBUG").to("jms:queue:order?jmsMessageType=Text");
Processor
org.apache.camel.Processor
is a Message consumer of Message Exchange. Processors are of course elements of Routes and can be used for message format translation or other transformation.
Processor myProcessor = new Processor() {
public void process(Exchange exchange) {
exchange.getBody();
//e.g do something with Body..
}
};
from("file:data/inbox").filter(header("foo").isEqualTo("bar"))
.process(myProcessor).to("jms:queue:order")
As we see processors can be used for various data transformations.
Example
Create new Camel project with maven (Camel archetypes overview). When selected maven will create sample project by:
mvn archetype:generate -DgroupId=org.holbreich -DartifactId=filecopy -DarchetypeGroupId=org.apache.camel.archetypes -DarchetypeArtifactId=camel-archetype-java -Dversion=1.0.0-SNAPSHOT
This project should contains something like the following initial code:
package org.holbreich.filecopy;
import org.apache.camel.main.Main;
public class MainApp {
/**
* A main() so we can easily run these routing rules in our IDE
*/
public static void main(String... args) throws Exception {
Main main = new Main();
main.enableHangupSupport();
main.addRouteBuilder(new MyRouteBuilder());
main.run(args);
}
}
and
package org.holbreich.filecopy;
import org.apache.camel.builder.RouteBuilder;
/**
* A Camel Java DSL Router
*/
public class MyRouteBuilder extends RouteBuilder {
/**
* Let's configure the Camel routing rules using Java code...
*/
public void configure() {
// here is a sample which processes the input files
// (leaving them in place - see the 'noop' flag)
// then performs content based routing on the message using XPath
from("file:src/data?noop=true")
.choice()
.when(xpath("/person/city = 'London'"))
.to("file:target/messages/uk")
.otherwise()
.to("file:target/messages/others");
}
}
This example is runnable already, try it out!
Please feel free to ask questions or improve.