You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by tm...@apache.org on 2006/11/15 09:06:57 UTC

svn commit: r475154 - in /struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher: AbstractFilter.java ActionContextCleanUp.java FilterDispatcher.java

Author: tmjee
Date: Wed Nov 15 00:06:56 2006
New Revision: 475154

URL: http://svn.apache.org/viewvc?view=rev&rev=475154
Log:
WW-1489
 - Refactor ActionContextCleanUp and DispatcherFilter to have common logics in an abstract super class
 - moving this back in as discussed in Struts2 maling list.
 - This basically allows, (during sitemesh integration) that sitemesh decorators have access to struts internals and request gets wrapped and properly encoded before it reaches sitemesh.

Added:
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/AbstractFilter.java
Modified:
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ActionContextCleanUp.java
    struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/FilterDispatcher.java

Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/AbstractFilter.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/AbstractFilter.java?view=auto&rev=475154
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/AbstractFilter.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/AbstractFilter.java Wed Nov 15 00:06:56 2006
@@ -0,0 +1,226 @@
+/*
+ * $Id: ActionContextCleanUp.java 454720 2006-10-10 12:31:52Z tmjee $
+ *
+ * Copyright 2006 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.struts2.dispatcher;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * An abstract for superclass for Struts2 filter, encapsulating common logics and 
+ * helper methods usefull to subclass, to avoid duplication. 
+ * 
+ * Common logics encapsulated:-
+ * <ul>
+ * 	<li>
+ * 		Dispatcher instance creation through <code>createDispatcher</code> method that acts
+ * 		as a hook subclass could override. By default it creates an instance of Dispatcher.
+ *  </li>
+ *  <li>
+ *  	<code>postInit(FilterConfig)</code> is a hook subclass may use to add post initialization
+ *      logics in <code>{@link javax.servlet.Filter#init(FilterConfig)}</code>. It is called before
+ *      {@link javax.servlet.Filter#init(FilterConfig)} method ends.
+ *  </li>
+ *  <li>
+ *  	A default <code>{@link javax.servlet.Filter#destroy()}</code> that clean up Dispatcher by 
+ *      calling <code>dispatcher.cleanup()</code>
+ *  </li>
+ *  <li>
+ *  	<code>prepareDispatcherAndWrapRequest(HttpServletRequest, HttpServletResponse)</code> helper method
+ *      that basically called <code>dispatcher.prepare()</code>, wrap the HttpServletRequest and return the 
+ *      wrapped version.
+ *  </li>
+ *  <li>
+ *  	Various other common helper methods like
+ *      <ul>
+ *      	<li>getFilterConfig</li>
+ *      	<li>getServletContext</li>
+ *      </ul>
+ *  </li>
+ * </ul>
+ * 
+ * 
+ * @see Dispatcher
+ * @see FilterDispatcher
+ * @see ActionContextCleanUp
+ * 
+ * @version $Date$ $Id$
+ */
+public abstract class AbstractFilter implements Filter {
+
+	private static final Log LOG = LogFactory.getLog(AbstractFilter.class);
+	
+	/** 
+     * Internal copy of dispatcher, created when Filter instance gets initialized. 
+     * This is needed when ActionContextCleanUp filter is used (Sitemesh integration), 
+     * such that a {@link Dispatcher} instance could be prepared and request wrapped before
+     * Sitemesh is given a chance to handle the request. This results in Sitemesh 
+     * have access to internals of Struts2. With the following filter configuration
+     * <ol>
+     *   <li>ActionContextCleanUp</li>
+     *   <li>Sitemesh filter</li>
+     *   <li>FilterDispatcher</li>
+     * </ol>
+     * Both {@link ActionContextCleanUp} and {@link FilterDispatcher} will have a 
+     * copy of a {@link Dispatcher}, however only one will be copied to 
+     * {@link Dispatcher} ThreadLocal.
+     * 
+     * @see {@link #prepareDispatcherAndWrapRequest(HttpServletRequest, HttpServletResponse)}
+     */
+	private Dispatcher _internalCopyOfDispatcher; 
+	
+	protected FilterConfig filterConfig;
+	
+	/** Dispatcher instance to be used by subclass. */
+	protected Dispatcher dispatcher;
+	
+	
+	/**
+     * Initializes the filter
+     * 
+     * @param filterConfig The filter configuration
+     */
+    public void init(FilterConfig filterConfig) throws ServletException {
+        this.filterConfig = filterConfig;
+        _internalCopyOfDispatcher = createDispatcher(filterConfig);
+        postInit(filterConfig);
+    }
+    
+    /**
+     * Cleans up the dispatcher. Calls dispatcher.cleanup,
+     * which in turn releases local threads and destroys any DispatchListeners.
+     * 
+     * @see javax.servlet.Filter#destroy()
+     */
+    public void destroy() {
+        if (_internalCopyOfDispatcher == null) {
+        	LOG.warn("something is seriously wrong, Dispatcher is not initialized (null) ");
+        } else {
+        	_internalCopyOfDispatcher.cleanup();
+        }
+    }
+    
+    /**
+     * Hook for subclass todo custom initialization, called after 
+     * <code>javax.servlet.Filter.init(FilterConfig)</code>.
+     * 
+     * @param filterConfig
+     * @throws ServletException
+     */
+    protected abstract void postInit(FilterConfig filterConfig) throws ServletException;
+	
+    
+    /**
+     * Create a default {@link Dispatcher} that subclasses can override
+     * with a custom Dispatcher, if needed.
+     *
+     * @param filterConfig Our FilterConfig
+     * @return Initialized Dispatcher 
+     */
+    protected Dispatcher createDispatcher(FilterConfig filterConfig) {
+        Map<String,String> params = new HashMap<String,String>();
+        for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements(); ) {
+            String name = (String) e.nextElement();
+            String value = filterConfig.getInitParameter(name);
+            params.put(name, value);
+        }
+        return new Dispatcher(filterConfig.getServletContext(), params);
+    }
+    
+    
+    /**
+     * Provide a workaround for some versions of WebLogic.
+     * <p/>
+     * Servlet 2.3 specifies that the servlet context can be retrieved from the session. Unfortunately, some versions of
+     * WebLogic can only retrieve the servlet context from the filter config. Hence, this method enables subclasses to
+     * retrieve the servlet context from other sources.
+     *
+     * @return the servlet context.
+     */
+    protected ServletContext getServletContext() {
+        return filterConfig.getServletContext();
+    }
+    
+    /**
+     * Expose the FilterConfig instance.
+     *
+     * @return Our FilterConfit instance
+     */
+    protected FilterConfig getFilterConfig() {
+        return filterConfig;
+    }
+    
+    /**
+     * Wrap and return the given request, if needed, so as to to transparently
+     * handle multipart data as a wrapped class around the given request.
+     * 
+     * <p/>
+     * 
+     * Helper method that prepare <code>Dispatcher</code> 
+     * (by calling <code>Dispatcher.prepare(HttpServletRequest, HttpServletResponse)</code>)
+     * following by wrapping and returning  the wrapping <code>HttpServletRequest</code> [ through 
+     * <code>dispatcher.wrapRequest(HttpServletRequest, ServletContext)</code> ]
+     * 
+     * @param request Our ServletRequest object
+     * @param response Our ServerResponse object
+     * @return Wrapped HttpServletRequest object
+     * @throws ServletException on any error
+     */
+    protected HttpServletRequest prepareDispatcherAndWrapRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException {
+    	
+    	Dispatcher du = Dispatcher.getInstance();
+        
+    	// Prepare and wrap the request if the cleanup filter hasn't already, cleanup filter should be
+    	// configured first before struts2 dispatcher filter, hence when its cleanup filter's turn, 
+    	// static instance of Dispatcher should be null.
+    	if (du == null) {
+    		dispatcher = _internalCopyOfDispatcher;
+    		
+    		Dispatcher.setInstance(dispatcher);
+    		
+    		// prepare the request no matter what - this ensures that the proper character encoding
+    		// is used before invoking the mapper (see WW-9127)
+    		dispatcher.prepare(request, response);
+
+    		try {
+    			// Wrap request first, just in case it is multipart/form-data 
+    			// parameters might not be accessible through before encoding (ww-1278)
+    			request = dispatcher.wrapRequest(request, getServletContext());
+    		} catch (IOException e) {
+    			String message = "Could not wrap servlet request with MultipartRequestWrapper!";
+    			LOG.error(message, e);
+    			throw new ServletException(message, e);
+    		}
+    	}
+    	else {
+    		dispatcher = du;
+    	}
+		return request;
+    }
+}

Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ActionContextCleanUp.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ActionContextCleanUp.java?view=diff&rev=475154&r1=475153&r2=475154
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ActionContextCleanUp.java (original)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ActionContextCleanUp.java Wed Nov 15 00:06:56 2006
@@ -65,12 +65,24 @@
  *
  * @version $Date$ $Id$
  */
-public class ActionContextCleanUp implements Filter {
+public class ActionContextCleanUp extends AbstractFilter implements Filter {
 
     private static final Log LOG = LogFactory.getLog(ActionContextCleanUp.class);
 
     private static final String COUNTER = "__cleanup_recursion_counter";
 
+    
+    /**
+     * Does nothing in this implementation.
+     * 
+     * @see org.apache.struts2.dispatcher.AbstractFilter#postInit(javax.servlet.FilterConfig)
+     */
+    @Override
+    protected void postInit(FilterConfig filterConfig) throws ServletException {
+        // do nothing
+    }
+    
+    
     /**
      * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
      */
@@ -79,10 +91,14 @@
         HttpServletRequest request = (HttpServletRequest) req;
         HttpServletResponse response = (HttpServletResponse) res;
 
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("doFilter");
+        }
+        
         String timerKey = "ActionContextCleanUp_doFilter: ";
         try {
             UtilTimerStack.push(timerKey);
-
+            request = prepareDispatcherAndWrapRequest(request, response);
             try {
                 Integer count = (Integer)request.getAttribute(COUNTER);
                 if (count == null) {
@@ -132,11 +148,5 @@
         if (LOG.isDebugEnabled()) {
             LOG.debug("clean up ");
         }
-    }
-
-    public void destroy() {
-    }
-
-    public void init(FilterConfig arg0) throws ServletException {
     }
 }

Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/FilterDispatcher.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/FilterDispatcher.java?view=diff&rev=475154&r1=475153&r2=475154
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/FilterDispatcher.java (original)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/FilterDispatcher.java Wed Nov 15 00:06:56 2006
@@ -121,7 +121,7 @@
  *
  * @version $Date$ $Id$
  */
-public class FilterDispatcher implements StrutsStatics, Filter {
+public class FilterDispatcher extends AbstractFilter implements StrutsStatics, Filter {
 
     /**
      * Provide a logging instance.
@@ -168,15 +168,6 @@
      */
     private static ActionMapper actionMapper;
 
-    /**
-     * Provide FilterConfig instance, set on init.
-     */
-    private FilterConfig filterConfig;
-
-    /**
-     * Expose Dispatcher instance to subclass.
-     */
-    protected Dispatcher dispatcher;
 
     /**
      * Initializes the filter by creating a default dispatcher
@@ -184,9 +175,7 @@
      *
      * @param filterConfig The filter configuration
      */
-    public void init(FilterConfig filterConfig) throws ServletException {
-        dispatcher = createDispatcher(filterConfig);
-        this.filterConfig = filterConfig;
+    public void postInit(FilterConfig filterConfig) throws ServletException {
         String param = filterConfig.getInitParameter("packages");
         String packages = "org.apache.struts2.static template org.apache.struts2.interceptor.debugging";
         if (param != null) {
@@ -195,36 +184,6 @@
         this.pathPrefixes = parse(packages);
     }
 
-    /**
-     * Calls dispatcher.cleanup,
-     * which in turn releases local threads and destroys any DispatchListeners.
-     *
-     * @see javax.servlet.Filter#destroy()
-     */
-    public void destroy() {
-        if (dispatcher == null) {
-            LOG.warn("something is seriously wrong, Dispatcher is not initialized (null) ");
-        } else {
-            dispatcher.cleanup();
-        }
-    }
-    
-    /**
-     * Create a default {@link Dispatcher} that subclasses can override
-     * with a custom Dispatcher, if needed.
-     *
-     * @param filterConfig Our FilterConfig
-     * @return Initialized Dispatcher 
-     */
-    protected Dispatcher createDispatcher(FilterConfig filterConfig) {
-        Map<String,String> params = new HashMap<String,String>();
-        for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements(); ) {
-            String name = (String) e.nextElement();
-            String value = filterConfig.getInitParameter(name);
-            params.put(name, value);
-        }
-        return new Dispatcher(filterConfig.getServletContext(), params);
-    }
 
     /**
      * Modify state of StrutsConstants.STRUTS_SERVE_STATIC_CONTENT setting.
@@ -263,68 +222,6 @@
     }
     
     /**
-     * Provide a workaround for some versions of WebLogic.
-     * <p/>
-     * Servlet 2.3 specifies that the servlet context can be retrieved from the session. Unfortunately, some versions of
-     * WebLogic can only retrieve the servlet context from the filter config. Hence, this method enables subclasses to
-     * retrieve the servlet context from other sources.
-     *
-     * @return the servlet context.
-     */
-    protected ServletContext getServletContext() {
-        return filterConfig.getServletContext();
-    }
-
-    /**
-     * Expose the FilterConfig instance.
-     *
-     * @return Our FilterConfit instance
-     */
-    protected FilterConfig getFilterConfig() {
-        return filterConfig;
-    }
-
-    /**
-     * Wrap and return the given request, if needed, so as to to transparently
-     * handle multipart data as a wrapped class around the given request.
-     *
-     * @param request Our ServletRequest object
-     * @param response Our ServerResponse object
-     * @return Wrapped HttpServletRequest object
-     * @throws ServletException on any error
-     */
-    protected HttpServletRequest prepareDispatcherAndWrapRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException {
-
-        Dispatcher du = Dispatcher.getInstance();
-
-        // Prepare and wrap the request if the cleanup filter hasn't already, cleanup filter should be
-        // configured first before struts2 dispatcher filter, hence when its cleanup filter's turn,
-        // static instance of Dispatcher should be null.
-        if (du == null) {
-
-            Dispatcher.setInstance(dispatcher);
-
-            // prepare the request no matter what - this ensures that the proper character encoding
-            // is used before invoking the mapper (see WW-9127)
-            dispatcher.prepare(request, response);
-
-            try {
-                // Wrap request first, just in case it is multipart/form-data
-                // parameters might not be accessible through before encoding (ww-1278)
-                request = dispatcher.wrapRequest(request, getServletContext());
-            } catch (IOException e) {
-                String message = "Could not wrap servlet request with MultipartRequestWrapper!";
-                LOG.error(message, e);
-                throw new ServletException(message, e);
-            }
-        }
-        else {
-            dispatcher = du;
-        }
-        return request;
-    }
-
-    /**
      * Create a string array from a comma-delimited list of packages.
      *
      * @param packages A comma-delimited String listing packages
@@ -369,6 +266,10 @@
         HttpServletRequest request = (HttpServletRequest) req;
         HttpServletResponse response = (HttpServletResponse) res;
         ServletContext servletContext = getServletContext();
+        
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("doFilter");
+        }
 
         String timerKey = "FilterDispatcher_doFilter: ";
         try {