You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2020/03/21 09:06:09 UTC

[struts] 01/01: WW-4789 WW-3788 ActionContext refactoring

This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch action-context-boost
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 6721c9c98ae2eaf926f20901998990c4add798f2
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Sat Mar 21 10:05:48 2020 +0100

    WW-4789 WW-3788 ActionContext refactoring
---
 .../com/opensymphony/xwork2/ActionContext.java     |  46 +++++-
 .../opensymphony/xwork2/ognl/OgnlValueStack.java   |   5 +
 .../interceptor/ActionAutowiringInterceptor.java   |   5 +-
 .../com/opensymphony/xwork2/util/ValueStack.java   |  44 +++---
 .../org/apache/struts2/ServletActionContext.java   |  38 +++--
 .../java/org/apache/struts2/StrutsStatics.java     |  38 +++--
 .../apache/struts2/components/ActionComponent.java |   8 +-
 .../struts2/components/ServletUrlRenderer.java     |   2 +-
 .../template/FreemarkerTemplateEngine.java         |   8 +-
 .../org/apache/struts2/dispatcher/Dispatcher.java  | 155 ++++++++++++---------
 .../apache/struts2/dispatcher/InitOperations.java  |   4 +-
 .../dispatcher/listener/StrutsListener.java        |   1 -
 .../dispatcher/mapper/DefaultActionMapper.java     |   2 +-
 .../ActionMappingParametersInterceptor.java        |   2 +-
 .../interceptor/CookieProviderInterceptor.java     |   2 +-
 .../interceptor/CreateSessionInterceptor.java      |   9 +-
 .../struts2/interceptor/FileUploadInterceptor.java |   2 +-
 .../interceptor/MessageStoreInterceptor.java       |   2 +-
 .../interceptor/ServletConfigInterceptor.java      |  16 +--
 .../interceptor/TokenSessionStoreInterceptor.java  |   6 +-
 .../debugging/DebuggingInterceptor.java            |   6 +-
 .../main/java/org/apache/struts2/util/URLBean.java |   3 +-
 .../struts2/views/freemarker/FreemarkerResult.java |   2 +-
 .../com/opensymphony/xwork2/StubValueStack.java    |   5 +
 .../apache/struts2/ServletActionContextTest.java   |  10 +-
 .../interceptor/CreateSessionInterceptorTest.java  |  13 +-
 .../struts2/interceptor/I18nInterceptorTest.java   |   2 +-
 .../main/java/org/apache/struts2/JSPLoader.java    |   6 +-
 .../sitemesh/FreemarkerDecoratorServlet.java       |   2 +-
 .../struts2/sitemesh/VelocityDecoratorServlet.java |   2 +-
 30 files changed, 270 insertions(+), 176 deletions(-)

diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java
index 757dffd..595c7c6 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java
@@ -22,8 +22,14 @@ import com.opensymphony.xwork2.conversion.impl.ConversionData;
 import com.opensymphony.xwork2.inject.Container;
 import com.opensymphony.xwork2.util.ValueStack;
 import org.apache.struts2.StrutsException;
+import org.apache.struts2.StrutsStatics;
 import org.apache.struts2.dispatcher.HttpParameters;
+import org.apache.struts2.dispatcher.mapper.ActionMapping;
 
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.PageContext;
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Locale;
@@ -106,12 +112,18 @@ public class ActionContext implements Serializable {
      * Creates a new ActionContext initialized with another context.
      *
      * @param context a context map.
+     *
+     * @deprecated Please use {@link #of(Map)} builder method
      */
+    @Deprecated
     public ActionContext(Map<String, Object> context) {
         this.context = context;
     }
 
-
+    public static ActionContext of(Map<String, Object> context) {
+        ActionContext.setContext(new ActionContext(context));
+        return ActionContext.getContext();
+    }
     /**
      * Sets the action invocation (the execution state).
      *
@@ -347,4 +359,36 @@ public class ActionContext implements Serializable {
     public void put(String key, Object value) {
         context.put(key, value);
     }
+
+    public ServletContext getServletContext() {
+        return (ServletContext) get(StrutsStatics.SERVLET_CONTEXT);
+    }
+
+    public HttpServletRequest getServletRequest() {
+        return (HttpServletRequest) get(StrutsStatics.HTTP_REQUEST);
+    }
+
+    public HttpServletResponse getServletResponse() {
+        return (HttpServletResponse) get(StrutsStatics.HTTP_RESPONSE);
+    }
+
+    public void setServletContext(ServletContext servletContext) {
+        put(StrutsStatics.SERVLET_CONTEXT, servletContext);
+    }
+
+    public ActionMapping getActionMapping() {
+        return (ActionMapping) get(StrutsStatics.ACTION_MAPPING);
+    }
+
+    public PageContext getPageContext() {
+        return (PageContext) get(StrutsStatics.PAGE_CONTEXT);
+    }
+
+    public void setServletRequest(HttpServletRequest request) {
+        put(StrutsStatics.HTTP_REQUEST, request);
+    }
+
+    public void setServletResponse(HttpServletResponse response) {
+        put(StrutsStatics.HTTP_RESPONSE, response);
+    }
 }
diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlValueStack.java b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlValueStack.java
index 5aec937..1568a54 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlValueStack.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlValueStack.java
@@ -117,6 +117,11 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
         return context;
     }
 
+    @Override
+    public ActionContext getActionContext() {
+        return new ActionContext(context);
+    }
+
     /**
      * @see com.opensymphony.xwork2.util.ValueStack#setDefaultType(java.lang.Class)
      */
diff --git a/core/src/main/java/com/opensymphony/xwork2/spring/interceptor/ActionAutowiringInterceptor.java b/core/src/main/java/com/opensymphony/xwork2/spring/interceptor/ActionAutowiringInterceptor.java
index 72f8438..bf87805 100644
--- a/core/src/main/java/com/opensymphony/xwork2/spring/interceptor/ActionAutowiringInterceptor.java
+++ b/core/src/main/java/com/opensymphony/xwork2/spring/interceptor/ActionAutowiringInterceptor.java
@@ -64,9 +64,8 @@ import org.springframework.web.context.WebApplicationContext;
  * @author Eric Hauser
  */
 public class ActionAutowiringInterceptor extends AbstractInterceptor implements ApplicationContextAware {
-    private static final Logger LOG = LogManager.getLogger(ActionAutowiringInterceptor.class);
 
-    public static final String APPLICATION_CONTEXT = "com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor.applicationContext";
+    private static final Logger LOG = LogManager.getLogger(ActionAutowiringInterceptor.class);
 
     private boolean initialized = false;
     private ApplicationContext context;
@@ -121,8 +120,6 @@ public class ActionAutowiringInterceptor extends AbstractInterceptor implements
         if (factory != null) {
             Object bean = invocation.getAction();
             factory.autoWireBean(bean);
-    
-            ActionContext.getContext().put(APPLICATION_CONTEXT, context);
         }
         return invocation.invoke();
     }
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/ValueStack.java b/core/src/main/java/com/opensymphony/xwork2/util/ValueStack.java
index c14b01b..4d02b23 100644
--- a/core/src/main/java/com/opensymphony/xwork2/util/ValueStack.java
+++ b/core/src/main/java/com/opensymphony/xwork2/util/ValueStack.java
@@ -18,6 +18,8 @@
  */
 package com.opensymphony.xwork2.util;
 
+import com.opensymphony.xwork2.ActionContext;
+
 import java.util.Map;
 
 /**
@@ -28,23 +30,25 @@ import java.util.Map;
  */
 public interface ValueStack {
 
-    public static final String VALUE_STACK = "com.opensymphony.xwork2.util.ValueStack.ValueStack";
+    String VALUE_STACK = "com.opensymphony.xwork2.util.ValueStack.ValueStack";
 
-    public static final String REPORT_ERRORS_ON_NO_PROP = "com.opensymphony.xwork2.util.ValueStack.ReportErrorsOnNoProp";
+    String REPORT_ERRORS_ON_NO_PROP = "com.opensymphony.xwork2.util.ValueStack.ReportErrorsOnNoProp";
 
     /**
      * Gets the context for this value stack. The context holds all the information in the value stack and it's surroundings.
      *
      * @return  the context.
      */
-    public abstract Map<String, Object> getContext();
+    Map<String, Object> getContext();
+
+    ActionContext getActionContext();
 
     /**
      * Sets the default type to convert to if no type is provided when getting a value.
      *
      * @param defaultType the new default type
      */
-    public abstract void setDefaultType(Class defaultType);
+    void setDefaultType(Class defaultType);
 
     /**
      * Set a override map containing <code> key -&gt; values </code> that takes precedent when doing find operations on the ValueStack.
@@ -54,21 +58,21 @@ public interface ValueStack {
      *
      * @param overrides  overrides map.
      */
-    public abstract void setExprOverrides(Map<Object, Object> overrides);
+    void setExprOverrides(Map<Object, Object> overrides);
 
     /**
      * Gets the override map if anyone exists.
      *
      * @return the override map, <tt>null</tt> if not set.
      */
-    public abstract Map<Object, Object> getExprOverrides();
+    Map<Object, Object> getExprOverrides();
 
     /**
      * Get the CompoundRoot which holds the objects pushed onto the stack
      *
      * @return the root
      */
-    public abstract CompoundRoot getRoot();
+    CompoundRoot getRoot();
 
     /**
      * Attempts to set a property on a bean in the stack with the given expression using the default search order.
@@ -76,7 +80,7 @@ public interface ValueStack {
      * @param expr  the expression defining the path to the property to be set.
      * @param value the value to be set into the named property
      */
-    public abstract void setValue(String expr, Object value);
+    void setValue(String expr, Object value);
 
     /**
      * Attempts to set a property on a bean in the stack with the given expression using the default search order.
@@ -94,10 +98,10 @@ public interface ValueStack {
      * @param throwExceptionOnFailure a flag to tell whether an exception should be thrown if there is no property with
      *                                the given name.
      */
-    public abstract void setValue(String expr, Object value, boolean throwExceptionOnFailure);
+    void setValue(String expr, Object value, boolean throwExceptionOnFailure);
 
-    public abstract String findString(String expr);
-    public abstract String findString(String expr, boolean throwExceptionOnFailure);
+    String findString(String expr);
+    String findString(String expr, boolean throwExceptionOnFailure);
 
     /**
      * Find a value by evaluating the given expression against the stack in the default search order.
@@ -105,9 +109,9 @@ public interface ValueStack {
      * @param expr the expression giving the path of properties to navigate to find the property value to return
      * @return the result of evaluating the expression
      */
-    public abstract Object findValue(String expr);
+    Object findValue(String expr);
 
-    public abstract Object findValue(String expr, boolean throwExceptionOnFailure);
+    Object findValue(String expr, boolean throwExceptionOnFailure);
 
     /**
      * Find a value by evaluating the given expression against the stack in the default search order.
@@ -116,8 +120,8 @@ public interface ValueStack {
      * @param asType the type to convert the return value to
      * @return the result of evaluating the expression
      */
-    public abstract Object findValue(String expr, Class asType);
-    public abstract Object findValue(String expr, Class asType,  boolean throwExceptionOnFailure);
+    Object findValue(String expr, Class asType);
+    Object findValue(String expr, Class asType, boolean throwExceptionOnFailure);
 
     /**
      * Get the object on the top of the stack <b>without</b> changing the stack.
@@ -125,7 +129,7 @@ public interface ValueStack {
      * @return the object on the top.
      * @see CompoundRoot#peek()
      */
-    public abstract Object peek();
+    Object peek();
 
     /**
      * Get the object on the top of the stack and <b>remove</b> it from the stack.
@@ -133,7 +137,7 @@ public interface ValueStack {
      * @return the object on the top of the stack
      * @see CompoundRoot#pop()
      */
-    public abstract Object pop();
+    Object pop();
 
     /**
      * Put this object onto the top of the stack
@@ -141,7 +145,7 @@ public interface ValueStack {
      * @param o the object to be pushed onto the stack
      * @see CompoundRoot#push(Object)
      */
-    public abstract void push(Object o);
+    void push(Object o);
 
     /**
      * Sets an object on the stack with the given key
@@ -150,13 +154,13 @@ public interface ValueStack {
      * @param key  the key
      * @param o    the object
      */
-    public abstract void set(String key, Object o);
+    void set(String key, Object o);
 
     /**
      * Get the number of objects in the stack
      *
      * @return the number of objects in the stack
      */
-    public abstract int size();
+    int size();
 
 }
\ No newline at end of file
diff --git a/core/src/main/java/org/apache/struts2/ServletActionContext.java b/core/src/main/java/org/apache/struts2/ServletActionContext.java
index 4af8d53..6942dbd 100644
--- a/core/src/main/java/org/apache/struts2/ServletActionContext.java
+++ b/core/src/main/java/org/apache/struts2/ServletActionContext.java
@@ -26,23 +26,18 @@ import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.jsp.PageContext;
-import java.util.Map;
 
 /**
  * Web-specific context information for actions. This class subclasses <tt>ActionContext</tt> which
  * provides access to things like the action name, value stack, etc. This class adds access to
  * web objects like servlet parameters, request attributes and things like the HTTP session.
  */
-public class ServletActionContext extends ActionContext implements StrutsStatics {
-
-    private static final long serialVersionUID = -666854718275106687L;
+public class ServletActionContext implements StrutsStatics {
 
     public static final String STRUTS_VALUESTACK_KEY = "struts.valueStack";
-    public static final String ACTION_MAPPING = "struts.actionMapping";
 
     @SuppressWarnings("unused")
-    private ServletActionContext(Map context) {
-        super(context);
+    private ServletActionContext() {
     }
 
     /**
@@ -61,6 +56,19 @@ public class ServletActionContext extends ActionContext implements StrutsStatics
     }
 
     /**
+     * Do not use this method, use {@link #getActionContext()}
+     * @return action context
+     * @deprecated Use {@link #getActionContext()} instead
+     */
+    @Deprecated
+    public static ActionContext getContext() {
+        return ActionContext.getContext();
+    }
+
+    public static ActionContext getActionContext() {
+        return ActionContext.getContext();
+    }
+    /**
      * Gets the current value stack for this request
      *
      * @param req The request
@@ -76,7 +84,7 @@ public class ServletActionContext extends ActionContext implements StrutsStatics
      * @return The action mapping
      */
     public static ActionMapping getActionMapping() {
-        return (ActionMapping) ActionContext.getContext().get(ACTION_MAPPING);
+        return ActionContext.getContext().getActionMapping();
     }
 
     /**
@@ -85,7 +93,7 @@ public class ServletActionContext extends ActionContext implements StrutsStatics
      * @return the HTTP page context.
      */
     public static PageContext getPageContext() {
-        return (PageContext) ActionContext.getContext().get(PAGE_CONTEXT);
+        return ActionContext.getContext().getPageContext();
     }
 
     /**
@@ -94,7 +102,7 @@ public class ServletActionContext extends ActionContext implements StrutsStatics
      * @param request the HTTP servlet request object.
      */
     public static void setRequest(HttpServletRequest request) {
-        ActionContext.getContext().put(HTTP_REQUEST, request);
+        ActionContext.getContext().setServletRequest(request);
     }
 
     /**
@@ -103,7 +111,7 @@ public class ServletActionContext extends ActionContext implements StrutsStatics
      * @return the HTTP servlet request object.
      */
     public static HttpServletRequest getRequest() {
-        return (HttpServletRequest) ActionContext.getContext().get(HTTP_REQUEST);
+        return ActionContext.getContext().getServletRequest();
     }
 
     /**
@@ -112,7 +120,7 @@ public class ServletActionContext extends ActionContext implements StrutsStatics
      * @param response the HTTP servlet response object.
      */
     public static void setResponse(HttpServletResponse response) {
-        ActionContext.getContext().put(HTTP_RESPONSE, response);
+        ActionContext.getContext().setServletResponse(response);
     }
 
     /**
@@ -121,7 +129,7 @@ public class ServletActionContext extends ActionContext implements StrutsStatics
      * @return the HTTP servlet response object.
      */
     public static HttpServletResponse getResponse() {
-        return (HttpServletResponse) ActionContext.getContext().get(HTTP_RESPONSE);
+        return ActionContext.getContext().getServletResponse();
     }
 
     /**
@@ -130,7 +138,7 @@ public class ServletActionContext extends ActionContext implements StrutsStatics
      * @return the servlet context.
      */
     public static ServletContext getServletContext() {
-        return (ServletContext) ActionContext.getContext().get(SERVLET_CONTEXT);
+        return ActionContext.getContext().getServletContext();
     }
 
     /**
@@ -139,6 +147,6 @@ public class ServletActionContext extends ActionContext implements StrutsStatics
      * @param servletContext The servlet context to use
      */
     public static void setServletContext(ServletContext servletContext) {
-        ActionContext.getContext().put(SERVLET_CONTEXT, servletContext);
+        ActionContext.getContext().setServletContext(servletContext);
     }
 }
diff --git a/core/src/main/java/org/apache/struts2/StrutsStatics.java b/core/src/main/java/org/apache/struts2/StrutsStatics.java
index c4e2c1c..e0adccc 100644
--- a/core/src/main/java/org/apache/struts2/StrutsStatics.java
+++ b/core/src/main/java/org/apache/struts2/StrutsStatics.java
@@ -18,22 +18,12 @@
  */
 package org.apache.struts2;
 
+import javax.servlet.ServletContext;
+
 /**
  * <p>
- * Constants used by Struts. The constants can be used to get or set objects
- * out of the action context or other collections.
- * </p>
- *
- * <p>
- * Example:
- *
- * <code>ActionContext.getContext().put(HTTP_REQUEST, request);</code>
- *
- * or
- *
- * <code>
- * ActionContext context = ActionContext.getContext();<br>
- * HttpServletRequest request = (HttpServletRequest)context.get(HTTP_REQUEST);</code>
+ * Constants used internally by Struts. Do not use these constants directly,
+ * instead use exposed helpers eg.: {@link org.apache.struts2.dispatcher.Dispatcher#getInstance(ServletContext)}
  * </p>
  */
 public interface StrutsStatics {
@@ -41,34 +31,38 @@ public interface StrutsStatics {
     /**
      * Constant for the HTTP request object.
      */
-    public static final String HTTP_REQUEST = "com.opensymphony.xwork2.dispatcher.HttpServletRequest";
+    String HTTP_REQUEST = "com.opensymphony.xwork2.dispatcher.HttpServletRequest";
 
     /**
      * Constant for the HTTP response object.
      */
-    public static final String HTTP_RESPONSE = "com.opensymphony.xwork2.dispatcher.HttpServletResponse";
+    String HTTP_RESPONSE = "com.opensymphony.xwork2.dispatcher.HttpServletResponse";
 
     /**
      * Constant for an HTTP {@link javax.servlet.RequestDispatcher request dispatcher}.
      */
-    public static final String SERVLET_DISPATCHER = "com.opensymphony.xwork2.dispatcher.ServletDispatcher";
+    String SERVLET_DISPATCHER = "com.opensymphony.xwork2.dispatcher.ServletDispatcher";
 
     /**
      * Constant for the {@link javax.servlet.ServletContext servlet context} object.
      */
-    public static final String SERVLET_CONTEXT = "com.opensymphony.xwork2.dispatcher.ServletContext";
+    String SERVLET_CONTEXT = "com.opensymphony.xwork2.dispatcher.ServletContext";
 
     /**
      * Constant for the JSP {@link javax.servlet.jsp.PageContext page context}.
      */
-    public static final String PAGE_CONTEXT = "com.opensymphony.xwork2.dispatcher.PageContext";
+    String PAGE_CONTEXT = "com.opensymphony.xwork2.dispatcher.PageContext";
 
-    /** Constant for the PortletContext object */
-    public static final String STRUTS_PORTLET_CONTEXT = "struts.portlet.context";
+    /**
+     * Constant for the PortletContext object
+     */
+    String STRUTS_PORTLET_CONTEXT = "struts.portlet.context";
 
     /**
      * Set as an attribute in the request to let other parts of the framework know that the invocation is happening inside an
      * action tag
      */
-    public static final String STRUTS_ACTION_TAG_INVOCATION= "struts.actiontag.invocation";
+    String STRUTS_ACTION_TAG_INVOCATION = "struts.actiontag.invocation";
+
+    String ACTION_MAPPING = "struts.actionMapping";
 }
diff --git a/core/src/main/java/org/apache/struts2/components/ActionComponent.java b/core/src/main/java/org/apache/struts2/components/ActionComponent.java
index 901556f..8c32d43 100644
--- a/core/src/main/java/org/apache/struts2/components/ActionComponent.java
+++ b/core/src/main/java/org/apache/struts2/components/ActionComponent.java
@@ -178,10 +178,10 @@ public class ActionComponent extends ContextBean {
     protected Map createExtraContext() {
         HttpParameters newParams = createParametersForContext();
 
-        ActionContext ctx = new ActionContext(stack.getContext());
-        PageContext pageContext = (PageContext) ctx.get(ServletActionContext.PAGE_CONTEXT);
-        Map session = ctx.getSession();
-        Map application = ctx.getApplication();
+        ActionContext ctx = stack.getActionContext();
+        PageContext pageContext = ctx.getPageContext();
+        Map<String, Object> session = ctx.getSession();
+        Map<String, Object> application = ctx.getApplication();
 
         Dispatcher du = Dispatcher.getInstance();
         Map<String, Object> extraContext = du.createContextMap(new RequestMap(req),
diff --git a/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java b/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java
index b41b4d6..550fa35 100644
--- a/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java
+++ b/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java
@@ -74,7 +74,7 @@ public class ServletUrlRenderer implements UrlRenderer {
         }
 
         String result;
-        ActionInvocation ai = (ActionInvocation) ActionContext.getContext().get(ActionContext.ACTION_INVOCATION);
+        ActionInvocation ai = ActionContext.getContext().getActionInvocation();
         if (urlComponent.getValue() == null && urlComponent.getAction() != null) {
             result = urlComponent.determineActionURL(urlComponent.getAction(), urlComponent.getNamespace(), urlComponent.getMethod(), urlComponent.getHttpServletRequest(), urlComponent.getHttpServletResponse(), urlComponent.getParameters(), scheme, urlComponent.isIncludeContext(), urlComponent.isEncode(), urlComponent.isForceAddSchemeHostAndPort(), urlComponent.isEscapeAmp());
         } else if (urlComponent.getValue() == null && urlComponent.getAction() == null && ai != null) {
diff --git a/core/src/main/java/org/apache/struts2/components/template/FreemarkerTemplateEngine.java b/core/src/main/java/org/apache/struts2/components/template/FreemarkerTemplateEngine.java
index a272697..7cec84a 100644
--- a/core/src/main/java/org/apache/struts2/components/template/FreemarkerTemplateEngine.java
+++ b/core/src/main/java/org/apache/struts2/components/template/FreemarkerTemplateEngine.java
@@ -68,10 +68,10 @@ public class FreemarkerTemplateEngine extends BaseTemplateEngine {
     public void renderTemplate(TemplateRenderingContext templateContext) throws Exception {
     	// get the various items required from the stack
         ValueStack stack = templateContext.getStack();
-        Map context = stack.getContext();
-        ServletContext servletContext = (ServletContext) context.get(ServletActionContext.SERVLET_CONTEXT);
-        HttpServletRequest req = (HttpServletRequest) context.get(ServletActionContext.HTTP_REQUEST);
-        HttpServletResponse res = (HttpServletResponse) context.get(ServletActionContext.HTTP_RESPONSE);
+        ActionContext context = stack.getActionContext();
+        ServletContext servletContext = context.getServletContext();
+        HttpServletRequest req = context.getServletRequest();
+        HttpServletResponse res = context.getServletResponse();
 
         // prepare freemarker
         Configuration config = freemarkerManager.getConfiguration(servletContext);
diff --git a/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java b/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java
index 27d025b..8bf67cf 100644
--- a/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java
+++ b/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java
@@ -18,8 +18,22 @@
  */
 package org.apache.struts2.dispatcher;
 
-import com.opensymphony.xwork2.*;
-import com.opensymphony.xwork2.config.*;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.ActionProxy;
+import com.opensymphony.xwork2.ActionProxyFactory;
+import com.opensymphony.xwork2.FileManager;
+import com.opensymphony.xwork2.FileManagerFactory;
+import com.opensymphony.xwork2.LocaleProviderFactory;
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.Result;
+import com.opensymphony.xwork2.config.Configuration;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.config.ConfigurationManager;
+import com.opensymphony.xwork2.config.ConfigurationProvider;
+import com.opensymphony.xwork2.config.FileManagerFactoryProvider;
+import com.opensymphony.xwork2.config.FileManagerProvider;
+import com.opensymphony.xwork2.config.ServletContextAwareConfigurationProvider;
 import com.opensymphony.xwork2.config.entities.InterceptorMapping;
 import com.opensymphony.xwork2.config.entities.InterceptorStackConfig;
 import com.opensymphony.xwork2.config.entities.PackageConfig;
@@ -34,8 +48,8 @@ import com.opensymphony.xwork2.util.ValueStackFactory;
 import com.opensymphony.xwork2.util.location.LocatableProperties;
 import com.opensymphony.xwork2.util.location.Location;
 import com.opensymphony.xwork2.util.location.LocationUtils;
-import org.apache.commons.lang3.LocaleUtils;
 import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.LocaleUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -44,15 +58,16 @@ import org.apache.struts2.ServletActionContext;
 import org.apache.struts2.StrutsConstants;
 import org.apache.struts2.StrutsException;
 import org.apache.struts2.StrutsStatics;
-import org.apache.struts2.config.StrutsBeanSelectionProvider;
 import org.apache.struts2.config.DefaultPropertiesProvider;
 import org.apache.struts2.config.PropertiesConfigurationProvider;
+import org.apache.struts2.config.StrutsBeanSelectionProvider;
 import org.apache.struts2.config.StrutsJavaConfiguration;
 import org.apache.struts2.config.StrutsJavaConfigurationProvider;
 import org.apache.struts2.config.StrutsXmlConfigurationProvider;
 import org.apache.struts2.dispatcher.mapper.ActionMapping;
 import org.apache.struts2.dispatcher.multipart.MultiPartRequest;
 import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
+import org.apache.struts2.dispatcher.servlet.StrutsServlet;
 import org.apache.struts2.util.AttributeMap;
 import org.apache.struts2.util.ObjectFactoryDestroyable;
 import org.apache.struts2.util.fs.JBossFileManager;
@@ -63,7 +78,13 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.IOException;
-import java.util.*;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.regex.Pattern;
 
@@ -220,15 +241,20 @@ public class Dispatcher {
      * Create the Dispatcher instance for a given ServletContext and set of initialization parameters.
      *
      * @param servletContext Our servlet context
-     * @param initParams The set of initialization parameters
+     * @param initParams     The set of initialization parameters
      */
     public Dispatcher(ServletContext servletContext, Map<String, String> initParams) {
         this.servletContext = servletContext;
         this.initParams = initParams;
     }
 
+    public static Dispatcher getInstance(ServletContext servletContext) {
+        return (Dispatcher) servletContext.getAttribute(StrutsStatics.SERVLET_DISPATCHER);
+    }
+
     /**
      * Modify state of StrutsConstants.STRUTS_DEVMODE setting.
+     *
      * @param mode New setting
      */
     @Inject(StrutsConstants.STRUTS_DEVMODE)
@@ -242,24 +268,27 @@ public class Dispatcher {
 
     /**
      * Modify state of StrutsConstants.DISABLE_REQUEST_ATTRIBUTE_VALUE_STACK_LOOKUP setting.
+     *
      * @param disableRequestAttributeValueStackLookup New setting
      */
-    @Inject(value=StrutsConstants.STRUTS_DISABLE_REQUEST_ATTRIBUTE_VALUE_STACK_LOOKUP, required=false)
+    @Inject(value = StrutsConstants.STRUTS_DISABLE_REQUEST_ATTRIBUTE_VALUE_STACK_LOOKUP, required = false)
     public void setDisableRequestAttributeValueStackLookup(String disableRequestAttributeValueStackLookup) {
         this.disableRequestAttributeValueStackLookup = BooleanUtils.toBoolean(disableRequestAttributeValueStackLookup);
     }
 
     /**
      * Modify state of StrutsConstants.STRUTS_LOCALE setting.
+     *
      * @param val New setting
      */
-    @Inject(value=StrutsConstants.STRUTS_LOCALE, required=false)
+    @Inject(value = StrutsConstants.STRUTS_LOCALE, required = false)
     public void setDefaultLocale(String val) {
         defaultLocale = val;
     }
 
     /**
      * Modify state of StrutsConstants.STRUTS_I18N_ENCODING setting.
+     *
      * @param val New setting
      */
     @Inject(StrutsConstants.STRUTS_I18N_ENCODING)
@@ -269,6 +298,7 @@ public class Dispatcher {
 
     /**
      * Modify state of StrutsConstants.STRUTS_MULTIPART_SAVEDIR setting.
+     *
      * @param val New setting
      */
     @Inject(StrutsConstants.STRUTS_MULTIPART_SAVEDIR)
@@ -314,17 +344,15 @@ public class Dispatcher {
      * Releases all instances bound to this dispatcher instance.
      */
     public void cleanup() {
-
-    	// clean up ObjectFactory
+        // clean up ObjectFactory
         ObjectFactory objectFactory = getContainer().getInstance(ObjectFactory.class);
         if (objectFactory == null) {
-        	LOG.warn("Object Factory is null, something is seriously wrong, no clean up will be performed");
+            LOG.warn("Object Factory is null, something is seriously wrong, no clean up will be performed");
         }
         if (objectFactory instanceof ObjectFactoryDestroyable) {
             try {
-                ((ObjectFactoryDestroyable)objectFactory).destroy();
-            }
-            catch(Exception e) {
+                ((ObjectFactoryDestroyable) objectFactory).destroy();
+            } catch (Exception e) {
                 // catch any exception that may occurred during destroy() and log it
                 LOG.error("Exception occurred while destroying ObjectFactory [{}]", objectFactory.toString(), e);
             }
@@ -332,6 +360,7 @@ public class Dispatcher {
 
         // clean up Dispatcher itself for this thread
         instance.set(null);
+        servletContext.setAttribute(StrutsStatics.SERVLET_DISPATCHER, null);
 
         // clean up DispatcherListeners
         if (!dispatcherListeners.isEmpty()) {
@@ -347,13 +376,13 @@ public class Dispatcher {
             for (Object config : packageConfig.getAllInterceptorConfigs().values()) {
                 if (config instanceof InterceptorStackConfig) {
                     for (InterceptorMapping interceptorMapping : ((InterceptorStackConfig) config).getInterceptors()) {
-                	    interceptors.add(interceptorMapping.getInterceptor());
+                        interceptors.add(interceptorMapping.getInterceptor());
                     }
                 }
             }
         }
         for (Interceptor interceptor : interceptors) {
-        	interceptor.destroy();
+            interceptor.destroy();
         }
 
         // Clear container holder when application is unloaded / server shutdown
@@ -363,8 +392,8 @@ public class Dispatcher {
         ActionContext.setContext(null);
 
         // clean up configuration
-    	configurationManager.destroyConfiguration();
-    	configurationManager = null;
+        configurationManager.destroyConfiguration();
+        configurationManager = null;
     }
 
     private void init_FileManager() throws ClassNotFoundException {
@@ -388,7 +417,7 @@ public class Dispatcher {
     private void init_DefaultProperties() {
         configurationManager.addContainerProvider(new DefaultPropertiesProvider());
     }
-    
+
     private void init_LegacyStrutsProperties() {
         configurationManager.addContainerProvider(new PropertiesConfigurationProvider());
     }
@@ -443,17 +472,17 @@ public class Dispatcher {
             for (String cname : classes) {
                 try {
                     Class cls = ClassLoaderUtil.loadClass(cname, this.getClass());
-                    ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();
+                    ConfigurationProvider prov = (ConfigurationProvider) cls.newInstance();
                     if (prov instanceof ServletContextAwareConfigurationProvider) {
-                        ((ServletContextAwareConfigurationProvider)prov).initWithContext(servletContext);
+                        ((ServletContextAwareConfigurationProvider) prov).initWithContext(servletContext);
                     }
                     configurationManager.addContainerProvider(prov);
                 } catch (InstantiationException e) {
-                    throw new ConfigurationException("Unable to instantiate provider: "+cname, e);
+                    throw new ConfigurationException("Unable to instantiate provider: " + cname, e);
                 } catch (IllegalAccessException e) {
-                    throw new ConfigurationException("Unable to access provider: "+cname, e);
+                    throw new ConfigurationException("Unable to access provider: " + cname, e);
                 } catch (ClassNotFoundException e) {
-                    throw new ConfigurationException("Unable to locate provider class: "+cname, e);
+                    throw new ConfigurationException("Unable to locate provider class: " + cname, e);
                 }
             }
         }
@@ -495,7 +524,7 @@ public class Dispatcher {
             paramsWorkaroundEnabled = true;
         } else {
             paramsWorkaroundEnabled = "true".equals(container.getInstance(String.class,
-                    StrutsConstants.STRUTS_DISPATCHER_PARAMETERSWORKAROUND));
+                StrutsConstants.STRUTS_DISPATCHER_PARAMETERSWORKAROUND));
         }
     }
 
@@ -504,10 +533,9 @@ public class Dispatcher {
      * and update optional settings, including whether to reload configurations and resource files.
      */
     public void init() {
-
-    	if (configurationManager == null) {
-    		configurationManager = createConfigurationManager(Container.DEFAULT_NAME);
-    	}
+        if (configurationManager == null) {
+            configurationManager = createConfigurationManager(Container.DEFAULT_NAME);
+        }
 
         try {
             init_FileManager();
@@ -516,8 +544,8 @@ public class Dispatcher {
             init_JavaConfigurations();
             init_LegacyStrutsProperties(); // [3]
             init_CustomConfigurationProviders(); // [5]
-            init_FilterInitParameters() ; // [6]
-            init_AliasStandardObjects() ; // [7]
+            init_FilterInitParameters(); // [6]
+            init_AliasStandardObjects(); // [7]
 
             Container container = init_PreloadConfiguration();
             container.inject(this);
@@ -530,6 +558,9 @@ public class Dispatcher {
             }
             errorHandler.init(servletContext);
 
+            if (servletContext.getAttribute(StrutsStatics.SERVLET_DISPATCHER) == null) {
+                servletContext.setAttribute(StrutsStatics.SERVLET_DISPATCHER, this);
+            }
         } catch (Exception ex) {
             LOG.error("Dispatcher initialization failed", ex);
             throw new StrutsException(ex);
@@ -559,11 +590,10 @@ public class Dispatcher {
      * @param mapping  the action mapping object
      * @throws ServletException when an unknown error occurs (not a 404, but typically something that
      *                          would end up as a 5xx by the servlet container)
-     *
      * @since 2.3.17
      */
     public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)
-            throws ServletException {
+        throws ServletException {
 
         Map<String, Object> extraContext = createContextMap(request, response, mapping);
 
@@ -591,7 +621,7 @@ public class Dispatcher {
             ActionInvocation invocation = ActionContext.getContext().getActionInvocation();
             if (invocation == null || invocation.isExecuted()) {
                 proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method,
-                        extraContext, true, false);
+                    extraContext, true, false);
             } else {
                 proxy = invocation.getProxy();
             }
@@ -629,7 +659,7 @@ public class Dispatcher {
      * Performs logging of missing action/result configuration exception
      *
      * @param request current {@link HttpServletRequest}
-     * @param e {@link ConfigurationException} that occurred
+     * @param e       {@link ConfigurationException} that occurred
      */
     protected void logConfigurationException(HttpServletRequest request, ConfigurationException e) {
         // WW-2874 Only log error if in devMode
@@ -647,15 +677,14 @@ public class Dispatcher {
     /**
      * Create a context map containing all the wrapped request objects
      *
-     * @param request The servlet request
+     * @param request  The servlet request
      * @param response The servlet response
-     * @param mapping The action mapping
+     * @param mapping  The action mapping
      * @return A map of context objects
-     *
      * @since 2.3.17
      */
-    public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,
-            ActionMapping mapping) {
+    public Map<String, Object> createContextMap(HttpServletRequest request, HttpServletResponse response,
+                                                ActionMapping mapping) {
 
         // request map wrapping the http request objects
         Map requestMap = new RequestMap(request);
@@ -669,7 +698,7 @@ public class Dispatcher {
         // application map wrapping the ServletContext
         Map application = new ApplicationMap(servletContext);
 
-        Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response);
+        Map<String, Object> extraContext = createContextMap(requestMap, params, session, application, request, response);
 
         if (mapping != null) {
             extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);
@@ -688,15 +717,14 @@ public class Dispatcher {
      * @param request        the HttpServletRequest object.
      * @param response       the HttpServletResponse object.
      * @return a HashMap representing the <tt>Action</tt> context.
-     *
      * @since 2.3.17
      */
-    public HashMap<String,Object> createContextMap(Map requestMap,
-                                    HttpParameters parameters,
-                                    Map sessionMap,
-                                    Map applicationMap,
-                                    HttpServletRequest request,
-                                    HttpServletResponse response) {
+    public HashMap<String, Object> createContextMap(Map requestMap,
+                                                    HttpParameters parameters,
+                                                    Map sessionMap,
+                                                    Map applicationMap,
+                                                    HttpServletRequest request,
+                                                    HttpServletResponse response) {
         HashMap<String, Object> extraContext = new HashMap<>();
         extraContext.put(ActionContext.PARAMETERS, parameters);
         extraContext.put(ActionContext.SESSION, sessionMap);
@@ -727,7 +755,7 @@ public class Dispatcher {
                 locale = LocaleUtils.toLocale(defaultLocale);
             } catch (IllegalArgumentException e) {
                 LOG.warn(new ParameterizedMessage("Cannot convert 'struts.locale' = [{}] to proper locale, defaulting to request locale [{}]",
-                                defaultLocale, request.getLocale()), e);
+                    defaultLocale, request.getLocale()), e);
                 locale = request.getLocale();
             }
         } else {
@@ -746,7 +774,7 @@ public class Dispatcher {
 
         if (saveDir.equals("")) {
             File tempdir = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
-        	LOG.info("Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir");
+            LOG.info("Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir");
 
             if (tempdir != null) {
                 saveDir = tempdir.toString();
@@ -780,7 +808,7 @@ public class Dispatcher {
     /**
      * Prepare a request, including setting the encoding and locale.
      *
-     * @param request The request
+     * @param request  The request
      * @param response The response
      */
     public void prepare(HttpServletRequest request, HttpServletResponse response) {
@@ -834,9 +862,8 @@ public class Dispatcher {
      *
      * @param request the HttpServletRequest object.
      * @return a wrapped request or original request.
-     * @see org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper
      * @throws java.io.IOException on any error.
-     *
+     * @see org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper
      * @since 2.3.17
      */
     public HttpServletRequest wrapRequest(HttpServletRequest request) throws IOException {
@@ -850,11 +877,11 @@ public class Dispatcher {
             LocaleProviderFactory localeProviderFactory = getContainer().getInstance(LocaleProviderFactory.class);
 
             request = new MultiPartRequestWrapper(
-                    multiPartRequest,
-                    request,
-                    getSaveDir(),
-                    localeProviderFactory.createLocaleProvider(),
-                    disableRequestAttributeValueStackLookup
+                multiPartRequest,
+                request,
+                getSaveDir(),
+                localeProviderFactory.createLocaleProvider(),
+                disableRequestAttributeValueStackLookup
             );
         } else {
             request = new StrutsRequestWrapper(request, disableRequestAttributeValueStackLookup);
@@ -865,10 +892,9 @@ public class Dispatcher {
 
     /**
      * Checks if support to parse multipart requests is enabled
-     * 
+     *
      * @param request current servlet request
      * @return false if disabled
-     *
      * @since 2.5.11
      */
     protected boolean isMultipartSupportEnabled(HttpServletRequest request) {
@@ -880,7 +906,6 @@ public class Dispatcher {
      *
      * @param request current servlet request
      * @return true if it is a multipart request
-     *
      * @since 2.5.11
      */
     protected boolean isMultipartRequest(HttpServletRequest request) {
@@ -888,8 +913,8 @@ public class Dispatcher {
         String contentType = request.getContentType();
 
         return REQUEST_POST_METHOD.equalsIgnoreCase(httpMethod) &&
-                contentType != null &&
-                multipartValidationPattern.matcher(contentType.toLowerCase(Locale.ENGLISH)).matches();
+            contentType != null &&
+            multipartValidationPattern.matcher(contentType.toLowerCase(Locale.ENGLISH)).matches();
     }
 
     /**
@@ -907,7 +932,7 @@ public class Dispatcher {
                 mpr = getContainer().getInstance(MultiPartRequest.class, multiName);
             }
         }
-        if (mpr == null ) {
+        if (mpr == null) {
             mpr = getContainer().getInstance(MultiPartRequest.class);
         }
         return mpr;
@@ -935,7 +960,6 @@ public class Dispatcher {
      * @param response the HttpServletResponse object.
      * @param code     the HttpServletResponse error code (see {@link javax.servlet.http.HttpServletResponse} for possible error codes).
      * @param e        the Exception that is reported.
-     *
      * @since 2.3.17
      */
     public void sendError(HttpServletRequest request, HttpServletResponse response, int code, Exception e) {
@@ -976,6 +1000,7 @@ public class Dispatcher {
 
     /**
      * Expose the dependency injection container.
+     *
      * @return Our dependency injection container
      */
     public Container getContainer() {
diff --git a/core/src/main/java/org/apache/struts2/dispatcher/InitOperations.java b/core/src/main/java/org/apache/struts2/dispatcher/InitOperations.java
index 55f6481..ed47533 100644
--- a/core/src/main/java/org/apache/struts2/dispatcher/InitOperations.java
+++ b/core/src/main/java/org/apache/struts2/dispatcher/InitOperations.java
@@ -81,8 +81,8 @@ public class InitOperations {
      */
     protected Dispatcher createDispatcher(HostConfig filterConfig) {
         Map<String, String> params = new HashMap<>();
-        for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {
-            String name = (String) e.next();
+        for ( Iterator<String> parameterNames = filterConfig.getInitParameterNames(); parameterNames.hasNext(); ) {
+            String name = parameterNames.next();
             String value = filterConfig.getInitParameter(name);
             params.put(name, value);
         }
diff --git a/core/src/main/java/org/apache/struts2/dispatcher/listener/StrutsListener.java b/core/src/main/java/org/apache/struts2/dispatcher/listener/StrutsListener.java
index bf83984..5bdeee1 100644
--- a/core/src/main/java/org/apache/struts2/dispatcher/listener/StrutsListener.java
+++ b/core/src/main/java/org/apache/struts2/dispatcher/listener/StrutsListener.java
@@ -44,7 +44,6 @@ public class StrutsListener implements ServletContextListener {
             init.initStaticContentLoader(config, dispatcher);
 
             prepare = new PrepareOperations(dispatcher);
-            sce.getServletContext().setAttribute(StrutsStatics.SERVLET_DISPATCHER, dispatcher);
         } finally {
             if (dispatcher != null) {
                 dispatcher.cleanUpAfterInit();
diff --git a/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java b/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java
index 06c31d4..a9679a3 100644
--- a/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java
+++ b/core/src/main/java/org/apache/struts2/dispatcher/mapper/DefaultActionMapper.java
@@ -564,7 +564,7 @@ public class DefaultActionMapper implements ActionMapper {
             // Look for the current extension, if available
             ActionContext context = ActionContext.getContext();
             if (context != null) {
-                ActionMapping orig = (ActionMapping) context.get(ServletActionContext.ACTION_MAPPING);
+                ActionMapping orig = context.getActionMapping();
                 if (orig != null) {
                     extension = orig.getExtension();
                 }
diff --git a/core/src/main/java/org/apache/struts2/interceptor/ActionMappingParametersInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/ActionMappingParametersInterceptor.java
index 2b04795..79cd0cc 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/ActionMappingParametersInterceptor.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/ActionMappingParametersInterceptor.java
@@ -81,7 +81,7 @@ public class ActionMappingParametersInterceptor extends ParametersInterceptor {
      */
     @Override
     protected HttpParameters retrieveParameters(ActionContext ac) {
-        ActionMapping mapping = (ActionMapping) ac.get(ServletActionContext.ACTION_MAPPING);
+        ActionMapping mapping = ac.getActionMapping();
         if (mapping != null) {
             return HttpParameters.create(mapping.getParams()).buildNoNestedWrapping();
         } else {
diff --git a/core/src/main/java/org/apache/struts2/interceptor/CookieProviderInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/CookieProviderInterceptor.java
index 4e415e2..e04c3fa 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/CookieProviderInterceptor.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/CookieProviderInterceptor.java
@@ -96,7 +96,7 @@ public class CookieProviderInterceptor extends AbstractInterceptor implements Pr
             LOG.trace("beforeResult start");
             ActionContext ac = invocation.getInvocationContext();
             if (invocation.getAction() instanceof CookieProvider) {
-                HttpServletResponse response = (HttpServletResponse) ac.get(StrutsStatics.HTTP_RESPONSE);
+                HttpServletResponse response = ac.getServletResponse();
                 addCookiesToResponse((CookieProvider) invocation.getAction(), response);
             }
             LOG.trace("beforeResult end");
diff --git a/core/src/main/java/org/apache/struts2/interceptor/CreateSessionInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/CreateSessionInterceptor.java
index 32aea1e..9091220 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/CreateSessionInterceptor.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/CreateSessionInterceptor.java
@@ -18,6 +18,7 @@
  */
 package org.apache.struts2.interceptor;
 
+import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.ActionInvocation;
 import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
 import org.apache.logging.log4j.LogManager;
@@ -25,6 +26,7 @@ import org.apache.logging.log4j.Logger;
 import org.apache.struts2.ServletActionContext;
 import org.apache.struts2.dispatcher.SessionMap;
 
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 
 /**
@@ -86,11 +88,12 @@ public class CreateSessionInterceptor extends AbstractInterceptor {
      * @see com.opensymphony.xwork2.interceptor.Interceptor#intercept(com.opensymphony.xwork2.ActionInvocation)
      */
     public String intercept(ActionInvocation invocation) throws Exception {
-        HttpSession httpSession = ServletActionContext.getRequest().getSession(false);
+        HttpServletRequest servletRequest = invocation.getInvocationContext().getServletRequest();
+        HttpSession httpSession = servletRequest.getSession(false);
         if (httpSession == null) {
             LOG.debug("Creating new HttpSession and new SessionMap in ServletActionContext");
-            ServletActionContext.getRequest().getSession(true);
-            ServletActionContext.getContext().setSession(new SessionMap<String, Object>(ServletActionContext.getRequest()));
+            servletRequest.getSession(true);
+            invocation.getInvocationContext().setSession(new SessionMap<>(servletRequest));
         }
         return invocation.invoke();
     }
diff --git a/core/src/main/java/org/apache/struts2/interceptor/FileUploadInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/FileUploadInterceptor.java
index b6a0fa9..e0619e2 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/FileUploadInterceptor.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/FileUploadInterceptor.java
@@ -232,7 +232,7 @@ public class FileUploadInterceptor extends AbstractInterceptor {
     public String intercept(ActionInvocation invocation) throws Exception {
         ActionContext ac = invocation.getInvocationContext();
 
-        HttpServletRequest request = (HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST);
+        HttpServletRequest request = ac.getServletRequest();
 
         if (!(request instanceof MultiPartRequestWrapper)) {
             if (LOG.isDebugEnabled()) {
diff --git a/core/src/main/java/org/apache/struts2/interceptor/MessageStoreInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/MessageStoreInterceptor.java
index 5d72945..1596be5 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/MessageStoreInterceptor.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/MessageStoreInterceptor.java
@@ -233,7 +233,7 @@ public class MessageStoreInterceptor extends AbstractInterceptor {
             Object action = invocation.getAction();
             if (action instanceof ValidationAware) {
                 // retrieve error / message from session
-                Map session = (Map) invocation.getInvocationContext().get(ActionContext.SESSION);
+                Map<String, Object> session = invocation.getInvocationContext().getSession();
 
                 if (session == null) {
                     LOG.debug("Session is not open, no errors / messages could be retrieve for action [{}]", action);
diff --git a/core/src/main/java/org/apache/struts2/interceptor/ServletConfigInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/ServletConfigInterceptor.java
index 9707896..0ef0f37 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/ServletConfigInterceptor.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/ServletConfigInterceptor.java
@@ -125,22 +125,22 @@ public class ServletConfigInterceptor extends AbstractInterceptor implements Str
         final ActionContext context = invocation.getInvocationContext();
 
         if (action instanceof ServletRequestAware) {
-            HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
+            HttpServletRequest request = context.getServletRequest();
             ((ServletRequestAware) action).setServletRequest(request);
         }
 
         if (action instanceof org.apache.struts2.action.ServletRequestAware) {
-            HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
+            HttpServletRequest request = context.getServletRequest();
             ((org.apache.struts2.action.ServletRequestAware) action).withServletRequest(request);
         }
 
         if (action instanceof ServletResponseAware) {
-            HttpServletResponse response = (HttpServletResponse) context.get(HTTP_RESPONSE);
+            HttpServletResponse response = context.getServletResponse();
             ((ServletResponseAware) action).setServletResponse(response);
         }
 
         if (action instanceof org.apache.struts2.action.ServletResponseAware) {
-            HttpServletResponse response = (HttpServletResponse) context.get(HTTP_RESPONSE);
+            HttpServletResponse response = context.getServletResponse();
             ((org.apache.struts2.action.ServletResponseAware) action).withServletResponse(response);
         }
 
@@ -177,7 +177,7 @@ public class ServletConfigInterceptor extends AbstractInterceptor implements Str
         }
 
         if (action instanceof PrincipalAware) {
-            HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
+            HttpServletRequest request = context.getServletRequest();
             if(request != null) {
                 // We are in servtlet environment, so principal information resides in HttpServletRequest
                 ((PrincipalAware) action).setPrincipalProxy(new ServletPrincipalProxy(request));
@@ -185,7 +185,7 @@ public class ServletConfigInterceptor extends AbstractInterceptor implements Str
         }
 
         if (action instanceof org.apache.struts2.action.PrincipalAware) {
-            HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
+            HttpServletRequest request = context.getServletRequest();
             if(request != null) {
                 // We are in servlet environment, so principal information resides in HttpServletRequest
                 ((org.apache.struts2.action.PrincipalAware) action).withPrincipalProxy(new ServletPrincipalProxy(request));
@@ -193,12 +193,12 @@ public class ServletConfigInterceptor extends AbstractInterceptor implements Str
         }
 
         if (action instanceof ServletContextAware) {
-            ServletContext servletContext = (ServletContext) context.get(SERVLET_CONTEXT);
+            ServletContext servletContext = context.getServletContext();
             ((ServletContextAware) action).setServletContext(servletContext);
         }
 
         if (action instanceof org.apache.struts2.action.ServletContextAware) {
-            ServletContext servletContext = (ServletContext) context.get(SERVLET_CONTEXT);
+            ServletContext servletContext = context.getServletContext();
             ((org.apache.struts2.action.ServletContextAware) action).withServletContext(servletContext);
         }
 
diff --git a/core/src/main/java/org/apache/struts2/interceptor/TokenSessionStoreInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/TokenSessionStoreInterceptor.java
index 863e804..05e491e 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/TokenSessionStoreInterceptor.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/TokenSessionStoreInterceptor.java
@@ -130,8 +130,8 @@ public class TokenSessionStoreInterceptor extends TokenInterceptor {
     protected String handleInvalidToken(ActionInvocation invocation) throws Exception {
         ActionContext ac = invocation.getInvocationContext();
 
-        HttpServletRequest request = (HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST);
-        HttpServletResponse response = (HttpServletResponse) ac.get(ServletActionContext.HTTP_RESPONSE);
+        HttpServletRequest request = ac.getServletRequest();
+        HttpServletResponse response = ac.getServletResponse();
         String tokenName = TokenHelper.getTokenName();
         String token = TokenHelper.getToken(tokenName);
 
@@ -169,7 +169,7 @@ public class TokenSessionStoreInterceptor extends TokenInterceptor {
 
     /**
      * Handles processing of valid tokens.  Stores the current invocation for
-     * later use by {@link handleInvalidToken}.
+     * later use by {@see #handleValidToken(ActionInvocation)}.
      * See {@link org.apache.struts2.util.InvocationSessionStore#storeInvocation(String key, String token, ActionInvocation invocation)} for details.
      * 
      * @param invocation
diff --git a/core/src/main/java/org/apache/struts2/interceptor/debugging/DebuggingInterceptor.java b/core/src/main/java/org/apache/struts2/interceptor/debugging/DebuggingInterceptor.java
index 10fdcf4..1cff710 100644
--- a/core/src/main/java/org/apache/struts2/interceptor/debugging/DebuggingInterceptor.java
+++ b/core/src/main/java/org/apache/struts2/interceptor/debugging/DebuggingInterceptor.java
@@ -192,7 +192,7 @@ public class DebuggingInterceptor extends AbstractInterceptor {
                 ValueStack stack = (ValueStack) ctx.getSession().get(SESSION_KEY);
                 if (stack == null) {
                     //allows it to be embedded on another page
-                    stack = (ValueStack) ctx.get(ActionContext.VALUE_STACK);
+                    stack = ctx.getValueStack();
                     ctx.getSession().put(SESSION_KEY, stack);
                 }
                 String cmd = getParameter(EXPRESSION_PARAM);
@@ -218,7 +218,7 @@ public class DebuggingInterceptor extends AbstractInterceptor {
                                 rootObjectExpression = "action";
                             }
                             String decorate = getParameter(DECORATE_PARAM);
-                            ValueStack stack = (ValueStack) ctx.get(ActionContext.VALUE_STACK);
+                            ValueStack stack = ctx.getValueStack();
                             Object rootObject = stack.findValue(rootObjectExpression);
 
                             try (StringWriter writer = new StringWriter()) {
@@ -258,7 +258,7 @@ public class DebuggingInterceptor extends AbstractInterceptor {
             } finally {
                 if (devMode && consoleEnabled) {
                     final ActionContext ctx = ActionContext.getContext();
-                    ctx.getSession().put(SESSION_KEY, ctx.get(ActionContext.VALUE_STACK));
+                    ctx.getSession().put(SESSION_KEY, ctx.getValueStack());
                 }
             }
         } else {
diff --git a/core/src/main/java/org/apache/struts2/util/URLBean.java b/core/src/main/java/org/apache/struts2/util/URLBean.java
index c5cf6fb..5e09718 100644
--- a/core/src/main/java/org/apache/struts2/util/URLBean.java
+++ b/core/src/main/java/org/apache/struts2/util/URLBean.java
@@ -18,6 +18,7 @@
  */
 package org.apache.struts2.util;
 
+import com.opensymphony.xwork2.ActionContext;
 import org.apache.struts2.ServletActionContext;
 import org.apache.struts2.views.util.DefaultUrlHelper;
 import org.apache.struts2.views.util.UrlHelper;
@@ -48,7 +49,7 @@ public class URLBean {
 
     public void setRequest(HttpServletRequest request) {
         this.request = request;
-        urlHelper = ServletActionContext.getContext().getInstance(DefaultUrlHelper.class);
+        urlHelper = ActionContext.getContext().getInstance(DefaultUrlHelper.class);
     }
 
     public void setResponse(HttpServletResponse response) {
diff --git a/core/src/main/java/org/apache/struts2/views/freemarker/FreemarkerResult.java b/core/src/main/java/org/apache/struts2/views/freemarker/FreemarkerResult.java
index 5bdb2e9..5f57297 100644
--- a/core/src/main/java/org/apache/struts2/views/freemarker/FreemarkerResult.java
+++ b/core/src/main/java/org/apache/struts2/views/freemarker/FreemarkerResult.java
@@ -275,7 +275,7 @@ public class FreemarkerResult extends StrutsResultSupport {
         ServletContext servletContext = ServletActionContext.getServletContext();
         HttpServletRequest request = ServletActionContext.getRequest();
         HttpServletResponse response = ServletActionContext.getResponse();
-        ValueStack stack = ServletActionContext.getContext().getValueStack();
+        ValueStack stack = ActionContext.getContext().getValueStack();
 
         Object action = null;
         if(invocation!= null ) action = invocation.getAction(); //Added for NullPointException
diff --git a/core/src/test/java/com/opensymphony/xwork2/StubValueStack.java b/core/src/test/java/com/opensymphony/xwork2/StubValueStack.java
index ea475f0..f5d4665 100644
--- a/core/src/test/java/com/opensymphony/xwork2/StubValueStack.java
+++ b/core/src/test/java/com/opensymphony/xwork2/StubValueStack.java
@@ -35,6 +35,11 @@ public class StubValueStack implements ValueStack {
         return ctx;
     }
 
+    @Override
+    public ActionContext getActionContext() {
+        return new ActionContext(ctx);
+    }
+
     public void setDefaultType(Class defaultType) {
     }
 
diff --git a/core/src/test/java/org/apache/struts2/ServletActionContextTest.java b/core/src/test/java/org/apache/struts2/ServletActionContextTest.java
index bd748c6..3e92e85 100644
--- a/core/src/test/java/org/apache/struts2/ServletActionContextTest.java
+++ b/core/src/test/java/org/apache/struts2/ServletActionContextTest.java
@@ -37,15 +37,14 @@ import java.util.Map;
  */
 public class ServletActionContextTest extends TestCase implements StrutsStatics {
 
-    ActionContext actionContext;
-    ServletActionContext servletActionContext;
+    private ActionContext actionContext;
     private HttpServletRequest request;
     private HttpServletResponse response;
     private MockServletContext servletContext;
 
 
     public void setUp() {
-        Map extraContext = new HashMap();
+        Map<String, Object> extraContext = new HashMap<>();
 
         request = new MockHttpServletRequest();
         response = new MockHttpServletResponse();
@@ -55,8 +54,7 @@ public class ServletActionContextTest extends TestCase implements StrutsStatics
         extraContext.put(HTTP_RESPONSE, response);
         extraContext.put(SERVLET_CONTEXT, servletContext);
 
-        actionContext = new ActionContext(extraContext);
-        ServletActionContext.setContext(actionContext);
+        actionContext = ActionContext.of(extraContext);
     }
 
     public void testContextParams() {
@@ -66,7 +64,7 @@ public class ServletActionContextTest extends TestCase implements StrutsStatics
     }
 
     public void testGetContext() {
-        ActionContext threadContext = ServletActionContext.getContext();
+        ActionContext threadContext = ServletActionContext.getActionContext();
         assertEquals(actionContext, threadContext);
     }
 }
diff --git a/core/src/test/java/org/apache/struts2/interceptor/CreateSessionInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/CreateSessionInterceptorTest.java
index 0ea33f8..3a887c2 100644
--- a/core/src/test/java/org/apache/struts2/interceptor/CreateSessionInterceptorTest.java
+++ b/core/src/test/java/org/apache/struts2/interceptor/CreateSessionInterceptorTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.struts2.interceptor;
 
+import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.mock.MockActionInvocation;
 import org.apache.struts2.ServletActionContext;
 import org.apache.struts2.StrutsInternalTestCase;
@@ -33,6 +34,15 @@ import javax.servlet.http.HttpServletRequest;
  */
 public class CreateSessionInterceptorTest extends StrutsInternalTestCase {
 
+    private MockActionInvocation invocation;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        invocation = new MockActionInvocation();
+        invocation.setInvocationContext(ActionContext.getContext());
+    }
+
     public void testCreateSession() throws Exception {
         Mock httpServletRequestMock = new Mock(HttpServletRequest.class);
         httpServletRequestMock.expects(new InvokeOnceMatcher()).method("getSession").with(new IsEqual(Boolean.FALSE));
@@ -43,7 +53,8 @@ public class CreateSessionInterceptorTest extends StrutsInternalTestCase {
         ServletActionContext.setRequest(request);
 
         CreateSessionInterceptor interceptor = new CreateSessionInterceptor();
-        interceptor.intercept(new MockActionInvocation());
+
+        interceptor.intercept(invocation);
 
         httpServletRequestMock.verify();
     }
diff --git a/core/src/test/java/org/apache/struts2/interceptor/I18nInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/I18nInterceptorTest.java
index da5607f..7cd0fcb 100644
--- a/core/src/test/java/org/apache/struts2/interceptor/I18nInterceptorTest.java
+++ b/core/src/test/java/org/apache/struts2/interceptor/I18nInterceptorTest.java
@@ -261,8 +261,8 @@ public class I18nInterceptorTest extends TestCase {
         ctx.put(ActionContext.SESSION, session);
 
         ac = new ActionContext(ctx);
+        ActionContext.setContext(ac);
 
-        ServletActionContext.setContext(ac);
         request = new MockHttpServletRequest();
         request.setSession(new MockHttpSession());
         ServletActionContext.setRequest(request);
diff --git a/plugins/embeddedjsp/src/main/java/org/apache/struts2/JSPLoader.java b/plugins/embeddedjsp/src/main/java/org/apache/struts2/JSPLoader.java
index 713fcb8..57c19fb 100644
--- a/plugins/embeddedjsp/src/main/java/org/apache/struts2/JSPLoader.java
+++ b/plugins/embeddedjsp/src/main/java/org/apache/struts2/JSPLoader.java
@@ -182,11 +182,11 @@ public class JSPLoader {
         List<URL> urls = urlSet.getUrls();
 
         if (urls != null && urls.size() > 0) {
-            final FileManagerFactory fileManagerFactoryGetInstance = ServletActionContext.getContext().getInstance(FileManagerFactory.class);
-            final FileManagerFactory contextFileManagerFactory = (fileManagerFactoryGetInstance != null ? fileManagerFactoryGetInstance : (FileManagerFactory) ServletActionContext.getContext().get(StrutsConstants.STRUTS_FILE_MANAGER_FACTORY)); 
+            final FileManagerFactory fileManagerFactoryGetInstance = ServletActionContext.getActionContext().getInstance(FileManagerFactory.class);
+            final FileManagerFactory contextFileManagerFactory = (fileManagerFactoryGetInstance != null ? fileManagerFactoryGetInstance : (FileManagerFactory) ServletActionContext.getActionContext().get(StrutsConstants.STRUTS_FILE_MANAGER_FACTORY));
             final FileManagerFactory fileManagerFactory = (contextFileManagerFactory != null ? contextFileManagerFactory : new DefaultFileManagerFactory());
             final FileManager fileManagerGetInstance = fileManagerFactory.getFileManager();
-            final FileManager contextFileManager = (fileManagerGetInstance != null ? fileManagerGetInstance : (FileManager) ServletActionContext.getContext().get(StrutsConstants.STRUTS_FILE_MANAGER));
+            final FileManager contextFileManager = (fileManagerGetInstance != null ? fileManagerGetInstance : (FileManager) ServletActionContext.getActionContext().get(StrutsConstants.STRUTS_FILE_MANAGER));
             final FileManager fileManager = (contextFileManager != null ? contextFileManager : new DefaultFileManager());
             for (URL url : urls) {
                 URL normalizedUrl = fileManager.normalizeToFileProtocol(url);
diff --git a/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreemarkerDecoratorServlet.java b/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreemarkerDecoratorServlet.java
index e3760cf..85ef896 100644
--- a/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreemarkerDecoratorServlet.java
+++ b/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/FreemarkerDecoratorServlet.java
@@ -66,7 +66,7 @@ public class FreemarkerDecoratorServlet extends freemarker.ext.servlet.Freemarke
 
     public void init() throws ServletException {
         try {
-            Dispatcher dispatcher = (Dispatcher) getServletContext().getAttribute(StrutsStatics.SERVLET_DISPATCHER);
+            Dispatcher dispatcher = Dispatcher.getInstance(getServletContext());
             if (dispatcher == null) {
                 throw new IllegalStateException("Unable to find the Dispatcher in the Servlet Context. Is '" + StrutsListener.class.getName() + "' missing in web.xml?");
             }
diff --git a/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityDecoratorServlet.java b/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityDecoratorServlet.java
index 7fd2265..4859c4f 100644
--- a/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityDecoratorServlet.java
+++ b/plugins/sitemesh/src/main/java/org/apache/struts2/sitemesh/VelocityDecoratorServlet.java
@@ -74,7 +74,7 @@ public class VelocityDecoratorServlet extends VelocityViewServlet {
      */
     public void init(ServletConfig config) throws ServletException {
         super.init(config);
-        Dispatcher dispatcher = (Dispatcher) getServletContext().getAttribute(StrutsStatics.SERVLET_DISPATCHER);
+        Dispatcher dispatcher = Dispatcher.getInstance(getServletContext());
         if (dispatcher == null) {
             throw new IllegalStateException("Unable to find the Dispatcher in the Servlet Context. Is '" + StrutsListener.class.getName() + "' missing in web.xml?");
         }