...
To get started we give quick sample before digging into how it works.
For example if you want to perform a specific piece of processing if a certain exception is raised you can do this simply via:
Code Block |
---|
onException(ValidationException.class).
to("activemq:validationFailed");
from("seda:inputA").
to("validation:foo/bar.xsd", "activemq:someQueue");
from("seda:inputB").to("direct:foo").
to("rnc:mySchema.rnc", "activemq:anotherQueue");
|
...
You can define multiple onException clauses for different behavior
Code Block | ||||
---|---|---|---|---|
| ||||
onException(ValidationException.class).
to("activemq:validationFailed");
onException(ShipOrderException.class).
to("activemq:shipFailed");
from("seda:order").to("bean:processOrder");
|
...
Exception clauses is scoped as either:
- global (for Java DSL that is per RouteBuilder instances, to reuse, see note below)
- or route specific
Where the global are the simplest and most easy to understand. In the advanced section we dig into the route specific and even combining them. However
Info |
---|
Global scope for Java DSL is per |
How does Camel select which clause should handle a given thrown Exception
...
This is best illustrated with an exception:
Code Block | ||||
---|---|---|---|---|
| ||||
onException(IOException.class).maximumRedeliveries(3);
onException(OrderFailedException.class).maximumRedeliveries(2);
|
...
So if an exception is thrown with this hierarchy:
Code Block |
---|
+ RuntimeCamelException (wrapper exception by Camel)
+ OrderFailedException
+ IOException
+ FileNotFoundException
|
...
If we add a third onException clause with the FileNotFoundException
Code Block | ||||
---|---|---|---|---|
| ||||
onException(IOException.class).maximumRedeliveries(3);
onException(OrderFailedException.class).maximumRedeliveries(2);
onException(FileNotFoundException.class).handled(true).to("log:nofile");
|
...
Now a new situation if this exception was thrown instead:
Code Block |
---|
+ RuntimeCamelException (wrapper exception by Camel)
+ OrderFailedException
+ OrderNotFoundException
|
...
And this last sample demonstrates the instanceof
test aspect in which Camel will select an exception if it's an instance of the defined exception in the onException
clause. Illustrated as:
Code Block |
---|
+ RuntimeCamelException (wrapper exception by Camel)
+ SocketException
|
...
However if you want to customize any methods on the RedeliveryPolicy object, you can do this via the fluent API. So lets retry in case of ValidationException up till two times.
Code Block |
---|
onException(ValidationException.class).
maximumRedeliveries(2);
|
And the spring DSL:
Code Block | ||||
---|---|---|---|---|
| ||||
<onException>
<exception>com.mycompany.ValidationException</exception>
<redeliveryPolicy maximumRedeliveries="2"/>
</onException>
|
You can customize any of the RedeliveryPolicy so we can for instance set a different delay of 5000 millis:
Code Block | ||||
---|---|---|---|---|
| ||||
<onException>
<exception>com.mycompany.ValidationException</exception>
<redeliveryPolicy maximumRedeliveries="2" delay="5000"/>
</onException>
|
...
All redelivery attempts start at the point of the failure. So the route:
Code Block |
---|
.onException(ConnectException.class)
.from("direct:start")
.process("processor1")
.process("processor2") // <--- throws a ConnectException
.to("mock:theEnd")
|
...
Available as of Camel 1.5.1 or later
You can reference a RedeliveryPolicy
so you can reuse existing configurations and use standard spring bean style configuration that supports property placeholders.
Code Block | ||||
---|---|---|---|---|
| ||||
<bean id="myRedeliveryPolicy" class="org.apache.camel.processor.RedeliveryPolicy">
<property name="maximumRedeliveries" value="${myprop.max}"/>
</bean>
<!-- here we reference our redelivery policy defined above -->
<onException redeliveryPolicyRef="myRedeliveryPolicy">
<!-- you can define multiple exceptions just adding more exception elements as show below -->
<exception>com.mycompany.MyFirstException</exception>
<exception>com.mycompany.MySecondException</exception>
</onException>
|
...
In Camel 1.5 the exception clauses has been renamed to onException and it also supports multiple exception classes:
Code Block |
---|
onException(MyBusinessException.class, MyOtherBusinessException.class)
.maximumRedeliveries(2)
.to("activemq:businessFailed");
|
And in Spring DSL you just add another exception element:
Code Block | ||||
---|---|---|---|---|
| ||||
<onException>
<exception>com.mycompany.MyBusinessException</exception>
<exception>com.mycompany.MyOtherBusinessException</exception>
<redeliveryPolicy maximumRedeliveries="2"/>
<to uri="activemq:businessFailed"/>
</onException>
|
...
For instance to mark all ValidationException
as being handled we can do this:
Code Block |
---|
onException(ValidationException).handled(true);
|
...
For instance to just ignore and continue if the IDontCareException
was thrown we can do this:
Code Block |
---|
onException(IDontCareException).continued(true);
|
...
For instance if you have this route:
Code Block |
---|
from("jms:queue:order:input")
.to("bean:validateOrder");
.to("bean:transformOrder")
.to("bean:handleOrder");
|
The route listen for JMS messages and validates, transforms and handle it. During this the Exchange payload is transformed/modified. So in case something goes wrong and we want to move the message to another JMS destination, then we can add an onException. But when we move the Exchange to this destination we do not know in which state the message is in. Did the error happen in before the transformOrder or after? So to be sure we want to move the original input message we received from jms:queue:order:input
. So we can do this by enabling the useOriginalMessage option as shown below:
Code Block | ||||
---|---|---|---|---|
| ||||
// will use original input body
onException(MyOrderException.class)
.useOriginalMessage().handled(true)
.to("jms:queue:order:failed");
|
...
The useOriginalMessage option is defined as a boolean attribute on the <onException> XML tag in Spring DSL. So the definition above would be:
Code Block | ||||
---|---|---|---|---|
| ||||
<onException useOriginalMessage="true">
<exception>com.mycompany.MyOrderException</exception>
<handled><constant>true</constant></handled>
<to uri="jms:queue:order:failed"/>
</onException>
|
...
You can use all of the above mentioned exception clause features in the Spring DSL as well. Here are a few examples:
Global scoped - Available in Camel 2.0
Wiki Markup {snippet:id=e1|lang=xml|url=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/onexception/deadLetterChannelHandledExampleTest.xml}
Route specific scoped
Wiki Markup {snippet:id=e1|lang=xml|url=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/onexception/onExceptionSubRouteTest.xml}
...