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 2013/01/02 21:15:37 UTC

svn commit: r1427992 - /incubator/deltaspike/site/trunk/content/deltaspike/core.mdtext

Author: lightguardjp
Date: Wed Jan  2 20:15:37 2013
New Revision: 1427992

URL: http://svn.apache.org/viewvc?rev=1427992&view=rev
Log:
Adding Exception Handling text

Modified:
    incubator/deltaspike/site/trunk/content/deltaspike/core.mdtext

Modified: incubator/deltaspike/site/trunk/content/deltaspike/core.mdtext
URL: http://svn.apache.org/viewvc/incubator/deltaspike/site/trunk/content/deltaspike/core.mdtext?rev=1427992&r1=1427991&r2=1427992&view=diff
==============================================================================
--- incubator/deltaspike/site/trunk/content/deltaspike/core.mdtext (original)
+++ incubator/deltaspike/site/trunk/content/deltaspike/core.mdtext Wed Jan  2 20:15:37 2013
@@ -336,10 +336,334 @@ TODO
 
 ## Exception Control
 
-TODO (Overview)
+Exception handling in DeltaSpike is based around the CDI eventing model.  While
+the implementation of exception handlers may not be the same as a CDI event,
+and the programming model is not exactly the same as specifying a CDI event
+observer, the concepts are very similar. DeltaSpike makes use of events for
+many of its features. Eventing is actually the only way to start using
+DeltaSpike's exception handling.
+
+This event is fired either by the application or a DeltaSpike exception
+handling integration. DeltaSpike then hands the exception off to a chain of
+registered handlers, which deal with the exception appropriately. The use of
+CDI events to connect exceptions to handlers makes this strategy of exception
+handling non-invasive and minimally coupled to the exception handling
+infrastructure.
+
+The exception handling process remains mostly transparent to the developer. In
+most cases, you register an exception handler simply by annotating a handler
+method. Alternatively, you can handle an exception programmatically, just as
+you would observe an event in CDI.
+
+Exception Handling - Usage
+--------------------------
+
+### Eventing into the exception handling framework
+
+The entire exception handling process starts with an event. This helps keep
+your application minimally coupled to DeltaSpike, but also allows for further
+extension. Exception handling in DeltaSpike is all about letting you take care
+of exceptions the way that makes the most sense for your application Events
+provide this delicate balance. Firing the event is the main way of starting the
+exception handling proccess.
+
+Manually firing an event to use DeltaSpike's exception handling is primarily
+used in your own try/catch blocks. It's very painless and also easy. Let's
+examine a sample that might exist inside of a simple business logic lookup into
+an inventory database:
+
+    public class InventoryActions {
+        @PersistenceContext private EntityManager em;
+        @Inject private Event<ExceptionToCatchEvent> catchEvent;
+
+        public Integer queryForItem(Item item) {
+            try {
+              Query q = em.createQuery("SELECT i from Item i where i.id = :id");
+              q.setParameter("id", item.getId());
+              return q.getSingleResult();
+            } catch (PersistenceException e) {
+              catchEvent.fire(new ExceptionToCatchEvent(e));
+            }
+        }
+    }
+
+The `Event` of generic type `ExceptionToCatchEvent` is injected into your
+class for use later within a try/catch block.
+
+The event is fired with a new instance of `ExceptionToCatchEvent` constructed
+with the exception to be handled.
+
+Exception handlers
+------------------
+
+As an application developer (i.e., an end user of DeltaSpike's exception
+handling), you'll be focused on writing exception handlers. An exception
+handler is a method on a CDI bean that is invoked to handle a specific type of
+exception. Within that method, you can implement any logic necessary to handle
+or respond to the exception.
+
+**If there are no exception handlers for an exception, the exception is
+rethrown.**
+
+Given that exception handler beans are CDI beans, they can make use of
+dependency injection, be scoped, have interceptors or decorators and any other
+functionality available to CDI beans.
+
+Exception handler methods are designed to follow the syntax and semantics of
+CDI observers, with some special purpose exceptions explained in this guide.
+The advantage of this design is that exception handlers will be immediately
+familiar to you if you are studying or well-versed in CDI.
+
+In this and subsequent sections, you'll learn how to define an exception
+handler, explore how and when it gets invoked, modify an exception and a stack
+trace, and even extend exception handling further through events that are fired
+during the handling workflow. We'll begin by covering the two annotations that
+are used to declare an exception handler, `@ExceptionHandler` and
+`@Handles`, and `@BeforeHandles` to create a callback before the handler is
+called.
+
+### Exception handler annotations
+
+Exception handlers are contained within exception handler beans, which are CDI
+beans annotated with `@ExceptionHandler`. Exception handlers are methods
+which have a parameter which is an instance of `ExceptionEvent<T extends
+Throwable>` annotated with the `@Handles` annotation.
+
+#### `@ExceptionHandler`
+
+The `@ExceptionHandler` annotation is simply a marker annotation that
+instructs the DeltaSpike exception handling CDI extension to scan the bean for
+handler methods.
+
+Let's designate a CDI bean as an exception handler by annotating it with
+`@ExceptionHandler`.
+
+    @ExceptionHandler
+    public class MyHandlers {}
+
+That's all there is to it. Now we can begin defining exception handling methods on this bean.
+
+#### `@Handles` and `@BeforeHandles`
+
+`@Handles` is a method parameter annotation that designates a method as an
+exception handler. Exception handler methods are registered on beans annotated
+with `@ExceptionHandler`. DeltaSpike will discover all such methods at
+deployment time.
+
+Let's look at an example. The following method is invoked for every exception
+that DeltaSpike processes and prints the exception message to stdout.
+(`Throwable` is the base exception type in Java and thus represents all
+exceptions).
+
+    @ExceptionHandler
+    public class MyHandlers
+    {
+        void printExceptions(@Handles ExceptionEvent<Throwable> evt)
+        {
+            System.out.println("Something bad happened:" +
+            evt.getException().getMessage());
+            evt.handleAndContinue();
+        }
+    }
+
+The `@Handles` annotation on the first parameter designates this method as an
+exception handler (though it is not required to be the first parameter).  This
+parameter must be of type `ExceptionEvent<T extends Throwable>`, otherwise
+it's detected as a definition error. The type parameter designates which
+exception the method should handle. This method is notified of all exceptions
+(requested by the base exception type `Throwable`).
+
+The `ExceptionEvent` instance provides access to information about the
+exception and can be used to control exception handling flow. In this case,
+it's used to read the current exception being handled in the exception chain,
+as returned by `getException()`.
+
+This handler does not modify the invocation of subsequent handlers, as
+designated by invoking `handleAndContinue()` on `ExceptionEvent`. As this
+is the default behavior, this line could be omitted.
+
+The `@Handles` annotation must be placed on a parameter of the method, which
+must be of type `ExceptionEvent<T extends Throwable>`. Handler methods are
+similar to CDI observers and, as such, follow the same principles and
+guidelines as observers (such as invocation, injection of parameters,
+qualifiers, etc) with the following exceptions:
+
+-   a parameter of a handler method must be a `ExceptionEvent`
+-   handlers are ordered before they are invoked (invocation order of
+    observers is non-deterministic)
+-   any handler can prevent subsequent handlers from being invoked
+
+In addition to designating a method as exception handler, the `@Handles`
+annotation specifies an `ordinal` about when the method should be invoked
+relative to other handler methods of the same type. Handlers with higher
+ordinal are invoked before handlers with a lower ordinal that handle the same
+exception type. The default ordinal (if not specified) is 0.
+
+The `@BeforeHandles` designates a method as a callback to happen before
+handlers are called.
+
+Let's take a look at more sophisticated example that uses all the features of
+handlers to log all exceptions.
+
+    @ExceptionHandler
+    public class MyHandlers
+    {
+       void logExceptions(@BeforeHandles @WebRequest ExceptionEvent<Throwable> evt, Logger log)
+       {
+          log.warn("Something bad happened: " + evt.getException().getMessage());
+       }
+
+       void logExceptions(@Handles @WebRequest ExceptionEvent<Throwable> evt, Logger log)
+       {
+          // possibly send a HTTP Error code
+       }
+    }
+
+This handler has a default ordinal of 0 (the default value of the ordinal
+attribute on `@Handles`).
+
+This handler is qualified with `@WebRequest`. When DeltaSpike calculates the
+handler chain, it filters handlers based on the exception type and qualifiers.
+This handler will only be invoked for exceptions passed to DeltaSpike that
+carry the `@WebRequest` qualifier.  We'll assume this qualifier distinguishes
+a web page request from a REST request.
+
+Any additional parameters of a handler method are treated as injection points.
+These parameters are injected into the handler when it is invoked by
+DeltaSpike. In this case, we are injecting a `Logger` bean that must be
+defined within the application (or by an extension).
+
+A handler is guaranteed to only be invoked once per exception (automatically
+muted), unless it re-enables itself by invoking the `unmute()` method on the
+`ExceptionEvent` instance.
+
+Handlers must not throw checked exceptions, and should avoid throwing unchecked
+exceptions. Should a handler throw an unchecked exception it will propagate up
+the stack and all handling done via DeltaSpike will cease. Any exception that
+was being handled will be lost.
+
+Exception Chain Processing
+--------------------------
+
+When an exception is thrown, chances are it's nested (wrapped) inside other
+exceptions. (If you've ever examined a server log, you'll appreciate this
+fact). The collection of exceptions in its entirety is termed an exception
+chain.
+
+The outermost exception of an exception chain (e.g., EJBException,
+ServletException, etc) is probably of little use to exception handlers. That's
+why DeltaSpike doesn't simply pass the exception chain directly to the
+exception handlers. Instead, it intelligently unwraps the chain and treats the
+root exception cause as the primary exception.
+
+The first exception handlers to be invoked by DeltaSpike are those that match
+the type of root cause. Thus, instead of seeing a vague `EJBException`, your
+handlers will instead see an meaningful exception such as
+`ConstraintViolationException`.  *This feature, alone, makes DeltaSpike's
+exception handling a worthwhile tool.*
+
+DeltaSpike continues to work through the exception chain, notifying handlers of
+each exception in the stack, until a handler flags the exception as handled or
+the whole exception chain has been iterated. Once an exception is marked as
+handled, DeltaSpike stops processing the exception chain. If a handler
+instructs DeltaSpike to rethrow the exception (by invoking
+`ExceptionEvent#throwOriginal()`, DeltaSpike will rethrow the exception
+outside the DeltaSpike exception handling infrastructure. Otherwise, it simply
+returns flow control to the caller.
+
+Consider a exception chain containing the following nested causes (from outer
+cause to root cause):
+
+-   EJBException
+-   PersistenceException
+-   SQLGrammarException
+
+DeltaSpike will unwrap this exception and notify handlers in the following
+order:
+
+-   SQLGrammarException
+-   PersistenceException
+-   EJBException
+
+If there's a handler for `PersistenceException`, it will likely prevent the
+handlers for `EJBException` from being invoked, which is a good thing since
+what useful information can really be obtained from `EJBException`?
+
+Handler ordinal
+---------------
+
+When DeltaSpike finds more than one handler for the same exception type, it
+orders the handlers by ordinal.  Handlers with higher ordinal are executed
+before handlers with a lower ordinal. If DeltaSpike detects two handlers for
+the same type with the same ordinal, the order is non-deterministic.
+
+Let's define two handlers with different ordinals:
+
+    void handleIOExceptionFirst(@Handles(ordinal = 100) ExceptionEvent<IOException> evt)
+    {
+       System.out.println("Invoked first");
+    }
+
+    void handleIOExceptionSecond(@Handles ExceptionEvent<IOException> evt)
+    {
+     System.out.println(“Invoked second”);
+    }
+
+The first method is invoked first since it has a higher ordinal (100) than the
+second method, which has the default ordinal (0).
+
+To summarize, here's how DeltaSpike determines the order of handlers to invoke
+(until a handler marks exception as handled):
+
+1.  Unwrap exception stack
+2.  Begin processing root cause
+3.  Invoke any callback methods annotated with @BeforeHandles for the
+    closest type to the exception
+4.  Find handler for the closest type to the exception
+5.  If multiple handlers for same type, invoke handlers with higher
+    ordinal first
+6.  Continue above steps for each exception in stack
+
+APIs for exception information and flow control
+-----------------------------------------------
+
+There are two APIs provided by DeltaSpike that should be familiar to
+application developers:
+
+-   `ExceptionEvent`
+-   `ExceptionStackEvent`
+
+### ExceptionEvent
+
+In addition to providing information about the exception being handled, the
+`ExceptionEvent` object contains methods to control the exception handling
+process, such as rethrowing the exception, aborting the handler chain or
+unmuting the current handler.  Five methods exist on the `ExceptionEvent`
+object to give flow control to the handler
+
+-   `abort()` - terminate all handling immediately after this handler,
+    does not mark the exception as handled, does not re-throw the
+    exception.
+-   `throwOriginal()` - continues through all handlers, but once all
+    handlers have been called (assuming another handler does not call
+    abort() or handled()) the initial exception passed to DeltaSpike is
+    rethrown. Does not mark the exception as handled.
+-   `handled()` - marks the exception as handled and terminates
+    further handling.
+-   `handleAndContinue()` - default. Marks the exception as handled
+    and proceeds with the rest of the handlers.
+-   `skipCause()` - marks the exception as handled, but proceeds to
+    the next cause in the cause container, without calling other
+    handlers for the current cause.
+-   `rethrow(Throwable)` - Throw a new exception after this handler is
+    invoked
+
+Once a handler is invoked it is muted, meaning it will not be run again for
+that exception chain, unless it's explicitly marked as unmuted via the
+`unmute()` method on `ExceptionEvent`.
 
 ## Scopes
 
 # Core - Utils
 
-TODO
\ No newline at end of file
+TODO