/* * Copyright 2008 biaoping.yin * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.frameworkset.web.servlet; import java.io.IOException; import java.lang.reflect.Method; import java.security.Principal; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Set; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.PageContext; import org.apache.log4j.Logger; import org.frameworkset.http.converter.HttpMessageConverter; import org.frameworkset.spi.BaseApplicationContext; import org.frameworkset.spi.LifeCycleProcessorExecutor; import org.frameworkset.spi.assemble.Pro; import org.frameworkset.spi.assemble.ProList; import org.frameworkset.spi.event.IocLifeCycleEventListener; import org.frameworkset.spi.io.PropertiesLoaderUtils; import org.frameworkset.spi.support.LocaleContextHolder; import org.frameworkset.util.ClassUtils; import org.frameworkset.util.DataFormatUtil; import org.frameworkset.util.beans.BeansException; import org.frameworkset.util.io.ClassPathResource; import org.frameworkset.web.HttpRequestMethodNotSupportedException; import org.frameworkset.web.multipart.MultipartException; import org.frameworkset.web.multipart.MultipartHttpServletRequest; import org.frameworkset.web.multipart.MultipartResolver; import org.frameworkset.web.request.async.WebAsyncManager; import org.frameworkset.web.request.async.WebAsyncUtils; import org.frameworkset.web.servlet.context.RequestContextHolder; import org.frameworkset.web.servlet.context.WebApplicationContext; import org.frameworkset.web.servlet.handler.AbstractUrlHandlerMapping; import org.frameworkset.web.servlet.handler.HandlerMappingsTable; import org.frameworkset.web.servlet.handler.HandlerMeta; import org.frameworkset.web.servlet.handler.HandlerUtils; import org.frameworkset.web.servlet.handler.PathURLNotSetException; import org.frameworkset.web.servlet.handler.annotations.AnnotationMethodHandlerAdapter; import org.frameworkset.web.servlet.handler.annotations.DefaultAnnotationHandlerMapping; import org.frameworkset.web.servlet.i18n.DefaultLocaleResolver; import org.frameworkset.web.servlet.mvc.HttpRequestHandlerAdapter; import org.frameworkset.web.servlet.mvc.ServletWebRequest; import org.frameworkset.web.servlet.mvc.SimpleControllerHandlerAdapter; import org.frameworkset.web.servlet.support.RequestContext; import org.frameworkset.web.servlet.support.RequestContextUtils; import org.frameworkset.web.servlet.support.RequestMethodHttpServletRequest; import org.frameworkset.web.servlet.support.WebApplicationContextUtils; import org.frameworkset.web.servlet.view.AbstractUrlBasedView; import org.frameworkset.web.servlet.view.UrlBasedViewResolver; import org.frameworkset.web.servlet.view.View; import org.frameworkset.web.servlet.view.ViewResolver; import org.frameworkset.web.ui.ThemeSource; import org.frameworkset.web.util.UrlPathHelper; import org.frameworkset.web.util.WebUtils; import com.frameworkset.spi.assemble.BeanInstanceException; import com.frameworkset.util.StringUtil; /** * <p>Title: DispatchServlet.java</p> * <p>Description: </p> * <p>bboss workgroup</p> * <p>Copyright (c) 2008</p> * @Date 2010-9-22 * @author biaoping.yin * @version 1.0 */ public class DispatchServlet extends BaseServlet { private static Properties defaultStrategies; private String iocLifeCycleEventListeners; private String iocLifeCycleEventListenerParams; private List<IocLifeCycleEventListener> iocLifeCycleEventListenerList ; public static Properties getDefaultStrategies() { return defaultStrategies; } public static void destory() { DispatchServlet.defaultStrategies = null; DispatchServlet.localeResolver = null; DispatchServlet.viewResolvers = null; DispatchServlet.webApplicationContext = null; } /** * Name of the class path resource (relative to the DispatcherServlet class) * that defines DispatcherServlet's default strategy names. */ private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties"; private static Logger logger = Logger.getLogger(DispatchServlet.class); static { // Load default strategy implementations from properties file. // This is currently strictly internal and not meant to be customized // by application developers. try { // ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatchServlet.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage()); } } /** Should we dispatch an HTTP OPTIONS request to {@link #doService}? */ private boolean dispatchOptionsRequest = false; /** Should we dispatch an HTTP TRACE request to {@link #doService}? */ private boolean dispatchTraceRequest = false; /** * Well-known name for the MultipartResolver object in the bean factory for this namespace. */ public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver"; /** * Well-known name for the LocaleResolver object in the bean factory for this namespace. */ public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver"; /** * Well-known name for the ThemeResolver object in the bean factory for this namespace. */ public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver"; /** * Well-known name for the HandlerMapping object in the bean factory for this namespace. * Only used when "detectAllHandlerMappings" is turned off. * @see #setDetectAllHandlerMappings */ public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping"; /** * Well-known name for the HandlerAdapter object in the bean factory for this namespace. * Only used when "detectAllHandlerAdapters" is turned off. * @see #setDetectAllHandlerAdapters */ // public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter"; /** * Well-known name for the HandlerExceptionResolver object in the bean factory for this * namespace. Only used when "detectAllHandlerExceptionResolvers" is turned off. * @see #setDetectAllHandlerExceptionResolvers */ public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver"; /** * Well-known name for the RequestToViewNameTranslator object in the bean factory for * this namespace. */ public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator"; /** * Well-known name for the ViewResolver object in the bean factory for this namespace. * Only used when "detectAllViewResolvers" is turned off. * @see #setDetectAllViewResolvers */ public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver"; /** * Request attribute to hold the currently chosen HandlerExecutionChain. * Only used for internal optimizations. */ public static final String HANDLER_EXECUTION_CHAIN_ATTRIBUTE = DispatchServlet.class.getName() + ".HANDLER"; /** * Request attribute to hold the current web application context. * Otherwise only the global web app context is obtainable by tags etc. * @see RequestContextUtils#getWebApplicationContext */ public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatchServlet.class.getName() + ".CONTEXT"; /** * Request attribute to hold the current LocaleResolver, retrievable by views. * @see RequestContextUtils#getLocaleResolver */ public static final String LOCALE_RESOLVER_ATTRIBUTE = DispatchServlet.class.getName() + ".LOCALE_RESOLVER"; /** * Request attribute to hold the current ThemeResolver, retrievable by views. * @see RequestContextUtils#getThemeResolver */ public static final String THEME_RESOLVER_ATTRIBUTE = DispatchServlet.class.getName() + ".THEME_RESOLVER"; /** * Request attribute to hold the current ThemeSource, retrievable by views. * @see RequestContextUtils#getThemeSource */ public static final String THEME_SOURCE_ATTRIBUTE = DispatchServlet.class.getName() + ".THEME_SOURCE"; /** * Log category to use when no mapped handler is found for a request. */ public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.frameworkset.web.servlet.PageNotFound"; /** * Log category to use when no mapped handler is found for a request. */ public static final String messageConverters_KEY = "org.frameworkset.web.servlet.messageConverters_KEY"; /** * Additional logger to use when no mapped handler is found for a request. */ protected static final Logger pageNotFoundLogger = Logger.getLogger(PAGE_NOT_FOUND_LOG_CATEGORY); /** List of ViewResolvers used by this servlet */ private static List viewResolvers; /** List of HandlerMappings used by this servlet */ private HandlerMappingsTable handlerMappings; /** List of HandlerAdapters used by this servlet */ // private List<HandlerAdapter> handlerAdapters; org.frameworkset.web.servlet.handler.annotations.AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter; org.frameworkset.web.servlet.mvc.SimpleControllerHandlerAdapter simpleControllerHandlerAdapter; org.frameworkset.web.servlet.mvc.HttpRequestHandlerAdapter httpRequestHandlerAdapter; /** List of HandlerAdapters used by this servlet */ private List<HandlerInterceptor> gloabelHandlerInterceptors; private HttpMessageConverter[] messageConverters; /** Expose LocaleContext and RequestAttributes as inheritable for child threads? */ private static boolean threadContextInheritable = false; /** MultipartResolver used by this servlet */ private MultipartResolver multipartResolver; /** RequestToViewNameTranslator used by this servlet */ private RequestToViewNameTranslator viewNameTranslator; /** List of HandlerExceptionResolvers used by this servlet */ private List handlerExceptionResolvers; /** WebApplicationContext for this servlet */ public static WebApplicationContext webApplicationContext; private static String messagesources = null; private static String useCodeAsDefaultMessage = "true"; public static String getMessagesources() { return messagesources; } /** * Set whether this servlet should dispatch an HTTP OPTIONS request to * the {@link #doService} method. * <p>Default is "false", applying {@link javax.servlet.http.HttpServlet}'s * default behavior (i.e. enumerating all standard HTTP request methods * as a response to the OPTIONS request). * <p>Turn this flag on if you prefer OPTIONS requests to go through the * regular dispatching chain, just like other HTTP requests. This usually * means that your controllers will receive those requests; make sure * that those endpoints are actually able to handle an OPTIONS request. * <p>Note that HttpServlet's default OPTIONS processing will be applied * in any case. Your controllers are simply available to override the * default headers and optionally generate a response body. */ public void setDispatchOptionsRequest(boolean dispatchOptionsRequest) { this.dispatchOptionsRequest = dispatchOptionsRequest; } /** * Set whether this servlet should dispatch an HTTP TRACE request to * the {@link #doService} method. * <p>Default is "false", applying {@link javax.servlet.http.HttpServlet}'s * default behavior (i.e. reflecting the message received back to the client). * <p>Turn this flag on if you prefer TRACE requests to go through the * regular dispatching chain, just like other HTTP requests. This usually * means that your controllers will receive those requests; make sure * that those endpoints are actually able to handle a TRACE request. * <p>Note that HttpServlet's default TRACE processing will be applied * in any case. Your controllers are simply available to override the * default headers and the default body, calling <code>response.reset()</code> * if necessary. */ public void setDispatchTraceRequest(boolean dispatchTraceRequest) { this.dispatchTraceRequest = dispatchTraceRequest; } /** * Override HttpServlet's <code>getLastModified</code> method to evaluate * the Last-Modified value of the mapped handler. */ protected long getLastModified(HttpServletRequest request) { if (logger.isDebugEnabled()) { String requestUri = new UrlPathHelper().getRequestUri(request); logger.debug("DispatcherServlet with name '" + getServletName() + "' determining Last-Modified value for [" + requestUri + "]"); } try { if(request instanceof RequestMethodHttpServletRequest) { } else { request = new RequestMethodHttpServletRequest(request); } HandlerExecutionChain mappedHandler = getHandler(request, true); if (mappedHandler == null || mappedHandler.getHandler() == null || mappedHandler.getHandler().getHandler() == null) { // Ignore -> will reappear on doService. logger.debug("No handler found in getLastModified"); return -1; } HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isInfoEnabled()) { String requestUri = new UrlPathHelper().getRequestUri(request); logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified); } return lastModified; } catch (Exception ex) { // Ignore -> will reappear on doService. logger.error("Exception thrown in getLastModified", ex); return -1; } } /** * Return the HandlerExecutionChain for this request. * Try all handler mappings in order. * @param request current HTTP request * @param cache whether to cache the HandlerExecutionChain in a request attribute * @return the HandlerExceutionChain, or <code>null</code> if no handler could be found */ protected HandlerExecutionChain getHandler(HttpServletRequest request, boolean cache) throws Exception { HandlerExecutionChain handler = (HandlerExecutionChain) request.getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE); if (handler != null) { if (!cache) { request.removeAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE); } return handler; } handler = this.handlerMappings.getHandler(request, this.getServletName()); if (handler != null) { if (cache) { request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE, handler); } return handler; } // Iterator it = this.handlerMappings.iterator(); // while (it.hasNext()) { // HandlerMapping hm = (HandlerMapping) it.next(); // if (logger.isTraceEnabled()) { // logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + // getServletName() + "'"); // } // handler = hm.getHandler(request); // if (handler != null) { // if (cache) { // request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE, handler); // } // return handler; // } // } return null; } /** * Return the HandlerAdapter for this handler object. * @param handler the handler object to find an adapter for * @throws ServletException if no HandlerAdapter can be found for the handler. * This is a fatal error. */ protected HandlerAdapter getHandlerAdapter(HandlerMeta handler) throws ServletException { // Iterator it = this.handlerAdapters.iterator(); // while (it.hasNext()) { // HandlerAdapter ha = (HandlerAdapter) it.next(); // // if (ha.supports(handler)) { // return ha; // } // } if(this.annotationMethodHandlerAdapter.supports(handler)) return this.annotationMethodHandlerAdapter; else if(this.simpleControllerHandlerAdapter.supports(handler)) return this.simpleControllerHandlerAdapter; else if(this.httpRequestHandlerAdapter.supports(handler)) return httpRequestHandlerAdapter; throw new ServletException("No adapter for handler [" + handler.getHandlerName() + "]: Does your handler implement a supported interface like Controller?"); } // /** // * Process this request, publishing an event regardless of the outcome. // * <p>The actual event handling is performed by the abstract // * {@link #doService} template method. // */ // protected final void processRequest(HttpServletRequest request, HttpServletResponse response) // throws ServletException, IOException { // // long startTime = System.currentTimeMillis(); // Throwable failureCause = null; // // try { // doService(request, response); // } // catch (ServletException ex) { // failureCause = ex; // throw ex; // } // catch (IOException ex) { // failureCause = ex; // throw ex; // } // catch (Throwable ex) { // failureCause = ex; // throw new NestedServletException("Request processing failed", ex); // } // // finally { // if (failureCause != null) { //// this.logger.debug("Could not complete request", failureCause); // } // else { // this.logger.debug("Successfully completed request"); // } //// if (this.publishEvents) { //// // Whether or not we succeeded, publish an event. //// long processingTime = System.currentTimeMillis() - startTime; //// this.webApplicationContext.publishEvent( //// new ServletRequestHandledEvent(this, //// request.getRequestURI(), request.getRemoteAddr(), //// request.getMethod(), getServletConfig().getServletName(), //// WebUtils.getSessionId(request), getUsernameForRequest(request), //// processingTime, failureCause)); //// } // } // } /** * No handler found -> set appropriate HTTP response status. * @param request current HTTP request * @param response current HTTP response * @throws Exception if preparing the response failed */ protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception { // if (pageNotFoundLogger.isWarnEnabled()) { String requestUri = new UrlPathHelper().getRequestUri(request); pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + requestUri + "] in DispatcherServlet with name '" + getServletName() + "'"); } response.sendError(HttpServletResponse.SC_NOT_FOUND); } private String contextAttribute = "contextConfigLocation"; private boolean publishContext; private boolean cleanupAfterInclude; /** ThemeResolver used by this servlet */ private ThemeResolver themeResolver; private String getContextAttributeName() { return contextAttribute; } /** * Retrieve a <code>WebApplicationContext</code> from the <code>ServletContext</code> * attribute with the {@link #setContextAttribute configured name}. The * <code>WebApplicationContext</code> must have already been loaded and stored in the * <code>ServletContext</code> before this servlet gets initialized (or invoked). * <p>Subclasses may override this method to provide a different * <code>WebApplicationContext</code> retrieval strategy. * @return the WebApplicationContext for this servlet, or <code>null</code> if not found * @see #getContextAttribute() */ protected WebApplicationContext findWebApplicationContext() { String attrName = getContextAttributeName(); if (attrName == null) { return null; } WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName); // if (wac == null) { // throw new IllegalStateException("No WebApplicationContext found: initializer not registered?"); // } return wac; } /** * Overridden method of {@link HttpServletBean}, invoked after any bean properties * have been set. Creates this servlet's WebApplicationContext. * @throws Exception */ protected final void initServletBean(ServletConfig config) throws Exception { getServletContext().log("Initializing Bboss MVC FrameworkServlet '" + getServletName() + "'"); // if (this.logger.isInfoEnabled()) { this.logger.debug("FrameworkServlet '" + getServletName() + "': initialization started"); // } long startTime = System.currentTimeMillis(); try { initWebApplicationContext( config); // initFrameworkServlet(); } // catch (ServletException ex) { // this.logger.error("Context initialization failed", ex); // throw ex; // } catch (Exception ex) { this.logger.error("Context initialization failed", ex); throw ex; } // if (this.logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; this.logger.debug("FrameworkServlet '" + getServletName() + "': initialization completed in " + elapsedTime + " ms"); // } } protected final void publishWebService(ServletConfig config) { String wsloadclass = "org.frameworkset.spi.remote.webservice.WSLoader"; Method publishAllWebService = null; try { Class clazz = Class.forName(wsloadclass); publishAllWebService = clazz.getMethod("publishAllWebService", ClassLoader.class,ServletConfig.class); // WSLoader.publishAllWebService(this.getClass().getClassLoader(),config); } catch (Throwable e) { logger.debug(" Not found "+wsloadclass + " or "+e.getMessage()+" in classpath,Ignore publish mvc webservices."); } try { if(publishAllWebService != null) { logger.debug("Publish MVC webservice start."); publishAllWebService.invoke(null, this.getClass().getClassLoader(),config); logger.debug("Publish MVC webservice finished."); } } catch (Exception e) { logger.debug("Publish mvc webservices failed:",e); } } /** * Initialize and publish the WebApplicationContext for this servlet. * <p>Delegates to {@link #createWebApplicationContext} for actual creation * of the context. Can be overridden in subclasses. * @return the WebApplicationContext instance * @throws BeansException if the context couldn't be initialized * @see #setContextClass * @see #setContextConfigLocation */ protected WebApplicationContext initWebApplicationContext(ServletConfig config) { WebApplicationContext wac = findWebApplicationContext(); if (wac == null) { // // No fixed context defined for this servlet - create a local one. // WebApplicationContext parent = // WebApplicationContextUtils.getWebApplicationContext(getServletContext()); wac = createWebApplicationContext( config); } // if (!this.refreshEventReceived) { // // Apparently not a ConfigurableApplicationContext with refresh support: // // triggering initial onRefresh manually here. // onRefresh(wac); // } if (this.publishContext) { // Publish the context as a servlet context attribute. String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); if (this.logger.isDebugEnabled()) { this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() + "' as ServletContext attribute with name [" + attrName + "]"); } } return wac; } private LifeCycleProcessorExecutor lifeCycleProcessorExecutor; private void startLifeCycleProcessor() { if(lifeCycleProcessorExecutor != null) { lifeCycleProcessorExecutor.startProcessor(); } } private void stopLifeCycleProcessor() { if(lifeCycleProcessorExecutor != null) { lifeCycleProcessorExecutor.stopProcessor(); } } /** * Prefix for the ServletContext attribute for the WebApplicationContext. * The completion is the servlet name. */ public static final String SERVLET_CONTEXT_PREFIX = DispatchServlet.class.getName() + ".CONTEXT."; /** * Return the ServletContext attribute name for this servlet's WebApplicationContext. * <p>The default implementation returns * <code>SERVLET_CONTEXT_PREFIX + servlet name</code>. * @see #SERVLET_CONTEXT_PREFIX * @see #getServletName */ public String getServletContextAttributeName() { return SERVLET_CONTEXT_PREFIX + getServletName(); } /** * Instantiate the WebApplicationContext for this servlet, either a default * * or a {@link #setContextClass custom context class}, if set. * <p>This implementation expects custom contexts to implement the * interface. Can be overridden in subclasses. * <p>Do not forget to register this servlet instance as application listener on the * created context (for triggering its {@link #onRefresh callback}, and to call * before returning the context instance. * @param parent the parent ApplicationContext to use, or <code>null</code> if none * @return the WebApplicationContext for this servlet * @throws BeansException if the context couldn't be initialized */ protected WebApplicationContext createWebApplicationContext(ServletConfig config) { String contextConfigLocation = config.getInitParameter("contextConfigLocation"); //start event webApplicationContext = WebApplicationContext.getWebApplicationContext(config.getServletContext(),contextConfigLocation); return webApplicationContext; } //-------------------begin private static String getRequestUri(HttpServletRequest request) { String uri = (String) request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE); if (uri == null) { uri = request.getRequestURI(); } return uri; } /** * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch} * for the actual dispatching. */ @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : ""; logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]"); } // Keep a snapshot of the request attributes in case of an include, // to be able to restore the original attributes after the include. Map<String, Object> attributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap<String, Object>(); Enumeration<?> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith("org.frameworkset.web.servlet")) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } // Make framework objects available to handlers and view objects. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); try { DataFormatUtil.initDateformatThreadLocal(); doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { DataFormatUtil.releaseDateformatThreadLocal(); // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } } } /** * Process the actual dispatching to the handler. * <p>The handler will be obtained by applying the servlet's HandlerMappings in order. * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters * to find the first that supports the handler class. * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers * themselves to decide which methods are acceptable. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure */ protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { /**yinbiaoping*/ HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; PageContext pageContext = RequestContextHolder.getPageContext(); try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. mappedHandler = getHandler(processedRequest,false); if (mappedHandler == null || mappedHandler.getHandler() == null || mappedHandler.getHandler().getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } mappedHandler.addInterceptors(this.gloabelHandlerInterceptors); if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. mv = ha.handle(processedRequest, response,pageContext, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } } private void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, Exception ex) throws Exception { if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, ex); } throw ex; } private void triggerAfterCompletionWithError(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, Error error) throws Exception { ServletException ex = new NestedServletException("Handler processing failed", error); if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, ex); } throw ex; } /** * Do we need view name translation? */ private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception { if (mv != null && !mv.hasView()) { mv.setViewName(getDefaultViewName(request)); } } /** * Handle the result of handler selection and handler invocation, which is * either a ModelAndView or an Exception to be resolved to a ModelAndView. */ private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception { boolean errorView = false; if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); HandlerMeta handlerMeta = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handlerMeta,exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isDebugEnabled()) { logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + "': assuming HandlerAdapter completed request handling"); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } /**yinbiaoping */ if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, null); } } // /** // * Build a LocaleContext for the given request, exposing the request's primary locale as current locale. // * <p>The default implementation uses the dispatcher's LocaleResolver to obtain the current locale, // * which might change during a request. // * @param request current HTTP request // * @return the corresponding LocaleContext // */ // // protected LocaleContext buildLocaleContext(final HttpServletRequest request) { // if (this.localeResolver instanceof LocaleContextResolver) { // return ((LocaleContextResolver) this.localeResolver).resolveLocaleContext(request); // } // else { // return new LocaleContext() { // @Override // public Locale getLocale() { // return localeResolver.resolveLocale(request); // } // }; // } // } //-------------------end // /** // * Exposes the DispatcherServlet-specific request attributes and // * delegates to {@link #doDispatch} for the actual dispatching. // */ // protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { // if (logger.isDebugEnabled()) { // String requestUri = new UrlPathHelper().getRequestUri(request); // logger.debug("DispatcherServlet with name '" + getServletName() + // "' processing request for [" + requestUri + "]"); // } // // // Keep a snapshot of the request attributes in case of an include, // // to be able to restore the original attributes after the include. // Map attributesSnapshot = null; // if (WebUtils.isIncludeRequest(request)) { // logger.debug("Taking snapshot of request attributes before include"); // attributesSnapshot = new HashMap(); // Enumeration attrNames = request.getAttributeNames(); // while (attrNames.hasMoreElements()) { // String attrName = (String) attrNames.nextElement(); // if (this.cleanupAfterInclude || attrName.startsWith("org.frameworkset.web.servlet")) { // attributesSnapshot.put(attrName, request.getAttribute(attrName)); // } // } // } // // // Make framework objects available to handlers and view objects. // request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); // request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); // request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); // request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); // // try { // DataFormatUtil.initDateformatThreadLocal(); // doDispatch(request, response); // } // finally { // DataFormatUtil.releaseDateformatThreadLocal(); // // Restore the original attribute snapshot, in case of an include. // if (attributesSnapshot != null) { // restoreAttributesAfterInclude(request, attributesSnapshot); // } // } // } /** * Restore the request attributes after an include. * @param request current HTTP request * @param attributesSnapshot the snapshot of the request attributes * before the include */ @SuppressWarnings("unchecked") private void restoreAttributesAfterInclude(HttpServletRequest request, Map<?,?> attributesSnapshot) { // Need to copy into separate Collection here, to avoid side effects // on the Enumeration when removing attributes. Set<String> attrsToCheck = new HashSet<String>(); Enumeration<?> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith("org.frameworkset.web.servlet")) { attrsToCheck.add(attrName); } } // Add attributes that may have been removed attrsToCheck.addAll((Set<String>) attributesSnapshot.keySet()); // Iterate over the attributes to check, restoring the original value // or removing the attribute, respectively, if appropriate. for (String attrName : attrsToCheck) { Object attrValue = attributesSnapshot.get(attrName); if (attrValue == null){ request.removeAttribute(attrName); } else if (attrValue != request.getAttribute(attrName)) { request.setAttribute(attrName, attrValue); } } } /** * Return this servlet's ThemeSource, if any; else return <code>null</code>. * <p>Default is to return the WebApplicationContext as ThemeSource, * provided that it implements the ThemeSource interface. * @return the ThemeSource, if any * @see #getWebApplicationContext() */ public final ThemeSource getThemeSource() { if (getWebApplicationContext() instanceof ThemeSource) { return (ThemeSource) getWebApplicationContext(); } else { return null; } } /** * 设置语言环境 * @param request */ public static void setLocaleContext(final HttpServletRequest request) { LocaleContextHolder.setLocaleContext(buildLocaleContext(request), threadContextInheritable); } /** * Process the actual dispatching to the handler. * <p>The handler will be obtained by applying the servlet's HandlerMappings in order. * The HandlerAdapter will be obtained by querying the servlet's installed * HandlerAdapters to find the first that supports the handler class. * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or * handlers themselves to decide which methods are acceptable. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure */ /**protected void doDispatch1(HttpServletRequest request, HttpServletResponse response) throws Exception { request = new RequestMethodHttpServletRequest(request); HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; int interceptorIndex = -1; // Expose current LocaleResolver and request as LocaleContext. LocaleContext previousLocaleContext = null; // Expose current RequestAttributes to current thread. RequestAttributes previousRequestAttributes = null; ServletRequestAttributes requestAttributes = null; if (logger.isTraceEnabled()) { logger.trace("Bound request context to thread: " + request); } PageContext pageContext = null; JspFactory fac= null; try { previousLocaleContext = LocaleContextHolder.getLocaleContext(); // LocaleContextHolder.setLocaleContext(buildLocaleContext(request), this.threadContextInheritable); setLocaleContext( request); // Expose current RequestAttributes to current thread. previousRequestAttributes = RequestContextHolder.getRequestAttributes(); fac=JspFactory.getDefaultFactory(); pageContext=fac.getPageContext(this, request,response, null, false, JspWriter.DEFAULT_BUFFER <= 0?8192:JspWriter.DEFAULT_BUFFER, true); requestAttributes = new ServletRequestAttributes(request, response,pageContext); RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable); ModelAndView mv = null; boolean errorView = false; try { processedRequest = checkMultipart(request); // Determine handler for the current request. mappedHandler = getHandler(processedRequest, false); if (mappedHandler == null || mappedHandler.getHandler() == null || mappedHandler.getHandler().getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Apply preHandle methods of registered interceptors. mappedHandler.addInterceptors(this.gloabelHandlerInterceptors); HandlerInterceptor[] interceptors = mappedHandler.getInterceptors(); if (interceptors != null) { for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) { triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null); return; } interceptorIndex = i; } } // Actually invoke the handler. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // if(this.messageConverters != null && messageConverters.length > 0) // { // try // { // request.setAttribute(messageConverters_KEY, this.messageConverters); // mv = ha.handle(processedRequest,response, pageContext,mappedHandler.getHandler()); // } // finally // { // request.removeAttribute(messageConverters_KEY); // } // // } // else { mv = ha.handle(processedRequest,response, pageContext,mappedHandler.getHandler()); } // Do we need view name translation? if (mv != null && !mv.hasView()) { mv.setViewName(getDefaultViewName(request)); } // Apply postHandle methods of registered interceptors. if (interceptors != null) { for (int i = interceptors.length - 1; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv); } } } catch (ModelAndViewDefiningException ex) { logger.debug("ModelAndViewDefiningException encountered", ex); mv = ex.getModelAndView(); } catch (Exception ex) { HandlerMeta handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(processedRequest, response, handler, ex); errorView = (mv != null); } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { render(mv, processedRequest, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isDebugEnabled()) { logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + "': assuming HandlerAdapter completed request handling"); } } // Trigger after-completion for successful outcome. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null); } catch (Exception ex) { // Trigger after-completion for thrown exception. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex); throw ex; } catch (Error err) { ServletException ex = new NestedServletException("Handler processing failed", err); // Trigger after-completion for thrown exception. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex); throw ex; } catch (Throwable err) { ServletException ex = new NestedServletException("Handler processing failed", err); // Trigger after-completion for thrown exception. triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex); throw ex; } finally { // Clean up any resources used by a multipart request. try { if (processedRequest != request) { cleanupMultipart(processedRequest); } } catch (Exception e) { } // Reset thread-bound context. RequestContextHolder.setRequestAttributes(previousRequestAttributes, this.threadContextInheritable); LocaleContextHolder.setLocaleContext(previousLocaleContext, this.threadContextInheritable); // Clear request attributes. requestAttributes.requestCompleted(); if (logger.isTraceEnabled()) { logger.trace("Cleared thread-bound request context: " + request); } if(fac != null && pageContext != null) { fac.releasePageContext(pageContext); } } }*/ /** * Clean up any resources used by the given multipart request (if any). * @param request current HTTP request * @see MultipartResolver#cleanupMultipart */ protected void cleanupMultipart(HttpServletRequest request) { if (request instanceof MultipartHttpServletRequest) { this.multipartResolver.cleanupMultipart((MultipartHttpServletRequest) request); } } /** * @FIXME * Determine an error ModelAndView via the registered HandlerExceptionResolvers. * @param request current HTTP request * @param response current HTTP response * @param handler the executed handler, or <code>null</code> if none chosen at the time of * the exception (for example, if multipart resolution failed) * @param ex the exception that got thrown during handler execution * @return a corresponding ModelAndView to forward to * @throws Exception if no error ModelAndView found */ protected ModelAndView processHandlerException( HttpServletRequest request, HttpServletResponse response, HandlerMeta handlerMeta, Exception ex) throws Exception { // Check registerer HandlerExceptionResolvers... ModelAndView exMv = null; if(handlerExceptionResolvers != null) { for (Iterator it = this.handlerExceptionResolvers.iterator(); exMv == null && it.hasNext();) { HandlerExceptionResolver resolver = (HandlerExceptionResolver) it.next(); exMv = resolver.resolveException(request, response, handlerMeta, ex); } } if (exMv != null) { try { if(exMv.getView() != null && exMv.getView() instanceof AbstractUrlBasedView) { // AbstractUrlBasedView view = (AbstractUrlBasedView) exMv.getView(); String url = view.getUrl(); if(UrlBasedViewResolver.isPathVariable(url)) { url = handlerMeta.getUrlPath(url,null,handlerMeta.getHandler(),request); view.setUrl(url); } } if(exMv != null && UrlBasedViewResolver.isPathVariable(exMv.getViewName())) { exMv.setViewName(handlerMeta.getUrlPath(exMv.getViewName(),null,handlerMeta.getHandler(),request)); } } catch(PathURLNotSetException ex1) { return HandlerUtils.handleNoSuchRequestHandlingMethod(ex1, request, response); } // if (logger.isDebugEnabled()) { logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex); } WebUtils.exposeErrorRequestAttributes(request, ex, getServletName()); return exMv; } // Send default responses for well-known exceptions, if possible. if (ex instanceof HttpRequestMethodNotSupportedException && !response.isCommitted()) { String[] supportedMethods = ((HttpRequestMethodNotSupportedException) ex).getSupportedMethods(); if (supportedMethods != null) { response.setHeader("Allow", StringUtil.arrayToDelimitedString(supportedMethods, ", ")); } response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, ex.getMessage()); return null; } throw ex; } /** * Translate the supplied request into a default view name. * @param request current HTTP servlet request * @return the view name (or <code>null</code> if no default found) * @throws Exception if view name translation failed */ protected String getDefaultViewName(HttpServletRequest request) throws Exception { return this.viewNameTranslator.getViewName(request); } /** * Trigger afterCompletion callbacks on the mapped HandlerInterceptors. * Will just invoke afterCompletion for all interceptors whose preHandle * invocation has successfully completed and returned true. * @param mappedHandler the mapped HandlerExecutionChain * @param interceptorIndex index of last interceptor that successfully completed * @param ex Exception thrown on handler execution, or <code>null</code> if none * @see HandlerInterceptor#afterCompletion */ private void triggerAfterCompletion( HandlerExecutionChain mappedHandler, int interceptorIndex, HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception { // Apply afterCompletion methods of registered interceptors. if (mappedHandler != null) { HandlerInterceptor[] interceptors = mappedHandler.getInterceptors(); if (interceptors != null) { for (int i = interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; try { interceptor.afterCompletion(request, response, mappedHandler.getHandler(), ex); } catch (Throwable ex2) { logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } } } } /** * Convert the request into a multipart request, and make multipart resolver available. * If no multipart resolver is set, simply use the existing request. * @param request current HTTP request * @return the processed request (multipart wrapper if necessary) * @see MultipartResolver#resolveMultipart */ protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException { if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) { if (request instanceof MultipartHttpServletRequest) { logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " + "this typically results from an additional MultipartFilter in web.xml"); } else { return this.multipartResolver.resolveMultipart(request); } } // If not returned before: return original request. return request; } /** * Return this servlet's WebApplicationContext. */ public final WebApplicationContext getWebApplicationContext() { return webApplicationContext; } /** * Render the given ModelAndView. This is the last stage in handling a request. * It may involve resolving the view by name. * @param mv the ModelAndView to render * @param request current HTTP servlet request * @param response current HTTP servlet response * @throws Exception if there's a problem rendering the view */ protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine locale for request and apply it to the response. // Locale locale = this.localeResolver.resolveLocale(request); Locale locale = RequestContextUtils.getRequestContextLocal(request); response.setLocale(locale); View view = null; if (mv.isReference()) { // We need to resolve the view name. view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + getServletName() + "'"); } } else { // No need to lookup: the ModelAndView object contains the actual View object. view = mv.getView(); if (view == null) { throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " + "View object in servlet with name '" + getServletName() + "'"); } } // Delegate to the View object for rendering. if (logger.isDebugEnabled()) { logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'"); } try { if(mv.hasErrors()) request.setAttribute(RequestContext.BIND_ERROR_MESSAGES_KEY, mv.getErrors()); view.render(mv.getModelInternal(), request, response); } finally { request.removeAttribute(RequestContext.BIND_ERROR_MESSAGES_KEY); } } /** * Resolve the given view name into a View object (to be rendered). * <p>Default implementations asks all ViewResolvers of this dispatcher. * Can be overridden for custom resolution strategies, potentially based * on specific model attributes or request parameters. * @param viewName the name of the view to resolve * @param model the model to be passed to the view * @param locale the current locale * @param request current HTTP servlet request * @return the View object, or <code>null</code> if none found * @throws Exception if the view cannot be resolved * (typically in case of problems creating an actual View object) * @see ViewResolver#resolveViewName */ protected View resolveViewName(String viewName, Map model, Locale locale, HttpServletRequest request) throws Exception { for (Iterator it = this.viewResolvers.iterator(); it.hasNext();) { ViewResolver viewResolver = (ViewResolver) it.next(); View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } return null; } protected void initMessagesources(ServletConfig config) { messagesources = config.getInitParameter("messagesources"); if(messagesources == null) { messagesources = DispatchServlet.getDefaultStrategies().getProperty("messageSource.basename","/WEB-INF/messages"); } useCodeAsDefaultMessage = config.getInitParameter("useCodeAsDefaultMessage"); if(useCodeAsDefaultMessage == null) { useCodeAsDefaultMessage = DispatchServlet.getDefaultStrategies().getProperty("messageSource.useCodeAsDefaultMessage","true"); } } protected void initWebsockets(ServletConfig config) { String WebSocketLoader = "org.frameworkset.web.socket.config.WebSocketLoader"; Method publishAllWebService = null; try { publishAllWebService = Class.forName(WebSocketLoader).getMethod("loadMvcWebSocketService", ClassLoader.class,HandlerMappingsTable.class,ServletConfig.class); // WSLoader.publishAllWebService(this.getClass().getClassLoader(),config); } catch (Exception e) { logger.debug(" Not found "+WebSocketLoader + " or "+e.getMessage()+" in classpath,Ignore publish WebSocket Services."); } try { if(publishAllWebService != null) { logger.debug("Publish WebSocket Services start."); publishAllWebService.invoke(null, this.getClass().getClassLoader(),this.handlerMappings,config); if(handlerMappings.getWebsocketLifecycleProcessor() != null) { this.lifeCycleProcessorExecutor = new LifeCycleProcessorExecutor(); this.lifeCycleProcessorExecutor.setLifecycleProcessor(handlerMappings.getWebsocketLifecycleProcessor()); } logger.debug("Publish WebSocket Services finished."); } } catch (Exception e) { logger.debug("Publish WebSocket Services failed:",e); } } private Map<String,String> parserIocLifeCycleEventListenerParams(String iocLifeCycleEventListenerParams) { Map<String,String> paramMap = new HashMap<String,String>(); if(iocLifeCycleEventListenerParams != null && iocLifeCycleEventListenerParams.trim().length() > 0) { String[] params = iocLifeCycleEventListenerParams.split("\\|"); for(String param :params) { String[] pv = param.split("="); paramMap.put(pv[0], pv[1]); } } return paramMap; } protected void initIocLifeCycleEventListeners(ServletConfig config) { iocLifeCycleEventListeners = config.getInitParameter("iocLifeCycleEventListeners"); if(StringUtil.isNotEmpty(iocLifeCycleEventListeners )) { iocLifeCycleEventListenerParams = config.getInitParameter("iocLifeCycleEventListenerParams"); Map<String,String> params = parserIocLifeCycleEventListenerParams(iocLifeCycleEventListenerParams); String[] iocLifeCycleEventListeners_ = iocLifeCycleEventListeners.split(","); this.iocLifeCycleEventListenerList = new ArrayList<IocLifeCycleEventListener>(); for(String iocLifeCycleEventListener:iocLifeCycleEventListeners_) { try { IocLifeCycleEventListener l = (IocLifeCycleEventListener)Class.forName(iocLifeCycleEventListener).newInstance(); if(params != null && params.size() > 0) l.init(params); iocLifeCycleEventListenerList.add(l); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /** * Initialize the strategy objects that this servlet uses. * <p>May be overridden in subclasses in order to initialize * further strategy objects. * @throws Exception */ protected void init_(ServletConfig config) throws Exception { // loadCustomJars(config); initMessagesources(config); this.initIocLifeCycleEventListeners( config); for(int i = 0; this.iocLifeCycleEventListenerList != null && i < this.iocLifeCycleEventListenerList.size(); i ++) { IocLifeCycleEventListener l = this.iocLifeCycleEventListenerList.get(i); try { l.beforestart(); } catch (Exception e) { logger.warn("before start WebApplicationContext:",e); } } try { this.initServletBean(config); publishWebService(config); // WebApplicationContext context = this.initWebApplicationContext( config); initMessageConverters(this.webApplicationContext); initMultipartResolver(this.webApplicationContext); initLocaleResolver(this.webApplicationContext); initThemeResolver(this.webApplicationContext); initHandlerMappings(this.webApplicationContext); initHandlerAdapters(this.webApplicationContext); initHandlerExceptionResolvers(this.webApplicationContext); initRequestToViewNameTranslator(this.webApplicationContext); initViewResolvers(this.webApplicationContext); initGloabelHandlerInterceptors(this.webApplicationContext); initWebsockets(config); startLifeCycleProcessor( ); } catch (Exception e1) { logger.warn("Init WebApplicationContext:",e1); } for(int i = 0; this.iocLifeCycleEventListenerList != null && i < this.iocLifeCycleEventListenerList.size(); i ++) { IocLifeCycleEventListener l = this.iocLifeCycleEventListenerList.get(i); try { l.afterstart(webApplicationContext); } catch (Exception e) { logger.warn("After start WebApplicationContext:",e); } } } private void initMessageConverters( WebApplicationContext webApplicationContext) { ProList<Pro> list = webApplicationContext.getListProperty("httpMessageConverters"); if(list != null && list.size() > 0) { messageConverters = new HttpMessageConverter[list.size()]; for(int i = 0; i < list.size(); i ++) { Pro t = list.get(i); try { this.messageConverters[i] = (HttpMessageConverter) t .getBean(); } catch (Exception e) { System.out.println("load messageConvert failed:" + t.getClazz()); logger.error("load messageConvert failed:" + t.getClazz(), e); } } } } // private void loadCustomJars(ServletConfig config) // { // String docbase = this.getServletContext().getRealPath(""); // String customJarsLocation = config.getInitParameter("customJarsLocation"); // logger.debug("load custom Jars from Location:\r\n" + customJarsLocation); // CustomClassLoader classLoader = (CustomClassLoader)getDefaultStrategy(null, CustomClassLoader.class); // classLoader.initClassLoader(this.getClass().getClassLoader()); // CustomJarsLauncher launcher = new CustomJarsLauncher(); // launcher.loadFromRepository(classLoader, docbase, customJarsLocation); // } /** * Initialize the ViewResolvers used by this class. * <p>If no ViewResolver beans are defined in the BeanFactory * for this namespace, we default to InternalResourceViewResolver. */ private void initViewResolvers(BaseApplicationContext context) { this.viewResolvers = null; // if (this.detectAllViewResolvers) { // // Find all ViewResolvers in the ApplicationContext, // // including ancestor contexts. // Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors( // context, ViewResolver.class, true, false); // if (!matchingBeans.isEmpty()) { // this.viewResolvers = new ArrayList(matchingBeans.values()); // // We keep ViewResolvers in sorted order. // Collections.sort(this.viewResolvers, new OrderComparator()); // } // } // else { try { Object vr = context.getBeanObject(VIEW_RESOLVER_BEAN_NAME); this.viewResolvers = Collections.singletonList(vr); } catch (Exception ex) { // Ignore, we'll add a default ViewResolver later. } } // Ensure we have at least one ViewResolver, by registering // a default ViewResolver if no other resolvers are found. if (this.viewResolvers == null) { this.viewResolvers = getDefaultStrategies(context, ViewResolver.class); if (logger.isDebugEnabled()) { logger.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default"); } } } /** * Initialize the RequestToViewNameTranslator used by this servlet instance. If no * implementation is configured then we default to DefaultRequestToViewNameTranslator. */ private void initRequestToViewNameTranslator(BaseApplicationContext context) { try { this.viewNameTranslator = (RequestToViewNameTranslator) context.getBeanObject( REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME); if (logger.isDebugEnabled()) { logger.debug("Using RequestToViewNameTranslator [" + this.viewNameTranslator + "]"); } } catch (Exception ex) { // We need to use the default. try { this.viewNameTranslator = (RequestToViewNameTranslator) getDefaultStrategy(context, RequestToViewNameTranslator.class); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } if (logger.isDebugEnabled()) { logger.debug("Unable to locate RequestToViewNameTranslator with name '" + REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME + "': using default [" + this.viewNameTranslator.getClass().getCanonicalName() + "]"); } } } /** * Initialize the HandlerExceptionResolver used by this class. * <p>If no bean is defined with the given name in the BeanFactory * for this namespace, we default to no exception resolver. */ private void initHandlerExceptionResolvers(BaseApplicationContext context) { this.handlerExceptionResolvers = null; // if (this.detectAllHandlerExceptionResolvers) { // // Find all HandlerExceptionResolvers in the ApplicationContext, // // including ancestor contexts. // Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors( // context, HandlerExceptionResolver.class, true, false); // if (!matchingBeans.isEmpty()) { // this.handlerExceptionResolvers = new ArrayList(matchingBeans.values()); // // We keep HandlerExceptionResolvers in sorted order. // Collections.sort(this.handlerExceptionResolvers, new OrderComparator()); // } // } // else { try { Object her = context.getBeanObject( HANDLER_EXCEPTION_RESOLVER_BEAN_NAME); this.handlerExceptionResolvers = Collections.singletonList(her); } catch (Exception ex) { // Ignore, no HandlerExceptionResolver is fine too. } } // Just for consistency, check for default HandlerExceptionResolvers... // There aren't any in usual scenarios. if (this.handlerExceptionResolvers == null) { this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default"); } } if(this.handlerExceptionResolvers != null && this.handlerExceptionResolvers.size() == 0) this.handlerExceptionResolvers = null; } private void initGloabelHandlerInterceptors(BaseApplicationContext context) { try { this.gloabelHandlerInterceptors = (List<HandlerInterceptor>)context. getBeanObject("org.frameworkset.web.servlet.gloabel.HandlerInterceptors"); } catch (Exception e) { this.gloabelHandlerInterceptors = new ArrayList<HandlerInterceptor>(); } } /** * Initialize the HandlerAdapters used by this class. * <p>If no HandlerAdapter beans are defined in the BeanFactory * for this namespace, we default to SimpleControllerHandlerAdapter. */ private void initHandlerAdapters(BaseApplicationContext context) { // this.handlerAdapters = null; // //// if (this.detectAllHandlerAdapters) { //// // Find all HandlerAdapters in the ApplicationContext, //// // including ancestor contexts. //// Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors( //// context, HandlerAdapter.class, true, false); //// if (!matchingBeans.isEmpty()) { //// this.handlerAdapters = new ArrayList(matchingBeans.values()); //// // We keep HandlerAdapters in sorted order. //// Collections.sort(this.handlerAdapters, new OrderComparator()); //// } //// } //// else //// { //// try { //// Object ha = context.getBeanObject(HANDLER_ADAPTER_BEAN_NAME); //// List temp = Collections.singletonList(ha); //// this.handlerAdapters = (List<HandlerAdapter>)temp; //// } //// catch (Exception ex) { //// // Ignore, we'll add a default HandlerAdapter later. //// } //// } // // // Ensure we have at least some HandlerAdapters, by registering // // default HandlerAdapters if no other adapters are found. // if (this.handlerAdapters == null) { // this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class); // if (logger.isDebugEnabled()) { // logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default"); // } // } // if(handlerAdapters != null) // { // for(HandlerAdapter adapter :handlerAdapters) // { // if(!adapter.containMessageConverters()) // adapter.setMessageConverters(messageConverters); // } // } this.annotationMethodHandlerAdapter = createDefaultStrategy(context, AnnotationMethodHandlerAdapter.class); if(!annotationMethodHandlerAdapter.containMessageConverters()) annotationMethodHandlerAdapter.setMessageConverters(messageConverters); this.simpleControllerHandlerAdapter = createDefaultStrategy(context, SimpleControllerHandlerAdapter.class); if(!simpleControllerHandlerAdapter.containMessageConverters()) simpleControllerHandlerAdapter.setMessageConverters(messageConverters); this.httpRequestHandlerAdapter = createDefaultStrategy(context, HttpRequestHandlerAdapter.class); if(!httpRequestHandlerAdapter.containMessageConverters()) httpRequestHandlerAdapter.setMessageConverters(messageConverters); } /** * Initialize the HandlerMappings used by this class. * <p>If no HandlerMapping beans are defined in the BeanFactory * for this namespace, we default to BeanNameUrlHandlerMapping. */ private void initHandlerMappings(BaseApplicationContext context) { this.handlerMappings = null; // this.handlerMappings = (HandlerMappingsTable)context.getBeanObject(HANDLER_MAPPING_BEAN_NAME); // if (this.handlerMappings == null) { // List handlerMappings_ = getDefaultStrategies(context, HandlerMapping.class); // handlerMappings = (HandlerMappingsTable) context.createBean(HandlerMappingsTable.class); // initHandlerMappings(handlerMappings_); // handlerMappings.setHandlerMappings(handlerMappings_); // if (logger.isDebugEnabled()) { // logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default"); // } // } handlerMappings = (HandlerMappingsTable) context.createBean(HandlerMappingsTable.class); DefaultAnnotationHandlerMapping handlerMapping = (DefaultAnnotationHandlerMapping) context.createBean(DefaultAnnotationHandlerMapping.class); // @SuppressWarnings("unchecked") // HandlerUrlMappingRegisterTable<String,HandlerMeta> registTable = (HandlerUrlMappingRegisterTable<String,HandlerMeta>) context.createBean(HandlerUrlMappingRegisterTable.class); // handlerMapping.setHandlerMap(registTable); _initHandlerMappings(handlerMapping); handlerMappings.setHandlerMapping(handlerMapping); //// Map matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors( //// context, HandlerMapping.class, true, false); //// if (!matchingBeans.isEmpty()) { //// this.handlerMappings = new ArrayList(matchingBeans.values()); //// // We keep HandlerMappings in sorted order. //// Collections.sort(this.handlerMappings, new OrderComparator()); //// } // //// else // { // try { // Object hm = context.getBeanObject(HANDLER_MAPPING_BEAN_NAME); // this.handlerMappings = Collections.singletonList(hm); // } // catch (Exception ex) { // // Ignore, we'll add a default HandlerMapping later. // } // } // // // Ensure we have at least one HandlerMapping, by registering // // a default HandlerMapping if no other mappings are found. // if (this.handlerMappings == null) { // this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); // initHandlerMappings(); // if (logger.isDebugEnabled()) { // logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default"); // } // } } // private void initHandlerMappings(List handlerMappings_) // { // if(handlerMappings_ != null && handlerMappings_.size() > 0) // { // for(int i = 0; i < handlerMappings_.size(); i ++) // { // Object handler = handlerMappings_.get(i); // if(handler instanceof AbstractUrlHandlerMapping) // { // ((AbstractUrlHandlerMapping)handler).setAlwaysUseFullPath(true); // } // } // } // } private void _initHandlerMappings(Object handler) { if(handler instanceof AbstractUrlHandlerMapping) { ((AbstractUrlHandlerMapping)handler).setAlwaysUseFullPath(true); } } /** * Initialize the ThemeResolver used by this class. * <p>If no bean is defined with the given name in the BeanFactory * for this namespace, we default to a FixedThemeResolver. */ private void initThemeResolver(BaseApplicationContext context) { try { this.themeResolver = (ThemeResolver) context.getBeanObject(THEME_RESOLVER_BEAN_NAME); if (logger.isDebugEnabled()) { logger.debug("Using ThemeResolver [" + this.themeResolver + "]"); } } catch (Exception ex) { // We need to use the default. try { this.themeResolver = (ThemeResolver) getDefaultStrategy(context, ThemeResolver.class); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } if (logger.isDebugEnabled()) { logger.debug("Unable to locate ThemeResolver with name '" + THEME_RESOLVER_BEAN_NAME + "': using default [" + this.themeResolver + "]"); } } } public static LocaleResolver getLocaleResolver(WebApplicationContext context) { if(localeResolver != null) { return localeResolver; } else { initLocaleResolver(context); return localeResolver; } } public static LocaleResolver getLocaleResolver() { if(localeResolver != null) { return localeResolver; } else { initLocaleResolver(DispatchServlet.webApplicationContext); return localeResolver; } } /** * Initialize the LocaleResolver used by this class. * <p>If no bean is defined with the given name in the BeanFactory * for this namespace, we default to AcceptHeaderLocaleResolver. */ public synchronized static void initLocaleResolver(WebApplicationContext context) { if(localeResolver == null) { try { localeResolver = (LocaleResolver) context.getBeanObject(LOCALE_RESOLVER_BEAN_NAME); if (logger.isDebugEnabled()) { logger.debug("Using LocaleResolver [" + localeResolver + "]"); } } catch (Exception ex) { // We need to use the default. try { localeResolver = (LocaleResolver) getDefaultStrategy(context, LocaleResolver.class); } catch (Exception e) { localeResolver = new DefaultLocaleResolver(); e.printStackTrace(); } if (logger.isDebugEnabled()) { logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME + "': using default [" + localeResolver + "]"); } } } } /** * Return the default strategy object for the given strategy interface. * <p>The default implementation delegates to {@link #getDefaultStrategies}, * expecting a single object in the list. * @param context the current WebApplicationContext * @param strategyInterface the strategy interface * @return the corresponding strategy object * @throws BeansException if initialization failed * @see #getDefaultStrategies */ public static Object getDefaultStrategy(BaseApplicationContext context, Class strategyInterface) throws BeanInstanceException { List strategies = getDefaultStrategies(context, strategyInterface); if (strategies.size() <= 0) { throw new BeanInstanceException( "DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]"); } return strategies.get(0); } /** * Create a List of default strategy objects for the given strategy interface. * <p>The default implementation uses the "DispatcherServlet.properties" file * (in the same package as the DispatcherServlet class) to determine the class names. * It instantiates the strategy objects through the context's BeanFactory. * @param context the current WebApplicationContext * @param strategyInterface the strategy interface * @return the List of corresponding strategy objects * @throws BeansException if initialization failed */ public static List getDefaultStrategies(BaseApplicationContext context, Class strategyInterface) throws BeanInstanceException { String key = strategyInterface.getName(); List strategies = null; String value = defaultStrategies.getProperty(key); if (value != null) { String[] classNames = StringUtil.commaDelimitedListToStringArray(value); strategies = new ArrayList(classNames.length); for (int i = 0; i < classNames.length; i++) { String className = classNames[i]; // if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15 && className.indexOf("Annotation") != -1) { // // Skip Java 5 specific strategies when running on JDK 1.4... // continue; // } try { Class clazz = ClassUtils.forName(className, DispatchServlet.class.getClassLoader()); Object strategy = createDefaultStrategy(context, clazz); strategies.add(strategy); } catch (ClassNotFoundException ex) { throw new BeanInstanceException( "Could not find DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", ex); } catch (LinkageError err) { throw new BeanInstanceException( "Error loading DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]: problem with class file or dependent class", err); } } } else { strategies = Collections.EMPTY_LIST; } return strategies; } /** * Create a default strategy. * <p>The default implementation uses * @param context the current WebApplicationContext * @param clazz the strategy implementation class to instantiate * @throws BeansException if initialization failed * @return the fully configured strategy instance */ protected static <T> T createDefaultStrategy(BaseApplicationContext context, Class<T> clazz) throws BeanInstanceException { if(context != null) return (T)context.createBean(clazz); else { try { return clazz.newInstance(); } catch (InstantiationException e) { throw new BeanInstanceException(e); } catch (IllegalAccessException e) { throw new BeanInstanceException(e); } catch (Exception e) { throw new BeanInstanceException(e); } } } /** * Initialize the MultipartResolver used by this class. * <p>If no bean is defined with the given name in the BeanFactory * for this namespace, no multipart handling is provided. */ private void initMultipartResolver(WebApplicationContext context) { try { this.multipartResolver = (MultipartResolver) context.getBeanObject(MULTIPART_RESOLVER_BEAN_NAME); if (logger.isDebugEnabled()) { logger.debug("Using MultipartResolver [" + this.multipartResolver + "]"); } } catch (Exception ex) { // Default is no multipart resolver. this.multipartResolver = null; if (logger.isDebugEnabled()) { logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME + "': no multipart request handling provided"); } } } @Override public void init(ServletConfig config) throws ServletException { super.init(config); try { init_( config); } catch(ServletException e) { throw e; } catch (Exception e) { throw new NestedServletException("",e); } } // // /** // * Delegate GET requests to processRequest/doService. // * <p>Will also be invoked by HttpServlet's default implementation of <code>doHead</code>, // * with a <code>NoBodyResponse</code> that just captures the content length. // * @see #doService // * @see #doHead // */ // protected final void doGet(HttpServletRequest request, HttpServletResponse response) // throws ServletException, IOException { // // processRequest(request, response); // } // /** // * Delegate POST requests to {@link #processRequest}. // * @see #doService // */ // protected final void doPost(HttpServletRequest request, HttpServletResponse response) // throws ServletException, IOException { // // processRequest(request, response); // } // /** // * Delegate PUT requests to {@link #processRequest}. // * @see #doService // */ // protected final void doPut(HttpServletRequest request, HttpServletResponse response) // throws ServletException, IOException { // // processRequest(request, response); // } // /** // * Delegate DELETE requests to {@link #processRequest}. // * @see #doService // */ // protected final void doDelete(HttpServletRequest request, HttpServletResponse response) // throws ServletException, IOException { // // processRequest(request, response); // } // /** // * Delegate OPTIONS requests to {@link #processRequest}, if desired. // * <p>Applies HttpServlet's standard OPTIONS processing first. // * @see #doService // */ // protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // super.doOptions(request, response); // if (this.dispatchOptionsRequest) { // processRequest(request, response); // } // } // /** // * Delegate TRACE requests to {@link #processRequest}, if desired. // * <p>Applies HttpServlet's standard TRACE processing first. // * @see #doService // */ // protected void doTrace(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // super.doTrace(request, response); // if (this.dispatchTraceRequest) { // processRequest(request, response); // } // } // /** * Determine the username for the given request. * <p>The default implementation takes the name of the UserPrincipal, if any. * Can be overridden in subclasses. * @param request current HTTP request * @return the username, or <code>null</code> if none found * @see javax.servlet.http.HttpServletRequest#getUserPrincipal() */ protected String getUsernameForRequest(HttpServletRequest request) { Principal userPrincipal = request.getUserPrincipal(); return (userPrincipal != null ? userPrincipal.getName() : null); } public static String getUseCodeAsDefaultMessage() { return useCodeAsDefaultMessage; } @Override public void destroy() { // TODO Auto-generated method stub super.destroy(); // if(this.handlerAdapters != null) // { // for(int i = 0 ; i < this.handlerAdapters.size() ;i ++) // { // HandlerAdapter ha = this.handlerAdapters.get(i); // ha.destroy(); // } // this.handlerAdapters.clear(); // this.handlerAdapters = null; // } if(annotationMethodHandlerAdapter != null) this.annotationMethodHandlerAdapter.destroy(); if(simpleControllerHandlerAdapter != null) this.simpleControllerHandlerAdapter.destroy(); if(httpRequestHandlerAdapter != null) this.httpRequestHandlerAdapter.destroy(); stopLifeCycleProcessor(); if(webApplicationContext != null) this.webApplicationContext.destroy(); } }