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/22 05:59:32 UTC

[struts] branch WW-5065-append-or-not created (now 6a01767)

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

lukaszlenart pushed a change to branch WW-5065-append-or-not
in repository https://gitbox.apache.org/repos/asf/struts.git.


      at 6a01767  WW-5065 Defines a new flag to control appending params

This branch includes the following new commits:

     new 6a01767  WW-5065 Defines a new flag to control appending params

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[struts] 01/01: WW-5065 Defines a new flag to control appending params

Posted by lu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-5065-append-or-not
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 6a01767dbff98b2570a5ce3fd26293d61106ee2a
Author: Lukasz Lenart <lu...@apache.org>
AuthorDate: Wed Apr 22 07:59:13 2020 +0200

    WW-5065 Defines a new flag to control appending params
---
 .../xwork2/config/impl/AbstractMatcher.java        | 35 ++++++++++++--
 .../xwork2/config/impl/ActionConfigMatcher.java    | 28 ++++++++++-
 .../xwork2/config/impl/DefaultConfiguration.java   | 15 ++++--
 .../xwork2/config/impl/NamespaceMatcher.java       | 20 ++++++--
 .../providers/XWorkConfigurationProvider.java      |  2 +
 .../java/org/apache/struts2/StrutsConstants.java   |  3 ++
 .../config/impl/ActionConfigMatcherTest.java       | 55 ++++++++++++++++------
 7 files changed, 132 insertions(+), 26 deletions(-)

diff --git a/core/src/main/java/com/opensymphony/xwork2/config/impl/AbstractMatcher.java b/core/src/main/java/com/opensymphony/xwork2/config/impl/AbstractMatcher.java
index eee29ec..f3b84a9 100644
--- a/core/src/main/java/com/opensymphony/xwork2/config/impl/AbstractMatcher.java
+++ b/core/src/main/java/com/opensymphony/xwork2/config/impl/AbstractMatcher.java
@@ -36,6 +36,9 @@ import java.util.*;
  * @since 2.1
  */
 public abstract class AbstractMatcher<E> implements Serializable {
+
+    private static final Logger LOG = LogManager.getLogger(AbstractMatcher.class);
+
     /**
      * <p> The logging instance </p>
      */
@@ -50,10 +53,23 @@ public abstract class AbstractMatcher<E> implements Serializable {
      * <p> The compiled patterns and their associated target objects </p>
      */
     List<Mapping<E>> compiledPatterns = new ArrayList<>();
-    ;
+
+    /**
+     * This flag controls if passed named params should be appended
+     * to the map in {@link #replaceParameters(Map, Map)}
+     * and will be accessible in {@link com.opensymphony.xwork2.config.entities.ResultConfig}.
+     * If set to false, the names parameters won't be appended.
+     *
+     * This behaviour is controlled by {@link org.apache.struts2.StrutsConstants#STRUTS_MATCHER_APPEND_NAMED_PARAMETERS}
+     *
+     * @since 2.5.23
+     * See WW-5065
+     */
+    private final boolean appendNamedParameters;
     
-    public AbstractMatcher(PatternMatcher<?> helper) {
+    public AbstractMatcher(PatternMatcher<?> helper, boolean appendNamedParameters) {
         this.wildcard = (PatternMatcher<Object>) helper;
+        this.appendNamedParameters = appendNamedParameters;
     }
 
     /**
@@ -152,12 +168,23 @@ public abstract class AbstractMatcher<E> implements Serializable {
      */
     protected Map<String,String> replaceParameters(Map<String, String> orig, Map<String,String> vars) {
         Map<String, String> map = new LinkedHashMap<>();
-        
+
         //this will set the group index references, like {1}
         for (Map.Entry<String,String> entry : orig.entrySet()) {
             map.put(entry.getKey(), convertParam(entry.getValue(), vars));
         }
-        
+
+        if (appendNamedParameters) {
+            LOG.debug("Appending named parameters to result the map");
+            //the values map will contain entries like name->"Lex Luthor" and 1->"Lex Luthor"
+            //now add the non-numeric values
+            for (Map.Entry<String,String> entry: vars.entrySet()) {
+                if (!NumberUtils.isCreatable(entry.getKey())) {
+                    map.put(entry.getKey(), entry.getValue());
+                }
+            }
+        }
+
         return map;
     }
 
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/impl/ActionConfigMatcher.java b/core/src/main/java/com/opensymphony/xwork2/config/impl/ActionConfigMatcher.java
index b94fff6..344339e 100644
--- a/core/src/main/java/com/opensymphony/xwork2/config/impl/ActionConfigMatcher.java
+++ b/core/src/main/java/com/opensymphony/xwork2/config/impl/ActionConfigMatcher.java
@@ -58,7 +58,33 @@ public class ActionConfigMatcher extends AbstractMatcher<ActionConfig> implement
     public ActionConfigMatcher(PatternMatcher<?> patternMatcher,
             Map<String, ActionConfig> configs,
             boolean looseMatch) {
-        super(patternMatcher);
+        this(patternMatcher, configs, looseMatch, true);
+    }
+
+    /**
+     * <p> Finds and precompiles the wildcard patterns from the ActionConfig
+     * "path" attributes. ActionConfig's will be evaluated in the order they
+     * exist in the config file. Only paths that actually contain a
+     * wildcard will be compiled. </p>
+     *
+     * <p>Patterns can optionally be matched "loosely".  When
+     * the end of the pattern matches \*[^*]\*$ (wildcard, no wildcard,
+     * wildcard), if the pattern fails, it is also matched as if the
+     * last two characters didn't exist.  The goal is to support the
+     * legacy "*!*" syntax, where the "!*" is optional.</p>
+     *
+     * @param patternMatcher pattern matcher
+     * @param configs An array of ActionConfig's to process
+     * @param looseMatch To loosely match wildcards or not
+     * @param appendNamedParameters To append named parameters or not
+     *
+     * @since 2.5.23
+     * See WW-5065
+     */
+    public ActionConfigMatcher(PatternMatcher<?> patternMatcher,
+            Map<String, ActionConfig> configs,
+            boolean looseMatch, boolean appendNamedParameters) {
+        super(patternMatcher, appendNamedParameters);
         for (Map.Entry<String, ActionConfig> entry : configs.entrySet()) {
             addPattern(entry.getKey(), entry.getValue(), looseMatch);
         }
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java b/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java
index 4474677..06f9eff 100644
--- a/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java
+++ b/core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java
@@ -289,6 +289,8 @@ public class DefaultConfiguration implements Configuration {
         builder.constant(XWorkConstants.RELOAD_XML_CONFIGURATION, "false");
         builder.constant(StrutsConstants.STRUTS_I18N_RELOAD, "false");
 
+        builder.constant(StrutsConstants.STRUTS_MATCHER_APPEND_NAMED_PARAMETERS, "true");
+
         return builder.create(true);
     }
 
@@ -338,8 +340,12 @@ public class DefaultConfiguration implements Configuration {
         }
 
         PatternMatcher<int[]> matcher = container.getInstance(PatternMatcher.class);
+        boolean appendNamedParameters = Boolean.parseBoolean(
+                container.getInstance(String.class, StrutsConstants.STRUTS_MATCHER_APPEND_NAMED_PARAMETERS)
+        );
+
         return new RuntimeConfigurationImpl(Collections.unmodifiableMap(namespaceActionConfigs),
-                Collections.unmodifiableMap(namespaceConfigs), matcher);
+                Collections.unmodifiableMap(namespaceConfigs), matcher, appendNamedParameters);
     }
 
     private void setDefaultResults(Map<String, ResultConfig> results, PackageConfig packageContext) {
@@ -417,15 +423,16 @@ public class DefaultConfiguration implements Configuration {
 
         public RuntimeConfigurationImpl(Map<String, Map<String, ActionConfig>> namespaceActionConfigs,
                                         Map<String, String> namespaceConfigs,
-                                        PatternMatcher<int[]> matcher) {
+                                        PatternMatcher<int[]> matcher, boolean appendNamedParameters) {
             this.namespaceActionConfigs = namespaceActionConfigs;
             this.namespaceConfigs = namespaceConfigs;
 
             this.namespaceActionConfigMatchers = new LinkedHashMap<>();
-            this.namespaceMatcher = new NamespaceMatcher(matcher, namespaceActionConfigs.keySet());
+            this.namespaceMatcher = new NamespaceMatcher(matcher, namespaceActionConfigs.keySet(), appendNamedParameters);
 
             for (Map.Entry<String, Map<String, ActionConfig>> entry : namespaceActionConfigs.entrySet()) {
-                namespaceActionConfigMatchers.put(entry.getKey(), new ActionConfigMatcher(matcher, entry.getValue(), true));
+                ActionConfigMatcher configMatcher = new ActionConfigMatcher(matcher, entry.getValue(), true, appendNamedParameters);
+                namespaceActionConfigMatchers.put(entry.getKey(), configMatcher);
             }
         }
 
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/impl/NamespaceMatcher.java b/core/src/main/java/com/opensymphony/xwork2/config/impl/NamespaceMatcher.java
index 01decd3..b24fc75 100644
--- a/core/src/main/java/com/opensymphony/xwork2/config/impl/NamespaceMatcher.java
+++ b/core/src/main/java/com/opensymphony/xwork2/config/impl/NamespaceMatcher.java
@@ -29,9 +29,23 @@ import java.util.Set;
  * @since 2.1
  */
 public class NamespaceMatcher extends AbstractMatcher<NamespaceMatch> {
-     public NamespaceMatcher(PatternMatcher<?> patternMatcher,
-            Set<String> namespaces) {
-        super(patternMatcher);
+
+    public NamespaceMatcher(PatternMatcher<?> patternMatcher, Set<String> namespaces) {
+        this(patternMatcher, namespaces, true);
+    }
+
+    /**
+     * Matches namespace strings against a wildcard pattern matcher
+     *
+     * @param patternMatcher pattern matcher
+     * @param namespaces A set of namespaces to process
+     * @param appendNamedParameters To append named parameters or not
+     *
+     * @since 2.5.23
+     * See WW-5065
+     */
+    public NamespaceMatcher(PatternMatcher<?> patternMatcher, Set<String> namespaces, boolean appendNamedParameters) {
+        super(patternMatcher, appendNamedParameters);
         for (String name : namespaces) {
             if (!patternMatcher.isLiteral(name)) {
                 addPattern(name, new NamespaceMatch(name, null), false);
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java b/core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java
index cd27ed3..f1d4f11 100644
--- a/core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java
+++ b/core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java
@@ -108,6 +108,7 @@ import com.opensymphony.xwork2.validator.DefaultValidatorFactory;
 import com.opensymphony.xwork2.validator.DefaultValidatorFileParser;
 import com.opensymphony.xwork2.validator.ValidatorFactory;
 import com.opensymphony.xwork2.validator.ValidatorFileParser;
+import com.sun.org.apache.xpath.internal.operations.Bool;
 import ognl.MethodAccessor;
 import ognl.PropertyAccessor;
 import org.apache.struts2.StrutsConstants;
@@ -227,6 +228,7 @@ public class XWorkConfigurationProvider implements ConfigurationProvider {
         props.setProperty(XWorkConstants.ENABLE_OGNL_EVAL_EXPRESSION, Boolean.FALSE.toString());
         props.setProperty(XWorkConstants.RELOAD_XML_CONFIGURATION, Boolean.FALSE.toString());
         props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, Boolean.FALSE.toString());
+        props.setProperty(StrutsConstants.STRUTS_MATCHER_APPEND_NAMED_PARAMETERS, Boolean.TRUE.toString());
     }
 
 }
diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java
index 371540b..298958a 100644
--- a/core/src/main/java/org/apache/struts2/StrutsConstants.java
+++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java
@@ -341,4 +341,7 @@ public final class StrutsConstants {
     public static final String STRUTS_DISALLOW_PROXY_MEMBER_ACCESS = "struts.disallowProxyMemberAccess";
 
     public static final String STRUTS_OGNL_AUTO_GROWTH_COLLECTION_LIMIT = "struts.ognl.autoGrowthCollectionLimit";
+
+    /** See {@link com.opensymphony.xwork2.config.impl.AbstractMatcher#appendNamedParameters */
+    public static final String STRUTS_MATCHER_APPEND_NAMED_PARAMETERS = "";
 }
diff --git a/core/src/test/java/com/opensymphony/xwork2/config/impl/ActionConfigMatcherTest.java b/core/src/test/java/com/opensymphony/xwork2/config/impl/ActionConfigMatcherTest.java
index 3fba5b1..448a43c 100644
--- a/core/src/test/java/com/opensymphony/xwork2/config/impl/ActionConfigMatcherTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/config/impl/ActionConfigMatcherTest.java
@@ -147,7 +147,7 @@ public class ActionConfigMatcherTest extends XWorkTestCase {
      * Test to make sure the {@link AbstractMatcher#replaceParameters(Map, Map)} method isn't adding values to the
      * return value.
      */
-    public void testReplaceParameters() {
+    public void testReplaceParametersWithNoAppendingParams() {
         Map<String, ActionConfig> map = new HashMap<>();
 
         HashMap<String, String> params = new HashMap<>();
@@ -162,25 +162,52 @@ public class ActionConfigMatcherTest extends XWorkTestCase {
                 .setStrictMethodInvocation(false)
                 .build();
         map.put("foo/{one}/{two}/{three}", config);
-        ActionConfigMatcher replaceMatcher = new ActionConfigMatcher(new RegexPatternMatcher(), map, false);
+        ActionConfigMatcher replaceMatcher = new ActionConfigMatcher(new RegexPatternMatcher(), map, false, false);
         ActionConfig matched = replaceMatcher.match("foo/paramOne/paramTwo/paramThree");
         assertNotNull("ActionConfig should be matched", matched);
 
         // Verify all The ActionConfig, ExceptionConfig, and ResultConfig have the correct number of params
-        assertTrue("The ActionConfig should have the correct number of params",
-                matched.getParams().size() == 1);
-        assertTrue("The ExceptionMappingConfigs should have the correct number of params",
-                matched.getExceptionMappings().get(0).getParams().size() == 1);
-        assertTrue("The ResultConfigs should have the correct number of params",
-                matched.getResults().get("successparamOne").getParams().size() == 1);
+        assertEquals("The ActionConfig should have the correct number of params", 1, matched.getParams().size());
+        assertEquals("The ExceptionMappingConfigs should have the correct number of params", 1, matched.getExceptionMappings().get(0).getParams().size());
+        assertEquals("The ResultConfigs should have the correct number of params", 1, matched.getResults().get("successparamOne").getParams().size());
 
         // Verify the params are still getting their values replaced correctly
-        assertTrue("The ActionConfig params have replaced values",
-                "paramOne".equals(matched.getParams().get("first")));
-        assertTrue("The ActionConfig params have replaced values",
-                "paramOne".equals(matched.getExceptionMappings().get(0).getParams().get("first")));
-        assertTrue("The ActionConfig params have replaced values",
-                "paramOne".equals(matched.getResults().get("successparamOne").getParams().get("first")));
+        assertEquals("The ActionConfig params have replaced values", "paramOne", matched.getParams().get("first"));
+        assertEquals("The ActionConfig params have replaced values", "paramOne", matched.getExceptionMappings().get(0).getParams().get("first"));
+        assertEquals("The ActionConfig params have replaced values", "paramOne", matched.getResults().get("successparamOne").getParams().get("first"));
+    }
+
+    /**
+     * Test to make sure the {@link AbstractMatcher#replaceParameters(Map, Map)} method is adding values to the
+     * return value.
+     */
+    public void testReplaceParametersWithAppendingParams() {
+        Map<String, ActionConfig> map = new HashMap<>();
+
+        HashMap<String, String> params = new HashMap<>();
+        params.put("first", "{1}");
+
+        ActionConfig config = new ActionConfig.Builder("package", "foo/{one}/{two}/{three}", "foo.bar.Action")
+                .addParams(params)
+                .addExceptionMapping(new ExceptionMappingConfig.Builder("foo{1}", "java.lang.{2}Exception", "success{1}")
+                        .addParams(new HashMap<>(params))
+                        .build())
+                .addResultConfig(new ResultConfig.Builder("success{1}", "foo.{2}").addParams(params).build())
+                .setStrictMethodInvocation(false)
+                .build();
+        map.put("foo/{one}/{two}/{three}", config);
+        ActionConfigMatcher replaceMatcher = new ActionConfigMatcher(new RegexPatternMatcher(), map, false, true);
+        ActionConfig matched = replaceMatcher.match("foo/paramOne/paramTwo/paramThree");
+        assertNotNull("ActionConfig should be matched", matched);
+
+        assertEquals(4, matched.getParams().size());
+        assertEquals(4, matched.getExceptionMappings().get(0).getParams().size());
+        assertEquals(4, matched.getResults().get("successparamOne").getParams().size());
+
+        // Verify the params are still getting their values replaced correctly
+        assertEquals("paramOne", matched.getParams().get("first"));
+        assertEquals("paramOne", matched.getExceptionMappings().get(0).getParams().get("first"));
+        assertEquals("paramOne", matched.getResults().get("successparamOne").getParams().get("first"));
     }
 
     private Map<String,ActionConfig> buildActionConfigMap() {