Revision: 913
          http://stripes.svn.sourceforge.net/stripes/?rev=913&view=rev
Author:   tfenne
Date:     2008-05-20 05:12:06 -0700 (Tue, 20 May 2008)

Log Message:
-----------
Fix for STS-569: make DefaultEH more useful by pulling up some parts of 
DelegatingEH

Modified Paths:
--------------
    
trunk/stripes/src/net/sourceforge/stripes/exception/DefaultExceptionHandler.java
    
trunk/stripes/src/net/sourceforge/stripes/exception/DelegatingExceptionHandler.java

Modified: 
trunk/stripes/src/net/sourceforge/stripes/exception/DefaultExceptionHandler.java
===================================================================
--- 
trunk/stripes/src/net/sourceforge/stripes/exception/DefaultExceptionHandler.java
    2008-05-19 15:58:31 UTC (rev 912)
+++ 
trunk/stripes/src/net/sourceforge/stripes/exception/DefaultExceptionHandler.java
    2008-05-20 12:12:06 UTC (rev 913)
@@ -14,40 +14,199 @@
  */
 package net.sourceforge.stripes.exception;
 
+import net.sourceforge.stripes.action.Resolution;
 import net.sourceforge.stripes.config.Configuration;
 import net.sourceforge.stripes.util.Log;
 
+import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import javax.servlet.ServletException;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
- * Default ExceptionHandler implementation that simply rethrows any 
ServletExceptions and
- * wraps and rethrows other exceptions, letting the container deal with them.
+ * <p>Default ExceptionHandler implementation that makes it easy for users to 
extend and
+ * add custom handling for different types of exception. When extending this 
class methods
+ * can be added that meet the following requirements:</p>
  *
+ * <ul>
+ *   <li>Methods must be public</li>
+ *   <li>Methods must be non-abstract</li>
+ *   <li>Methods must have exactly three parameters</li>
+ *   <li>The first parameter type must be Throwable or a subclass thereof</li>
+ *   <li>The second and third arguments must be of type HttpServletRequest and
+ *       HttpServletResponse respectively</li>
+ *   <li>Methods may <i>optionally</i> return a Resolution in which case the 
resolution
+ *       will be executed</li>
+ * </ul>
+ *
+ * <p>When an exception is caught the exception handler attempts to find a 
method that
+ * can handle that type of exception. If none is found the exception's 
super-types are
+ * iterated through and methods looked for which match the super-types. If a 
matching
+ * method is found it will be invoked.  Otherwise the exception will simply be 
rethrown
+ * by the exception handler - though first it will be wrapped in a 
StripesServletException
+ * if necessary in order to make it acceptable to the container.</p>
+ *
+ * <p>The following are examples of method signatures that might be added by 
subclasses:</p>
+ *
+ * <pre>
+ * public Resolution handle(FileUploadLimitExceededException ex, 
HttpServletRequest req, HttpServletResponse resp) { ... }
+ * public void handle(MySecurityException ex, HttpServletRequest req, 
HttpServletResponse resp) { ... }
+ * public void catchAll(Throwable t, HttpServletRequest req, 
HttpServletResponse resp) { ... }
+ * </pre>
+ *
  * @author Tim Fennell
  * @since Stripes 1.3
  */
 public class DefaultExceptionHandler implements ExceptionHandler {
     private static final Log log = 
Log.getInstance(DefaultExceptionHandler.class);
+    private Configuration configuration;
 
-    /** Simply rethrows the exception passed in. */
+    /** A cache of exception types handled mapped to proxy objects that can do 
the handling. */
+    private Map<Class<? extends Throwable>, HandlerProxy> handlers =
+            new HashMap<Class<? extends Throwable>, HandlerProxy>();
+
+    /**
+     * Inner class that ties a class and method together an invokable object.
+     * @author Tim Fennell
+     * @since Stripes 1.3
+     */
+    protected static class HandlerProxy {
+        private Object handler;
+        private Method handlerMethod;
+
+        /** Constructs a new HandlerProxy that will tie together the instance 
and method used. */
+        public HandlerProxy(Object handler, Method handlerMethod) {
+            this.handler = handler;
+            this.handlerMethod = handlerMethod;
+        }
+
+        /** Invokes the handler and executes the resolution if one is 
returned. */
+        public void handle(Throwable t, HttpServletRequest req, 
HttpServletResponse res)  throws Exception {
+            Object resolution = handlerMethod.invoke(this.handler, t, req, 
res);
+            if (resolution != null && resolution instanceof Resolution) {
+                ((Resolution) resolution).execute(req, res);
+            }
+        }
+    }
+
+    /**
+     * Implementation of the ExceptionHandler interface that attempts to find 
a method
+     * that is capable of handing the exception. If it finds one then it is 
delegated to, and if
+     * it returns a resolution it will be executed. Otherwise rethrows any 
unhandled exceptions,
+     * wrapped in a StripesServletException if necessary.
+     *
+     * @param throwable the exception being handled
+     * @param request the current request being processed
+     * @param response the response paired with the current request
+     */
     public void handle(Throwable throwable,
                        HttpServletRequest request,
-                       HttpServletResponse response) throws ServletException {
+                       HttpServletResponse response) throws ServletException, 
IOException {
+        try {
+            Throwable actual = unwrap(throwable);
+            Class<?> type = actual.getClass();
+            HandlerProxy proxy = null;
 
-        log.warn(throwable, "Unhandled exception caught by the Stripes default 
exception handler.");
+            while (type != null && proxy == null) {
+                proxy = this.handlers.get(type);
+                type = type.getSuperclass();
+            }
 
-        if (throwable instanceof ServletException) {
-            throw (ServletException) throwable;
+            if (proxy != null) {
+                proxy.handle(actual, request, response);
+            }
+            else {
+                // If there's no sensible proxy, rethrow the original 
throwable,
+                // NOT the unwrapped one since they may add extra information
+                log.warn(throwable, "Unhandled exception caught by the Stripes 
default exception handler.");
+                throw throwable;
+            }
         }
-        else {
-            throw new StripesServletException
-                    ("Unhandled exception caught by the default exception 
handler.", throwable);
+        catch (ServletException se) { throw se; }
+        catch (IOException ioe) { throw ioe; }
+        catch (Throwable t) {
+            throw new StripesServletException("Unhandled exception in 
exception handler.", t);
         }
+    }
 
+    /** Stores the configuration and examines the handler for usable delegate 
methods. */
+    public void init(Configuration configuration) throws Exception {
+        this.configuration = configuration;
+        addHandler(this);
     }
 
-    /** Does nothing. */
-    public void init(Configuration configuration) throws Exception { }
+    /**
+     * Adds a class to the set of configured delegate handlers. Examines all 
the methods on the
+     * class looking for public non-abstract methods with a signature matching 
that described in
+     * the class level javadoc.  Each method is wrapped in a HandlerProxy and 
stored in a cache
+     * by the exception type it takes.
+     *
+     * @param handlerClass the class being configured
+     * @throws Exception if the handler class cannot be instantiated
+     */
+    protected void addHandler(Class<?> handlerClass) throws Exception {
+        addHandler(handlerClass.newInstance());
+    }
+
+    /**
+     * Adds an object instance to the set of configured handles. Examines
+     * all the methods on the class looking for public non-abstract methods 
with a signature
+     * matching that described in the class level javadoc.  Each method is 
wrapped in a
+     * HandlerProxy and stored in a cache by the exception type it takes.
+     *
+     * @param handler the handler instance being configured
+     */
+    @SuppressWarnings("unchecked")
+    protected void addHandler(Object handler) throws Exception {
+        Method[] methods = handler.getClass().getMethods();
+        for (Method method : methods) {
+            // Check the method Signature
+            Class[] parameters = method.getParameterTypes();
+            int mods = method.getModifiers();
+
+            // Check all the reasons not to add it!
+            if (!Modifier.isPublic(mods)) continue;
+            if (Modifier.isAbstract(mods)) continue;
+            if (parameters.length != 3) continue;
+            if (!Throwable.class.isAssignableFrom(parameters[0])) continue;
+            if (!HttpServletRequest.class.equals(parameters[1])) continue;
+            if (!HttpServletResponse.class.equals(parameters[2])) continue;
+            if (handler == this && method.getName().equals("handle") &&
+                    Throwable.class.equals(parameters[0])) continue;
+
+            // And if we made it this far, add it!
+            Class<? extends Throwable> type = parameters[0];
+            HandlerProxy proxy = new HandlerProxy(handler, method);
+            handlers.put(type, proxy);
+
+            log.debug("Added exception handler '", 
handler.getClass().getSimpleName(), ".",
+                      method.getName(), "()' for exception type: ", type);
+        }
+    }
+
+    /** Provides subclasses with access to the configuration. */
+    protected Configuration getConfiguration() { return configuration; }
+
+    /**
+     * Unwraps the throwable passed in.  If the throwable is a 
ServletException and has
+     * a root case, the root cause is returned, otherwise the throwable is 
returned as is.
+     *
+     * @param throwable a throwable
+     * @return another thowable, either the root cause of the one passed in
+     */
+    protected Throwable unwrap(Throwable throwable) {
+        if (throwable instanceof ServletException) {
+            Throwable t = ((ServletException) throwable).getRootCause();
+
+            if (t != null) {
+                throwable = t;
+            }
+        }
+
+        return throwable;
+    }
 }

Modified: 
trunk/stripes/src/net/sourceforge/stripes/exception/DelegatingExceptionHandler.java
===================================================================
--- 
trunk/stripes/src/net/sourceforge/stripes/exception/DelegatingExceptionHandler.java
 2008-05-19 15:58:31 UTC (rev 912)
+++ 
trunk/stripes/src/net/sourceforge/stripes/exception/DelegatingExceptionHandler.java
 2008-05-20 12:12:06 UTC (rev 913)
@@ -14,7 +14,6 @@
  */
 package net.sourceforge.stripes.exception;
 
-import net.sourceforge.stripes.action.Resolution;
 import net.sourceforge.stripes.config.BootstrapPropertyResolver;
 import net.sourceforge.stripes.config.Configuration;
 import net.sourceforge.stripes.controller.AnnotatedClassActionResolver;
@@ -22,25 +21,21 @@
 import net.sourceforge.stripes.util.ResolverUtil;
 import net.sourceforge.stripes.util.StringUtil;
 
-import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 /**
  * <p>An alternative implementation of [EMAIL PROTECTED] ExceptionHandler} 
that discovers and automatically
  * configures individual [EMAIL PROTECTED] AutoExceptionHandler} classes to 
handle specific types of
  * exceptions. This implementation is most useful when ActionBeans may produce 
many different
- * types of exceptions which require different handling, since independent 
AutoExceptionHandler
- * classes can be used to manage the different types of exceptions.</p>
+ * types of exceptions and it is desirable to separate exception handling 
logic for different
+ * groups or classes of exceptions. Using this approach multiple 
AutoExceptionHandlers can be
+ * configured simultaneously but do not have to be co-located.</p>
  *
  * <p>Searches for implementations of AutoExceptionHandler using the same 
mechanism as is used
  * to discover ActionBean implementations - a search of the classpath for 
classes that implement
@@ -71,7 +66,7 @@
  * @author Jeppe Cramon, Tim Fennell
  * @since Stripes 1.3
  */
-public class DelegatingExceptionHandler implements ExceptionHandler {
+public class DelegatingExceptionHandler extends DefaultExceptionHandler {
     /** Log instance for use within in this class. */
     private static final Log log = 
Log.getInstance(DelegatingExceptionHandler.class);
 
@@ -87,40 +82,7 @@
      */
     public static final String PACKAGES = 
"DelegatingExceptionHandler.Packages";
 
-    private Configuration configuration;
-
-    /** Provides subclasses with access to the configuration object. */
-    protected Configuration getConfiguration() { return this.configuration; }
-
     /**
-     * Inner class that ties a class and method together an invokable object.
-     * @author Tim Fennell
-     * @since Stripes 1.3
-     */
-    private static class HandlerProxy {
-        private AutoExceptionHandler handler;
-        private Method handlerMethod;
-
-        /** Constructs a new HandlerProxy that will tie together the instance 
and method used. */
-        public HandlerProxy(AutoExceptionHandler handler, Method 
handlerMethod) {
-            this.handler = handler;
-            this.handlerMethod = handlerMethod;
-        }
-
-        /** Invokes the handler and executes the resolution if one is 
returned. */
-        public void handle(Throwable t, HttpServletRequest req, 
HttpServletResponse res)  throws Exception {
-            Object resolution = handlerMethod.invoke(this.handler, t, req, 
res);
-            if (resolution != null && resolution instanceof Resolution) {
-                ((Resolution) resolution).execute(req, res);
-            }
-        }
-    }
-
-    /** A cache of exception types handled mapped to proxy objects that can do 
the handling. */
-    Map<Class<? extends Throwable>, HandlerProxy> handlers =
-            new HashMap<Class<? extends Throwable>, HandlerProxy>();
-
-    /**
      * Looks up the filters as defined in the Configuration and then invokes 
the
      * [EMAIL PROTECTED] ResolverUtil} to find implementations of 
AutoExceptionHandler. Each
      * implementation found is then examined and cached by calling
@@ -131,7 +93,7 @@
      *         instantiated
      */
     public void init(Configuration configuration) throws Exception {
-        this.configuration = configuration;
+        super.init(configuration);
 
         // Fetch the AutoExceptionHandler implementations and add them to the 
cache
         Set<Class<? extends AutoExceptionHandler>> handlers = findClasses();
@@ -144,98 +106,6 @@
     }
 
     /**
-     * Adds an AutoExceptionHandler class to the set of configured handles. 
Examines
-     * all the methods on the class looking for public non-abstract methods 
with a signature
-     * matching that described in the documentation for AutoExceptionHandler.  
Each method
-     * is wrapped in a HandlerProxy and stored in a cache by the exception 
type it takes.
-     *
-     * @param handlerClass the AutoExceptionHandler class being configured
-     * @throws Exception if the AutoExceptionHandler class cannot be 
instantiated
-     */
-    @SuppressWarnings("unchecked")
-       protected void addHandler(Class<? extends AutoExceptionHandler> 
handlerClass) throws Exception {
-        Method[] methods = handlerClass.getMethods();
-        for (Method method : methods) {
-            // Check the method Signature
-            Class[] parameters = method.getParameterTypes();
-            int mods = method.getModifiers();
-
-            if (Modifier.isPublic(mods) && !Modifier.isAbstract(mods) &&
-                 parameters.length == 3 && 
Throwable.class.isAssignableFrom(parameters[0]) &&
-                    HttpServletRequest.class.equals(parameters[1]) &&
-                        HttpServletResponse.class.equals(parameters[2])) {
-
-                Class<? extends Throwable> type = parameters[0];
-                AutoExceptionHandler handler = handlerClass.newInstance();
-                HandlerProxy proxy = new HandlerProxy(handler, method);
-                handlers.put(type, proxy);
-
-                log.debug("Added exception handler '", 
handlerClass.getSimpleName(), ".",
-                          method.getName(), "()' for exception type: ", type);
-            }
-        }
-    }
-
-    /**
-     * Implementation of the ExceptionHandler interface that attempts to find 
an
-     * [EMAIL PROTECTED] AutoExceptionHandler} that is capable of handing the 
exception. If it finds one
-     * then it is delegated to, and if it returns a resolution it will be 
executed. Otherwise
-     * behaves like the default implementation by rethrowing any unhandled 
exceptions, wrapped
-     * in a StripesServletException if necessary.
-     *
-     * @param throwable the exception being handled
-     * @param request the current request being processed
-     * @param response the response paired with the current request
-     */
-    public void handle(Throwable throwable,
-                       HttpServletRequest request,
-                       HttpServletResponse response) throws ServletException, 
IOException {
-        try {
-            Throwable actual = unwrap(throwable);
-            Class<?> type = actual.getClass();
-            HandlerProxy proxy = null;
-
-            while (type != null && proxy == null) {
-                proxy = this.handlers.get(type);
-                type = type.getSuperclass();
-            }
-
-            if (proxy != null) {
-                proxy.handle(actual, request, response);
-            }
-            else {
-                // If there's no sensible proxy, rethrow the original 
throwable,
-                // NOT the unwrapped one since they may add extra information
-                throw throwable;
-            }
-        }
-        catch (ServletException se) { throw se; }
-        catch (IOException ioe) { throw ioe; }
-        catch (Throwable t) {
-            throw new StripesServletException("Unhandled exception in 
exception handler.", t);
-        }
-    }
-
-    /**
-     * Unwraps the throwable passed in.  If the throwable is a 
ServletException and has
-     * a root case, the root cause is returned, otherwise the throwable is 
returned as is.
-     *
-     * @param throwable a throwable
-     * @return another thowable, either the root cause of the one passed in
-     */
-    protected Throwable unwrap(Throwable throwable) {
-        if (throwable instanceof ServletException) {
-            Throwable t = ((ServletException) throwable).getRootCause();
-
-            if (t != null) {
-                throwable = t;
-            }
-        }
-
-        return throwable;
-    }
-
-    /**
      * Helper method to find implementations of AutoExceptionHandler in the 
packages specified in
      * Configuration using the [EMAIL PROTECTED] ResolverUtil} class.
      *


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft 
Defy all challenges. Microsoft(R) Visual Studio 2008. 
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development

Reply via email to