/*
* $Id: ActionServlet.java 264684 2005-08-30 03:08:01Z niallp $
*
* Copyright 2000-2005 The Apache Software Foundation.
*
* 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.apache.struts.action;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.MissingResourceException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.beanutils.converters.BigDecimalConverter;
import org.apache.commons.beanutils.converters.BigIntegerConverter;
import org.apache.commons.beanutils.converters.BooleanConverter;
import org.apache.commons.beanutils.converters.ByteConverter;
import org.apache.commons.beanutils.converters.CharacterConverter;
import org.apache.commons.beanutils.converters.DoubleConverter;
import org.apache.commons.beanutils.converters.FloatConverter;
import org.apache.commons.beanutils.converters.IntegerConverter;
import org.apache.commons.beanutils.converters.LongConverter;
import org.apache.commons.beanutils.converters.ShortConverter;
import org.apache.commons.collections.FastHashMap;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.RuleSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.Globals;
import org.apache.struts.config.ConfigRuleSet;
import org.apache.struts.config.DataSourceConfig;
import org.apache.struts.config.FormBeanConfig;
import org.apache.struts.config.MessageResourcesConfig;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.config.ModuleConfigFactory;
import org.apache.struts.config.PlugInConfig;
import org.apache.struts.util.MessageResources;
import org.apache.struts.util.MessageResourcesFactory;
import org.apache.struts.util.ModuleUtils;
import org.apache.struts.util.RequestUtils;
import org.apache.struts.util.ServletContextWriter;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* <p><strong>ActionServlet</strong> provides the "controller" in the
* Model-View-Controller (MVC) design pattern for web applications that is
* commonly known as "Model 2". This nomenclature originated with a
* description in the JavaServerPages Specification, version 0.92, and has
* persisted ever since (in the absence of a better name).</p>
*
* <p>Generally, a "Model 2" application is architected as follows:</p>
* <ul>
* <li>The user interface will generally be created with server pages, which
* will not themselves contain any business logic. These pages represent
* the "view" component of an MVC architecture.</li>
* <li>Forms and hyperlinks in the user interface that require business logic
* to be executed will be submitted to a request URI that is mapped to this
* servlet.</li>
* <li>There can be <b>one</b> instance of this servlet class,
* which receives and processes all requests that change the state of
* a user's interaction with the application. The servlet delegates the
* handling of a request to a {@link RequestProcessor} object. This component
* represents the "controller" component of an MVC architecture.</li>
* <li>The <code>RequestProcessor</code> selects and invokes an {@link Action} class to perform
* the requested business logic, or delegates the response to another resource.</li>
* <li>The <code>Action</code> classes can manipulate the state of the application's
* interaction with the user, typically by creating or modifying JavaBeans
* that are stored as request or session attributes (depending on how long
* they need to be available). Such JavaBeans represent the "model"
* component of an MVC architecture.</li>
* <li>Instead of producing the next page of the user interface directly,
* <code>Action</code> classes generally return an {@link ActionForward} to indicate
* which resource should handle the response. If the <code>Action</code>
* does not return null, the <code>RequestProcessor</code> forwards or
* redirects to the specified resource (by utilizing
* <code>RequestDispatcher.forward</code> or <code>Response.sendRedirect</code>)
* so as to produce the next page of the user interface.</li>
* </ul>
*
* <p>The standard version of <code>RequestsProcessor</code> implements the
* following logic for each incoming HTTP request. You can override
* some or all of this functionality by subclassing this object and
* implementing your own version of the processing.</p>
* <ul>
* <li>Identify, from the incoming request URI, the substring that will be
* used to select an action procedure.</li>
* <li>Use this substring to map to the Java class name of the corresponding
* action class (an implementation of the <code>Action</code> interface).
* </li>
* <li>If this is the first request for a particular <code>Action</code> class,
* instantiate an instance of that class and cache it for future use.</li>
* <li>Optionally populate the properties of an <code>ActionForm</code> bean
* associated with this mapping.</li>
* <li>Call the <code>execute</code> method of this <code>Action</code> class, passing
* on a reference to the mapping that was used, the relevant form-bean
* (if any), and the request and the response that were passed to the
* controller by the servlet container (thereby providing access to any
* specialized properties of the mapping itself as well as to the
* ServletContext).
* </li>
* </ul>
*
* <p>The standard version of <code>ActionServlet</code> is configured based
* on the following servlet initialization parameters, which you will specify
* in the web application deployment descriptor (<code>/WEB-INF/web.xml</code>)
* for your application. Subclasses that specialize this servlet are free to
* define additional initialization parameters. </p>
* <ul>
* <li><strong>config</strong> - Comma-separated list of context-relative
* path(s) to the XML resource(s) containing the configuration information
* for the default module. (Multiple files support since Struts 1.1)
* [/WEB-INF/struts-config.xml].</li>
* <li><strong>config/${module}</strong> - Comma-separated list of
* Context-relative path(s) to the XML resource(s)
* containing the configuration information for the module that
* will use the specified prefix (/${module}). This can be repeated as many
* times as required for multiple modules. (Since Struts 1.1)</li>
* <li><strong>configFactory</strong> - The Java class name of the
* <code>ModuleConfigFactory</code> used to create the implementation of the
* <code>ModuleConfig</code> interface.
* [org.apache.struts.config.impl.DefaultModuleConfigFactory]
* </li>
* <li><strong>convertNull</strong> - Force simulation of the Struts 1.0 behavior
* when populating forms. If set to true, the numeric Java wrapper class types
* (like <code>java.lang.Integer</code>) will default to null (rather than 0).
* (Since Struts 1.1) [false] </li>
* <li><strong>rulesets</strong> - Comma-delimited list of fully qualified
* classnames of additional <code>org.apache.commons.digester.RuleSet</code>
* instances that should be added to the <code>Digester</code> that will
* be processing <code>struts-config.xml</code> files. By default, only
* the <code>RuleSet</code> for the standard configuration elements is
* loaded. (Since Struts 1.1)</li>
* <li><strong>validating</strong> - Should we use a validating XML parser to
* process the configuration file (strongly recommended)? [true]</li>
* </ul>
*
* @version $Rev: 264684 $ $Date: 2005-08-30 04:08:01 +0100 (Tue, 30 Aug 2005) $
*/
public class ActionServlet extends HttpServlet {
// ----------------------------------------------------- Instance Variables
/**
* <p>Comma-separated list of context-relative path(s) to our configuration
* resource(s) for the default module.</p>
*/
protected String config = "/WEB-INF/struts-config.xml";
/**
* <p>The Digester used to produce ModuleConfig objects from a
* Struts configuration file.</p>
*
* @since Struts 1.1
*/
protected Digester configDigester = null;
/**
* <p>The flag to request backwards-compatible conversions for form bean
* properties of the Java wrapper class types.</p>
*
* @since Struts 1.1
*/
protected boolean convertNull = false;
/**
* <p>The JDBC data sources that has been configured for this module,
* if any, keyed by the servlet context attribute under which they are
* stored.</p>
*/
protected FastHashMap dataSources = new FastHashMap();
/**
* <p>The resources object for our internal resources.</p>
*/
protected MessageResources internal = null;
/**
* <p>The Java base name of our internal resources.</p>
* @since Struts 1.1
*/
protected String internalName = "org.apache.struts.action.ActionResources";
/**
* <p>Commons Logging instance.</p>
*
* @since Struts 1.1
*/
protected static Log log = LogFactory.getLog(ActionServlet.class);
/**
* <p>The <code>RequestProcessor</code> instance we will use to process
* all incoming requests.</p>
*
* @since Struts 1.1
*/
protected RequestProcessor processor = null;
/**
* <p>The set of public identifiers, and corresponding resource names, for
* the versions of the configuration file DTDs that we know about. There
* <strong>MUST</strong> be an even number of Strings in this list!</p>
*/
protected String registrations[] = {
"-//Apache Software Foundation//DTD Struts Configuration 1.0//EN",
"/org/apache/struts/resources/struts-config_1_0.dtd",
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN",
"/org/apache/struts/resources/struts-config_1_1.dtd",
"-//Apache Software Foundation//DTD Struts Configuration 1.2//EN",
"/org/apache/struts/resources/struts-config_1_2.dtd",
"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",
"/org/apache/struts/resources/web-app_2_2.dtd",
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
"/org/apache/struts/resources/web-app_2_3.dtd"
};
/**
* <p>The URL pattern to which we are mapped in our web application
* deployment descriptor.</p>
*/
protected String servletMapping = null; // :FIXME: - multiples?
/**
* <p>The servlet name under which we are registered in our web application
* deployment descriptor.</p>
*/
protected String servletName = null;
// ---------------------------------------------------- HttpServlet Methods
/**
* <p>Gracefully shut down this controller servlet, releasing any resources
* that were allocated at initialization.</p>
*/
public void destroy() {
if (log.isDebugEnabled()) {
log.debug(internal.getMessage("finalizing"));
}
destroyModules();
destroyInternal();
getServletContext().removeAttribute(Globals.ACTION_SERVLET_KEY);
// Release our LogFactory and Log instances (if any)
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = ActionServlet.class.getClassLoader();
}
try {
LogFactory.release(classLoader);
} catch (Throwable t) {
; // Servlet container doesn't have the latest version
; // of commons-logging-api.jar installed
// :FIXME: Why is this dependent on the container's version of commons-logging?
// Shouldn't this depend on the version packaged with Struts?
/*
Reason: LogFactory.release(classLoader); was added as
an attempt to investigate the OutOfMemory error reported on Bugzilla #14042.
It was committed for version 1.136 by craigmcc
*/
}
PropertyUtils.clearDescriptors();
}
/**
* <p>Initialize this servlet. Most of the processing has been factored into
* support methods so that you can override particular functionality at a
* fairly granular level.</p>
*
* @exception ServletException if we cannot configure ourselves correctly
*/
public void init() throws ServletException {
// Wraps the entire initialization in a try/catch to better handle
// unexpected exceptions and errors to provide better feedback
// to the developer
try {
initInternal();
initOther();
initServlet();
getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);
initModuleConfigFactory();
// Initialize modules as needed
ModuleConfig moduleConfig = initModuleConfig("", config);
initModuleMessageResources(moduleConfig);
initModuleDataSources(moduleConfig);
initModulePlugIns(moduleConfig);
moduleConfig.freeze();
Enumeration names = getServletConfig().getInitParameterNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
if (!name.startsWith("config/")) {
continue;
}
String prefix = name.substring(6);
moduleConfig = initModuleConfig
(prefix, getServletConfig().getInitParameter(name));
initModuleMessageResources(moduleConfig);
initModuleDataSources(moduleConfig);
initModulePlugIns(moduleConfig);
moduleConfig.freeze();
}
this.initModulePrefixes(this.getServletContext());
this.destroyConfigDigester();
} catch (UnavailableException ex) {
throw ex;
} catch (Throwable t) {
// The follow error message is not retrieved from internal message
// resources as they may not have been able to have been
// initialized
log.error("Unable to initialize Struts ActionServlet due to an "
+ "unexpected exception or error thrown, so marking the "
+ "servlet as unavailable. Most likely, this is due to an "
+ "incorrect or missing library dependency.", t);
throw new UnavailableException(t.getMessage());
}
}
/**
* <p>Saves a String[] of module prefixes in the ServletContext under
* Globals.MODULE_PREFIXES_KEY. <strong>NOTE</strong> -
* the "" prefix for the default module is not included in this list.</p>
*
* @param context The servlet context.
* @since Struts 1.2
*/
protected void initModulePrefixes(ServletContext context) {
ArrayList prefixList = new ArrayList();
Enumeration names = context.getAttributeNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
if (!name.startsWith(Globals.MODULE_KEY)) {
continue;
}
String prefix = name.substring(Globals.MODULE_KEY.length());
if (prefix.length() > 0) {
prefixList.add(prefix);
}
}
String[] prefixes = (String[]) prefixList.toArray(new String[prefixList.size()]);
context.setAttribute(Globals.MODULE_PREFIXES_KEY, prefixes);
}
/**
* <p>Process an HTTP "GET" request.</p>
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet exception occurs
*/
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
process(request, response);
}
/**
* <p>Process an HTTP "POST" request.</p>
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet exception occurs
*/
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
process(request, response);
}
// --------------------------------------------------------- Public Methods
/**
* <p>Remember a servlet mapping from our web application deployment
* descriptor, if it is for this servlet.</p>
*
* @param servletName The name of the servlet being mapped
* @param urlPattern The URL pattern to which this servlet is mapped
*/
public void addServletMapping(String servletName, String urlPattern) {
if (log.isDebugEnabled()) {
log.debug("Process servletName=" + servletName +
", urlPattern=" + urlPattern);
}
if (servletName == null) {
return;
}
if (servletName.equals(this.servletName)) {
this.servletMapping = urlPattern;
}
}
/**
* <p>Return the <code>MessageResources</code> instance containing our
* internal message strings.</p>
*
* @since Struts 1.1
*/
public MessageResources getInternal() {
return (this.internal);
}
// ------------------------------------------------------ Protected Methods
/**
* <p>Gracefully terminate use of any modules associated with this
* application (if any).</p>
*
* @since Struts 1.1
*/
protected void destroyModules() {
ArrayList values = new ArrayList();
Enumeration names = getServletContext().getAttributeNames();
while (names.hasMoreElements()) {
values.add(names.nextElement());
}
Iterator keys = values.iterator();
while (keys.hasNext()) {
String name = (String) keys.next();
Object value = getServletContext().getAttribute(name);
if (!(value instanceof ModuleConfig)) {
continue;
}
ModuleConfig config = (ModuleConfig) value;
if (this.getProcessorForModule(config) != null) {
this.getProcessorForModule(config).destroy();
}
getServletContext().removeAttribute(name);
PlugIn plugIns[] =
(PlugIn[]) getServletContext().getAttribute(
Globals.PLUG_INS_KEY + config.getPrefix());
if (plugIns != null) {
for (int i = 0; i < plugIns.length; i++) {
int j = plugIns.length - (i + 1);
plugIns[j].destroy();
}
getServletContext().removeAttribute(
Globals.PLUG_INS_KEY + config.getPrefix());
}
}
}
/**
* <p>Gracefully release any configDigester instance that we have created.</p>
*
* @since Struts 1.1
*/
protected void destroyConfigDigester() {
configDigester = null;
}
/**
* <p>Gracefully terminate use of the internal MessageResources.</p>
*/
protected void destroyInternal() {
internal = null;
}
/**
* <p>Return the module configuration object for the currently selected
* module.</p>
*
* @param request The servlet request we are processing
* @since Struts 1.1
*/
protected ModuleConfig getModuleConfig
(HttpServletRequest request) {
ModuleConfig config = (ModuleConfig)
request.getAttribute(Globals.MODULE_KEY);
if (config == null) {
config = (ModuleConfig)
getServletContext().getAttribute(Globals.MODULE_KEY);
}
return (config);
}
/**
* <p>Look up and return the {@link RequestProcessor} responsible for the
* specified module, creating a new one if necessary.</p>
*
* @param config The module configuration for which to
* acquire and return a RequestProcessor.
*
* @exception ServletException if we cannot instantiate a RequestProcessor
* instance
* @since Struts 1.1
*/
protected synchronized RequestProcessor getRequestProcessor(ModuleConfig config)
throws ServletException {
// :FIXME: Document UnavailableException?
RequestProcessor processor = this.getProcessorForModule(config);
if (processor == null) {
try {
processor =
(RequestProcessor) RequestUtils.applicationInstance(
config.getControllerConfig().getProcessorClass());
} catch (Exception e) {
throw new UnavailableException(
"Cannot initialize RequestProcessor of class "
+ config.getControllerConfig().getProcessorClass()
+ ": "
+ e);
}
processor.init(this, config);
String key = Globals.REQUEST_PROCESSOR_KEY + config.getPrefix();
getServletContext().setAttribute(key, processor);
}
return (processor);
}
/**
* <p>Returns the RequestProcessor for the given module or null if one does not
* exist. This method will not create a RequestProcessor.</p>
*
* @param config The ModuleConfig.
*/
private RequestProcessor getProcessorForModule(ModuleConfig config) {
String key = Globals.REQUEST_PROCESSOR_KEY + config.getPrefix();
return (RequestProcessor) getServletContext().getAttribute(key);
}
/**
* <p>Initialize the factory used to create the module configuration.</p>
* @since Struts 1.2
*/
protected void initModuleConfigFactory(){
String configFactory = getServletConfig().getInitParameter("configFactory");
if (configFactory != null) {
ModuleConfigFactory.setFactoryClass(configFactory);
}
}
/**
* <p>Initialize the module configuration information for the
* specified module.</p>
*
* @param prefix Module prefix for this module
* @param paths Comma-separated list of context-relative resource path(s)
* for this modules's configuration resource(s)
*
* @exception ServletException if initialization cannot be performed
* @since Struts 1.1
*/
protected ModuleConfig initModuleConfig(String prefix, String paths)
throws ServletException {
// :FIXME: Document UnavailableException? (Doesn't actually throw anything)
if (log.isDebugEnabled()) {
log.debug(
"Initializing module path '"
+ prefix
+ "' configuration from '"
+ paths
+ "'");
}
// Parse the configuration for this module
ModuleConfigFactory factoryObject = ModuleConfigFactory.createFactory();
ModuleConfig config = factoryObject.createModuleConfig(prefix);
// Configure the Digester instance we will use
Digester digester = initConfigDigester();
// Process each specified resource path
while (paths.length() > 0) {
digester.push(config);
String path = null;
int comma = paths.indexOf(',');
if (comma >= 0) {
path = paths.substring(0, comma).trim();
paths = paths.substring(comma + 1);
} else {
path = paths.trim();
paths = "";
}
if (path.length() < 1) {
break;
}
this.parseModuleConfigFile(digester, path);
}
getServletContext().setAttribute(
Globals.MODULE_KEY + config.getPrefix(),
config);
// Force creation and registration of DynaActionFormClass instances
// for all dynamic form beans we wil be using
FormBeanConfig fbs[] = config.findFormBeanConfigs();
for (int i = 0; i < fbs.length; i++) {
if (fbs[i].getDynamic()) {
fbs[i].getDynaActionFormClass();
}
}
return config;
}
/**
* <p>Parses one module config file.</p>
*
* @param digester Digester instance that does the parsing
* @param path The path to the config file to parse.
*
* @throws UnavailableException if file cannot be read or parsed
* @since Struts 1.2
*/
protected void parseModuleConfigFile(Digester digester, String path)
throws UnavailableException {
InputStream input = null;
try {
URL url = getServletContext().getResource(path);
// If the config isn't in the servlet context, try the class loader
// which allows the config files to be stored in a jar
if (url == null) {
url = getClass().getResource(path);
}
if (url == null) {
String msg = internal.getMessage("configMissing", path);
log.error(msg);
throw new UnavailableException(msg);
}
InputSource is = new InputSource(url.toExternalForm());
input = url.openStream();
is.setByteStream(input);
digester.parse(is);
} catch (MalformedURLException e) {
handleConfigException(path, e);
} catch (IOException e) {
handleConfigException(path, e);
} catch (SAXException e) {
handleConfigException(path, e);
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
throw new UnavailableException(e.getMessage());
}
}
}
}
/**
* <p>Simplifies exception handling in the <code>parseModuleConfigFile</code> method.<p>
* @param path
* @param e
* @throws UnavailableException as a wrapper around Exception
*/
private void handleConfigException(String path, Exception e)
throws UnavailableException {
String msg = internal.getMessage("configParse", path);
log.error(msg, e);
throw new UnavailableException(msg);
}
/**
* <p>Initialize the data sources for the specified module.</p>
*
* @param config ModuleConfig information for this module
*
* @exception ServletException if initialization cannot be performed
* @since Struts 1.1
*/
protected void initModuleDataSources(ModuleConfig config) throws ServletException {
// :FIXME: Document UnavailableException?
if (log.isDebugEnabled()) {
log.debug("Initializing module path '" + config.getPrefix() +
"' data sources");
}
ServletContextWriter scw =
new ServletContextWriter(getServletContext());
DataSourceConfig dscs[] = config.findDataSourceConfigs();
if (dscs == null) {
dscs = new DataSourceConfig[0];
}
dataSources.setFast(false);
for (int i = 0; i < dscs.length; i++) {
if (log.isDebugEnabled()) {
log.debug("Initializing module path '" + config.getPrefix() +
"' data source '" + dscs[i].getKey() + "'");
}
DataSource ds = null;
try {
ds = (DataSource)
RequestUtils.applicationInstance(dscs[i].getType());
BeanUtils.populate(ds, dscs[i].getProperties());
ds.setLogWriter(scw);
} catch (Exception e) {
log.error(internal.getMessage("dataSource.init", dscs[i].getKey()), e);
throw new UnavailableException
(internal.getMessage("dataSource.init", dscs[i].getKey()));
}
getServletContext().setAttribute
(dscs[i].getKey() + config.getPrefix(), ds);
dataSources.put(dscs[i].getKey(), ds);
}
dataSources.setFast(true);
}
/**
* <p>Initialize the plug ins for the specified module.</p>
*
* @param config ModuleConfig information for this module
*
* @exception ServletException if initialization cannot be performed
* @since Struts 1.1
*/
protected void initModulePlugIns
(ModuleConfig config) throws ServletException {
if (log.isDebugEnabled()) {
log.debug("Initializing module path '" + config.getPrefix() + "' plug ins");
}
PlugInConfig plugInConfigs[] = config.findPlugInConfigs();
PlugIn plugIns[] = new PlugIn[plugInConfigs.length];
getServletContext().setAttribute(Globals.PLUG_INS_KEY + config.getPrefix(), plugIns);
for (int i = 0; i < plugIns.length; i++) {
try {
plugIns[i] =
(PlugIn)RequestUtils.applicationInstance(plugInConfigs[i].getClassName());
BeanUtils.populate(plugIns[i], plugInConfigs[i].getProperties());
// Pass the current plugIn config object to the PlugIn.
// The property is set only if the plugin declares it.
// This plugin config object is needed by Tiles
try {
PropertyUtils.setProperty(
plugIns[i],
"currentPlugInConfigObject",
plugInConfigs[i]);
} catch (Exception e) {
// FIXME Whenever we fail silently, we must document a valid reason
// for doing so. Why should we fail silently if a property can't be set on
// the plugin?
/**
* Between version 1.138-1.140 cedric made these changes.
* The exceptions are caught to deal with containers applying strict security.
* This was in response to bug #15736
*
* Recommend that we make the currentPlugInConfigObject part of the PlugIn Interface if we can, Rob
*/
}
plugIns[i].init(this, config);
} catch (ServletException e) {
throw e;
} catch (Exception e) {
String errMsg =
internal.getMessage(
"plugIn.init",
plugInConfigs[i].getClassName());
log(errMsg, e);
throw new UnavailableException(errMsg);
}
}
}
/**
* <p>Initialize the application <code>MessageResources</code> for the specified
* module.</p>
*
* @param config ModuleConfig information for this module
*
* @exception ServletException if initialization cannot be performed
* @since Struts 1.1
*/
protected void initModuleMessageResources(ModuleConfig config)
throws ServletException {
MessageResourcesConfig mrcs[] = config.findMessageResourcesConfigs();
for (int i = 0; i < mrcs.length; i++) {
if ((mrcs[i].getFactory() == null)
|| (mrcs[i].getParameter() == null)) {
continue;
}
if (log.isDebugEnabled()) {
log.debug(
"Initializing module path '"
+ config.getPrefix()
+ "' message resources from '"
+ mrcs[i].getParameter()
+ "'");
}
String factory = mrcs[i].getFactory();
MessageResourcesFactory.setFactoryClass(factory);
MessageResourcesFactory factoryObject =
MessageResourcesFactory.createFactory();
factoryObject.setConfig(mrcs[i]);
MessageResources resources =
factoryObject.createResources(mrcs[i].getParameter());
resources.setReturnNull(mrcs[i].getNull());
resources.setEscape(mrcs[i].isEscape());
getServletContext().setAttribute(
mrcs[i].getKey() + config.getPrefix(),
resources);
}
}
/**
* <p>Create (if needed) and return a new <code>Digester</code>
* instance that has been initialized to process Struts module
* configuration files and configure a corresponding <code>ModuleConfig</code>
* object (which must be pushed on to the evaluation stack before parsing
* begins).</p>
*
* @exception ServletException if a Digester cannot be configured
* @since Struts 1.1
*/
protected Digester initConfigDigester() throws ServletException {
// :FIXME: Where can ServletException be thrown?
// Do we have an existing instance?
if (configDigester != null) {
return (configDigester);
}
// Create a new Digester instance with standard capabilities
configDigester = new Digester();
configDigester.setNamespaceAware(true);
configDigester.setValidating(this.isValidating());
configDigester.setUseContextClassLoader(true);
configDigester.addRuleSet(new ConfigRuleSet());
for (int i = 0; i < registrations.length; i += 2) {
URL url = this.getClass().getResource(registrations[i+1]);
if (url != null) {
configDigester.register(registrations[i], url.toString());
}
}
this.addRuleSets();
// Return the completely configured Digester instance
return (configDigester);
}
/**
* <p>Add any custom RuleSet instances to configDigester that have
* been specified in the <code>rulesets</code> init parameter.</p>
*
* @throws ServletException
*/
private void addRuleSets() throws ServletException {
String rulesets = getServletConfig().getInitParameter("rulesets");
if (rulesets == null) {
rulesets = "";
}
rulesets = rulesets.trim();
String ruleset = null;
while (rulesets.length() > 0) {
int comma = rulesets.indexOf(",");
if (comma < 0) {
ruleset = rulesets.trim();
rulesets = "";
} else {
ruleset = rulesets.substring(0, comma).trim();
rulesets = rulesets.substring(comma + 1).trim();
}
if (log.isDebugEnabled()) {
log.debug("Configuring custom Digester Ruleset of type " + ruleset);
}
try {
RuleSet instance = (RuleSet) RequestUtils.applicationInstance(ruleset);
this.configDigester.addRuleSet(instance);
} catch (Exception e) {
log.error("Exception configuring custom Digester RuleSet", e);
throw new ServletException(e);
}
}
}
/**
* <p>Check the status of the <code>validating</code> initialization parameter.</p>
*
* @return true if the module Digester should validate.
*/
private boolean isValidating() {
boolean validating = true;
String value = getServletConfig().getInitParameter("validating");
if ("false".equalsIgnoreCase(value)
|| "no".equalsIgnoreCase(value)
|| "n".equalsIgnoreCase(value)
|| "0".equalsIgnoreCase(value)) {
validating = false;
}
return validating;
}
/**
* <p>Initialize our internal MessageResources bundle.</p>
*
* @exception ServletException if we cannot initialize these resources
*/
protected void initInternal() throws ServletException {
// :FIXME: Document UnavailableException
try {
internal = MessageResources.getMessageResources(internalName);
} catch (MissingResourceException e) {
log.error("Cannot load internal resources from '" + internalName + "'",
e);
throw new UnavailableException
("Cannot load internal resources from '" + internalName + "'");
}
}
/**
* <p>Initialize other global characteristics of the controller servlet.</p>
*
* @exception ServletException if we cannot initialize these resources
*/
protected void initOther() throws ServletException {
String value = null;
value = getServletConfig().getInitParameter("config");
if (value != null) {
config = value;
}
// Backwards compatibility for form beans of Java wrapper classes
// Set to true for strict Struts 1.0 compatibility
value = getServletConfig().getInitParameter("convertNull");
if ("true".equalsIgnoreCase(value)
|| "yes".equalsIgnoreCase(value)
|| "on".equalsIgnoreCase(value)
|| "y".equalsIgnoreCase(value)
|| "1".equalsIgnoreCase(value)) {
convertNull = true;
}
if (convertNull) {
ConvertUtils.deregister();
ConvertUtils.register(new BigDecimalConverter(null), BigDecimal.class);
ConvertUtils.register(new BigIntegerConverter(null), BigInteger.class);
ConvertUtils.register(new BooleanConverter(null), Boolean.class);
ConvertUtils.register(new ByteConverter(null), Byte.class);
ConvertUtils.register(new CharacterConverter(null), Character.class);
ConvertUtils.register(new DoubleConverter(null), Double.class);
ConvertUtils.register(new FloatConverter(null), Float.class);
ConvertUtils.register(new IntegerConverter(null), Integer.class);
ConvertUtils.register(new LongConverter(null), Long.class);
ConvertUtils.register(new ShortConverter(null), Short.class);
}
}
/**
* <p>Initialize the servlet mapping under which our controller servlet
* is being accessed. This will be used in the <code>&html:form></code>
* tag to generate correct destination URLs for form submissions.</p>
*
* @throws ServletException if error happens while scanning web.xml
*/
protected void initServlet() throws ServletException {
// Remember our servlet name
this.servletName = getServletConfig().getServletName();
// Prepare a Digester to scan the web application deployment descriptor
Digester digester = new Digester();
digester.push(this);
digester.setNamespaceAware(true);
digester.setValidating(false);
// Register our local copy of the DTDs that we can find
for (int i = 0; i < registrations.length; i += 2) {
URL url = this.getClass().getResource(registrations[i+1]);
if (url != null) {
digester.register(registrations[i], url.toString());
}
}
// Configure the processing rules that we need
digester.addCallMethod("web-app/servlet-mapping",
"addServletMapping", 2);
digester.addCallParam("web-app/servlet-mapping/servlet-name", 0);
digester.addCallParam("web-app/servlet-mapping/url-pattern", 1);
// Process the web application deployment descriptor
if (log.isDebugEnabled()) {
log.debug("Scanning web.xml for controller servlet mapping");
}
InputStream input =
getServletContext().getResourceAsStream("/WEB-INF/web.xml");
if (input == null) {
log.error(internal.getMessage("configWebXml"));
throw new ServletException(internal.getMessage("configWebXml"));
}
try {
digester.parse(input);
} catch (IOException e) {
log.error(internal.getMessage("configWebXml"), e);
throw new ServletException(e);
} catch (SAXException e) {
log.error(internal.getMessage("configWebXml"), e);
throw new ServletException(e);
} finally {
try {
input.close();
} catch (IOException e) {
log.error(internal.getMessage("configWebXml"), e);
throw new ServletException(e);
}
}
// Record a servlet context attribute (if appropriate)
if (log.isDebugEnabled()) {
log.debug("Mapping for servlet '" + servletName + "' = '" +
servletMapping + "'");
}
if (servletMapping != null) {
getServletContext().setAttribute(Globals.SERVLET_KEY, servletMapping);
}
}
/**
* <p>Perform the standard request processing for this request, and create
* the corresponding response.</p>
*
* @param request The servlet request we are processing
* @param response The servlet response we are creating
*
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet exception is thrown
*/
protected void process(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
ModuleUtils.getInstance().selectModule(request, getServletContext());
ModuleConfig config = getModuleConfig(request);
RequestProcessor processor = getProcessorForModule(config);
if (processor == null) {
processor = getRequestProcessor(config);
}
processor.process(request, response);
}
}
分享到:
相关推荐
Struts是Apache软件基金会下的一个开源项目,它是一款基于MVC(Model-View-Controller)设计模式的Java Web应用程序框架。这里的"struts-1.2.9-lib.zip"和"struts-1.2.9-src.zip"是Struts 1.2.9版本的两个重要组件。...
1. **ActionServlet**:这是Struts框架的心脏,是一个实现了Servlet API的Servlet,负责处理所有的HTTP请求,并根据配置信息将请求转发给相应的Action。 2. **Action**:Action类是业务逻辑的载体,它接收来自控制...
2. 创建`struts-config.xml`配置文件,并在web.xml中配置ActionServlet。 3. 编写Action、ActionForm和JSP页面,遵循Struts的MVC模式。 4. 配置服务器,如Tomcat,将应用部署上去。 **总结:** Struts 1.2.9是Java ...
3. Action:这是业务逻辑组件,处理由ActionServlet转发过来的请求,完成特定的业务操作,并返回一个表示下一步动作的ActionForward。 4. ActionMapping:定义了Action与请求URL之间的映射关系,以及ActionForm的...
- `struts-core.jar`:这是Struts的核心库,包含ActionServlet、ActionForm、Action、Dispatcher等关键类,它们是Struts框架的基础。 - `struts-tiles.jar`:Tiles扩展了Struts,提供了一种方式来组织和重用页面...
用户在页面上填写的信息被封装到ActionForm对象中,然后由ActionServlet转发到Action。 4. **Action**:每个Action类对应一个业务逻辑,处理特定的用户请求,并可能调用业务服务层(Service)进行数据处理。Action...
- **ActionForm**:用于封装用户表单数据,与ActionServlet交互,传递请求参数到业务逻辑层。 - **Action**:实现了业务逻辑,通常对应一个特定的用户请求,处理完业务逻辑后,返回一个ActionForward对象来决定...
Struts 1.2.9 是一个开源的Java Web应用程序框架,由Apache软件基金会开发。这个框架主要用于构建基于MVC(Model-View-Controller)设计模式的Web应用。Struts 1.2.9 源码包"struts-1.2.9-src.rar"提供了框架的核心...
Struts 1.2.9 是一个开源的Java框架,主要用于构建基于J2EE平台的Web应用程序。这个框架的核心是模型-视图-控制器(MVC)架构模式,它简化了开发过程,提供了可重用的组件,并且提高了代码的组织性和可维护性。...
5. **配置文件**:主要包括struts-config.xml,用于配置Action、ActionForm、ActionMapping等,以及web.xml,用于配置ActionServlet。 6. **标签库**:提供了一系列JSP标签,简化视图层的开发,如logic、bean、html...
了解并熟练使用这些组件,可以帮助开发者高效地构建基于Struts 1.2.9的Java Web应用程序。虽然现在Struts 2和Spring MVC等新框架更为流行,但对于维护旧系统或学习历史技术的开发者,Struts 1.2.9仍然是一个有价值的...
此外,理解Struts的工作流程至关重要,这包括用户发起请求,请求被ActionServlet拦截,ActionServlet根据配置文件找到相应的Action,调用Action执行业务逻辑,然后将结果返回给JSP页面。在这个过程中,ActionForm、...
1. **ActionServlet**: Struts框架的入口点,作为Servlet拦截所有HTTP请求,并根据配置文件(struts-config.xml)进行转发。 2. **ActionForm**: 表单数据的载体,与视图层的HTML表单对应,负责收集和验证用户输入...
4. Action将结果返回给ActionServlet,ActionServlet会根据结果决定如何转发请求。 5. 转发到相应的JSP页面,JSP页面使用Struts标签展示数据。 **总结** Struts框架为Java Web开发提供了一个强大的基础,通过提供...
它提供了ActionForm、Action、ActionServlet等关键组件,使得开发者可以方便地实现业务逻辑与视图层的分离,同时支持请求分发和页面跳转。 2. **Antlr.jar**:Antlr是一个强大的解析器生成器,用于读取、处理、执行...
Action返回一个ActionForward对象,指示ActionServlet转发到哪个页面。 6. ActionServlet根据ActionForward转发请求到指定的JSP页面。 4. **Struts 1.2.9的改进与特性** - 动态方法调用(Dynamic Method ...
2. **Action**:Action是业务逻辑的载体,它实现了.struts.action.Action接口,负责处理来自ActionServlet的请求,执行业务逻辑,并返回一个ActionForward对象指示下一步操作。 3. **ActionForm**:用于收集和验证...
在Web项目的web.xml文件中,需要配置Struts的核心过滤器(ActionServlet),以便能够处理请求并将其转发至相应的Action对象。 示例配置如下: ```xml <filter-name>action <filter-class>org.apache.struts....
Struts1.2.9是Apache软件基金会的一个开源项目,它是Model-View-Controller(MVC)设计模式在Java Web应用程序中的实现。这个框架的主要目标是简化开发过程,提高代码组织性和可维护性,使开发者能够更高效地构建...
Struts框架的核心组件包括Action、ActionForm、ActionServlet、Config、Tiles等。Action是处理用户请求的中心,它接收表单数据并调用业务逻辑;ActionForm用于封装表单数据,提供验证功能;ActionServlet作为控制器...