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/10 17:39:19 UTC

[struts] branch action-context-boost updated: WW-4789 WW-3788 Marks CONTAINER 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 c253b7f  WW-4789 WW-3788 Marks CONTAINER as deprecated on behalf using helper methods
c253b7f is described below

commit c253b7f480c85a554105e3711668a282cca64f93
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Fri Apr 10 19:39:10 2020 +0200

    WW-4789 WW-3788 Marks CONTAINER as deprecated on behalf using helper methods
---
 .../com/opensymphony/xwork2/ActionContext.java     | 19 +++++++-
 .../xwork2/DefaultActionInvocation.java            | 31 ++++++++------
 .../xwork2/ognl/OgnlValueStackFactory.java         | 50 ++++++++++++++++------
 .../opensymphony/xwork2/util/TextParseUtil.java    | 10 ++---
 .../xwork2/util/XWorkTestCaseHelper.java           | 15 ++-----
 .../struts2/components/ServletUrlRenderer.java     |  3 +-
 .../apache/struts2/util/StrutsTestCaseHelper.java  |  5 +--
 .../java/org/apache/struts2/util/StrutsUtil.java   |  6 +--
 .../struts2/views/freemarker/tags/TagModel.java    |  2 +-
 .../struts2/views/jsp/ComponentTagSupport.java     |  2 +-
 .../org/apache/struts2/views/util/ContextUtil.java | 13 +++---
 .../validator/validators/ValidatorSupportTest.java |  3 +-
 .../struts2/result/ServletRedirectResultTest.java  |  7 ++-
 .../org/apache/struts2/views/jsp/TextTagTest.java  | 37 ++++++++--------
 .../apache/struts2/views/jsp/ui/DebugTagTest.java  |  2 +-
 .../apache/struts2/views/util/ContextUtilTest.java |  2 +-
 .../struts2/views/util/DefaultUrlHelperTest.java   |  2 +-
 .../org/apache/struts2/EmbeddedJSPResultTest.java  |  4 +-
 .../struts2/views/java/simple/AbstractTest.java    |  8 ++--
 .../struts2/components/PortletUrlRenderer.java     |  2 +-
 .../struts2/components/PortletUrlRendererTest.java |  2 +-
 .../velocity/components/AbstractDirective.java     |  2 +-
 22 files changed, 128 insertions(+), 99 deletions(-)

diff --git a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java
index fbc15b9..3c9d0e5 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ActionContext.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ActionContext.java
@@ -63,7 +63,7 @@ public class ActionContext implements Serializable {
     /**
      * Constant for the name of the action being executed.
      *
-     * @deprecated use helper methods instead
+     * @deprecated scope will be narrowed to "private", use helper methods instead
      */
     @Deprecated
     public static final String ACTION_NAME = "com.opensymphony.xwork2.ActionContext.name";
@@ -95,19 +95,23 @@ public class ActionContext implements Serializable {
 
     /**
      * Constant for the action's {@link com.opensymphony.xwork2.ActionInvocation invocation} context.
+     * @deprecated scope will be narrowed to "private", use helper methods instead
      */
+    @Deprecated
     public static final String ACTION_INVOCATION = "com.opensymphony.xwork2.ActionContext.actionInvocation";
 
     /**
      * Constant for the map of type conversion errors.
-     * @deprecated use helper method instead
+     * @deprecated scope will be narrowed to "private", use helper methods instead
      */
     @Deprecated
     public static final String CONVERSION_ERRORS = "com.opensymphony.xwork2.ActionContext.conversionErrors";
 
     /**
      * Constant for the container
+     * @deprecated scope will be narrowed to "private", use helper methods instead
      */
+    @Deprecated
     public static final String CONTAINER = "com.opensymphony.xwork2.ActionContext.container";
 
     private final Map<String, Object> context;
@@ -518,4 +522,15 @@ public class ActionContext implements Serializable {
         return this;
     }
 
+    public ActionContext withExtraContext(Map<String, Object> extraContext) {
+        if (extraContext != null) {
+            getContext().context.putAll(extraContext);
+        }
+        return this;
+    }
+
+    public ActionContext withLocale(Locale locale) {
+        put(LOCALE, locale);
+        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 215d568..acf7a65 100644
--- a/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java
+++ b/core/src/main/java/com/opensymphony/xwork2/DefaultActionInvocation.java
@@ -324,9 +324,10 @@ public class DefaultActionInvocation implements ActionInvocation {
     }
 
     protected Map<String, Object> createContextMap() {
-        Map<String, Object> contextMap;
+        ActionContext oldContext = ActionContext.getContext();
+        ActionContext actionContext;
 
-        if ((extraContext != null) && (extraContext.containsKey(ActionContext.VALUE_STACK))) {
+        if (extraContext != null && extraContext.containsKey(ActionContext.VALUE_STACK)) {
             // In case the ValueStack was passed in
             stack = (ValueStack) extraContext.get(ActionContext.VALUE_STACK);
 
@@ -334,26 +335,30 @@ public class DefaultActionInvocation implements ActionInvocation {
                 throw new IllegalStateException("There was a null Stack set into the extra params.");
             }
 
-            contextMap = stack.getContext();
+            actionContext = stack.getActionContext();
         } else {
             // create the value stack
             // this also adds the ValueStack to its context
             stack = valueStackFactory.createValueStack();
 
             // create the action context
-            contextMap = stack.getContext();
+            actionContext = stack.getActionContext();
         }
 
-        // put extraContext in
-        if (extraContext != null) {
-            contextMap.putAll(extraContext);
+        try {
+            return actionContext
+                .bind()
+                .withExtraContext(extraContext)
+                .withActionInvocation(this)
+                .withContainer(container)
+                .getContextMap();
+        } finally {
+            ActionContext.clear();
+            if (oldContext != null) {
+                LOG.debug("Re-binding the old context");
+                oldContext.bind();
+            }
         }
-
-        //put this DefaultActionInvocation into the context map
-        contextMap.put(ActionContext.ACTION_INVOCATION, this);
-        contextMap.put(ActionContext.CONTAINER, container);
-
-        return contextMap;
     }
 
     /**
diff --git a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlValueStackFactory.java b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlValueStackFactory.java
index bf4e571..d19fd6b 100644
--- a/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlValueStackFactory.java
+++ b/core/src/main/java/com/opensymphony/xwork2/ognl/OgnlValueStackFactory.java
@@ -34,17 +34,17 @@ import ognl.PropertyAccessor;
 import org.apache.commons.lang3.BooleanUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.apache.struts2.StrutsConstants;
 
 import java.util.Map;
 import java.util.Set;
-import org.apache.struts2.StrutsConstants;
 
 /**
  * Creates an Ognl value stack
  */
 public class OgnlValueStackFactory implements ValueStackFactory {
-    
-	private static final Logger LOG = LogManager.getLogger(OgnlValueStackFactory.class);
+
+    private static final Logger LOG = LogManager.getLogger(OgnlValueStackFactory.class);
 
     protected XWorkConverter xworkConverter;
     protected CompoundRootAccessor compoundRootAccessor;
@@ -55,7 +55,7 @@ public class OgnlValueStackFactory implements ValueStackFactory {
     protected void setXWorkConverter(XWorkConverter converter) {
         this.xworkConverter = converter;
     }
-    
+
     @Inject("system")
     protected void setTextProvider(TextProvider textProvider) {
         this.textProvider = textProvider;
@@ -63,20 +63,44 @@ public class OgnlValueStackFactory implements ValueStackFactory {
 
     public ValueStack createValueStack() {
         ValueStack stack = new OgnlValueStack(xworkConverter, compoundRootAccessor, textProvider,
-                containerAllowsStaticMethodAccess(), containerAllowsStaticFieldAccess());
+            containerAllowsStaticMethodAccess(), containerAllowsStaticFieldAccess());
         container.inject(stack);
-        stack.getContext().put(ActionContext.CONTAINER, container);
-        return stack;
+        ActionContext oldContext = ActionContext.getContext();
+        try {
+            return stack.getActionContext()
+                .bind()
+                .withContainer(container)
+                .withValueStack(stack)
+                .getValueStack();
+        } finally {
+            ActionContext.clear();
+            if (oldContext != null) {
+                LOG.debug("Re-binding the old context");
+                oldContext.bind();
+            }
+        }
     }
 
     public ValueStack createValueStack(ValueStack stack) {
         ValueStack result = new OgnlValueStack(stack, xworkConverter, compoundRootAccessor,
-                containerAllowsStaticMethodAccess(), containerAllowsStaticFieldAccess());
+            containerAllowsStaticMethodAccess(), containerAllowsStaticFieldAccess());
         container.inject(result);
-        stack.getContext().put(ActionContext.CONTAINER, container);
-        return result;
+        ActionContext oldContext = ActionContext.getContext();
+        try {
+            return result.getActionContext()
+                .bind()
+                .withContainer(container)
+                .withValueStack(result)
+                .getValueStack();
+        } finally {
+            ActionContext.clear();
+            if (oldContext != null) {
+                LOG.debug("Re-binding the old context");
+                oldContext.bind();
+            }
+        }
     }
-    
+
     @Inject
     protected void setContainer(Container container) throws ClassNotFoundException {
         Set<String> names = container.getInstanceNames(PropertyAccessor.class);
@@ -116,7 +140,7 @@ public class OgnlValueStackFactory implements ValueStackFactory {
 
     /**
      * Retrieve allowsStaticMethodAccess state from the container (allows for lazy fetching)
-     * 
+     *
      * @return
      */
     protected boolean containerAllowsStaticMethodAccess() {
@@ -125,7 +149,7 @@ public class OgnlValueStackFactory implements ValueStackFactory {
 
     /**
      * Retrieve allowStaticFieldAccess state from the container (allows for lazy fetching)
-     * 
+     *
      * @return
      */
     protected boolean containerAllowsStaticFieldAccess() {
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/TextParseUtil.java b/core/src/main/java/com/opensymphony/xwork2/util/TextParseUtil.java
index f22a255..c054856 100644
--- a/core/src/main/java/com/opensymphony/xwork2/util/TextParseUtil.java
+++ b/core/src/main/java/com/opensymphony/xwork2/util/TextParseUtil.java
@@ -164,7 +164,7 @@ public class TextParseUtil {
             }
         };
 
-        TextParser parser = ((Container)stack.getContext().get(ActionContext.CONTAINER)).getInstance(TextParser.class);
+        TextParser parser = stack.getActionContext().getContainer().getInstance(TextParser.class);
 
         return parser.evaluate(openChars, expression, ognlEval, maxLoopCount);
     }
@@ -205,8 +205,8 @@ public class TextParseUtil {
             }
         };
 
-        Map<String, Object> context = stack.getContext();
-        TextParser parser = ((Container)context.get(ActionContext.CONTAINER)).getInstance(TextParser.class);
+        ActionContext actionContext = stack.getActionContext();
+        TextParser parser = actionContext.getContainer().getInstance(TextParser.class);
 
         Object result = parser.evaluate(openChars, expression, ognlEval, maxLoopCount);
 
@@ -216,10 +216,10 @@ public class TextParseUtil {
             Collection<Object> casted = (Collection<Object>)result;
             resultCol = new ArrayList<>();
 
-            XWorkConverter conv = ((Container)context.get(ActionContext.CONTAINER)).getInstance(XWorkConverter.class);
+            XWorkConverter conv = actionContext.getContainer().getInstance(XWorkConverter.class);
 
             for (Object element : casted) {
-                String stringElement = (String)conv.convertValue(context, element, String.class);
+                String stringElement = (String) conv.convertValue(actionContext.getContextMap(), element, String.class);
                 if (shallBeIncluded(stringElement, excludeEmptyElements)) {
                     if (evaluator != null) {
                         stringElement = evaluator.evaluate(stringElement).toString();
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/XWorkTestCaseHelper.java b/core/src/main/java/com/opensymphony/xwork2/util/XWorkTestCaseHelper.java
index 6bef3af..bde73ca 100644
--- a/core/src/main/java/com/opensymphony/xwork2/util/XWorkTestCaseHelper.java
+++ b/core/src/main/java/com/opensymphony/xwork2/util/XWorkTestCaseHelper.java
@@ -39,14 +39,8 @@ public class XWorkTestCaseHelper {
         
         // Reset the value stack
         ValueStack stack = container.getInstance(ValueStackFactory.class).createValueStack();
-        stack.getContext().put(ActionContext.CONTAINER, container);
-        ActionContext.of(stack.getContext()).bind();
-    
-        // clear out localization
-        //container.getInstance(LocalizedTextUtil.class).reset();
-        
-    
-        //ObjectFactory.setObjectFactory(container.getInstance(ObjectFactory.class));
+        stack.getActionContext().withContainer(container).withValueStack(stack).bind();
+
         return configurationManager;
     }
 
@@ -79,9 +73,8 @@ public class XWorkTestCaseHelper {
         
         // Reset the value stack
         ValueStack stack = container.getInstance(ValueStackFactory.class).createValueStack();
-        stack.getContext().put(ActionContext.CONTAINER, container);
-        ActionContext.of(stack.getContext()).bind();
-        
+        stack.getActionContext().withContainer(container).withValueStack(stack).bind();
+
         return configurationManager;
     }
 
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 550fa35..b8b7a3c 100644
--- a/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java
+++ b/core/src/main/java/org/apache/struts2/components/ServletUrlRenderer.java
@@ -137,8 +137,7 @@ public class ServletUrlRenderer implements UrlRenderer {
         } else {
             // no action supplied? ok, then default to the current request
             // (action or general URL)
-            ActionInvocation ai = (ActionInvocation) formComponent.getStack().getContext().get(
-                    ActionContext.ACTION_INVOCATION);
+            ActionInvocation ai = formComponent.getStack().getActionContext().getActionInvocation();
             if (ai != null) {
                 action = ai.getProxy().getActionName();
                 namespace = ai.getProxy().getNamespace();
diff --git a/core/src/main/java/org/apache/struts2/util/StrutsTestCaseHelper.java b/core/src/main/java/org/apache/struts2/util/StrutsTestCaseHelper.java
index e87ec6e..42e107f 100644
--- a/core/src/main/java/org/apache/struts2/util/StrutsTestCaseHelper.java
+++ b/core/src/main/java/org/apache/struts2/util/StrutsTestCaseHelper.java
@@ -47,9 +47,8 @@ public class StrutsTestCaseHelper {
         // Reset the value stack
         Container container = du.getContainer();
         ValueStack stack = container.getInstance(ValueStackFactory.class).createValueStack();
-        stack.getContext().put(ActionContext.CONTAINER, container);
-        ActionContext.of(stack.getContext()).bind();
-        
+        stack.getActionContext().withContainer(container).withValueStack(stack).bind();
+
         return du;
     }
 
diff --git a/core/src/main/java/org/apache/struts2/util/StrutsUtil.java b/core/src/main/java/org/apache/struts2/util/StrutsUtil.java
index 647a743..2d95314 100644
--- a/core/src/main/java/org/apache/struts2/util/StrutsUtil.java
+++ b/core/src/main/java/org/apache/struts2/util/StrutsUtil.java
@@ -61,9 +61,9 @@ public class StrutsUtil {
         this.stack = stack;
         this.request = request;
         this.response = response;
-        this.ognl = ((Container)stack.getContext().get(ActionContext.CONTAINER)).getInstance(OgnlTool.class);
-        this.urlHelper = ((Container)stack.getContext().get(ActionContext.CONTAINER)).getInstance(UrlHelper.class);
-        this.objectFactory = ((Container)stack.getContext().get(ActionContext.CONTAINER)).getInstance(ObjectFactory.class);
+        this.ognl = stack.getActionContext().getContainer().getInstance(OgnlTool.class);
+        this.urlHelper = stack.getActionContext().getContainer().getInstance(UrlHelper.class);
+        this.objectFactory = stack.getActionContext().getContainer().getInstance(ObjectFactory.class);
     }
 
     public Object bean(Object aName) throws Exception {
diff --git a/core/src/main/java/org/apache/struts2/views/freemarker/tags/TagModel.java b/core/src/main/java/org/apache/struts2/views/freemarker/tags/TagModel.java
index 5d307a2..1124574 100644
--- a/core/src/main/java/org/apache/struts2/views/freemarker/tags/TagModel.java
+++ b/core/src/main/java/org/apache/struts2/views/freemarker/tags/TagModel.java
@@ -55,7 +55,7 @@ public abstract class TagModel implements TemplateTransformModel {
     public Writer getWriter(Writer writer, Map params)
         throws TemplateModelException, IOException {
         Component bean = getBean();
-        Container container = (Container) stack.getContext().get(ActionContext.CONTAINER);
+        Container container = stack.getActionContext().getContainer();
         container.inject(bean);
 
         Map unwrappedParameters = unwrapParameters(params);
diff --git a/core/src/main/java/org/apache/struts2/views/jsp/ComponentTagSupport.java b/core/src/main/java/org/apache/struts2/views/jsp/ComponentTagSupport.java
index f39d581..9dd463c 100644
--- a/core/src/main/java/org/apache/struts2/views/jsp/ComponentTagSupport.java
+++ b/core/src/main/java/org/apache/struts2/views/jsp/ComponentTagSupport.java
@@ -44,7 +44,7 @@ public abstract class ComponentTagSupport extends StrutsBodyTagSupport {
     public int doStartTag() throws JspException {
         ValueStack stack = getStack();
         component = getBean(stack, (HttpServletRequest) pageContext.getRequest(), (HttpServletResponse) pageContext.getResponse());
-        Container container = (Container) stack.getContext().get(ActionContext.CONTAINER);
+        Container container = stack.getActionContext().getContainer();
         container.inject(component);
         
         populateParams();
diff --git a/core/src/main/java/org/apache/struts2/views/util/ContextUtil.java b/core/src/main/java/org/apache/struts2/views/util/ContextUtil.java
index 8d493f6..d213f5a 100644
--- a/core/src/main/java/org/apache/struts2/views/util/ContextUtil.java
+++ b/core/src/main/java/org/apache/struts2/views/util/ContextUtil.java
@@ -56,10 +56,10 @@ public class ContextUtil {
         map.put(SESSION, req.getSession(false));
         map.put(BASE, req.getContextPath());
         map.put(STACK, stack);
-        map.put(OGNL, ((Container)stack.getContext().get(ActionContext.CONTAINER)).getInstance(OgnlTool.class));
+        map.put(OGNL, stack.getActionContext().getContainer().getInstance(OgnlTool.class));
         map.put(STRUTS, new StrutsUtil(stack, req, res));
 
-        ActionInvocation invocation = (ActionInvocation) stack.getContext().get(ActionContext.ACTION_INVOCATION);
+        ActionInvocation invocation = stack.getActionContext().getActionInvocation();
         if (invocation != null) {
             map.put(ACTION, invocation.getAction());
         }
@@ -71,22 +71,23 @@ public class ContextUtil {
      * @param context stack's context
      * @return boolean
      */
-    public static boolean isUseAltSyntax(Map context) {
+    public static boolean isUseAltSyntax(Map<String, Object> context) {
         // We didn't make altSyntax static cause, if so, struts.configuration.xml.reload will not work
         // plus the Configuration implementation should cache the properties, which the framework's
         // configuration implementation does
-        return "true".equals(((Container)context.get(ActionContext.CONTAINER)).getInstance(String.class, StrutsConstants.STRUTS_TAG_ALTSYNTAX)) ||(
+        String tagAltSytnax = ActionContext.of(context).getContainer().getInstance(String.class, StrutsConstants.STRUTS_TAG_ALTSYNTAX);
+        return "true".equals(tagAltSytnax) ||(
                 (context.containsKey("useAltSyntax") &&
                         context.get("useAltSyntax") != null &&
                         "true".equals(context.get("useAltSyntax").toString())));
     }
-    
+
     /**
      * Returns a String for overriding the default templateSuffix if templateSuffix is on the stack
      * @param context stack's context
      * @return String
      */
-    public static String getTemplateSuffix(Map context) {
+    public static String getTemplateSuffix(Map<String, Object> context) {
         return context.containsKey("templateSuffix") ? (String) context.get("templateSuffix") : null;
     }
 }
diff --git a/core/src/test/java/com/opensymphony/xwork2/validator/validators/ValidatorSupportTest.java b/core/src/test/java/com/opensymphony/xwork2/validator/validators/ValidatorSupportTest.java
index b9b805c..c1b7f18 100644
--- a/core/src/test/java/com/opensymphony/xwork2/validator/validators/ValidatorSupportTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/validator/validators/ValidatorSupportTest.java
@@ -28,10 +28,9 @@ public class ValidatorSupportTest extends XWorkTestCase {
 
     public void testConditionalParseExpression() {
         OgnlValueStack stack = (OgnlValueStack) container.getInstance(ValueStackFactory.class).createValueStack();
-        stack.getContext().put(ActionContext.CONTAINER, container);
         stack.getContext().put("something", "somevalue");
 
-        ActionContext.of(stack.getContext()).bind();
+        ActionContext.of(stack.getContext()).withContainer(container).bind();
 
         ValidatorSupport validator = new ValidatorSupport() {
             public void validate(Object object) throws ValidationException {
diff --git a/core/src/test/java/org/apache/struts2/result/ServletRedirectResultTest.java b/core/src/test/java/org/apache/struts2/result/ServletRedirectResultTest.java
index a1c046a..c6be2ab 100644
--- a/core/src/test/java/org/apache/struts2/result/ServletRedirectResultTest.java
+++ b/core/src/test/java/org/apache/struts2/result/ServletRedirectResultTest.java
@@ -293,11 +293,10 @@ public class ServletRedirectResultTest extends StrutsInternalTestCase implements
         ActionInvocation mockInvocation = control.createMock(ActionInvocation.class);
 
         ValueStack mockValueStack = control.createMock(ValueStack.class);
-        Map<String, Object> mockContext = new HashMap<>();
-        mockContext.put(ActionContext.CONTAINER, container);
+        ActionContext actionContext = ActionContext.of(new HashMap<>()).withContainer(container);
 
         expect(mockInvocation.getStack()).andReturn(mockValueStack);
-        expect(mockValueStack.getContext()).andReturn(mockContext);
+        expect(mockValueStack.getActionContext()).andReturn(actionContext);
 
         expect(mockInvocation.getStack()).andReturn(mockValueStack);
 
@@ -308,7 +307,7 @@ public class ServletRedirectResultTest extends StrutsInternalTestCase implements
         expect(mockActionProxy.getConfig()).andReturn(actionConfig);
         expect(mockInvocation.getInvocationContext()).andReturn(context);
 
-        expect(mockValueStack.getContext()).andReturn(mockContext);
+        expect(mockValueStack.getActionContext()).andReturn(actionContext);
 
         control.replay();
         result.setActionMapper(container.getInstance(ActionMapper.class));
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/TextTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/TextTagTest.java
index e0a1201..684d262 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/TextTagTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/TextTagTest.java
@@ -18,15 +18,11 @@
  */
 package org.apache.struts2.views.jsp;
 
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-
-import javax.servlet.jsp.JspException;
-import javax.servlet.jsp.tagext.BodyTag;
-
+import com.mockobjects.servlet.MockJspWriter;
+import com.opensymphony.xwork2.Action;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.ValueStackFactory;
 import org.apache.struts2.ServletActionContext;
 import org.apache.struts2.StrutsException;
 import org.apache.struts2.TestAction;
@@ -34,16 +30,19 @@ import org.apache.struts2.components.Text;
 import org.apache.struts2.views.jsp.ui.StrutsBodyContent;
 import org.apache.struts2.views.jsp.ui.TestAction1;
 
-import com.mockobjects.servlet.MockJspWriter;
-import com.opensymphony.xwork2.Action;
-import com.opensymphony.xwork2.ActionContext;
-import com.opensymphony.xwork2.util.ValueStack;
-import com.opensymphony.xwork2.util.ValueStackFactory;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.BodyTag;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import static org.junit.Assert.assertNotEquals;
 
 
 /**
  * TextTagTest
- *
  */
 public class TextTagTest extends AbstractTagTest {
 
@@ -173,8 +172,7 @@ public class TextTagTest extends AbstractTagTest {
         final StringBuffer buffer = writer.getBuffer();
         buffer.delete(0, buffer.length());
         ValueStack newStack = container.getInstance(ValueStackFactory.class).createValueStack();
-        newStack.getContext().put(ActionContext.LOCALE, foreignLocale);
-        newStack.getContext().put(ActionContext.CONTAINER, container);
+        newStack.getActionContext().withLocale(foreignLocale).withContainer(container);
         newStack.push(container.inject(TestAction1.class));
         request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, newStack);
         assertNotSame(ActionContext.getContext().getValueStack().peek(), newStack.peek());
@@ -203,10 +201,9 @@ public class TextTagTest extends AbstractTagTest {
         final StringBuffer buffer = writer.getBuffer();
         buffer.delete(0, buffer.length());
         String value_int = getLocalizedMessage(foreignLocale);
-        assertFalse(value_default.equals(value_int));
+        assertNotEquals(value_default, value_int);
         ValueStack newStack = container.getInstance(ValueStackFactory.class).createValueStack(stack);
-        newStack.getContext().put(ActionContext.LOCALE, foreignLocale);
-        newStack.getContext().put(ActionContext.CONTAINER, container);
+        newStack.getActionContext().withLocale(foreignLocale).withContainer(container);
         assertNotSame(newStack.getContext().get(ActionContext.LOCALE), ActionContext.getContext().getLocale());
         request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, newStack);
         assertEquals(ActionContext.getContext().getValueStack().peek(), newStack.peek());
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java
index 0a4e50d..bbee23b 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java
@@ -110,6 +110,6 @@ public class DebugTagTest extends AbstractUITagTest {
 
         configurationManager.reload();
         container = configurationManager.getConfiguration().getContainer();
-        stack.getContext().put(ActionContext.CONTAINER, container);
+        stack.getActionContext().withContainer(container);
     }
 }
\ No newline at end of file
diff --git a/core/src/test/java/org/apache/struts2/views/util/ContextUtilTest.java b/core/src/test/java/org/apache/struts2/views/util/ContextUtilTest.java
index 3da2447..9a79cb8 100755
--- a/core/src/test/java/org/apache/struts2/views/util/ContextUtilTest.java
+++ b/core/src/test/java/org/apache/struts2/views/util/ContextUtilTest.java
@@ -36,7 +36,7 @@ public class ContextUtilTest extends StrutsInternalTestCase {
     private void setAltSyntax(ValueStack stack, String val) {
         Mock container = new Mock(Container.class);
         container.expectAndReturn("getInstance", C.args(C.eq(String.class), C.eq(StrutsConstants.STRUTS_TAG_ALTSYNTAX)), val);
-        stack.getContext().put(ActionContext.CONTAINER, container.proxy());
+        stack.getActionContext().withContainer((Container) container.proxy());
     }
     
     public void testAltSyntaxMethod1() throws Exception {
diff --git a/core/src/test/java/org/apache/struts2/views/util/DefaultUrlHelperTest.java b/core/src/test/java/org/apache/struts2/views/util/DefaultUrlHelperTest.java
index 1532e9b..9266e49 100644
--- a/core/src/test/java/org/apache/struts2/views/util/DefaultUrlHelperTest.java
+++ b/core/src/test/java/org/apache/struts2/views/util/DefaultUrlHelperTest.java
@@ -427,7 +427,7 @@ public class DefaultUrlHelperTest extends StrutsInternalTestCase {
     public void setUp() throws Exception {
         super.setUp();
         stubContainer = new StubContainer(container);
-        ActionContext.getContext().put(ActionContext.CONTAINER, stubContainer);
+        ActionContext.getContext().withContainer(stubContainer);
         urlHelper = new DefaultUrlHelper();
     }
     
diff --git a/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java b/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java
index ceaa8df..a5b3bb2 100644
--- a/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java
+++ b/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java
@@ -330,9 +330,8 @@ public class EmbeddedJSPResultTest extends TestCase {
         EasyMock.replay(request);
 
         //mock value stack
-        Map<String, Object> stackContext = new HashMap<>();
         ValueStack valueStack = EasyMock.createNiceMock(ValueStack.class);
-        EasyMock.expect(valueStack.getContext()).andReturn(stackContext).anyTimes();
+        EasyMock.expect(valueStack.getActionContext()).andReturn(ActionContext.getContext()).anyTimes();
         EasyMock.replay(valueStack);
 
         //mock converter
@@ -355,7 +354,6 @@ public class EmbeddedJSPResultTest extends TestCase {
         EasyMock.expect(container.getInstance(FileManagerFactory.class)).andReturn(fileManagerFactory).anyTimes();
 
         EasyMock.replay(container);
-        stackContext.put(ActionContext.CONTAINER, container);
 
         ActionContext.of(new HashMap<>())
             .withParameters(HttpParameters.create(params).build())
diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java
index aa14c67..00f17fc 100644
--- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java
+++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java
@@ -21,6 +21,7 @@
 
 package org.apache.struts2.views.java.simple;
 
+import com.opensymphony.xwork2.Action;
 import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
 import com.opensymphony.xwork2.inject.Container;
@@ -101,11 +102,13 @@ public abstract class AbstractTest extends TestCase {
 
         context = new TemplateRenderingContext(template, writer, stack, map, null);
         stackContext.put(Component.COMPONENT_STACK, new Stack());
+        ActionContext actionContext = ActionContext.of(stackContext).bind();
 
         request = createNiceMock(HttpServletRequest.class);
         expect(request.getContextPath()).andReturn("/some/path").anyTimes();
         response = createNiceMock(HttpServletResponse.class);
 
+        expect(stack.getActionContext()).andReturn(actionContext).anyTimes();
         expect(stack.getContext()).andReturn(stackContext).anyTimes();
 
         Container container = createNiceMock(Container.class);
@@ -114,15 +117,12 @@ public abstract class AbstractTest extends TestCase {
         expect(container.getInstance(XWorkConverter.class)).andReturn(converter).anyTimes();
         TextParser parser = new OgnlTextParser();
         expect(container.getInstance(TextParser.class)).andReturn(parser).anyTimes();
-        stackContext.put(ActionContext.CONTAINER, container);
-
 
         replay(request);
         replay(stack);
         replay(container);
 
-        ActionContext actionContext = ActionContext.of(stackContext).bind();
-        actionContext.withServletRequest(request);
+        actionContext.withContainer(container).withServletRequest(request);
     }
 
     protected static String s(String input) {
diff --git a/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java b/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java
index 9277d67..4b51f7e 100644
--- a/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java
+++ b/plugins/portlet/src/main/java/org/apache/struts2/components/PortletUrlRenderer.java
@@ -165,7 +165,7 @@ public class PortletUrlRenderer implements UrlRenderer {
         if (formComponent.action != null) {
             action = formComponent.findString(formComponent.action);
         } else {
-            ActionInvocation ai = (ActionInvocation) formComponent.getStack().getContext().get(ActionContext.ACTION_INVOCATION);
+            ActionInvocation ai = formComponent.getStack().getActionContext().getActionInvocation();
             action = ai.getProxy().getActionName();
         }
 
diff --git a/plugins/portlet/src/test/java/org/apache/struts2/components/PortletUrlRendererTest.java b/plugins/portlet/src/test/java/org/apache/struts2/components/PortletUrlRendererTest.java
index fbc87db..afc2c5c 100644
--- a/plugins/portlet/src/test/java/org/apache/struts2/components/PortletUrlRendererTest.java
+++ b/plugins/portlet/src/test/java/org/apache/struts2/components/PortletUrlRendererTest.java
@@ -43,7 +43,7 @@ public class PortletUrlRendererTest extends StrutsTestCasePortletTests {
         super.setUp();
 
         ActionProxy actionProxy = getActionProxy("/portlettest/test"); // creates new empty ActionContext
-        ActionContext.getContext().put(ActionContext.ACTION_INVOCATION, actionProxy.getInvocation());
+        ActionContext.getContext().withActionInvocation(actionProxy.getInvocation());
 
         PortletContext portletCtx = new MockPortletContext();
         ActionContext.getContext().put(StrutsStatics.STRUTS_PORTLET_CONTEXT, portletCtx);
diff --git a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/components/AbstractDirective.java b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/components/AbstractDirective.java
index 99f0059..e955b32 100644
--- a/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/components/AbstractDirective.java
+++ b/plugins/velocity/src/main/java/org/apache/struts2/views/velocity/components/AbstractDirective.java
@@ -62,7 +62,7 @@ public abstract class AbstractDirective extends Directive {
         HttpServletRequest req = (HttpServletRequest) stack.getContext().get(ServletActionContext.HTTP_REQUEST);
         HttpServletResponse res = (HttpServletResponse) stack.getContext().get(ServletActionContext.HTTP_RESPONSE);
         Component bean = getBean(stack, req, res);
-        Container container = (Container) stack.getContext().get(ActionContext.CONTAINER);
+        Container container = stack.getActionContext().getContainer();
         container.inject(bean);
         // get the parameters
         Map params = createPropertyMap(ctx, node);