You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by ge...@apache.org on 2005/11/01 20:58:42 UTC

svn commit: r330112 - /struts/core/trunk/src/java/org/apache/struts/chain/ComposableRequestProcessor.java

Author: germuska
Date: Tue Nov  1 11:58:40 2005
New Revision: 330112

URL: http://svn.apache.org/viewcvs?rev=330112&view=rev
Log:
Provide support for specifying an alternative ActionContext implementation class 
in struts-config.xml rather than requiring subclassing of ComposableRequestProcessor.  See JavaDoc for details.

Modified:
    struts/core/trunk/src/java/org/apache/struts/chain/ComposableRequestProcessor.java

Modified: struts/core/trunk/src/java/org/apache/struts/chain/ComposableRequestProcessor.java
URL: http://svn.apache.org/viewcvs/struts/core/trunk/src/java/org/apache/struts/chain/ComposableRequestProcessor.java?rev=330112&r1=330111&r2=330112&view=diff
==============================================================================
--- struts/core/trunk/src/java/org/apache/struts/chain/ComposableRequestProcessor.java (original)
+++ struts/core/trunk/src/java/org/apache/struts/chain/ComposableRequestProcessor.java Tue Nov  1 11:58:40 2005
@@ -18,11 +18,15 @@
 
 
 import java.io.IOException;
+import java.lang.reflect.Constructor;
 
+import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
+import javax.servlet.UnavailableException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.commons.beanutils.ConstructorUtils;
 import org.apache.commons.chain.Catalog;
 import org.apache.commons.chain.CatalogFactory;
 import org.apache.commons.chain.Command;
@@ -35,6 +39,7 @@
 import org.apache.struts.config.ControllerConfig;
 import org.apache.struts.config.ModuleConfig;
 import org.apache.struts.upload.MultipartRequestWrapper;
+import org.apache.struts.util.RequestUtils;
 
 
 /**
@@ -63,6 +68,12 @@
     // ------------------------------------------------------ Instance Variables
 
 
+    private static final Class[] SERVLET_ACTION_CONTEXT_CTOR_SIGNATURE = new Class[] { ServletContext.class, HttpServletRequest.class, HttpServletResponse.class };
+
+
+    public static final String ACTION_CONTEXT_CLASS = "ACTION_CONTEXT_CLASS";
+
+
     /**
      * <p>The {@link CatalogFactory} from which catalog containing the the
      * base request-processing {@link Command} will be retrieved.</p>
@@ -83,6 +94,10 @@
     protected Command command = null;
 
 
+    private Class actionContextClass;
+
+    private Constructor servletActionContextConstructor = null;
+
     /**
      * <p>The <code>Log</code> instance for this class.</p>
      */
@@ -102,6 +117,8 @@
         catalogFactory = null;
         catalog = null;
         command = null;
+        actionContextClass = null;
+        servletActionContextConstructor = null;
 
     }
 
@@ -140,8 +157,45 @@
                                        commandName + "'");
         }
 
+        this.setActionContextClassName( controllerConfig.getProperty(ACTION_CONTEXT_CLASS) );
+        
     }
 
+    private void setActionContextClass(Class actionContextClass) throws ServletException {
+        this.actionContextClass = actionContextClass;
+        // if there is a custom class provided and if it uses our "preferred" constructor,
+        // cache a reference to that constructor rather than looking it up every time.
+        if (actionContextClass != null) {
+            this.servletActionContextConstructor = ConstructorUtils.getAccessibleConstructor(actionContextClass, SERVLET_ACTION_CONTEXT_CTOR_SIGNATURE);
+        } else {
+            this.servletActionContextConstructor = null;
+        }
+        
+    }
+
+    /**
+     * Make sure that the specified <code>className</code> identfies a class which can be found
+     * and which implements the <code>ActionContext</code> interface.
+     * @param className
+     * @throws ServletException
+     */
+    private void setActionContextClassName(String className) throws ServletException {
+        if (className != null && className.trim().length() > 0) {
+            log.debug("setActionContextClassName: requested context class: " + className);
+            try {
+                Class actionContextClass = RequestUtils.applicationClass(className);
+                if (!ActionContext.class.isAssignableFrom(actionContextClass)) {
+                    throw new UnavailableException("ActionContextClass [" + className + "] must implement ActionContext interface.");
+                }
+                this.setActionContextClass(actionContextClass);
+            } catch (ClassNotFoundException e) {
+                throw new UnavailableException("ActionContextClass " + className + " not found.");
+            }
+        } else {
+            log.debug("setActionContextClassName: no actionContextClass specified");
+            this.setActionContextClass(null);
+        }
+    }
 
     /**
      * <p>Establish the <code>CatalogFactory</code> which will be used to look up
@@ -196,15 +250,59 @@
         context.release();
     }
 
+    /**
+     * Provide the initialized <code>ActionContext</code> instance which will be used by this request.
+     * Internally, this simply calls <code>createActionContextInstance</code> followed by 
+     * <code>initializeActionContext</code>. 
+     * @param request
+     * @param response
+     * @return
+     * @throws ServletException
+     */
     protected ActionContext contextInstance(HttpServletRequest request,
-                                            HttpServletResponse response) {
-        // Create and populate a Context for this request
-        ServletActionContext context = new ServletActionContext(getServletContext(), request, response);
-        context.setActionServlet(this.servlet);
-        context.setModuleConfig(this.moduleConfig);
+                                            HttpServletResponse response) throws ServletException {
+        ActionContext context = createActionContextInstance(getServletContext(), request, response);
+        initializeActionContext(context);
         return context;
     }
 
+    /**
+     * Create a new instance of <code>ActionContext</code> according to configuration.  If no alternative was specified at initialization, 
+     * a new instance <code>ServletActionContext</code> is returned.  If an alternative was specified using the 
+     * <code>ACTION_CONTEXT_CLASS</code> property, then that value is treated as a classname, and an instance of that class
+     * is created.  If that class implements the same constructor that <code>ServletActionContext</code> does, then that constructor
+     * will be used: <code>ServletContext, HttpServletRequest, HttpServletResponse</code>; otherwise, it is assumed that the class
+     * has a no-arguments constructor.  If these constraints do not suit you, simply override this method in a subclass.
+     * @param servletContext
+     * @param request
+     * @param response
+     * @return
+     * @throws ServletException
+     */
+    protected ActionContext createActionContextInstance(ServletContext servletContext, HttpServletRequest request, HttpServletResponse response) throws ServletException {
+        if (this.actionContextClass == null) return new ServletActionContext(servletContext, request, response);
+        try {
+            if (this.servletActionContextConstructor == null) return (ActionContext) this.actionContextClass.newInstance();
+            return (ActionContext) this.servletActionContextConstructor.newInstance(new Object[] { servletContext, request, response });
+        } catch (Exception e) {
+            throw new ServletException("Error creating ActionContext instance of type " + this.actionContextClass, e);
+        }
+    }
+    
+    /**
+     * Set common properties on the given <code>ActionContext</code> instance so that commands in the chain
+     * can count on their presence.  Note that while this method does not require that its argument 
+     * be an instance of <code>ServletActionContext</code>, at this time many common Struts
+     * commands will be expecting to receive an <code>ActionContext</code> which is also a <code>ServletActionContext</code>.
+     * @param context
+     */
+    protected void initializeActionContext(ActionContext context) {
+        if (context instanceof ServletActionContext) {
+            ((ServletActionContext) context).setActionServlet(this.servlet);
+        }
+        context.setModuleConfig(this.moduleConfig);
+    }
+    
     /**
      * If this is a multipart request, wrap it with a special wrapper.
      * Otherwise, return the request unchanged.



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@struts.apache.org
For additional commands, e-mail: dev-help@struts.apache.org