You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2008/12/04 14:27:12 UTC

svn commit: r723314 - in /activemq/camel/trunk/camel-core/src: main/java/org/apache/camel/processor/exceptionpolicy/DefaultExceptionPolicyStrategy.java test/java/org/apache/camel/processor/onexception/OnExceptionWrappedExceptionTest.java

Author: davsclaus
Date: Thu Dec  4 05:27:12 2008
New Revision: 723314

URL: http://svn.apache.org/viewvc?rev=723314&view=rev
Log:
CAMEL-1144: DefaultExceptionPolicyStrategy now tests caused by exceptions (using bottom to top exception hieracy iterator)

Added:
    activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionWrappedExceptionTest.java   (contents, props changed)
      - copied, changed from r723229, activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionRouteTest.java
Modified:
    activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/DefaultExceptionPolicyStrategy.java

Modified: activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/DefaultExceptionPolicyStrategy.java
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/DefaultExceptionPolicyStrategy.java?rev=723314&r1=723313&r2=723314&view=diff
==============================================================================
--- activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/DefaultExceptionPolicyStrategy.java (original)
+++ activemq/camel/trunk/camel-core/src/main/java/org/apache/camel/processor/exceptionpolicy/DefaultExceptionPolicyStrategy.java Thu Dec  4 05:27:12 2008
@@ -18,6 +18,10 @@
 
 import java.util.Map;
 import java.util.Set;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.model.ExceptionType;
@@ -31,11 +35,13 @@
  * <b>Selection strategy:</b>
  * <br/>This strategy applies the following rules:
  * <ul>
- *   <li>The exception type must be configured with an Exception that is an instance of the thrown exception, this
- *  is tested using the {@link #filter(org.apache.camel.model.ExceptionType, Class, Throwable)} method. </li>
- *   <li>If the exception type has exactly the thrown exception then its selected as its an exact match</li>
- *   <li>Otherwise the type that has an exception that is the closests super of the thrown exception is selected
- *       (recurring up the exception hierarchy)</li>
+ * <li>Will walk the exception hieracy from bottom upwards till the thrown exception, meaning that the most outer caused
+ * by is selected first, ending with the thrown exception itself</li>
+ * <li>The exception type must be configured with an Exception that is an instance of the thrown exception, this
+ * is tested using the {@link #filter(org.apache.camel.model.ExceptionType, Class, Throwable)} method. </li>
+ * <li>If the exception type has exactly the thrown exception then its selected as its an exact match</li>
+ * <li>Otherwise the type that has an exception that is the closests super of the thrown exception is selected
+ * (recurring up the exception hierarchy)</li>
  * </ul>
  * <p/>
  * <b>Fine grained matching:</b>
@@ -50,6 +56,22 @@
 
     public ExceptionType getExceptionPolicy(Map<ExceptionPolicyKey, ExceptionType> exceptionPolicices, Exchange exchange,
                                             Throwable exception) {
+
+        // recursive up the tree using the iterator
+        Iterator<Throwable> it = new ExceptionIterator(exception);
+        while (it.hasNext()) {
+            ExceptionType type = doGetExceptionPolicy(exceptionPolicices, exchange, it.next());
+            if (type != null) {
+                return type;
+            }
+        }
+
+        // no type found
+        return null;
+    }
+
+    private ExceptionType doGetExceptionPolicy(Map<ExceptionPolicyKey, ExceptionType> exceptionPolicices, Exchange exchange,
+                                               Throwable exception) {
         if (LOG.isDebugEnabled()) {
             LOG.debug("Finding best suited exception policy for thrown exception " + exception.getClass().getName());
         }
@@ -109,10 +131,10 @@
     /**
      * Strategy to filter the given type exception class with the thrown exception
      *
-     * @param type  the exception type
-     * @param exceptionClass  the current exception class for testing
-     * @param exception  the thrown exception
-     * @return <tt>true</tt> if the to current exception class is a candidate, <tt>false</tt> to skip it. 
+     * @param type           the exception type
+     * @param exceptionClass the current exception class for testing
+     * @param exception      the thrown exception
+     * @return <tt>true</tt> if the to current exception class is a candidate, <tt>false</tt> to skip it.
      */
     protected boolean filter(ExceptionType type, Class exceptionClass, Throwable exception) {
         // must be instance of check to ensure that the exceptionClass is one type of the thrown exception
@@ -124,12 +146,12 @@
      * <p/>
      * This default implementation will match as:
      * <ul>
-     *   <li>Always true if no when predicate on the exception type
-     *   <li>Otherwise the when predicate is matches against the current exchange
+     * <li>Always true if no when predicate on the exception type
+     * <li>Otherwise the when predicate is matches against the current exchange
      * </ul>
      *
-     * @param type  the exception type
-     * @param exchange  the current {@link Exchange}
+     * @param type     the exception type
+     * @param exchange the current {@link Exchange}
      * @return <tt>true</tt> if matched, <tt>false</tt> otherwise.
      */
     protected boolean matchesWhen(ExceptionType type, Exchange exchange) {
@@ -147,4 +169,40 @@
         return 1 + getInheritanceLevel(clazz.getSuperclass());
     }
 
+    /**
+     * Iterator that walks the exception hieracy in the order we should match.
+     * <p/>
+     * Will default walk from bottom upwards to the root exception
+     */
+    protected class ExceptionIterator implements Iterator<Throwable> {
+        private List<Throwable> tree = new ArrayList<Throwable>();
+        private Iterator<Throwable> it;
+
+        public ExceptionIterator(Throwable exception) {
+            Throwable current = exception;
+            // spool to the bottom of the caused by tree
+            while (current != null) {
+                tree.add(current);
+                current = current.getCause();
+            }
+
+            // reverse tree so we go from bottom to top
+            Collections.reverse(tree);
+            it = tree.iterator();
+        }
+
+        public boolean hasNext() {
+            return it.hasNext();
+        }
+
+        public Throwable next() {
+            return it.next();
+        }
+
+        public void remove() {
+            it.remove();
+        }
+    }
+
+
 }

Copied: activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionWrappedExceptionTest.java (from r723229, activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionRouteTest.java)
URL: http://svn.apache.org/viewvc/activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionWrappedExceptionTest.java?p2=activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionWrappedExceptionTest.java&p1=activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionRouteTest.java&r1=723229&r2=723314&rev=723314&view=diff
==============================================================================
--- activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionRouteTest.java (original)
+++ activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionWrappedExceptionTest.java Thu Dec  4 05:27:12 2008
@@ -17,116 +17,55 @@
 package org.apache.camel.processor.onexception;
 
 import org.apache.camel.ContextTestSupport;
-import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverter;
 import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.impl.JndiRegistry;
+import static org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException;
 
 /**
- * Unit test inspired by user forum.
+ * Unit test to test that onException handles wrapped exceptions
  */
-public class OnExceptionRouteTest extends ContextTestSupport {
+public class OnExceptionWrappedExceptionTest extends ContextTestSupport {
 
-    private MyOwnHandlerBean myOwnHandlerBean;
-    private MyServiceBean myServiceBean;
-
-    public void testNoError() throws Exception {
+    public void testWrappedException() throws Exception {
         getMockEndpoint("mock:error").expectedMessageCount(0);
+        getMockEndpoint("mock:wrapped").expectedMessageCount(1);
+        getMockEndpoint("mock:end").expectedMessageCount(0);
 
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMessageCount(1);
-
-        template.sendBody("direct:start", "<order><type>myType</type><user>James</user></order>");
+        template.sendBody("direct:start", "Hello World");
 
         assertMockEndpointsSatisfied();
     }
 
-    public void testFunctionalError() throws Exception {
-        getMockEndpoint("mock:error").expectedMessageCount(0);
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                context.getTypeConverterRegistry().addTypeConverter(LocalDateTime.class, String.class, new MyLocalDateTimeConverter());
 
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMessageCount(0);
+                errorHandler(deadLetterChannel("mock:error"));
 
-        template.sendBody("direct:start", "<order><type>myType</type><user>Func</user></order>");
+                onException(IllegalArgumentException.class).handled(true).to("mock:wrapped");
 
-        assertMockEndpointsSatisfied();
-        assertEquals("<order><type>myType</type><user>Func</user></order>", myOwnHandlerBean.getPayload());
+                from("direct:start").convertBodyTo(LocalDateTime.class).to("mock:end");
+            }
+        };
     }
 
-    public void testTechnicalError() throws Exception {
-        getMockEndpoint("mock:error").expectedMessageCount(1);
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMessageCount(0);
-
-        template.sendBody("direct:start", "<order><type>myType</type><user>Tech</user></order>");
-
-        assertMockEndpointsSatisfied();
-        // should not handle it
-        assertNull(myOwnHandlerBean.getPayload());
+    public static class LocalDateTime {
     }
 
-    public void testErrorWhileHandlingException() throws Exception {
-        getMockEndpoint("mock:error").expectedMessageCount(0);
-
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMessageCount(0);
+    private class MyLocalDateTimeConverter implements TypeConverter {
 
-        try {
-            template.sendBody("direct:start", "<order><type>myType</type><user>FuncError</user></order>");
-            fail("Should throw a RuntimeCamelException");
-        } catch (RuntimeCamelException e) {
-            assertEquals("Damm something did not work", e.getCause().getMessage());
+        public <T> T convertTo(Class<T> type, Object value) {
+            // simulate @Converter where we wrap thrown exception in RuntimeCamelException
+            throw wrapRuntimeCamelException(new IllegalArgumentException("Bad Data"));
         }
 
-        assertMockEndpointsSatisfied();
-        // should not handle it
-        assertNull(myOwnHandlerBean.getPayload());
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        myOwnHandlerBean = new MyOwnHandlerBean();
-        myServiceBean = new MyServiceBean();
-        super.setUp();
-    }
-
-    @Override
-    protected JndiRegistry createRegistry() throws Exception {
-        JndiRegistry jndi = super.createRegistry();
-        jndi.bind("myOwnHandler", myOwnHandlerBean);
-        jndi.bind("myServiceBean", myServiceBean);
-        return jndi;
-    }
-
-    @Override
-    protected RouteBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                // default should errors go to mock:error
-                errorHandler(deadLetterChannel("mock:error"));
-                
-                // START SNIPPET: e1
-                // 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 SNIPPET: e1
-                        .to("mock:result");
-            }
-        };
+        public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
+            return convertTo(type, value);
+        }
     }
 
-
-}
+}
\ No newline at end of file

Propchange: activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionWrappedExceptionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionWrappedExceptionTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Propchange: activemq/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/onexception/OnExceptionWrappedExceptionTest.java
------------------------------------------------------------------------------
    svn:mergeinfo =