WW-4789 WW-3788 Marks VALUE_STACK, APPLICATION and SESSION as deprecated on behalf using helper methods
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 @@
         }
         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.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 @@
 
     /**
      * 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 @@
         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 @@
         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 @@
     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 @@
         return end;
     }
 
-    protected Map createExtraContext() {
+    protected Map<String, Object> createExtraContext() {
         HttpParameters newParams = createParametersForContext();
 
         ActionContext ctx = stack.getActionContext();
@@ -184,7 +184,8 @@
         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 @@
                 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 @@
             }
         }
         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 @@
      * @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 @@
         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 @@
             }
         }
         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.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 @@
         return VALUE;
     }
 
-    @Override public void setUp() throws Exception {
+    @Override
+    public void setUp() throws Exception {
         super.setUp();
         loadConfigurationProviders(new NestedTestConfigurationProvider());
 
@@ -64,7 +66,8 @@
         context.getValueStack().push(this);
     }
 
-    @Override protected void tearDown() throws Exception {
+    @Override
+    protected void tearDown() throws Exception {
         super.tearDown();
     }
 
@@ -90,8 +93,9 @@
         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 @@
 
     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 @@
 
     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 @@
         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 @@
     }
 
     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 @@
     private class WaitConfigurationProvider implements ConfigurationProvider {
 
         Configuration configuration;
+
         public void destroy() {
             waitInterceptor.destroy();
         }
@@ -250,8 +261,8 @@
                     .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.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 @@
 
     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 @@
         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 @@
         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.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 @@
         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 @@
 

     /**

      * 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 @@
     /**

      * 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 @@
     /**

      * 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 @@
             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 @@
     }

 

     /**

-     *  Reset the action context.

+     * Reset the action context.

      */

     void resetActionContext() {

         ActionContext.clear();

@@ -355,59 +352,54 @@
      * 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 @@
                 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 @@
      * 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 @@
             } 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 @@
      *

      * @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 @@
 

     /**

      * Get the namespace part of the action path.

+     *

      * @param actionPath Full path to action

      * @return The namespace part.

      */

@@ -565,6 +556,7 @@
 

     /**

      * Get the action name part of the action path.

+     *

      * @param actionPath Full path to action

      * @return The action name.

      */

@@ -584,7 +576,7 @@
      * @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 @@
 

     /**

      * Convenience method to ease testing.

+     *

      * @param factory action proxy factory

      */

     protected void setActionProxyFactory(ActionProxyFactory factory) {

@@ -627,6 +620,7 @@
      * 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 @@
      * 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 @@
         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();