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 [EMAIL PROTECTED] CatalogFactory} from which catalog containing the the * base request-processing [EMAIL PROTECTED] 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: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]