2008-11-23

Apache Camel Community helps drive the roadmap

We, the good Camel riders, get numerous times positive feedback from end users that they appreciate the great community that spins around Camel.

As a rider myself I enjoy all the great feedback we receive and it helps steer the Camel in the right direction.

Lately I have been in dialog with an end-user that had a bit more advanced use case for routing and handling certain custom exceptions. So after discussing and realizing that he needed an improvement in Camel I created the ticket for it.

The use case
The use case is that in case of a org.my.exception.FunctionalException is thrown and this exception is in a certain state then route the message to a certain bean handler. This can be expressed like this:

<onException>
<exception>org.my.exception.FunctionalException<exception>
<redeliveryPolicy maximumRedeliveries="0"/>
<handled>
<constant>true</constant>
<handled>
<to uri="bean:myOwnErrorHandler"/>
<onException>

The problem
The problem by its core is that Camel in case of an exception being thrown will look for (if any) onException that should handle it. And currently you can only state a list of exceptions and if the thrown exception is an instanceof on of these exceptions Camel will choice the first onException defined that matches. But the end-users needed to alter this choice to also express a predicate so the matching will only occur if the predicate is true as well.

The algorithm is: FunctionalException is thrown + hasSpecialEnumCode returns true

Camel is very flexible and the end user could actually implement this right out of the box, however he needed to provide his own ExceptionPolicyStrategty that contains the logic to select which onException to handle the given thrown exception. So he could have implemented the org.apache.camel.processor.exceptionpolicy.ExceptionPolicyStrategy interface and defined Camel to use this policy instead of the default. Yes Camel is flexible.
But as the author of this policy in the first place I picked up the glove to add this directly to Camel. Here is a short summary how this was done:

The solution
1)
First of all I added the when predicate to the onException so you can add it (optional).

@XmlElement(name = "when", required = false)
private WhenType when;

Camel supports both Java DSL and spring DSL. As the Spring DSL XSD is auto generated we only add the JAXB binding annotations to control the XSD.

2)
I then had to improve the DefaultExceptionPolicyStrategy to consider this new predicate (when).

Basically I had to add this piece of code, that in case if a when predicate is provided will match it, for onException without this predicate it returns true.

protected boolean matchesWhen(ExceptionType type, Exchange exchange) {
if (type.getWhen() == null || type.getWhen().getExpression() == null) {
// if no predicate then it's always a match
return true;
}
return type.getWhen().getExpression().matches(exchange);
}

Now we have a method to determine if there is a match or not, then I just had to skip non matching in the iteration while Camel finds the correct onException to use

// must match
if (!matchesWhen(type, exchange)) {
if (LOG.isDebugEnabled()) {
LOG.debug("The type did not match when: " + type);
}
continue;
}

That is basically it.

And the final route
Now we can add the onWhen predicate that will call a method on the bean mySpecialEnumChecker that will return either true or false. So the onException is only triggered when the exception FunctionalException is thrown + the predicate returns true.

The route is now:
<onException>
<exception>org.my.exception.FunctionalException<exception>
<onWhen>
<method bean="mySpecialEnumChecker" method="hasEnum"/>
<onWhen>
<redeliveryPolicy maximumRedeliveries="0"/>
<handled>
<constant>true</constant>
<handled>
<to uri="bean:myOwnErrorHandler"/>
<onException>


Conclusion
Apache Camel valuates its community and we strive to be there for the community and together steer Camel in the right direction.

No comments: