|
Page Edited :
CAMEL :
Exception Clause
Exception Clause has been edited by Claus Ibsen (Oct 21, 2008). Change summary: CAMEL-1001 Exception ClauseYou can use the Exception Clause in the Java DSL to specify the error handling you require on a per type basis using the exception() method. For example if you want to perform a specific piece of processing if a certain exception is raised you can do this simply via exception(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. Changes in Camel 1.5In Camel 1.5 the exception clauses has been renamed to onException and it also supports multiple exception classes: onException(MyBusinessException.class, MyOtherBusinessException.class).
to("activemq:businessFailed");
But the most important new feature is support for marking exceptions as being handled. Marking exceptions as being handledAvailable 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:
For instance to mark all ValidationException as being handled we can do this: onException(ValidationException).handled(true);
Example using handledIn 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 can not 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("Can not 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 can not 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 DSLIn Spring DSL only booleans is supported for setting handled as either true or false. The same route as above in Spring DSL: <!-- 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://activemq.apache.org/camel/schema/spring"> <route> <!-- the route --> <from uri="direct:start"/> <!-- we must configure the on exception within the route, as opposed to Java DSL where we can do this outside --> <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</maximumRedeliveries> </redeliveryPolicy> <!-- mark this as handled. Spring DSL only support boolean types --> <handled>true</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> <!-- 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> Overloading the RedeliveryPolicyThe 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. Sometimes you want to overload the redelivery policy on a per exception type basis. By default in the above examples, if a ValidationException occurs then the message will not be redelivered; however if some other exception occurs (such as a JDBC deadlock or remote method invocation) the route will be retried. However if you want to customize any methods on the RedeliveryPolicy onException(MyException.class). maximumRedeliveries(2); You can mix and match these approaches; specifying a custom processor to be used after all the redeliveries fail together with customizing any aspect of the RedeliveryPolicy |
Unsubscribe or edit your notifications preferences
