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