/*
* $Id: Dispatcher.java 566474 2007-08-16 02:55:44Z jholmes $
*
* 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.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.StrutsStatics;
import org.apache.struts2.config.*;
import org.apache.struts2.config.ClasspathConfigurationProvider.ClasspathPageLocator;
import org.apache.struts2.config.ClasspathConfigurationProvider.PageLocator;
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.util.FileManager;
import com.opensymphony.xwork2.*;
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.providers.XmlConfigurationProvider;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.LocalizedTextUtil;
import com.opensymphony.xwork2.util.ObjectTypeDeterminer;
import com.opensymphony.xwork2.util.ObjectTypeDeterminerFactory;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.ValueStackFactory;
import com.opensymphony.xwork2.util.location.Location;
import com.opensymphony.xwork2.util.location.LocationUtils;
import com.opensymphony.xwork2.util.location.LocatableProperties;
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
* @see org.apache.struts2.portlet.dispatcher.Jsr168Dispatcher
*/
public class Dispatcher {
/**
* Provide a logging instance.
*/
private static final Log LOG = LogFactory.getLog(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 ArrayList<DispatcherListener>();
/**
* Store ConfigurationManager instance, set on init.
*/
private ConfigurationManager configurationManager;
/**
* Store whether portlet support is active
* (set to true by Jsr168Dispatcher).
*/
private static boolean portletSupportActive;
/**
* Store state of StrutsConstants.STRUTS_DEVMODE setting.
*/
private static boolean devMode;
/**
* Store state of StrutsConstants.STRUTS_I18N_ENCODING setting.
*/
private static String defaultEncoding;
/**
* Store state of StrutsConstants.STRUTS_LOCALE setting.
*/
private static String defaultLocale;
/**
* Store state of StrutsConstants.STRUTS_MULTIPART_SAVEDIR setting.
*/
private static String multipartSaveDir;
/**
* 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);
// Tie the ObjectFactory threadlocal instance to this Dispatcher instance
if (instance != null) {
Container cont = instance.getContainer();
if (cont != null) {
ObjectFactory.setObjectFactory(cont.getInstance(ObjectFactory.class));
} else {
LOG.warn("This dispatcher instance doesn't have a container, so the object factory won't be set.");
}
} else {
ObjectFactory.setObjectFactory(null);
}
}
/**
* Add a dispatcher lifecycle listener.
*
* @param listener The listener to add
*/
public static synchronized void addDispatcherListener(DispatcherListener listener) {
dispatcherListeners.add(listener);
}
/**
* Remove a specific dispatcher lifecycle listener.
*
* @param listener The listener
*/
public static synchronized void removeDispatcherListener(DispatcherListener listener) {
dispatcherListeners.remove(listener);
}
private ServletContext servletContext;
private Map<String, String> initParams;
/**
* 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 static 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 static void setDefaultLocale(String val) {
defaultLocale = val;
}
/**
* Modify state of StrutsConstants.STRUTS_I18N_ENCODING setting.
* @param val New setting
*/
@Inject(StrutsConstants.STRUTS_I18N_ENCODING)
public static void setDefaultEncoding(Stri