2、struct2的工作流程
阅读原文时间:2023年07月10日阅读:1

1、首先执行StrutsPrepareAndExecuteFilter,调用StrutsPrepareAndExecuteFilter类的doFilter方法

在该方法中会产生一个ActionMapping 对象,如果客户端访问不是action对象,例如访问jsp对象ActionMapping 就为空

如果访问是action对象,则ActionMapping 不为null执行

2、execute.executeAction(request, response, mapping);该方法调用下面的dispatcher.serviceAction(request, response, servletContext, mapping);

3、在dispatcher.serviceAction(request, response, servletContext, mapping);调用下面的函数

ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
namespace, name, method, extraContext, true, false);

创建一个ActionProxy 代理对象

public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext) {

ActionInvocation inv = new DefaultActionInvocation(extraContext, true);
container.inject(inv);
return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
}

在创建代理对象的同时创建了ActionInvocation 对象

4、

/*
* $Id: DefaultActionSupport.java 651946 2008-04-27 13:41:38Z apetrelli $
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.struts2.dispatcher.ng.filter;

import org.apache.struts2.StrutsStatics;
import org.apache.struts2.dispatcher.Dispatcher;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.dispatcher.ng.ExecuteOperations;
import org.apache.struts2.dispatcher.ng.InitOperations;
import org.apache.struts2.dispatcher.ng.PrepareOperations;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.regex.Pattern;

/**
* Handles both the preparation and execution phases of the Struts dispatching process. This filter is better to use
* when you don't have another filter that needs access to action context information, such as Sitemesh.
*/
public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {
protected PrepareOperations prepare;
protected ExecuteOperations execute;
protected List excludedPatterns = null;

public void init(FilterConfig filterConfig) throws ServletException {  
    InitOperations init = new InitOperations();  
    try {  
        FilterHostConfig config = new FilterHostConfig(filterConfig);  
        init.initLogging(config);  
        Dispatcher dispatcher = init.initDispatcher(config);  
        init.initStaticContentLoader(config, dispatcher);

        prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);  
        execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);  
        this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);

        postInit(dispatcher, filterConfig);  
    } finally {  
        init.cleanup();  
    }

}

/\*\*  
 \* Callback for post initialization  
 \*/  
protected void postInit(Dispatcher dispatcher, FilterConfig filterConfig) {  
}

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

    HttpServletRequest request = (HttpServletRequest) req;  
    HttpServletResponse response = (HttpServletResponse) res;

    try {  
        prepare.setEncodingAndLocale(request, response);  
        prepare.createActionContext(request, response);  
        prepare.assignDispatcherToThread();  
        if ( excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {  
            chain.doFilter(request, response);  
        } else {  
            request = prepare.wrapRequest(request);  
            ActionMapping mapping = prepare.findActionMapping(request, response, true);  
            if (mapping == null) {  
                boolean handled = execute.executeStaticResourceRequest(request, response);  
                if (!handled) {  
                    chain.doFilter(request, response);  
                }  
            } else {  
                execute.executeAction(request, response, mapping);  
            }  
        }  
    } finally {  
        prepare.cleanupRequest(request);  
    }  
}

public void destroy() {  
    prepare.cleanupDispatcher();  
}  

}

/*
* $Id: DefaultActionSupport.java 651946 2008-04-27 13:41:38Z apetrelli $
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.struts2.dispatcher.ng;

import org.apache.struts2.dispatcher.Dispatcher;
import org.apache.struts2.dispatcher.StaticContentLoader;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.RequestUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* Contains execution operations for filters
*/
public class ExecuteOperations {
private ServletContext servletContext;
private Dispatcher dispatcher;

public ExecuteOperations(ServletContext servletContext, Dispatcher dispatcher) {  
    this.dispatcher = dispatcher;  
    this.servletContext = servletContext;  
}

/\*\*  
 \* Tries to execute a request for a static resource  
 \* @return True if it was handled, false if the filter should fall through  
 \* @throws IOException  
 \* @throws ServletException  
 \*/  
public boolean executeStaticResourceRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {  
    // there is no action in this request, should we look for a static resource?  
    String resourcePath = RequestUtils.getServletPath(request);

    if ("".equals(resourcePath) && null != request.getPathInfo()) {  
        resourcePath = request.getPathInfo();  
    }

    StaticContentLoader staticResourceLoader = dispatcher.getContainer().getInstance(StaticContentLoader.class);  
    if (staticResourceLoader.canHandle(resourcePath)) {  
        staticResourceLoader.findStaticResource(resourcePath, request, response);  
        // The framework did its job here  
        return true;

    } else {  
        // this is a normal request, let it pass through  
        return false;  
    }  
}

/\*\*  
 \* Executes an action  
 \* @throws ServletException  
 \*/  
public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {  
    dispatcher.serviceAction(request, response, servletContext, mapping);  
}  

}

/*
* $Id: Dispatcher.java 783012 2009-06-09 14:15:54Z wesw $
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.struts2.dispatcher;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.StrutsStatics;
import org.apache.struts2.StrutsException;
import org.apache.struts2.config.BeanSelectionProvider;
import org.apache.struts2.config.DefaultPropertiesProvider;
import org.apache.struts2.config.LegacyPropertiesConfigurationProvider;
import org.apache.struts2.config.StrutsXmlConfigurationProvider;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.dispatcher.multipart.MultiPartRequest;
import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
import org.apache.struts2.util.AttributeMap;
import org.apache.struts2.util.ClassLoaderUtils;
import org.apache.struts2.util.ObjectFactoryDestroyable;
import org.apache.struts2.views.freemarker.FreemarkerManager;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.ActionProxyFactory;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.Result;
import com.opensymphony.xwork2.config.Configuration;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.config.ConfigurationManager;
import com.opensymphony.xwork2.config.ConfigurationProvider;
import com.opensymphony.xwork2.config.entities.InterceptorMapping;
import com.opensymphony.xwork2.config.entities.InterceptorStackConfig;
import com.opensymphony.xwork2.config.entities.PackageConfig;
import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.interceptor.Interceptor;
import com.opensymphony.xwork2.util.FileManager;
import com.opensymphony.xwork2.util.LocalizedTextUtil;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.ValueStackFactory;
import com.opensymphony.xwork2.util.location.LocatableProperties;
import com.opensymphony.xwork2.util.location.Location;
import com.opensymphony.xwork2.util.location.LocationUtils;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import com.opensymphony.xwork2.util.profiling.UtilTimerStack;

import freemarker.template.Template;

/**
* A utility class the actual dispatcher delegates most of its tasks to. Each instance
* of the primary dispatcher holds an instance of this dispatcher to be shared for
* all requests.
*
* @see org.apache.struts2.dispatcher.FilterDispatcher
*/
public class Dispatcher {

/\*\*  
 \* Provide a logging instance.  
 \*/  
private static final Logger LOG = LoggerFactory.getLogger(Dispatcher.class);

/\*\*  
 \* Provide a thread local instance.  
 \*/  
private static ThreadLocal<Dispatcher> instance = new ThreadLocal<Dispatcher>();

/\*\*  
 \* Store list of DispatcherListeners.  
 \*/  
private static List<DispatcherListener> dispatcherListeners =  
    new CopyOnWriteArrayList<DispatcherListener>();

/\*\*  
 \* Store ConfigurationManager instance, set on init.  
 \*/  
private ConfigurationManager configurationManager;

/\*\*  
 \* Store state of  StrutsConstants.STRUTS\_DEVMODE setting.  
 \*/  
private boolean devMode;

/\*\*  
 \* Store state of StrutsConstants.STRUTS\_I18N\_ENCODING setting.  
 \*/  
private String defaultEncoding;

/\*\*  
 \* Store state of StrutsConstants.STRUTS\_LOCALE setting.  
 \*/  
private String defaultLocale;

/\*\*  
 \* Store state of StrutsConstants.STRUTS\_MULTIPART\_SAVEDIR setting.  
 \*/  
private String multipartSaveDir;

/\*\*  
 \* Stores the value of StrutsConstants.STRUTS\_MULTIPART\_HANDLER setting  
 \*/  
private String multipartHandlerName;

/\*\*  
 \* Provide list of default configuration files.  
 \*/  
private static final String DEFAULT\_CONFIGURATION\_PATHS = "struts-default.xml,struts-plugin.xml,struts.xml";

/\*\*  
 \* Store state of STRUTS\_DISPATCHER\_PARAMETERSWORKAROUND.  
 \* <p/>  
 \* The workaround is for WebLogic.  
 \* We try to autodect WebLogic on Dispatcher init.  
 \* The workaround can also be enabled manually.  
 \*/  
private boolean paramsWorkaroundEnabled = false;

/\*\*  
 \* Provide the dispatcher instance for the current thread.  
 \*  
 \* @return The dispatcher instance  
 \*/  
public static Dispatcher getInstance() {  
    return instance.get();  
}

/\*\*  
 \* Store the dispatcher instance for this thread.  
 \*  
 \* @param instance The instance  
 \*/  
public static void setInstance(Dispatcher instance) {  
    Dispatcher.instance.set(instance);  
}

/\*\*  
 \* Add a dispatcher lifecycle listener.  
 \*  
 \* @param listener The listener to add  
 \*/  
public static void addDispatcherListener(DispatcherListener listener) {  
    dispatcherListeners.add(listener);  
}

/\*\*  
 \* Remove a specific dispatcher lifecycle listener.  
 \*  
 \* @param listener The listener  
 \*/  
public static void removeDispatcherListener(DispatcherListener listener) {  
    dispatcherListeners.remove(listener);  
}

private ServletContext servletContext;  
private Map<String, String> initParams;

private ValueStackFactory valueStackFactory;

/\*\*  
 \* Create the Dispatcher instance for a given ServletContext and set of initialization parameters.  
 \*  
 \* @param servletContext Our servlet context  
 \* @param initParams The set of initialization parameters  
 \*/  
public Dispatcher(ServletContext servletContext, Map<String, String> initParams) {  
    this.servletContext = servletContext;  
    this.initParams = initParams;  
}

/\*\*  
 \* Modify state of StrutsConstants.STRUTS\_DEVMODE setting.  
 \* @param mode New setting  
 \*/  
@Inject(StrutsConstants.STRUTS\_DEVMODE)  
public void setDevMode(String mode) {  
    devMode = "true".equals(mode);  
}

/\*\*  
 \* Modify state of StrutsConstants.STRUTS\_LOCALE setting.  
 \* @param val New setting  
 \*/  
@Inject(value=StrutsConstants.STRUTS\_LOCALE, required=false)  
public void setDefaultLocale(String val) {  
    defaultLocale = val;  
}

/\*\*  
 \* Modify state of StrutsConstants.STRUTS\_I18N\_ENCODING setting.  
 \* @param val New setting  
 \*/  
@Inject(StrutsConstants.STRUTS\_I18N\_ENCODING)  
public void setDefaultEncoding(String val) {  
    defaultEncoding = val;  
}

/\*\*  
 \* Modify state of StrutsConstants.STRUTS\_MULTIPART\_SAVEDIR setting.  
 \* @param val New setting  
 \*/  
@Inject(StrutsConstants.STRUTS\_MULTIPART\_SAVEDIR)  
public void setMultipartSaveDir(String val) {  
    multipartSaveDir = val;  
}

@Inject(StrutsConstants.STRUTS\_MULTIPART\_HANDLER)  
public void setMultipartHandler(String val) {  
    multipartHandlerName = val;  
}

@Inject  
public void setValueStackFactory(ValueStackFactory valueStackFactory) {  
    this.valueStackFactory = valueStackFactory;  
}

/\*\*  
 \* Releases all instances bound to this dispatcher instance.  
 \*/  
public void cleanup() {

    // clean up ObjectFactory  
    ObjectFactory objectFactory = getContainer().getInstance(ObjectFactory.class);  
    if (objectFactory == null) {  
        LOG.warn("Object Factory is null, something is seriously wrong, no clean up will be performed");  
    }  
    if (objectFactory instanceof ObjectFactoryDestroyable) {  
        try {  
            ((ObjectFactoryDestroyable)objectFactory).destroy();  
        }  
        catch(Exception e) {  
            // catch any exception that may occured during destroy() and log it  
            LOG.error("exception occurred while destroying ObjectFactory \["+objectFactory+"\]", e);  
        }  
    }

    // clean up Dispatcher itself for this thread  
    instance.set(null);

    // clean up DispatcherListeners  
    if (!dispatcherListeners.isEmpty()) {  
        for (DispatcherListener l : dispatcherListeners) {  
            l.dispatcherDestroyed(this);  
        }  
    }

    // clean up all interceptors by calling their destroy() method  
    Set<Interceptor> interceptors = new HashSet<Interceptor>();  
    Collection<PackageConfig> packageConfigs = configurationManager.getConfiguration().getPackageConfigs().values();  
    for (PackageConfig packageConfig : packageConfigs) {  
        for (Object config : packageConfig.getAllInterceptorConfigs().values()) {  
            if (config instanceof InterceptorStackConfig) {  
                for (InterceptorMapping interceptorMapping : ((InterceptorStackConfig) config).getInterceptors()) {  
                    interceptors.add(interceptorMapping.getInterceptor());  
                }  
            }  
        }  
    }  
    for (Interceptor interceptor : interceptors) {  
        interceptor.destroy();  
    }

    //cleanup action context  
    ActionContext.setContext(null);

    // clean up configuration  
    configurationManager.destroyConfiguration();  
    configurationManager = null;  
}

private void init\_DefaultProperties() {  
    configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());  
}

private void init\_LegacyStrutsProperties() {  
    configurationManager.addConfigurationProvider(new LegacyPropertiesConfigurationProvider());  
}

private void init\_TraditionalXmlConfigurations() {  
    String configPaths = initParams.get("config");  
    if (configPaths == null) {  
        configPaths = DEFAULT\_CONFIGURATION\_PATHS;  
    }  
    String\[\] files = configPaths.split("\\\\s\*\[,\]\\\\s\*");  
    for (String file : files) {  
        if (file.endsWith(".xml")) {  
            if ("xwork.xml".equals(file)) {  
                configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));  
            } else {  
                configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));  
            }  
        } else {  
            throw new IllegalArgumentException("Invalid configuration file name");  
        }  
    }  
}

private void init\_CustomConfigurationProviders() {  
    String configProvs = initParams.get("configProviders");  
    if (configProvs != null) {  
        String\[\] classes = configProvs.split("\\\\s\*\[,\]\\\\s\*");  
        for (String cname : classes) {  
            try {  
                Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());  
                ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();  
                configurationManager.addConfigurationProvider(prov);  
            } catch (InstantiationException e) {  
                throw new ConfigurationException("Unable to instantiate provider: "+cname, e);  
            } catch (IllegalAccessException e) {  
                throw new ConfigurationException("Unable to access provider: "+cname, e);  
            } catch (ClassNotFoundException e) {  
                throw new ConfigurationException("Unable to locate provider class: "+cname, e);  
            }  
        }  
    }  
}

private void init\_FilterInitParameters() {  
    configurationManager.addConfigurationProvider(new ConfigurationProvider() {  
        public void destroy() {}  
        public void init(Configuration configuration) throws ConfigurationException {}  
        public void loadPackages() throws ConfigurationException {}  
        public boolean needsReload() { return false; }

        public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {  
            props.putAll(initParams);  
        }  
    });  
}

private void init\_AliasStandardObjects() {  
    configurationManager.addConfigurationProvider(new BeanSelectionProvider());  
}

private Container init\_PreloadConfiguration() {  
    Configuration config = configurationManager.getConfiguration();  
    Container container = config.getContainer();

    boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS\_I18N\_RELOAD));  
    LocalizedTextUtil.setReloadBundles(reloadi18n);

    return container;  
}

private void init\_CheckConfigurationReloading(Container container) {  
    FileManager.setReloadingConfigs("true".equals(container.getInstance(String.class,  
            StrutsConstants.STRUTS\_CONFIGURATION\_XML\_RELOAD)));  
}

private void init\_CheckWebLogicWorkaround(Container container) {  
    // test whether param-access workaround needs to be enabled  
    if (servletContext != null && servletContext.getServerInfo() != null  
            && servletContext.getServerInfo().indexOf("WebLogic") >= 0) {  
        LOG.info("WebLogic server detected. Enabling Struts parameter access work-around.");  
        paramsWorkaroundEnabled = true;  
    } else {  
        paramsWorkaroundEnabled = "true".equals(container.getInstance(String.class,  
                StrutsConstants.STRUTS\_DISPATCHER\_PARAMETERSWORKAROUND));  
    }  
}

/\*\*  
 \* Load configurations, including both XML and zero-configuration strategies,  
 \* and update optional settings, including whether to reload configurations and resource files.  
 \*/  
public void init() {

    if (configurationManager == null) {  
        configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT\_BEAN\_NAME);  
    }

    try {  
        init\_DefaultProperties(); // \[1\]  
        init\_TraditionalXmlConfigurations(); // \[2\]  
        init\_LegacyStrutsProperties(); // \[3\]  
        init\_CustomConfigurationProviders(); // \[5\]  
        init\_FilterInitParameters() ; // \[6\]  
        init\_AliasStandardObjects() ; // \[7\]

        Container container = init\_PreloadConfiguration();  
        container.inject(this);  
        init\_CheckConfigurationReloading(container);  
        init\_CheckWebLogicWorkaround(container);

        if (!dispatcherListeners.isEmpty()) {  
            for (DispatcherListener l : dispatcherListeners) {  
                l.dispatcherInitialized(this);  
            }  
        }  
    } catch (Exception ex) {  
        if (LOG.isErrorEnabled())  
            LOG.error("Dispatcher initialization failed", ex);  
        throw new StrutsException(ex);  
    }  
}

/\*\*  
 \* Load Action class for mapping and invoke the appropriate Action method, or go directly to the Result.  
 \* <p/>  
 \* This method first creates the action context from the given parameters,  
 \* and then loads an <tt>ActionProxy</tt> from the given action name and namespace.  
 \* After that, the Action method is executed and output channels through the response object.  
 \* Actions not found are sent back to the user via the {@link Dispatcher#sendError} method,  
 \* using the 404 return code.  
 \* All other errors are reported by throwing a ServletException.  
 \*  
 \* @param request  the HttpServletRequest object  
 \* @param response the HttpServletResponse object  
 \* @param mapping  the action mapping object  
 \* @throws ServletException when an unknown error occurs (not a 404, but typically something that  
 \*                          would end up as a 5xx by the servlet container)  
 \* @param context Our ServletContext object  
 \*/  
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,  
                          ActionMapping mapping) throws ServletException {

    Map<String, Object> extraContext = createContextMap(request, response, mapping, context);

    // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action  
    ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS\_VALUESTACK\_KEY);  
    boolean nullStack = stack == null;  
    if (nullStack) {  
        ActionContext ctx = ActionContext.getContext();  
        if (ctx != null) {  
            stack = ctx.getValueStack();  
        }  
    }  
    if (stack != null) {  
        extraContext.put(ActionContext.VALUE\_STACK, valueStackFactory.createValueStack(stack));  
    }

    String timerKey = "Handling request from Dispatcher";  
    try {  
        UtilTimerStack.push(timerKey);  
        String namespace = mapping.getNamespace();  
        String name = mapping.getName();  
        String method = mapping.getMethod();

        Configuration config = configurationManager.getConfiguration();  
        ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(  
                namespace, name, method, extraContext, true, false);

        request.setAttribute(ServletActionContext.STRUTS\_VALUESTACK\_KEY, proxy.getInvocation().getStack());

        // if the ActionMapping says to go straight to a result, do it!  
        if (mapping.getResult() != null) {  
            Result result = mapping.getResult();  
            result.execute(proxy.getInvocation());  
        } else {  
            proxy.execute();  
        }

        // If there was a previous value stack then set it back onto the request  
        if (!nullStack) {  
            request.setAttribute(ServletActionContext.STRUTS\_VALUESTACK\_KEY, stack);  
        }  
    } catch (ConfigurationException e) {  
        // WW-2874 Only log error if in devMode  
        if(devMode) {  
            LOG.error("Could not find action or result", e);  
        }  
        else {  
            LOG.warn("Could not find action or result", e);  
        }  
        sendError(request, response, context, HttpServletResponse.SC\_NOT\_FOUND, e);  
    } catch (Exception e) {  
        sendError(request, response, context, HttpServletResponse.SC\_INTERNAL\_SERVER\_ERROR, e);  
    } finally {  
        UtilTimerStack.pop(timerKey);  
    }  
}

/\*\*  
 \* Create a context map containing all the wrapped request objects  
 \*  
 \* @param request The servlet request  
 \* @param response The servlet response  
 \* @param mapping The action mapping  
 \* @param context The servlet context  
 \* @return A map of context objects  
 \*/  
public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,  
        ActionMapping mapping, ServletContext context) {

    // request map wrapping the http request objects  
    Map requestMap = new RequestMap(request);

    // parameters map wrapping the http parameters.  ActionMapping parameters are now handled and applied separately  
    Map params = new HashMap(request.getParameterMap());

    // session map wrapping the http session  
    Map session = new SessionMap(request);

    // application map wrapping the ServletContext  
    Map application = new ApplicationMap(context);

    Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);

    if (mapping != null) {  
        extraContext.put(ServletActionContext.ACTION\_MAPPING, mapping);  
    }  
    return extraContext;  
}

/\*\*  
 \* Merge all application and servlet attributes into a single <tt>HashMap</tt> to represent the entire  
 \* <tt>Action</tt> context.  
 \*  
 \* @param requestMap     a Map of all request attributes.  
 \* @param parameterMap   a Map of all request parameters.  
 \* @param sessionMap     a Map of all session attributes.  
 \* @param applicationMap a Map of all servlet context attributes.  
 \* @param request        the HttpServletRequest object.  
 \* @param response       the HttpServletResponse object.  
 \* @param servletContext the ServletContextmapping object.  
 \* @return a HashMap representing the <tt>Action</tt> context.  
 \*/  
public HashMap<String,Object> createContextMap(Map requestMap,  
                                Map parameterMap,  
                                Map sessionMap,  
                                Map applicationMap,  
                                HttpServletRequest request,  
                                HttpServletResponse response,  
                                ServletContext servletContext) {  
    HashMap<String,Object> extraContext = new HashMap<String,Object>();  
    extraContext.put(ActionContext.PARAMETERS, new HashMap(parameterMap));  
    extraContext.put(ActionContext.SESSION, sessionMap);  
    extraContext.put(ActionContext.APPLICATION, applicationMap);

    Locale locale;  
    if (defaultLocale != null) {  
        locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());  
    } else {  
        locale = request.getLocale();  
    }

    extraContext.put(ActionContext.LOCALE, locale);  
    //extraContext.put(ActionContext.DEV\_MODE, Boolean.valueOf(devMode));

    extraContext.put(StrutsStatics.HTTP\_REQUEST, request);  
    extraContext.put(StrutsStatics.HTTP\_RESPONSE, response);  
    extraContext.put(StrutsStatics.SERVLET\_CONTEXT, servletContext);

    // helpers to get access to request/session/application scope  
    extraContext.put("request", requestMap);  
    extraContext.put("session", sessionMap);  
    extraContext.put("application", applicationMap);  
    extraContext.put("parameters", parameterMap);

    AttributeMap attrMap = new AttributeMap(extraContext);  
    extraContext.put("attr", attrMap);

    return extraContext;  
}

/\*\*  
 \* Return the path to save uploaded files to (this is configurable).  
 \*  
 \* @return the path to save uploaded files to  
 \* @param servletContext Our ServletContext  
 \*/  
private String getSaveDir(ServletContext servletContext) {  
    String saveDir = multipartSaveDir.trim();

    if (saveDir.equals("")) {  
        File tempdir = (File) servletContext.getAttribute("javax.servlet.context.tempdir");  
        LOG.info("Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir");

        if (tempdir != null) {  
            saveDir = tempdir.toString();  
            setMultipartSaveDir(saveDir);  
        }  
    } else {  
        File multipartSaveDir = new File(saveDir);

        if (!multipartSaveDir.exists()) {  
            if (multipartSaveDir.mkdir() == false) {  
                String logMessage;  
            try {  
                    logMessage = "Could not find create multipart save directory '"+multipartSaveDir.getCanonicalPath()+"'.";  
            } catch (IOException e) {  
                    logMessage = "Could not find create multipart save directory '"+multipartSaveDir.toString()+"'.";  
            }  
            if(devMode) {  
                    LOG.error(logMessage);  
            }  
            else {  
                    LOG.warn(logMessage);  
            }  
            }  
        }  
    }

    if (LOG.isDebugEnabled()) {  
        LOG.debug("saveDir=" + saveDir);  
    }

    return saveDir;  
}

/\*\*  
 \* Prepare a request, including setting the encoding and locale.  
 \*  
 \* @param request The request  
 \* @param response The response  
 \*/  
public void prepare(HttpServletRequest request, HttpServletResponse response) {  
    String encoding = null;  
    if (defaultEncoding != null) {  
        encoding = defaultEncoding;  
    }

    Locale locale = null;  
    if (defaultLocale != null) {  
        locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());  
    }

    if (encoding != null) {  
        try {  
            request.setCharacterEncoding(encoding);  
        } catch (Exception e) {  
            LOG.error("Error setting character encoding to '" + encoding + "' - ignoring.", e);  
        }  
    }

    if (locale != null) {  
        response.setLocale(locale);  
    }

    if (paramsWorkaroundEnabled) {  
        request.getParameter("foo"); // simply read any parameter (existing or not) to "prime" the request  
    }  
}

/\*\*  
 \* Wrap and return the given request or return the original request object.  
 \* </p>  
 \* This method transparently handles multipart data as a wrapped class around the given request.  
 \* Override this method to handle multipart requests in a special way or to handle other types of requests.  
 \* Note, {@link org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper} is  
 \* flexible - look first to that object before overriding this method to handle multipart data.  
 \*  
 \* @param request the HttpServletRequest object.  
 \* @param servletContext Our ServletContext object  
 \* @return a wrapped request or original request.  
 \* @see org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper  
 \* @throws java.io.IOException on any error.  
 \*/  
public HttpServletRequest wrapRequest(HttpServletRequest request, ServletContext servletContext) throws IOException {  
    // don't wrap more than once  
    if (request instanceof StrutsRequestWrapper) {  
        return request;  
    }

    String content\_type = request.getContentType();  
    if (content\_type != null && content\_type.indexOf("multipart/form-data") != -1) {  
        MultiPartRequest mpr = null;  
        //check for alternate implementations of MultiPartRequest  
        Set<String> multiNames = getContainer().getInstanceNames(MultiPartRequest.class);  
        if (multiNames != null) {  
            for (String multiName : multiNames) {  
                if (multiName.equals(multipartHandlerName)) {  
                    mpr = getContainer().getInstance(MultiPartRequest.class, multiName);  
                }  
            }  
        }  
        if (mpr == null ) {  
            mpr = getContainer().getInstance(MultiPartRequest.class);  
        }  
        request = new MultiPartRequestWrapper(mpr, request, getSaveDir(servletContext));  
    } else {  
        request = new StrutsRequestWrapper(request);  
    }

    return request;  
}

/\*\*  
 \* Send an HTTP error response code.  
 \*  
 \* @param request  the HttpServletRequest object.  
 \* @param response the HttpServletResponse object.  
 \* @param code     the HttpServletResponse error code (see {@link javax.servlet.http.HttpServletResponse} for possible error codes).  
 \* @param e        the Exception that is reported.  
 \* @param ctx      the ServletContext object.  
 \*/  
public void sendError(HttpServletRequest request, HttpServletResponse response,  
        ServletContext ctx, int code, Exception e) {  
    if (devMode) {  
        response.setContentType("text/html");

        try {  
            FreemarkerManager mgr = getContainer().getInstance(FreemarkerManager.class);

            freemarker.template.Configuration config = mgr.getConfiguration(ctx);  
            Template template = config.getTemplate("/org/apache/struts2/dispatcher/error.ftl");

            List<Throwable> chain = new ArrayList<Throwable>();  
            Throwable cur = e;  
            chain.add(cur);  
            while ((cur = cur.getCause()) != null) {  
                chain.add(cur);  
            }

            HashMap<String,Object> data = new HashMap<String,Object>();  
            data.put("exception", e);  
            data.put("unknown", Location.UNKNOWN);  
            data.put("chain", chain);  
            data.put("locator", new Locator());  
            template.process(data, response.getWriter());  
            response.getWriter().close();  
        } catch (Exception exp) {  
            try {  
                response.sendError(code, "Unable to show problem report: " + exp);  
            } catch (IOException ex) {  
                // we're already sending an error, not much else we can do if more stuff breaks  
            }  
        }  
    } else {  
        try {  
            // WW-1977: Only put errors in the request when code is a 500 error  
            if (code == HttpServletResponse.SC\_INTERNAL\_SERVER\_ERROR) {  
                // send a http error response to use the servlet defined error handler  
                // make the exception availible to the web.xml defined error page  
                request.setAttribute("javax.servlet.error.exception", e);

                // for compatibility  
                request.setAttribute("javax.servlet.jsp.jspException", e);  
            }

            // send the error response  
            response.sendError(code, e.getMessage());  
        } catch (IOException e1) {  
            // we're already sending an error, not much else we can do if more stuff breaks  
        }  
    }  
}

/\*\*  
 \* Provide an accessor class for static XWork utility.  
 \*/  
public static class Locator {  
    public Location getLocation(Object obj) {  
        Location loc = LocationUtils.getLocation(obj);  
        if (loc == null) {  
            return Location.UNKNOWN;  
        }  
        return loc;  
    }  
}

/\*\*  
 \* Expose the ConfigurationManager instance.  
 \*  
 \* @return The instance  
 \*/  
public ConfigurationManager getConfigurationManager() {  
    return configurationManager;  
}

/\*\*  
 \* Modify the ConfigurationManager instance  
 \*  
 \* @param mgr The configuration manager  
 \*/  
public void setConfigurationManager(ConfigurationManager mgr) {  
    this.configurationManager = mgr;  
}

/\*\*  
 \* Expose the dependency injection container.  
 \* @return Our dependency injection container  
 \*/  
public Container getContainer() {  
    ConfigurationManager mgr = getConfigurationManager();  
    if (mgr == null) {  
        throw new IllegalStateException("The configuration manager shouldn't be null");  
    } else {  
        Configuration config = mgr.getConfiguration();  
        if (config == null) {  
            throw new IllegalStateException("Unable to load configuration");  
        } else {  
            return config.getContainer();  
        }  
    }  
}  

}

/*
* Copyright (c) 2002-2007 by OpenSymphony
* All rights reserved.
*/
package com.opensymphony.xwork2;

import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;

import java.util.Map;

/**
* Default factory for {@link com.opensymphony.xwork2.ActionProxyFactory}.
*
* @author Jason Carreira
*/
public class DefaultActionProxyFactory implements ActionProxyFactory {

protected Container container;

public DefaultActionProxyFactory() {  
    super();  
}

@Inject  
public void setContainer(Container container) {  
    this.container = container;  
}

public ActionProxy createActionProxy(String namespace, String actionName, Map<String, Object> extraContext) {  
    return createActionProxy(namespace, actionName, null, extraContext, true, true);  
}

public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext) {  
    return createActionProxy(namespace, actionName, methodName, extraContext, true, true);  
}

public ActionProxy createActionProxy(String namespace, String actionName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) {  
    return createActionProxy(namespace, actionName, null, extraContext, executeResult, cleanupContext);  
}

public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) {

    ActionInvocation inv = new DefaultActionInvocation(extraContext, true);  
    container.inject(inv);  
    return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);  
}

public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, boolean executeResult, boolean cleanupContext) {

    return createActionProxy(inv, namespace, actionName, null, executeResult, cleanupContext);  
}

public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {

    DefaultActionProxy proxy = new DefaultActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);  
    container.inject(proxy);  
    proxy.prepare();  
    return proxy;  
}

}