Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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
java
java

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 RouteBuilder instance, so if you want to share among multiple RouteBuilder classes, then create a base abstract RouteBuilder class and put the error handling logic in its configure method. And then extend this class, and make sure to class super.configure(). We are just using the Java inheritance technique.

 

How does Camel select which clause should handle a given thrown Exception

...

This is best illustrated with an exception:

Code Block
java
java

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
java
java

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
xml
xml

<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
xml
xml

<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
xml
xml

    <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
xml
xml

<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
java
java

    // 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
xml
xml

    <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}

...