Book Image

Instant Apache Camel Message Routing

By : Bilgin Ibryam
Book Image

Instant Apache Camel Message Routing

By: Bilgin Ibryam

Overview of this book

With new APIs and technologies emerging every day, the need for integrating applications is greater than ever before. With the right tools, integrating applications is not hard. Apache Camel is the leading open source integration and message orchestration framework. Apache Camel, which has a variety of connectors and features numerous well-known integration patterns, has an enormous advantage over home grown integration solutions. Instant Apache Camel Message Routing helps you to get started using the Camel routing engine and Enterprise Integration Patterns. This book will show you how to create integration applications using Apache Camel. You will learn how Camel works and how to leverage the Enterprise Integration Patterns for message routing. Instant Apache Camel Message Routing is a practical and step-by-step guide to Apache Camel and integration patterns. This book will show you how Apache Camel works and how it integrates disparate systems using Enterprise Integration Patterns. The book starts with a high level overview of the Camel architecture before diving into message routing principles. Then, it introduces a number of patterns, complete with diagrams, common use cases, and examples about how to use them with Camel. The book also shows you how to test and monitor Camel applications and cope with failure scenarios.
Table of Contents (7 chapters)

Routing messages to different destinations (Simple)


In the previous tutorial, we routed all the messages through the same processing steps. Integrating real applications usually involves more complex routing scenarios where each message type is processed differently. In this tutorial, we are going to route a message into different locations based on the message content, using a Context-Based Router pattern.

Getting ready

The complete source code for this tutorial is located under the following project: camel-message-routing-examples/routing-different-destinations.

How to do it...

We will extend the previous example by adding conditions to direct incoming files into different folders based on file names:

from("file://source")
        .choice()
        .when(simple("${in.header.CamelFileName} contains 'widget.txt'"))
            .to("file://widget")
        .when(simple("${in.header.CamelFileName} contains 'gadget.txt'"))
            .to("file://gadget")
        .otherwise()
            .to("log://org.apache.camel.howto?showAll=true");

How it works...

A Context-Based Router is similar to a switch statement or to the if then-elseif statement in Java. The incoming message will be directed to one of the possible channels, depending on the condition that is evaluated, usually against the message content. In our example, there are three possible destinations for the incoming messages, and the conditions are written using Simple language. The condition has to be a predicate, that is, an expression that returns only true or false. If the result is true, the message is routed into that channel of the Context-Based Router, otherwise the next condition in order is evaluated. Similar to the default case in a Java switch statement, there is an optional otherwise element for this pattern. If the message doesn't match any of the predicates, it will be directed to the default channel of the route.

Camel expressions operate on the routed message and are used as part of various integration patterns. There are two types of expressions: one that implements the Expression interface and can produce a value from any type, and the other that implements the Predicate interface and produces a Boolean result. Expressions give access to all parts of the routed message, which in Camel world is represented by the Exchange class and has the following structure:

The Exchange class wraps the mandatory In Message representing the request data coming from an inbound channel, and an optional Out Message for the response going into an outbound channel. Each message consists of a payload called Body with Object type and Headers, which is a Map for storing key-value pairs associated with the message. The Exchange class also has Properties for storing Camel specific data, Message Exchange Pattern (MEP), ExchangeId, and Exception field for tracking exceptions if any were encountered during routing. Usually, when a processor receives Exchange, it reads the data from In Message (including Body and Headers), and depending on MEP writes the processed results to Out Message or updates In Message, to be passed to the next processor in the route. In our example, file consumer reads a file from the source folder then puts its reference to the message body, and populates various headers with information about the file (this is where the CamelFileName header gets populated). Then the expressions in the Context-Based Router retrieve the file name from the headers and do the comparison. If the file name contains the string widget.txt the message is sent to the widget folder, otherwise the next condition is evaluated which does a similar comparison with the gadget.txt string. If the message doesn't satisfy any of the conditions, it is sent to the default channel where it is logged and not written to any folder.

There's more...

Next, we will have a look at the other expression languages that Camel supports, and how to make the routing even more dynamic, using Java beans for deciding which is the next endpoint for a message.

Expression languages

The Predicate statement used in the previous example was created using Simple language, but there are many other supported languages. It includes popular scripting languages such as Beanshell, Groovy, Ruby, Python and languages for working with XML, such as XPath, XQuery, the Unified EL, OGNL, among others. The choice of language usually depends on the message format and personal preferences, but Simple language is flexible enough for most occasions. Simple language is a home grown language developed by the Camel community for writing powerful expressions. It gives easy access to different parts of the Exchange, such as input body ${in.body} or a specific message header ${in.header.userId}, properties {property.someKey}, environment variables ${sysenv.someOtherKet}, and so on. It also has good operator support used mostly for predicates such as >=, contains, !=, regex, &&, ||, and so on.

Dynamic routing

A Context-Based Router can direct a message to the correct recipient if all the recipients are known in advance. All of the outbound channels of the Context-Based Router have to be specified as part of its definition, and only then it can choose one based on the message content. This introduces a dependency of the router to all possible destinations and prevents it from choosing a destination dynamically. Dynamic Router pattern solves this problem by choosing a destination for each message at runtime, and configuring itself using control messages from each participating destination.

In Camel, a Dynamic Router pattern is implemented with the dynamicRouter statement that accepts an expression to determine where the message should go next. After routing the message, the expression is evaluated again using the updated message to determine where the message should be routed next. Evaluating the expression and routing the message continues until the expression returns null to indicate the end of routing for that message. So it is important for the expression to return null at some point, otherwise Camel will continue routing the same message endlessly. Because of this complex nature, dynamicRouter expressions usually use Bean expressions:

from("direct:start")
    .dynamicRouter(method(DestinationChooser.class, "nextEndpoint"));

Note

For an example using the Dynamic Router, have a look at http://camel.apache.org/dynamic-router.html.