KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > web > servlet > DispatcherServlet


1 /*
2  * Copyright 2002-2007 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;
18
19 import java.io.IOException JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Collections JavaDoc;
22 import java.util.Enumeration JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.HashSet JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Locale JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.Properties JavaDoc;
30 import java.util.Set JavaDoc;
31
32 import javax.servlet.ServletException JavaDoc;
33 import javax.servlet.http.HttpServletRequest JavaDoc;
34 import javax.servlet.http.HttpServletResponse JavaDoc;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38
39 import org.springframework.beans.BeansException;
40 import org.springframework.beans.factory.BeanFactoryUtils;
41 import org.springframework.beans.factory.BeanInitializationException;
42 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
43 import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
44 import org.springframework.context.i18n.LocaleContext;
45 import org.springframework.context.i18n.LocaleContextHolder;
46 import org.springframework.core.OrderComparator;
47 import org.springframework.core.io.ClassPathResource;
48 import org.springframework.core.io.support.PropertiesLoaderUtils;
49 import org.springframework.ui.context.ThemeSource;
50 import org.springframework.util.ClassUtils;
51 import org.springframework.util.StringUtils;
52 import org.springframework.web.context.request.RequestAttributes;
53 import org.springframework.web.context.request.RequestContextHolder;
54 import org.springframework.web.context.request.ServletRequestAttributes;
55 import org.springframework.web.multipart.MultipartException;
56 import org.springframework.web.multipart.MultipartHttpServletRequest;
57 import org.springframework.web.multipart.MultipartResolver;
58 import org.springframework.web.util.NestedServletException;
59 import org.springframework.web.util.UrlPathHelper;
60 import org.springframework.web.util.WebUtils;
61
62 /**
63  * Central dispatcher for HTTP request handlers/controllers,
64  * e.g. for web UI controllers or HTTP-based remote service exporters.
65  * Dispatches to registered handlers for processing a web request,
66  * providing convenient mapping and exception handling facilities.
67  *
68  * <p>This servlet is very flexible: It can be used with just about any workflow,
69  * with the installation of the appropriate adapter classes. It offers the
70  * following functionality that distinguishes it from other request-driven
71  * web MVC frameworks:
72  *
73  * <ul>
74  * <li>It is based around a JavaBeans configuration mechanism.
75  *
76  * <li>It can use any {@link HandlerMapping} implementation - pre-built or provided
77  * as part of an application - to control the routing of requests to handler objects.
78  * Default is {@link org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping}.
79  * HandlerMapping objects can be defined as beans in the servlet's application context,
80  * implementing the HandlerMapping interface, overriding the default HandlerMapping
81  * if present. HandlerMappings can be given any bean name (they are tested by type).
82  *
83  * <li>It can use any {@link HandlerAdapter}; this allows to use any handler interface.
84  * Default adapters are {@link org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter},
85  * {@link org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter} and
86  * {@link org.springframework.web.servlet.mvc.throwaway.ThrowawayControllerHandlerAdapter},
87  * for Spring's {@link org.springframework.web.HttpRequestHandler},
88  * {@link org.springframework.web.servlet.mvc.Controller} and
89  * {@link org.springframework.web.servlet.mvc.throwaway.ThrowawayController} interfaces,
90  * respectively. HandlerAdapter objects can be added as beans in the application context,
91  * overriding the default HandlerAdapters. Like HandlerMappings, HandlerAdapters
92  * can be given any bean name (they are tested by type).
93  *
94  * <li>The dispatcher's exception resolution strategy can be specified via a
95  * {@link HandlerExceptionResolver}, for example mapping certain exceptions to
96  * error pages. Default is none. Additional HandlerExceptionResolvers can be added
97  * through the application context. HandlerExceptionResolver can be given any
98  * bean name (they are tested by type).
99  *
100  * <li>Its view resolution strategy can be specified via a {@link ViewResolver}
101  * implementation, resolving symbolic view names into View objects. Default is
102  * {@link org.springframework.web.servlet.view.InternalResourceViewResolver}.
103  * ViewResolver objects can be added as beans in the application context,
104  * overriding the default ViewResolver. ViewResolvers can be given any bean name
105  * (they are tested by type).
106  *
107  * <li>If a {@link View} or view name is not supplied by the user, then the configured
108  * {@link RequestToViewNameTranslator} will translate the current request into a
109  * view name. The corresponding bean name is "viewNameTranslator"; the default is
110  * {@link org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator}.
111  *
112  * <li>The dispatcher's strategy for resolving multipart requests is determined by
113  * a {@link org.springframework.web.multipart.MultipartResolver} implementation.
114  * Implementations for Jakarta Commons FileUpload and Jason Hunter's COS are
115  * included; the typical choise is
116  * {@link org.springframework.web.multipart.commons.CommonsMultipartResolver}.
117  * The MultipartResolver bean name is "multipartResolver"; default is none.
118  *
119  * <li>Its locale resolution strategy is determined by a {@link LocaleResolver}.
120  * Out-of-the-box implementations work via HTTP accept header, cookie, or session.
121  * The LocaleResolver bean name is "localeResolver"; default is
122  * {@link org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver}.
123  *
124  * <li>Its theme resolution strategy is determined by a {@link ThemeResolver}.
125  * Implementations for a fixed theme and for cookie and session storage are included.
126  * The ThemeResolver bean name is "themeResolver"; default is
127  * {@link org.springframework.web.servlet.theme.FixedThemeResolver}.
128  * </ul>
129  *
130  * <p><b>A web application can define any number of DispatcherServlets.</b>
131  * Each servlet will operate in its own namespace, loading its own application
132  * context with mappings, handlers, etc. Only the root application context
133  * as loaded by {@link org.springframework.web.context.ContextLoaderListener},
134  * if any, will be shared.
135  *
136  * @author Rod Johnson
137  * @author Juergen Hoeller
138  * @author Rob Harrop
139  * @see org.springframework.web.HttpRequestHandler
140  * @see org.springframework.web.servlet.mvc.Controller
141  * @see org.springframework.web.context.ContextLoaderListener
142  */

143 public class DispatcherServlet extends FrameworkServlet {
144
145     /**
146      * Well-known name for the MultipartResolver object in the bean factory for this namespace.
147      */

148     public static final String JavaDoc MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
149
150     /**
151      * Well-known name for the LocaleResolver object in the bean factory for this namespace.
152      */

153     public static final String JavaDoc LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
154
155     /**
156      * Well-known name for the ThemeResolver object in the bean factory for this namespace.
157      */

158     public static final String JavaDoc THEME_RESOLVER_BEAN_NAME = "themeResolver";
159
160     /**
161      * Well-known name for the HandlerMapping object in the bean factory for this namespace.
162      * Only used when "detectAllHandlerMappings" is turned off.
163      * @see #setDetectAllHandlerMappings
164      */

165     public static final String JavaDoc HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
166
167     /**
168      * Well-known name for the HandlerAdapter object in the bean factory for this namespace.
169      * Only used when "detectAllHandlerAdapters" is turned off.
170      * @see #setDetectAllHandlerAdapters
171      */

172     public static final String JavaDoc HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
173
174     /**
175      * Well-known name for the HandlerExceptionResolver object in the bean factory for this
176      * namespace. Only used when "detectAllHandlerExceptionResolvers" is turned off.
177      * @see #setDetectAllHandlerExceptionResolvers
178      */

179     public static final String JavaDoc HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
180
181     /**
182      * Well-known name for the RequestToViewNameTranslator object in the bean factory for
183      * this namespace.
184      */

185     public static final String JavaDoc REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";
186
187     /**
188      * Well-known name for the ViewResolver object in the bean factory for this namespace.
189      * Only used when "detectAllViewResolvers" is turned off.
190      * @see #setDetectAllViewResolvers
191      */

192     public static final String JavaDoc VIEW_RESOLVER_BEAN_NAME = "viewResolver";
193
194     /**
195      * Request attribute to hold the currently chosen HandlerExecutionChain.
196      * Only used for internal optimizations.
197      */

198     public static final String JavaDoc HANDLER_EXECUTION_CHAIN_ATTRIBUTE = DispatcherServlet.class.getName() + ".HANDLER";
199
200     /**
201      * Request attribute to hold the current web application context.
202      * Otherwise only the global web app context is obtainable by tags etc.
203      * @see org.springframework.web.servlet.support.RequestContextUtils#getWebApplicationContext
204      */

205     public static final String JavaDoc WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName() + ".CONTEXT";
206
207     /**
208      * Request attribute to hold the current LocaleResolver, retrievable by views.
209      * @see org.springframework.web.servlet.support.RequestContextUtils#getLocaleResolver
210      */

211     public static final String JavaDoc LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".LOCALE_RESOLVER";
212
213     /**
214      * Request attribute to hold the current ThemeResolver, retrievable by views.
215      * @see org.springframework.web.servlet.support.RequestContextUtils#getThemeResolver
216      */

217     public static final String JavaDoc THEME_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_RESOLVER";
218
219     /**
220      * Request attribute to hold the current ThemeSource, retrievable by views.
221      * @see org.springframework.web.servlet.support.RequestContextUtils#getThemeSource
222      */

223     public static final String JavaDoc THEME_SOURCE_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_SOURCE";
224
225
226     /**
227      * Log category to use when no mapped handler is found for a request.
228      */

229     public static final String JavaDoc PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";
230
231     /**
232      * Name of the class path resource (relative to the DispatcherServlet class)
233      * that defines DispatcherServlet's default strategy names.
234      */

235     private static final String JavaDoc DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
236
237
238     /**
239      * Additional logger to use when no mapped handler is found for a request.
240      */

241     protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY);
242
243     private static final Properties JavaDoc defaultStrategies;
244
245     static {
246         // Load default strategy implementations from properties file.
247
// This is currently strictly internal and not meant to be customized
248
// by application developers.
249
try {
250             ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
251             defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
252         }
253         catch (IOException JavaDoc ex) {
254             throw new IllegalStateException JavaDoc("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
255         }
256     }
257
258
259     /** Detect all HandlerMappings or just expect "handlerMapping" bean? */
260     private boolean detectAllHandlerMappings = true;
261
262     /** Detect all HandlerAdapters or just expect "handlerAdapter" bean? */
263     private boolean detectAllHandlerAdapters = true;
264
265     /** Detect all HandlerExceptionResolvers or just expect "handlerExceptionResolver" bean? */
266     private boolean detectAllHandlerExceptionResolvers = true;
267
268     /** Detect all ViewResolvers or just expect "viewResolver" bean? */
269     private boolean detectAllViewResolvers = true;
270
271     /** Perform cleanup of request attributes after include request? */
272     private boolean cleanupAfterInclude = true;
273
274     /** Expose LocaleContext and RequestAttributes as inheritable for child threads? */
275     private boolean threadContextInheritable = false;
276
277
278     /** MultipartResolver used by this servlet */
279     private MultipartResolver multipartResolver;
280
281     /** LocaleResolver used by this servlet */
282     private LocaleResolver localeResolver;
283
284     /** ThemeResolver used by this servlet */
285     private ThemeResolver themeResolver;
286
287     /** List of HandlerMappings used by this servlet */
288     private List JavaDoc handlerMappings;
289
290     /** List of HandlerAdapters used by this servlet */
291     private List JavaDoc handlerAdapters;
292
293     /** List of HandlerExceptionResolvers used by this servlet */
294     private List JavaDoc handlerExceptionResolvers;
295
296     /** RequestToViewNameTranslator used by this servlet */
297     private RequestToViewNameTranslator viewNameTranslator;
298
299     /** List of ViewResolvers used by this servlet */
300     private List JavaDoc viewResolvers;
301
302
303     /**
304      * Set whether to detect all HandlerMapping beans in this servlet's context.
305      * Else, just a single bean with name "handlerMapping" will be expected.
306      * <p>Default is "true". Turn this off if you want this servlet to use a
307      * single HandlerMapping, despite multiple HandlerMapping beans being
308      * defined in the context.
309      */

310     public void setDetectAllHandlerMappings(boolean detectAllHandlerMappings) {
311         this.detectAllHandlerMappings = detectAllHandlerMappings;
312     }
313
314     /**
315      * Set whether to detect all HandlerAdapter beans in this servlet's context.
316      * Else, just a single bean with name "handlerAdapter" will be expected.
317      * <p>Default is "true". Turn this off if you want this servlet to use a
318      * single HandlerAdapter, despite multiple HandlerAdapter beans being
319      * defined in the context.
320      */

321     public void setDetectAllHandlerAdapters(boolean detectAllHandlerAdapters) {
322         this.detectAllHandlerAdapters = detectAllHandlerAdapters;
323     }
324
325     /**
326      * Set whether to detect all HandlerExceptionResolver beans in this servlet's context.
327      * Else, just a single bean with name "handlerExceptionResolver" will be expected.
328      * <p>Default is "true". Turn this off if you want this servlet to use a
329      * single HandlerExceptionResolver, despite multiple HandlerExceptionResolver
330      * beans being defined in the context.
331      */

332     public void setDetectAllHandlerExceptionResolvers(boolean detectAllHandlerExceptionResolvers) {
333         this.detectAllHandlerExceptionResolvers = detectAllHandlerExceptionResolvers;
334     }
335
336     /**
337      * Set whether to detect all ViewResolver beans in this servlet's context.
338      * Else, just a single bean with name "viewResolver" will be expected.
339      * <p>Default is "true". Turn this off if you want this servlet to use a
340      * single ViewResolver, despite multiple ViewResolver beans being
341      * defined in the context.
342      */

343     public void setDetectAllViewResolvers(boolean detectAllViewResolvers) {
344         this.detectAllViewResolvers = detectAllViewResolvers;
345     }
346
347     /**
348      * Set whether to perform cleanup of request attributes after an include request,
349      * that is, whether to reset the original state of all request attributes after
350      * the DispatcherServlet has processed within an include request. Else, just the
351      * DispatcherServlet's own request attributes will be reset, but not model
352      * attributes for JSPs or special attributes set by views (for example, JSTL's).
353      * <p>Default is "true", which is strongly recommended. Views should not rely on
354      * request attributes having been set by (dynamic) includes. This allows JSP views
355      * rendered by an included controller to use any model attributes, even with the
356      * same names as in the main JSP, without causing side effects. Only turn this
357      * off for special needs, for example to deliberately allow main JSPs to access
358      * attributes from JSP views rendered by an included controller.
359      */

360     public void setCleanupAfterInclude(boolean cleanupAfterInclude) {
361         this.cleanupAfterInclude = cleanupAfterInclude;
362     }
363
364     /**
365      * Set whether to expose the LocaleContext and RequestAttributes as inheritable
366      * for child threads (using an {@link java.lang.InheritableThreadLocal}).
367      * <p>Default is "false", to avoid side effects on spawned background threads.
368      * Switch this to "true" to enable inheritance for custom child threads which
369      * are spawned during request processing and only used for this request
370      * (that is, ending after their initial task, without reuse of the thread).
371      * <p><b>WARNING:</b> Do not use inheritance for child threads if you are
372      * accessing a thread pool which is configured to potentially add new threads
373      * on demand (e.g. a JDK {@link java.util.concurrent.ThreadPoolExecutor}),
374      * since this will expose the inherited context to such a pooled thread.
375      */

376     public void setThreadContextInheritable(boolean threadContextInheritable) {
377         this.threadContextInheritable = threadContextInheritable;
378     }
379
380
381     /**
382      * Overridden method, invoked after any bean properties have been set and the
383      * WebApplicationContext and BeanFactory for this namespace is available.
384      * <p>Loads HandlerMapping and HandlerAdapter objects, and configures a
385      * ViewResolver and a LocaleResolver.
386      */

387     protected void initFrameworkServlet() throws ServletException JavaDoc, BeansException {
388         initMultipartResolver();
389         initLocaleResolver();
390         initThemeResolver();
391         initHandlerMappings();
392         initHandlerAdapters();
393         initHandlerExceptionResolvers();
394         initRequestToViewNameTranslator();
395         initViewResolvers();
396     }
397
398     /**
399      * Initialize the MultipartResolver used by this class.
400      * <p>If no bean is defined with the given name in the BeanFactory
401      * for this namespace, no multipart handling is provided.
402      */

403     private void initMultipartResolver() {
404         try {
405             this.multipartResolver = (MultipartResolver)
406                     getWebApplicationContext().getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
407             if (logger.isDebugEnabled()) {
408                 logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
409             }
410         }
411         catch (NoSuchBeanDefinitionException ex) {
412             // Default is no multipart resolver.
413
this.multipartResolver = null;
414             if (logger.isDebugEnabled()) {
415                 logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
416                         "': no multipart request handling provided");
417             }
418         }
419     }
420
421     /**
422      * Initialize the LocaleResolver used by this class.
423      * <p>If no bean is defined with the given name in the BeanFactory
424      * for this namespace, we default to AcceptHeaderLocaleResolver.
425      */

426     private void initLocaleResolver() {
427         try {
428             this.localeResolver = (LocaleResolver)
429                     getWebApplicationContext().getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
430             if (logger.isDebugEnabled()) {
431                 logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
432             }
433         }
434         catch (NoSuchBeanDefinitionException ex) {
435             // We need to use the default.
436
this.localeResolver = (LocaleResolver) getDefaultStrategy(LocaleResolver.class);
437             if (logger.isDebugEnabled()) {
438                 logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
439                         "': using default [" + this.localeResolver + "]");
440             }
441         }
442     }
443
444     /**
445      * Initialize the ThemeResolver used by this class.
446      * <p>If no bean is defined with the given name in the BeanFactory
447      * for this namespace, we default to a FixedThemeResolver.
448      */

449     private void initThemeResolver() {
450         try {
451             this.themeResolver = (ThemeResolver)
452                     getWebApplicationContext().getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
453             if (logger.isDebugEnabled()) {
454                 logger.debug("Using ThemeResolver [" + this.themeResolver + "]");
455             }
456         }
457         catch (NoSuchBeanDefinitionException ex) {
458             // We need to use the default.
459
this.themeResolver = (ThemeResolver) getDefaultStrategy(ThemeResolver.class);
460             if (logger.isDebugEnabled()) {
461                 logger.debug("Unable to locate ThemeResolver with name '" + THEME_RESOLVER_BEAN_NAME +
462                         "': using default [" + this.themeResolver + "]");
463             }
464         }
465     }
466
467     /**
468      * Initialize the HandlerMappings used by this class.
469      * <p>If no HandlerMapping beans are defined in the BeanFactory
470      * for this namespace, we default to BeanNameUrlHandlerMapping.
471      */

472     private void initHandlerMappings() {
473         if (this.detectAllHandlerMappings) {
474             // Find all HandlerMappings in the ApplicationContext,
475
// including ancestor contexts.
476
Map JavaDoc matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
477                     getWebApplicationContext(), HandlerMapping.class, true, false);
478             if (!matchingBeans.isEmpty()) {
479                 this.handlerMappings = new ArrayList JavaDoc(matchingBeans.values());
480                 // We keep HandlerMappings in sorted order.
481
Collections.sort(this.handlerMappings, new OrderComparator());
482             }
483         }
484         else {
485             try {
486                 Object JavaDoc hm = getWebApplicationContext().getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
487                 this.handlerMappings = Collections.singletonList(hm);
488             }
489             catch (NoSuchBeanDefinitionException ex) {
490                 // Ignore, we'll add a default HandlerMapping later.
491
}
492         }
493
494         // Ensure we have at least one HandlerMapping, by registering
495
// a default HandlerMapping if no other mappings are found.
496
if (this.handlerMappings == null) {
497             this.handlerMappings = getDefaultStrategies(HandlerMapping.class);
498             if (logger.isDebugEnabled()) {
499                 logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
500             }
501         }
502     }
503
504     /**
505      * Initialize the HandlerAdapters used by this class.
506      * <p>If no HandlerAdapter beans are defined in the BeanFactory
507      * for this namespace, we default to SimpleControllerHandlerAdapter.
508      */

509     private void initHandlerAdapters() {
510         if (this.detectAllHandlerAdapters) {
511             // Find all HandlerAdapters in the ApplicationContext,
512
// including ancestor contexts.
513
Map JavaDoc matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
514                     getWebApplicationContext(), HandlerAdapter.class, true, false);
515             if (!matchingBeans.isEmpty()) {
516                 this.handlerAdapters = new ArrayList JavaDoc(matchingBeans.values());
517                 // We keep HandlerAdapters in sorted order.
518
Collections.sort(this.handlerAdapters, new OrderComparator());
519             }
520         }
521         else {
522             try {
523                 Object JavaDoc ha = getWebApplicationContext().getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
524                 this.handlerAdapters = Collections.singletonList(ha);
525             }
526             catch (NoSuchBeanDefinitionException ex) {
527                 // Ignore, we'll add a default HandlerAdapter later.
528
}
529         }
530
531         // Ensure we have at least some HandlerAdapters, by registering
532
// default HandlerAdapters if no other adapters are found.
533
if (this.handlerAdapters == null) {
534             this.handlerAdapters = getDefaultStrategies(HandlerAdapter.class);
535             if (logger.isDebugEnabled()) {
536                 logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
537             }
538         }
539     }
540
541     /**
542      * Initialize the HandlerExceptionResolver used by this class.
543      * <p>If no bean is defined with the given name in the BeanFactory
544      * for this namespace, we default to no exception resolver.
545      */

546     private void initHandlerExceptionResolvers() {
547         if (this.detectAllHandlerExceptionResolvers) {
548             // Find all HandlerExceptionResolvers in the ApplicationContext,
549
// including ancestor contexts.
550
Map JavaDoc matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
551                     getWebApplicationContext(), HandlerExceptionResolver.class, true, false);
552             this.handlerExceptionResolvers = new ArrayList JavaDoc(matchingBeans.values());
553             // We keep HandlerExceptionResolvers in sorted order.
554
Collections.sort(this.handlerExceptionResolvers, new OrderComparator());
555         }
556         else {
557             try {
558                 Object JavaDoc her = getWebApplicationContext().getBean(
559                         HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
560                 this.handlerExceptionResolvers = Collections.singletonList(her);
561             }
562             catch (NoSuchBeanDefinitionException ex) {
563                 // Ignore, no HandlerExceptionResolver is fine too.
564
this.handlerExceptionResolvers = getDefaultStrategies(HandlerExceptionResolver.class);
565             }
566         }
567     }
568
569     /**
570      * Initialize the RequestToViewNameTranslator used by this servlet instance. If no
571      * implementation is configured then we default to DefaultRequestToViewNameTranslator.
572      */

573     private void initRequestToViewNameTranslator() {
574         try {
575             this.viewNameTranslator = (RequestToViewNameTranslator) getWebApplicationContext().getBean(
576                     REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
577             if (logger.isDebugEnabled()) {
578                 logger.debug("Using RequestToViewNameTranslator [" + this.viewNameTranslator + "]");
579             }
580         }
581         catch (NoSuchBeanDefinitionException ex) {
582             // We need to use the default.
583
this.viewNameTranslator =
584                     (RequestToViewNameTranslator) getDefaultStrategy(RequestToViewNameTranslator.class);
585             if (logger.isDebugEnabled()) {
586                 logger.debug("Unable to locate RequestToViewNameTranslator with name '" +
587                         REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME +
588                         "': using default [" + this.viewNameTranslator + "]");
589             }
590         }
591     }
592
593     /**
594      * Initialize the ViewResolvers used by this class.
595      * <p>If no ViewResolver beans are defined in the BeanFactory
596      * for this namespace, we default to InternalResourceViewResolver.
597      */

598     private void initViewResolvers() {
599         if (this.detectAllViewResolvers) {
600             // Find all ViewResolvers in the ApplicationContext,
601
// including ancestor contexts.
602
Map JavaDoc matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
603                     getWebApplicationContext(), ViewResolver.class, true, false);
604             if (!matchingBeans.isEmpty()) {
605                 this.viewResolvers = new ArrayList JavaDoc(matchingBeans.values());
606                 // We keep ViewResolvers in sorted order.
607
Collections.sort(this.viewResolvers, new OrderComparator());
608             }
609         }
610         else {
611             try {
612                 Object JavaDoc vr = getWebApplicationContext().getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
613                 this.viewResolvers = Collections.singletonList(vr);
614             }
615             catch (NoSuchBeanDefinitionException ex) {
616                 // Ignore, we'll add a default ViewResolver later.
617
}
618         }
619
620         // Ensure we have at least one ViewResolver, by registering
621
// a default ViewResolver if no other resolvers are found.
622
if (this.viewResolvers == null) {
623             this.viewResolvers = getDefaultStrategies(ViewResolver.class);
624             if (logger.isDebugEnabled()) {
625                 logger.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default");
626             }
627         }
628     }
629
630     /**
631      * Return this servlet's ThemeSource, if any; else return <code>null</code>.
632      * <p>Default is to return the WebApplicationContext as ThemeSource,
633      * provided that it implements the ThemeSource interface.
634      * @see #getWebApplicationContext()
635      */

636     public ThemeSource getThemeSource() {
637         if (getWebApplicationContext() instanceof ThemeSource) {
638             return (ThemeSource) getWebApplicationContext();
639         }
640         else {
641             return null;
642         }
643     }
644
645
646     /**
647      * Return the default strategy object for the given strategy interface.
648      * <p>The default implementation delegates to {@link #getDefaultStrategies},
649      * expecting a single object in the list.
650      * @param strategyInterface the strategy interface
651      * @return the corresponding strategy object
652      * @throws BeansException if initialization failed
653      * @see #getDefaultStrategies
654      */

655     protected Object JavaDoc getDefaultStrategy(Class JavaDoc strategyInterface) throws BeansException {
656         List JavaDoc strategies = getDefaultStrategies(strategyInterface);
657         if (strategies.size() != 1) {
658             throw new BeanInitializationException(
659                     "DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");
660         }
661         return strategies.get(0);
662     }
663
664     /**
665      * Create a List of default strategy objects for the given strategy interface.
666      * <p>The default implementation uses the "DispatcherServlet.properties" file
667      * (in the same package as the DispatcherServlet class) to determine the class names.
668      * It instantiates the strategy objects through the context's BeanFactory.
669      * @param strategyInterface the strategy interface
670      * @return the List of corresponding strategy objects
671      * @throws BeansException if initialization failed
672      */

673     protected List JavaDoc getDefaultStrategies(Class JavaDoc strategyInterface) throws BeansException {
674         String JavaDoc key = strategyInterface.getName();
675         List JavaDoc strategies = null;
676         String JavaDoc value = defaultStrategies.getProperty(key);
677         if (value != null) {
678             String JavaDoc[] classNames = StringUtils.commaDelimitedListToStringArray(value);
679             strategies = new ArrayList JavaDoc(classNames.length);
680             for (int i = 0; i < classNames.length; i++) {
681                 String JavaDoc className = classNames[i];
682                 try {
683                     Class JavaDoc clazz = ClassUtils.forName(className, getClass().getClassLoader());
684                     Object JavaDoc strategy = createDefaultStrategy(clazz);
685                     strategies.add(strategy);
686                 }
687                 catch (ClassNotFoundException JavaDoc ex) {
688                     throw new BeanInitializationException(
689                             "Could not find DispatcherServlet's default strategy class [" + className +
690                             "] for interface [" + key + "]", ex);
691                 }
692                 catch (LinkageError JavaDoc err) {
693                     throw new BeanInitializationException(
694                             "Error loading DispatcherServlet's default strategy class [" + className +
695                             "] for interface [" + key + "]: problem with class file or dependent class", err);
696                 }
697             }
698         }
699         else {
700             strategies = Collections.EMPTY_LIST;
701         }
702         return strategies;
703     }
704
705     /**
706      * Create a default strategy.
707      * <p>The default implementation uses
708      * {@link org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean}.
709      * @param clazz the strategy implementation class to instantiate
710      * @throws BeansException if initialization failed
711      * @return the fully configured strategy instance
712      * @see #getWebApplicationContext()
713      * @see org.springframework.context.ApplicationContext#getAutowireCapableBeanFactory()
714      * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#createBean
715      */

716     protected Object JavaDoc createDefaultStrategy(Class JavaDoc clazz) throws BeansException {
717         return getWebApplicationContext().getAutowireCapableBeanFactory().createBean(
718                 clazz, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
719     }
720
721
722     /**
723      * Exposes the DispatcherServlet-specific request attributes and
724      * delegates to {@link #doDispatch} for the actual dispatching.
725      */

726     protected void doService(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) throws Exception JavaDoc {
727         if (logger.isDebugEnabled()) {
728             logger.debug("DispatcherServlet with name '" + getServletName() + "' received request for [" +
729                     request.getRequestURI() + "]");
730         }
731
732         // Keep a snapshot of the request attributes in case of an include,
733
// to be able to restore the original attributes after the include.
734
Map JavaDoc attributesSnapshot = null;
735         if (WebUtils.isIncludeRequest(request)) {
736             logger.debug("Taking snapshot of request attributes before include");
737             attributesSnapshot = new HashMap JavaDoc();
738             Enumeration JavaDoc attrNames = request.getAttributeNames();
739             while (attrNames.hasMoreElements()) {
740                 String JavaDoc attrName = (String JavaDoc) attrNames.nextElement();
741                 if (this.cleanupAfterInclude || attrName.startsWith(DispatcherServlet.class.getName())) {
742                     attributesSnapshot.put(attrName, request.getAttribute(attrName));
743                 }
744             }
745         }
746
747         // Make framework objects available to handlers and view objects.
748
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
749         request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
750         request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
751         request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
752
753         try {
754             doDispatch(request, response);
755         }
756         finally {
757             // Restore the original attribute snapshot, in case of an include.
758
if (attributesSnapshot != null) {
759                 restoreAttributesAfterInclude(request, attributesSnapshot);
760             }
761         }
762     }
763
764     /**
765      * Process the actual dispatching to the handler.
766      * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
767      * The HandlerAdapter will be obtained by querying the servlet's installed
768      * HandlerAdapters to find the first that supports the handler class.
769      * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or
770      * handlers themselves to decide which methods are acceptable.
771      * @param request current HTTP request
772      * @param response current HTTP response
773      * @throws Exception in case of any kind of processing failure
774      */

775     protected void doDispatch(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response) throws Exception JavaDoc {
776         HttpServletRequest JavaDoc processedRequest = request;
777         HandlerExecutionChain mappedHandler = null;
778         int interceptorIndex = -1;
779
780