You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by li...@apache.org on 2012/04/11 17:38:20 UTC

[5/6] git commit: Adding implementation and fixing checkstyle.

Adding implementation and fixing checkstyle.

There are test failures now because of not being able to find an
implementation of on of the interfaces. I'll look at those later.


Project: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/commit/46285dcb
Tree: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/tree/46285dcb
Diff: http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/diff/46285dcb

Branch: refs/heads/master
Commit: 46285dcbcbe329b623c6fd0d14005c7ca8c6559f
Parents: ac5bc0f
Author: Jason Porter <li...@apache.org>
Authored: Mon Apr 9 22:02:49 2012 -0600
Committer: Jason Porter <li...@apache.org>
Committed: Tue Apr 10 16:31:05 2012 -0600

----------------------------------------------------------------------
 .gitignore                                         |    1 +
 .../core/api/exception/control/BeforeHandles.java  |    9 +-
 .../api/exception/control/CaughtException.java     |   46 ++--
 .../api/exception/control/ExceptionHandler.java    |    6 +-
 .../exception/control/ExceptionHandlingFlow.java   |   33 ++
 .../core/api/exception/control/ExceptionStack.java |   34 ++-
 .../api/exception/control/ExceptionStackItem.java  |    4 +-
 .../api/exception/control/ExceptionToCatch.java    |    7 +-
 .../core/api/exception/control/HandlerMethod.java  |    8 +-
 .../exception/control/HandlerMethodStorage.java    |   21 +-
 .../core/api/exception/control/Handles.java        |    8 +-
 .../control/ExceptionHandlerComparator.java        |  103 +++++
 .../control/ExceptionHandlerDispatch.java          |  223 +++++++++++
 .../impl/exception/control/HandlerMethodImpl.java  |  303 +++++++++++++++
 .../control/OutboundParameterValueRedefiner.java   |   78 ++++
 .../control/extension/CatchExtension.java          |  222 +++++++++++
 16 files changed, 1065 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 37cbdf9..929407e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ target
 .idea
 .checkstyle
 atlassian-ide-plugin.xml
+.sonar-ide.properties

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/BeforeHandles.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/BeforeHandles.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/BeforeHandles.java
index 9cf3135..d30756e 100644
--- a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/BeforeHandles.java
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/BeforeHandles.java
@@ -19,7 +19,12 @@
 
 package org.apache.deltaspike.core.api.exception.control;
 
-import java.lang.annotation.*;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
  * Marker annotation for a method to be considered an Exception Handler, handles the exception in the BEFORE
@@ -35,5 +40,5 @@ public @interface BeforeHandles
     /**
      * Precedence relative to callbacks for the same type
      */
-    public abstract int ordinal() default 0;
+    int ordinal() default 0;
 }

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/CaughtException.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/CaughtException.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/CaughtException.java
index a062ce4..3f7bc95 100644
--- a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/CaughtException.java
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/CaughtException.java
@@ -27,23 +27,12 @@ import javax.enterprise.inject.Typed;
  *
  * @param <T> Exception type this event represents
  */
+// CHECKSTYLE:OFF
 @SuppressWarnings({"unchecked", "CdiManagedBeanInconsistencyInspection"})
+// CHECKSTYLE:ON
 @Typed()
 public class CaughtException<T extends Throwable>
 {
-    /**
-     * Flow control enum.  Used in the dispatcher to determine how to markHandled.
-     */
-    protected enum ExceptionHandlingFlow
-    {
-        HANDLED,
-        HANDLED_AND_CONTINUE,
-        SKIP_CAUSE,
-        ABORT,
-        THROW_ORIGINAL,
-        THROW
-    }
-
     private final ExceptionStack exceptionStack;
     private final T exception;
     private boolean unmute;
@@ -56,20 +45,20 @@ public class CaughtException<T extends Throwable>
     /**
      * Initial state constructor.
      *
-     * @param exceptionStack  Information about the current exception and cause chain.
+     * @param stack           Information about the current exception and cause chain.
      * @param beforeTraversal flag indicating the direction of the cause chain traversal
      * @param handled         flag indicating the exception has already been handled by a previous handler
-     * @throws IllegalArgumentException if exceptionStack is null
+     * @throws IllegalArgumentException if stack is null
      */
-    public CaughtException(final ExceptionStack exceptionStack, final boolean beforeTraversal, final boolean handled)
+    public CaughtException(final ExceptionStack stack, final boolean beforeTraversal, final boolean handled)
     {
-        if (exceptionStack == null)
+        if (stack == null)
         {
-            throw new IllegalArgumentException("null is not valid for exceptionStack");
+            throw new IllegalArgumentException("null is not valid for stack");
         }
 
-        this.exception = (T) exceptionStack.getCurrent();
-        this.exceptionStack = exceptionStack;
+        this.exception = (T) stack.getCurrent();
+        this.exceptionStack = stack;
         this.beforeTraversal = beforeTraversal;
         this.markedHandled = handled;
         this.flow = ExceptionHandlingFlow.HANDLED_AND_CONTINUE;
@@ -130,7 +119,10 @@ public class CaughtException<T extends Throwable>
         this.unmute = true;
     }
 
-    protected boolean isUnmute()
+    /**
+     * Internal only
+     */
+    public boolean isUnmute()
     {
         return this.unmute;
     }
@@ -140,7 +132,10 @@ public class CaughtException<T extends Throwable>
     }
     */
 
-    protected ExceptionHandlingFlow getFlow()
+    /**
+     * Internal only
+     */
+    public ExceptionHandlingFlow getFlow()
     {
         return this.flow;
     }
@@ -161,7 +156,12 @@ public class CaughtException<T extends Throwable>
         this.flow = ExceptionHandlingFlow.THROW;
     }
 
-    protected Throwable getThrowNewException()
+    /**
+     * Internal only.
+     *
+     * @return
+     */
+    public Throwable getThrowNewException()
     {
         return this.throwNewException;
     }

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionHandler.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionHandler.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionHandler.java
index 31a4946..d706909 100644
--- a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionHandler.java
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionHandler.java
@@ -19,7 +19,11 @@
 
 package org.apache.deltaspike.core.api.exception.control;
 
-import java.lang.annotation.*;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
  * Marker for types containing Exception Handler methods.

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionHandlingFlow.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionHandlingFlow.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionHandlingFlow.java
new file mode 100644
index 0000000..e454e86
--- /dev/null
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionHandlingFlow.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.deltaspike.core.api.exception.control;
+
+/**
+ * Flow control enum.  Used in the dispatcher to determine how to markHandled.
+ */
+public enum ExceptionHandlingFlow
+{
+    HANDLED,
+    HANDLED_AND_CONTINUE,
+    SKIP_CAUSE,
+    ABORT,
+    THROW_ORIGINAL,
+    THROW
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionStack.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionStack.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionStack.java
index e190753..c25d26a 100644
--- a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionStack.java
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionStack.java
@@ -30,6 +30,7 @@ import java.util.Deque;
 /**
  * Information about the current exception and exception cause container.  This object is not immutable.
  */
+@SuppressWarnings("CdiManagedBeanInconsistencyInspection")
 @Typed()
 public class ExceptionStack implements Serializable
 {
@@ -58,6 +59,7 @@ public class ExceptionStack implements Serializable
         Throwable e = exception;
         this.exceptionStackItems = new ArrayDeque<ExceptionStackItem>();
 
+        // CHECKSTYLE:OFF
         do
         {
             this.exceptionStackItems.addFirst(new ExceptionStackItem(e));
@@ -73,9 +75,10 @@ public class ExceptionStack implements Serializable
             }
         }
         while ((e = e.getCause()) != null);
+        // CHECKSTYLE:ON
 
         this.initialStackSize = this.exceptionStackItems.size();
-        this.causes = this.createThrowableCollectionFrom(exceptionStackItems);
+        this.causes = this.createThrowableCollection(exceptionStackItems);
         // TODO: Later this.origExceptionStackItems = new ArrayDeque<ExceptionStackItem>(exceptionStackItems);
         this.init();
 
@@ -89,7 +92,8 @@ public class ExceptionStack implements Serializable
         {
             this.current = this.exceptionStackItems.removeFirst().getThrowable();
             this.remaining = Collections.unmodifiableCollection(this.exceptionStackItems);
-        } else
+        }
+        else
         {
             this.remaining = Collections.emptyList();
             this.current = null;
@@ -99,7 +103,7 @@ public class ExceptionStack implements Serializable
         this.next = (this.last) ? null : this.exceptionStackItems.peekFirst().getThrowable();
     }
 
-    private Collection<ExceptionStackItem> createExceptionStackCollectionFrom(Collection<Throwable> throwables)
+    private Collection<ExceptionStackItem> createExceptionStackFrom(Collection<Throwable> throwables)
     {
         final Deque<ExceptionStackItem> returningCollection = new ArrayDeque<ExceptionStackItem>(throwables.size());
 
@@ -111,9 +115,10 @@ public class ExceptionStack implements Serializable
         return returningCollection;
     }
 
-    private Collection<Throwable> createThrowableCollectionFrom(final Collection<ExceptionStackItem> exceptionStackItems)
+    private Collection<Throwable> createThrowableCollection(final Collection<ExceptionStackItem> exceptionStackItems)
     {
-        final Deque<Throwable> returningCollection = new ArrayDeque<Throwable>(exceptionStackItems.size() + 1); // allow current
+        // allow current
+        final Deque<Throwable> returningCollection = new ArrayDeque<Throwable>(exceptionStackItems.size() + 1);
 
         for (ExceptionStackItem item : exceptionStackItems)
         {
@@ -145,7 +150,7 @@ public class ExceptionStack implements Serializable
 
     public Collection<Throwable> getRemaining()
     {
-        return Collections.unmodifiableCollection(this.createThrowableCollectionFrom(this.remaining));
+        return Collections.unmodifiableCollection(this.createThrowableCollection(this.remaining));
     }
 
     /**
@@ -168,9 +173,22 @@ public class ExceptionStack implements Serializable
         return this.current;
     }
 
-    void setCauseElements(Collection<Throwable> elements)
+    /**
+     * Internal only.
+     *
+     * @param elements new stack.
+     */
+    public void setCauseElements(Collection<Throwable> elements)
+    {
+        this.exceptionStackItems = new ArrayDeque<ExceptionStackItem>(this.createExceptionStackFrom(elements));
+        this.init();
+    }
+
+    /**
+     * Internal only.
+     */
+    public void skipCause()
     {
-        this.exceptionStackItems = new ArrayDeque<ExceptionStackItem>(this.createExceptionStackCollectionFrom(elements));
         this.init();
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionStackItem.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionStackItem.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionStackItem.java
index 6484bca..14ec670 100644
--- a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionStackItem.java
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionStackItem.java
@@ -32,8 +32,8 @@ public final class ExceptionStackItem implements Serializable
 {
     private static final long serialVersionUID = 5162936095781886477L;
 
-    final private Throwable throwable;
-    final private StackTraceElement[] stackTraceElements;
+    private final Throwable throwable;
+    private final StackTraceElement[] stackTraceElements;
 
     public ExceptionStackItem(final Throwable cause)
     {

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionToCatch.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionToCatch.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionToCatch.java
index b2d4127..a1ebc2d 100644
--- a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionToCatch.java
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/ExceptionToCatch.java
@@ -70,7 +70,12 @@ public class ExceptionToCatch implements Serializable
         return this.exception;
     }
 
-    protected void setHandled(boolean handled)
+    /**
+     * Internal only.
+     *
+     * @param handled new value
+     */
+    public void setHandled(boolean handled)
     {
         this.handled = handled;
     }

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/HandlerMethod.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/HandlerMethod.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/HandlerMethod.java
index 44767a3..e2a7f40 100644
--- a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/HandlerMethod.java
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/HandlerMethod.java
@@ -43,6 +43,11 @@ public interface HandlerMethod<T extends Throwable>
     Type getExceptionType();
 
     /**
+     * Flag indicating this handler should be invoked during the before traversal.
+     */
+    boolean isBefore();
+
+    /**
      * Calls the handler method, passing the given event object.
      *
      * @param event event to pass to the handler.
@@ -56,7 +61,8 @@ public interface HandlerMethod<T extends Throwable>
     int getOrdinal();
 
     /**
-     * Basic {@link Object#equals(Object)} but must use all of the get methods from this interface to maintain compatibility.
+     * Basic {@link Object#equals(Object)} but must use all of the get methods from this interface to
+     * maintain compatibility.
      *
      * @param o Object being compared to this.
      * @return true or false based on standard equality.

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/HandlerMethodStorage.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/HandlerMethodStorage.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/HandlerMethodStorage.java
index 8c549fb..100c6fb 100644
--- a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/HandlerMethodStorage.java
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/HandlerMethodStorage.java
@@ -19,8 +19,14 @@
 
 package org.apache.deltaspike.core.api.exception.control;
 
+import javax.enterprise.inject.spi.BeanManager;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.Set;
+
 /**
- * Injectable storage to support programmatic registration of {@link HandlerMethod} instances.
+ * Injectable storage to support programmatic registration and lookup of {@link HandlerMethod} instances.
  */
 public interface HandlerMethodStorage
 {
@@ -30,4 +36,17 @@ public interface HandlerMethodStorage
      * @param handlerMethod HandlerMethod implementation to register with the storage
      */
     <T extends Throwable> void registerHandlerMethod(HandlerMethod<T> handlerMethod);
+
+    /**
+     * Obtains the applicable handlers for the given type or super type of the given type to order the handlers.
+     *
+     * @param exceptionClass    Type of exception to narrow handler list
+     * @param bm                active BeanManager
+     * @param handlerQualifiers additional handlerQualifiers to limit handlers
+     * @param isBefore          traversal limiter
+     * @return An order collection of handlers for the given type.
+     */
+    Collection<HandlerMethod<? extends Throwable>> getHandlersForException(Type exceptionClass, BeanManager bm,
+                                                                           Set<Annotation> handlerQualifiers,
+                                                                           boolean isBefore);
 }

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/Handles.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/Handles.java b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/Handles.java
index 6284873..8d86160 100644
--- a/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/Handles.java
+++ b/deltaspike/core/api/src/main/java/org/apache/deltaspike/core/api/exception/control/Handles.java
@@ -19,7 +19,11 @@
 
 package org.apache.deltaspike.core.api.exception.control;
 
-import java.lang.annotation.*;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
  * Marker annotation for a method to be considered an Exception Handler. Handlers are typically in the form of
@@ -34,5 +38,5 @@ public @interface Handles
     /**
      * Precedence relative to handlers for the same type
      */
-    public abstract int ordinal() default 0; //TODO discuss Precedence
+    int ordinal() default 0; //TODO discuss Precedence
 }

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/ExceptionHandlerComparator.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/ExceptionHandlerComparator.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/ExceptionHandlerComparator.java
new file mode 100644
index 0000000..c5523f7
--- /dev/null
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/ExceptionHandlerComparator.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.deltaspike.core.impl.exception.control;
+
+import org.apache.deltaspike.core.api.exception.control.HandlerMethod;
+import org.apache.deltaspike.core.util.HierarchyDiscovery;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Set;
+
+/**
+ * Comparator to sort exception handlers according qualifier ({@link org.apache.deltaspike.core.api.exception.control.BeforeHandles} first), ordinal
+ * (highest to lowest) and finally hierarchy (least to most specific).
+ */
+@SuppressWarnings({"MethodWithMoreThanThreeNegations"})
+public final class ExceptionHandlerComparator implements Comparator<HandlerMethod<?>>
+{
+
+    /**
+     * {@inheritDoc}
+     */
+    public int compare(HandlerMethod<?> lhs, HandlerMethod<?> rhs)
+    {
+        if (lhs.equals(rhs))
+        {
+            return 0;
+        }
+
+        // Really this is so all handlers are returned in the TreeSet (even if they're of the same type, but one is
+        // before, the other is not
+        if (lhs.getExceptionType().equals(rhs.getExceptionType()))
+        {
+            final int returnValue = this.comparePrecedence(lhs.getOrdinal(), rhs.getOrdinal(),
+                    lhs.isBefore());
+            // Compare number of qualifiers if they exist so handlers that handle the same type
+            // are both are returned and not thrown out (order doesn't really matter)
+            if (returnValue == 0 && !lhs.getQualifiers().isEmpty())
+            {
+                return -1;
+            }
+
+            // Either precedence is non-zero or lhs doesn't have qualifiers so return the precedence compare
+            // If it's 0 this is essentially the same handler for our purposes
+            return returnValue;
+        }
+        else
+        {
+            return compareHierarchies(lhs.getExceptionType(), rhs.getExceptionType());
+        }
+
+        // Currently we're only looking at one type of traversal mode, if this changes, we'll need
+        // to re-add lines to check for this.
+    }
+
+    private int compareHierarchies(Type lhsExceptionType, Type rhsExceptionType)
+    {
+        HierarchyDiscovery lhsHierarchy = new HierarchyDiscovery(lhsExceptionType);
+        Set<Type> lhsTypeclosure = lhsHierarchy.getTypeClosure();
+
+        if (lhsTypeclosure.contains(rhsExceptionType))
+        {
+            final int indexOfLhsType = new ArrayList<Type>(lhsTypeclosure).indexOf(lhsExceptionType);
+            final int indexOfRhsType = new ArrayList<Type>(lhsTypeclosure).indexOf(rhsExceptionType);
+
+            if (indexOfLhsType > indexOfRhsType)
+            {
+                return 1;
+            }
+        }
+        return -1;
+    }
+
+    private int comparePrecedence(final int lhs, final int rhs, final boolean isBefore)
+    {
+        if (isBefore)
+        {
+            return (lhs - rhs);
+        }
+        else
+        {
+            return (lhs - rhs) * -1;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/ExceptionHandlerDispatch.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/ExceptionHandlerDispatch.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/ExceptionHandlerDispatch.java
new file mode 100644
index 0000000..af14cd6
--- /dev/null
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/ExceptionHandlerDispatch.java
@@ -0,0 +1,223 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.deltaspike.core.impl.exception.control;
+
+import org.apache.deltaspike.core.api.exception.control.CaughtException;
+import org.apache.deltaspike.core.api.exception.control.ExceptionStack;
+import org.apache.deltaspike.core.api.exception.control.ExceptionToCatch;
+import org.apache.deltaspike.core.api.exception.control.HandlerMethod;
+import org.apache.deltaspike.core.api.exception.control.HandlerMethodStorage;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.spi.BeanManager;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+
+/**
+ * Observer of {@link ExceptionToCatch} events and handler dispatcher. All handlers are invoked from this class.  This
+ * class is immutable.
+ */
+public class ExceptionHandlerDispatch implements java.io.Serializable
+{
+    private static final long serialVersionUID = -144788905363939591L;
+
+    private ExceptionToCatch exceptionToCatch;
+    private ExceptionStack exceptionStack;
+
+    private final Logger log = Logger.getLogger(this.getClass().toString());
+
+    /**
+     * Observes the event, finds the correct exception handler(s) and invokes them.
+     *
+     * @param eventException exception to be invoked
+     * @param bm             active bean manager
+     * @param handlerMethodStorage      catch handlerMethodStorage instance to obtain handlers
+     * @throws Throwable If a handler requests the exception to be re-thrown.
+     */
+    @SuppressWarnings({"unchecked", "MethodWithMultipleLoops", "ThrowableResultOfMethodCallIgnored"})
+    public void executeHandlers(@Observes @Any ExceptionToCatch eventException, final BeanManager bm,
+                                HandlerMethodStorage handlerMethodStorage) throws Throwable
+    {
+        log.entering(ExceptionHandlerDispatch.class.getName(), "executeHandlers", eventException.getException());
+
+        CreationalContext<Object> ctx = null;
+        this.exceptionToCatch = eventException;
+
+        Throwable throwException = null;
+
+        try
+        {
+            ctx = bm.createCreationalContext(null);
+
+            final Set<HandlerMethod<?>> processedHandlers = new HashSet<HandlerMethod<?>>();
+
+            final ExceptionStack stack = new ExceptionStack(eventException.getException());
+
+            bm.fireEvent(stack); // Allow for modifying the exception stack
+
+            inbound_cause:
+            while (stack.getCurrent() != null)
+            {
+                this.exceptionStack = stack;
+
+                final List<HandlerMethod<?>> breadthFirstHandlerMethods = new ArrayList<HandlerMethod<?>>(
+                        handlerMethodStorage.getHandlersForException(stack.getCurrent().getClass(),
+                                bm, eventException.getQualifiers(), true));
+
+                for (HandlerMethod<?> handler : breadthFirstHandlerMethods)
+                {
+                    if (!processedHandlers.contains(handler))
+                    {
+                        log.fine(String.format("Notifying handler %s", handler));
+
+                        @SuppressWarnings("rawtypes")
+                        final CaughtException breadthFirstEvent = new CaughtException(stack, true,
+                                eventException.isHandled());
+                        handler.notify(breadthFirstEvent);
+
+                        log.fine(String.format("Handler %s returned status %s", handler,
+                                breadthFirstEvent.getFlow().name()));
+
+                        if (!breadthFirstEvent.isUnmute())
+                        {
+                            processedHandlers.add(handler);
+                        }
+
+                        switch (breadthFirstEvent.getFlow())
+                        {
+                            case HANDLED:
+                                eventException.setHandled(true);
+                                return;
+                            case HANDLED_AND_CONTINUE:
+                                eventException.setHandled(true);
+                                break;
+                            case ABORT:
+                                return;
+                            case SKIP_CAUSE:
+                                eventException.setHandled(true);
+                                stack.skipCause();
+                                continue inbound_cause;
+                            case THROW_ORIGINAL:
+                                throwException = eventException.getException();
+                                break;
+                            case THROW:
+                                throwException = breadthFirstEvent.getThrowNewException();
+                        }
+                    }
+                }
+
+                final Collection<HandlerMethod<? extends Throwable>> handlersForException =
+                        handlerMethodStorage.getHandlersForException(stack.getCurrent().getClass(),
+                        bm, eventException.getQualifiers(), false);
+
+                final List<HandlerMethod<? extends Throwable>> depthFirstHandlerMethods =
+                        new ArrayList<HandlerMethod<? extends Throwable>>(handlersForException);
+
+                // Reverse these so category handlers are last
+                Collections.reverse(depthFirstHandlerMethods);
+
+                for (HandlerMethod<?> handler : depthFirstHandlerMethods)
+                {
+                    if (!processedHandlers.contains(handler))
+                    {
+                        log.fine(String.format("Notifying handler %s", handler));
+
+                        @SuppressWarnings("rawtypes")
+                        final CaughtException depthFirstEvent = new CaughtException(stack, false,
+                                eventException.isHandled());
+                        handler.notify(depthFirstEvent);
+
+                        log.fine(String.format("Handler %s returned status %s", handler,
+                                depthFirstEvent.getFlow().name()));
+
+                        if (!depthFirstEvent.isUnmute())
+                        {
+                            processedHandlers.add(handler);
+                        }
+
+                        switch (depthFirstEvent.getFlow())
+                        {
+                            case HANDLED:
+                                eventException.setHandled(true);
+                                return;
+                            case HANDLED_AND_CONTINUE:
+                                eventException.setHandled(true);
+                                break;
+                            case ABORT:
+                                return;
+                            case SKIP_CAUSE:
+                                eventException.setHandled(true);
+                                stack.skipCause();
+                                continue inbound_cause;
+                            case THROW_ORIGINAL:
+                                throwException = eventException.getException();
+                                break;
+                            case THROW:
+                                throwException = depthFirstEvent.getThrowNewException();
+                        }
+                    }
+                }
+                this.exceptionStack.skipCause();
+            }
+
+            if (!eventException.isHandled() && throwException == null)
+            {
+                log.warning(String.format("No handlers found for exception %s", eventException.getException()));
+                throw eventException.getException();
+            }
+
+            if (throwException != null)
+            {
+                throw throwException;
+            }
+        } finally
+        {
+            if (ctx != null)
+            {
+                ctx.release();
+            }
+        }
+
+        log.exiting(ExceptionHandlerDispatch.class.getName(), "executeHandlers", exceptionToCatch.getException());
+    }
+
+    /* TODO: Later
+    @Produces
+    @ConversationScoped
+    @Named("handledException")
+    public ExceptionStack getExceptionStack() {
+        return this.exceptionStack == null ? new ExceptionStack() : this.exceptionStack;
+    }
+
+    @Produces
+    @ConversationScoped
+    @Named("caughtException")
+    public ExceptionToCatch getExceptionToCatch() {
+        return this.exceptionToCatch == null ? new ExceptionToCatch() : this.exceptionToCatch;
+    }
+    */
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/HandlerMethodImpl.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/HandlerMethodImpl.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/HandlerMethodImpl.java
new file mode 100644
index 0000000..4eef88c
--- /dev/null
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/HandlerMethodImpl.java
@@ -0,0 +1,303 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.deltaspike.core.impl.exception.control;
+
+import org.apache.deltaspike.core.api.exception.control.BeforeHandles;
+import org.apache.deltaspike.core.api.exception.control.CaughtException;
+import org.apache.deltaspike.core.api.exception.control.HandlerMethod;
+import org.apache.deltaspike.core.api.exception.control.Handles;
+import org.apache.deltaspike.core.api.literal.AnyLiteral;
+import org.apache.deltaspike.core.api.metadata.builder.ImmutableInjectionPoint;
+import org.apache.deltaspike.core.api.metadata.builder.InjectableMethod;
+import org.apache.deltaspike.core.util.BeanUtils;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedParameter;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.InjectionPoint;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.text.MessageFormat;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Implementation of {@link HandlerMethod}.
+ *
+ * @param <T> Type of the exception this handler handles.
+ */
+public class HandlerMethodImpl<T extends Throwable> implements HandlerMethod<T>
+{
+    private final Class<?> beanClass;
+    private Bean<?> bean;
+    private final Set<Annotation> qualifiers;
+    private final Type exceptionType;
+    private final AnnotatedMethod<?> handler;
+    private final boolean before;
+    private final int ordinal;
+    private final Method javaMethod;
+    private final AnnotatedParameter<?> handlerParameter;
+    private final Set<InjectionPoint> injectionPoints;
+    private BeanManager beanManager;
+
+    /**
+     * Determines if the given method is a handler by looking for the {@link Handles} annotation on a parameter.
+     *
+     * @param method method to search
+     * @return true if {@link Handles} is found, false otherwise
+     */
+    public static boolean isHandler(final AnnotatedMethod<?> method)
+    {
+        if (method == null)
+        {
+            throw new IllegalArgumentException("Method must not be null");
+        }
+
+        for (AnnotatedParameter<?> param : method.getParameters())
+        {
+            if (param.isAnnotationPresent(Handles.class) || param.isAnnotationPresent(BeforeHandles.class))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public static AnnotatedParameter<?> findHandlerParameter(final AnnotatedMethod<?> method)
+    {
+        if (!isHandler(method))
+        {
+            throw new IllegalArgumentException("Method is not a valid handler");
+        }
+
+        AnnotatedParameter<?> returnParam = null;
+
+        for (AnnotatedParameter<?> param : method.getParameters())
+        {
+            if (param.isAnnotationPresent(Handles.class) || param.isAnnotationPresent(BeforeHandles.class))
+            {
+                returnParam = param;
+                break;
+            }
+        }
+
+        return returnParam;
+    }
+
+    /**
+     * Sole Constructor.
+     *
+     * @param method found handler
+     * @param bm     active BeanManager
+     * @throws IllegalArgumentException if method is null, has no params or first param is not annotated with
+     *                                  {@link Handles} or {@link BeforeHandles}
+     */
+    public HandlerMethodImpl(final AnnotatedMethod<?> method, final BeanManager bm)
+    {
+        if (!HandlerMethodImpl.isHandler(method))
+        {
+            throw new IllegalArgumentException(MessageFormat.format("{0} is not a valid handler", method));
+        }
+
+        this.beanManager = bm;
+
+        final Set<Annotation> tmpQualifiers = new HashSet<Annotation>();
+
+        this.handler = method;
+        this.javaMethod = method.getJavaMember();
+
+        this.handlerParameter = findHandlerParameter(method);
+
+        if (!this.handlerParameter.isAnnotationPresent(Handles.class) && !this.handlerParameter.isAnnotationPresent(BeforeHandles.class))
+        {
+            throw new IllegalArgumentException("Method is not annotated with @Handles or @BeforeHandles");
+        }
+
+        this.before = this.handlerParameter.getAnnotation(BeforeHandles.class) != null;
+        this.ordinal = this.handlerParameter.getAnnotation(Handles.class).ordinal();
+        tmpQualifiers.addAll(BeanUtils.getQualifiers(bm, this.handlerParameter.getAnnotations()));
+
+        if (tmpQualifiers.isEmpty())
+        {
+            tmpQualifiers.add(new AnyLiteral());
+        }
+
+        this.qualifiers = tmpQualifiers;
+        this.beanClass = method.getJavaMember().getDeclaringClass();
+        this.exceptionType = ((ParameterizedType) this.handlerParameter.getBaseType()).getActualTypeArguments()[0];
+        this.injectionPoints = new HashSet<InjectionPoint>(method.getParameters().size() - 1);
+
+        for (AnnotatedParameter<?> param : method.getParameters())
+        {
+            if (!param.equals(this.handlerParameter))
+            {
+                this.injectionPoints.add(new ImmutableInjectionPoint(param, bm, this.getBean(bm), false, false));
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Class<?> getBeanClass()
+    {
+        return this.beanClass;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized Bean<?> getBean(BeanManager bm)
+    {
+        if (this.bean == null)
+        {
+            this.bean = bm.resolve(bm.getBeans(this.beanClass));
+        }
+        return this.bean;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Set<Annotation> getQualifiers()
+    {
+        return Collections.unmodifiableSet(this.qualifiers);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Type getExceptionType()
+    {
+        return this.exceptionType;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void notify(final CaughtException<T> event)
+    {
+        CreationalContext<?> ctx = null;
+        try
+        {
+            ctx = beanManager.createCreationalContext(null);
+            Object handlerInstance = beanManager.getReference(this.getBean(beanManager), this.beanClass, ctx);
+            InjectableMethod<?> im = createInjectableMethod(this.handler, this.getBean(beanManager), beanManager);
+            im.invoke(handlerInstance, ctx, new OutboundParameterValueRedefiner(event, beanManager, this));
+        } finally
+        {
+            if (ctx != null)
+            {
+                ctx.release();
+            }
+        }
+    }
+
+    private <X> InjectableMethod<X> createInjectableMethod(AnnotatedMethod<X> handlerMethod, Bean<?> bean, BeanManager manager)
+    {
+        return new InjectableMethod<X>(handlerMethod, bean, manager);
+    }
+
+    @Override
+    public boolean isBefore()
+    {
+        return this.before;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int getOrdinal()
+    {
+        return this.ordinal;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Method getJavaMethod()
+    {
+        return this.javaMethod;
+    }
+
+    public AnnotatedParameter<?> getHandlerParameter()
+    {
+        return this.handlerParameter;
+    }
+
+    public Set<InjectionPoint> getInjectionPoints()
+    {
+        return new HashSet<InjectionPoint>(this.injectionPoints);
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o)
+        {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass())
+        {
+            return false;
+        }
+
+        HandlerMethod<?> that = (HandlerMethod<?>) o;
+
+        if (!qualifiers.equals(that.getQualifiers()))
+        {
+            return false;
+        }
+        if (!exceptionType.equals(that.getExceptionType()))
+        {
+            return false;
+        }
+        return ordinal == that.getOrdinal();
+
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int result = beanClass.hashCode();
+        result = 5 * result + qualifiers.hashCode();
+        result = 5 * result + exceptionType.hashCode();
+        result = 5 * result + ordinal;
+        result = 5 * result + javaMethod.hashCode();
+        result = 5 * result + handlerParameter.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString()
+    {
+        return new StringBuilder("Qualifiers: ").append(this.qualifiers).append(" ")
+                .append("Handles Type: ").append(this.exceptionType).append(" ")
+                .append("Before: ").append(this.before).append(" ")
+                .append("Precedence: ").append(this.ordinal).append(" ")
+                .append(this.handler.toString()).toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/OutboundParameterValueRedefiner.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/OutboundParameterValueRedefiner.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/OutboundParameterValueRedefiner.java
new file mode 100644
index 0000000..26210a7
--- /dev/null
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/OutboundParameterValueRedefiner.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.deltaspike.core.impl.exception.control;
+
+import org.apache.deltaspike.core.api.exception.control.CaughtException;
+import org.apache.deltaspike.core.api.metadata.builder.ParameterValueRedefiner;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+
+/**
+ * Redefiner allowing to inject a non contextual instance of {@link CaughtException} into the first parameter. This
+ * class is immutable.
+ */
+public class OutboundParameterValueRedefiner implements ParameterValueRedefiner
+{
+    final private CaughtException<?> event;
+    final private BeanManager bm;
+    final private Bean<?> declaringBean;
+    final private HandlerMethodImpl<?> handlerMethod;
+
+    /**
+     * Sole constructor.
+     *
+     * @param event   instance of CaughtException to inject.
+     * @param manager active BeanManager
+     * @param handler Handler method this redefiner is for
+     */
+    public OutboundParameterValueRedefiner(final CaughtException<?> event, final BeanManager manager,
+                                           final HandlerMethodImpl<?> handler)
+    {
+        this.event = event;
+        this.bm = manager;
+        this.declaringBean = handler.getBean(manager);
+        this.handlerMethod = handler;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object redefineParameterValue(ParameterValue value)
+    {
+        CreationalContext<?> ctx = this.bm.createCreationalContext(this.declaringBean);
+
+        try
+        {
+            if (value.getPosition() == this.handlerMethod.getHandlerParameter().getPosition())
+            {
+                return event;
+            }
+            return value.getDefaultValue(ctx);
+        } finally
+        {
+            if (ctx != null)
+            {
+                ctx.release();
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-deltaspike/blob/46285dcb/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/extension/CatchExtension.java
----------------------------------------------------------------------
diff --git a/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/extension/CatchExtension.java b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/extension/CatchExtension.java
new file mode 100644
index 0000000..964af98
--- /dev/null
+++ b/deltaspike/core/impl/src/main/java/org/apache/deltaspike/core/impl/exception/control/extension/CatchExtension.java
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.deltaspike.core.impl.exception.control.extension;
+
+import org.apache.deltaspike.core.api.exception.control.ExceptionHandler;
+import org.apache.deltaspike.core.api.exception.control.HandlerMethod;
+import org.apache.deltaspike.core.api.exception.control.HandlerMethodStorage;
+import org.apache.deltaspike.core.api.literal.AnyLiteral;
+import org.apache.deltaspike.core.impl.exception.control.ExceptionHandlerComparator;
+import org.apache.deltaspike.core.impl.exception.control.HandlerMethodImpl;
+import org.apache.deltaspike.core.util.HierarchyDiscovery;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.InjectionException;
+import javax.enterprise.inject.spi.AfterDeploymentValidation;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedParameter;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.BeforeShutdown;
+import javax.enterprise.inject.spi.Decorator;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.Interceptor;
+import javax.enterprise.inject.spi.ProcessBean;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.logging.Logger;
+
+/**
+ * CDI extension to find handlers at startup.
+ */
+@SuppressWarnings({"unchecked", "CdiManagedBeanInconsistencyInspection"})
+public class CatchExtension implements Extension, HandlerMethodStorage
+{
+    private static Map<? super Type, Collection<HandlerMethod<? extends Throwable>>> allHandlers;
+
+    private final Logger log = Logger.getLogger(CatchExtension.class.toString());
+
+    public CatchExtension()
+    {
+        this.allHandlers = new HashMap<Type, Collection<HandlerMethod<? extends Throwable>>>();
+    }
+
+    /**
+     * Listener to ProcessBean event to locate handlers.
+     *
+     * @param pmb Event from CDI SPI
+     * @param bm  Activated Bean Manager
+     * @throws TypeNotPresentException if any of the actual type arguments refers to a non-existent type declaration when
+     *                                 trying to obtain the actual type arguments from a {@link ParameterizedType}
+     * @throws java.lang.reflect.MalformedParameterizedTypeException
+     *                                 if any of the actual type parameters refer to a parameterized type that cannot be
+     *                                 instantiated for any reason when trying to obtain the actual type arguments from a
+     *                                 {@link ParameterizedType}
+     */
+    public <T> void findHandlers(@Observes final ProcessBean<?> pmb, final BeanManager bm)
+    {
+        if (!(pmb.getAnnotated() instanceof AnnotatedType) || pmb.getBean() instanceof Interceptor ||
+                pmb.getBean() instanceof Decorator)
+        {
+            return;
+        }
+
+        final AnnotatedType<T> type = (AnnotatedType<T>) pmb.getAnnotated();
+
+        if (type.getJavaClass().isAnnotationPresent(ExceptionHandler.class))
+        {
+            final Set<AnnotatedMethod<? super T>> methods = type.getMethods();
+
+            for (AnnotatedMethod<? super T> method : methods)
+            {
+                if (HandlerMethodImpl.isHandler(method))
+                {
+                    final AnnotatedParameter<?> param = HandlerMethodImpl.findHandlerParameter(method);
+                    if (method.getJavaMember().getExceptionTypes().length != 0)
+                    {
+                        pmb.addDefinitionError(new IllegalArgumentException(
+                                String.format("Handler method %s must not throw exceptions", method.getJavaMember())));
+                    }
+                    final Class<? extends Throwable> exceptionType = (Class<? extends Throwable>) ((ParameterizedType) param.getBaseType()).getActualTypeArguments()[0];
+
+                    registerHandlerMethod(new HandlerMethodImpl(method, bm));
+                }
+            }
+        }
+    }
+
+    /**
+     * Verifies all injection points for every handler are valid.
+     *
+     * @param adv Lifecycle event
+     * @param bm  BeanManager instance
+     */
+    public void verifyInjectionPoints(@Observes final AfterDeploymentValidation adv, final BeanManager bm)
+    {
+        for (Map.Entry<? super Type, Collection<HandlerMethod<? extends Throwable>>> entry : this.allHandlers.entrySet())
+        {
+            for (HandlerMethod<? extends Throwable> handler : entry.getValue())
+            {
+                for (InjectionPoint ip : ((HandlerMethodImpl<? extends Throwable>) handler).getInjectionPoints())
+                {
+                    try
+                    {
+                        bm.validate(ip);
+                    } catch (InjectionException e)
+                    {
+                        adv.addDeploymentProblem(e);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Obtains the applicable handlers for the given type or super type of the given type.  Also makes use of {@link
+     * org.apache.deltaspike.core.impl.exception.control.ExceptionHandlerComparator} to order the handlers.
+     *
+     * @param exceptionClass    Type of exception to narrow handler list
+     * @param bm                active BeanManager
+     * @param handlerQualifiers additional handlerQualifiers to limit handlers
+     * @param isBefore          traversal limiter
+     * @return An order collection of handlers for the given type.
+     */
+    public Collection<HandlerMethod<? extends Throwable>> getHandlersForException(Type exceptionClass, BeanManager bm,
+                                                                                  Set<Annotation> handlerQualifiers,
+                                                                                  boolean isBefore)
+    {
+        final Collection<HandlerMethod<? extends Throwable>> returningHandlers =
+                new TreeSet<HandlerMethod<? extends Throwable>>(new ExceptionHandlerComparator());
+        final HierarchyDiscovery h = new HierarchyDiscovery(exceptionClass);
+        final Set<Type> closure = h.getTypeClosure();
+
+        for (Type hierarchyType : closure)
+        {
+            if (CatchExtension.allHandlers.get(hierarchyType) != null)
+            {
+                for (HandlerMethod<?> handler : CatchExtension.allHandlers.get(hierarchyType))
+                {
+                    if (handler.isBefore())
+                    {
+                        if (handler.getQualifiers().contains(new AnyLiteral()))
+                        {
+                            returningHandlers.add(handler);
+                        }
+                        else
+                        {
+                            if (!handlerQualifiers.isEmpty() && this.containsAny(handler.getQualifiers(),
+                                    handlerQualifiers))
+                            {
+                                returningHandlers.add(handler);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        log.fine(String.format("Found handlers %s for exception type %s, qualifiers %s", returningHandlers,
+                exceptionClass, handlerQualifiers));
+        return Collections.unmodifiableCollection(returningHandlers);
+    }
+
+    public void cleanup(@Observes BeforeShutdown beforeShutdown)
+    {
+        CatchExtension.allHandlers.clear();
+    }
+
+    private boolean containsAny(final Collection<? extends Annotation> haystack,
+                                final Collection<? extends Annotation> needles)
+    {
+        for (Annotation a : needles)
+        {
+            if (haystack.contains(a))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public <T extends Throwable> void registerHandlerMethod(HandlerMethod<T> handlerMethod)
+    {
+        log.fine(String.format("Adding handler %s to known handlers", handlerMethod));
+        if (CatchExtension.allHandlers.containsKey(handlerMethod.getExceptionType()))
+        {
+            CatchExtension.allHandlers.get(handlerMethod.getExceptionType()).add(handlerMethod);
+        }
+        else
+        {
+            CatchExtension.allHandlers.put(handlerMethod.getExceptionType(),
+                    new HashSet<HandlerMethod<? extends Throwable>>(Arrays.asList(handlerMethod)));
+        }
+    }
+}