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/04/13 15:24:24 UTC

[struts] branch action-context-boost updated: WW-4789 WW-3788 Marks VALUE_STACK, APPLICATION and SESSION as deprecated on behalf using helper methods

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


The following commit(s) were added to refs/heads/action-context-boost by this push:
     new adcc67d  WW-4789 WW-3788 Marks VALUE_STACK, APPLICATION and SESSION as deprecated on behalf using helper methods
adcc67d is described below

commit adcc67d9dc40782c5df04e33282440749e977548
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Mon Apr 13 17:24:16 2020 +0200

    WW-4789 WW-3788 Marks VALUE_STACK, APPLICATION and SESSION as deprecated on behalf using helper methods
---
 .../com/opensymphony/xwork2/ActionChainResult.java |   9 +-
 .../com/opensymphony/xwork2/ActionContext.java     |  18 ++
 .../xwork2/DefaultActionInvocation.java            |   4 +-
 .../apache/struts2/components/ActionComponent.java |  15 +-
 .../org/apache/struts2/dispatcher/Dispatcher.java  |  46 +++---
 .../debugging/DebuggingInterceptor.java            |  14 +-
 .../com/opensymphony/xwork2/ActionNestingTest.java |  38 +++--
 .../interceptor/ExecuteAndWaitInterceptorTest.java |  41 +++--
 .../struts2/interceptor/TokenInterceptorTest.java  |  28 ++--
 .../apache/struts2/validators/DWRValidator.java    |   8 +-
 .../portlet/dispatcher/Jsr168Dispatcher.java       | 183 ++++++++++-----------
 .../struts2/views/jsp/PortletUrlTagTest.java       |  17 +-
 12 files changed, 225 insertions(+), 196 deletions(-)

diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionChainResult.java b/core/src/main/java/com/opensymphony/xwork2/ActionChainResult.java
index 6094f4b..06ab021 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ActionChainResult.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ActionChainResult.java
@@ -221,10 +221,11 @@ public class ActionChainResult implements Result {
         }
         addToHistory(finalNamespace, finalActionName, finalMethodName);
 
-        HashMap<String, Object> extraContext = new HashMap<>();
-        extraContext.put(ActionContext.VALUE_STACK, invocation.getInvocationContext().getValueStack());
-        extraContext.put(ActionContext.PARAMETERS, invocation.getInvocationContext().getParameters());
-        extraContext.put(CHAIN_HISTORY, ActionChainResult.getChainHistory());
+        Map<String, Object> extraContext = ActionContext.of(new HashMap<>())
+            .withValueStack(invocation.getInvocationContext().getValueStack())
+            .withParameters(invocation.getInvocationContext().getParameters())
+            .with(CHAIN_HISTORY, ActionChainResult.getChainHistory())
+            .getContextMap();
 
         LOG.debug("Chaining to action {}", finalActionName);
 
diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java
index e4d9f73..8900aef 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java
@@ -32,6 +32,7 @@ import javax.servlet.http.HttpServletResponse;
 import javax.servlet.jsp.PageContext;
 import java.io.Serializable;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.Locale;
 import java.util.Map;
 
@@ -70,22 +71,30 @@ public class ActionContext implements Serializable {
 
     /**
      * Constant for the {@link com.opensymphony.xwork2.util.ValueStack OGNL value stack}.
+     * @deprecated scope will be narrowed to "private", use helper methods instead
      */
+    @Deprecated
     public static final String VALUE_STACK = ValueStack.VALUE_STACK;
 
     /**
      * Constant for the action's session.
+     * @deprecated scope will be narrowed to "private", use helper methods instead
      */
+    @Deprecated
     public static final String SESSION = "com.opensymphony.xwork2.ActionContext.session";
 
     /**
      * Constant for the action's application context.
+     * @deprecated scope will be narrowed to "private", use helper methods instead
      */
+    @Deprecated
     public static final String APPLICATION = "com.opensymphony.xwork2.ActionContext.application";
 
     /**
      * Constant for the action's parameters.
+     * @deprecated scope will be narrowed to "private", use helper methods instead
      */
+    @Deprecated
     public static final String PARAMETERS = "com.opensymphony.xwork2.ActionContext.parameters";
 
     /**
@@ -150,6 +159,10 @@ public class ActionContext implements Serializable {
         return ActionContext.getContext();
     }
 
+    public static boolean containsValueStack(Map<String, Object> context) {
+        return context != null && context.containsKey(VALUE_STACK);
+    }
+
     /**
      * Binds this context with the current thread
      *
@@ -533,4 +546,9 @@ public class ActionContext implements Serializable {
         put(LOCALE, locale);
         return this;
     }
+
+    public ActionContext with(String key, Object value) {
+        put(key, value);
+        return this;
+    }
 }
diff --git a/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java b/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java
index 6ca0c92..ea2076d 100644
--- a/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java
+++ b/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java
@@ -326,9 +326,9 @@ public class DefaultActionInvocation implements ActionInvocation {
     protected Map<String, Object> createContextMap() {
         ActionContext actionContext;
 
-        if (extraContext != null && extraContext.containsKey(ActionContext.VALUE_STACK)) {
+        if (ActionContext.containsValueStack(extraContext)) {
             // In case the ValueStack was passed in
-            stack = (ValueStack) extraContext.get(ActionContext.VALUE_STACK);
+            stack = ActionContext.of(extraContext).getValueStack();
 
             if (stack == null) {
                 throw new IllegalStateException("There was a null Stack set into the extra params.");
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 727a216..98251ba 100644
--- a/core/src/main/java/org/apache/struts2/components/ActionComponent.java
+++ b/core/src/main/java/org/apache/struts2/components/ActionComponent.java
@@ -175,7 +175,7 @@ public class ActionComponent extends ContextBean {
         return end;
     }
 
-    protected Map createExtraContext() {
+    protected Map<String, Object> createExtraContext() {
         HttpParameters newParams = createParametersForContext();
 
         ActionContext ctx = stack.getActionContext();
@@ -184,7 +184,8 @@ public class ActionComponent extends ContextBean {
         Map<String, Object> application = ctx.getApplication();
 
         Dispatcher du = Dispatcher.getInstance();
-        Map<String, Object> extraContext = du.createContextMap(new RequestMap(req),
+        Map<String, Object> extraContext = du.createContextMap(
+            new RequestMap(req),
                 newParams,
                 session,
                 application,
@@ -192,12 +193,12 @@ public class ActionComponent extends ContextBean {
                 res);
 
         ValueStack newStack = valueStackFactory.createValueStack(stack);
-        extraContext.put(ActionContext.VALUE_STACK, newStack);
 
-        // add page context, such that ServletDispatcherResult will do an include
-        extraContext.put(ServletActionContext.PAGE_CONTEXT, pageContext);
-
-        return extraContext;
+        return ActionContext.of(extraContext)
+            .withValueStack(newStack)
+            // add page context, such that ServletDispatcherResult will do an include
+            .withPageContext(pageContext)
+            .getContextMap();
     }
 
     /**
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 44c7b91..b2951ad 100644
--- a/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java
+++ b/core/src/main/java/org/apache/struts2/dispatcher/Dispatcher.java
@@ -606,7 +606,9 @@ public class Dispatcher {
             }
         }
         if (stack != null) {
-            extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));
+            extraContext = ActionContext.of(extraContext)
+                .withValueStack(valueStackFactory.createValueStack(stack))
+                .getContextMap();
         }
 
         try {
@@ -718,28 +720,26 @@ public class Dispatcher {
      * @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) {
-        HashMap<String, Object> extraContext = new HashMap<>();
-        extraContext.put(ActionContext.PARAMETERS, parameters);
-        extraContext.put(ActionContext.SESSION, sessionMap);
-        extraContext.put(ActionContext.APPLICATION, applicationMap);
-
-        extraContext.put(ActionContext.LOCALE, getLocale(request));
-
-        extraContext.put(StrutsStatics.HTTP_REQUEST, request);
-        extraContext.put(StrutsStatics.HTTP_RESPONSE, response);
-        extraContext.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
-
-        // helpers to get access to request/session/application scope
-        extraContext.put("request", requestMap);
-        extraContext.put("session", sessionMap);
-        extraContext.put("application", applicationMap);
-        extraContext.put("parameters", parameters);
+    public Map<String, Object> createContextMap(Map<String, Object> requestMap,
+                                                HttpParameters parameters,
+                                                Map<String, Object> sessionMap,
+                                                Map<String, Object> applicationMap,
+                                                HttpServletRequest request,
+                                                HttpServletResponse response) {
+        Map<String, Object> extraContext = ActionContext.of(new HashMap<>())
+            .withParameters(parameters)
+            .withSession(sessionMap)
+            .withApplication(applicationMap)
+            .withLocale(getLocale(request))
+            .withServletRequest(request)
+            .withServletResponse(response)
+            .withServletContext(servletContext)
+            // helpers to get access to request/session/application scope
+            .with("request", requestMap)
+            .with("session", sessionMap)
+            .with("application", applicationMap)
+            .with("parameters", parameters)
+            .getContextMap();
 
         AttributeMap attrMap = new AttributeMap(extraContext);
         extraContext.put("attr", attrMap);
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 1cff710..62f8716 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
@@ -304,14 +304,12 @@ public class DebuggingInterceptor extends AbstractInterceptor {
         writer.startNode(DEBUG_PARAM);
         serializeIt(ctx.getParameters(), "parameters", writer, new ArrayList<>());
         writer.startNode("context");
-        String key;
-        Map ctxMap = ctx.getContextMap();
-        for (Object o : ctxMap.keySet()) {
-            key = o.toString();
+        Map<String, Object> ctxMap = ctx.getContextMap();
+        for (String key : ctxMap.keySet()) {
             boolean print = !ignoreKeys.contains(key);
 
-            for (String ignorePrefixe : ignorePrefixes) {
-                if (key.startsWith(ignorePrefixe)) {
+            for (String ignorePrefix : ignorePrefixes) {
+                if (key.startsWith(ignorePrefix)) {
                     print = false;
                     break;
                 }
@@ -321,11 +319,11 @@ public class DebuggingInterceptor extends AbstractInterceptor {
             }
         }
         writer.endNode();
-        Map requestMap = (Map) ctx.get("request");
+        Map<String, Object> requestMap = (Map<String, Object>) ctx.get("request");
         serializeIt(requestMap, "request", writer, filterValueStack(requestMap));
         serializeIt(ctx.getSession(), "session", writer, new ArrayList<>());
 
-        ValueStack stack = (ValueStack) ctx.get(ActionContext.VALUE_STACK);
+        ValueStack stack = ctx.getValueStack();
         serializeIt(stack.getRoot(), "valueStack", writer, new ArrayList<>());
         writer.endNode();
     }
diff --git a/core/src/test/java/com/opensymphony/xwork2/ActionNestingTest.java b/core/src/test/java/com/opensymphony/xwork2/ActionNestingTest.java
index 3344ee5..cc4f017 100644
--- a/core/src/test/java/com/opensymphony/xwork2/ActionNestingTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/ActionNestingTest.java
@@ -29,13 +29,14 @@ import com.opensymphony.xwork2.util.ValueStack;
 import com.opensymphony.xwork2.util.location.LocatableProperties;
 
 import java.util.HashMap;
+import java.util.Map;
 
 
 /**
  * ActionNestingTest
  *
  * @author Jason Carreira
- *         Created Mar 5, 2003 2:02:01 PM
+ * Created Mar 5, 2003 2:02:01 PM
  */
 public class ActionNestingTest extends XWorkTestCase {
 
@@ -56,7 +57,8 @@ public class ActionNestingTest extends XWorkTestCase {
         return VALUE;
     }
 
-    @Override public void setUp() throws Exception {
+    @Override
+    public void setUp() throws Exception {
         super.setUp();
         loadConfigurationProviders(new NestedTestConfigurationProvider());
 
@@ -64,7 +66,8 @@ public class ActionNestingTest extends XWorkTestCase {
         context.getValueStack().push(this);
     }
 
-    @Override protected void tearDown() throws Exception {
+    @Override
+    protected void tearDown() throws Exception {
         super.tearDown();
     }
 
@@ -90,8 +93,9 @@ public class ActionNestingTest extends XWorkTestCase {
         ValueStack stack = ActionContext.getContext().getValueStack();
         assertEquals(VALUE, stack.findValue(KEY));
 
-        HashMap<String, Object> extraContext = new HashMap<>();
-        extraContext.put(ActionContext.VALUE_STACK, stack);
+        Map<String, Object> extraContext = ActionContext.of(new HashMap<>())
+            .withValueStack(stack)
+            .getContextMap();
 
         ActionProxy proxy = actionProxyFactory.createActionProxy(NAMESPACE, STACK_ACTION_NAME, null, extraContext);
         proxy.execute();
@@ -105,30 +109,32 @@ public class ActionNestingTest extends XWorkTestCase {
 
     class NestedTestConfigurationProvider implements ConfigurationProvider {
         private Configuration configuration;
+
         public void destroy() {
         }
+
         public void init(Configuration configuration) {
             this.configuration = configuration;
         }
 
         public void register(ContainerBuilder builder, LocatableProperties props) {
         }
-        
+
         public void loadPackages() {
-            
+
             PackageConfig packageContext = new PackageConfig.Builder("nestedActionTest")
                 .addActionConfig(SIMPLE_ACTION_NAME, new ActionConfig.Builder("nestedActionTest", SIMPLE_ACTION_NAME, SimpleAction.class.getName())
-                        .addResultConfig(new ResultConfig.Builder(Action.SUCCESS, MockResult.class.getName()).build())
-                        .addResultConfig(new ResultConfig.Builder(Action.ERROR, MockResult.class.getName()).build())
-                        .build())
+                    .addResultConfig(new ResultConfig.Builder(Action.SUCCESS, MockResult.class.getName()).build())
+                    .addResultConfig(new ResultConfig.Builder(Action.ERROR, MockResult.class.getName()).build())
+                    .build())
                 .addActionConfig(NO_STACK_ACTION_NAME, new ActionConfig.Builder("nestedActionTest", NO_STACK_ACTION_NAME, NestedAction.class.getName())
-                        .addResultConfig(new ResultConfig.Builder(Action.SUCCESS, MockResult.class.getName()).build())
-                        .methodName("noStack")
-                        .build())
+                    .addResultConfig(new ResultConfig.Builder(Action.SUCCESS, MockResult.class.getName()).build())
+                    .methodName("noStack")
+                    .build())
                 .addActionConfig(STACK_ACTION_NAME, new ActionConfig.Builder("nestedActionTest", STACK_ACTION_NAME, NestedAction.class.getName())
-                        .addResultConfig(new ResultConfig.Builder(Action.SUCCESS, MockResult.class.getName()).build())
-                        .methodName("stack")
-                        .build())
+                    .addResultConfig(new ResultConfig.Builder(Action.SUCCESS, MockResult.class.getName()).build())
+                    .methodName("stack")
+                    .build())
                 .namespace(NAMESPACE)
                 .build();
             configuration.addPackageConfig("nestedActionTest", packageContext);
diff --git a/core/src/test/java/org/apache/struts2/interceptor/ExecuteAndWaitInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/ExecuteAndWaitInterceptorTest.java
index 1372a5a..08c034b 100644
--- a/core/src/test/java/org/apache/struts2/interceptor/ExecuteAndWaitInterceptorTest.java
+++ b/core/src/test/java/org/apache/struts2/interceptor/ExecuteAndWaitInterceptorTest.java
@@ -18,7 +18,12 @@
  */
 package org.apache.struts2.interceptor;
 
-import com.opensymphony.xwork2.*;
+import com.opensymphony.xwork2.Action;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionProxy;
+import com.opensymphony.xwork2.ActionProxyFactory;
+import com.opensymphony.xwork2.DefaultActionProxyFactory;
+import com.opensymphony.xwork2.ObjectFactory;
 import com.opensymphony.xwork2.config.Configuration;
 import com.opensymphony.xwork2.config.ConfigurationException;
 import com.opensymphony.xwork2.config.ConfigurationProvider;
@@ -52,9 +57,9 @@ public class ExecuteAndWaitInterceptorTest extends StrutsInternalTestCase {
 
     private StrutsMockHttpServletRequest request;
     private HttpSession httpSession;
-    private Map context;
-    private Map params;
-    private Map session;
+    private Map<String, Object> context;
+    private Map<String, Object> params;
+    private Map<String, Object> session;
     private ExecuteAndWaitInterceptor waitInterceptor;
     private ParametersInterceptor parametersInterceptor;
 
@@ -175,13 +180,13 @@ public class ExecuteAndWaitInterceptorTest extends StrutsInternalTestCase {
         ObjectOutputStream oos = new ObjectOutputStream(baos);
         oos.writeObject(session);//WW-4900 action1 and invocation are not serializable but we should not fail at this line
         oos.close();
-        byte b[] = baos.toByteArray();
+        byte[] b = baos.toByteArray();
         baos.close();
 
         ByteArrayInputStream bais = new ByteArrayInputStream(b);
         ObjectInputStream ois = new ObjectInputStream(bais);
-        session = (Map) ois.readObject();
-        context.put(ActionContext.SESSION, session);
+        session = (Map<String, Object>) ois.readObject();
+        context = ActionContext.of(context).withSession(session).getContextMap();
         ois.close();
         bais.close();
 
@@ -203,19 +208,24 @@ public class ExecuteAndWaitInterceptorTest extends StrutsInternalTestCase {
     }
 
     protected void setUp() throws Exception {
+        super.setUp();
         loadConfigurationProviders(new WaitConfigurationProvider());
 
-        session = new HashMap();
-        params = new HashMap();
-        context = new HashMap();
-        context.put(ActionContext.SESSION, session);
-        context.put(ActionContext.PARAMETERS, HttpParameters.create().build());
+        session = new HashMap<>();
+        params = new HashMap<>();
+        context = new HashMap<>();
 
         request = new StrutsMockHttpServletRequest();
         httpSession = new StrutsMockHttpSession();
         request.setSession(httpSession);
         request.setParameterMap(params);
-        context.put(ServletActionContext.HTTP_REQUEST, request);
+
+        context = ActionContext.of(context)
+            .withSession(session)
+            .withParameters(HttpParameters.create().build())
+            .withServletRequest(request)
+            .getContextMap();
+
         container.inject(parametersInterceptor);
     }
 
@@ -226,6 +236,7 @@ public class ExecuteAndWaitInterceptorTest extends StrutsInternalTestCase {
     private class WaitConfigurationProvider implements ConfigurationProvider {
 
         Configuration configuration;
+
         public void destroy() {
             waitInterceptor.destroy();
         }
@@ -250,8 +261,8 @@ public class ExecuteAndWaitInterceptorTest extends StrutsInternalTestCase {
                     .addResultConfig(new ResultConfig.Builder(ExecuteAndWaitInterceptor.WAIT, MockResult.class.getName()).build())
                     .addInterceptor(new InterceptorMapping("params", parametersInterceptor))
                     .addInterceptor(new InterceptorMapping("execAndWait", waitInterceptor))
-                .build())
-            .build();
+                    .build())
+                .build();
             configuration.addPackageConfig("", wait);
         }
 
diff --git a/core/src/test/java/org/apache/struts2/interceptor/TokenInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/TokenInterceptorTest.java
index f10e5e5..2208047 100644
--- a/core/src/test/java/org/apache/struts2/interceptor/TokenInterceptorTest.java
+++ b/core/src/test/java/org/apache/struts2/interceptor/TokenInterceptorTest.java
@@ -18,12 +18,10 @@
  */
 package org.apache.struts2.interceptor;
 
-import java.util.Map;
-import java.util.TreeMap;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
-
+import com.opensymphony.xwork2.Action;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ActionProxy;
+import com.opensymphony.xwork2.util.ValueStack;
 import org.apache.struts2.ServletActionContext;
 import org.apache.struts2.StrutsInternalTestCase;
 import org.apache.struts2.TestConfigurationProvider;
@@ -32,10 +30,10 @@ import org.apache.struts2.util.TokenHelper;
 import org.apache.struts2.views.jsp.StrutsMockHttpServletRequest;
 import org.apache.struts2.views.jsp.StrutsMockHttpSession;
 
-import com.opensymphony.xwork2.Action;
-import com.opensymphony.xwork2.ActionContext;
-import com.opensymphony.xwork2.ActionProxy;
-import com.opensymphony.xwork2.util.ValueStack;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.util.Map;
+import java.util.TreeMap;
 
 
 /**
@@ -95,10 +93,10 @@ public class TokenInterceptorTest extends StrutsInternalTestCase {
 
     protected void setToken(String token) {
         request.getParameterMap().put(TokenHelper.TOKEN_NAME_FIELD, new String[]{
-                TokenHelper.DEFAULT_TOKEN_NAME
+            TokenHelper.DEFAULT_TOKEN_NAME
         });
         request.getParameterMap().put(TokenHelper.DEFAULT_TOKEN_NAME, new String[]{
-                token
+            token
         });
         extraContext.put(ActionContext.PARAMETERS, HttpParameters.create(params).build());
     }
@@ -111,8 +109,10 @@ public class TokenInterceptorTest extends StrutsInternalTestCase {
         session = new TreeMap<>();
         params = new TreeMap<>();
         extraContext = new TreeMap<>();
-        extraContext.put(ActionContext.SESSION, session);
-        extraContext.put(ActionContext.PARAMETERS, HttpParameters.create().build());
+        extraContext = ActionContext.of(extraContext)
+            .withSession(session)
+            .withParameters(HttpParameters.create().build())
+            .getContextMap();
 
         request = new StrutsMockHttpServletRequest();
         httpSession = new StrutsMockHttpSession();
diff --git a/plugins/dwr/src/main/java/org/apache/struts2/validators/DWRValidator.java b/plugins/dwr/src/main/java/org/apache/struts2/validators/DWRValidator.java
index 60edf4b..c8cc669 100644
--- a/plugins/dwr/src/main/java/org/apache/struts2/validators/DWRValidator.java
+++ b/plugins/dwr/src/main/java/org/apache/struts2/validators/DWRValidator.java
@@ -75,11 +75,11 @@ public class DWRValidator {
         if (params != null) {
             requestParams = requestParams.withExtraParams(params);
         }
-        Map requestMap = new RequestMap(req);
-        Map session = new SessionMap(req);
-        Map application = new ApplicationMap(servletContext);
+        Map<String, Object> requestMap = new RequestMap(req);
+        Map<String, Object> session = new SessionMap<>(req);
+        Map<String, Object> application = new ApplicationMap(servletContext);
         Dispatcher du = Dispatcher.getInstance();
-        HashMap<String, Object> ctx = du.createContextMap(requestMap,
+        Map<String, Object> ctx = du.createContextMap(requestMap,
                 requestParams.build(),
                 session,
                 application,
diff --git a/plugins/portlet/src/main/java/org/apache/struts2/portlet/dispatcher/Jsr168Dispatcher.java b/plugins/portlet/src/main/java/org/apache/struts2/portlet/dispatcher/Jsr168Dispatcher.java
index 6b985ff..cc7b00c 100644
--- a/plugins/portlet/src/main/java/org/apache/struts2/portlet/dispatcher/Jsr168Dispatcher.java
+++ b/plugins/portlet/src/main/java/org/apache/struts2/portlet/dispatcher/Jsr168Dispatcher.java
@@ -24,9 +24,9 @@ import com.opensymphony.xwork2.ActionProxyFactory;
 import com.opensymphony.xwork2.config.ConfigurationException;
 import com.opensymphony.xwork2.inject.Container;
 import org.apache.commons.lang3.LocaleUtils;
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.LogManager;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.message.ParameterizedMessage;
 import org.apache.struts2.StrutsConstants;
 import org.apache.struts2.StrutsException;
@@ -214,21 +214,21 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
         LOG.debug("PortletNamespace: {}", portletNamespace);
 
         parseModeConfig(actionMap, cfg, PortletMode.VIEW, "viewNamespace",
-                "defaultViewAction");
+            "defaultViewAction");
         parseModeConfig(actionMap, cfg, PortletMode.EDIT, "editNamespace",
-                "defaultEditAction");
+            "defaultEditAction");
         parseModeConfig(actionMap, cfg, PortletMode.HELP, "helpNamespace",
-                "defaultHelpAction");
+            "defaultHelpAction");
         parseModeConfig(actionMap, cfg, new PortletMode("config"), "configNamespace",
-                "defaultConfigAction");
+            "defaultConfigAction");
         parseModeConfig(actionMap, cfg, new PortletMode("about"), "aboutNamespace",
-                "defaultAboutAction");
+            "defaultAboutAction");
         parseModeConfig(actionMap, cfg, new PortletMode("print"), "printNamespace",
-                "defaultPrintAction");
+            "defaultPrintAction");
         parseModeConfig(actionMap, cfg, new PortletMode("preview"), "previewNamespace",
-                "defaultPreviewAction");
+            "defaultPreviewAction");
         parseModeConfig(actionMap, cfg, new PortletMode("edit_defaults"),
-                "editDefaultsNamespace", "defaultEditDefaultsAction");
+            "editDefaultsNamespace", "defaultEditDefaultsAction");
         if (StringUtils.isEmpty(portletNamespace)) {
             portletNamespace = "";
         }
@@ -239,13 +239,14 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
 
     /**
      * Parse the mode to namespace mappings configured in portlet.xml
-     * @param actionMap The map with mode <-> default action mapping.
-     * @param portletConfig The PortletConfig.
-     * @param portletMode The PortletMode.
-     * @param nameSpaceParam Name of the init parameter where the namespace for the mode
-     * is configured.
+     *
+     * @param actionMap          The map with mode <-> default action mapping.
+     * @param portletConfig      The PortletConfig.
+     * @param portletMode        The PortletMode.
+     * @param nameSpaceParam     Name of the init parameter where the namespace for the mode
+     *                           is configured.
      * @param defaultActionParam Name of the init parameter where the default action to
-     * execute for the mode is configured.
+     *                           execute for the mode is configured.
      */
     void parseModeConfig(Map<PortletMode, ActionMapping> actionMap, PortletConfig portletConfig,
                          PortletMode portletMode, String nameSpaceParam,
@@ -286,25 +287,23 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
     /**
      * Service an action from the <tt>event</tt> phase.
      *
-     * @param request action request
-     * @param response  action response
-     *
+     * @param request  action request
+     * @param response action response
      * @throws PortletException in case of errors
-     * @throws IOException in case of IO errors
-     *
+     * @throws IOException      in case of IO errors
      * @see javax.portlet.Portlet#processAction(javax.portlet.ActionRequest,
-     *      javax.portlet.ActionResponse)
+     * javax.portlet.ActionResponse)
      */
     public void processAction(ActionRequest request, ActionResponse response)
-            throws PortletException, IOException {
+        throws PortletException, IOException {
         if (LOG.isDebugEnabled()) {
             LOG.debug("Entering processAction in mode ", request.getPortletMode().toString());
         }
         resetActionContext();
         try {
             serviceAction(request, response, getRequestMap(request), getParameterMap(request),
-                    getSessionMap(request), getApplicationMap(),
-                    portletNamespace, PortletPhase.ACTION_PHASE);
+                getSessionMap(request), getApplicationMap(),
+                portletNamespace, PortletPhase.ACTION_PHASE);
             if (LOG.isDebugEnabled()) LOG.debug("Leaving processAction");
         } finally {
             ActionContext.clear();
@@ -314,17 +313,15 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
     /**
      * Service an action from the <tt>render</tt> phase.
      *
-     * @param request render request
-     * @param response  render response
-     *
+     * @param request  render request
+     * @param response render response
      * @throws PortletException in case of errors
-     * @throws IOException in case of IO errors
-     *
+     * @throws IOException      in case of IO errors
      * @see javax.portlet.Portlet#render(javax.portlet.RenderRequest,
-     *      javax.portlet.RenderResponse)
+     * javax.portlet.RenderResponse)
      */
     public void render(RenderRequest request, RenderResponse response)
-            throws PortletException, IOException {
+        throws PortletException, IOException {
 
         if (LOG.isDebugEnabled()) {
             LOG.debug("Entering render in mode ", request.getPortletMode().toString());
@@ -335,8 +332,8 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
             try {
                 // Check to see if an event set the render to be included directly
                 serviceAction(request, response, getRequestMap(request), getParameterMap(request),
-                        getSessionMap(request), getApplicationMap(),
-                        portletNamespace, PortletPhase.RENDER_PHASE);
+                    getSessionMap(request), getApplicationMap(),
+                    portletNamespace, PortletPhase.RENDER_PHASE);
                 if (LOG.isDebugEnabled()) LOG.debug("Leaving render");
             } finally {
                 resetActionContext();
@@ -345,7 +342,7 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
     }
 
     /**
-     *  Reset the action context.
+     * Reset the action context.
      */
     void resetActionContext() {
         ActionContext.clear();
@@ -355,59 +352,54 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
      * Merges all application and portlet attributes into a single
      * <tt>HashMap</tt> to represent the entire <tt>Action</tt> context.
      *
-     * @param requestMap a Map of all request attributes.
-     * @param parameterMap a Map of all request parameters.
-     * @param sessionMap a Map of all session attributes.
-     * @param applicationMap a Map of all servlet context attributes.
-     * @param request the PortletRequest object.
-     * @param response the PortletResponse object.
-     * @param servletRequest the HttpServletRequest object.
+     * @param requestMap      a Map of all request attributes.
+     * @param parameterMap    a Map of all request parameters.
+     * @param sessionMap      a Map of all session attributes.
+     * @param applicationMap  a Map of all servlet context attributes.
+     * @param request         the PortletRequest object.
+     * @param response        the PortletResponse object.
+     * @param servletRequest  the HttpServletRequest object.
      * @param servletResponse the HttpServletResponse object.
-     * @param servletContext the ServletContext object.
-     * @param portletConfig the PortletConfig object.
-     * @param phase The portlet phase (render or action, see
-     *        {@link PortletConstants})
+     * @param servletContext  the ServletContext object.
+     * @param portletConfig   the PortletConfig object.
+     * @param phase           The portlet phase (render or action, see
+     *                        {@link PortletConstants})
      * @return a HashMap representing the <tt>Action</tt> context.
-     *
      * @throws IOException in case of IO errors
      */
-    public HashMap<String, Object> createContextMap(Map<String, Object> requestMap, Map<String, String[]> parameterMap,
-                                                    Map<String, Object> sessionMap, Map<String, Object> applicationMap,
-                                                    PortletRequest request, PortletResponse response, HttpServletRequest servletRequest,
-                                                    HttpServletResponse servletResponse, ServletContext servletContext,
-                                                    PortletConfig portletConfig, PortletPhase phase) throws IOException {
+    public Map<String, Object> createContextMap(Map<String, Object> requestMap, Map<String, String[]> parameterMap,
+                                                Map<String, Object> sessionMap, Map<String, Object> applicationMap,
+                                                PortletRequest request, PortletResponse response, HttpServletRequest servletRequest,
+                                                HttpServletResponse servletResponse, ServletContext servletContext,
+                                                PortletConfig portletConfig, PortletPhase phase) throws IOException {
 
         // TODO Must put http request/response objects into map for use with
         container.inject(servletRequest);
 
         // ServletActionContext
-        HashMap<String, Object> extraContext = new HashMap<String, Object>();
-        // The dummy servlet objects. Eases reuse of existing interceptors that uses the servlet objects.
-        extraContext.put(StrutsStatics.HTTP_REQUEST, servletRequest);
-        extraContext.put(StrutsStatics.HTTP_RESPONSE, servletResponse);
-        extraContext.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
-        // End dummy servlet objects
-        extraContext.put(ActionContext.PARAMETERS, HttpParameters.create(parameterMap).build());
-        extraContext.put(ActionContext.SESSION, sessionMap);
-        extraContext.put(ActionContext.APPLICATION, applicationMap);
-
-        extraContext.put(ActionContext.LOCALE, getLocale(request));
-
-        extraContext.put(StrutsStatics.STRUTS_PORTLET_CONTEXT, getPortletContext());
-        extraContext.put(REQUEST, request);
-        extraContext.put(RESPONSE, response);
-        extraContext.put(PORTLET_CONFIG, portletConfig);
-        extraContext.put(PORTLET_NAMESPACE, portletNamespace);
-        extraContext.put(DEFAULT_ACTION_FOR_MODE, actionMap.get(request.getPortletMode()));
-        // helpers to get access to request/session/application scope
-        extraContext.put("request", requestMap);
-        extraContext.put("session", sessionMap);
-        extraContext.put("application", applicationMap);
-        extraContext.put("parameters", parameterMap);
-        extraContext.put(MODE_NAMESPACE_MAP, modeMap);
-        extraContext.put(PortletConstants.DEFAULT_ACTION_MAP, actionMap);
-
-        extraContext.put(PortletConstants.PHASE, phase);
+        Map<String, Object> extraContext = ActionContext.of(new HashMap<String, Object>())
+            .withServletRequest(servletRequest)
+            .withServletResponse(servletResponse)
+            .withServletContext(servletContext)
+            .withParameters(HttpParameters.create(parameterMap).build())
+            .withSession(sessionMap)
+            .withApplication(applicationMap)
+            .withLocale(getLocale(request))
+            .with(StrutsStatics.STRUTS_PORTLET_CONTEXT, getPortletContext())
+            .with(REQUEST, request)
+            .with(RESPONSE, response)
+            .with(PORTLET_CONFIG, portletConfig)
+            .with(PORTLET_NAMESPACE, portletNamespace)
+            .with(DEFAULT_ACTION_FOR_MODE, actionMap.get(request.getPortletMode()))
+            // helpers to get access to request/session/application scope
+            .with("request", requestMap)
+            .with("session", sessionMap)
+            .with("application", applicationMap)
+            .with("parameters", parameterMap)
+            .with(MODE_NAMESPACE_MAP, modeMap)
+            .with(PortletConstants.DEFAULT_ACTION_MAP, actionMap)
+            .with(PortletConstants.PHASE, phase)
+            .getContextMap();
 
         AttributeMap attrMap = new AttributeMap(extraContext);
         extraContext.put("attr", attrMap);
@@ -423,7 +415,7 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
                 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 {
@@ -438,15 +430,14 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
      * from the given action name and namespace. After that, the action is
      * executed and output channels throught the response object.
      *
-     * @param request the HttpServletRequest object.
-     * @param response the HttpServletResponse object.
-     * @param requestMap a Map of request attributes.
-     * @param parameterMap a Map of request parameters.
-     * @param sessionMap a Map of all session attributes.
-     * @param applicationMap a Map of all application attributes.
+     * @param request          the HttpServletRequest object.
+     * @param response         the HttpServletResponse object.
+     * @param requestMap       a Map of request attributes.
+     * @param parameterMap     a Map of request parameters.
+     * @param sessionMap       a Map of all session attributes.
+     * @param applicationMap   a Map of all application attributes.
      * @param portletNamespace the namespace or context of the action.
-     * @param phase The portlet phase (render or action, see {@link PortletConstants})
-     *
+     * @param phase            The portlet phase (render or action, see {@link PortletConstants})
      * @throws PortletException in case of errors
      */
     public void serviceAction(PortletRequest request, PortletResponse response, Map<String, Object> requestMap, Map<String, String[]> parameterMap,
@@ -475,9 +466,9 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
             } else {
                 namespace = mapping.getNamespace();
             }
-            HashMap<String, Object> extraContext = createContextMap(requestMap, parameterMap,
-                    sessionMap, applicationMap, request, response, servletRequest, servletResponse,
-                    servletContext, getPortletConfig(), phase);
+            Map<String, Object> extraContext = createContextMap(requestMap, parameterMap,
+                sessionMap, applicationMap, request, response, servletRequest, servletResponse,
+                servletContext, getPortletConfig(), phase);
             extraContext.put(PortletConstants.ACTION_MAPPING, mapping);
             if (LOG.isDebugEnabled()) {
                 LOG.debug("Creating action proxy for name = " + actionName + ", namespace = " + namespace);
@@ -518,7 +509,6 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
      *
      * @param portletRequest the PortletRequest object.
      * @param servletRequest the ServletRequest to use
-     *
      * @return the namespace of the action.
      */
     protected ActionMapping getActionMapping(final PortletRequest portletRequest, final HttpServletRequest servletRequest) {
@@ -551,6 +541,7 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
 
     /**
      * Get the namespace part of the action path.
+     *
      * @param actionPath Full path to action
      * @return The namespace part.
      */
@@ -565,6 +556,7 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
 
     /**
      * Get the action name part of the action path.
+     *
      * @param actionPath Full path to action
      * @return The action name.
      */
@@ -584,7 +576,7 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
      * @param request the PortletRequest object.
      * @return a Map of all request parameters.
      * @throws IOException if an exception occurs while retrieving the parameter
-     *         map.
+     *                     map.
      */
     protected Map<String, String[]> getParameterMap(PortletRequest request) throws IOException {
         return new HashMap<String, String[]>(request.getParameterMap());
@@ -616,6 +608,7 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
 
     /**
      * Convenience method to ease testing.
+     *
      * @param factory action proxy factory
      */
     protected void setActionProxyFactory(ActionProxyFactory factory) {
@@ -627,6 +620,7 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
      * mode has been changed with the portal widgets, the action name is invalid, since the
      * action name belongs to the previous executing portlet mode. If this method evaluates to
      * <code>true</code> the <code>default&lt;Mode&gt;Action</code> is used instead.
+     *
      * @param request The portlet request.
      * @return <code>true</code> if the action should be reset.
      */
@@ -670,10 +664,9 @@ public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics {
      * Method to create a PortletServletResponse matching the used Portlet API, to be overridden for JSR286 Dispatcher.
      *
      * @param response The Response used for building the wrapper.
-     *
      * @return The wrapper response for Servlet bound usage.
      */
-    protected PortletServletResponse createPortletServletResponse( PortletResponse response ) {
+    protected PortletServletResponse createPortletServletResponse(PortletResponse response) {
         return new PortletServletResponse(response);
     }
 
diff --git a/plugins/portlet/src/test/java/org/apache/struts2/views/jsp/PortletUrlTagTest.java b/plugins/portlet/src/test/java/org/apache/struts2/views/jsp/PortletUrlTagTest.java
index a1e5598..9beef5d 100644
--- a/plugins/portlet/src/test/java/org/apache/struts2/views/jsp/PortletUrlTagTest.java
+++ b/plugins/portlet/src/test/java/org/apache/struts2/views/jsp/PortletUrlTagTest.java
@@ -144,14 +144,15 @@ public class PortletUrlTagTest extends MockObjectTestCase {
         actionMap.put(PortletMode.HELP, new ActionMapping("defaultHelp", "/help", "execute", new HashMap<>()));
         actionMap.put(PortletMode.EDIT, new ActionMapping("defaultEdit", "/edit", "execute", new HashMap<>()));
 
-        Map<String, Object> contextMap = stack.getContext();
-        contextMap.put(ActionContext.SESSION, new HashMap<String, Object>());
-        contextMap.put(PortletConstants.REQUEST, mockPortletReq.proxy());
-        contextMap.put(PortletConstants.RESPONSE, mockPortletRes.proxy());
-        contextMap.put(PortletConstants.PHASE, PortletPhase.RENDER_PHASE);
-        contextMap.put(PortletConstants.MODE_NAMESPACE_MAP, modeMap);
-        contextMap.put(PortletConstants.DEFAULT_ACTION_MAP, actionMap);
-        contextMap.put(STRUTS_PORTLET_CONTEXT, mockCtx.proxy());
+        Map<String, Object> contextMap = stack.getActionContext()
+            .withSession(new HashMap<>())
+            .with(PortletConstants.REQUEST, mockPortletReq.proxy())
+            .with(PortletConstants.RESPONSE, mockPortletRes.proxy())
+            .with(PortletConstants.PHASE, PortletPhase.RENDER_PHASE)
+            .with(PortletConstants.MODE_NAMESPACE_MAP, modeMap)
+            .with(PortletConstants.DEFAULT_ACTION_MAP, actionMap)
+            .with(STRUTS_PORTLET_CONTEXT, mockCtx.proxy())
+            .getContextMap();
 
         ActionInvocation ai = (ActionInvocation) mockActionInvocation.proxy();