SeamFramework.orgCommunity Documentation
An end user of the Seam Catch Framework is typically only concerned with Exception Handlers (methods in Handler
Beans, which are similar to CDI Observers). Handler Beans are CDI beans with the
@HandlesExceptions
annotation. There may be other resources made available by other modules
which can be injected into handler methods on an as needed basis. For further information, please check the API
docs, or examples.
The
@HandlesException
annotation is simply a marker annotation instructing the Seam
Catch CDI extension to scan the bean for handler methods.
Example
@HandlesExceptions
public class MyHandlers
{
public void catchAllHandler(@Handles(during = TraversalPath.DESCENDING) @MyFramework CaughtException<Throwable> event, Logger log)
{
log.warn("Exception occured: " + event.getException().getMessage());
}
}
This is a complete and valid handler showing all the current features of handlers. The Handler Bean is
defined by the class level annotation
@HandlesExceptions
and the actual handler is
defined by the method that takes a
CaughtException
of type
Throwable
which
is annotated using the
@Handles
annotation. Also notice the handler is qualified using
the
@MyFramework
qualifier. This works the same as qualifers in CDI Observers,
it will only be invoked for exceptions (it catches typeThrowable
) where the
initial
ExceptionToCatchEvent
was created with the
@MyFramework
annotation passed to the constructor. The Logger instance is also injected into the handler when it is
invoked. The handler has a default precedence of 0 and a
TraversalPath
of
DESCENDING
. It does not modify flow control of other handlers however and simply uses
the default proceed.
@Handles
is a parameter annotation that specifies a method as an exception handler. It
acts similar to the
@Observes
annotation from CDI. In addition to promoting a normal
method to an exception handler it also carries data about the handler:
TraversalPath.ASCENDING
being default)
The
@Handles
annotation must be placed on the first parameter of the method, which must
be of type CaughtException. Handler methods are similar to CDI Obeservers and follow the same principals and
guidelines (such as invocation, injection of parameters, qualifiers, etc). They differ from Observer
methods in that:
A handler is guaranteed to only be invoked once per exception (unless it is unmuted via the CaughtException
object by callingunMute()
). Handlers must not throw checked exceptions, and should
avoid throwing unchecked exceptions.
Adding a handler is simply creating a class and a method the follows the above rules (class annotated with
@HandlesExceptions
and a method with the first parameter being a CaughtException and annotated
with@Handles
). Catch will discover all handler methods at deploy time. See the example
above for a simple, but complete handler.
The ordering of handlers is multifaceted. Based on the traversal path of the causing container handlers are
ordered according to the hiearchy of the excption type (most specific first if
TraversalPath.ASCENDING
, least specific first if
TraversalPath.DESCENDING
traversal), and the precedence when two handlers are for the
same exception type.
The
precedence
of a handler helps determine the order of the handler relative to other
handlers of the same exception type. It follows a high-to-low integer schema (the higher the precedence, the
sooner the handler is invoked during traversal of the causing chain).
When an exception is handled with Catch the causing container is unwrapped to get at each exception. The
first pass (TraversalPath.DESCENDING
) starts with the outer most exception working it's
way to the root exception. The traversal is then reversed and traversed from root cause up. This allows
handlers to take part in various stages of the causing container. At each entry in the container, handlers
are invoked based on the exception type (either an exact match or a super type) of the entry. For example
if the exception type isSocketException
, handlers for types
SocketException
,
IOException,
Exception
and
Throwable
would all invoked (in that order), however, a handler for
BindException
would not be invoked.
There are other objects used in Catch that should be familiar to handler writers namely
CaughtException
CauseContainer
CaughtException
contains methods to interact with the handling procces, allowing a level of flow
control to be available to handler (such as re-throwing the exception, or aborting), and allowing a handler
to
be unmuted. Once a handler is invoked it is muted, meaning it will not be run again for that causing
container,
unless it is explicitly marked as unmuted via the
CaughtException.unMute()
object.
Five methods exist on the
CaughtException
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.
rethrow()
- 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 Catch is
rethrown. Does not mark the exception as handled.
handled()
- marks the exception as handled and terminates further handling.
proceed()
- default. Marks the exception as handled and proceeds with the rest of the
handlers.
proceedToCause()
- marks the exception as handled, but proceeds to the next cause in
the cause container, without calling other handlers for the current cause.