2009-02-15

Apache Camel and using compound predicates in routes

While reading a very a nice post by Roger Searjeant's on using Apache Camel in the health care space, and rocking to AC DC's new album Black Ice, got me on the track for the topic of this blog post.

How to use compound predicates in Apache Camel.

Roger is starting to grok Camel. And yes I admit it can take a little time to get the feeling and hang of it, but then you really get these "AHA/this is so cool" experiences. 

Roger wants to do content based routing, that is a very common EIP pattern to use. And Camel have first class support for this using its strong Predicate and Expression types. 

Roger wants to test if his HL7 message is either a ORM message type and the trigger event is 001. 

An example:
header("hl7.msh.messageType").isEqualTo("ORM")
AND
header("hl7.msh.triggerEvent").isEqualTo("001")

The problem is how to express the AND in the compound predicate?

Camel has support for combining predicate using all kind of binary operators in its: org.apache.camel.builder.PredicateBuilder class.

As the fluent builder can get a bit complex I like to divide, so we define our predicates outside the route:

Predicate p1 = header("hl7.msh.messageType").isEqualTo("ORM"):
Predicate p2 = header("hl7.msh.triggerEvent").isEqualTo("001");

Now we have our predicates and we can use the PredicateBuilder to create our compound predicate:

Predicate isOrm = PredicateBuilder.and(p1, p2);

And then we can refer to the isOrm predicate in our route.
when(isOrm)...

So Rogers route can be written as:
from("hl7listener")
    .unmarshal(hl7format)
    .choice()
        .when(isOrm).beanRef("hl7handler", "handleORM")
        .otherwise().beanRef("hl7handler", "badMessage")
    .end()
    .marshal(hl7format);
 
Inlining the compound predicates can be a bit cumbersome as the Java compiler can get a bit spooked when the fluent builders get long and complex. That is why we encourage you to split your route such as above. It also enhances the readably as the route above is a kind of high level diagram without all the minor details of predicates and expressions.  

2 comments:

Adam said...

Cool solution with a compound predicate. Very handy indeed.
Thanks

Claus Ibsen said...

You can even stack predicates so if you want to do a
AND + OR you can do:

Predicate p1 = ...
Predicate p2 = ...
Predicate p3 = ...

Predicate isOrm = PredicateBuilder.and(p1, p2);
Predicate isOrmOrFoo = PredicateBuilder.or(isOrm, p3).