camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Camel > Exception Clause
Date Mon, 01 Feb 2010 06:16:00 GMT
<html>
<head>
    <base href="http://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/1519/1/1/_/styles/combined.css?spaceKey=CAMEL&amp;forWysiwyg=true" type="text/css">
    </head>
<body style="background-color: white" bgcolor="white">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
     <h2><a href="http://cwiki.apache.org/confluence/display/CAMEL/Exception+Clause">Exception Clause</a></h2>
     <h4>Page <b>edited</b> by             <a href="http://cwiki.apache.org/confluence/display/~davsclaus">Claus Ibsen</a>
    </h4>
     
          <br/>
     <div class="notificationGreySide">
         <h2><a name="ExceptionClause-ExceptionClause"></a>Exception Clause</h2>

<p>You can use the <em>Exception Clause</em> in the Java <a href="/confluence/display/CAMEL/DSL" title="DSL">DSL</a> to specify the error handling you require on a per exception type basis using the <b>onException()</b> method.</p>

<p>To get started we give quick sample before digging into how it works.<br/>
For example if you want to perform a specific piece of processing if a certain exception is raised you can do this simply via:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
onException(ValidationException.class).
  to(<span class="code-quote">"activemq:validationFailed"</span>);
  
from(<span class="code-quote">"seda:inputA"</span>).
  to(<span class="code-quote">"validation:foo/bar.xsd"</span>, <span class="code-quote">"activemq:someQueue"</span>);

from(<span class="code-quote">"seda:inputB"</span>).to(<span class="code-quote">"direct:foo"</span>).
  to(<span class="code-quote">"rnc:mySchema.rnc"</span>, <span class="code-quote">"activemq:anotherQueue"</span>);
</pre>
</div></div>

<p>Here if the processing of <b>seda:inputA</b> or <b>seda:inputB</b> cause a ValidationException to be thrown (such as due to the XSD validation of the <a href="/confluence/display/CAMEL/Validation" title="Validation">Validation</a> component or the Relax NG Compact syntax validation of the <a href="/confluence/display/CAMEL/Jing" title="Jing">Jing</a> component), then the message will be sent to <b>activemq:validationFailed</b> queue.</p>

<p>You can define multiple onException clauses for different behavior</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
onException(ValidationException.class).
  to(<span class="code-quote">"activemq:validationFailed"</span>);

onException(ShipOrderException.class).
  to(<span class="code-quote">"activemq:shipFailed"</span>);

from(<span class="code-quote">"seda:order"</span>).to(<span class="code-quote">"bean:processOrder"</span>);
</pre>
</div></div>

<h3><a name="ExceptionClause-Scopes"></a>Scopes</h3>
<p>Exception clauses is scoped as either:</p>
<ul class="alternate" type="square">
	<li>global</li>
	<li>or route specific</li>
</ul>


<p>Where the <b>global</b> are the simplest and most easy to understand. In the advanced section we dig into the route specific and even combining them. However </p>

<h3><a name="ExceptionClause-HowdoesCamelselectwhichclauseshouldhandleagiventhrownException"></a>How does Camel select which clause should handle a given thrown Exception</h3>
<p>Camel uses <tt>DefaultExceptionPolicyStrategy</tt> to determine a strategy how an exception being thrown should be handled by which <tt>onException</tt> clause. The strategy is:</p>
<ul class="alternate" type="square">
	<li>the order in which the <tt>onException</tt> is configured takes precedence. Camel will test from first...last defined.</li>
	<li>Camel will start from the bottom (nested caused by) and recursive up in the exception hierarchy to find the first matching <tt>onException</tt> clause</li>
	<li><tt>instanceof</tt> test is used for testing the given exception with the <tt>onException</tt> clause defined exception list. An exact <tt>instanceof</tt> match will always be used, otherwise the <tt>onException</tt> clause that has an exception that is the closets super of the thrown exception is selected (recurring up the exception hierarchy)</li>
</ul>


<p>This is best illustrated with an exception:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
onException(IOException.class).maximumRedeliveries(3);

onException(OrderFailedException.class).maximumRedeliveries(2);
</pre>
</div></div>

<p>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.</p>

<p>So if an exception is thrown with this hierarchy:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
+ RuntimeCamelException (wrapper exception by Camel)
   + OrderFailedException 
       + IOException
            + FileNotFoundException
</pre>
</div></div>

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

<p>If we add a third onException clause with the <tt>FileNotFoundException</tt></p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
onException(IOException.class).maximumRedeliveries(3);

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

onException(FileNotFoundException.class).handled(<span class="code-keyword">true</span>).to(<span class="code-quote">"log:nofile"</span>);
</pre>
</div></div>
<p>Then with the previous example Camel will now use the last <tt>onException(FileNotFoundException.class)</tt> as its an <b>exact</b> match. Since this is an exact match it will override the general IOException that was used before to handle the same exception thrown. </p>

<p>Now a new situation if this exception was thrown instead:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
+ RuntimeCamelException (wrapper exception by Camel)
   + OrderFailedException 
       + OrderNotFoundException
</pre>
</div></div>

<p>Then the <tt>onException(OrderFailedException.class)</tt> will be selected - no surprise here.</p>

<p>And this last sample demonstrates the <tt>instanceof</tt> test aspect in which Camel will select an exception if it's an instance of the defined exception in the <tt>onException</tt> clause. Illustrated as:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
+ RuntimeCamelException (wrapper exception by Camel)
   + SocketException
</pre>
</div></div>

<p>Since SocketException is an instanceof IOException, Camel will select the <tt>onException(IOException.class)</tt> clause.</p>

<h3><a name="ExceptionClause-ConfiguringReliveryPolicy%28redeliveroptions%29"></a>Configuring ReliveryPolicy (redeliver options)</h3>

<p><a href="http://camel.apache.org/maven/camel-core/apidocs/org/apache/camel/processor/RedeliveryPolicy.html" rel="nofollow">RedeliveryPolicy</a> requires to use the <a href="/confluence/display/CAMEL/Dead+Letter+Channel" title="Dead Letter Channel">Dead Letter Channel</a> as the <a href="/confluence/display/CAMEL/Error+Handler" title="Error Handler">Error Handler</a>.</p>

<p>The default error handler used in Camel is the <a href="/confluence/display/CAMEL/Dead+Letter+Channel" title="Dead Letter Channel">Dead Letter Channel</a> which supports attempting to redeliver the message exchange a number of times before sending it to a dead letter endpoint. See <a href="/confluence/display/CAMEL/Dead+Letter+Channel" title="Dead Letter Channel">Dead Letter Channel</a> for further information about redeliver and which redeliver options exists.</p>

<div class='panelMacro'><table class='infoMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/confluence/images/icons/emoticons/information.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td><b>No redelivery is default for onException</b><br /><p>By default any <a href="/confluence/display/CAMEL/Exception+Clause" title="Exception Clause">Exception Clause</a> will <b>not</b> redeliver! (as it sets the <tt>maximumRedeliveries</tt> option to 0).</p></td></tr></table></div>

<p>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 <a href="/confluence/display/CAMEL/Dead+Letter+Channel" title="Dead Letter Channel">Dead Letter Channel</a>. </p>

<p>However if you want to customize any methods on the <a href="http://camel.apache.org/maven/camel-core/apidocs/org/apache/camel/processor/RedeliveryPolicy.html" rel="nofollow">RedeliveryPolicy</a> object, you can do this via the fluent API. So lets retry in case of ValidationException up till two times.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
onException(ValidationException.class).
  maximumRedeliveries(2);
</pre>
</div></div>

<p>And the spring DSL:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;onException&gt;</span>
   <span class="code-tag">&lt;exception&gt;</span>com.mycompany.ValidationException<span class="code-tag">&lt;/exception&gt;</span>
   <span class="code-tag">&lt;redeliveryPolicy maximumRedeliveries=<span class="code-quote">"2"</span>/&gt;</span>
<span class="code-tag">&lt;/onException&gt;</span>
</pre>
</div></div>

<p>You can customize any of the <a href="http://camel.apache.org/maven/camel-core/apidocs/org/apache/camel/processor/RedeliveryPolicy.html" rel="nofollow">RedeliveryPolicy</a> so we can for instance set a different delay of 5000 millis:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;onException&gt;</span>
   <span class="code-tag">&lt;exception&gt;</span>com.mycompany.ValidationException<span class="code-tag">&lt;/exception&gt;</span>
   <span class="code-tag">&lt;redeliveryPolicy maximumRedeliveries=<span class="code-quote">"2"</span> delay=<span class="code-quote">"5000"</span>/&gt;</span>
<span class="code-tag">&lt;/onException&gt;</span>
</pre>
</div></div>

<h4><a name="ExceptionClause-ReusingReliveryPolicy"></a>Reusing ReliveryPolicy</h4>
<p><b>Available as of Camel 1.5.1 or later</b><br/>
You can reference a <tt>RedeliveryPolicy</tt> so you can reuse existing configurations and use standard spring bean style configuration that supports property placeholders.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
    <span class="code-tag">&lt;bean id=<span class="code-quote">"myRedeliveryPolicy"</span> class=<span class="code-quote">"org.apache.camel.processor.RedeliveryPolicy"</span>&gt;</span>
        <span class="code-tag">&lt;property name=<span class="code-quote">"maximumRedeliveries"</span> value=<span class="code-quote">"${myprop.max}"</span>/&gt;</span>
    <span class="code-tag">&lt;/bean&gt;</span>

     <span class="code-tag">&lt;onException&gt;</span>
         <span class="code-tag"><span class="code-comment">&lt;!-- you can define multiple exceptions just adding more exception elements as show below --&gt;</span></span>
         <span class="code-tag">&lt;exception&gt;</span>com.mycompany.MyFirstException<span class="code-tag">&lt;/exception&gt;</span>
         <span class="code-tag">&lt;exception&gt;</span>com.mycompany.MySecondException<span class="code-tag">&lt;/exception&gt;</span>

         <span class="code-tag"><span class="code-comment">&lt;!-- here we reference our redelivery policy defined above --&gt;</span></span>
         <span class="code-tag">&lt;redeliveryPolicy ref=<span class="code-quote">"myRedeliveryPolicy"</span>/&gt;</span>
     <span class="code-tag">&lt;/onException&gt;</span>
</pre>
</div></div>

<h3><a name="ExceptionClause-Catchingmultipleexceptions"></a>Catching multiple exceptions</h3>
<p><b>Available as of Camel 1.5</b></p>

<p>In Camel 1.5 the <b>exception</b> clauses has been renamed to <b>onException</b> and it also supports multiple exception classes:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
onException(MyBusinessException.class, MyOtherBusinessException.class)
  .maximumRedeliveries(2)
  .to(<span class="code-quote">"activemq:businessFailed"</span>);
</pre>
</div></div>

<p>And in Spring DSL you just add another exception element:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;onException&gt;</span>
   <span class="code-tag">&lt;exception&gt;</span>com.mycompany.MyBusinessException<span class="code-tag">&lt;/exception&gt;</span>
   <span class="code-tag">&lt;exception&gt;</span>com.mycompany.MyOtherBusinessException<span class="code-tag">&lt;/exception&gt;</span>
   <span class="code-tag">&lt;redeliveryPolicy maximumRedeliveries=<span class="code-quote">"2"</span>/&gt;</span>
   <span class="code-tag">&lt;to uri=<span class="code-quote">"activemq:businessFailed"</span>/&gt;</span>
<span class="code-tag">&lt;/onException&gt;</span>
</pre>
</div></div>

<h3><a name="ExceptionClause-Usingaprocessorasfailurehandler"></a>Using a processor as failure handler</h3>
<p>We want to handle certain exceptions specially so we add a <b>onException</b> clause for that exception. </p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-comment">// here we register exception cause <span class="code-keyword">for</span> MyFunctionException
</span><span class="code-comment">// when <span class="code-keyword">this</span> exception occur we want it to be processed by our proceesor
</span>onException(MyFunctionalException.class).process(<span class="code-keyword">new</span> MyFunctionFailureHandler()).stop();
</pre>
</div></div>

<p>So what happens is that whenever a <tt>MyFunctionalException</tt> is thrown it is being routed to our processor <tt>MyFunctionFailureHandler</tt>. 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 <a href="/confluence/display/CAMEL/Dead+Letter+Channel" title="Dead Letter Channel">Dead Letter Channel</a> 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 <b>failure handled</b>. So our processor is the end of the route. So lets look the code for our processor.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-keyword">public</span> <span class="code-keyword">static</span> class MyFunctionFailureHandler <span class="code-keyword">implements</span> Processor {

    <span class="code-keyword">public</span> void process(Exchange exchange) <span class="code-keyword">throws</span> Exception {
        <span class="code-comment">// the caused by exception is stored in a property on the exchange
</span>        Throwable caused = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Throwable.class);
        assertNotNull(caused);
        <span class="code-comment">// here you can <span class="code-keyword">do</span> what you want, but Camel regard <span class="code-keyword">this</span> exception as handled, and
</span>        <span class="code-comment">// <span class="code-keyword">this</span> processor as a failurehandler, so it wont <span class="code-keyword">do</span> redeliveries. So <span class="code-keyword">this</span> is the
</span>        <span class="code-comment">// end of <span class="code-keyword">this</span> route. But <span class="code-keyword">if</span> we want to route it somewhere we can just get a
</span>        <span class="code-comment">// producer template and send it.
</span>
        <span class="code-comment">// send it to our mock endpoint
</span>        exchange.getContext().createProducerTemplate().send(<span class="code-quote">"mock:myerror"</span>, exchange);
    }
}
</pre>
</div></div>
<p>Notice how we get the <b>caused by</b> 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.</p>

<h2><a name="ExceptionClause-Markingexceptionsasbeinghandled"></a>Marking exceptions as being handled</h2>
<p><b>Available as of Camel 1.5</b></p>

<p>Using <b>onException</b> 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 <b>handle</b> DSL. The handle is a <a href="/confluence/display/CAMEL/Predicate" title="Predicate">Predicate</a> that is overloaded to accept three types of parameters:</p>
<ul class="alternate" type="square">
	<li>Boolean</li>
	<li><a href="/confluence/display/CAMEL/Predicate" title="Predicate">Predicate</a></li>
	<li><a href="/confluence/display/CAMEL/Expression" title="Expression">Expression</a> that will be evaluates as a <a href="/confluence/display/CAMEL/Predicate" title="Predicate">Predicate</a> using this rule set: If the expressions returns a Boolean its used directly. For any other response its regarded as <tt>true</tt> if the response is <tt>not null</tt>.</li>
</ul>


<p>For instance to mark all <tt>ValidationException</tt> as being handled we can do this:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  onException(ValidationException).handled(<span class="code-keyword">true</span>);
</pre>
</div></div>

<h3><a name="ExceptionClause-Exampleusinghandled"></a>Example using handled</h3>
<p>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:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-comment">// we <span class="code-keyword">do</span> special error handling <span class="code-keyword">for</span> when OrderFailedException is thrown
</span>onException(OrderFailedException.class)
    <span class="code-comment">// we mark the exchange as handled so the caller doesn't receive the
</span>    <span class="code-comment">// OrderFailedException but whatever we want to <span class="code-keyword">return</span> instead
</span>    .handled(<span class="code-keyword">true</span>)
    <span class="code-comment">// <span class="code-keyword">this</span> bean handles the error handling where we can customize the error
</span>    <span class="code-comment">// response using java code
</span>    .bean(OrderService.class, <span class="code-quote">"orderFailed"</span>)
    <span class="code-comment">// and since <span class="code-keyword">this</span> is an unit test we use mocks <span class="code-keyword">for</span> testing
</span>    .to(<span class="code-quote">"mock:error"</span>);

<span class="code-comment">// <span class="code-keyword">this</span> is just the <span class="code-keyword">generic</span> error handler where we set the destination
</span><span class="code-comment">// and the number of redeliveries we want to <span class="code-keyword">try</span>
</span>errorHandler(deadLetterChannel(<span class="code-quote">"mock:error"</span>).maximumRedeliveries(1));

<span class="code-comment">// <span class="code-keyword">this</span> is our route where we handle orders
</span>from(<span class="code-quote">"direct:start"</span>)
    <span class="code-comment">// <span class="code-keyword">this</span> bean is our order service
</span>    .bean(OrderService.class, <span class="code-quote">"handleOrder"</span>)
    <span class="code-comment">// <span class="code-keyword">this</span> is the destination <span class="code-keyword">if</span> the order is OK
</span>    .to(<span class="code-quote">"mock:result"</span>);
</pre>
</div></div>
<p>Then we have our service beans that is just plain POJO demonstrating how you can use <a href="/confluence/display/CAMEL/Bean+Integration" title="Bean Integration">Bean Integration</a> in Camel to avoid being tied to the Camel API:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">/**
 * Order service as a plain POJO class
 */
<span class="code-keyword">public</span> <span class="code-keyword">static</span> class OrderService {

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

    /**
     * This method creates the response to the caller <span class="code-keyword">if</span> the order could not be processed
     * @param in      the in headers
     * @param payload the in payload
     * @param out     the out headers
     * @<span class="code-keyword">return</span> the out payload
     */
    <span class="code-keyword">public</span> <span class="code-object">Object</span> orderFailed(@Headers Map in, @Body <span class="code-object">String</span> payload, @OutHeaders Map out) {
        out.put(<span class="code-quote">"customerid"</span>, in.get(<span class="code-quote">"customerid"</span>));
        out.put(<span class="code-quote">"orderid"</span>, <span class="code-quote">"failed"</span>);
        <span class="code-keyword">return</span> <span class="code-quote">"Order ERROR"</span>;
    }
}
</pre>
</div></div>
<p>And finally the exception that is being thrown is just a regular exception:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">/**
 * Exception thrown <span class="code-keyword">if</span> the order cannot be processed
 */
<span class="code-keyword">public</span> <span class="code-keyword">static</span> class OrderFailedException <span class="code-keyword">extends</span> Exception {

    <span class="code-keyword">public</span> OrderFailedException(<span class="code-object">String</span> message) {
        <span class="code-keyword">super</span>(message);
    }
    
}
</pre>
</div></div>

<p>So what happens?</p>

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

<p>If the order could <b>not</b> be processed and thus an OrderFailedException was thrown the caller will <b>not</b> 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 <tt>orderFailed</tt> method in our <tt>OrderService</tt>. So the caller receives an Exchange with the payload <tt>Order ERROR</tt> and a <tt>orderid=failed</tt> in a header.</p>

<h3><a name="ExceptionClause-UsinghandledwithSpringDSL"></a>Using handled with Spring DSL</h3>
<p>The same route as above in Spring DSL:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml"><span class="code-tag"><span class="code-comment">&lt;!-- setup our error handler as the deal letter channel --&gt;</span></span>
<span class="code-tag">&lt;bean id=<span class="code-quote">"errorHandler"</span> class=<span class="code-quote">"org.apache.camel.builder.DeadLetterChannelBuilder"</span>&gt;</span>
    <span class="code-tag">&lt;property name=<span class="code-quote">"deadLetterUri"</span> value=<span class="code-quote">"mock:error"</span>/&gt;</span>
<span class="code-tag">&lt;/bean&gt;</span>

<span class="code-tag"><span class="code-comment">&lt;!-- this is our POJO bean with our business logic defined as a plain spring bean --&gt;</span></span>
<span class="code-tag">&lt;bean id=<span class="code-quote">"orderService"</span> class=<span class="code-quote">"org.apache.camel.spring.processor.onexception.OrderService"</span> /&gt;</span>

<span class="code-tag"><span class="code-comment">&lt;!-- this is the camel context where we define the routes --&gt;</span></span>
<span class="code-tag"><span class="code-comment">&lt;!-- define our error handler as a global error handler --&gt;</span></span>
<span class="code-tag">&lt;camelContext errorHandlerRef=<span class="code-quote">"errorHandler"</span> xmlns=<span class="code-quote">"http://camel.apache.org/schema/spring"</span>&gt;</span>

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

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

<span class="code-tag">&lt;/camelContext&gt;</span>
</pre>
</div></div>

<h3><a name="ExceptionClause-Handlingandsendingafixedresponsebacktotheclient"></a>Handling and sending a fixed response back to the client</h3>
<p>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 <a href="/confluence/display/CAMEL/Message+Translator" title="Message Translator">transform</a> to set the response, as shown in the sample below:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-comment">// we <span class="code-keyword">catch</span> MyFunctionalException and want to mark it as handled (= no failure returned to client)
</span><span class="code-comment">// but we want to <span class="code-keyword">return</span> a fixed text response, so we transform OUT body as Sorry.
</span>onException(MyFunctionalException.class)
        .handled(<span class="code-keyword">true</span>)
        .transform().constant(<span class="code-quote">"Sorry"</span>);
</pre>
</div></div>

<p>We modify the sample slightly to return the original caused exception message instead of the fixed text Sorry:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-comment">// we <span class="code-keyword">catch</span> MyFunctionalException and want to mark it as handled (= no failure returned to client)
</span><span class="code-comment">// but we want to <span class="code-keyword">return</span> a fixed text response, so we transform OUT body and <span class="code-keyword">return</span> the exception message
</span>onException(MyFunctionalException.class)
        .handled(<span class="code-keyword">true</span>)
        .transform(exceptionMessage());
</pre>
</div></div>

<p>And we can use the <a href="/confluence/display/CAMEL/Simple" title="Simple">Simple</a> language to set a readable error message with the caused excepetion message:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-comment">// we <span class="code-keyword">catch</span> MyFunctionalException and want to mark it as handled (= no failure returned to client)
</span><span class="code-comment">// but we want to <span class="code-keyword">return</span> a fixed text response, so we transform OUT body and <span class="code-keyword">return</span> a nice message
</span><span class="code-comment">// using the simple language where we want insert the exception message
</span>onException(MyFunctionalException.class)
        .handled(<span class="code-keyword">true</span>)
        .transform().simple(<span class="code-quote">"Error reported: ${exception.message} - cannot process <span class="code-keyword">this</span> message."</span>);
</pre>
</div></div>

<h3><a name="ExceptionClause-UsinguseOriginalMessage"></a>Using useOriginalMessage</h3>
<p><b>Available as of Camel 2.0</b><br/>
The option <b>useOriginalMessage</b> is used for routing the original input body instead of the current body that potential is modified during routing.</p>

<p>For instance if you have this route:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
   from(<span class="code-quote">"jms:queue:order:input"</span>)
       .to(<span class="code-quote">"bean:validateOrder"</span>);
       .to(<span class="code-quote">"bean:transformOrder"</span>)
       .to(<span class="code-quote">"bean:handleOrder"</span>);
</pre>
</div></div>
<p>The route listen for JMS messages and validates, transforms and handle it. During this the <a href="/confluence/display/CAMEL/Exchange" title="Exchange">Exchange</a> 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 <b>onException</b>. But when we move the <a href="/confluence/display/CAMEL/Exchange" title="Exchange">Exchange</a> 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 <tt>jms:queue:order:input</tt>. So we can do this by enabling the <b>useOriginalMessage</b> option as shown below:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
    <span class="code-comment">// will use original input body
</span>    onException(MyOrderException.class)
       .useOriginalMessage().handled(<span class="code-keyword">true</span>)
       .to(<span class="code-quote">"jms:queue:order:failed"</span>);
</pre>
</div></div>

<p>Then the messages routed to the <tt>jms:queue:order:failed</tt> 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.</p>

<h4><a name="ExceptionClause-useOriginalMessagewithSpringDSL"></a>useOriginalMessage with Spring DSL</h4>
<p>The <b>useOriginalMessage</b> option is defined as a boolean attribute on the &lt;onException&gt; XML tag in Spring DSL. So the definition above would be:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
    <span class="code-tag">&lt;onException useOriginalMessage=<span class="code-quote">"true"</span>&gt;</span>
        <span class="code-tag">&lt;exception&gt;</span>com.mycompany.MyOrderException<span class="code-tag">&lt;/exception&gt;</span>
        <span class="code-tag">&lt;handled&gt;</span><span class="code-tag">&lt;constant&gt;</span>true<span class="code-tag">&lt;/constant&gt;</span><span class="code-tag">&lt;/handled&gt;</span>
        <span class="code-tag">&lt;to uri=<span class="code-quote">"jms:queue:order:failed"</span>/&gt;</span>
    <span class="code-tag">&lt;/onException&gt;</span>
</pre>
</div></div>

<h2><a name="ExceptionClause-AdvancedUsageofExceptionClause"></a>Advanced Usage of <a href="/confluence/display/CAMEL/Exception+Clause" title="Exception Clause">Exception Clause</a></h2>

<h3><a name="ExceptionClause-Usingglobalandperrouteexceptionclauses"></a>Using global and per route exception clauses</h3>
<p>Camel supports quite advanced configuration of exception clauses.</p>

<p>You can define exception clauses either as:</p>
<ul class="alternate" type="square">
	<li>global</li>
	<li>or route specific</li>
</ul>


<p>We start off with the sample sample that we change over time. First off we use only global exception clauses:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-comment">// <span class="code-keyword">default</span> should errors go to mock:error
</span>errorHandler(deadLetterChannel(<span class="code-quote">"mock:error"</span>).redeliverDelay(0));

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

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

<span class="code-comment">// here we route message to our service bean
</span>from(<span class="code-quote">"direct:start"</span>)
    .choice()
        .when().xpath(<span class="code-quote">"<span class="code-comment">//type = 'myType'"</span>).to(<span class="code-quote">"bean:myServiceBean"</span>)
</span>    .end()
    .to(<span class="code-quote">"mock:result"</span>);
</pre>
</div></div>

<p>In the next sample we change the global exception policies to be pure route specific.</p>
<div class='panelMacro'><table class='infoMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/confluence/images/icons/emoticons/information.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td><b>Must use .end() for route specific exception policies</b><br /><p><b>Important:</b> This requires to end the <b>onException</b> route with <tt>.end()</tt> to indicate where it stops and when the regular route continues.</p></td></tr></table></div>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-comment">// <span class="code-keyword">default</span> should errors go to mock:error
</span>errorHandler(deadLetterChannel(<span class="code-quote">"mock:error"</span>));

<span class="code-comment">// here we start the routing with the consumer
</span>from(<span class="code-quote">"direct:start"</span>)

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

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

    <span class="code-comment">// here we have the regular routing
</span>    .choice()
        .when().xpath(<span class="code-quote">"<span class="code-comment">//type = 'myType'"</span>).to(<span class="code-quote">"bean:myServiceBean"</span>)
</span>    .end()
    .to(<span class="code-quote">"mock:result"</span>);
</pre>
</div></div>

<p>And now it gets complex as we combine global and route specific exception policies as we introduce a 2nd route in the sample:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-comment">// global error handler
</span><span class="code-comment">// as its based on a unit test we <span class="code-keyword">do</span> not have any delays between and <span class="code-keyword">do</span> not log the stack trace
</span>errorHandler(deadLetterChannel(<span class="code-quote">"mock:error"</span>).redeliverDelay(0).logStackTrace(<span class="code-keyword">false</span>));

<span class="code-comment">// shared <span class="code-keyword">for</span> both routes
</span>onException(MyTechnicalException.class).handled(<span class="code-keyword">true</span>).maximumRedeliveries(2).to(<span class="code-quote">"mock:tech.error"</span>);

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

from(<span class="code-quote">"direct:start2"</span>)
    <span class="code-comment">// route specific on exception <span class="code-keyword">for</span> MyFunctionalException that is different than the previous route
</span>    <span class="code-comment">// here we marked it as handled and send it to a different destination mock:handled
</span>    <span class="code-comment">// we MUST use .end() to indicate that <span class="code-keyword">this</span> sub block is ended
</span>    .onException(MyFunctionalException.class).handled(<span class="code-keyword">true</span>).maximumRedeliveries(0).to(<span class="code-quote">"mock:handled"</span>).end()
    .to(<span class="code-quote">"bean:myServiceBean"</span>)
    .to(<span class="code-quote">"mock:result"</span>);
</pre>
</div></div>
<p>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. </p>

<p>And finally we top this by throwing in a nested error handler as well, as we add the 3rd route shown below:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">from(<span class="code-quote">"direct:start3"</span>)
    <span class="code-comment">// route specific error handler that is different than the global error handler
</span>    <span class="code-comment">// here we <span class="code-keyword">do</span> not redeliver and send errors to mock:error3 instead of the global endpoint
</span>    .errorHandler(deadLetterChannel(<span class="code-quote">"mock:error3"</span>)
            .maximumRedeliveries(0))

    <span class="code-comment">// route specific on exception to mark MyFunctionalException as being handled
</span>    .onException(MyFunctionalException.class).handled(<span class="code-keyword">true</span>).end()
    <span class="code-comment">// however we want the IO exceptions to redeliver at most 3 times
</span>    .onException(IOException.class).maximumRedeliveries(3).end()
    .to(<span class="code-quote">"bean:myServiceBean"</span>)
    .to(<span class="code-quote">"mock:result"</span>);
</pre>
</div></div>

<div class='panelMacro'><table class='infoMacro'><colgroup><col width='24'><col></colgroup><tr><td valign='top'><img src="/confluence/images/icons/emoticons/information.gif" width="16" height="16" align="absmiddle" alt="" border="0"></td><td><b>Global exception policies and nested error handlers</b><br /><p>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 <b>global</b> exception clauses is really global so they also applies for nested error handlers. So if a <tt>MyTechnicalException</tt> is thrown then it's the global exception policy that is selected.</p></td></tr></table></div>

<h3><a name="ExceptionClause-UsingfinegrainedselectionusingonWhenpredicate"></a>Using fine grained selection using onWhen predicate</h3>
<p><b>Available as of Camel 1.5.1 or later</b></p>

<p>You can attach an <a href="/confluence/display/CAMEL/Expression" title="Expression">Expression</a> to the exception clause to have fine grained control when a clause should be selected or not. As it's an <a href="/confluence/display/CAMEL/Expression" title="Expression">Expression</a> you can use any kind of code to perform the test. Here is a sample:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-keyword">public</span> void configure() <span class="code-keyword">throws</span> Exception {
    errorHandler(deadLetterChannel(<span class="code-quote">"mock:error"</span>).redeliverDelay(0).maximumRedeliveries(3));

    <span class="code-comment">// here we define our onException to <span class="code-keyword">catch</span> MyUserException when
</span>    <span class="code-comment">// there is a header[user] on the exchange that is not <span class="code-keyword">null</span>
</span>    onException(MyUserException.class).onWhen(header(<span class="code-quote">"user"</span>).isNotNull())
        .maximumRedeliveries(1)
        .to(ERROR_USER_QUEUE);

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

<p>In the sample above we have two onException's defined. The first has an <b>onWhen</b> 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. <b>Notice:</b> this is not required, if the 2nd clause is omitted, then the default error handler will kick in.</p>

<h3><a name="ExceptionClause-UsingonRedeliveryprocessor"></a>Using onRedelivery processor</h3>
<p><b>Available as of Camel 2.0</b></p>

<p><a href="/confluence/display/CAMEL/Dead+Letter+Channel" title="Dead Letter Channel">Dead Letter Channel</a> has support for <b>onRedelivery</b> 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 <a href="/confluence/display/CAMEL/Exception+Clause" title="Exception Clause">Exception Clause</a> as well, so you can use per exception scoped on redelivery. Camel will fallback to use the one defined on <a href="/confluence/display/CAMEL/Dead+Letter+Channel" title="Dead Letter Channel">Dead Letter Channel</a> if any, if none exists on the <a href="/confluence/display/CAMEL/Exception+Clause" title="Exception Clause">Exception Clause</a>. See <a href="/confluence/display/CAMEL/Dead+Letter+Channel" title="Dead Letter Channel">Dead Letter Channel</a> for more details on <b>onRedelivery</b>.</p>

<p>In the code below we want to do some custom code before redelivering any IOException. So we configure an <b>onException</b> for the IOException and set the <b>onRedelivery</b> to use our custom processor:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-comment">// when we redeliver caused by an IOException we want to <span class="code-keyword">do</span> some special
</span><span class="code-comment">// code before the redeliver attempt
</span>onException(IOException.class).onRedelivery(<span class="code-keyword">new</span> MyIORedeliverPrcessor());
</pre>
</div></div>

<p>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.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-comment">// This is our processor that is executed before IOException redeliver attempt
</span><span class="code-comment">// here we can <span class="code-keyword">do</span> what we want in the java code, such as altering the message
</span>
<span class="code-keyword">public</span> <span class="code-keyword">static</span> class MyIORedeliverPrcessor <span class="code-keyword">implements</span> Processor {

    <span class="code-keyword">public</span> void process(Exchange exchange) <span class="code-keyword">throws</span> Exception {
        <span class="code-comment">// just <span class="code-keyword">for</span> show and tell, here we set a special header to instruct
</span>        <span class="code-comment">// the receive a given timeout value
</span>        exchange.getIn().setHeader(<span class="code-quote">"Timeout"</span>, 5000);
    }
}
</pre>
</div></div>

<h4><a name="ExceptionClause-UsingonRedeliveryinSpringDSL"></a>Using onRedelivery in Spring DSL</h4>
<p>In Spring DSL you need to use the <b>onRedeliveryRef</b> attribute to refer to a spring bean id that is your custom processor:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml"><span class="code-tag">&lt;onException onRedeliveryRef=<span class="code-quote">"myIORedeliverProcessor"</span>&gt;</span>
    <span class="code-tag">&lt;exception&gt;</span>java.io.IOException<span class="code-tag">&lt;/exception&gt;</span>
<span class="code-tag">&lt;/onException&gt;</span>
</pre>
</div></div>

<p>And our processor is just a regular spring bean (we use $ for the inner class as this code is based on unit testing)</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">&lt;bean id=<span class="code-quote">"myRedeliveryProcessor"</span>
      class=<span class="code-quote">"org.apache.camel.processor.DeadLetterChannelOnExceptionOnRedeliveryTest$MyRedeliverPrcessor"</span>/&gt;
</pre>
</div></div>


<h3><a name="ExceptionClause-UsingfinegrainedretryusingretryUntilpredicate"></a>Using fine grained retry using retryUntil predicate</h3>
<p><b>Available as of Camel 2.0</b></p>

<p>When you need fine grained control for determining if an exchange should be retried or not you can use the <b>retryUntil</b> predicate. Camel will redeliver until the predicate returns false.<br/>
This is demonstrated in the sample below:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-comment">// we want to use a predicate <span class="code-keyword">for</span> retries so we can determine in our bean
</span><span class="code-comment">// when retry should stop, notice it will overrule the global error handler
</span><span class="code-comment">// where we defined at most 1 redelivery attempt. Here we will <span class="code-keyword">continue</span> until
</span><span class="code-comment">// the predicate <span class="code-keyword">false</span>
</span>onException(MyFunctionalException.class)
        .retryUntil(bean(<span class="code-quote">"myRetryHandler"</span>))
        .handled(<span class="code-keyword">true</span>)
        .transform().constant(<span class="code-quote">"Sorry"</span>);
</pre>
</div></div>

<p>Where the bean myRetryHandler is computing if we should retry or not:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-keyword">public</span> class MyRetryBean {

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

        assertEquals(<span class="code-quote">"Hello World"</span>, body);
        assertTrue(causedBy <span class="code-keyword">instanceof</span> MyFunctionalException);

        <span class="code-comment">// we can of course <span class="code-keyword">do</span> what ever we want to determine the result but <span class="code-keyword">this</span> is a unit test so we end after 3 attempts
</span>        <span class="code-keyword">return</span> counter &lt; 3;
    }
}
</pre>
</div></div>

<h3><a name="ExceptionClause-UsingcustomExceptionPolicyStrategy"></a>Using custom ExceptionPolicyStrategy</h3>
<p><b>Available in Camel 1.4</b></p>

<p>The default <a href="http://camel.apache.org/maven/camel-core/apidocs/org/apache/camel/processor/exceptionpolicy/ExceptionPolicyStrategy.html" rel="nofollow">ExceptionPolicyStrategy</a> in Camel should be sufficient in nearly all use-cases (see section <em>How does Camel select which clause should handle a given thrown Exception</em>). However if you need to use your own this can be configued as the sample below illustrates:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-keyword">public</span> void configure() <span class="code-keyword">throws</span> Exception {
    <span class="code-comment">// configure the error handler to use my policy instead of the <span class="code-keyword">default</span> from Camel
</span>    errorHandler(deadLetterChannel(<span class="code-quote">"mock:error"</span>).exceptionPolicyStrategy(<span class="code-keyword">new</span> MyPolicy()));

    onException(MyPolicyException.class)
        .maximumRedeliveries(1)
        .setHeader(MESSAGE_INFO, constant(<span class="code-quote">"Damm my policy exception"</span>))
        .to(ERROR_QUEUE);

    onException(CamelException.class)
        .maximumRedeliveries(3)
        .setHeader(MESSAGE_INFO, constant(<span class="code-quote">"Damm a Camel exception"</span>))
        .to(ERROR_QUEUE);
</pre>
</div></div>

<p>Using our own strategy <b>MyPolicy</b> we can change the default behavior of Camel with our own code to resolve which <a href="http://camel.apache.org/maven/camel-core/apidocs/org/apache/camel/model/ExceptionType.html" rel="nofollow">ExceptionType</a> from above should be handling the given thrown exception. </p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-keyword">public</span> <span class="code-keyword">static</span> class MyPolicy <span class="code-keyword">implements</span> ExceptionPolicyStrategy {

    <span class="code-keyword">public</span> OnExceptionDefinition getExceptionPolicy(Map&lt;ExceptionPolicyKey, OnExceptionDefinition&gt; exceptionPolicices,
                                            Exchange exchange,
                                            Throwable exception) {
        <span class="code-comment">// This is just an example that always forces the exception type configured
</span>        <span class="code-comment">// with MyPolicyException to win.
</span>        <span class="code-keyword">return</span> exceptionPolicices.get(ExceptionPolicyKey.newInstance(MyPolicyException.class));
    }
}
</pre>
</div></div>

<h3><a name="ExceptionClause-UsingtheexceptionclauseinSpringDSL"></a>Using the exception clause in Spring DSL</h3>

<p>You can use all of the above mentioned exception clause features in the Spring DSL as well. Here are a few examples:</p>

<ul>
	<li>Global scoped - <b>Available in Camel 2.0</b>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml"><span class="code-tag"><span class="code-comment">&lt;!-- setup our error handler as the deal letter channel --&gt;</span></span>
<span class="code-tag">&lt;bean id=<span class="code-quote">"errorHandler"</span> class=<span class="code-quote">"org.apache.camel.builder.DeadLetterChannelBuilder"</span>&gt;</span>
    <span class="code-tag">&lt;property name=<span class="code-quote">"deadLetterUri"</span> value=<span class="code-quote">"mock:error"</span>/&gt;</span>
<span class="code-tag">&lt;/bean&gt;</span>

<span class="code-tag"><span class="code-comment">&lt;!-- this is our POJO bean with our business logic defined as a plain spring bean --&gt;</span></span>
<span class="code-tag">&lt;bean id=<span class="code-quote">"orderService"</span> class=<span class="code-quote">"org.apache.camel.spring.processor.onexception.OrderService"</span> /&gt;</span>

<span class="code-tag"><span class="code-comment">&lt;!-- this is the camel context where we define the routes --&gt;</span></span>
<span class="code-tag"><span class="code-comment">&lt;!-- define our error handler as a global error handler --&gt;</span></span>
<span class="code-tag">&lt;camelContext errorHandlerRef=<span class="code-quote">"errorHandler"</span> xmlns=<span class="code-quote">"http://camel.apache.org/schema/spring"</span>&gt;</span>

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

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

<span class="code-tag">&lt;/camelContext&gt;</span>
</pre>
</div></div></li>
</ul>


<ul>
	<li>Route specific scoped
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml"><span class="code-tag"><span class="code-comment">&lt;!-- setup our error handler as the deal letter channel --&gt;</span></span>
<span class="code-tag">&lt;bean id=<span class="code-quote">"deadLetter"</span> class=<span class="code-quote">"org.apache.camel.builder.DeadLetterChannelBuilder"</span>&gt;</span>
    <span class="code-tag">&lt;property name=<span class="code-quote">"deadLetterUri"</span> value=<span class="code-quote">"mock:dead"</span>/&gt;</span>
<span class="code-tag">&lt;/bean&gt;</span>

<span class="code-tag"><span class="code-comment">&lt;!-- the default error handler used in the 2nd route --&gt;</span></span>
<span class="code-tag">&lt;bean id=<span class="code-quote">"defaultErrorHandler"</span> class=<span class="code-quote">"org.apache.camel.builder.DefaultErrorHandlerBuilder"</span>/&gt;</span>

<span class="code-tag"><span class="code-comment">&lt;!-- this is our POJO bean with our business logic defined as a plain spring bean --&gt;</span></span>
<span class="code-tag">&lt;bean id=<span class="code-quote">"orderService"</span> class=<span class="code-quote">"org.apache.camel.spring.processor.onexception.OrderService"</span>/&gt;</span>

<span class="code-tag"><span class="code-comment">&lt;!-- this is the camel context where we define the routes --&gt;</span></span>
<span class="code-tag">&lt;camelContext xmlns=<span class="code-quote">"http://camel.apache.org/schema/spring"</span>&gt;</span>

    <span class="code-tag">&lt;route errorHandlerRef=<span class="code-quote">"deadLetter"</span>&gt;</span>
        <span class="code-tag">&lt;from uri=<span class="code-quote">"direct:start"</span>/&gt;</span>
        <span class="code-tag">&lt;onException&gt;</span>
            <span class="code-tag">&lt;exception&gt;</span>org.apache.camel.spring.processor.onexception.OrderFailedException<span class="code-tag">&lt;/exception&gt;</span>
            <span class="code-tag">&lt;redeliveryPolicy maximumRedeliveries=<span class="code-quote">"1"</span>/&gt;</span>
            <span class="code-tag">&lt;handled&gt;</span>
                <span class="code-tag">&lt;constant&gt;</span>true<span class="code-tag">&lt;/constant&gt;</span>
            <span class="code-tag">&lt;/handled&gt;</span>
            <span class="code-tag">&lt;bean ref=<span class="code-quote">"orderService"</span> method=<span class="code-quote">"orderFailed"</span>/&gt;</span>
            <span class="code-tag">&lt;to uri=<span class="code-quote">"mock:error"</span>/&gt;</span>
        <span class="code-tag">&lt;/onException&gt;</span>
        <span class="code-tag">&lt;bean ref=<span class="code-quote">"orderService"</span> method=<span class="code-quote">"handleOrder"</span>/&gt;</span>
        <span class="code-tag">&lt;to uri=<span class="code-quote">"mock:result"</span>/&gt;</span>
    <span class="code-tag">&lt;/route&gt;</span>

    <span class="code-tag"><span class="code-comment">&lt;!-- The exception clause specified in the first route will not be used in this route --&gt;</span></span>
    <span class="code-tag">&lt;route errorHandlerRef=<span class="code-quote">"defaultErrorHandler"</span>&gt;</span>
        <span class="code-tag">&lt;from uri=<span class="code-quote">"direct:start_with_no_handler"</span>/&gt;</span>
        <span class="code-tag">&lt;bean ref=<span class="code-quote">"orderService"</span> method=<span class="code-quote">"handleOrder"</span>/&gt;</span>
        <span class="code-tag">&lt;to uri=<span class="code-quote">"mock:result"</span>/&gt;</span>
    <span class="code-tag">&lt;/route&gt;</span>

<span class="code-tag">&lt;/camelContext&gt;</span>
</pre>
</div></div></li>
</ul>


<h3><a name="ExceptionClause-Seealso"></a>See also</h3>
<p>The <a href="/confluence/display/CAMEL/Error+Handler" title="Error Handler">Error Handler</a> for the general error handling documentation<br/>
The <a href="/confluence/display/CAMEL/Dead+Letter+Channel" title="Dead Letter Channel">Dead Letter Channel</a> for further details.<br/>
The <a href="/confluence/display/CAMEL/Transactional+Client" title="Transactional Client">Transactional Client</a> for transactional behavior</p>


     </div>
     <div id="commentsSection" class="wiki-content pageSection">
       <div style="float: right;">
            <a href="http://cwiki.apache.org/confluence/users/viewnotifications.action" class="grey">Change Notification Preferences</a>
       </div>

       <a href="http://cwiki.apache.org/confluence/display/CAMEL/Exception+Clause">View Online</a>
       |
       <a href="http://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=63781&revisedVersion=44&originalVersion=43">View Change</a>
              |
       <a href="http://cwiki.apache.org/confluence/display/CAMEL/Exception+Clause?showComments=true&amp;showCommentArea=true#addcomment">Add Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message