Dashboard > Stripes > ... > How To's > Exception Handling
Stripes Log In   View a printable version of the current page.
Exception Handling
Added by Tim Fennell, last edited by Tim Fennell on Aug 27, 2006  (view change)

Stripes has moved! This site is no longer being actively maintained. Please point your browsers at http://www.stripesframework.org and update your bookmarks. Thank you.

Introduction to Exception Handling

Web Applications can generate exceptions and unfortunately the Servlet specifications built in exception handling mechanism is somewhat limited. Specifically it can only forward the user to an alternative JSP or file; it cannot forward to a servlet or cause non-JSP code to be executed. This is what the Stripes exception handling mechanism aims to solve.

Most of the major interfaces in Stripes allow developers to throw any exceptions they don't want to handle. Handler methods, validation methods, etc. call all throw Throwable! It's up to you to define your exception handling strategy: Stripes will not impose one on you. That said, it's the author's opinion that you should generally propogate (not catch, wrap and throw) and exception that you can't handle, and let the framework take care of it.

The starting point is the ExceptionHandler interface. Implementations of this interface are used to handle any exceptions that arise during a request. They may rethrow exceptions, or execute arbitrary code and return a Resolution to tell Stripes what to do next.

The ExceptionHandler is invoked from the Stripes Filter. This allows it to handle exceptions generated in ActionBeans, in JSPs and even in other Servlet Filters that are lower down the chain than the Stripes Filter.

Default Exception Handler

The DefaultExceptionHandler used by Stripes doesn't do much! If the exception being handled is a ServletException it is rethrown, otherwise it is wrapped in a StripesServletException and rethrown. That's it!

Delegating Exception Handler

The DelegatingExceptionHandler is a more substantial class. It works in a manner similar to the ActionResolvers that ship with Stripes, except that instead of binding ActionBeans to events it binds AutoExceptionHandlers to Exception types. This exception handler delegates the handling of exceptions to classes that implement the AutoExceptionHandler marker interface.

AutoExceptionHandlers can have one or more methods with the following signature:

public Resolution someMethod(Exception e, HttpServletRequest req, HttpServletResponse res);
public Resolution someMethod(NullPointerException npe, HttpServletRequest req, HttpServletResponse res);

 

The first argument can be any subclass of java.lang.Throwable, and the exact type is used to determine when the method should be invoked. The remaining arguments are just the current request and response. These are passed instead of any more "Stripey" alternatives because things like the ActionBeanContext may not always be available; this way the interface is consistent and reliable.

When it is initialized the DelegatingExceptionHandler scans the classpath to find all instances of AutoExceptionHandler. This can be quite time consuming, and just like the ActionResolvers, the DelegatingExceptionHandler accepts a pair of initialization parameters to restrict its scanning. For details see the Configuration Reference.

When an exception is handled the DelegatingExceptionHandler looks for the most specific AutoExceptionHandler method to handle the exception. If it cannot find one that handles the exact exception type thrown, it will look for a method that handles the parent type and so on up the hierarchy. If no handler can be found, then the exception is rethrown. For this reason it is recommended to always have a handler method that takes Exception.

Writing Your Own Exception Handler

Writing your own exception handler is quite straightforward. The class simply has to implement ExceptionHandler interface, which specifies two methods (including the inherited one). For example:

public class MyExceptionHandler implements ExceptionHandler {
    /** Doesn't have to do anything... */
    public void init(Configuration configuration) throws Exception { }

    /** Do something a bit more complicated that just going to a view. */
    public void handle(Throwable throwable,
                       HttpServletRequest request,
                       HttpServletResponse response) throws ServletException, IOException {

        TransactionUtil.rollback(); // rollback any tx in progress
        if (AppProperties.isDevMode()) {
           throw new StripesServletException(throwable);
        }
        else {
            request.setAttribute("exception", throwable);
            request.getRequestDispatcher("/error.jsp").forward(request, response);
        }
    }
}

Configuring an Alternative Exception Handler

Having created your own exception handler, you'll need to configure it. You can do this by adding an initialization parameter for the Stripes Filter, e.g.

<init-param>
    <param-name>ExceptionHandler.Class</param-name>
    <param-value>com.myco.exception.MyExceptionHandler</param-value>
</init-param>

Accessing the ActionBean, ActionBeanContext etc.

The interface of ExceptionHandler is quite basic:

public void handle(Throwable throwable,
                   HttpServletRequest request,
                   HttpServletResponse response) throws ServletException;

This is primarily because the exception handler can handle exceptions from anywhere in a Stripes application - even prior to things like the ActionBean and ActionBeanContext having been created! The interface of AutoExceptionHandler is similar. This may leave you wondering how to get access to the ActionBean etc. should one be present. For example you may know, based on the type of exception being handled, that it had to originate from an ActionBean. Or you might simply wish to handle things differently if an ActionBean is present.

Checking for and retrieving an ActionBean is relatively simple, and through it the ActionBeanContext, ValidaitonErrors etc. For example:

/**
 * If there's an ActionBean present, send the user back where they came from with
 * a stern warning, otherwise send them to the global error page.
 */
public void handle(Throwable throwable,
                   HttpServletRequest request,
                   HttpServletResponse response) throws ServletException {
    ActionBean bean = (ActionBean)
        request.getAttribute(StripesConstants.REQ_ATTR_ACTION_BEAN);

    if (bean != null) {
        bean.getContext().getValidationErrors().addGlobalError(
            new SimpleError("You made something blow up!  Bad user!"));
        bean.getContext.getSourcePageResolution().execute(request, response);
    }
    else {
        request.getDispatcher("/error.jsp").forward(request, response);
    }
}

Site powered by a free Open Source Project / Non-profit License (more) of Confluence - the Enterprise wiki.
Learn more or evaluate Confluence for your organisation.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.2.7 Build:#524 Jul 28, 2006) - Bug/feature request - Contact Administrators