KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > web > servlet > mvc > multiaction > MultiActionController


1 /*
2  * Copyright 2002-2006 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.web.servlet.mvc.multiaction;
18
19 import java.lang.reflect.InvocationTargetException JavaDoc;
20 import java.lang.reflect.Method JavaDoc;
21 import java.util.ArrayList JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.Map JavaDoc;
25
26 import javax.servlet.ServletRequest JavaDoc;
27 import javax.servlet.http.HttpServletRequest JavaDoc;
28 import javax.servlet.http.HttpServletResponse JavaDoc;
29 import javax.servlet.http.HttpSession JavaDoc;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33
34 import org.springframework.beans.BeanUtils;
35 import org.springframework.util.Assert;
36 import org.springframework.validation.ValidationUtils;
37 import org.springframework.validation.Validator;
38 import org.springframework.web.HttpSessionRequiredException;
39 import org.springframework.web.bind.ServletRequestDataBinder;
40 import org.springframework.web.servlet.ModelAndView;
41 import org.springframework.web.servlet.mvc.AbstractController;
42 import org.springframework.web.servlet.mvc.LastModified;
43 import org.springframework.web.util.NestedServletException;
44
45 /**
46  * Controller implementation that allows multiple request types to be
47  * handled by the same class. Subclasses of this class can handle several
48  * different types of request with methods of the form
49  *
50  * <pre>
51  * (ModelAndView | Map | void) actionName(HttpServletRequest request, HttpServletResponse response);</pre>
52  *
53  * May take a third parameter HttpSession in which an existing session will be required,
54  * or a third parameter of an arbitrary class that gets treated as command
55  * (i.e. an instance of the class gets created, and request parameters get bound to it)
56  *
57  * <p>These methods can throw any kind of exception, but should only let propagate
58  * those that they consider fatal, or which their class or superclass is prepared to
59  * catch by implementing an exception handler.
60  *
61  * <p>When returning just a {@link Map} instance view name translation will be used to generate
62  * the view name. The configured {@link org.springframework.web.servlet.RequestToViewNameTranslator}
63  * will be used to determine the view name.
64  *
65  * <p>When returning <code>void</code> a return value of <code>null</code> is assumed
66  * meaning that the handler method is responsible for writing the response directly to
67  * the supplied {@link HttpServletResponse}.
68  *
69  * <p>This model allows for rapid coding, but loses the advantage of compile-time
70  * checking. It is similar to a Struts 1.1 DispatchAction, but more sophisticated.
71  * Also supports delegation to another object.
72  *
73  * <p>An implementation of the MethodNameResolver interface defined in this package
74  * should return a method name for a given request, based on any aspect of the request,
75  * such as its URL or an "action" parameter. The actual strategy can be configured
76  * via the "methodNameResolver" bean property, for each MultiActionController.
77  *
78  * <p>The default MethodNameResolver is InternalPathMethodNameResolver; further included
79  * strategies are PropertiesMethodNameResolver and ParameterMethodNameResolver.
80  *
81  * <p>Subclasses can implement custom exception handler methods with names such as:
82  *
83  * <pre>
84  * ModelAndView anyMeaningfulName(HttpServletRequest request, HttpServletResponse response, ExceptionClass exception);</pre>
85  *
86  * The third parameter can be any subclass or Exception or RuntimeException.
87  *
88  * <p>There can also be an optional lastModified method for handlers, of signature:
89  *
90  * <pre>
91  * long anyMeaningfulNameLastModified(HttpServletRequest request)</pre>
92  *
93  * If such a method is present, it will be invoked. Default return from getLastModified
94  * is -1, meaning that the content must always be regenerated.
95  *
96  * <p>Note that method overloading isn't allowed.
97  *
98  * <p>See also the description of the workflow performed by
99  * {@link AbstractController the superclass} (in that section of the class
100  * level Javadoc entitled 'workflow').
101  *
102  * <p><b>Note:</b> For maximum data binding flexibility, consider direct usage
103  * of a ServletRequestDataBinder in your controller method, instead of relying
104  * on a declared command argument. This allows for full control over the entire
105  * binder setup and usage, including the invocation of Validators and the
106  * subsequent evaluation of binding/validation errors.
107  *
108  * @author Rod Johnson
109  * @author Juergen Hoeller
110  * @author Colin Sampaleanu
111  * @author Rob Harrop
112  * @see MethodNameResolver
113  * @see InternalPathMethodNameResolver
114  * @see PropertiesMethodNameResolver
115  * @see ParameterMethodNameResolver
116  * @see org.springframework.web.servlet.mvc.LastModified#getLastModified
117  * @see org.springframework.web.bind.ServletRequestDataBinder
118  */

119 public class MultiActionController extends AbstractController implements LastModified {
120         
121     /** Suffix for last-modified methods */
122     public static final String JavaDoc LAST_MODIFIED_METHOD_SUFFIX = "LastModified";
123
124     /** Default command name used for binding command objects: "command" */
125     public static final String JavaDoc DEFAULT_COMMAND_NAME = "command";
126
127     /** Log category to use when no mapped handler is found for a request */
128     public static final String JavaDoc PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";
129
130     /** Additional logger to use when no mapped handler is found for a request */
131     protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY);
132
133
134     /**
135      * Helper object that knows how to return method names from incoming requests.
136      * Can be overridden via the methodNameResolver bean property
137      */

138     private MethodNameResolver methodNameResolver = new InternalPathMethodNameResolver();
139
140     /** List of Validators to apply to commands */
141     private Validator[] validators;
142
143     /** Object we'll invoke methods on. Defaults to this. */
144     private Object JavaDoc delegate;
145
146     /** Methods, keyed by name */
147     private Map JavaDoc handlerMethodMap = new HashMap JavaDoc();
148     
149     /** LastModified methods, keyed by handler method name (without LAST_MODIFIED_SUFFIX) */
150     private Map JavaDoc lastModifiedMethodMap = new HashMap JavaDoc();
151     
152     /** Methods, keyed by exception class */
153     private Map JavaDoc exceptionHandlerMap = new HashMap JavaDoc();
154
155
156     /**
157      * Constructor for MultiActionController that looks for handler methods
158      * in the present subclass. Caches methods for quick invocation later.
159      * This class's use of reflection will impose little overhead at runtime.
160      */

161     public MultiActionController() {
162         this.delegate = this;
163         registerHandlerMethods(this.delegate);
164         // We'll accept no handler methods found here - a delegate might be set later on.
165
}
166     
167     /**
168      * Constructor for MultiActionController that looks for handler methods in delegate,
169      * rather than a subclass of this class. Caches methods for quick invocation later.
170      * @param delegate handler object. This doesn't need to implement any particular
171      * interface, as everything is done using reflection.
172      */

173     public MultiActionController(Object JavaDoc delegate) {
174         setDelegate(delegate);
175     }
176     
177     
178     /**
179      * Set the method name resolver that this class should use.
180      * Allows parameterization of handler method mappings.
181      */

182     public final void setMethodNameResolver(MethodNameResolver methodNameResolver) {
183         this.methodNameResolver = methodNameResolver;
184     }
185     
186     /**
187      * Return the MethodNameResolver used by this class.
188      */

189     public final MethodNameResolver getMethodNameResolver() {
190         return this.methodNameResolver;
191     }
192     
193     /**
194      * Set the Validators for this controller.
195      * The Validator must support the specified command class.
196      */

197     public final void setValidators(Validator[] validators) {
198         this.validators = validators;
199     }
200
201     /**
202      * Return the Validators for this controller.
203      */

204     public final Validator[] getValidators() {
205         return validators;
206     }
207
208     /**
209      * Set the delegate used by this class. The default is <code>this</code>,
210      * assuming that handler methods have been added by a subclass.
211      * <p>This method does not get invoked once the class is configured.
212      * @param delegate an object containing handler methods
213      */

214     public final void setDelegate(Object JavaDoc delegate) {
215         Assert.notNull(delegate, "Delegate must not be null");
216         this.delegate = delegate;
217         registerHandlerMethods(this.delegate);
218         // There must be SOME handler methods.
219
if (this.handlerMethodMap.isEmpty()) {
220             throw new IllegalStateException JavaDoc("No handler methods in class [" + this.delegate.getClass() + "]");
221         }
222     }
223
224
225     /**
226      * Registers all handlers methods on the delegate object.
227      */

228     private void registerHandlerMethods(Object JavaDoc delegate) {
229         this.handlerMethodMap.clear();
230         this.lastModifiedMethodMap.clear();
231         this.exceptionHandlerMap.clear();
232
233         // Look at all methods in the subclass, trying to find
234
// methods that are validators according to our criteria
235
Method JavaDoc[] methods = delegate.getClass().getMethods();
236         for (int i = 0; i < methods.length; i++) {
237             // We're looking for methods with given parameters.
238
Method JavaDoc method = methods[i];
239             if (isHandlerMethod(method)) {
240                 registerHandlerMethod(method);
241                 registerLastModifiedMethodIfExists(delegate, method);
242             }
243         }
244
245         // Now look for exception handlers.
246
for (int i = 0; i < methods.length; i++) {
247             Method JavaDoc method = methods[i];
248             if (isExceptionHandlerMethod(method)) {
249                 // Have an exception handler
250
registerExceptionHandlerMethod(method);
251             }
252         }
253     }
254
255     /**
256      * Is the supplied method a valid handler method?
257      * <p>Does not consider <code>Controller.handleRequest</code> itself
258      * as handler method (to avoid potential stack overflow).
259      */

260     private boolean isHandlerMethod(Method JavaDoc method) {
261         Class JavaDoc returnType = method.getReturnType();
262         if (ModelAndView.class.equals(returnType) || Map JavaDoc.class.equals(returnType) || void.class.equals(returnType)) {
263             Class JavaDoc[] parameterTypes = method.getParameterTypes();
264             return (parameterTypes.length >= 2 &&
265                     HttpServletRequest JavaDoc.class.equals(parameterTypes[0]) &&
266                     HttpServletResponse JavaDoc.class.equals(parameterTypes[1]) &&
267                     !("handleRequest".equals(method.getName()) && parameterTypes.length == 2));
268         }
269         return false;
270     }
271
272     /**
273      * Is the supplied method a valid exception handler method?
274      */

275     private boolean isExceptionHandlerMethod(Method JavaDoc method) {
276         return (isHandlerMethod(method) &&
277                 method.getParameterTypes().length == 3 &&
278                 Throwable JavaDoc.class.isAssignableFrom(method.getParameterTypes()[2]));
279     }
280
281     /**
282      * Registers the supplied method as a request handler.
283      */

284     private void registerHandlerMethod(Method JavaDoc method) {
285         if (logger.isDebugEnabled()) {
286             logger.debug("Found action method [" + method + "]");
287         }
288         this.handlerMethodMap.put(method.getName(), method);
289     }
290
291     /**
292      * Registers a LastModified handler method for the supplied handler method
293      * if one exists.
294      */

295     private void registerLastModifiedMethodIfExists(Object JavaDoc delegate, Method JavaDoc method) {
296         // Look for corresponding LastModified method.
297
try {
298             Method JavaDoc lastModifiedMethod = delegate.getClass().getMethod(
299                     method.getName() + LAST_MODIFIED_METHOD_SUFFIX,
300                     new Class JavaDoc[] {HttpServletRequest JavaDoc.class});
301             // Put in cache, keyed by handler method name.
302
this.lastModifiedMethodMap.put(method.getName(), lastModifiedMethod);
303             if (logger.isDebugEnabled()) {
304                 logger.debug("Found last modified method for action method [" + method + "]");
305             }
306         }
307         catch (NoSuchMethodException JavaDoc ex) {
308             // No last modified method. That's ok.
309
}
310     }
311
312     /**
313      * Registers the supplied method as an exception handler.
314      */

315     private void registerExceptionHandlerMethod(Method JavaDoc method) {
316         this.exceptionHandlerMap.put(method.getParameterTypes()[2], method);
317         if (logger.isDebugEnabled()) {
318             logger.debug("Found exception handler method [" + method + "]");
319         }
320     }
321
322
323     //---------------------------------------------------------------------
324
// Implementation of LastModified
325
//---------------------------------------------------------------------
326

327     /**
328      * Try to find an XXXXLastModified method, where XXXX is the name of a handler.
329      * Return -1, indicating that content must be updated, if there's no such handler.
330      * @see org.springframework.web.servlet.mvc.LastModified#getLastModified(HttpServletRequest)
331      */

332     public long getLastModified(HttpServletRequest JavaDoc request) {
333         try {
334             String JavaDoc handlerMethodName = this.methodNameResolver.getHandlerMethodName(request);
335             Method JavaDoc lastModifiedMethod = (Method JavaDoc) this.lastModifiedMethodMap.get(handlerMethodName);
336             if (lastModifiedMethod != null) {
337                 try {
338                     // invoke the last-modified method
339
Long JavaDoc wrappedLong = (Long JavaDoc) lastModifiedMethod.invoke(this.delegate, new Object JavaDoc[] { request });
340                     return wrappedLong.longValue();
341                 }
342                 catch (Exception JavaDoc ex) {
343                     // We encountered an error invoking the last-modified method.
344
// We can't do anything useful except log this, as we can't throw an exception.
345
logger.error("Failed to invoke last-modified method", ex);
346                 }
347             } // if we had a lastModified method for this request
348
}
349         catch (NoSuchRequestHandlingMethodException ex) {
350             // No handler method for this request. This shouldn't happen, as this
351
// method shouldn't be called unless a previous invocation of this class
352
// has generated content. Do nothing, that's OK: We'll return default.
353
}
354         return -1L;
355     }
356
357
358     //---------------------------------------------------------------------
359
// Implementation of AbstractController
360
//---------------------------------------------------------------------
361

362     /**
363      * Determine a handler method and invoke it.
364      * @see MethodNameResolver#getHandlerMethodName
365      * @see #invokeNamedMethod
366      * @see #handleNoSuchRequestHandlingMethod
367      */

368     protected ModelAndView handleRequestInternal(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
369         throws Exception JavaDoc {
370         try {
371             String JavaDoc methodName = this.methodNameResolver.getHandlerMethodName(request);
372             return invokeNamedMethod(methodName, request, response);
373         }
374         catch (NoSuchRequestHandlingMethodException ex) {
375             return handleNoSuchRequestHandlingMethod(ex, request, response);
376         }
377     }
378
379     /**
380      * Handle the case where no request handler method was found.
381      * <p>The default implementation logs a warning and sends an HTTP 404 error.
382      * Alternatively, a fallback view could be chosen, or the
383      * NoSuchRequestHandlingMethodException could be rethrown as-is.
384      * @param ex the NoSuchRequestHandlingMethodException to be handled
385      * @param request current HTTP request
386      * @param response current HTTP response
387      * @return a ModelAndView to render, or <code>null</code> if handled directly
388      * @throws Exception an Exception that should be thrown as result of the servlet request
389      */

390     protected ModelAndView handleNoSuchRequestHandlingMethod(
391             NoSuchRequestHandlingMethodException ex, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
392             throws Exception JavaDoc {
393
394         pageNotFoundLogger.warn(ex.getMessage());
395         response.sendError(HttpServletResponse.SC_NOT_FOUND);
396         return null;
397     }
398
399     /**
400      * Invokes the named method.
401      * <p>Uses a custom exception handler if possible; otherwise, throw an
402      * unchecked exception; wrap a checked exception or Throwable.
403      */

404     protected final ModelAndView invokeNamedMethod(
405             String JavaDoc methodName, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) throws Exception JavaDoc {
406         
407         Method JavaDoc method = (Method JavaDoc) this.handlerMethodMap.get(methodName);
408         if (method == null) {
409             throw new NoSuchRequestHandlingMethodException(methodName, getClass());
410         }
411
412         try {
413             List JavaDoc params = new ArrayList JavaDoc(4);
414             params.add(request);
415             params.add(response);
416                 
417             if (method.getParameterTypes().length >= 3 && method.getParameterTypes()[2].equals(HttpSession JavaDoc.class) ){
418                 HttpSession JavaDoc session = request.getSession(false);
419                 if (session == null) {
420                     throw new HttpSessionRequiredException(
421                             "Pre-existing session required for handler method '" + methodName + "'");
422                 }
423                 params.add(session);
424             }
425             
426             // If last parameter isn't of HttpSession type, it's a command.
427
if (method.getParameterTypes().length >= 3 &&
428                     !method.getParameterTypes()[method.getParameterTypes().length - 1].equals(HttpSession JavaDoc.class)) {
429                 Object JavaDoc command = newCommandObject(method.getParameterTypes()[method.getParameterTypes().length - 1]);
430                 params.add(command);
431                 bind(request, command);
432             }
433             
434             Object JavaDoc returnValue = method.invoke(this.delegate, params.toArray(new Object JavaDoc[params.size()]));
435             return massageReturnValueIfNecessary(returnValue);
436         }
437         catch (InvocationTargetException JavaDoc ex) {
438             // The handler method threw an exception.
439
return handleException(request, response, ex.getTargetException());
440         }
441         catch (Exception JavaDoc ex) {
442             // The binding process threw an exception.
443
return handleException(request, response, ex);
444         }
445     }
446
447     /**
448      * Processes the return value of a handler method to ensure that it either returns
449      * <code>null</code> or an instance of {@link ModelAndView}. When returning a {@link Map},
450      * the {@link Map} instance is wrapped in a new {@link ModelAndView} instance.
451      */

452     private ModelAndView massageReturnValueIfNecessary(Object JavaDoc returnValue) {
453         if (returnValue instanceof ModelAndView) {
454             return (ModelAndView) returnValue;
455         }
456         else if (returnValue instanceof Map JavaDoc) {
457             return new ModelAndView().addAllObjects((Map JavaDoc) returnValue);
458         }
459         else {
460             // Either returned null or was 'void' return.
461
// We'll assume that the handle method already wrote the response.
462
return null;
463         }
464     }
465
466
467     /**
468      * Create a new command object of the given class.
469      * <p>This implementation uses <code>BeanUtils.instantiateClass</code>,
470      * so commands need to have public no-arg constructors.
471      * Subclasses can override this implementation if desired.
472      * @throws Exception if the command object could not be instantiated
473      * @see org.springframework.beans.BeanUtils#instantiateClass(Class)
474      */

475     protected Object JavaDoc newCommandObject(Class JavaDoc clazz) throws Exception JavaDoc {
476         if (logger.isDebugEnabled()) {
477             logger.debug("Must create new command of class [" + clazz.getName() + "]");
478         }
479         return BeanUtils.instantiateClass(clazz);
480     }
481
482     /**
483      * Bind request parameters onto the given command bean
484      * @param request request from which parameters will be bound
485      * @param command command object, that must be a JavaBean
486      * @throws Exception in case of invalid state or arguments
487      */

488     protected void bind(HttpServletRequest JavaDoc request, Object JavaDoc command) throws Exception JavaDoc {
489         logger.debug("Binding request parameters onto MultiActionController command");
490         ServletRequestDataBinder binder = createBinder(request, command);
491         binder.bind(request);
492         if (this.validators != null) {
493             for (int i = 0; i < this.validators.length; i++) {
494                 if (this.validators[i].supports(command.getClass())) {
495                     ValidationUtils.invokeValidator(this.validators[i], command, binder.getBindingResult());
496                 }
497             }
498         }
499         binder.closeNoCatch();
500     }
501     
502     /**
503      * Create a new binder instance for the given command and request.
504      * <p>Called by <code>bind</code>. Can be overridden to plug in custom
505      * ServletRequestDataBinder subclasses.
506      * <p>Default implementation creates a standard ServletRequestDataBinder,
507      * and invokes <code>initBinder</code>. Note that <code>initBinder</code>
508      * will not be invoked if you override this method!
509      * @param request current HTTP request
510      * @param command the command to bind onto
511      * @return the new binder instance
512      * @throws Exception in case of invalid state or arguments
513      * @see #bind
514      * @see #initBinder
515      */

516     protected ServletRequestDataBinder createBinder(HttpServletRequest JavaDoc request, Object JavaDoc command)
517         throws Exception JavaDoc {
518
519         ServletRequestDataBinder binder = new ServletRequestDataBinder(command, getCommandName(command));
520         initBinder(request, binder);
521         return binder;
522     }
523
524     /**
525      * Return the command name to use for the given command object.
526      * Default is "command".
527      * @param command the command object
528      * @return the command name to use
529      * @see #DEFAULT_COMMAND_NAME
530      */

531     protected String JavaDoc getCommandName(Object JavaDoc command) {
532         return DEFAULT_COMMAND_NAME;
533     }
534
535     /**
536      * Initialize the given binder instance, for example with custom editors.
537      * Called by <code>createBinder</code>.
538      * <p>This method allows you to register custom editors for certain fields of your
539      * command class. For instance, you will be able to transform Date objects into a
540      * String pattern and back, in order to allow your JavaBeans to have Date properties
541      * and still be able to set and display them in an HTML interface.
542      * <p>Default implementation is empty.
543      * <p>Note: the command object is not directly passed to this method, but it's available
544      * via {@link org.springframework.validation.DataBinder#getTarget()}
545      * @param request current HTTP request
546      * @param binder new binder instance
547      * @throws Exception in case of invalid state or arguments
548      * @see #createBinder
549      * @see org.springframework.validation.DataBinder#registerCustomEditor
550      * @see org.springframework.beans.propertyeditors.CustomDateEditor
551      */

552     protected void initBinder(HttpServletRequest JavaDoc request, ServletRequestDataBinder binder)
553         throws Exception JavaDoc {
554
555         initBinder((ServletRequest JavaDoc) request, binder);
556     }
557
558     /**
559      * Initialize the given binder instance, for example with custom editors.
560      * @deprecated since Spring 2.0:
561      * use <code>initBinder(HttpServletRequest, ServletRequestDataBinder) instead
562      */

563     protected void initBinder(ServletRequest JavaDoc request, ServletRequestDataBinder binder)
564         throws Exception JavaDoc {
565     }
566
567
568     /**
569      * Determine the exception handler method for the given exception.
570      * Can return null if not found.
571      * @return a handler for the given exception type, or <code>null</code>
572      * @param exception the exception to handle
573      */

574     protected Method JavaDoc getExceptionHandler(Throwable JavaDoc exception) {
575         Class JavaDoc exceptionClass = exception.getClass();
576         if (logger.isDebugEnabled()) {
577             logger.debug("Trying to find handler for exception class [" + exceptionClass.getName() + "]");
578         }
579         Method JavaDoc handler = (Method JavaDoc) this.exceptionHandlerMap.get(exceptionClass);
580         while (handler == null && !exceptionClass.equals(Throwable JavaDoc.class)) {
581             if (logger.isDebugEnabled()) {
582                 logger.debug("Trying to find handler for exception superclass [" + exceptionClass.getName() + "]");
583             }
584             exceptionClass = exceptionClass.getSuperclass();
585             handler = (Method JavaDoc) this.exceptionHandlerMap.get(exceptionClass);
586         }
587         return handler;
588     }
589
590     /**
591      * We've encountered an exception which may be recoverable
592      * (InvocationTargetException or HttpSessionRequiredException).
593      * Allow the subclass a chance to handle it.
594      * @param request current HTTP request
595      * @param response current HTTP response
596      * @param ex the exception that got thrown
597      * @return a ModelAndView to render the response
598      */

599     private ModelAndView handleException(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, Throwable JavaDoc ex)
600             throws Exception JavaDoc {
601
602         Method JavaDoc handler = getExceptionHandler(ex);
603         if (handler != null) {
604             return invokeExceptionHandler(handler, request, response, ex);
605         }
606         // If we get here, there was no custom handler
607
if (ex instanceof Exception JavaDoc) {
608             throw (Exception JavaDoc) ex;
609         }
610         if (ex instanceof Error JavaDoc) {
611             throw (Error JavaDoc) ex;
612         }
613         // Should never happen!
614
throw new NestedServletException("Unknown Throwable type encountered", ex);
615     }
616
617     /**
618      * Invoke the selected exception handler.
619      * @param handler handler method to invoke
620      */

621     private ModelAndView invokeExceptionHandler(
622             Method JavaDoc handler, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, Throwable JavaDoc ex)
623             throws Exception JavaDoc {
624
625         if (handler == null) {
626             throw new NestedServletException("No handler for exception", ex);
627         }
628
629         // If we get here, we have a handler.
630
if (logger.isDebugEnabled()) {
631             logger.debug("Invoking exception handler [" + handler + "] for exception [" + ex + "]");
632         }
633         try {
634             Object JavaDoc returnValue = handler.invoke(this.delegate, new Object JavaDoc[] {request, response, ex});
635             return massageReturnValueIfNecessary(returnValue);
636         }
637         catch (InvocationTargetException JavaDoc ex2) {
638             Throwable JavaDoc targetEx = ex2.getTargetException();
639             if (targetEx instanceof Exception JavaDoc) {
640                 throw (Exception JavaDoc) targetEx;
641             }
642             if (targetEx instanceof Error JavaDoc) {
643                 throw (Error JavaDoc) targetEx;
644             }
645             // Should never happen!
646
throw new NestedServletException("Unknown Throwable type encountered", targetEx);
647         }
648     }
649
650 }
651
Popular Tags