Exception Clause has been edited by Claus Ibsen (May 12, 2009).

(View changes)

Content:

Exception Clause

You can use the Exception Clause in the Java DSL to specify the error handling you require on a per exception type basis using the onException() method.

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:

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");

Here if the processing of seda:inputA or seda:inputB cause a ValidationException to be thrown (such as due to the XSD validation of the Validation component or the Relax NG Compact syntax validation of the Jing component), then the message will be sent to activemq:validationFailed queue.

You can define multiple onException clauses for different behavior

onException(ValidationException.class).
  to("activemq:validationFailed");

onException(ShipOrderException.class).
  to("activemq:shipFailed");

from("seda:order").to("bean:processOrder");

Number of features depend on Error Handler being used

The Exception Clause supports a wide range of features, that are dependent on the Error Handler used. For instance Dead Letter Channel supports it all, where as the DefaultErrorHandler and TransactionErrorHandler doe not support anything related to redelivery.

Here is a breakdown of which features is supported by the Error Handler(s):

Feature Supported by the following Error Handler
all scopes DefaultErrorHandler, TransactionErrorHandler, Dead Letter Channel
onException DefaultErrorHandler, TransactionErrorHandler, Dead Letter Channel
onWhen DefaultErrorHandler, TransactionErrorHandler, Dead Letter Channel
handled DefaultErrorHandler, TransactionErrorHandler, Dead Letter Channel
Custom ExceptionPolicy DefaultErrorHandler, TransactionErrorHandler, Dead Letter Channel
useOriginalBody Dead Letter Channel
dead letter queue Dead Letter Channel
redeliverUntil Dead Letter Channel
onRedelivery Dead Letter Channel
RedeliveryPolicy Dead Letter Channel

Scopes

Exception clauses is scoped as either:

  • global
  • 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

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

Camel uses DefaultExceptionPolicyStrategy to determine a strategy how an exception being thrown should be handled by which onException clause. The strategy is:

  • the order in which the onException is configured takes precedence. Camel will test from first...last defined.
  • Camel will start from the bottom (nested caused by) and recursive up in the exception hierarchy to find the first matching onException clause
  • instanceof test is used for testing the given exception with the onException clause defined exception list. An exact instanceof match will always be used, otherwise the onException clause that has an exception that is the closets super of the thrown exception is selected (recurring up the exception hierarchy)

This is best illustrated with an exception:

onException(IOException.class).maximumRedeliveries(3);

onException(OrderFailedException.class).maximumRedeliveries(2);

In the sample above we have defined two exceptions in which IOException is first, so Camel will pickup this exception if there is a match. IOException that is more general is selected then.

So if an exception is thrown with this hierarchy:

+ RuntimeCamelException (wrapper exception by Camel)
   + OrderFailedException 
       + IOException
            + FileNotFoundException

Then Camel will try testing the exception in this order: FileNotFoundException, IOException, OrderFailedException and RuntimeCamelException.
As we have defined a onException(IOException.class) Camel will select this as it's the closest match.

If we add a third onException clause with the FileNotFoundException

onException(IOException.class).maximumRedeliveries(3);

onException(OrderFailedException.class).maximumRedeliveries(2);

onException(FileNotFoundException.class).handled(true).to("log:nofile");

Then with the previous example Camel will now use the last onException(FileNotFoundException.class) as its an exact match. Since this is an exact match it will override the general IOException that was used before to handle the same exception thrown.

Now a new situation if this exception was thrown instead:

+ RuntimeCamelException (wrapper exception by Camel)
   + OrderFailedException 
       + OrderNotFoundException

Then the onException(OrderFailedException.class) will be selected - no surprise here.

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:

+ RuntimeCamelException (wrapper exception by Camel)
   + SocketException

Since SocketException is an instanceof IOException, Camel will select the onException(IOException.class) clause.

Configuring ReliveryPolicy (redeliver options)

RedeliveryPolicy requires to use the Dead Letter Channel as the Error Handler.

The default error handler used in Camel is the Dead Letter Channel which supports attempting to redeliver the message exchange a number of times before sending it to a dead letter endpoint. See Dead Letter Channel for further information about redeliver and which redeliver options exists.

No redelivery is default for onException

By default any Exception Clause will not redeliver! (as it sets the maximumRedeliveries option to 0).

Sometimes you want to configure the redelivery policy on a per exception type basis. By default in the top examples, if a ValidationException occurs then the message will not be redelivered; however if some other exception occurs (IOException or whatelse) the route will be retried according to the settings from the Dead Letter Channel.

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.

onException(ValidationException.class).
  maximumRedeliveries(2);

And the spring DSL:

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

<onException>
   <exception>com.mycompany.ValidationException</exception>
   <redeliveryPolicy maximumRedeliveries="2" delay="5000"/>
</onException>

Reusing ReliveryPolicy

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.

<bean id="myRedeliveryPolicy" class="org.apache.camel.processor.RedeliveryPolicy">
        <property name="maximumRedeliveries" value="${myprop.max}"/>
    </bean>

     <onException>
         <!-- you can define multiple exceptions just adding more exception elements as show below -->
         <exception>com.mycompany.MyFirstException</exception>
         <exception>com.mycompany.MySecondException</exception>

         <!-- here we reference our redelivery policy defined above -->
         <redeliveryPolicy ref="myRedeliveryPolicy"/>
     </onException>

Catching multiple exceptions

Available as of Camel 1.5

In Camel 1.5 the exception clauses has been renamed to onException and it also supports multiple exception classes:

onException(MyBusinessException.class, MyOtherBusinessException.class)
  .maximumRedeliveries(2)
  .to("activemq:businessFailed");

And in Spring DSL you just add another exception element:

<onException>
   <exception>com.mycompany.MyBusinessException</exception>
   <exception>com.mycompany.MyOtherBusinessException</exception>
   <redeliveryPolicy maximumRedeliveries="2"/>
   <to uri="activemq:businessFailed"/>
</onException>

Using a processor as failure handler

We want to handle certain exceptions specially so we add a onException clause for that exception.

// here we register exception cause for MyFunctionException
// when this exception occur we want it to be processed by our proceesor
onException(MyFunctionalException.class).process(new MyFunctionFailureHandler());

So what happens is that whenever a MyFunctionalException is thrown it is being routed to our processor MyFunctionFailureHandler. So you can say that the exchange is diverted when a MyFunctionalException is thrown during processing. It's important to distinct this as perfect valid. The default redelivery policy from the Dead Letter Channel will not kick in, so our processor receives the Exchange directly, without any redeliver attempted. In our processor we need to determine what to do. Camel regards the Exchange as failure handled. So our processor is the end of the route. So lets look the code for our processor.

public static class MyFunctionFailureHandler implements Processor {

    public void process(Exchange exchange) throws Exception {
        // the caused by exception is stored in a property on the exchange
        Throwable caused = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Throwable.class);
        assertNotNull(caused);
        // here you can do what you want, but Camel regard this exception as handled, and
        // this processor as a failurehandler, so it wont do redeliveries. So this is the
        // end of this route. But if we want to route it somewhere we can just get a
        // producer template and send it.

        // send it to our mock endpoint
        exchange.getContext().createProducerTemplate().send("mock:myerror", exchange);
    }
}

Notice how we get the caused by exception using a property on the Exchange. This is where Camel stores any caught exception during processing. So you can fetch this property and check what the exception message and do what you want. In the code above we just route it to a mock endpoint using a producer template from Exchange.

Marking exceptions as being handled

Available as of Camel 1.5

Using onException to handle known exceptions is a very powerful feature in Camel. However prior to Camel 1.5 you could not mark the exception as being handled, so the caller would still receive the caused exception as a response. In Camel 1.5 you can now change this behavior with the new handle DSL. The handle is a Predicate that is overloaded to accept three types of parameters:

  • Boolean
  • Predicate
  • Expression that will be evaluates as a Predicate using this rule set: If the expressions returns a Boolean its used directly. For any other response its regarded as true if the response is not null.

For instance to mark all ValidationException as being handled we can do this:

onException(ValidationException).handled(true);

Example using handled

In this route below we want to do special handling of all OrderFailedException as we want to return a customized response to the caller. First we setup our routing as:

// we do special error handling for when OrderFailedException is thrown
onException(OrderFailedException.class)
    // we mark the exchange as handled so the caller doesn't receive the
    // OrderFailedException but whatever we want to return instead
    .handled(true)
    // this bean handles the error handling where we can customize the error
    // response using java code
    .bean(OrderService.class, "orderFailed")
    // and since this is an unit test we use mocks for testing
    .to("mock:error");

// this is just the generic error handler where we set the destination
// and the number of redeliveries we want to try
errorHandler(deadLetterChannel("mock:error").maximumRedeliveries(1));

// this is our route where we handle orders
from("direct:start")
    // this bean is our order service
    .bean(OrderService.class, "handleOrder")
    // this is the destination if the order is OK
    .to("mock:result");

Then we have our service beans that is just plain POJO demonstrating how you can use Bean Integration in Camel to avoid being tied to the Camel API:

/**
 * Order service as a plain POJO class
 */
public static class OrderService {

    /**
     * This method handle our order input and return the order
     *
     * @param in      the in headers
     * @param payload the in payload
     * @param out     the out headers
     * @return the out payload
     * @throws OrderFailedException is thrown if the order cannot be processed
     */
    public Object handleOrder(@Headers Map in, @Body String payload, @OutHeaders Map out)
        throws OrderFailedException {
        out.put("customerid", in.get("customerid"));
        if ("Order: kaboom".equals(payload)) {
            throw new OrderFailedException("Cannot order: kaboom");
        } else {
            out.put("orderid", "123");
            return "Order OK";
        }
    }

    /**
     * This method creates the response to the caller if the order could not be processed
     * @param in      the in headers
     * @param payload the in payload
     * @param out     the out headers
     * @return the out payload
     */
    public Object orderFailed(@Headers Map in, @Body String payload, @OutHeaders Map out) {
        out.put("customerid", in.get("customerid"));
        out.put("orderid", "failed");
        return "Order ERROR";
    }
}

And finally the exception that is being thrown is just a regular exception:

/**
 * Exception thrown if the order cannot be processed
 */
public static class OrderFailedException extends Exception {

    public OrderFailedException(String message) {
        super(message);
    }
    
}

So what happens?

If we sent an order that is being processed OK then the caller will receive an Exchange as reply containing Order OK as the payload and orderid=123 in a header.

If the order could not be processed and thus an OrderFailedException was thrown the caller will not receive this exception (as opposed to in Camel 1.4, where the caller received the OrderFailedException) but our customized response that we have fabricated in the orderFailed method in our OrderService. So the caller receives an Exchange with the payload Order ERROR and a orderid=failed in a header.

Using handled with Spring DSL

The same route as above in Spring DSL:

<!-- setup our error handler as the deal letter channel -->
<bean id="errorHandler" class="org.apache.camel.builder.DeadLetterChannelBuilder">
    <property name="deadLetterUri" value="mock:error"/>
</bean>

<!-- this is our POJO bean with our business logic defined as a plain spring bean -->
<bean id="orderService" class="org.apache.camel.spring.processor.onexception.OrderService" />

<!-- this is the camel context where we define the routes -->
<!-- define our error handler as a global error handler -->
<camelContext errorHandlerRef="errorHandler" xmlns="http://camel.apache.org/schema/spring">

  <onException>
    <!-- the exception is full qualified names as plain strings -->
    <!-- there can be more just add a 2nd, 3rd exception element (unbounded) -->
    <exception>org.apache.camel.spring.processor.onexception.OrderFailedException</exception>
    <!-- we can set the redelivery policy here as well -->
    <redeliveryPolicy maximumRedeliveries="1" />
    <!-- mark this as handled -->
    <handled>
      <constant>true</constant>
    </handled>
    <!-- let our order service handle this exception, call the orderFailed method -->
    <bean ref="orderService" method="orderFailed" />
    <!-- and since this is a unit test we use mock for assertions -->
    <to uri="mock:error" />
  </onException>

  <route>
    <!-- the route -->
    <from uri="direct:start" />
    <!-- in the normal route then route to our order service and call handleOrder method -->
    <bean ref="orderService" method="handleOrder" />
    <!-- and since this is a unit test we use mock for assertions -->
    <to uri="mock:result" />
  </route>

</camelContext>

Handling and sending a fixed response back to the client

In the route above we handled the exception but routed it to a different endpoint. What if you need to alter the response and send a fixed response back to the original caller (the client). No secret here just do as you do in normal Camel routing, use transform to set the response, as shown in the sample below:

// we catch MyFunctionalException and want to mark it as handled (= no failure returned to client)
// but we want to return a fixed text response, so we transform OUT body as Sorry.
onException(MyFunctionalException.class)
        .handled(true)
        .transform().constant("Sorry");

We modify the sample slightly to return the original caused exception message instead of the fixed text Sorry:

// we catch MyFunctionalException and want to mark it as handled (= no failure returned to client)
// but we want to return a fixed text response, so we transform OUT body and return the exception message
onException(MyFunctionalException.class)
        .handled(true)
        .transform(exceptionMessage());

And we can use the Simple language to set a readable error message with the caused excepetion message:

// we catch MyFunctionalException and want to mark it as handled (= no failure returned to client)
// but we want to return a fixed text response, so we transform OUT body and return a nice message
// using the simple language where we want insert the exception message
onException(MyFunctionalException.class)
        .handled(true)
        .transform().simple("Error reported: ${exception.message} - cannot process this message.");

Using useOriginalBody

Available as of Camel 2.0
The option useOriginalBody is used for routing the original input body instead of the current body that potential is modified during routing.

For instance if you have this route:

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 useOriginalBody option as shown below:

// will use original input body
    onException(MyOrderException.class)
       .useOriginalBody().handled(true)
       .to("jms:queue:order:failed");

Then the messages routed to the jms:queue:order:failed is the original input. If we want to manually retry we can move the JMS message from the failed to the input queue, with no problem as the message is the same as the original we received.

Advanced Usage of Exception Clause

Using global and per route exception clauses

Camel supports quite advanced configuration of exception clauses.

You can define exception clauses either as:

  • global
  • or route specific

We start off with the sample sample that we change over time. First off we use only global exception clauses:

// default should errors go to mock:error
errorHandler(deadLetterChannel("mock:error"));

// if a MyTechnicalException is thrown we will not try to redeliver and we mark it as handled
// so the caller does not get a failure
// since we have no to then the exchange will continue to be routed to the normal error handler
// destination that is mock:error as defined above
onException(MyTechnicalException.class).maximumRedeliveries(0).handled(true);

// if a MyFunctionalException is thrown we do not want Camel to redelivery but handle it our self using
// our bean myOwnHandler, then the exchange is not routed to the default error (mock:error)
onException(MyFunctionalException.class).maximumRedeliveries(0).handled(true).to("bean:myOwnHandler");

// here we route message to our service bean
from("direct:start")
    .choice()
        .when().xpath("//type = 'myType'").to("bean:myServiceBean")
    .end()
    .to("mock:result");

In the next sample we change the global exception policies to be pure route specific.

Must use .end() for route specific exception policies

Important: This requires to end the onException route with .end() to indicate where it stops and when the regular route continues.

// default should errors go to mock:error
errorHandler(deadLetterChannel("mock:error"));

// here we start the routing with the consumer
from("direct:start")

    // if a MyTechnicalException is thrown we will not try to redeliver and we mark it as handled
    // so the caller does not get a failure
    // since we have no to then the exchange will continue to be routed to the normal error handler
    // destination that is mock:error as defined above
    // we MUST use .end() to indicate that this sub block is ended
    .onException(MyTechnicalException.class).maximumRedeliveries(0).handled(true).end()

    // if a MyFunctionalException is thrown we do not want Camel to redelivery but handle it our self using
    // our bean myOwnHandler, then the exchange is not routed to the default error (mock:error)
    // we MUST use .end() to indicate that this sub block is ended
    .onException(MyFunctionalException.class).maximumRedeliveries(0).handled(true).to("bean:myOwnHandler").end()

    // here we have the regular routing
    .choice()
        .when().xpath("//type = 'myType'").to("bean:myServiceBean")
    .end()
    .to("mock:result");

And now it gets complex as we combine global and route specific exception policies as we introduce a 2nd route in the sample:

// global error handler
// as its based on a unit test we do not have any delays between and do not log the stack trace
errorHandler(deadLetterChannel("mock:error").delay(0).logStackTrace(false));

// shared for both routes
onException(MyTechnicalException.class).handled(true).maximumRedeliveries(2).to("mock:tech.error");

from("direct:start")
    // route specific on exception for MyFunctionalException
    // we MUST use .end() to indicate that this sub block is ended
    .onException(MyFunctionalException.class).maximumRedeliveries(0).end()
    .to("bean:myServiceBean")
    .to("mock:result");

from("direct:start2")
    // route specific on exception for MyFunctionalException that is different than the previous route
    // here we marked it as handled and send it to a different destination mock:handled
    // we MUST use .end() to indicate that this sub block is ended
    .onException(MyFunctionalException.class).handled(true).maximumRedeliveries(0).to("mock:handled").end()
    .to("bean:myServiceBean")
    .to("mock:result");

Notice that we can define the same exception MyFunctionalException in both routes, but they are configured differently and thus is handled different depending on the route. You can of course also add a new onException to one of the routes so it has an additional exception policy.

And finally we top this by throwing in a nested error handler as well, as we add the 3rd route shown below:

from("direct:start3")
    // route specific error handler that is different than the global error handler
    // here we do not redeliver and send errors to mock:error3 instead of the global endpoint
    .errorHandler(deadLetterChannel("mock:error3")
            .maximumRedeliveries(0))

    // route specific on exception to mark MyFunctionalException as being handled
    .onException(MyFunctionalException.class).handled(true).end()
    // however we want the IO exceptions to redeliver at most 3 times
    .onException(IOException.class).maximumRedeliveries(3).end()
    .to("bean:myServiceBean")
    .to("mock:result");
Global exception policies and nested error handlers

The sample above with both nested error handlers and both global and per route exception clauses is a bit advanced. It's important to get the fact straight that the global exception clauses is really global so they also applies for nested error handlers. So if a MyTechnicalException is thrown then it's the global exception policy that is selected.

Using fine grained selection using onWhen predicate

Available as of Camel 1.5.1 or later

You can attach an Expression to the exception clause to have fine grained control when a clause should be selected or not. As it's an Expression you can use any kind of code to perform the test. Here is a sample:

public void configure() throws Exception {
    errorHandler(deadLetterChannel("mock:error").delay(0).maximumRedeliveries(3));

    // here we define our onException to catch MyUserException when
    // there is a header[user] on the exchange that is not null
    onException(MyUserException.class).onWhen(header("user").isNotNull())
        .maximumRedeliveries(1)
        .to(ERROR_USER_QUEUE);

    // here we define onException to catch MyUserException as a kind
    // of fallback when the above did not match.
    // Noitce: The order how we have defined these onException is
    // important as Camel will resolve in the same order as they
    // have been defined
    onException(MyUserException.class)
        .maximumRedeliveries(2)
        .to(ERROR_QUEUE);

In the sample above we have two onException's defined. The first has an onWhen expression attached to only trigger if the message has a header with the key user that is not null. If so this clause is selected and is handling the thrown exception. The 2nd clause is a for coarse gained selection to select the same exception being thrown but when the expression is evaluated to false. Notice: this is not required, if the 2nd clause is omitted, then the default error handler will kick in.

Using onRedelivery processor

Available as of Camel 2.0

Dead Letter Channel has support for onRedelivery to allow custom processing of a Message before its being redelivered. It can be used to add some customer header or whatnot. In Camel 2.0 we have added this feature to Exception Clause as well, so you can use per exception scoped on redelivery. Camel will fallback to use the one defined on Dead Letter Channel if any, if none exists on the Exception Clause. See Dead Letter Channel for more details on onRedelivery.

In the code below we want to do some custom code before redelivering any IOException. So we configure an onException for the IOException and set the onRedelivery to use our custom processor:

// when we redeliver caused by an IOException we want to do some special
// code before the redeliver attempt
onException(IOException.class).onRedelivery(new MyIORedeliverPrcessor());

And in our custom processor we set a special timeout header to the message. You can of course do anything what you like in your code.

// This is our processor that is executed before IOException redeliver attempt
// here we can do what we want in the java code, such as altering the message

public static class MyIORedeliverPrcessor implements Processor {

    public void process(Exchange exchange) throws Exception {
        // just for show and tell, here we set a special header to instruct
        // the receive a given timeout value
        exchange.getIn().setHeader("Timeout", 5000);
    }
}

Using onRedelivery in Spring DSL

In Spring DSL you need to use the onRedeliveryRef attribute to refer to a spring bean id that is your custom processor:

<onException onRedeliveryRef="myIORedeliverProcessor">
    <exception>java.io.IOException</exception>
</onException>

And our processor is just a regular spring bean (we use $ for the inner class as this code is based on unit testing)

<bean id="myRedeliveryProcessor"
      class="org.apache.camel.processor.DeadLetterChannelOnExceptionOnRedeliveryTest$MyRedeliverPrcessor"/>

Using fine grained retry using retryUntil predicate

Available as of Camel 2.0

When you need fine grained control for determining if an exchange should be retried or not you can use the retryUntil predicate. Camel will redeliver until the predicate returns false.
This is demonstrated in the sample below:

// we want to use a predicate for retries so we can determine in our bean
// when retry should stop, notice it will overrule the global error handler
// where we defined at most 1 redelivery attempt. Here we will continue until
// the predicate false
onException(MyFunctionalException.class)
        .retryUntil(bean("myRetryHandler"))
        .handled(true)
        .transform().constant("Sorry");

Where the bean myRetryHandler is computing if we should retry or not:

public class MyRetryBean {

    // using bean binding we can bind the information from the exchange to the types we have in our method signature
    public boolean retryUntil(@Header(Exchange.REDELIVERY_COUNTER) Integer counter, @Body String body, @ExchangeException Exception causedBy) {
        // NOTE: counter is the redelivery attempt, will start from 1
        invoked++;

        assertEquals("Hello World", body);
        assertTrue(causedBy instanceof MyFunctionalException);

        // we can of course do what ever we want to determine the result but this is a unit test so we end after 3 attempts
        return counter < 3;
    }
}

Using custom ExceptionPolicyStrategy

Available in Camel 1.4

The default ExceptionPolicyStrategy in Camel should be sufficient in nearly all use-cases (see section How does Camel select which clause should handle a given thrown Exception). However if you need to use your own this can be configued as the sample below illustrates:

public void configure() throws Exception {
    // configure the error handler to use my policy instead of the default from Camel
    errorHandler(deadLetterChannel().exceptionPolicyStrategy(new MyPolicy()));

    onException(MyPolicyException.class)
        .maximumRedeliveries(1)
        .setHeader(MESSAGE_INFO, constant("Damm my policy exception"))
        .to(ERROR_QUEUE);

    onException(CamelException.class)
        .maximumRedeliveries(3)
        .setHeader(MESSAGE_INFO, constant("Damm a Camel exception"))
        .to(ERROR_QUEUE);

Using our own strategy MyPolicy we can change the default behavior of Camel with our own code to resolve which ExceptionType from above should be handling the given thrown exception.

public static class MyPolicy implements ExceptionPolicyStrategy {

    public OnExceptionDefinition getExceptionPolicy(Map<ExceptionPolicyKey, OnExceptionDefinition> exceptionPolicices,
                                            Exchange exchange,
                                            Throwable exception) {
        // This is just an example that always forces the exception type configured
        // with MyPolicyException to win.
        return exceptionPolicices.get(ExceptionPolicyKey.newInstance(MyPolicyException.class));
    }
}

Using the exception clause in Spring DSL

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
    <!-- setup our error handler as the deal letter channel -->
    <bean id="errorHandler" class="org.apache.camel.builder.DeadLetterChannelBuilder">
        <property name="deadLetterUri" value="mock:error"/>
    </bean>
    
    <!-- this is our POJO bean with our business logic defined as a plain spring bean -->
    <bean id="orderService" class="org.apache.camel.spring.processor.onexception.OrderService" />
    
    <!-- this is the camel context where we define the routes -->
    <!-- define our error handler as a global error handler -->
    <camelContext errorHandlerRef="errorHandler" xmlns="http://camel.apache.org/schema/spring">
    
      <onException>
        <!-- the exception is full qualified names as plain strings -->
        <!-- there can be more just add a 2nd, 3rd exception element (unbounded) -->
        <exception>org.apache.camel.spring.processor.onexception.OrderFailedException</exception>
        <!-- we can set the redelivery policy here as well -->
        <redeliveryPolicy maximumRedeliveries="1" />
        <!-- mark this as handled -->
        <handled>
          <constant>true</constant>
        </handled>
        <!-- let our order service handle this exception, call the orderFailed method -->
        <bean ref="orderService" method="orderFailed" />
        <!-- and since this is a unit test we use mock for assertions -->
        <to uri="mock:error" />
      </onException>
    
      <route>
        <!-- the route -->
        <from uri="direct:start" />
        <!-- in the normal route then route to our order service and call handleOrder method -->
        <bean ref="orderService" method="handleOrder" />
        <!-- and since this is a unit test we use mock for assertions -->
        <to uri="mock:result" />
      </route>
    
    </camelContext>
  • Route specific scoped
    <!-- setup our error handler as the deal letter channel -->
    <bean id="deadLetter" class="org.apache.camel.builder.DeadLetterChannelBuilder">
        <property name="deadLetterUri" value="mock:dead"/>
    </bean>
    
    <!-- the default error handler used in the 2nd route -->
    <bean id="defaultErrorHandler" class="org.apache.camel.builder.DefaultErrorHandlerBuilder"/>
    
    <!-- this is our POJO bean with our business logic defined as a plain spring bean -->
    <bean id="orderService" class="org.apache.camel.spring.processor.onexception.OrderService"/>
    
    <!-- this is the camel context where we define the routes -->
    <camelContext xmlns="http://camel.apache.org/schema/spring">
    
        <route errorHandlerRef="deadLetter">
            <from uri="direct:start"/>
            <onException>
                <exception>org.apache.camel.spring.processor.onexception.OrderFailedException</exception>
                <redeliveryPolicy maximumRedeliveries="1"/>
                <handled>
                    <constant>true</constant>
                </handled>
                <bean ref="orderService" method="orderFailed"/>
                <to uri="mock:error"/>
            </onException>
            <bean ref="orderService" method="handleOrder"/>
            <to uri="mock:result"/>
        </route>
    
        <!-- The exception clause specified in the first route will not be used in this route -->
        <route errorHandlerRef="defaultErrorHandler">
            <from uri="direct:start_with_no_handler"/>
            <bean ref="orderService" method="handleOrder"/>
            <to uri="mock:result"/>
        </route>
    
    </camelContext>

See also

The Error Handler for the general error handling documentation
The Dead Letter Channel for further details.
The Transactional Client for transactional behavior

Powered by Atlassian Confluence (Version: 2.2.9 Build:#527 Sep 07, 2006) - Bug/feature request

Unsubscribe or edit your notifications preferences