Package org.apache.struts.action

Source Code of org.apache.struts.action.AddDataSourceRule

/*
* $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.68.2.1 2001/06/02 23:06:49 craigmcc Exp $
* $Revision: 1.68.2.1 $
* $Date: 2001/06/02 23:06:49 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution, if
*    any, must include the following acknowlegement:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowlegement may appear in the software itself,
*    if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Struts", and "Apache Software
*    Foundation" must not be used to endorse or promote products derived
*    from this software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
*    nor may "Apache" appear in their names without prior written
*    permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/


package org.apache.struts.action;


import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.MissingResourceException;
import javax.servlet.RequestDispatcher;
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.servlet.http.HttpSession;
import javax.sql.DataSource;
import org.apache.struts.digester.Digester;
import org.apache.struts.digester.Rule;
import org.apache.struts.taglib.html.Constants;
import org.apache.struts.util.FastHashMap;
import org.apache.struts.util.GenericDataSource;
import org.apache.struts.util.MessageResources;
import org.apache.struts.util.MessageResourcesFactory;
import org.apache.struts.util.RequestUtils;
import org.apache.struts.util.ServletContextWriter;
import org.apache.struts.upload.MultipartRequestWrapper;
import org.xml.sax.AttributeList;
import org.xml.sax.SAXException;


/**
* <p><strong>ActionServlet</strong> represents 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 JSP 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 the
*     controller servlet.</li>
* <li>There will be one instance of this servlet class,
*     which receives and processes all requests that change the state of
*     a user's interaction with the application.  This component represents
*     the "controller" component of an MVC architecture.</li>
* <li>The controller servlet will select and invoke an action class to perform
*     the requested business logic.</li>
* <li>The action classes will 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,
*     action classes will generally use the
*     <code>RequestDispatcher.forward()</code> facility of the servlet API
*     to pass control to an appropriate JSP page to produce the next page
*     of the user interface.</li>
* </ul>
*
* <p>The standard version of <code>ActionServlet</code> implements the
*    following logic for each incoming HTTP request.  You can override
*    some or all of this functionality by subclassing this servlet 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 action 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>perform()</code> method of this action class, passing
*     on a reference to the mapping that was used (thereby providing access
*     to the underlying ActionServlet and ServletContext, as well as any
*     specialized properties of the mapping itself), and the request and
*     response that were passed to the controller by the servlet container.
*     </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>application</strong> - Java class name of the application
*     resources bundle base class.  [NONE]</li>
* <li><strong>bufferSize</strong> - The size of the input buffer used when
*     processing file uploads.  [4096]</li>
* <li><strong>config</strong> - Context-relative path to the XML resource
*     containing our configuration information.
*     [/WEB-INF/struts-config.xml]</li>
* <li><strong>content</strong> - Default content type and character encoding
*     to be set on each response; may be overridden by a forwarded-to
*     servlet or JSP page.  [text/html]</li>
* <li><strong>debug</strong> - The debugging detail level for this
*     servlet, which controls how much information is logged.  [0]</li>
* <li><strong>detail</strong> - The debugging detail level for the Digester
*     we utilize in <code>initMapping()</code>, which logs to System.out
*     instead of the servlet log.  [0]</li>
* <li><strong>factory</strong> - The Java class name of the
*     <code>MessageResourcesFactory</code> used to create the application
*     <code>MessageResources</code> object.</li>
* <li><strong>formBean</strong> - The Java class name of the ActionFormBean
*     implementation to use [org.apache.struts.action.ActionFormBean].
* <li><strong>forward</strong> - The Java class name of the ActionForward
*     implementation to use [org.apache.struts.action.ActionForward].
*     Two convenient classes you may wish to use are:
*     <ul>
*     <li><em>org.apache.struts.action.ForwardingActionForward</em> -
*         Subclass of <code>org.apache.struts.action.ActionForward</code>
*         that defaults the <code>redirect</code> property to
*         <code>false</code> (same as the ActionForward default value).
*     <li><em>org.apache.struts.action.RedirectingActionForward</em> -
*         Subclass of <code>org.apache.struts.action.ActionForward</code>
*         that defaults the <code>redirect</code> property to
*         <code>true</code>.
*     </ul></li>
* <li><strong>locale</strong> - If set to <code>true</code>, and there is a
*     user session, identify and store an appropriate
*     <code>java.util.Locale</code> object (under the standard key
*     identified by <code>Action.LOCALE_KEY</code>) in the user's session
*     if there is not a Locale object there already.</li>
* <li><strong>mapping</strong> - The Java class name of the ActionMapping
*     implementation to use [org.apache.struts.action.ActionMapping].
*     Two convenient classes you may wish to use are:
*     <ul>
*     <li><em>org.apache.struts.action.RequestActionMapping</em> - Subclass
*         of <code>org.apache.struts.action.ActionMapping</code> that
*         defaults the <code>scope</code> property to "request".
*     <li><em>org.apache.struts.action.SessionActionMapping</em> - Subclass
*         of <code>org.apache.struts.action.ActionMapping</code> that
*         defaults the <code>scope</code> property to "session".  (Same
*         as the ActionMapping default value).
*     </ul></li>
* <li><strong>maxFileSize</strong> - The maximum size (in bytes) of a file
*     to be accepted as a file upload.  Can be expressed as a number followed
*     by a "K" "M", or "G", which are interpreted to mean kilobytes,
*     megabytes, or gigabytes, respectively.  [250M]</li>
* <li><strong>multipartClass</strong> - The fully qualified name of the
*     MultiplartRequestHandler implementation class to be used for processing
*     file uploads.  [org.apache.struts.upload.DiskMultipartRequestHandler]
*     </li>
* <li><strong>nocache</strong> - If set to <code>true</code>, add HTTP headers
*     to every response intended to defeat browser caching of any response we
*     generate or forward to.  [false]</li>
* <li><strong>null</strong> - If set to <code>true</code>, set our application
*     resources to return <code>null</code> if an unknown message key is used.
*     Otherwise, an error message including the offending message key will
*     be returned.  [true]</li>
* <li><strong>tempDir</strong> - The temporary working directory to use when
*     processing file uploads.  [The working directory provided to this web
*     application as a servlet context attribute]</li>
* <li><strong>validate</strong> - Are we using the new configuration file
*     format?  [true]</li>
* <li><strong>validating</strong> - Should we use a validating XML parse to
*     process the configuration file (strongly recommended)? [true]</li>
* </ul>
*
* @author Craig R. McClanahan
* @version $Revision: 1.68.2.1 $ $Date: 2001/06/02 23:06:49 $
*/

public class ActionServlet
    extends HttpServlet {


    // ----------------------------------------------------- Instance Variables


    /**
     * The set of Action instances that have been created and initialized,
     * keyed by the fully qualified Java class name.
     */
    protected FastHashMap actions = new FastHashMap();


    /**
     * The resources object for our application resources (if any).
     */
    protected MessageResources application = null;


    /**
     * The context-relative path to our configuration resource.
     */
    protected String config = "/WEB-INF/struts-config.xml";


    /**
     * The default content type and character encoding to be set on each
     * response (may be overridden by forwarded-to resources).
     */
    protected String content = "text/html";


    /**
     * The JDBC data sources that has been configured for this application,
     * if any, keyed by the servlet context attribute under which they are
     * stored.
     */
    protected FastHashMap dataSources = new FastHashMap();


    /**
     * The debugging detail level for this servlet.
     */
    protected int debug = 0;


    /**
     * The default Locale for this server.
     */
    protected final Locale defaultLocale = Locale.getDefault();


    /**
     * The Java class name of the <code>MessageResourcesFactory</code>
     * class for the application message resources bundle.
     */
    protected String factoryClass = null;


    /**
     * The Java class name of the ActionFormBean implementation class to use.
     */
    protected String formBeanClass =
        "org.apache.struts.action.ActionFormBean";


    /**
     * The global ActionFormBean collection for this controller.
     */
    protected ActionFormBeans formBeans = new ActionFormBeans();


    /**
     * The Java class name of the ActionForward implementation class to use.
     */
    protected String forwardClass =
  "org.apache.struts.action.ActionForward";


    /**
     * The global ActionForward collection for this controller.
     */
    protected ActionForwards forwards = new ActionForwards();


    /**
     * The resources object for our internal resources.
     */
    protected MessageResources internal = null;


    /**
     * The Java base name of our internal resources.
     */
    protected String internalName = "org.apache.struts.action.ActionResources";


    /**
     * Should we create a <code>java.util.Locale</code> for this user,
     * based on the HTTP headers of the request, if one is not present?
     */
    protected boolean locale = true;


    /**
     * The Java class name of our ActionMapping implementation class.
     */
    protected String mappingClass =
  "org.apache.struts.action.ActionMapping";


    /**
     * The configured mappings for this web application, keyed by path.
     */
    protected ActionMappings mappings = new ActionMappings();


    /**
     * Include the no-caching headers in our response?
     */
    protected boolean nocache = false;


    /**
     * 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!
     */
    protected String registrations[] = {
        "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN",
        "/org/apache/struts/resources/struts-config_1_0.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"
    };


    /**
     * The URL pattern to which we are mapped in our web application
     * deployment descriptor.
     */
    protected String servletMapping = null;


    /**
     * The servlet name under which we are registered in our web application
     * deployment descriptor.
     */
    protected String servletName = null;


    /**
     * Are we using the new configuration file format?
     */
    protected boolean validate = true;
   

    /**
     * Should we use a validating XML parser to read the configuration file?
     */
    protected boolean validating = true;


    /**
     * The size in bytes of the buffer used to read files from a client upload
     */
    protected int bufferSize = 4096;
   
    /**
     * The maximum size allowed for a client upload.  A suffix of "K"
     * represents Kilobytes, a suffix of "M" represents "Megabytes",
     * a suffix of "G" represents Gigabytes, and no suffix is taken
     * as bytes.
     */
    protected String maxFileSize = "250M";
   
    /**
     * The MultipartRequestHandler class name used for handling
     * multipart form requests.  This is the global default value,
     * the handler can also be set in individual mapping entries
     */
    protected String multipartClass = "org.apache.struts.upload.DiskMultipartRequestHandler";
   
    /**
     * The directory used to store temporary files for the DiskMultipartRequestHandler
     * multipart implementation
     */
    protected String tempDir;





    // ---------------------------------------------------- HttpServlet Methods


    /**
     * Gracefully shut down this controller servlet, releasing any resources
     * that were allocated at initialization.
     */
    public void destroy() {

  if (debug >= 1)
      log(internal.getMessage("finalizing"));

        destroyActions();
  destroyApplication();
        destroyDataSources();
  destroyInternal();

    }


    /**
     * 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.
     *
     * @exception ServletException if we cannot configure ourselves correctly
     */
    public void init() throws ServletException {

        initActions();
  initInternal();
  initDebug();
  initApplication();
  try {
      initMapping();
  } catch (IOException e) {
      throw new UnavailableException
    (internal.getMessage("configIO", config));
  }
        initUpload();
        initDataSources();
  initOther();
        initServlet();

    }


    /**
     * Process an HTTP "GET" request.
     *
     * @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);

    }


    /**
     * Process an HTTP "POST" request.
     *
     * @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


    /**
     * Add a data source object to be used by this application.
     *
     * @param key The servlet context attribute key under which to store
     *  this data source, or <code>null</code> for the default
     * @param dataSource The data source to be used
     */
    public void addDataSource(String key, DataSource dataSource) {

        if (key == null)
            key = Action.DATA_SOURCE_KEY;
        dataSources.put(key, dataSource);

    }


    /**
     * Register a form bean definition to the set configured for this servlet.
     *
     * @param formBean The form bean definition to be added
     */
    public void addFormBean(ActionFormBean formBean) {

        formBeans.addFormBean(formBean);

    }


    /**
     * Register a logical forwarding to the set configured for this servlet.
     *
     * @param forward The forwarding to be added
     */
    public void addForward(ActionForward forward) {

  forwards.addForward(forward);

    }


    /**
     * Register a mapping to the set configured for this servlet.
     *
     * @param mapping The mapping to be added
     */
    public void addMapping(ActionMapping mapping) {

        // Validate that exactly one of "include" or "type" is included
        int n = 0;
        if (mapping.getForward() != null)
            n++;
        if (mapping.getInclude() != null)
            n++;
        if (mapping.getType() != null)
            n++;
        if (n != 1) {
            String message =
                internal.getMessage("mappingType", mapping.getPath());
            log(message);
            throw new IllegalArgumentException(message);
        }

        // Add this mapping to our global collection
  mappings.addMapping(mapping);

    }


    /**
     * Remember a servlet mapping from our web application deployment
     * descriptor, if it is for this servlet.
     *
     * @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 (debug >= 1)
            log("Process servletName=" + servletName +
                ", urlPattern=" + urlPattern);
        if (servletName == null)
            return;
        if (servletName.equals(this.servletName))
            this.servletMapping = urlPattern;

    }


    /**
     * Return a JDBC data source associated with this application, if any.
     *
     * @param key The servlet context attribute key under which this data
     *  source is stored, or <code>null</code> for the default.
     */
    public DataSource findDataSource(String key) {

        if (key == null)
            return ((DataSource) dataSources.get(Action.DATA_SOURCE_KEY));
        else
            return ((DataSource) dataSources.get(key));

    }


    /**
     * Return the form bean definition associated with the specified
     * logical name, if any; otherwise return <code>null</code>.
     *
     * @param name Logical name of the requested form bean definition
     */
    public ActionFormBean findFormBean(String name) {

        return (formBeans.findFormBean(name));

    }


    /**
     * Return the forwarding associated with the specified logical name,
     * if any; otherwise return <code>null</code>.
     *
     * @param name Logical name of the requested forwarding
     */
    public ActionForward findForward(String name) {

  return (forwards.findForward(name));

    }


    /**
     * Return the mapping associated with the specified request path, if any;
     * otherwise return <code>null</code>.
     *
     * @param path Request path for which a mapping is requested
     */
    public ActionMapping findMapping(String path) {

  return (mappings.findMapping(path));

    }
   
    /**
     * Get the buffer size (how large of a chunk of data is
     * recieved by the input stream at once) used for file
     * uploading.
     *
     * @return The size in bytes of the buffer
     */
    public int getBufferSize() {

        return bufferSize;

    }


    /**
     * Return the debugging detail level for this servlet.
     */
    public int getDebug() {

  return (this.debug);

    }


    /**
     * Return the Java class name of the class used to instantiate
     * <code>ActionFormBean</code> objects.
     */
    public String getFormBeanClass() {

        return (this.formBeanClass);

    }


    /**
     * Return the Java class name of the class used to instantiate
     * <code>ActionForward</code> objects.
     */
    public String getForwardClass() {

  return (this.forwardClass);

    }


    /**
     * Return the Java class name of the class used to instantiate
     * <code>ActionMapping</code> objects.
     */
    public String getMappingClass() {

  return (this.mappingClass);

    }
   
   
    /**
     * Get the maximum file size.  See {@link #setMaxFileSize(java.lang.String) setMaxFileSize}
     * for information on the number format used.
     */
    public String getMaxFileSize() {
        return maxFileSize;
    }
   
    /**
     * Get the class name of the MultipartRequestHandler implementation
     *
     * @return A qualified classname of the MultipartRequestHandler implementation
     */
     public String getMultipartClass() {
        return multipartClass;
    }



    /**
     * Return the application resources for this web application, if any.
     */
    public MessageResources getResources() {

  return (application);

    }
   
    /**
     * Get the directory used to temporarily store form files
     *
     * @return A platform-dependant String representing the path to the temporary directory
     */
    public String getTempDir() {
        return tempDir;
    }



    /**
     * Log the specified message if the current debugging detail level for
     * this servlet has been set to an equal or higher value.  Otherwise,
     * ignore this message.
     *
     * @param message Message to be logged
     * @param level Debugging detail level of this message
     */
    public void log(String message, int level) {

        if (debug >= level)
            log(message);

    }


    /**
     * Reload the configuration of this controller servlet from our
     * underlying configuration files.
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet exception occurs
     */
    public void reload() throws IOException, ServletException {

        if (debug >= 1)
            log(internal.getMessage("reloading"));

        // Shut down our existing environment
        destroyActions();
        destroyApplication();
        destroyDataSources();
        destroyInternal();

        // Restart from our confirmation files
        initActions();
        initInternal();
        initDebug();
        initApplication();
        initMapping();
        initUpload();
        initDataSources();
        initOther();

    }


    /**
     * Deregister a form bean definition from the set configured for
     * this servlet.
     *
     * @param formBean The form bean definition to be deregistered
     */
    public void removeFormBean(ActionFormBean formBean) {

        formBeans.removeFormBean(formBean);

    }


    /**
     * Deregister a forwarding from the set configured for this servlet.
     *
     * @param forward The forwarding to be deregistered
     */
    public void removeForward(ActionForward forward) {

  forwards.removeForward(forward);

    }


    /**
     * Deregister a mapping from the set configured for this servlet.
     *
     * @param mapping The mapping to be deregistered
     */
    public void removeMapping(ActionMapping mapping) {

  mappings.removeMapping(mapping);

    }

   
    /**
     * Set the buffer size (how large of a chunk of data is
     * recieved by the input stream at once) used for file
     * uploading.
     *
     * @param bufferSize The size in bytes of the buffer
     */
    public void setBufferSize(int bufferSize) {

        this.bufferSize = bufferSize;

    }


    /**
     * Set the Java class name of the class used to instantiate
     * <code>ActionFormBean</code> objects.
     *
     * @param formBeanClass The new class name
     */
    public void setFormBeanClass(String formBeanClass) {

        this.formBeanClass = formBeanClass;

    }


    /**
     * Set the Java class name of the class used to instantiate
     * <code>ActionForward</code> objects.
     *
     * @param forwardClass The new class name
     */
    public void setForwardClass(String forwardClass) {

        this.forwardClass = forwardClass;

    }


    /**
     * Set the Java class name of the class used to instantiate
     * <code>ActionMapping</code> objects.
     *
     * @param mappingClass The new class name
     */
    public void setMappingClass(String mappingClass) {

        this.mappingClass = mappingClass;

    }
   
    /**
     * Set the maximum file size that a client can upload,  number String with a trailing
     * letter indicating the size.  "K" indicates "kilobytes", "M" indicates "megabytes",
     * "G" indicates "gigabytes".  If there's no trailing letter the suffix is assumed to
     * indicate the number is in bytes.  For example, to set a maximum file size of
     * 500 megabytes, you'd call <code>setMaxFileSize</code>("<i>500M</i>").
     *
     * @param maxFileSize A String representing the maximum file size.
     */
    public void setMaxFileSize(String maxFileSize) {
        this.maxFileSize = maxFileSize;
    }
   
    /**
     * Set the class name of the MultipartRequestHandler implementation
     *
     * @param multipartClass A qualified classname of the MultipartRequestHandler implementation
     */
    public void setMultipartClass(String multipartClass) {
        this.multipartClass = multipartClass;
    }

   
    /**
     * Set the directory used to temporarily store files for MultipartRequestHandler
     * implementations that write to the disk
     *
     * @param tempDir A platform-dependant String representing the path to the temporary directory
     */
    public void setTempDir(String tempDir) {
        this.tempDir = tempDir;
    }


    // ------------------------------------------------------ Protected Methods


    /**
     * Gracefully shut down any action instances we have created.
     */
    protected void destroyActions() {

        synchronized (this.actions) {
            Iterator actions = this.actions.values().iterator();
            while (actions.hasNext()) {
                Action action = (Action) actions.next();
                action.setServlet(null);
            }
            this.actions.clear();
        }

    }


    /**
     * Gracefully terminate use of the application MessageResources (if any).
     */
    protected void destroyApplication() {

  if (application != null)
      getServletContext().removeAttribute(Action.MESSAGES_KEY);
  application = null;

    }


    /**
     * Gracefully terminate use of the data source associated with this
     * application (if any).
     */
    protected void destroyDataSources() {

        synchronized (dataSources) {
            Iterator keys = dataSources.keySet().iterator();
            while (keys.hasNext()) {
                String key = (String) keys.next();
                getServletContext().removeAttribute(key);
                DataSource dataSource = findDataSource(key);
                if (dataSource instanceof GenericDataSource) {
                    if (debug >= 1)
                        log(internal.getMessage("dataSource.destroy", key));
                    try {
                        ((GenericDataSource) dataSource).close();
                    } catch (SQLException e) {
                        log(internal.getMessage("destroyDataSource", key), e);
                    }
                }
            }
            dataSources.setFast(false);
        }

    }


    /**
     * Gracefully terminate use of the internal MessageResources.
     */
    protected void destroyInternal() {

  internal = null;

    }


    /**
     * Initialize the collection of previously instantiated Action instances.
     */
    protected void initActions() {

        synchronized (actions) {
            actions.setFast(false);
            actions.clear();
            actions.setFast(true);
        }

    }


    /**
     * Initialize the MessageResources bundle for this application, if any.
     *
     * @exception ServletException if we cannot initialize these resources
     */
    protected void initApplication() throws ServletException {

  String value = getServletConfig().getInitParameter("application");
  if (value == null)
      return;
        String factory =
            getServletConfig().getInitParameter("factory");
  if (debug >= 1)
      log(internal.getMessage("applicationLoading", value));
  try {
            String oldFactory =
                MessageResourcesFactory.getFactoryClass();     
            if (factory != null)
                MessageResourcesFactory.setFactoryClass(factory);
            MessageResourcesFactory factoryObject =
                MessageResourcesFactory.createFactory();
            application = factoryObject.createResources(value);
            MessageResourcesFactory.setFactoryClass(oldFactory);
      value = getServletConfig().getInitParameter("null");
      if (value == null)
    value = "true";
      if (value.equalsIgnoreCase("true") ||
    value.equalsIgnoreCase("yes"))
    application.setReturnNull(true);
      else
    application.setReturnNull(false);
  } catch (Throwable e) {
      log(internal.getMessage("applicationResources", value), e);
      throw new UnavailableException
    (internal.getMessage("applicationResources", value));
  }
  getServletContext().setAttribute(Action.MESSAGES_KEY, application);

    }


    /**
     * Initialize use of the data sources associated with this
     * application (if any).
     *
     * @exception ServletException if a fatal initialization error occurs
     */
    protected void initDataSources() throws ServletException {

        ServletContextWriter scw =
            new ServletContextWriter(getServletContext());

        synchronized (dataSources) {
            Iterator keys = dataSources.keySet().iterator();
            while (keys.hasNext()) {
                String key = (String) keys.next();
                DataSource dataSource = findDataSource(key);
                try {
                    dataSource.setLogWriter(scw);
                } catch (SQLException e) {
                    log(internal.getMessage("initDataSource", key), e);
                    throw new ServletException
                        (internal.getMessage("initDataSource", key), e);
                }
                if (dataSource instanceof GenericDataSource) {
                    if (debug >= 1)
                        log(internal.getMessage("dataSource.init", key));
                    try {
                        ((GenericDataSource) dataSource).open();
                    } catch (SQLException e) {
                        log(internal.getMessage("initDataSource", key), e);
                        throw new ServletException
                            (internal.getMessage("initDataSource", key), e);
                    }
                }
                getServletContext().setAttribute(key, dataSource);
            }
            dataSources.setFast(true);
        }

    }


    /**
     * Initialize the debugging detail level for this application.
     *
     * @exception ServletException if we cannot initialize these resources
     */
    protected void initDebug() throws ServletException {

  String value = getServletConfig().getInitParameter("debug");
  try {
      debug = Integer.parseInt(value);
  } catch (Throwable t) {
      debug = 0;
  }
    }


    /**
     * Construct and return a digester that uses the new configuration
     * file format.
     */
    protected Digester initDigester(int detail) {

  // Initialize a new Digester instance
  Digester digester = new Digester();
  digester.push(this);
  digester.setDebug(detail);
  digester.setValidating(validating);

  // 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

        digester.addObjectCreate("struts-config/data-sources/data-source",
                                 "org.apache.struts.util.GenericDataSource",
                                 "type");
        digester.addSetProperties("struts-config/data-sources/data-source");
        digester.addRule("struts-config/data-sources/data-source",
                         new AddDataSourceRule(digester));
        digester.addSetProperty
            ("struts-config/data-sources/data-source/set-property",
             "property", "value");

        digester.addObjectCreate("struts-config/action-mappings/action",
                                 mappingClass, "className");
        digester.addSetProperties("struts-config/action-mappings/action");
        digester.addSetNext("struts-config/action-mappings/action",
                            "addMapping",
                            "org.apache.struts.action.ActionMapping");

        digester.addSetProperty
            ("struts-config/action-mappings/action/set-property",
             "property", "value");

        digester.addObjectCreate
            ("struts-config/action-mappings/action/forward",
             forwardClass, "className");
        digester.addSetProperties
            ("struts-config/action-mappings/action/forward");
        digester.addSetNext("struts-config/action-mappings/action/forward",
                            "addForward",
                            "org.apache.struts.action.ActionForward");

        digester.addSetProperty
            ("struts-config/action-mappings/action/forward/set-property",
             "property", "value");

        digester.addObjectCreate("struts-config/form-beans/form-bean",
                                 formBeanClass, "className");
        digester.addSetProperties("struts-config/form-beans/form-bean");
        digester.addSetNext("struts-config/form-beans/form-bean",
                            "addFormBean",
                            "org.apache.struts.action.ActionFormBean");

        digester.addSetProperty
            ("struts-config/form-beans/form-bean/set-property",
             "property", "value");

        digester.addObjectCreate("struts-config/global-forwards/forward",
                                 forwardClass, "className");
        digester.addSetProperties("struts-config/global-forwards/forward");
        digester.addSetNext("struts-config/global-forwards/forward",
                            "addForward",
                            "org.apache.struts.action.ActionForward");

        digester.addSetProperty
            ("struts-config/global-forwards/forward/set-property",
             "property", "value");

  return (digester);

    }


    /**
     * Construct and return a digester that uses the old configuration
     * file format.
     */
    protected Digester initDigesterOld(int detail) {

  // Initialize a new Digester instance
  Digester digester = new Digester();
  digester.push(this);
  digester.setDebug(detail);
  digester.setValidating(false);

  // Configure the processing rules
  digester.addObjectCreate("action-mappings/action", mappingClass,
         "className");
  digester.addSetProperties("action-mappings/action");
  digester.addSetNext("action-mappings/action", "addMapping",
          "org.apache.struts.action.ActionMapping");
  digester.addObjectCreate("action-mappings/action/forward",
         forwardClass, "className");
  digester.addSetProperties("action-mappings/action/forward");
  digester.addSetNext("action-mappings/action/forward", "addForward",
          "org.apache.struts.action.ActionForward");
  digester.addSetProperty("action-mappings/action/forward/property",
        "name", "value");
  digester.addSetProperty("action-mappings/action/property",
        "name", "value");
  digester.addObjectCreate("action-mappings/forward",
         forwardClass, "className");
  digester.addSetProperties("action-mappings/forward");
  digester.addSetNext("action-mappings/forward", "addForward",
          "org.apache.struts.action.ActionForward");
  digester.addSetProperty("action-mappings/forward/property",
        "name", "value");

  return (digester);

    }


    /**
     * Initialize our internal MessageResources bundle.
     *
     * @exception ServletException if we cannot initialize these resources
     */
    protected void initInternal() throws ServletException {

  try {
      internal = MessageResources.getMessageResources(internalName);
  } catch (MissingResourceException e) {
      log("Cannot load internal resources from '" + internalName + "'",
    e);
      throw new UnavailableException
    ("Cannot load internal resources from '" + internalName + "'");
  }

    }


    /**
     * Initialize the mapping information for this application.
     *
     * @exception IOException if an input/output error is encountered
     * @exception ServletException if we cannot initialize these resources
     */
    protected void initMapping() throws IOException, ServletException {

  String value = null;

        // Link our mappings collection to this servlet instance
        mappings.setServlet(this);

  // Initialize the debugging detail level we will use
  int detail;
  try {
      value = getServletConfig().getInitParameter("detail");
      detail = Integer.parseInt(value);
  } catch (Throwable t) {
      detail = 0;
  }

  // Initialize the format selector flag
  value = getServletConfig().getInitParameter("validate");
  if (value != null) {
      if (value.equalsIgnoreCase("true") ||
          value.equalsIgnoreCase("yes"))
          validate = true;
      else
          validate = false;
  }

  // Initialize the validating XML parser flag
  value = getServletConfig().getInitParameter("validating");
  if (value != null) {
      if (value.equalsIgnoreCase("true") ||
          value.equalsIgnoreCase("yes"))
          validating = true;
      else
          validating = false;
  }

        // Initialize the name of our ActionFormBean implementation class
        value = getServletConfig().getInitParameter("formBean");
        if (value != null)
            formBeanClass = value;

  // Initialize the name of our ActionForward implementation class
  value = getServletConfig().getInitParameter("forward");
  if (value != null)
      forwardClass = value;

  // Initialize the name of our ActionMapping implementation class
  value = getServletConfig().getInitParameter("mapping");
  if (value != null)
      mappingClass = value;

  // Initialize the context-relative path to our configuration resources
  value = getServletConfig().getInitParameter("config");
  if (value != null)
      config = value;
  if (debug >= 1)
      log(internal.getMessage("configInit", config));

  // Acquire an input stream to our configuration resource
  InputStream input = getServletContext().getResourceAsStream(config);
  if (input == null)
      throw new UnavailableException
    (internal.getMessage("configMissing", config));

  // Build a digester to process our configuration resource
  Digester digester = null;
  if (validate)
      digester = initDigester(detail);
  else
      digester = initDigesterOld(detail);

  // Parse the input stream to configure our mappings
  try {
            formBeans.setFast(false);
            forwards.setFast(false);
            mappings.setFast(false);
      digester.parse(input);
            mappings.setFast(true);
            forwards.setFast(true);
            formBeans.setFast(true);
  } catch (SAXException e) {
      throw new ServletException
    (internal.getMessage("configParse", config), e);
        } finally {
      input.close();
  }

        // Transitional support for old format
        if (!validate) {
            String paths[] = mappings.findMappings();
            for (int i = 0; i < paths.length; i++) {
                String name =
                    mappings.findMapping(paths[i]).getName();
                if (name == null)
                    continue;
                ActionFormBean formBean = new ActionFormBean();
                formBean.setName(name);
                formBean.setType(name);
                formBeans.addFormBean(formBean);
            }
        }

    }


    /**
     * Initialize other configuration parameters that have not yet
     * been processed.
     *
     * @exception ServletException if we cannot initialize these resources
     */
    protected void initOther() throws ServletException {

  // Process the "content", "locale", and "nocache" parameters
  String value = null;

        value = getServletConfig().getInitParameter("content");
        if (value != null)
            content = value;

        value = getServletConfig().getInitParameter("locale");
        if (value != null) {
            if ("true".equalsIgnoreCase(value) ||
                "yes".equalsIgnoreCase(value))
                locale = true;
            else
                locale = false;
        }

        value = getServletConfig().getInitParameter("nocache");
        if (value != null) {
            if ("true".equalsIgnoreCase(value) ||
                "yes".equalsIgnoreCase(value))
                nocache = true;
        }

  // Publish our internal collections as necessary
        getServletContext().setAttribute(Action.FORM_BEANS_KEY, formBeans);
  getServletContext().setAttribute(Action.FORWARDS_KEY, forwards);
  getServletContext().setAttribute(Action.MAPPINGS_KEY, mappings);

    }
   
   
    /**
     * Initialize the servlet mapping under which our controller servlet
     * is being accessed.  This will be used in the <code>&html:form&gt;</code>
     * tag to generate correct destination URLs for form submissions.
     */
    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.setDebug(this.debug);
        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
        InputStream input= null;
        try {
            input =
                getServletContext().getResourceAsStream("/WEB-INF/web.xml");
            digester.parse(input);
        } catch (Throwable e) {
            log(internal.getMessage("configWebXml"), e);
        } finally {
            if (input != null)
                input = null;
        }

        // Record a servlet context attribute (if appropriate)
        if (debug >= 1)
            log("Mapping for servlet '" + servletName + "' = '" +
                servletMapping + "'");
        if (servletMapping != null)
            getServletContext().setAttribute(Action.SERVLET_KEY,
                                             servletMapping);

    }


    /**
     * Initialize upload parameters and "bufferSize", "multipartClass",
     * "maxFileSize", "tempDir"
     *
     * @exception ServletException if there are invalid parameters
     */
    protected void initUpload() throws ServletException {
     
        //buffer size
        String bufferValue = getServletConfig().getInitParameter("bufferSize");
       
        if ((bufferValue != null) && (bufferValue.length() > 0)) {
            int oldBufferSize = bufferSize;
            try {
                bufferSize = Integer.parseInt(bufferValue, 10);
            }
            catch (NumberFormatException nfe) {
                if (debug > 0) {
                    log("initUpload(): invalid value \"" + bufferSize + "\" for " +
                        "init-parameter \"buffer size\"" +
                        ", defaulting to \"" + oldBufferSize + "\"");
                }
                bufferSize = oldBufferSize;
            }
        }
       
        //multipart class
        String classValue = getServletConfig().getInitParameter("multipartClass");
       
        if ((classValue != null) && (classValue.length() > 0)) {
            multipartClass = classValue;
        }
       
        //maximum file size
        String maxsizeValue = getServletConfig().getInitParameter("maxFileSize");
       
        if ((maxsizeValue != null) && (maxsizeValue.length() > 0)) {
            maxFileSize = maxsizeValue;
        }
       
        //temp directory
        String tempDirValue = getServletConfig().getInitParameter("tempDir");
       
        if ((tempDirValue != null) && (tempDirValue.length() > 0)) {
            tempDir = tempDirValue;
        }
    }



    /**
     * Process an HTTP request.
     *
     * @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
     */
    protected void process(HttpServletRequest request,
         HttpServletResponse response)
  throws IOException, ServletException {

        String contentType = request.getContentType();
        String method = request.getMethod();
       
        //if this is a multipart request, wrap the HttpServletRequest object
        //with a MultipartRequestWrapper to keep the process sub-methods
        //from failing when checking for certain request parameters
        //for command tokens and cancel button detection
        if ((contentType != null) && (contentType.startsWith("multipart/form-data"))
            && (method.equals("POST"))) {
                request = new MultipartRequestWrapper(request);
        }
           
  // Identify the path component we will use to select a mapping
  String path = processPath(request);
  if (path == null) {
      if (debug >= 1)
    log(" No path available for request URI " +
        request.getRequestURI());
      response.sendError(HttpServletResponse.SC_BAD_REQUEST,
             internal.getMessage("processPath"));
      return;
  }
  if (debug >= 1)
      log("Processing a " + request.getMethod() + " for " + path);

        // Automatically select a locale for this user if requested
        processLocale(request);

  // Set the content type and no-caching headers if requested
        processContent(response);
  processNoCache(response);

        // General purpose preprocessing hook
        if (!processPreprocess(request, response))
            return;

  // Look up the corresponding mapping
  ActionMapping mapping = processMapping(path, request);
  if (mapping == null) {
      if (debug >= 1)
    log(" No mapping available for path " + path);
      response.sendError(HttpServletResponse.SC_BAD_REQUEST,
             internal.getMessage("processInvalid", path));
      return;
  }

  // Process any ActionForm bean related to this request
  ActionForm formInstance = processActionForm(mapping, request);
        processPopulate(formInstance, mapping, request);
  if (!processValidate(mapping, formInstance, request, response))
      return;
       
        // Execute a forward if specified by this mapping
        if (!processForward(mapping, request, response))
            return;

        // Execute an include if specified by this mapping
        if (!processInclude(mapping, request, response))
            return;

        // Acquire the Action instance to process this request
        Action actionInstance = processActionCreate(mapping, request);
        if (actionInstance == null) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                               internal.getMessage("actionCreate",
                                                   mapping.getPath()));
            return;
        }

  // Call the Action instance itself
        ActionForward forward =
            processActionPerform(actionInstance, mapping, formInstance,
                                 request, response);
        //set the request back to it's normal state if it's currently wrapped,
        //to avoid ClassCastExceptions from ServletContainers if forwarding
        if (request instanceof MultipartRequestWrapper) {
            request = ((MultipartRequestWrapper) request).getRequest();
        }

        // Process the returned ActionForward (if any)
        processActionForward(forward, mapping, formInstance,
                             request, response);

    }


    /**
     * Create or retrieve the Action instance that will process this request,
     * or <code>null</code> if no such Action instance can be created.
     *
     * @param mapping The ActionMapping we are processing
     * @param request The servlet request we are processing
     */
    protected Action processActionCreate(ActionMapping mapping,
                                         HttpServletRequest request) {

        // Acquire the Action instance we will be using
        String actionClass = mapping.getType();
        if (debug >= 1)
            log(" Looking for Action instance for class " + actionClass);
        Action actionInstance = (Action) actions.get(actionClass);
        if (actionInstance == null) {
            synchronized (actions) {
                if (debug >= 1)
                    log("  Double checking for Action instance already there");
                // Double check to avoid a race condition
                actionInstance = (Action) actions.get(actionClass);
                if (actionInstance != null)
                    return (actionInstance);
                // Go ahead and create the new Action instance
                // ASSERT:  This will never ever happen more than once
                //  for a particular action class name
                try {
                    if (debug >= 1)
                        log("  Creating new Action instance");
                    Class clazz = Class.forName(actionClass);
                    actionInstance = (Action) clazz.newInstance();
                    actionInstance.setServlet(this);
                    actions.put(actionClass, actionInstance);
                } catch (Throwable t) {
                    log("Error creating Action instance for path '" +
                        mapping.getPath() + "', class name '" +
                        actionClass + "'", t);
                    return (null);
                }
            }
        }
        return (actionInstance);

    }


    /**
     * Retrieve and return the <code>ActionForm</code> bean associated with
     * this mapping, creating and stashing one if necessary.  If there is no
     * form bean associated with this mapping, return <code>null</code>.
     *
     * @param mapping The ActionMapping we are processing
     * @param request The servlet request we are processing
     */
    protected ActionForm processActionForm(ActionMapping mapping,
                 HttpServletRequest request) {

        // Is there a form bean associated with this mapping?
  String attribute = mapping.getAttribute();
        if (attribute == null)
            return (null);

        // Look up the existing form bean, if any
        if (debug >= 1)
            log(" Looking for ActionForm bean under attribute '" +
                attribute + "'");
  ActionForm instance = null;
  HttpSession session = null;
        if ("request".equals(mapping.getScope())) {
            instance = (ActionForm) request.getAttribute(attribute);
        } else {
            session = request.getSession();
            instance = (ActionForm) session.getAttribute(attribute);
        }

  // Determine the form bean class that we expect to use
        String name = mapping.getName();
        String className = null;
        ActionFormBean formBean = findFormBean(name);
        if (formBean != null)
            className = formBean.getType();
  else
            return (null);

  // Can we recycle the existing form bean instance?
  if ((instance != null) &&
      className.equals(instance.getClass().getName())) {
      if (debug >= 1)
          log(" Recycling existing ActionForm bean instance of class '"
        + className + "'");
      return (instance);
  }

        // Create a new form bean if we need to
        if (debug >= 1)
            log(" Creating new ActionForm instance of class '"
    + className + "'");
  try {
      instance = null;
      Class clazz = Class.forName(className);
      instance = (ActionForm) clazz.newInstance();
        } catch (Throwable t) {
      log("Error creating ActionForm instance of class '" +
    className + "'", t);
  }
        if (instance == null)
            return (null);

        // Store the newly created bean in the appropriate scope
        if (debug >= 1)
            log(" Storing instance under attribute '" +
                attribute + "' in scope '" + mapping.getScope() + "'");
        if ("request".equals(mapping.getScope()))
            request.setAttribute(attribute, instance);
        else
            session.setAttribute(attribute, instance);
        return (instance);

    }


    /**
     * Forward to the specified destination, by the specified mechanism,
     * if an <code>ActionForward</code> instance was returned by the
     * <code>Action</code>.
     *
     * @param forward The ActionForward returned by our action
     * @param mapping The ActionMapping we are processing
     * @param formInstance The ActionForm we are processing
     * @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
     */
    protected void processActionForward(ActionForward forward,
                                        ActionMapping mapping,
                                        ActionForm formInstance,
                                        HttpServletRequest request,
                                        HttpServletResponse response)
  throws IOException, ServletException {

  if (forward != null) {
      String path = forward.getPath();
      if (forward.getRedirect()) {
          if (path.startsWith("/"))
                    path = request.getContextPath() + path;
    response.sendRedirect(response.encodeRedirectURL(path));
      } else {
    RequestDispatcher rd =
        getServletContext().getRequestDispatcher(path);
                if (rd == null) {
                    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                                       internal.getMessage("requestDispatcher",
                                                           path));
                    return;
                }
    rd.forward(request, response);
      }
  }

    }


    /**
     * Ask the specified Action instance to handle this request.  Return
     * the <code>ActionForward</code> instance (if any) returned by
     * the called <code>Action</code>.
     *
     * @param action The Action to process this request
     * @param mapping The ActionMapping we are processing
     * @param formInstance The ActionForm we are processing
     * @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
     */
    protected ActionForward processActionPerform(Action action,
                                        ActionMapping mapping,
                                        ActionForm formInstance,
                                        HttpServletRequest request,
                                        HttpServletResponse response)
  throws IOException, ServletException {

  ActionForward forward =
      action.perform(mapping, formInstance, request, response);
        return (forward);

    }


    /**
     * Set the default content type (with optional character encoding) for
     * all responses.  This value may be overridden by forwarded-to servlets
     * or JSP pages.
     *
     * @param response The response we are processing
     */
    protected void processContent(HttpServletResponse response) {

        if (content != null)
            response.setContentType(content);

    }


    /**
     * Process a forward requested by this mapping, if any.  Return
     * <code>true</code> if processing of this request should continue (i.e.
     * be processed by an Action class), or <code>false</code> if we have
     * already handled this request.
     *
     * @param mapping The ActionMapping we are processing
     * @param request The request we are processing
     * @param response The response we are processing
     *
     * @exception IOException if the included resource throws an exception
     * @exception ServletException if the included resource throws an
     *  exception
     */
    protected boolean processForward(ActionMapping mapping,
                                     HttpServletRequest request,
                                     HttpServletResponse response)
        throws IOException, ServletException {

        // Are we going to process this request?
        String forward = mapping.getForward();
        if (forward == null)
            return (true);

        // Construct a request dispatcher for the specified path
        RequestDispatcher rd =
            getServletContext().getRequestDispatcher(forward);
        if (rd == null) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                               internal.getMessage("requestDispatcher",
                                                   forward));
            return (false);
        }

        // Delegate the processing of this request
        rd.forward(request, response);
        return (false);

    }


    /**
     * Process an include requested by this mapping, if any.  Return
     * <code>true</code> if processing of this request should continue (i.e.
     * be processed by an Action class), or <code>false</code> if we have
     * already handled this request.
     *
     * @param mapping The ActionMapping we are processing
     * @param request The request we are processing
     * @param response The response we are processing
     *
     * @exception IOException if the included resource throws an exception
     * @exception ServletException if the included resource throws an
     *  exception
     */
    protected boolean processInclude(ActionMapping mapping,
                                     HttpServletRequest request,
                                     HttpServletResponse response)
        throws IOException, ServletException {

        // Are we going to process this request?
        String include = mapping.getInclude();
        if (include == null)
            return (true);

        // Construct a request dispatcher for the specified path
        RequestDispatcher rd =
            getServletContext().getRequestDispatcher(include);
        if (rd == null) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                               internal.getMessage("requestDispatcher",
                                                   include));
            return (false);
        }

        // Delegate the processing of this request
        rd.include(request, response);
        return (false);

    }


    /**
     * Automatically calculate an appropriate <code>java.util.Locale</code>
     * for this user, and store it in their session, if there is no such
     * Locale object present already.
     *
     * @param request The request we are processing
     */
    protected void processLocale(HttpServletRequest request) {

        // Validate that we need to create a Locale
        if (!locale)
            return;             // Service not requested
        HttpSession session = request.getSession();
        if (session.getAttribute(Action.LOCALE_KEY) != null)
            return;             // Locale object is already present

        // Use the Locale returned by the servlet container (if any)
        Locale locale = request.getLocale();
        if (locale != null) {
            if (debug >= 1)
                log("Setting locale '" + locale + "'");
            session.setAttribute(Action.LOCALE_KEY, locale);
        }

    }


    /**
     * Identify and return an appropriate ActionMapping for the specified
     * path.  If no such mapping can be identified, return <code>null</code>.
     * The <code>request</code> parameter is available if you need to make
     * decisions on available mappings (such as checking permissions) based
     * on request parameters or other properties, but it is not used in the
     * default implementation.
     *
     * @param path Path component used to select a mapping
     * @param request The request we are processing
     */
    protected ActionMapping processMapping(String path,
                                           HttpServletRequest request) {

        ActionMapping mapping = findMapping(path);
        if (mapping == null)
            mapping = mappings.getUnknown(request);
        return (mapping);

    }


    /**
     * Render the HTTP headers to defeat browser caching if requested.
     *
     * @param response The servlet response we are creating
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet exception occurs
     */
    protected void processNoCache(HttpServletResponse response)
  throws IOException, ServletException {

  if (!nocache)
      return;

  response.setHeader("Pragma", "No-cache");
  response.setHeader("Cache-Control", "no-cache");
  response.setDateHeader("Expires", 1);

    }


    /**
     * Identify and return the path component (from the request URI) that
     * we will use to select an ActionMapping to dispatch with.  If no such
     * path can be identified, return <code>null</code>.
     *
     * @param request The servlet request we are processing
     */
    protected String processPath(HttpServletRequest request) {

  String path = null;

  // For prefix matching, we want to match on the path info (if any)
        path =
            (String) request.getAttribute("javax.servlet.include.path_info");
        if (path == null)
            path = request.getPathInfo();
  if ((path != null) && (path.length() > 0))
      return (path);

  // For extension matching, we want to strip the extension (if any)
        path =
           (String) request.getAttribute("javax.servlet.include.servlet_path");
        if (path == null)
            path = request.getServletPath();
  int slash = path.lastIndexOf("/");
  int period = path.lastIndexOf(".");
  if ((period >= 0) && (period > slash))
      path = path.substring(0, period);
  return (path);

    }


    /**
     * General purpose preprocessing hook that can be overridden to support
     * application specific preprocessing activity.  This hook can examine
     * and/or modify the properties of the request and response objects, and
     * optionally complete the response if it wishes.
     * <p>
     * The default implementation does nothing.
     *
     * @param request The servlet request we are processing
     * @param response The servlet response we are generating
     *
     * @return <code>true</code> if the remainder of the standard processing
     *  should be performed, or <code>false</code> if the response has already
     *  been created so the calling method should immediately exit
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet exception occurs
     */
    protected boolean processPreprocess(HttpServletRequest request,
                                        HttpServletResponse response)
        throws IOException, ServletException {

        return (true)// Default implementation does nothing

    }


    /**
     * Populate the properties of the specified ActionForm from the request
     * parameters included with this request.
     *
     * @param formInstance The ActionForm we are processing
     * @param mapping The ActionMapping we are processing
     * @param request The servlet request we are processing
     *
     * @exception ServletException if thrown by RequestUtils.populate()
     */
    protected void processPopulate(ActionForm formInstance,
                                   ActionMapping mapping,
                                   HttpServletRequest request)
  throws ServletException {

        if (formInstance == null)
            return;
        //set the servlet of the ActionForm
        formInstance.setServlet(this);

        // Populate the bean properties of this ActionForm instance
        if (debug >= 1)
            log(" Populating bean properties from this request");
        formInstance.reset(mapping, request);
        //place the mapping's multipart request handler class
        //into the request to be read by the RequestUtils.populate
        //method in the event of a multipart request
        if (mapping.getMultipartClass() != null)
            request.setAttribute(Action.MULTIPART_KEY,
                                mapping.getMultipartClass());
        //also pass the mapping through the request
        request.setAttribute(Action.MAPPING_KEY,
                             mapping);
        RequestUtils.populate(formInstance, mapping.getPrefix(),
                              mapping.getSuffix(), request);

    }


    /**
     * Call the <code>validate()</code> method of the specified ActionForm,
     * and forward back to the input form if there are any errors.  Return
     * <code>true</code> if we should continue processing (and call the
     * <code>Action</code> class <code>perform()</code> method), or return
     * <code>false</code> if we have already forwarded control back to the
     * input form.
     *
     * @param mapping The ActionMapping we are processing
     * @param formInstance The ActionForm we are processing
     * @param request The servlet request we are processing
     * @param response The servlet response we are processing
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet exception occurs
     */
    protected boolean processValidate(ActionMapping mapping,
        ActionForm formInstance, HttpServletRequest request,
        HttpServletResponse response)
        throws IOException, ServletException {

        if (formInstance == null)
            return (true);
        if (debug >= 1)
            log(" Validating input form properties");

        // Was this submit cancelled?
  if ((request.getParameter(Constants.CANCEL_PROPERTY) != null) ||
            (request.getParameter(Constants.CANCEL_PROPERTY_X) != null)) {
            if (debug >= 1)
                log("  Cancelled transaction, no validation");
            return (true);
        }

        // Has validation been turned off on this mapping?
        if (!mapping.getValidate())
            return (true);

        // Call the validate() method of our ActionForm bean
        ActionErrors errors = formInstance.validate(mapping, request);
        if ((errors == null) || errors.empty()) {
            if (debug >= 1)
                log("  No errors detected, accepting input");
            return (true);
        }
       
        //does our form have a multipart request?
        if (formInstance.getMultipartRequestHandler() != null) {
            //rollback the request
            if (debug > 1) {
                log("  Rolling back the multipart request");
            }
           
            formInstance.getMultipartRequestHandler().rollback();
        }

        // Has an input form been specified for this mapping?
  String uri = mapping.getInput();
        if (uri == null) {
            if (debug >= 1)
                log("  No input form, but validation returned errors");
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                               internal.getMessage("noInput",
                                                   mapping.getPath()));
            return (false);
        }

  // Save our error messages and return to the input form if possible
  if (debug >= 1)
      log("  Validation error(s), redirecting to: " + uri);
  request.setAttribute(Action.ERROR_KEY, errors);
  RequestDispatcher rd = getServletContext().getRequestDispatcher(uri);
        if (rd == null) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                               internal.getMessage("requestDispatcher",
                                                   uri));
            return (false);
        }
  rd.forward(request, response);
  return (false);

    }


}


// ------------------------------------------------------------ Private Classes


/**
* Private digester <code>Rule</code> that adds a data source to the underlying
* <code>ActionServlet</code> instance.  The servlet context attributes key
* is specified by the "key" attribute on the data source element, and defaults
* to the value of <code>Action.DATA_SOURCE_KEY</code> if not specified.
*/

final class AddDataSourceRule extends Rule {


    public AddDataSourceRule(Digester digester) {

        super(digester);

    }


    public void begin(AttributeList attributes) throws Exception {

        // Acquire the key under which this data source will be stored
        String key = null;
        for (int i = 0; i < attributes.getLength(); i++) {
            if ("key".equals(attributes.getName(i))) {
                key = attributes.getValue(i);
                break;
            }
        }
        if (key == null)
            key = Action.DATA_SOURCE_KEY;

        // Pass the data source at the top of the stack to the action servlet
        // at the next-to-top position
        DataSource child = (DataSource) digester.peek(0);
        ActionServlet parent = (ActionServlet) digester.peek(1);
        if (digester.getDebug() >= 1)
            digester.log("Call " + parent.getClass().getName() +
                         ".addDataSource(" + key + ", " + child + ")");
        parent.addDataSource(key, child);

    }

}
TOP

Related Classes of org.apache.struts.action.AddDataSourceRule

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.