Camel's choice() and when() - with examples

Apache Camel contains a powerful feature called the Content Based Router. This allows you to process messages differently based on their content. In this article I’m going to show you how to use the Content Based Router and show you the different options available for writing your conditions. Along the way there’s also some some example code.

The Basics

When you need to conditionally route a message based on some fact, you can use the choice and when constructs.

These are quite similar to the if/else construct in Java. However, in Camel, the equivalent words are when and otherwise.

A typical if/else block in Java might look something like this:

if (condition) {
    // ... do something ...
} else if (condition) {
    // ... do something else ...
} else {
    // otherwise do this
}

But in Camel’s Java DSL, it would look something like this:

from(anEndpoint)
    .choice()
        .when(someCondition).to(firstEndpoint)
        .when(anotherCondition).to(secondEndpoint)
    .otherwise()
        .to(thirdEndpoint)
    .end();

Notice how:

  • We start the block with choice() - this tells Camel that the following lines will contain some conditions to evaluate.

  • Each when() method indicates a new condition to be evaluated, similar to an if in core Java

  • The method otherwise() defines what to do when none of the previous when() conditions equal true.

  • The block ends with a .end().

How to build a when condition in Camel

You have many different options available to you when writing your when() condition. In Camel, this is called building a predicate. You can use several languages to build your predicate, but the most common ones are:

  • Simple language, Camel’s own language for building simple string comparisons

  • Header, for building a condition based on the value of a Header on the Exchange

  • Bean language, when you want to use the result of a Java method call

  • XPath or JSONPath, when you want to search in an XML document or JSON document

(For a complete list of the languages supported, see the languages entry in the Camel documentation.)

Example Camel predicates

Here are some examples of Predicates in Camel, along with their meaning:

Example predicate What it does
.when(body().contains("Hello, world!")) When the Body of the message contains the string "Hello, world!"
.when().simple("${body} == 'Disco'") Using the Simple language to test when the Body of the message is exactly "Disco"
.when(header("country").isEqualTo("GB")) When a Header with the name country equals "GB"
.when(header("CamelFileName")
.isEqualTo("disco.txt"))
Using the File component, check that the name of the received file is disco.txt
.when(header("CamelFileName").endsWith(".xml")) Using the File component, using PredicateBuilder.endsWith() to check that the name of the file received ends with .xml
.when(header("country").regex("US|FR|DE")) Using Camel’s regex method, check that the value of the Header with the name country is one of US, FR or DE.
.when(xpath("/customer/@status = 'gold'")) Using Camel’s XPath support, check that the value of the status attribute on the customer element is equal to gold

Adding actions to your when() condition

Each when() condition basically builds a mini-pipeline. You can follow a when() with to(), to tell Camel to route the message to an endpoint, based on a certain condition.

For example, the code fragment below will route a message to an ActiveMQ queue called hello if it contains the text Hello, world!:

.when(body().contains("Hello, world!")).to("activemq:queue:hello")

You can also stack multiple Camel DSL functions in your mini-pipeline, in the same way as you would write multiple statements in an if block in Java.

Here’s an example of using multiple statements in a when() condition. It changes the body of the message using the setBody() method, before writing it out to a folder on disk, using the File component:

.when(body().contains("Hello, world!"))
      .setBody(simple("Goodbye, world!"))
      .to("file:customers/out/goodbye")

Using ‘otherwise’ to specify your ‘else’ block

Once you’ve defined all of your when() conditions and actions, you might want to define an action that should be taken if your message does not match the previous conditions.

Just like an else statement, Camel’s otherwise allows you to do this. For example, you might want to log the message, or move it to a Dead Letter Queue.

.otherwise().to("activemq:queue:unprocessed")

Putting it all together

Now let’s put everything we’ve learned in this article into an example that shows how you might typically use choice() and when() in your Camel routes.

from("file:src/data?noop=true")
    .to("log:ordersReceived")
    .choice()
        // If the customer has a type="business"
        .when(xpath("/order/customer/@type = 'business'"))
            .log("Business order received")
            .to("file:out/business")

        // If the customer has a type="personal"
        .when(xpath("/order/customer/@type = 'personal'"))
            .log("Personal order received")
            .to("file:out/personal")

        .otherwise()
            .log("Other order received")
            .to("file:out/others")
    .end();

In the example above:

  • The route begins with an instruction to use the File component to read files from a location on disk (src/data)

  • Information about the file received is written to the log, using the logger name ordersReceived.

  • An XPath test is applied to the incoming file to check if it is a business customer order. If so, the file is moved to the out/business folder.

  • A second test checks if the order is from a personal customer. If so, the file is moved to the out/personal folder.

  • Finally, if neither of the above two conditions evaluate to true, the file is moved to the out/others folder.

Has this helped you understand how to use when, choice and otherwise in your Camel routes? Please post your feedback in the comments below!