Try ... Catch ... Finally
Camel supports the Java equivalent of try .. catch and finally directly in the DSL.
It aims to work like its Java sisters but with more power. Especially in Camel 2.0 where we gave this feature an overhaul.
In Camel we prefix the keywords with do to avoid having same keyword as Java. So we have:
- doTry
- doCatch
- doFinally
- end to end the block in Java DSL
Notice this document is based on how it works in Camel 2.0. In Camel 1.x this feature isn't as powerful and it uses a slight different keyword names.
About doCatch and its power over Java
The doCatch in Camel is empowered over its Java sister. First of all you can define multiple exceptions to catch in a single block. And secondly you can attach a onWhen predicate to signal if the catch should trigger or not at runtime.
To simulate rehrowing an exception from a doCatch you should use the handled predicate. If its evaluated to false Camel will reattach the exception on the Exchange.
And just like Java the order in which you have multiple doCatch blocks matter. Camel will iterate from the top going down and use the first doCatch that matches the exception and if the onWhen predicate matches as well (if any provided). This is the same behavior as the Exception Clause.
Using try .. catch .. finally in Java DSL
In the route below we have all keywords in action. As the code is based on a unit test we route using Mock.
from("direct:start")
.doTry()
.process(new ProcessorFail())
.to("mock:result")
.doCatch(IOException.class, IllegalStateException.class)
.to("mock:catch")
.doFinally()
.to("mock:finally")
.end();
And in the route below we want to indicate if an IOException occured we want to route it elsewhere and at the same time keep the exception so the original caller is notified about this exception. To do this we need to not rethrow the exception and this is why we use handled and set it to false to indicate, no we did not handle it so please keep the exception.
The 2nd exception block can be omitted but as the code is based on an unit test we want to test the behavior non IOException as well.
from("direct:start")
.doTry()
.process(new ProcessorFail())
.to("mock:result")
.doCatch(IOException.class)
.handled(false)
.to("mock:io")
.doCatch(Exception.class)
.to("mock:error")
.end();
And finally we have an example of the onWhen predicate in action. We can attach it to a doCatch block and at runtime determine if the block should be triggered or not.
In our case we only want to trigger if the caused exception message contains the damn word.
from("direct:start")
.doTry()
.process(new ProcessorFail())
.to("mock:result")
.doCatch(IOException.class, IllegalStateException.class)
.onWhen(exceptionMessage().contains("Damn"))
.to("mock:catch")
.doCatch(CamelExchangeException.class)
.to("mock:catchCamel")
.doFinally()
.to("mock:finally")
.end();
Using try .. catch .. finally in Spring DSL
We show the three sample samples using Spring DSL instead.
In the route below we have all keywords in action. As the code is based on a unit test we route using Mock.
An error occurred: http://svn.apache.org/repos/asf/camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/SpringTryProcessorMultipleExceptionTest.xml. The system administrator has been notified.
And in the route below we want to indicate if an IOException occured we want to route it elsewhere and at the same time keep the exception so the original caller is notified about this exception. To do this we need to not rethrow the exception and this is why we use handled and set it to false to indicate, no we did not handle it so please keep the exception.
The 2nd exception block can be omitted but as the code is based on an unit test we want to test the behavior non IOException as well.
<route>
<from uri="direct:start"/>
<doTry>
<process ref="processorFail"/>
<to uri="mock:result"/>
<doCatch>
<exception>java.io.IOException</exception>
<handled>
<constant>false</constant>
</handled>
<to uri="mock:io"/>
</doCatch>
<doCatch>
<exception>java.lang.Exception</exception>
<to uri="mock:error"/>
</doCatch>
</doTry>
</route>
And finally we have an example of the onWhen predicate in action. We can attach it to a doCatch block and at runtime determine if the block should be triggered or not.
In our case we only want to trigger if the caused exception message contains the damn word.
<route>
<from uri="direct:start"/>
<doTry>
<process ref="processorFail"/>
<to uri="mock:result"/>
<!-- here we catch the below 2 kind of exceptions but ONLY if the onWhen predicate matches
that means that the exception message should contain the string word 'Damn' -->
<doCatch>
<exception>java.io.IOException</exception>
<exception>java.lang.IllegalStateException</exception>
<onWhen>
<simple>${exception.message} contains 'Damn'</simple>
</onWhen>
<to uri="mock:catch"/>
</doCatch>
<doCatch>
<exception>org.apache.camel.CamelExchangeException</exception>
<to uri="mock:catchCamel"/>
</doCatch>
<doFinally>
<to uri="mock:finally"/>
</doFinally>
</doTry>
</route>
See Also