Dynamic Routes with Apache Camel

If you’ve spent any time with Apache Camel, you’ve likely wanted to make your routes more flexible. For example, you may want to redirect a route to a different endpoint based on changing criteria or conditions defined in a database. This post looks at two methods Apache Camel provides for altering your routes at runtime: Routing Slip and Dynamic Router.

Routing Slip

The first method to alter a route’s process is the Routing Slip pattern. The Routing Slip allows you to define a list of endpoints that should receive the message. In the Camel DSL, this looks like:

from("direct:start").routingSlip("decisionSlip");

The “decisionSlip” is header placed on the exchange containing a delimited list of the destination endpoints. The header can either be set on the ProducerTemplate:

producerTemplate.sendBodyAndHeader("direct:start", 
  order, "decisionSlip", 
  "direct:verify-account,direct:check-inventory,direct:place-order");

or using a bean method returning a list of endpoints:

from("direct:start")
  .setHeader("decisionSlip").method(OrderProcessorBean.class, "calculateRoute")
  .routingSlip("decisionSlip");

Additionally, you can use the @RoutingSlip annotation on a bean method, then call the bean in your route. First, the bean:

public class OrderProcessorBean {
  @RoutingSlip
  public String calculateRoute(@Body Order order) {...}
}

Calling the the OrderProcessorBean and invoking the annotated method looks like any other Camel route:

from("direct:start").bean(OrderProcessorBean.class);

While the @RoutingSlip annotation has its uses, I prefer to use other methods as the annotation isn’t obvious to the person reading or maintaining the route.

There are two important things to note about the Routing Slip. First and most obvious, the header containing the delimited list must be set in the route before the routingSlip(…) call is reached. The second point is the Routing Slip is only evaluated once, not after each step in the route. To determine the destination endpoint after each point in the route, we need to use a Dynamic Router.

Dynamic Router

Building on the Routing Slip is the Dynamic Router. Unlike the Routing Slip pattern, the Dynamic Router calculates the next endpoint at each step in the route. For example, if the route “direct:verify-account” returned an unverified account, the Dynamic Router can reroute to “direct:create-account”. The two steps to using a Dynamic Router are 1) define the logic and 2) define the route. The routing logic can be defined in a bean:

public class DynamicOrderProcessorBean {
  public String calculateRoute(@Body Order order, 
                               @Header(Exchange.SLIP_PREVIOUS) String prev) {
    if (prev == null) {
      return "direct:verify-account";
    }
    else if (order.getStatus() == OrderStatus.NO_ACCOUNT) {
      return "direct:create-account";
    }
    else if (order.getStatus() == OrderStatus.CHECK_INVENTORY) {
      return "direct:check-inventory";
    }
    else if (order.getStatus() == OrderStatus.IN_STOCK) {
      return "direct:place-order";
    }
    else {
      return null;
    }
  }
}

The above code is obviously contrived, but you get the idea. With the bean defined, the next step is to define the route:

from("direct:start")
  .dynamicRouter(DynamicOrderProcessorBean.class, "calculateRoute");

That’s really all there is to the Dynamic Router. Camel also supports a @DynamicRouter annotation which has similar usage to the @RoutingSlip annotation.

To find out more information on dynamic routing with Apache Camel, be sure to read the documentation on the Routing Slip and Dynamic Router patterns.

Share

Do you have something to say?

Your email is never published nor shared.
Required fields are marked *