Routes tips, tricks and gotchas
Best practices
Compartmentalize route logic
The Direct component makes it easy to create sub-routines within a given context allowing you to separate the logic of your route in different chunks.
In the following example, we create a route that queries information from a database and treats each row of the results in a separate sub-routine.
<routes xmlns="http://camel.apache.org/schema/spring" xmlns:u="http://www.systar.com/aluminium/camel-util">
<route>
<from uri="timer://foo?repeatCount=1"/>
<to uri="jdbc:issuesQuery"/>
<!-- We execute a query against a database that stores information for a bug-tracking application -->
<split>
<simple>${body}</simple>
<to uri="direct:row"/>
</split>
</route>
<route>
<from uri="direct:row"/>
<setHeader headerName="issueId" >
<simple>body[issueId]</simple>
</setHeader>
<!-- Do some computing on the values retrieved from the database -->
<to uri="tnd-absorption:createIssues"/>
</route>
</routes>
Tips
Comparing Comparable objects in simple predicates
Example of Comparable
types: java.util.Date
or org.joda.time.ReadableInstant
Simple predicates automatically use the compareTo
methods for the <
, >
, <=
and >=
operators. The second object will be converted to the type of the first one.
<choice>
<when>
<simple>${body['first date']} < ${body['second date']}</simple>
...
</when>
</choice>
SEDA and VM endpoint
The SEDA endpoint and VM endpoint rely on an in-memory queue to store the message between producer and consumer. When producer is faster than consumer the queue is growing. Since the default configuration doesn't limit the queue size it may lead to consuming too much memory and OutOfMemoryError may appear. To avoid that, always configure SEDA or VM endpoint in order to limit the queue size. This is done by setting the following properties:
size=xxx
– Indicates the maximum number of messages to be queued.
blockWhenFull=true
– When the queue is full, the default behavior is to fail and throw an exception. Most of the time, it is not the expected behavior, it is recommended to wait to have some place in the queue.
Both parameters must be set on the both sides (ie to and from). For example (given for SEDA only, the same can be applied to VM endpoint):
<route>
....
<to uri="seda:message?size=16&blockWhenFull=true" />
</route>
<route>
<from uri="seda:message?size=16&blockWhenFull=true" />
...
</route>
If the processing of the message queue needs to be multithreaded, the SEDA consuming route can specify the number of processing thread with the property concurrentConsumers
:
<route>
<from uri="seda:message?size=16&blockWhenFull=true&concurrentConsumers=4" />
...
</route>
Gotchas
Description
<to uri="file://{{DataPath}}/Shifted?charset=UTF-8&fileName=${header.NewFileName}&fileExist=Append"/>
can have awfully slow writing performance _ at least under "low" end laptop
Workaround
Use the forceWrites = false
option.
<to uri="file://{{DataPath}}/Shifted?charset=UTF-8&fileName=${header.NewFileName}&fileExist=Append&forceWrites=false"/>
Evaluating a value inside a <simple> tag inside a <setHeader> tag does not work
Description
<setHeader headerName="EvaluateMe">
<simple type="java.lang.Boolean">${body['SomeValue']} == 0</simple>
</setHeader>
The above code produces a String, no matter what... For instance, if body['SomeValue'] is set to 0, the above code sets the header EvaluateMe to "0 == 0"
instead of true
.
Workaround
To work around the limitation, you can use a choice tag:
<choice>
<when>
<simple>${body['SomeValue']} == 0</simple>
<setHeader headerName="EvaluateMe">
<simple type="java.lang.Boolean">true</simple>
</setHeader>
</when>
<otherwise>
<setHeader headerName="EvaluateMe">
<simple type="java.lang.Boolean">false</simple>
</setHeader>
</otherwise>
</choice>
or a groovy script (slower to run, but more concise):
<setHeader headerName="EvaluateMe">
<groovy>request.body['SomeValue'] == 0 ? true : false</groovy>
</setHeader>