Save This Page
Home » struts-2.0.11.2-src » org.apache » struts2 » dispatcher » [javadoc | source]
    1   /*
    2    * $Id: Dispatcher.java 566474 2007-08-16 02:55:44Z jholmes $
    3    *
    4    * Licensed to the Apache Software Foundation (ASF) under one
    5    * or more contributor license agreements.  See the NOTICE file
    6    * distributed with this work for additional information
    7    * regarding copyright ownership.  The ASF licenses this file
    8    * to you under the Apache License, Version 2.0 (the
    9    * "License"); you may not use this file except in compliance
   10    * with the License.  You may obtain a copy of the License at
   11    *
   12    *  http://www.apache.org/licenses/LICENSE-2.0
   13    *
   14    * Unless required by applicable law or agreed to in writing,
   15    * software distributed under the License is distributed on an
   16    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   17    * KIND, either express or implied.  See the License for the
   18    * specific language governing permissions and limitations
   19    * under the License.
   20    */
   21   package org.apache.struts2.dispatcher;
   22   
   23   import java.io.File;
   24   import java.io.IOException;
   25   import java.net.MalformedURLException;
   26   import java.net.URL;
   27   import java.util.ArrayList;
   28   import java.util.HashMap;
   29   import java.util.List;
   30   import java.util.Locale;
   31   import java.util.Map;
   32   
   33   import javax.servlet.ServletContext;
   34   import javax.servlet.ServletException;
   35   import javax.servlet.http.HttpServletRequest;
   36   import javax.servlet.http.HttpServletResponse;
   37   
   38   import org.apache.commons.logging.Log;
   39   import org.apache.commons.logging.LogFactory;
   40   import org.apache.struts2.ServletActionContext;
   41   import org.apache.struts2.StrutsConstants;
   42   import org.apache.struts2.StrutsStatics;
   43   import org.apache.struts2.config;
   44   import org.apache.struts2.config.ClasspathConfigurationProvider.ClasspathPageLocator;
   45   import org.apache.struts2.config.ClasspathConfigurationProvider.PageLocator;
   46   import org.apache.struts2.dispatcher.mapper.ActionMapping;
   47   import org.apache.struts2.dispatcher.multipart.MultiPartRequest;
   48   import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
   49   import org.apache.struts2.util.AttributeMap;
   50   import org.apache.struts2.util.ClassLoaderUtils;
   51   import org.apache.struts2.util.ObjectFactoryDestroyable;
   52   import org.apache.struts2.views.freemarker.FreemarkerManager;
   53   
   54   import com.opensymphony.xwork2.util.FileManager;
   55   import com.opensymphony.xwork2;
   56   import com.opensymphony.xwork2.Result;
   57   import com.opensymphony.xwork2.config.Configuration;
   58   import com.opensymphony.xwork2.config.ConfigurationException;
   59   import com.opensymphony.xwork2.config.ConfigurationManager;
   60   import com.opensymphony.xwork2.config.ConfigurationProvider;
   61   import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
   62   import com.opensymphony.xwork2.inject.Container;
   63   import com.opensymphony.xwork2.inject.ContainerBuilder;
   64   import com.opensymphony.xwork2.inject.Inject;
   65   import com.opensymphony.xwork2.util.LocalizedTextUtil;
   66   import com.opensymphony.xwork2.util.ObjectTypeDeterminer;
   67   import com.opensymphony.xwork2.util.ObjectTypeDeterminerFactory;
   68   import com.opensymphony.xwork2.util.ValueStack;
   69   import com.opensymphony.xwork2.util.ValueStackFactory;
   70   import com.opensymphony.xwork2.util.location.Location;
   71   import com.opensymphony.xwork2.util.location.LocationUtils;
   72   import com.opensymphony.xwork2.util.location.LocatableProperties;
   73   import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
   74   
   75   import freemarker.template.Template;
   76   
   77   /**
   78    * A utility class the actual dispatcher delegates most of its tasks to. Each instance
   79    * of the primary dispatcher holds an instance of this dispatcher to be shared for
   80    * all requests.
   81    *
   82    * @see org.apache.struts2.dispatcher.FilterDispatcher
   83    * @see org.apache.struts2.portlet.dispatcher.Jsr168Dispatcher
   84    */
   85   public class Dispatcher {
   86   
   87       /**
   88        * Provide a logging instance.
   89        */
   90       private static final Log LOG = LogFactory.getLog(Dispatcher.class);
   91   
   92       /**
   93        * Provide a thread local instance.
   94        */
   95       private static ThreadLocal<Dispatcher> instance = new ThreadLocal<Dispatcher>();
   96   
   97       /**
   98        * Store list of DispatcherListeners.
   99        */
  100       private static List<DispatcherListener> dispatcherListeners =
  101           new ArrayList<DispatcherListener>();
  102   
  103       /**
  104        * Store ConfigurationManager instance, set on init.
  105        */
  106       private ConfigurationManager configurationManager;
  107   
  108       /**
  109        * Store whether portlet support is active
  110        * (set to true by Jsr168Dispatcher).
  111        */
  112       private static boolean portletSupportActive;
  113   
  114       /**
  115        * Store state of  StrutsConstants.STRUTS_DEVMODE setting.
  116        */
  117       private static boolean devMode;
  118   
  119       /**
  120        * Store state of StrutsConstants.STRUTS_I18N_ENCODING setting.
  121        */
  122       private static String defaultEncoding;
  123   
  124       /**
  125        * Store state of StrutsConstants.STRUTS_LOCALE setting.
  126        */
  127       private static String defaultLocale;
  128   
  129       /**
  130        * Store state of StrutsConstants.STRUTS_MULTIPART_SAVEDIR setting.
  131        */
  132       private static String multipartSaveDir;
  133   
  134       /**
  135        * Provide list of default configuration files.
  136        */
  137       private static final String DEFAULT_CONFIGURATION_PATHS = "struts-default.xml,struts-plugin.xml,struts.xml";
  138   
  139       /**
  140        * Store state of STRUTS_DISPATCHER_PARAMETERSWORKAROUND.
  141        * <p/>
  142        * The workaround is for WebLogic.
  143        * We try to autodect WebLogic on Dispatcher init.
  144        * The workaround can also be enabled manually.
  145        */
  146       private boolean paramsWorkaroundEnabled = false;
  147   
  148       /**
  149        * Provide the dispatcher instance for the current thread.
  150        *
  151        * @return The dispatcher instance
  152        */
  153       public static Dispatcher getInstance() {
  154           return instance.get();
  155       }
  156   
  157       /**
  158        * Store the dispatcher instance for this thread.
  159        *
  160        * @param instance The instance
  161        */
  162       public static void setInstance(Dispatcher instance) {
  163           Dispatcher.instance.set(instance);
  164   
  165           // Tie the ObjectFactory threadlocal instance to this Dispatcher instance
  166           if (instance != null) {
  167               Container cont = instance.getContainer();
  168               if (cont != null) {
  169                   ObjectFactory.setObjectFactory(cont.getInstance(ObjectFactory.class));
  170               } else {
  171                   LOG.warn("This dispatcher instance doesn't have a container, so the object factory won't be set.");
  172               }
  173           } else {
  174               ObjectFactory.setObjectFactory(null);
  175           }
  176       }
  177   
  178       /**
  179        * Add a dispatcher lifecycle listener.
  180        *
  181        * @param listener The listener to add
  182        */
  183       public static synchronized void addDispatcherListener(DispatcherListener listener) {
  184           dispatcherListeners.add(listener);
  185       }
  186   
  187       /**
  188        * Remove a specific dispatcher lifecycle listener.
  189        *
  190        * @param listener The listener
  191        */
  192       public static synchronized void removeDispatcherListener(DispatcherListener listener) {
  193           dispatcherListeners.remove(listener);
  194       }
  195   
  196       private ServletContext servletContext;
  197       private Map<String, String> initParams;
  198   
  199   
  200       /**
  201        * Create the Dispatcher instance for a given ServletContext and set of initialization parameters.
  202        *
  203        * @param servletContext Our servlet context
  204        * @param initParams The set of initialization parameters
  205        */
  206       public  Dispatcher(ServletContext servletContext, Map<String, String> initParams) {
  207           this.servletContext = servletContext;
  208           this.initParams = initParams;
  209       }
  210   
  211       /**
  212        * Modify state of StrutsConstants.STRUTS_DEVMODE setting.
  213        * @param mode New setting
  214        */
  215       @Inject(StrutsConstants.STRUTS_DEVMODE)
  216       public static void setDevMode(String mode) {
  217           devMode = "true".equals(mode);
  218       }
  219   
  220       /**
  221        * Modify state of StrutsConstants.STRUTS_LOCALE setting.
  222        * @param val New setting
  223        */
  224       @Inject(value=StrutsConstants.STRUTS_LOCALE, required=false)
  225       public static void setDefaultLocale(String val) {
  226           defaultLocale = val;
  227       }
  228   
  229       /**
  230        * Modify state of StrutsConstants.STRUTS_I18N_ENCODING setting.
  231        * @param val New setting
  232        */
  233       @Inject(StrutsConstants.STRUTS_I18N_ENCODING)
  234       public static void setDefaultEncoding(String val) {
  235           defaultEncoding = val;
  236       }
  237   
  238       /**
  239        * Modify state of StrutsConstants.STRUTS_MULTIPART_SAVEDIR setting.
  240        * @param val New setting
  241        */
  242       @Inject(StrutsConstants.STRUTS_MULTIPART_SAVEDIR)
  243       public static void setMultipartSaveDir(String val) {
  244           multipartSaveDir = val;
  245       }
  246   
  247       /**
  248        * Releases all instances bound to this dispatcher instance.
  249        */
  250       public void cleanup() {
  251   
  252       	// clean up ObjectFactory
  253           ObjectFactory objectFactory = getContainer().getInstance(ObjectFactory.class);
  254           if (objectFactory == null) {
  255               LOG.warn("Object Factory is null, something is seriously wrong, no clean up will be performed");
  256           }
  257           if (objectFactory instanceof ObjectFactoryDestroyable) {
  258               try {
  259                   ((ObjectFactoryDestroyable)objectFactory).destroy();
  260               }
  261               catch(Exception e) {
  262                   // catch any exception that may occured during destroy() and log it
  263                   LOG.error("exception occurred while destroying ObjectFactory ["+objectFactory+"]", e);
  264               }
  265           }
  266   
  267           // clean up Dispatcher itself for this thread
  268           instance.set(null);
  269   
  270           // clean up DispatcherListeners
  271           synchronized(Dispatcher.class) {
  272               if (dispatcherListeners.size() > 0) {
  273                   for (DispatcherListener l : dispatcherListeners) {
  274                       l.dispatcherDestroyed(this);
  275                   }
  276               }
  277           }
  278   
  279           // clean up configuration
  280       	configurationManager.destroyConfiguration();
  281       	configurationManager = null;
  282       }
  283   
  284       private void init_DefaultProperties() {
  285           configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());
  286       }
  287       
  288       private void init_LegacyStrutsProperties() {
  289           configurationManager.addConfigurationProvider(new LegacyPropertiesConfigurationProvider());
  290       }
  291   
  292       private void init_TraditionalXmlConfigurations() {
  293           String configPaths = initParams.get("config");
  294           if (configPaths == null) {
  295               configPaths = DEFAULT_CONFIGURATION_PATHS;
  296           }
  297           String[] files = configPaths.split("\\s*[,]\\s*");
  298           for (String file : files) {
  299               if (file.endsWith(".xml")) {
  300                   if ("xwork.xml".equals(file)) {
  301                       configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));
  302                   } else {
  303                       configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));
  304                   }
  305               } else {
  306                   throw new IllegalArgumentException("Invalid configuration file name");
  307               }
  308           }
  309       }
  310   
  311       private void init_ZeroConfiguration() {
  312           String packages = initParams.get("actionPackages");
  313           if (packages != null) {
  314               String[] names = packages.split("\\s*[,]\\s*");
  315               // Initialize the classloader scanner with the configured packages
  316               if (names.length > 0) {
  317                   ClasspathConfigurationProvider provider = new ClasspathConfigurationProvider(names);
  318                   provider.setPageLocator(new ServletContextPageLocator(servletContext));
  319                   configurationManager.addConfigurationProvider(provider);
  320               }
  321           }
  322       }
  323   
  324       private void init_CustomConfigurationProviders() {
  325           String configProvs = initParams.get("configProviders");
  326           if (configProvs != null) {
  327               String[] classes = configProvs.split("\\s*[,]\\s*");
  328               for (String cname : classes) {
  329                   try {
  330                       Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());
  331                       ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();
  332                       configurationManager.addConfigurationProvider(prov);
  333                   } catch (InstantiationException e) {
  334                       throw new ConfigurationException("Unable to instantiate provider: "+cname, e);
  335                   } catch (IllegalAccessException e) {
  336                       throw new ConfigurationException("Unable to access provider: "+cname, e);
  337                   } catch (ClassNotFoundException e) {
  338                       throw new ConfigurationException("Unable to locate provider class: "+cname, e);
  339                   }
  340               }
  341           }
  342       }
  343   
  344       private void init_MethodConfigurationProvider() {
  345           // See https://issues.apache.org/struts/browse/WW-1522
  346       /*
  347       com.opensymphony.xwork2.inject.DependencyException: com.opensymphony.xwork2.inject.ContainerImpl$MissingDependencyException: No mapping found for dependency [type=org.apache.struts2.dispatcher.mapper.ActionMapper, name='default'] in public static void org.apache.struts2.dispatcher.FilterDispatcher.setActionMapper(org.apache.struts2.dispatcher.mapper.ActionMapper).
  348   	at com.opensymphony.xwork2.inject.ContainerImpl.addInjectorsForMembers(ContainerImpl.java:135)
  349   	at com.opensymphony.xwork2.inject.ContainerImpl.addInjectorsForMethods(ContainerImpl.java:104)
  350   	at com.opensymphony.xwork2.inject.ContainerImpl.injectStatics(ContainerImpl.java:89)
  351   	at com.opensymphony.xwork2.inject.ContainerBuilder.create(ContainerBuilder.java:494)
  352   	at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reload(DefaultConfiguration.java:140)
  353   	at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:52)
  354   	at org.apache.struts2.dispatcher.Dispatcher.init_MethodConfigurationProvider(Dispatcher.java:347)
  355   	at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:421)
  356   	at org.apache.struts2.config.MethodConfigurationProviderTest.setUp(MethodConfigurationProviderTest.java:68)
  357   	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)
  358   	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  359   	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
  360   	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
  361   	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)
  362   Caused by: com.opensymphony.xwork2.inject.ContainerImpl$MissingDependencyException: No mapping found for dependency [type=org.apache.struts2.dispatcher.mapper.ActionMapper, name='default'] in public static void org.apache.struts2.dispatcher.FilterDispatcher.setActionMapper(org.apache.struts2.dispatcher.mapper.ActionMapper).
  363   	at com.opensymphony.xwork2.inject.ContainerImpl.createParameterInjector(ContainerImpl.java:217)
  364   	at com.opensymphony.xwork2.inject.ContainerImpl.getParametersInjectors(ContainerImpl.java:207)
  365   	at com.opensymphony.xwork2.inject.ContainerImpl$MethodInjector.<init>(ContainerImpl.java:260)
  366   	at com.opensymphony.xwork2.inject.ContainerImpl$3.create(ContainerImpl.java:108)
  367   	at com.opensymphony.xwork2.inject.ContainerImpl$3.create(ContainerImpl.java:106)
  368   	at com.opensymphony.xwork2.inject.ContainerImpl.addInjectorsForMembers(ContainerImpl.java:132)
  369   	... 26 more
  370   
  371           MethodConfigurationProvider provider = new MethodConfigurationProvider();
  372           provider.init(configurationManager.getConfiguration());
  373           provider.loadPackages();
  374      */
  375       }
  376   
  377       private void init_FilterInitParameters() {
  378           configurationManager.addConfigurationProvider(new ConfigurationProvider() {
  379               public void destroy() {}
  380               public void init(Configuration configuration) throws ConfigurationException {}
  381               public void loadPackages() throws ConfigurationException {}
  382               public boolean needsReload() { return false; }
  383   
  384               public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
  385                   props.putAll(initParams);
  386               }
  387           });
  388       }
  389   
  390       private void init_AliasStandardObjects() {
  391           configurationManager.addConfigurationProvider(new BeanSelectionProvider());
  392       }
  393   
  394       private Container init_PreloadConfiguration() {
  395           Configuration config = configurationManager.getConfiguration();
  396           Container container = config.getContainer();
  397   
  398           boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));
  399           LocalizedTextUtil.setReloadBundles(reloadi18n);
  400   
  401           ObjectTypeDeterminer objectTypeDeterminer = container.getInstance(ObjectTypeDeterminer.class);
  402           ObjectTypeDeterminerFactory.setInstance(objectTypeDeterminer);
  403   
  404           return container;
  405       }
  406   
  407       private void init_CheckConfigurationReloading(Container container) {
  408           FileManager.setReloadingConfigs("true".equals(container.getInstance(String.class,
  409                   StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD)));
  410       }
  411   
  412       private void init_CheckWebLogicWorkaround(Container container) {
  413           // test whether param-access workaround needs to be enabled
  414           if (servletContext != null && servletContext.getServerInfo() != null
  415                   && servletContext.getServerInfo().indexOf("WebLogic") >= 0) {
  416               LOG.info("WebLogic server detected. Enabling Struts parameter access work-around.");
  417               paramsWorkaroundEnabled = true;
  418           } else {
  419               paramsWorkaroundEnabled = "true".equals(container.getInstance(String.class,
  420                       StrutsConstants.STRUTS_DISPATCHER_PARAMETERSWORKAROUND));
  421           }
  422   
  423           synchronized(Dispatcher.class) {
  424               if (dispatcherListeners.size() > 0) {
  425                   for (DispatcherListener l : dispatcherListeners) {
  426                       l.dispatcherInitialized(this);
  427                   }
  428               }
  429           }
  430   
  431       }
  432   
  433       /**
  434        * Load configurations, including both XML and zero-configuration strategies,
  435        * and update optional settings, including whether to reload configurations and resource files.
  436        */
  437       public void init() {
  438   
  439       	if (configurationManager == null) {
  440       		configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
  441       	}
  442   
  443       	init_DefaultProperties(); // [1]
  444           init_TraditionalXmlConfigurations(); // [2]
  445           init_LegacyStrutsProperties(); // [3]
  446           init_ZeroConfiguration(); // [4]
  447           init_CustomConfigurationProviders(); // [5]
  448           init_MethodConfigurationProvider();
  449           init_FilterInitParameters() ; // [6]
  450           init_AliasStandardObjects() ; // [7]
  451   
  452           Container container = init_PreloadConfiguration();
  453           init_CheckConfigurationReloading(container);
  454           init_CheckWebLogicWorkaround(container);
  455   
  456       }
  457   
  458       /**
  459        * Load Action class for mapping and invoke the appropriate Action method, or go directly to the Result.
  460        * <p/>
  461        * This method first creates the action context from the given parameters,
  462        * and then loads an <tt>ActionProxy</tt> from the given action name and namespace.
  463        * After that, the Action method is executed and output channels through the response object.
  464        * Actions not found are sent back to the user via the {@link Dispatcher#sendError} method,
  465        * using the 404 return code.
  466        * All other errors are reported by throwing a ServletException.
  467        *
  468        * @param request  the HttpServletRequest object
  469        * @param response the HttpServletResponse object
  470        * @param mapping  the action mapping object
  471        * @throws ServletException when an unknown error occurs (not a 404, but typically something that
  472        *                          would end up as a 5xx by the servlet container)
  473        * @param context Our ServletContext object
  474        */
  475       public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
  476                                 ActionMapping mapping) throws ServletException {
  477   
  478           Map<String, Object> extraContext = createContextMap(request, response, mapping, context);
  479   
  480           // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action
  481           ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
  482           if (stack != null) {
  483               extraContext.put(ActionContext.VALUE_STACK, ValueStackFactory.getFactory().createValueStack(stack));
  484           }
  485   
  486           String timerKey = "Handling request from Dispatcher";
  487           try {
  488               UtilTimerStack.push(timerKey);
  489               String namespace = mapping.getNamespace();
  490               String name = mapping.getName();
  491               String method = mapping.getMethod();
  492   
  493               Configuration config = configurationManager.getConfiguration();
  494               ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
  495                       namespace, name, extraContext, true, false);
  496               proxy.setMethod(method);
  497               request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
  498   
  499               // if the ActionMapping says to go straight to a result, do it!
  500               if (mapping.getResult() != null) {
  501                   Result result = mapping.getResult();
  502                   result.execute(proxy.getInvocation());
  503               } else {
  504                   proxy.execute();
  505               }
  506   
  507               // If there was a previous value stack then set it back onto the request
  508               if (stack != null) {
  509                   request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
  510               }
  511           } catch (ConfigurationException e) {
  512               LOG.error("Could not find action or result", e);
  513               sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);
  514           } catch (Exception e) {
  515               throw new ServletException(e);
  516           } finally {
  517               UtilTimerStack.pop(timerKey);
  518           }
  519       }
  520   
  521       /**
  522        * Create a context map containing all the wrapped request objects
  523        *
  524        * @param request The servlet request
  525        * @param response The servlet response
  526        * @param mapping The action mapping
  527        * @param context The servlet context
  528        * @return A map of context objects
  529        */
  530       public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,
  531               ActionMapping mapping, ServletContext context) {
  532   
  533           // request map wrapping the http request objects
  534           Map requestMap = new RequestMap(request);
  535   
  536           // parameters map wrapping the http paraneters.
  537           Map params = null;
  538           if (mapping != null) {
  539               params = mapping.getParams();
  540           }
  541           Map requestParams = new HashMap(request.getParameterMap());
  542           if (params != null) {
  543               params.putAll(requestParams);
  544           } else {
  545               params = requestParams;
  546           }
  547   
  548           // session map wrapping the http session
  549           Map session = new SessionMap(request);
  550   
  551           // application map wrapping the ServletContext
  552           Map application = new ApplicationMap(context);
  553   
  554           Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);
  555           extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);
  556           return extraContext;
  557       }
  558   
  559       /**
  560        * Merge all application and servlet attributes into a single <tt>HashMap</tt> to represent the entire
  561        * <tt>Action</tt> context.
  562        *
  563        * @param requestMap     a Map of all request attributes.
  564        * @param parameterMap   a Map of all request parameters.
  565        * @param sessionMap     a Map of all session attributes.
  566        * @param applicationMap a Map of all servlet context attributes.
  567        * @param request        the HttpServletRequest object.
  568        * @param response       the HttpServletResponse object.
  569        * @param servletContext the ServletContextmapping object.
  570        * @return a HashMap representing the <tt>Action</tt> context.
  571        */
  572       public HashMap<String,Object> createContextMap(Map requestMap,
  573                                       Map parameterMap,
  574                                       Map sessionMap,
  575                                       Map applicationMap,
  576                                       HttpServletRequest request,
  577                                       HttpServletResponse response,
  578                                       ServletContext servletContext) {
  579           HashMap<String,Object> extraContext = new HashMap<String,Object>();
  580           extraContext.put(ActionContext.PARAMETERS, new HashMap(parameterMap));
  581           extraContext.put(ActionContext.SESSION, sessionMap);
  582           extraContext.put(ActionContext.APPLICATION, applicationMap);
  583   
  584           Locale locale;
  585           if (defaultLocale != null) {
  586               locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
  587           } else {
  588               locale = request.getLocale();
  589           }
  590   
  591           extraContext.put(ActionContext.LOCALE, locale);
  592           //extraContext.put(ActionContext.DEV_MODE, Boolean.valueOf(devMode));
  593   
  594           extraContext.put(StrutsStatics.HTTP_REQUEST, request);
  595           extraContext.put(StrutsStatics.HTTP_RESPONSE, response);
  596           extraContext.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
  597   
  598           // helpers to get access to request/session/application scope
  599           extraContext.put("request", requestMap);
  600           extraContext.put("session", sessionMap);
  601           extraContext.put("application", applicationMap);
  602           extraContext.put("parameters", parameterMap);
  603   
  604           AttributeMap attrMap = new AttributeMap(extraContext);
  605           extraContext.put("attr", attrMap);
  606   
  607           return extraContext;
  608       }
  609   
  610       /**
  611        * Return the path to save uploaded files to (this is configurable).
  612        *
  613        * @return the path to save uploaded files to
  614        * @param servletContext Our ServletContext
  615        */
  616       private String getSaveDir(ServletContext servletContext) {
  617           String saveDir = multipartSaveDir.trim();
  618   
  619           if (saveDir.equals("")) {
  620               File tempdir = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
  621               LOG.info("Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir");
  622   
  623               if (tempdir != null) {
  624                   saveDir = tempdir.toString();
  625               }
  626           } else {
  627               File multipartSaveDir = new File(saveDir);
  628   
  629               if (!multipartSaveDir.exists()) {
  630                   multipartSaveDir.mkdir();
  631               }
  632           }
  633   
  634           if (LOG.isDebugEnabled()) {
  635               LOG.debug("saveDir=" + saveDir);
  636           }
  637   
  638           return saveDir;
  639       }
  640   
  641       /**
  642        * Prepare a request, including setting the encoding and locale.
  643        *
  644        * @param request The request
  645        * @param response The response
  646        */
  647       public void prepare(HttpServletRequest request, HttpServletResponse response) {
  648           String encoding = null;
  649           if (defaultEncoding != null) {
  650               encoding = defaultEncoding;
  651           }
  652   
  653           Locale locale = null;
  654           if (defaultLocale != null) {
  655               locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
  656           }
  657   
  658           if (encoding != null) {
  659               try {
  660                   request.setCharacterEncoding(encoding);
  661               } catch (Exception e) {
  662                   LOG.error("Error setting character encoding to '" + encoding + "' - ignoring.", e);
  663               }
  664           }
  665   
  666           if (locale != null) {
  667               response.setLocale(locale);
  668           }
  669   
  670           if (paramsWorkaroundEnabled) {
  671               request.getParameter("foo"); // simply read any parameter (existing or not) to "prime" the request
  672           }
  673       }
  674   
  675       /**
  676        * Wrap and return the given request or return the original request object.
  677        * </p>
  678        * This method transparently handles multipart data as a wrapped class around the given request.
  679        * Override this method to handle multipart requests in a special way or to handle other types of requests.
  680        * Note, {@link org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper} is
  681        * flexible - look first to that object before overriding this method to handle multipart data.
  682        *
  683        * @param request the HttpServletRequest object.
  684        * @param servletContext Our ServletContext object
  685        * @return a wrapped request or original request.
  686        * @see org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper
  687        * @throws java.io.IOException on any error.
  688        */
  689       public HttpServletRequest wrapRequest(HttpServletRequest request, ServletContext servletContext) throws IOException {
  690           // don't wrap more than once
  691           if (request instanceof StrutsRequestWrapper) {
  692               return request;
  693           }
  694   
  695           String content_type = request.getContentType();
  696           if (content_type != null && content_type.indexOf("multipart/form-data") != -1) {
  697               MultiPartRequest multi = getContainer().getInstance(MultiPartRequest.class);
  698               request = new MultiPartRequestWrapper(multi, request, getSaveDir(servletContext));
  699           } else {
  700               request = new StrutsRequestWrapper(request);
  701           }
  702   
  703           return request;
  704       }
  705   
  706       /**
  707        * Send an HTTP error response code.
  708        *
  709        * @param request  the HttpServletRequest object.
  710        * @param response the HttpServletResponse object.
  711        * @param code     the HttpServletResponse error code (see {@link javax.servlet.http.HttpServletResponse} for possible error codes).
  712        * @param e        the Exception that is reported.
  713        * @param ctx      the ServletContext object.
  714        */
  715       public void sendError(HttpServletRequest request, HttpServletResponse response,
  716               ServletContext ctx, int code, Exception e) {
  717           if (devMode) {
  718               response.setContentType("text/html");
  719   
  720               try {
  721                   FreemarkerManager mgr = getContainer().getInstance(FreemarkerManager.class);
  722   
  723                   freemarker.template.Configuration config = mgr.getConfiguration(ctx);
  724                   Template template = config.getTemplate("/org/apache/struts2/dispatcher/error.ftl");
  725   
  726                   List<Throwable> chain = new ArrayList<Throwable>();
  727                   Throwable cur = e;
  728                   chain.add(cur);
  729                   while ((cur = cur.getCause()) != null) {
  730                       chain.add(cur);
  731                   }
  732   
  733                   HashMap<String,Object> data = new HashMap<String,Object>();
  734                   data.put("exception", e);
  735                   data.put("unknown", Location.UNKNOWN);
  736                   data.put("chain", chain);
  737                   data.put("locator", new Locator());
  738                   template.process(data, response.getWriter());
  739                   response.getWriter().close();
  740               } catch (Exception exp) {
  741                   try {
  742                       response.sendError(code, "Unable to show problem report: " + exp);
  743                   } catch (IOException ex) {
  744                       // we're already sending an error, not much else we can do if more stuff breaks
  745                   }
  746               }
  747           } else {
  748               try {
  749                   // WW-1977: Only put errors in the request when code is a 500 error
  750                   if (code == HttpServletResponse.SC_INTERNAL_SERVER_ERROR) {
  751                       // send a http error response to use the servlet defined error handler
  752                       // make the exception availible to the web.xml defined error page
  753                       request.setAttribute("javax.servlet.error.exception", e);
  754   
  755                       // for compatibility
  756                       request.setAttribute("javax.servlet.jsp.jspException", e);
  757                   }
  758   
  759                   // send the error response
  760                   response.sendError(code, e.getMessage());
  761               } catch (IOException e1) {
  762                   // we're already sending an error, not much else we can do if more stuff breaks
  763               }
  764           }
  765       }
  766   
  767       /**
  768        * Return <tt>true</tt>, if portlet support is active, <tt>false</tt> otherwise.
  769        *
  770        * @return <tt>true</tt>, if portlet support is active, <tt>false</tt> otherwise.
  771        */
  772       public boolean isPortletSupportActive() {
  773           return portletSupportActive;
  774       }
  775   
  776       /**
  777        * Modify the portlet support mode.
  778        * @param portletSupportActive <tt>true</tt> or <tt>false</tt>
  779        */
  780       public static void setPortletSupportActive(boolean portletSupportActive) {
  781           Dispatcher.portletSupportActive = portletSupportActive;
  782       }
  783   
  784       /**
  785        * Search classpath for a page.
  786        */
  787       private final class ServletContextPageLocator implements PageLocator {
  788           private final ServletContext context;
  789           private ClasspathPageLocator classpathPageLocator = new ClasspathPageLocator();
  790   
  791           private ServletContextPageLocator(ServletContext context) {
  792               this.context = context;
  793           }
  794   
  795           public URL locate(String path) {
  796               URL url = null;
  797               try {
  798                   url = context.getResource(path);
  799                   if (url == null) {
  800                       url = classpathPageLocator.locate(path);
  801                   }
  802               } catch (MalformedURLException e) {
  803                   if (LOG.isDebugEnabled()) {
  804                       LOG.debug("Unable to resolve path "+path+" against the servlet context");
  805                   }
  806               }
  807               return url;
  808           }
  809       }
  810   
  811       /**
  812        * Provide an accessor class for static XWork utility.
  813        */
  814       public class Locator {
  815           public Location getLocation(Object obj) {
  816               Location loc = LocationUtils.getLocation(obj);
  817               if (loc == null) {
  818                   return Location.UNKNOWN;
  819               }
  820               return loc;
  821           }
  822       }
  823   
  824       /**
  825        * Expose the ConfigurationManager instance.
  826        *
  827        * @return The instance
  828        */
  829       public ConfigurationManager getConfigurationManager() {
  830           return configurationManager;
  831       }
  832   
  833       /**
  834        * Modify the ConfigurationManager instance
  835        *
  836        * @param mgr The configuration manager
  837        */
  838       public void setConfigurationManager(ConfigurationManager mgr) {
  839           this.configurationManager = mgr;
  840       }
  841   
  842       /**
  843        * Expose the dependency injection container.
  844        * @return Our dependency injection container
  845        */
  846       public Container getContainer() {
  847           ConfigurationManager mgr = getConfigurationManager();
  848           if (mgr == null) {
  849               throw new IllegalStateException("The configuration manager shouldn't be null");
  850           } else {
  851               Configuration config = mgr.getConfiguration();
  852               if (config == null) {
  853                   throw new IllegalStateException("Unable to load configuration");
  854               } else {
  855                   return config.getContainer();
  856               }
  857           }
  858       }
  859   }

Save This Page
Home » struts-2.0.11.2-src » org.apache » struts2 » dispatcher » [javadoc | source]