Author: tmjee Date: Sat Nov 4 23:47:19 2006 New Revision: 471375 URL: http://svn.apache.org/viewvc?view=rev&rev=471375 Log: WW-1489 - Refactor ActionContextCleanUp and DispatcherFilter to have common logics in an abstract super class
Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/AbstractFilter.java struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/ActionContextCleanUpTest.java struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/FilterTest.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 struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/FilterDispatcherTest.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=471375 ============================================================================== --- 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 Sat Nov 4 23:47:19 2006 @@ -0,0 +1,191 @@ +/* + * $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 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>[EMAIL PROTECTED] javax.servlet.Filter#init(FilterConfig)}</code>. It is called before + * [EMAIL PROTECTED] javax.servlet.Filter#init(FilterConfig)} method ends. + * </li> + * <li> + * A default <code>[EMAIL PROTECTED] 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. */ + private Dispatcher _dispatcher; + + 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; + _dispatcher = createDispatcher(); + postInit(filterConfig); + } + + /** + * Cleans up the dispatcher + * + * @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(); + } + } + + /** + * 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 [EMAIL PROTECTED] Dispatcher}, this serves as a hook for subclass to overried + * such that a custom [EMAIL PROTECTED] Dispatcher} could be created. + * + * @return Dispatcher + */ + protected Dispatcher createDispatcher() { + return new Dispatcher(filterConfig.getServletContext()); + } + + /** + * 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. + * + * @param session the HTTP session where, in Servlet 2.3, the servlet context can be retrieved + * @return the servlet context. + */ + protected ServletContext getServletContext() { + return filterConfig.getServletContext(); + } + + /** + * Gets this filter's configuration + * + * @return The filter config + */ + protected FilterConfig getFilterConfig() { + return filterConfig; + } + + /** + * 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 + * @param response + * @return HttpServletRequest + * @throws ServletException + */ + 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 = _dispatcher; + + 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=471375&r1=471374&r2=471375 ============================================================================== --- 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 Sat Nov 4 23:47:19 2006 @@ -19,10 +19,8 @@ import java.io.IOException; -import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; -import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; @@ -56,29 +54,28 @@ * </ul> * <!-- SNIPPET END: description --> * - * @version $Date$ $Id$ * * @see FilterDispatcher + * @see AbstractFilter + * @see Dispatcher + * + * @version $Date$ $Id$ */ -public class ActionContextCleanUp implements Filter { +public class ActionContextCleanUp extends AbstractFilter { private static final Log LOG = LogFactory.getLog(ActionContextCleanUp.class); private static final String COUNTER = "__cleanup_recursion_counter"; protected FilterConfig filterConfig; - protected Dispatcher dispatcher; + /** - * Initializes the filter - * - * @param filterConfig The filter configuration + * Empty implementation. */ - public void init(FilterConfig filterConfig) throws ServletException { - this.filterConfig = filterConfig; - dispatcher = new Dispatcher(filterConfig.getServletContext()); + protected void postInit(FilterConfig filterConfig) throws ServletException { + // does nothing. } - /** * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) @@ -92,19 +89,7 @@ try { UtilTimerStack.push(timerKey); - // prepare the request no matter what - this ensures that the proper character encoding - // is used before invoking the mapper (see WW-9127) - Dispatcher.setInstance(dispatcher); - dispatcher.prepare(request, response); - - ServletContext servletContext = filterConfig.getServletContext(); - try { - request = dispatcher.wrapRequest(request, servletContext); - } catch (IOException e) { - String message = "Could not wrap servlet request with MultipartRequestWrapper!"; - LOG.error(message, e); - throw new ServletException(message, e); - } + request = prepareDispatcherAndWrapRequest(request, response); try { Integer count = (Integer)request.getAttribute(COUNTER); @@ -115,6 +100,11 @@ count = new Integer(count.intValue()+1); } request.setAttribute(COUNTER, count); + + if (LOG.isDebugEnabled()) { + LOG.debug("filtering counter="+count); + } + chain.doFilter(request, response); } finally { int counterVal = ((Integer)request.getAttribute(COUNTER)).intValue(); @@ -135,21 +125,20 @@ */ protected static void cleanUp(ServletRequest req) { // should we clean up yet? - if (req.getAttribute(COUNTER) != null && - ((Integer)req.getAttribute(COUNTER)).intValue() > 0 ) { - return; - } + Integer count = (Integer) req.getAttribute(COUNTER); + if (count != null && count > 0 ) { + if (LOG.isDebugEnabled()) { + LOG.debug("skipping cleanup counter="+count); + } + return; + } // always dontClean up the thread request, even if an action hasn't been executed ActionContext.setContext(null); - Dispatcher.setInstance(null); - } - - - /* (non-Javadoc) - * @see javax.servlet.Filter#destroy() - */ - public void destroy() { + + if (LOG.isDebugEnabled()) { + LOG.debug("clean up "); + } } } 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=471375&r1=471374&r2=471375 ============================================================================== --- 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 Sat Nov 4 23:47:19 2006 @@ -28,7 +28,6 @@ import java.util.StringTokenizer; import java.util.TimeZone; -import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; @@ -37,7 +36,6 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -118,49 +116,30 @@ * * @version $Date$ $Id$ */ -public class FilterDispatcher implements Filter, StrutsStatics { +public class FilterDispatcher extends AbstractFilter implements StrutsStatics { + private static final Log LOG = LogFactory.getLog(FilterDispatcher.class); - private FilterConfig filterConfig; private String[] pathPrefixes; - private Dispatcher dispatcher; private SimpleDateFormat df = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss"); private final Calendar lastModifiedCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); private final String lastModified = df.format(lastModifiedCal.getTime()); - /** - * Gets this filter's configuration - * - * @return The filter config - */ - protected FilterConfig getFilterConfig() { - return filterConfig; - } - - /** - * Cleans up the dispatcher - */ - public void destroy() { - if (dispatcher == null) { - LOG.warn("something is seriously wrong, DispatcherUtil is not initialized (null) "); - } else { - dispatcher.cleanup(); - } - } - + /** - * Initializes the dispatcher and filter + * Look for "packages" defined through filter-config's parameters. + * + * @param FilterConfig + * @throws ServletException */ - public void init(FilterConfig filterConfig) throws ServletException { - this.filterConfig = filterConfig; - String param = filterConfig.getInitParameter("packages"); + protected 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) { packages = param + " " + packages; } this.pathPrefixes = parse(packages); - dispatcher = createDispatcher(); } /** @@ -188,45 +167,29 @@ } - /* (non-Javadoc) + /** * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) */ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; - ServletContext servletContext = filterConfig.getServletContext(); + ServletContext servletContext = getServletContext(); String timerKey = "FilterDispatcher_doFilter: "; try { UtilTimerStack.push(timerKey); - Dispatcher du = Dispatcher.getInstance(); - // Prepare and wrap the request if the cleanup filter hasn't already - if (du == null) { - du = dispatcher; - // prepare the request no matter what - this ensures that the proper character encoding - // is used before invoking the mapper (see WW-9127) - du.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 = du.wrapRequest(request, servletContext); - } catch (IOException e) { - String message = "Could not wrap servlet request with MultipartRequestWrapper!"; - LOG.error(message, e); - throw new ServletException(message, e); - } - Dispatcher.setInstance(du); - } + request = prepareDispatcherAndWrapRequest(request, response); + ActionMapper mapper = null; ActionMapping mapping = null; try { mapper = ActionMapperFactory.getMapper(); - mapping = mapper.getMapping(request, du.getConfigurationManager()); + mapping = mapper.getMapping(request, dispatcher.getConfigurationManager()); } catch (Exception ex) { - du.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex); + LOG.error("error getting ActionMapping", ex); + dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex); ActionContextCleanUp.cleanUp(req); return; } @@ -264,18 +227,6 @@ } /** - * 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. - * - * @param session the HTTP session where, in Servlet 2.3, the servlet context can be retrieved - * @return the servlet context. - */ - protected ServletContext getServletContext(HttpSession session) { - return filterConfig.getServletContext(); - } - - /** * Finds a static resource * * @param name The resource name @@ -385,15 +336,5 @@ resourcePath = URLDecoder.decode(resourcePath, enc); return ClassLoaderUtil.getResourceAsStream(resourcePath, getClass()); - } - - /** - * Create a [EMAIL PROTECTED] Dispatcher}, this serves as a hook for subclass to overried - * such that a custom [EMAIL PROTECTED] Dispatcher} could be created. - * - * @return Dispatcher - */ - protected Dispatcher createDispatcher() { - return new Dispatcher(filterConfig.getServletContext()); } } Added: struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/ActionContextCleanUpTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/ActionContextCleanUpTest.java?view=auto&rev=471375 ============================================================================== --- struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/ActionContextCleanUpTest.java (added) +++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/ActionContextCleanUpTest.java Sat Nov 4 23:47:19 2006 @@ -0,0 +1,205 @@ +/* + * $Id: FilterDispatcherTest.java 449367 2006-09-24 06:49:04Z mrdon $ + * + * 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.LinkedHashMap; +import java.util.Map; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.struts2.dispatcher.mapper.ActionMapping; +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; + +import com.mockobjects.servlet.MockFilterChain; + +import junit.framework.TestCase; + +/** + * @version $Date$ $Id$ + */ +public class ActionContextCleanUpTest extends TestCase { + + + protected MockFilterConfig filterConfig; + protected MockHttpServletRequest request; + protected MockHttpServletResponse response; + protected MockFilterChain filterChain; + protected MockFilterChain filterChain2; + protected MockServletContext servletContext; + + protected Counter counter; + protected Map<String, Integer> _tmpStore; + protected InnerDispatcher _dispatcher; + protected InnerDispatcher _dispatcher2; + protected ActionContextCleanUp cleanUp; + protected ActionContextCleanUp cleanUp2; + + + @Override + protected void tearDown() throws Exception { + filterConfig = null; + request = null; + response = null; + filterChain = null; + filterChain2 = null; + servletContext = null; + counter = null; + _tmpStore = null; + _dispatcher = null; + _dispatcher2 = null; + cleanUp = null; + cleanUp2 = null; + } + + @Override + protected void setUp() throws Exception { + Dispatcher.setInstance(null); + + counter = new Counter(); + _tmpStore = new LinkedHashMap<String, Integer>(); + + filterConfig = new MockFilterConfig(); + request = new MockHttpServletRequest(); + response = new MockHttpServletResponse(); + servletContext = new MockServletContext(); + _dispatcher = new InnerDispatcher(servletContext) { + @Override + public String toString() { + return "dispatcher"; + } + }; + _dispatcher2 = new InnerDispatcher(servletContext){ + @Override + public String toString() { + return "dispatcher2"; + } + }; + + + filterChain = new MockFilterChain() { + @Override + public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { + _tmpStore.put("counter"+(counter.count++), (Integer) request.getAttribute("__cleanup_recursion_counter")); + } + }; + + cleanUp = new ActionContextCleanUp() { + @Override + protected Dispatcher createDispatcher() { + return _dispatcher; + } + }; + + cleanUp2 = new ActionContextCleanUp() { + @Override + protected Dispatcher createDispatcher() { + return _dispatcher2; + } + }; + + filterChain2 = new MockFilterChain() { + @Override + public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { + _tmpStore.put("counter"+(counter.count++), (Integer) request.getAttribute("__cleanup_recursion_counter")); + cleanUp2.doFilter(request, response, filterChain); + } + }; + } + + + public void testSingle() throws Exception { + assertFalse(_dispatcher.prepare); + assertFalse(_dispatcher.wrapRequest); + assertNull(request.getAttribute("__cleanup_recursion_counter")); + + cleanUp.init(filterConfig); + cleanUp.doFilter(request, response, filterChain); + cleanUp.destroy(); + + assertEquals(_tmpStore.size(), 1); + assertEquals(_tmpStore.get("counter0"), new Integer(1)); + + assertTrue(_dispatcher.prepare); + assertTrue(_dispatcher.wrapRequest); + assertEquals(request.getAttribute("__cleanup_recursion_counter"), new Integer("0")); + } + + public void testMultiple() throws Exception { + assertFalse(_dispatcher.prepare); + assertFalse(_dispatcher.wrapRequest); + assertFalse(_dispatcher2.prepare); + assertFalse(_dispatcher2.wrapRequest); + assertNull(request.getAttribute("__cleanup_recursion_counter")); + + cleanUp.init(filterConfig); + cleanUp2.init(filterConfig); + cleanUp.doFilter(request, response, filterChain2); + cleanUp2.destroy(); + cleanUp.destroy(); + + assertEquals(_tmpStore.size(), 2); + assertEquals(_tmpStore.get("counter0"), new Integer(1)); + assertEquals(_tmpStore.get("counter1"), new Integer(2)); + + assertFalse(_dispatcher2.prepare); + assertFalse(_dispatcher2.wrapRequest); + assertTrue(_dispatcher.prepare); + assertTrue(_dispatcher.wrapRequest); + assertEquals(request.getAttribute("__cleanup_recursion_counter"), new Integer("0")); + } + + + class InnerDispatcher extends Dispatcher { + public boolean prepare = false; + public boolean wrapRequest = false; + public boolean service = false; + + public InnerDispatcher(ServletContext servletContext) { + super(servletContext); + } + + @Override + public void prepare(HttpServletRequest request, HttpServletResponse response) { + prepare = true; + } + + @Override + public HttpServletRequest wrapRequest(HttpServletRequest request, ServletContext servletContext) throws IOException { + wrapRequest = true; + return request; + } + + @Override + public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) throws ServletException { + service = true; + } + } + + class Counter { + public int count=0; + } +} Modified: struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/FilterDispatcherTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/FilterDispatcherTest.java?view=diff&rev=471375&r1=471374&r2=471375 ============================================================================== --- struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/FilterDispatcherTest.java (original) +++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/FilterDispatcherTest.java Sat Nov 4 23:47:19 2006 @@ -47,11 +47,13 @@ /** * FilterDispatcher TestCase. * + * @version $Date$ $Id$ */ public class FilterDispatcherTest extends StrutsTestCase { public void testParsePackages() throws Exception { + FilterDispatcher filterDispatcher = new FilterDispatcher(); String[] result1 = filterDispatcher.parse("foo.bar.package1 foo.bar.package2 foo.bar.package3"); String[] result2 = filterDispatcher.parse("foo.bar.package1\tfoo.bar.package2\tfoo.bar.package3"); @@ -136,12 +138,12 @@ MockHttpServletRequest req = new MockHttpServletRequest(servletContext); MockHttpServletResponse res = new MockHttpServletResponse(); MockFilterChain chain = new MockFilterChain(); - final NoOpDispatcher dispatcher = new NoOpDispatcher(servletContext); + final NoOpDispatcher _dispatcher = new NoOpDispatcher(servletContext); Dispatcher.setInstance(null); ConfigurationManager confManager = new ConfigurationManager(); confManager.setConfiguration(new DefaultConfiguration()); - dispatcher.setConfigurationManager(confManager); + _dispatcher.setConfigurationManager(confManager); ObjectFactory.setObjectFactory(new InnerObjectFactory()); @@ -152,13 +154,13 @@ FilterDispatcher filter = new FilterDispatcher() { protected Dispatcher createDispatcher() { - return dispatcher; + return _dispatcher; } }; filter.init(filterConfig); filter.doFilter(req, res, chain); - assertFalse(dispatcher.serviceRequest); + assertFalse(_dispatcher.serviceRequest); } finally { Settings.reset(); @@ -172,12 +174,12 @@ MockHttpServletRequest req = new MockHttpServletRequest(servletContext); MockHttpServletResponse res = new MockHttpServletResponse(); MockFilterChain chain = new MockFilterChain(); - final InnerDispatcher dispatcher = new InnerDispatcher(servletContext); + final InnerDispatcher _dispatcher = new InnerDispatcher(servletContext); Dispatcher.setInstance(null); ConfigurationManager confManager = new ConfigurationManager(); confManager.setConfiguration(new DefaultConfiguration()); - dispatcher.setConfigurationManager(confManager); + _dispatcher.setConfigurationManager(confManager); ObjectFactory.setObjectFactory(new InnerObjectFactory()); @@ -189,14 +191,14 @@ FilterDispatcher filter = new FilterDispatcher() { protected Dispatcher createDispatcher() { - return dispatcher; + return _dispatcher; } }; filter.init(filterConfig); filter.doFilter(req, res, chain); - assertTrue(dispatcher.wrappedRequest); - assertTrue(dispatcher.serviceRequest); + assertTrue(_dispatcher.wrappedRequest); + assertTrue(_dispatcher.serviceRequest); } finally { Settings.reset(); Added: struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/FilterTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/FilterTest.java?view=auto&rev=471375 ============================================================================== --- struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/FilterTest.java (added) +++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/FilterTest.java Sat Nov 4 23:47:19 2006 @@ -0,0 +1,344 @@ +/* + * $Id: FilterDispatcherTest.java 449367 2006-09-24 06:49:04Z mrdon $ + * + * 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 javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; + +import org.apache.struts2.StrutsConstants; +import org.apache.struts2.config.Settings; +import org.apache.struts2.dispatcher.mapper.ActionMapper; +import org.apache.struts2.dispatcher.mapper.ActionMapping; +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; + +import com.mockobjects.servlet.MockFilterChain; +import com.opensymphony.xwork2.ObjectFactory; +import com.opensymphony.xwork2.config.ConfigurationManager; + + +/** + * + * @version $Date$ $Id$ + */ +public class FilterTest extends TestCase { + + protected MockFilterConfig filterConfig; + protected MockHttpServletRequest request; + protected MockHttpServletResponse response; + protected MockFilterChain filterChain; + protected MockFilterChain filterChain2; + protected MockServletContext servletContext; + + protected InnerDispatcher _dispatcher1; + protected InnerDispatcher _dispatcher2; + protected ActionContextCleanUp cleanUp; + protected FilterDispatcher filterDispatcher; + + protected int cleanUpFilterCreateDispatcherCount = 0; // number of times clean up filter create a dispatcher + protected int filterDispatcherCreateDispatcherCount = 0; // number of times FilterDispatcher create a dispatcher + + + @Override + protected void tearDown() throws Exception { + filterConfig = null; + request = null; + response = null; + filterChain = null; + filterChain2 = null; + servletContext = null; + _dispatcher1 = null; + _dispatcher2 = null; + cleanUp = null; + filterDispatcher = null; + } + + @Override + protected void setUp() throws Exception { + Dispatcher.setInstance(null); + + filterConfig = new MockFilterConfig(); + request = new MockHttpServletRequest(); + response = new MockHttpServletResponse(); + servletContext = new MockServletContext(); + + _dispatcher1 = new InnerDispatcher(servletContext){ + @Override + public String toString() { + return "dispatcher1"; + } + }; + _dispatcher2 = new InnerDispatcher(servletContext){ + @Override + public String toString() { + return "dispatcher2"; + } + }; + filterChain = new MockFilterChain() { + @Override + public void doFilter(ServletRequest req, ServletResponse res) throws IOException, ServletException { + filterDispatcher.doFilter(req, res, filterChain2); + } + }; + filterChain2 = new MockFilterChain() { + @Override + public void doFilter(ServletRequest req, ServletResponse res) throws IOException, ServletException { + } + }; + + + cleanUp = new ActionContextCleanUp() { + @Override + protected Dispatcher createDispatcher() { + cleanUpFilterCreateDispatcherCount++; + return _dispatcher1; + } + + @Override + public String toString() { + return "cleanUp"; + } + }; + + filterDispatcher = new FilterDispatcher() { + @Override + protected Dispatcher createDispatcher() { + filterDispatcherCreateDispatcherCount++; + return _dispatcher2; + } + + @Override + public String toString() { + return "filterDispatcher"; + } + }; + } + + + public void testUsingFilterDispatcherOnly() throws Exception { + ObjectFactory oldObjecFactory = ObjectFactory.getObjectFactory(); + try { + ObjectFactory.setObjectFactory(new InnerObjectFactory()); + Settings.set(StrutsConstants.STRUTS_MAPPER_CLASS, "org.apache.struts2.dispatcher.FilterTest$InnerMapper"); + + assertEquals(cleanUpFilterCreateDispatcherCount, 0); + assertEquals(filterDispatcherCreateDispatcherCount, 0); + assertFalse(_dispatcher1.prepare); + assertFalse(_dispatcher1.wrapRequest); + assertFalse(_dispatcher1.service); + assertFalse(_dispatcher2.prepare); + assertFalse(_dispatcher2.wrapRequest); + assertFalse(_dispatcher2.service); + + filterDispatcher.init(filterConfig); + filterDispatcher.doFilter(request, response, filterChain2); + filterDispatcher.destroy(); + + // we are using FilterDispatcher only, so cleanUp filter's Dispatcher should not be created. + assertEquals(cleanUpFilterCreateDispatcherCount, 0); + assertEquals(filterDispatcherCreateDispatcherCount, 1); + assertFalse(_dispatcher1.prepare); + assertFalse(_dispatcher1.wrapRequest); + assertFalse(_dispatcher1.service); + assertTrue(_dispatcher2.prepare); + assertTrue(_dispatcher2.wrapRequest); + assertTrue(_dispatcher2.service); + assertTrue(Dispatcher.getInstance() == null); + } + finally { + ObjectFactory.setObjectFactory(oldObjecFactory); + } + } + + public void testUsingFilterDispatcherOnly_Multiple() throws Exception { + ObjectFactory oldObjecFactory = ObjectFactory.getObjectFactory(); + try { + ObjectFactory.setObjectFactory(new InnerObjectFactory()); + Settings.set(StrutsConstants.STRUTS_MAPPER_CLASS, "org.apache.struts2.dispatcher.FilterTest$InnerMapper"); + + assertEquals(cleanUpFilterCreateDispatcherCount, 0); + assertEquals(filterDispatcherCreateDispatcherCount, 0); + assertFalse(_dispatcher1.prepare); + assertFalse(_dispatcher1.wrapRequest); + assertFalse(_dispatcher1.service); + assertFalse(_dispatcher2.prepare); + assertFalse(_dispatcher2.wrapRequest); + assertFalse(_dispatcher2.service); + + filterDispatcher.init(filterConfig); + filterDispatcher.doFilter(request, response, filterChain2); + filterDispatcher.doFilter(request, response, filterChain2); + filterDispatcher.destroy(); + + assertEquals(cleanUpFilterCreateDispatcherCount, 0); + // We should create dispatcher once, although filter.doFilter(...) is called many times. + assertEquals(filterDispatcherCreateDispatcherCount, 1); + assertFalse(_dispatcher1.prepare); + assertFalse(_dispatcher1.wrapRequest); + assertFalse(_dispatcher1.service); + assertTrue(_dispatcher2.prepare); + assertTrue(_dispatcher2.wrapRequest); + assertTrue(_dispatcher2.service); + assertTrue(Dispatcher.getInstance() == null); + } + finally { + ObjectFactory.setObjectFactory(oldObjecFactory); + } + } + + public void testUsingCleanUpAndFilterDispatcher() throws Exception { + ObjectFactory oldObjecFactory = ObjectFactory.getObjectFactory(); + try { + ObjectFactory.setObjectFactory(new InnerObjectFactory()); + Settings.set(StrutsConstants.STRUTS_MAPPER_CLASS, "org.apache.struts2.dispatcher.FilterTest$InnerMapper"); + + assertEquals(cleanUpFilterCreateDispatcherCount, 0); + assertEquals(filterDispatcherCreateDispatcherCount, 0); + assertFalse(_dispatcher1.prepare); + assertFalse(_dispatcher1.wrapRequest); + assertFalse(_dispatcher1.service); + assertFalse(_dispatcher2.prepare); + assertFalse(_dispatcher2.wrapRequest); + assertFalse(_dispatcher2.service); + + cleanUp.init(filterConfig); + filterDispatcher.init(filterConfig); + cleanUp.doFilter(request, response, filterChain); + filterDispatcher.destroy(); + cleanUp.destroy(); + + assertEquals(cleanUpFilterCreateDispatcherCount, 1); + assertEquals(filterDispatcherCreateDispatcherCount, 1); + assertTrue(_dispatcher1.prepare); + assertTrue(_dispatcher1.wrapRequest); + assertTrue(_dispatcher1.service); + assertFalse(_dispatcher2.prepare); + assertFalse(_dispatcher2.wrapRequest); + assertFalse(_dispatcher2.service); + assertTrue(Dispatcher.getInstance() == null); + } + finally { + ObjectFactory.setObjectFactory(oldObjecFactory); + } + } + + + public void testUsingCleanUpAndFilterDispatcher_Multiple() throws Exception { + ObjectFactory oldObjecFactory = ObjectFactory.getObjectFactory(); + try { + ObjectFactory.setObjectFactory(new InnerObjectFactory()); + Settings.set(StrutsConstants.STRUTS_MAPPER_CLASS, "org.apache.struts2.dispatcher.FilterTest$InnerMapper"); + + assertEquals(cleanUpFilterCreateDispatcherCount, 0); + assertEquals(filterDispatcherCreateDispatcherCount, 0); + assertFalse(_dispatcher1.prepare); + assertFalse(_dispatcher1.wrapRequest); + assertFalse(_dispatcher1.service); + assertFalse(_dispatcher2.prepare); + assertFalse(_dispatcher2.wrapRequest); + assertFalse(_dispatcher2.service); + + cleanUp.init(filterConfig); + filterDispatcher.init(filterConfig); + cleanUp.doFilter(request, response, filterChain); + cleanUp.doFilter(request, response, filterChain); + filterDispatcher.destroy(); + cleanUp.destroy(); + + assertEquals(cleanUpFilterCreateDispatcherCount, 1); + assertEquals(filterDispatcherCreateDispatcherCount, 1); + assertTrue(_dispatcher1.prepare); + assertTrue(_dispatcher1.wrapRequest); + assertTrue(_dispatcher1.service); + assertFalse(_dispatcher2.prepare); + assertFalse(_dispatcher2.wrapRequest); + assertFalse(_dispatcher2.service); + assertTrue(Dispatcher.getInstance() == null); + } + finally { + ObjectFactory.setObjectFactory(oldObjecFactory); + } + } + + + class InnerDispatcher extends Dispatcher { + public boolean prepare = false; + public boolean wrapRequest = false; + public boolean service = false; + + public InnerDispatcher(ServletContext servletContext) { + super(servletContext); + } + + @Override + public void prepare(HttpServletRequest request, HttpServletResponse response) { + prepare = true; + } + + @Override + public HttpServletRequest wrapRequest(HttpServletRequest request, ServletContext servletContext) throws IOException { + wrapRequest = true; + return request; + } + + @Override + public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) throws ServletException { + service = true; + } + } + + class NullInnerMapper implements ActionMapper { + public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) { + return null; + } + + public String getUriFromActionMapping(ActionMapping mapping) { + return null; + } + } + + public static class InnerMapper implements ActionMapper { + + public InnerMapper() {} + + public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) { + return new ActionMapping(); + } + + public String getUriFromActionMapping(ActionMapping mapping) { + return ""; + } + } + + class InnerObjectFactory extends ObjectFactory { + public InnerObjectFactory() { + super(); + } + } +} +