In Camel, there are two abstractions for modeling messages, both of which we’ll cover in this section.
- org.apache.camel.Message—The fundamental entity containing the data being carried and routed in Camel
- org.apache.camel.Exchange—The Camel abstraction for an exchange of mes- sages. This exchange of messages has an “in” message and as a reply, an “out” message
Messages are the entities used by systems to communicate with each other when using messaging channels. Messages flow in one direction from a sender to a receiver, Messages have a body (a payload), headers, and optional attachments,
Messages are uniquely identified with an identifier of type java.lang.String. The identifier’s uniqueness is enforced and guaranteed by the message creator, it’s protocol depen- dent, and it doesn’t have a guaranteed format.
For protocols that don’t define a unique message identification scheme, Camel uses its own UID generator.
HEADERS AND ATTACHMENTS
Headers are values associated with the message, such as sender identifiers, hints about content encoding, authentication infor- mation, and so on. Headers are name-value pairs; the name is a unique, case-insensitive string, and the value is of type java. lang.Object. This means that Camel imposes no constraints on the type of the headers. Headers are stored as a map within the message. A message can also have optional attachments, which are typically used for the web service and email components.
An exchange in Camel is the message’s container during routing. An exchange also provides support for the various types of interactions between systems, also known as message exchange patterns (MEPs). MEPs are used to differentiate between one-way and request-response messaging styles. The Camel exchange holds a pattern property that can be either
- InOnly—A one-way message (also known as an Event message). For example, JMS messaging is often one-way messaging.
- InOut—A request-response message. For example, HTTP-based transports are often request reply, where a client requests to retrieve a web page, waiting for the reply from the server.
Camel doesn’t start magically by itself. Often it’s the server (container) that Camel is running inside that invokes the start method on CamelContext, starting up Camel. This is also what you saw in chapter 1, where you used Camel inside a standalone Java application. A standalone Java application isn’t the only deployment choice—you can also run Camel inside a container such as Spring or OSGi.
Regardless of which container you use, the same principle applies. The container must prepare and create an instance of CamelContext up front, before Camel can be started.
Camel provides the CamelNamespaceHandler.
When using Camel in the Spring XML file, you would define the
The http://camel.apache.org/schema/spring namespace is the Camel custom namespace. To let Spring know about this custom namespace, it must be identified in the META-INF/spring.handlers, where you map the namespace to the class implementation:
The CamelNamespaceHandler is then responsible for parsing the XML and dele- gating to other factories for further pro- cessing. One of these factories is the Camel- ContextFactoryBean, which is responsible for creating the CamelContext that essen- tially is your Camel application.
When Spring is finished initializing, it signals to third-party frameworks that they can start by broadcasting the Context- RefreshedEvent event.
At this point, CamelContext is ready to be started. What happens next is the same regardless of which container or deploy- ment option you’re using with Camel.
CamelContext is started by invoking its start method. The first step is to determines whether or not autostartup is enabled for Camel. If it’s disabled, the entire startup process is skipped. By default, Camel is set to autostart, which involves the following four steps.
1 Start internal services—Prepares and starts internal services used by Camel, such as the type-converter mechanism.
2 Compute starting order—Computes the order in which the routes should be started. By default, Camel will start up all the routes in the order they are defined in the Spring XML files or the RouteBuilder classes. We’ll cover how to configure the order of routes in section 13.1.3.
3 Prepare routes—Prepares the routes before they’re started.
4 Start routes—Starts the routes by starting the consumers, which essentially opens
the gates to Camel and lets the messages start to flow in.
After step 4, Camel writes a message to the log indicating that it has been started and that the startup process is complete.
An endpoint is the Camel abstraction that models the end of a channel through which a system can send or receive messages.
In Camel, you configure endpoints using URIs, such as
and you also refer to endpoints this way. At runtime, Camel will look up an endpoint based on the URI notation.
The scheme denotes which Camel component handles that type of endpoint. In this case,
the scheme of file selects the FileComponent.
The FileComponent then works as a factory creat-
ing the FileEndpoint based on the remaining parts of the URI.
The context path data/ inbox tells the FileComponent that the starting folder is data/inbox.
The option, delay=5000 indicates that files should be polled at a 5 second interval.
There’s more to an endpoint than meets the eye.
Queues are strictly point-to-point, where each message has only one consumer. Topics operate on a publish/subscribe scheme; a single message may be delivered to many consumers if they have subscribed to the topic.
JMS also provides a ConnectionFactory that clients (like Camel) can use to cre- ate a connection with a JMS provider. JMS providers are usually referred to as brokers because they manage the communication between a message producer and a mes- sage consumer.
To connect Camel to a specific JMS provider, you need to configure Camel’s JMS com- ponent with an appropriate ConnectionFactory.
Apache ActiveMQ is one of the most popular open source JMS providers, and it’s the primary JMS broker that the Camel team uses to test the JMS component.
There are two types of JMS destinations: queues and topics. The queue is a point-to-point channel, where each message has only one recipient. A topic delivers a copy of the message to all clients who have subscribed to receive it.
o in the case of Apache ActiveMQ, you can create an ActiveMQConnectionFactory
that points to the location of the running ActiveMQ broker:
ConnectionFactory connectionFactory =
The vm://localhost URI means that you should connect to an embedded broker named “localhost” running inside the current JVM. The vm transport connector in ActiveMQ creates a broker on demand if one isn’t running already, so it’s very handy for quickly testing JMS applications; for production scenarios, it’s recommended that you connect to a broker that’s already running.
Next, when you create your CamelContext, you can add the JMS component as follows:
CamelContext context = new DefaultCamelContext();
The JMS component and the ActiveMQ-specific connection factory aren’t part of the camel-core module. In order to use these, you’ll need to add some dependencies to your Maven-based project. For the plain JMS component, all you have to add is this:
The connection factory comes directly from ActiveMQ, so you’ll need the following dependency:
Once the JMS component is configured, you can start sending and receiving JMS mes- sages at your leisure. Because you’re using URIs, this is a real breeze to configure.
Let’s say you want to send a JMS message to the queue named incomingOrders. The URI in this case would be
This is pretty self-explanatory. The “jms” prefix indicates that you’re using the JMS component you configured before. By specifying “queue”, the JMS component knows to send to a queue named incomingOrders. You could even have omitted the queue
qualifier, because the default behavior is to send to a queue rather than a topic.
NOTE Some endpoints can have an intimidating list of endpoint URI proper- ties. For instance, the JMS component has about 60 options, many of which are only used in specific JMS scenarios. Camel always tries to provide built-in defaults that fit most cases, and you can always find out what the default values are by browsing to the component’s page in the online Camel documentation.
Using Camel’s Java DSL, you can send a message to the incomingOrders queue by using the to keyword like this:
This can be read as sending to the JMS queue named incomingOrders.
Using the Spring CamelContext as a runtime and the Java DSL for route development is a great way of using Camel. In fact, it’s the most frequent usage of Camel.
You saw before that you can explicitly tell the Spring CamelContext what route builders to load. You can do this by using the routerBuilder element:
Being this explicit results in a clean and concise definition of what is being loaded into Camel.
Sometimes, though, you may need to be a bit more dynamic. This is where the packageScan and contextScan elements come in:
This packageScan element will load all RouteBuilder classes found in the camelinac- tion.routes package, including all subpackages.
You can even be a bit more picky about what route builders are included:
In this case, you’re loading all route builders in the camelinaction.routes package, except for ones with “Test” in the class name. The matching syntax is similar to what is used in Apache Ant’s file pattern matchers.