WW-4518 Drops FilterDispatcher

This commit is contained in:
Lukasz Lenart
2015-06-23 16:09:34 +02:00
parent e133b9efc2
commit 8de090fda2
16 changed files with 46 additions and 1575 deletions
+1 -1
View File
@@ -10,7 +10,7 @@
<filter>
<filter-name>action2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
+1 -1
View File
@@ -10,7 +10,7 @@
<filter>
<filter-name>action2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
@@ -13,7 +13,7 @@
<filter>
<filter-name>action2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
@@ -1,92 +0,0 @@
/*
* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.config;
import javax.servlet.ServletContext;
/**
* This singleton holds an instance of the web servlet context.
* <p/>
* This is needed for running Struts on Weblogic Server 6.1
* because there is no provision to retrieve the servlet context
* from the web session object.
* <p/>
* This class is created to bet that this singleton can be set by
* {@link org.apache.struts2.dispatcher.FilterDispatcherCompatWeblogic61}
* before the servlet context is needed by
* {@link org.apache.struts2.lifecycle.SessionLifecycleListener}
* which will use this object to get it.
*
*/
public class ServletContextSingleton {
/**
* The web servlet context. Holding this is the
* purpose of this singleton.
*/
private ServletContext servletContext;
/**
* The sole instance of this class.
*/
private static ServletContextSingleton singleton;
/**
* Constructor which cannot be called
* publicly.
*/
private ServletContextSingleton() {
}
/**
* Answers the singleton.
* <p/>
* At some point, the caller must populate the web servlet
* context.
*
* @return Answers the singleton instance of this class
*/
public static ServletContextSingleton getInstance() {
if (singleton == null) {
singleton = new ServletContextSingleton();
}
return singleton;
}
/**
* Gets the servlet context
*
* @return The web servlet context
*/
public ServletContext getServletContext() {
return servletContext;
}
/**
* Sets the servlet context
*
* @param context The web servlet context
*/
public void setServletContext(ServletContext context) {
servletContext = context;
}
}
@@ -1,152 +0,0 @@
/*
* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* <!-- SNIPPET START: description -->
* Special filter designed to work with the {@link FilterDispatcher} and allow
* for easier integration with SiteMesh. Normally, ordering your filters to have
* SiteMesh go first, and then {@link FilterDispatcher} go second is perfectly fine.
* However, sometimes you may wish to access Struts features, including the
* value stack, from within your SiteMesh decorators. Because {@link FilterDispatcher}
* cleans up the {@link ActionContext}, your decorator won't have access to the
* data you want.
* <p/>
* <p/>
* By adding this filter, the {@link FilterDispatcher} will know to not clean up and
* instead defer cleanup to this filter. The ordering of the filters should then be:
* <p/>
* <ul>
* <li>this filter</li>
* <li>SiteMesh filter</li>
* <li>{@link FilterDispatcher}</li>
* </ul>
* <!-- SNIPPET END: description -->
*
*
* @deprecated Since Struts 2.1.3, use {@link org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter} and
* {@link org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter} to use other Servlet filters that need access to
* the ActionContext
* @see FilterDispatcher
* @see Dispatcher
* @see org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter
* @see org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter
*
* @version $Date$ $Id$
*/
public class ActionContextCleanUp implements Filter {
private static final Logger LOG = LogManager.getLogger(ActionContextCleanUp.class);
private static final String COUNTER = "__cleanup_recursion_counter";
/**
* @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 {
showDeprecatedWarning();
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String timerKey = "ActionContextCleanUp_doFilter: ";
try {
UtilTimerStack.push(timerKey);
try {
Integer count = (Integer)request.getAttribute(COUNTER);
if (count == null) {
count = 1;
}
else {
count = count.intValue() + 1;
}
request.setAttribute(COUNTER, count);
//LOG.debug("filtering counter="+count);
chain.doFilter(request, response);
} finally {
int counterVal = ((Integer) request.getAttribute(COUNTER));
counterVal -= 1;
request.setAttribute(COUNTER, counterVal);
cleanUp(request);
}
}
finally {
UtilTimerStack.pop(timerKey);
}
}
/**
* Clean up the request of threadlocals if this is the last execution
*
* @param req The servlet request
*/
protected static void cleanUp(ServletRequest req) {
// should we clean up yet?
Integer count = (Integer) req.getAttribute(COUNTER);
if (count != null && count > 0 ) {
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);
}
public void destroy() {
}
public void init(FilterConfig arg0) throws ServletException {
}
private void showDeprecatedWarning() {
String msg =
"\n\n" +
"***************************************************************************\n" +
"* WARNING!!! *\n" +
"* *\n" +
"* >>> ActionContextCleanUp <<< is deprecated! Please use the new filters! *\n" +
"* *\n" +
"* This can be a source of unpredictable problems! *\n" +
"* *\n" +
"* Please refer to the docs for more details! *\n" +
"* http://struts.apache.org/docs/webxml.html *\n" +
"* *\n" +
"***************************************************************************\n\n";
System.out.println(msg);
}
}
@@ -9,6 +9,8 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.StrutsException;
import org.apache.struts2.dispatcher.ng.ExecuteOperations;
import org.apache.struts2.dispatcher.ng.PrepareOperations;
import org.apache.struts2.views.freemarker.FreemarkerManager;
import javax.servlet.ServletContext;
@@ -53,7 +55,7 @@ public class DefaultDispatcherErrorHandler implements DispatcherErrorHandler {
}
public void handleError(HttpServletRequest request, HttpServletResponse response, int code, Exception e) {
Boolean devModeOverride = FilterDispatcher.getDevModeOverride();
Boolean devModeOverride = PrepareOperations.getDevModeOverride();
if (devModeOverride != null ? devModeOverride : devMode) {
handleErrorInDevMode(response, code, e);
} else {
@@ -1,460 +0,0 @@
/*
* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.config.Configuration;
import com.opensymphony.xwork2.config.ConfigurationProvider;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.ClassLoaderUtil;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.ValueStackFactory;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.RequestUtils;
import org.apache.struts2.StrutsStatics;
import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.dispatcher.ng.filter.FilterHostConfig;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* Master filter for Struts that handles four distinct
* responsibilities:
* <p/>
* <ul>
* <p/>
* <li>Executing actions</li>
* <p/>
* <li>Cleaning up the {@link ActionContext} (see note)</li>
* <p/>
* <li>Serving static content</li>
* <p/>
* <li>Kicking off XWork's interceptor chain for the request lifecycle</li>
* <p/>
* </ul>
* <p/>
* <p/> <b>IMPORTANT</b>: this filter must be mapped to all requests. Unless you know exactly what you are doing, always
* map to this URL pattern: /*
* <p/>
* <p/> <b>Executing actions</b>
* <p/>
* <p/> This filter executes actions by consulting the {@link ActionMapper} and determining if the requested URL should
* invoke an action. If the mapper indicates it should, <b>the rest of the filter chain is stopped</b> and the action is
* invoked. This is important, as it means that filters like the SiteMesh filter must be placed <b>before</b> this
* filter or they will not be able to decorate the output of actions.
* <p/>
* <p/> <b>Cleaning up the {@link ActionContext}</b>
* <p/>
* <p/> This filter will also automatically clean up the {@link ActionContext} for you, ensuring that no memory leaks
* take place. However, this can sometimes cause problems integrating with other products like SiteMesh. See {@link
* ActionContextCleanUp} for more information on how to deal with this.
* <p/>
* <p/> <b>Serving static content</b>
* <p/>
* <p/> This filter also serves common static content needed when using various parts of Struts, such as JavaScript
* files, CSS files, etc. It works by looking for requests to /struts/*, and then mapping the value after "/struts/"
* to common packages in Struts and, optionally, in your class path. By default, the following packages are
* automatically searched:
* <p/>
* <ul>
* <p/>
* <li>org.apache.struts2.static</li>
* <p/>
* <li>template</li>
* <p/>
* </ul>
* <p/>
* <p/> This means that you can simply request /struts/xhtml/styles.css and the XHTML UI theme's default stylesheet
* will be returned. Likewise, many of the AJAX UI components require various JavaScript files, which are found in the
* org.apache.struts2.static package. If you wish to add additional packages to be searched, you can add a comma
* separated (space, tab and new line will do as well) list in the filter init parameter named "packages". <b>Be
* careful</b>, however, to expose any packages that may have sensitive information, such as properties file with
* database access credentials.
* <p/>
* <p/>
* <p/>
* <p>
* <p/>
* This filter supports the following init-params:
* <!-- START SNIPPET: params -->
* <p/>
* <ul>
* <p/>
* <li><b>config</b> - a comma-delimited list of XML configuration files to load.</li>
* <p/>
* <li><b>actionPackages</b> - a comma-delimited list of Java packages to scan for Actions.</li>
* <p/>
* <li><b>configProviders</b> - a comma-delimited list of Java classes that implement the
* {@link ConfigurationProvider} interface that should be used for building the {@link Configuration}.</li>
* <p/>
* <li><b>loggerFactory</b> - The class name of the {@link LoggerFactory} implementation.</li>
* <p/>
* <li><b>*</b> - any other parameters are treated as framework constants.</li>
* <p/>
* </ul>
* <p/>
* <!-- END SNIPPET: params -->
* <p/>
* </p>
* <p/>
* To use a custom {@link Dispatcher}, the <code>createDispatcher()</code> method could be overriden by
* the subclass.
*
* @version $Date$ $Id$
* @deprecated Since Struts 2.1.3, use {@link org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter} instead or
* {@link org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter} and {@link org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter}
* if needing using the {@link ActionContextCleanUp} filter in addition to this one
*
* @see ActionMapper
* @see ActionContextCleanUp
* @see org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
* @see org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter
* @see org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter
*/
public class FilterDispatcher implements StrutsStatics, Filter {
/**
* Provide a logging instance.
*/
private Logger log;
/**
* Provide ActionMapper instance, set by injection.
*/
private ActionMapper actionMapper;
/**
* Provide FilterConfig instance, set on init.
*/
private FilterConfig filterConfig;
/**
* Expose Dispatcher instance to subclass.
*/
protected Dispatcher dispatcher;
/**
* Loads static resources, set by injection.
*/
protected StaticContentLoader staticResourceLoader;
/**
* Maintains per-request override of devMode configuration.
*/
private static ThreadLocal<Boolean> devModeOverride = new InheritableThreadLocal<>();
/**
* Initializes the filter by creating a default dispatcher
* and setting the default packages for static resources.
*
* @param filterConfig The filter configuration
*/
public void init(FilterConfig filterConfig) throws ServletException {
try {
this.filterConfig = filterConfig;
initLogging();
dispatcher = createDispatcher(filterConfig);
dispatcher.init();
dispatcher.getContainer().inject(this);
staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));
} finally {
ActionContext.setContext(null);
}
}
/**
* @deprecated since 2.5
*/
@Deprecated
private void initLogging() {
String factoryName = filterConfig.getInitParameter("loggerFactory");
if (factoryName != null) {
try {
Class cls = ClassLoaderUtil.loadClass(factoryName, this.getClass());
LoggerFactory fac = (LoggerFactory) cls.newInstance();
LoggerFactory.setLoggerFactory(fac);
} catch (InstantiationException e) {
System.err.println("Unable to instantiate logger factory: " + factoryName + ", using default");
e.printStackTrace();
} catch (IllegalAccessException e) {
System.err.println("Unable to access logger factory: " + factoryName + ", using default");
e.printStackTrace();
} catch (ClassNotFoundException e) {
System.err.println("Unable to locate logger factory class: " + factoryName + ", using default");
e.printStackTrace();
}
}
log = LogManager.getLogger(FilterDispatcher.class);
}
/**
* 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 {
try {
dispatcher.cleanup();
} finally {
ActionContext.setContext(null);
}
}
}
/**
* Set an override of the static devMode value. Do not set this via a
* request parameter or any other unprotected method. Using a signed
* cookie is one safe way to turn it on per request.
*
* @param devMode the override value
*/
public static void overrideDevMode(boolean devMode) {
devModeOverride.set(devMode);
}
/**
* @return Boolean override value, or null if no override
*/
public static Boolean getDevModeOverride()
{
return devModeOverride.get();
}
/**
* 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<>();
for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements();) {
String name = (String) e.nextElement();
String value = filterConfig.getInitParameter(name);
params.put(name, value);
}
return createDispatcher(filterConfig.getServletContext(), params);
}
/**
* Create a default {@link Dispatcher} that subclasses can override
* with a custom Dispatcher, if needed. Called by
* createDispatcher(FilterConfig).
*
* @param ctx ServletContext
* @param params parameters from FilterConfig
* @return Initialized Dispatcher
*/
protected Dispatcher createDispatcher(ServletContext ctx, Map<String, String> params) {
return new Dispatcher(ctx, params);
}
/**
* Modify state of StrutsConstants.STRUTS_STATIC_CONTENT_LOADER setting.
* @param staticResourceLoader val New setting
*/
@Inject
public void setStaticResourceLoader(StaticContentLoader staticResourceLoader) {
this.staticResourceLoader = staticResourceLoader;
}
/**
* Modify ActionMapper instance.
* @param mapper New instance
*/
@Inject
public void setActionMapper(ActionMapper mapper) {
actionMapper = mapper;
}
/**
* 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);
} else {
dispatcher = du;
}
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);
} catch (IOException e) {
String message = "Could not wrap servlet request with MultipartRequestWrapper!";
log.error(message, e);
throw new ServletException(message, e);
}
return request;
}
/**
* Process an action or handle a request a static resource.
* <p/>
* The filter tries to match the request to an action mapping.
* If mapping is found, the action processes is delegated to the dispatcher's serviceAction method.
* If action processing fails, doFilter will try to create an error page via the dispatcher.
* <p/>
* Otherwise, if the request is for a static resource,
* the resource is copied directly to the response, with the appropriate caching headers set.
* <p/>
* If the request does not match an action mapping, or a static resource page,
* then it passes through.
*
* @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 {
showDeprecatedWarning();
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
ServletContext servletContext = getServletContext();
String timerKey = "FilterDispatcher_doFilter: ";
try {
// FIXME: this should be refactored better to not duplicate work with the action invocation
ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
ActionContext ctx = new ActionContext(stack.getContext());
ActionContext.setContext(ctx);
UtilTimerStack.push(timerKey);
request = prepareDispatcherAndWrapRequest(request, response);
ActionMapping mapping;
try {
mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());
} catch (Exception ex) {
log.error("error getting ActionMapping", ex);
dispatcher.sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
return;
}
if (mapping == null) {
// there is no action in this request, should we look for a static resource?
String resourcePath = RequestUtils.getServletPath(request);
if ("".equals(resourcePath) && null != request.getPathInfo()) {
resourcePath = request.getPathInfo();
}
if (staticResourceLoader.canHandle(resourcePath)) {
staticResourceLoader.findStaticResource(resourcePath, request, response);
} else {
// this is a normal request, let it pass through
chain.doFilter(request, response);
}
// The framework did its job here
return;
}
dispatcher.serviceAction(request, response, mapping);
} finally {
dispatcher.cleanUpRequest(request);
try {
ActionContextCleanUp.cleanUp(req);
} finally {
UtilTimerStack.pop(timerKey);
}
devModeOverride.remove();
}
}
private void showDeprecatedWarning() {
String msg =
"\n\n" +
"***********************************************************************\n" +
"* WARNING!!! *\n" +
"* *\n" +
"* >>> FilterDispatcher <<< is deprecated! Please use the new filters! *\n" +
"* *\n" +
"* This can be a source of unpredictable problems! *\n" +
"* *\n" +
"* Please refer to the docs for more details! *\n" +
"* http://struts.apache.org/docs/webxml.html *\n" +
"* *\n" +
"***********************************************************************\n\n";
System.out.println(msg);
}
}
@@ -1,108 +0,0 @@
/*
* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import org.apache.struts2.config.ServletContextSingleton;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
/**
* When running Weblogic Server 6.1, this class should be
* specified in web.xml instead of {@link FilterDispatcher}.
* <p/>
* This class properly handles the weblogic.jar handling
* of servlet filters. There is one serious incompatibility, and
* that is that while {@link FilterDispatcher#init(FilterConfig)}
* throws a {@link ServletException}, this class's method
* {@link #setFilterConfig(FilterConfig)} does not throw
* the exception. Since {@link #setFilterConfig(FilterConfig)}
* invokes {@link FilterDispatcher#init(FilterConfig)}, the setter
* must "swallow" the exception. This it does by logging the
* exception as an error.
*
* @deprecated Since Struts 2.1.3 as it probably isn't used anymore
*
*/
public class FilterDispatcherCompatWeblogic61 extends FilterDispatcher {
private static Logger LOG = LogManager.getLogger(FilterDispatcherCompatWeblogic61.class);
/**
* dummy setter for {@link #filterConfig}; this method
* sets up the {@link org.apache.struts2.config.ServletContextSingleton} with
* the servlet context from the filter configuration.
* <p/>
* This is needed by Weblogic Server 6.1 because it
* uses a slightly obsolete Servlet 2.3-minus spec
* whose {@link Filter} interface requires this method.
* <p/>
*
* @param filterConfig the filter configuration.
*/
public void setFilterConfig(FilterConfig filterConfig) {
try {
init(filterConfig);
} catch (ServletException se) {
LOG.error("Couldn't set the filter configuration in this filter", se);
}
ServletContextSingleton singleton = ServletContextSingleton.getInstance();
singleton.setServletContext(filterConfig.getServletContext());
}
/**
* answers the servlet context.
* <p/>
* Servlet 2.3 specifies that this can be retrieved from
* the session. Unfortunately, weblogic.jar can only retrieve
* the servlet context from the filter config. Hence, this
* returns the servlet context from the singleton that was
* setup by {@link #setFilterConfig(FilterConfig)}.
*
* @param session the HTTP session. Not used
* @return the servlet context.
*/
protected ServletContext getServletContext(HttpSession session) {
ServletContextSingleton singleton =
ServletContextSingleton.getInstance();
return singleton.getServletContext();
}
/**
* This method is required by Weblogic 6.1 SP4 because
* they defined this as a required method just before
* the Servlet 2.3 specification was finalized.
*
* @return the filter's filter configuration
*/
public FilterConfig getFilterConfig() {
return super.getFilterConfig();
}
}
@@ -47,6 +47,12 @@ public class PrepareOperations {
private static final Logger LOG = LogManager.getLogger(PrepareOperations.class);
/**
* Maintains per-request override of devMode configuration.
*/
private static ThreadLocal<Boolean> devModeOverride = new InheritableThreadLocal<>();
private Dispatcher dispatcher;
private static final String STRUTS_ACTION_MAPPING_KEY = "struts.actionMapping";
public static final String CLEANUP_RECURSION_COUNTER = "__cleanup_recursion_counter";
@@ -99,6 +105,7 @@ public class PrepareOperations {
} finally {
ActionContext.setContext(null);
Dispatcher.setInstance(null);
devModeOverride.remove();
}
}
@@ -200,4 +207,23 @@ public class PrepareOperations {
return false;
}
/**
* Set an override of the static devMode value. Do not set this via a
* request parameter or any other unprotected method. Using a signed
* cookie is one safe way to turn it on per request.
*
* @param devMode the override value
*/
public static void overrideDevMode(boolean devMode) {
devModeOverride.set(devMode);
}
/**
* @return Boolean override value, or null if no override
*/
public static Boolean getDevModeOverride()
{
return devModeOverride.get();
}
}
@@ -32,7 +32,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.dispatcher.FilterDispatcher;
import org.apache.struts2.dispatcher.ng.PrepareOperations;
import org.apache.struts2.views.freemarker.FreemarkerManager;
import org.apache.struts2.views.freemarker.FreemarkerResult;
@@ -137,7 +137,7 @@ public class DebuggingInterceptor extends AbstractInterceptor {
public String intercept(ActionInvocation inv) throws Exception {
boolean actionOnly = false;
boolean cont = true;
Boolean devModeOverride = FilterDispatcher.getDevModeOverride();
Boolean devModeOverride = PrepareOperations.getDevModeOverride();
boolean devMode = devModeOverride != null ? devModeOverride : this.devMode;
if (devMode) {
final ActionContext ctx = ActionContext.getContext();
@@ -26,7 +26,6 @@ package org.apache.struts2.util;
* if it requires shutdown hook whenever an ObjectFactory is to be
* destroyed.
*
* @see org.apache.struts2.dispatcher.FilterDispatcher
* @see org.apache.struts2.dispatcher.Dispatcher
*/
public interface ObjectFactoryDestroyable {
@@ -1,186 +0,0 @@
/*
* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.HashMap;
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();
cleanUp2 = new ActionContextCleanUp();
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 {
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));
assertEquals(request.getAttribute("__cleanup_recursion_counter"), new Integer("0"));
}
public void testMultiple() throws Exception {
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));
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, new HashMap<String,String>());
}
@Override
public void prepare(HttpServletRequest request, HttpServletResponse response) {
prepare = true;
}
@Override
public HttpServletRequest wrapRequest(HttpServletRequest request) throws IOException {
wrapRequest = true;
return request;
}
@Override
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
service = true;
}
}
class Counter {
public int count=0;
}
}
@@ -35,13 +35,12 @@ import com.opensymphony.xwork2.interceptor.Interceptor;
import com.opensymphony.xwork2.util.LocalizedTextUtil;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.StrutsInternalTestCase;
import org.apache.struts2.dispatcher.FilterDispatcherTest.InnerDestroyableObjectFactory;
import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
import org.apache.struts2.util.ObjectFactoryDestroyable;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
@@ -273,4 +272,13 @@ public class DispatcherTest extends StrutsInternalTestCase {
public boolean isInitialized = false;
public boolean isDestroyed = false;
}
public static class InnerDestroyableObjectFactory extends ObjectFactory implements ObjectFactoryDestroyable {
public boolean destroyed = false;
public void destroy() {
destroyed = true;
}
}
}
@@ -1,203 +0,0 @@
/*
* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 com.mockobjects.servlet.MockFilterChain;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.config.ConfigurationManager;
import com.opensymphony.xwork2.config.impl.DefaultConfiguration;
import org.apache.struts2.StrutsInternalTestCase;
import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.util.ObjectFactoryDestroyable;
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 javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
/**
* FilterDispatcher TestCase.
*
* @version $Date$ $Id$
*/
public class FilterDispatcherTest extends StrutsInternalTestCase {
public void testIfActionMapperIsNullDontServiceAction() throws Exception {
MockServletContext servletContext = new MockServletContext();
MockFilterConfig filterConfig = new MockFilterConfig(servletContext);
MockHttpServletRequest req = new MockHttpServletRequest(servletContext);
MockHttpServletResponse res = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
ConfigurationManager confManager = new ConfigurationManager();
confManager.setConfiguration(new DefaultConfiguration());
final NoOpDispatcher _dispatcher = new NoOpDispatcher(servletContext, confManager);
Dispatcher.setInstance(_dispatcher);
FilterDispatcher filter = new FilterDispatcher() {
protected Dispatcher createDispatcher() {
return _dispatcher;
}
};
filter.init(filterConfig);
filter.setActionMapper(null);
filter.doFilter(req, res, chain);
assertFalse(_dispatcher.serviceRequest);
}
public void testCharacterEncodingSetBeforeRequestWrappingAndActionService() throws Exception {
MockServletContext servletContext = new MockServletContext();
MockFilterConfig filterConfig = new MockFilterConfig(servletContext);
MockHttpServletRequest req = new MockHttpServletRequest(servletContext);
MockHttpServletResponse res = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
final InnerDispatcher _dispatcher = new InnerDispatcher(servletContext);
Dispatcher.setInstance(null);
_dispatcher.setDefaultEncoding("UTF-16_DUMMY");
FilterDispatcher filter = new FilterDispatcher() {
protected Dispatcher createDispatcher(FilterConfig filterConfig) {
return _dispatcher;
}
};
filter.init(filterConfig);
// set ActionMapper after init() as all dependencies will be injected in init()
filter.setActionMapper(new InnerActionMapper());
_dispatcher.setDefaultEncoding("UTF-16_DUMMY");
filter.doFilter(req, res, chain);
assertTrue(_dispatcher.wrappedRequest);
assertTrue(_dispatcher.serviceRequest);
}
// === inner class ========
public static class InnerObjectFactory extends ObjectFactory {
}
public static class NoOpDispatcher extends Dispatcher {
protected boolean wrappedRequest = false;
protected boolean serviceRequest = false;
public NoOpDispatcher(ServletContext servletContext, ConfigurationManager cm) {
super(servletContext, new HashMap());
this.configurationManager = cm;
}
@Override
public HttpServletRequest wrapRequest(HttpServletRequest request) throws IOException {
wrappedRequest = true;
return request;
}
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
serviceRequest = true;
}
@Override
public void sendError(HttpServletRequest request, HttpServletResponse response, int code, Exception e) {
// NO-OP
}
}
public static class InnerDispatcher extends Dispatcher {
protected boolean wrappedRequest = false;
protected boolean serviceRequest = false;
public InnerDispatcher(ServletContext servletContext) {
super(servletContext, new HashMap());
}
@Override
public HttpServletRequest wrapRequest(HttpServletRequest request) throws IOException {
wrappedRequest = true;
// if we set the chracter encoding AFTER we do wrap request, we will get
// a failing test
assertNotNull(request.getCharacterEncoding());
assertEquals("UTF-16_DUMMY", request.getCharacterEncoding());
return request;
}
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
serviceRequest = true;
// if we set the chracter encoding AFTER we do wrap request, we will get
// a failing test
assertNotNull(request.getCharacterEncoding());
assertEquals("UTF-16_DUMMY", request.getCharacterEncoding());
}
}
public static class InnerActionMapper implements ActionMapper {
public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager config) {
return new ActionMapping("action", "/", null, Collections.<String, Object>emptyMap());
}
public ActionMapping getMappingFromActionName(String actionName) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public String getUriFromActionMapping(ActionMapping mapping) {
return null;
}
}
public static class NullActionMapper implements ActionMapper {
public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager config) {
return null;
}
public ActionMapping getMappingFromActionName(String actionName) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public String getUriFromActionMapping(ActionMapping mapping) {
return null;
}
}
public static class InnerDestroyableObjectFactory extends ObjectFactory implements ObjectFactoryDestroyable {
public boolean destroyed = false;
public void destroy() {
destroyed = true;
}
}
}
@@ -1,363 +0,0 @@
/*
* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.HashMap;
import javax.servlet.FilterConfig;
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.StrutsInternalTestCase;
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;
import com.opensymphony.xwork2.inject.Container;
/**
*
* @version $Date$ $Id$
*/
public class FilterTest extends StrutsInternalTestCase {
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 {
super.tearDown();
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 {
super.setUp();
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();
filterDispatcher = new FilterDispatcher() {
@Override
protected Dispatcher createDispatcher(FilterConfig filterConfig) {
filterDispatcherCreateDispatcherCount++;
return _dispatcher2;
}
@Override
public String toString() {
return "filterDispatcher";
}
};
}
public void testUsingFilterDispatcherOnly() throws Exception {
assertEquals(cleanUpFilterCreateDispatcherCount, 0);
assertEquals(filterDispatcherCreateDispatcherCount, 0);
assertFalse(_dispatcher1.init);
assertFalse(_dispatcher1.prepare);
assertFalse(_dispatcher1.wrapRequest);
assertFalse(_dispatcher1.service);
assertFalse(_dispatcher2.init);
assertFalse(_dispatcher2.prepare);
assertFalse(_dispatcher2.wrapRequest);
assertFalse(_dispatcher2.service);
filterDispatcher.init(filterConfig);
filterDispatcher.setActionMapper(new FilterTest.InnerMapper());
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.init);
assertFalse(_dispatcher1.prepare);
assertFalse(_dispatcher1.wrapRequest);
assertFalse(_dispatcher1.service);
assertTrue(_dispatcher2.init);
assertTrue(_dispatcher2.prepare);
assertTrue(_dispatcher2.wrapRequest);
assertTrue(_dispatcher2.service);
assertTrue(Dispatcher.getInstance() == null);
}
public void testUsingFilterDispatcherOnly_Multiple() throws Exception {
filterDispatcher.setActionMapper(new FilterTest.InnerMapper());
assertEquals(cleanUpFilterCreateDispatcherCount, 0);
assertEquals(filterDispatcherCreateDispatcherCount, 0);
assertFalse(_dispatcher1.prepare);
assertFalse(_dispatcher1.wrapRequest);
assertFalse(_dispatcher1.service);
assertFalse(_dispatcher1.cleanUp);
assertFalse(_dispatcher2.prepare);
assertFalse(_dispatcher2.wrapRequest);
assertFalse(_dispatcher2.service);
assertFalse(_dispatcher2.cleanUp);
filterDispatcher.init(filterConfig);
filterDispatcher.setActionMapper(new FilterTest.InnerMapper());
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);
assertFalse(_dispatcher1.cleanUp);
assertTrue(_dispatcher2.prepare);
assertTrue(_dispatcher2.wrapRequest);
assertTrue(_dispatcher2.service);
assertTrue(_dispatcher2.cleanUp);
assertTrue(Dispatcher.getInstance() == null);
}
/*public void testUsingCleanUpAndFilterDispatcher() throws Exception {
ObjectFactory oldObjecFactory = ObjectFactory.getObjectFactory();
try {
ObjectFactory.setObjectFactory(new InnerObjectFactory());
filterDispatcher.setActionMapper(new 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(1, cleanUpFilterCreateDispatcherCount);
assertEquals(1, filterDispatcherCreateDispatcherCount);
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());
filterDispatcher.setActionMapper(new 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 init = false;
public boolean prepare = false;
public boolean wrapRequest = false;
public boolean service = false;
public boolean cleanUp = false;
public InnerDispatcher(ServletContext servletContext) {
super(servletContext, new HashMap<String, String>());
}
@Override
public void init() {
init= true;
}
@Override
public Container getContainer() {
return container;
}
@Override
public void prepare(HttpServletRequest request, HttpServletResponse response) {
prepare = true;
}
@Override
public HttpServletRequest wrapRequest(HttpServletRequest request) throws IOException {
wrapRequest = true;
return request;
}
@Override
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
service = true;
}
@Override
public void cleanup() {
cleanUp = true;
}
}
class NullInnerMapper implements ActionMapper {
public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) {
return null;
}
public ActionMapping getMappingFromActionName(String actionName) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
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 ActionMapping getMappingFromActionName(String actionName) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public String getUriFromActionMapping(ActionMapping mapping) {
return "";
}
}
class InnerObjectFactory extends ObjectFactory {
public InnerObjectFactory() {
super();
}
}
}
@@ -31,7 +31,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.dispatcher.FilterDispatcher;
import org.apache.struts2.dispatcher.ng.PrepareOperations;
import org.apache.struts2.json.annotations.SMDMethod;
import org.apache.struts2.json.rpc.RPCError;
import org.apache.struts2.json.rpc.RPCErrorCode;
@@ -382,7 +382,7 @@ public class JSONInterceptor extends AbstractInterceptor {
* @return true if debugging is turned on
*/
public boolean getDebug() {
Boolean devModeOverride = FilterDispatcher.getDevModeOverride();
Boolean devModeOverride = PrepareOperations.getDevModeOverride();
return devModeOverride != null ? devModeOverride : this.debug;
}