You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by ya...@apache.org on 2019/04/20 05:24:40 UTC
[struts] branch struts-2-5-x updated: Proposed fix for WW-5029 for
the 2.5.x branch (#347)
This is an automated email from the ASF dual-hosted git repository.
yasserzamani pushed a commit to branch struts-2-5-x
in repository https://gitbox.apache.org/repos/asf/struts.git
The following commit(s) were added to refs/heads/struts-2-5-x by this push:
new fb38a91 Proposed fix for WW-5029 for the 2.5.x branch (#347)
fb38a91 is described below
commit fb38a919c9f6494cb0d3fbd83c11741c62eb3143
Author: JCgH4164838Gh792C124B5 <43...@users.noreply.github.com>
AuthorDate: Sat Apr 20 01:24:36 2019 -0400
Proposed fix for WW-5029 for the 2.5.x branch (#347)
* Proposed fix for WW-5029 for the 2.5.x branch:
- NOTE: If the PR is accepted please credit Maxime Clement for this change as they found
the issue, identified the probable cause/related details and opened the JIRA.
- Updated XWorkConfigurationProvider buildAllowedMethods(), loadGlobalAllowedMethods() so that
they now handle situations when a SAX parser produces multiple elements to represent the tag
body value.
- No changes to unit tests.
* Update commit to fix weakness identified by Maxime Clement:
- Implementation should now properly concatenate the node children values together (as a single unified string)
in both buildAllowedMethods(), loadGlobalAllowedMethods() - before generating the method Set to be added.
- Made some eligible variables final.
* Update commit to provide new unit tests:
- Added unit tests to confirm the fixes for buildAllowedMethods(), loadGlobalAllowedMethods()
- Added Mock DOM classes sufficient for these tests.
- Added unit tests to cover buildResults() and loadGlobalResults().
---
.../config/providers/XmlConfigurationProvider.java | 41 +-
.../providers/XmlConfigurationProviderTest.java | 802 +++++++++++++++++++++
2 files changed, 831 insertions(+), 12 deletions(-)
diff --git a/core/src/main/java/com/opensymphony/xwork2/config/providers/XmlConfigurationProvider.java b/core/src/main/java/com/opensymphony/xwork2/config/providers/XmlConfigurationProvider.java
index 3b72352..9cd21fb 100644
--- a/core/src/main/java/com/opensymphony/xwork2/config/providers/XmlConfigurationProvider.java
+++ b/core/src/main/java/com/opensymphony/xwork2/config/providers/XmlConfigurationProvider.java
@@ -874,15 +874,22 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
if (allowedMethodsEls.getLength() > 0) {
// user defined 'allowed-methods' so used them whatever Strict DMI was enabled or not
allowedMethods = new HashSet<>(packageContext.getGlobalAllowedMethods());
-
- if (allowedMethodsEls.getLength() > 0) {
- Node n = allowedMethodsEls.item(0).getFirstChild();
- if (n != null) {
- String s = n.getNodeValue().trim();
- if (s.length() > 0) {
- allowedMethods.addAll(TextParseUtil.commaDelimitedStringToSet(s));
+ // Fix for WW-5029 (concatenate all possible text node children)
+ final Node allowedMethodsNode = allowedMethodsEls.item(0);
+ if (allowedMethodsNode != null) {
+ final NodeList allowedMethodsChildren = allowedMethodsNode.getChildNodes();
+ final StringBuilder allowedMethodsSB = new StringBuilder();
+ for (int i = 0; i < allowedMethodsChildren.getLength(); i++) {
+ Node allowedMethodsChildNode = allowedMethodsChildren.item(i);
+ String childNodeValue = (allowedMethodsChildNode != null ? allowedMethodsChildNode.getNodeValue() : "");
+ childNodeValue = (childNodeValue != null ? childNodeValue.trim() : "");
+ if (childNodeValue.length() > 0) {
+ allowedMethodsSB.append(childNodeValue);
}
}
+ if (allowedMethodsSB.length() > 0) {
+ allowedMethods.addAll(TextParseUtil.commaDelimitedStringToSet(allowedMethodsSB.toString()));
+ }
}
} else if (packageContext.isStrictMethodInvocation()) {
// user enabled Strict DMI but didn't defined action specific 'allowed-methods' so we use 'global-allowed-methods' only
@@ -937,11 +944,21 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
if (globalAllowedMethodsElms.getLength() > 0) {
Set<String> globalAllowedMethods = new HashSet<>();
- Node n = globalAllowedMethodsElms.item(0).getFirstChild();
- if (n != null) {
- String s = n.getNodeValue().trim();
- if (s.length() > 0) {
- globalAllowedMethods = TextParseUtil.commaDelimitedStringToSet(s);
+ // Fix for WW-5029 (concatenate all possible text node children)
+ Node globaAllowedMethodsNode = globalAllowedMethodsElms.item(0);
+ if (globaAllowedMethodsNode != null) {
+ NodeList globaAllowedMethodsChildren = globaAllowedMethodsNode.getChildNodes();
+ final StringBuilder globalAllowedMethodsSB = new StringBuilder();
+ for (int i = 0; i < globaAllowedMethodsChildren.getLength(); i++) {
+ Node globalAllowedMethodsChildNode = globaAllowedMethodsChildren.item(i);
+ String childNodeValue = (globalAllowedMethodsChildNode != null ? globalAllowedMethodsChildNode.getNodeValue() : "");
+ childNodeValue = (childNodeValue != null ? childNodeValue.trim() : "");
+ if (childNodeValue.length() > 0) {
+ globalAllowedMethodsSB.append(childNodeValue);
+ }
+ }
+ if (globalAllowedMethodsSB.length() > 0) {
+ globalAllowedMethods.addAll(TextParseUtil.commaDelimitedStringToSet(globalAllowedMethodsSB.toString()));
}
}
packageContext.addGlobalAllowedMethods(globalAllowedMethods);
diff --git a/core/src/test/java/com/opensymphony/xwork2/config/providers/XmlConfigurationProviderTest.java b/core/src/test/java/com/opensymphony/xwork2/config/providers/XmlConfigurationProviderTest.java
index faa6b93..6aefed8 100644
--- a/core/src/test/java/com/opensymphony/xwork2/config/providers/XmlConfigurationProviderTest.java
+++ b/core/src/test/java/com/opensymphony/xwork2/config/providers/XmlConfigurationProviderTest.java
@@ -23,8 +23,11 @@ import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.config.ConfigurationProvider;
import com.opensymphony.xwork2.config.RuntimeConfiguration;
import com.opensymphony.xwork2.config.entities.PackageConfig;
+import com.opensymphony.xwork2.config.entities.ResultConfig;
+import com.opensymphony.xwork2.config.entities.ResultTypeConfig;
import com.opensymphony.xwork2.config.impl.MockConfiguration;
import com.opensymphony.xwork2.util.ClassLoaderUtil;
+import com.sun.org.apache.xerces.internal.dom.ElementImpl;
import org.w3c.dom.Document;
import java.io.File;
@@ -35,9 +38,20 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import org.apache.struts2.result.ServletDispatcherResult;
+import org.w3c.dom.Attr;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.TypeInfo;
+import org.w3c.dom.UserDataHandler;
public class XmlConfigurationProviderTest extends ConfigurationTestBase {
@@ -294,4 +308,792 @@ public class XmlConfigurationProviderTest extends ConfigurationTestBase {
assertTrue(loadedFileNames.contains("xwork-test-beans.xml"));
assertTrue(loadedFileNames.contains("xwork-test-default.xml"));
}
+
+ /**
+ * Test buildAllowedMethods() to ensure consistent results for processing
+ * <allowed-methods/> in <action/> XML configuration elements.
+ *
+ * @throws Exception
+ */
+ public void testBuildAllowedMethods() throws Exception {
+ // Test introduced with WW-5029 fix.
+ // Set up test using two mock DOM Elements:
+ // 1) A mock "action" Element with a single "allowed-methods" child Element that contains a single
+ // TEXT_NODE Node. This simulates a typical result from a SAX parser parsing the allowed-methods
+ // tag body.
+ // 2) A mock "action" Element with a single "allowed-methods" child Element that contains multiple
+ // TEXT_NODE Nodes. This simulates an unusal result from a SAX parser parsing the allowed-methods
+ // tag body (as reported with WW-5029).
+ final String fakeBodyString = "allowedMethod1,allowedMethod2,allowedMethod3";
+ PackageConfig.Builder testPackageConfigBuilder = new PackageConfig.Builder("allowedMethodsPackage");
+ List<String> singleStringList = new ArrayList(1);
+ List<String> multipleStringList = new ArrayList(4);
+ singleStringList.add(fakeBodyString);
+ multipleStringList.add("allowedMethod1,");
+ multipleStringList.add("allowed");
+ multipleStringList.add("Method2,");
+ multipleStringList.add("allowedMethod3");
+ NodeList mockNodeListSingleChild = new MockNodeList(singleStringList);
+ NodeList mockNodeListMultipleChild = new MockNodeList(multipleStringList);
+ Element mockSingleChildAllowedMethodsElement = new MockElement("allowed-methods", fakeBodyString,
+ "allowed-methods", fakeBodyString, Node.TEXT_NODE, mockNodeListSingleChild, null);
+ Element mockMultipleChildAllowedMethodsElement = new MockElement("allowed-methods", fakeBodyString,
+ "allowed-methods", fakeBodyString, Node.TEXT_NODE, mockNodeListMultipleChild, null);
+ MockNodeList mockActionElementChildrenSingle = new MockNodeList();
+ mockActionElementChildrenSingle.addToNodeList(mockSingleChildAllowedMethodsElement);
+ MockNodeList mockActionElementChildrenMultiple = new MockNodeList();
+ mockActionElementChildrenMultiple.addToNodeList(mockMultipleChildAllowedMethodsElement);
+ Element mockActionElementSingle = new MockElement("action", "fakeBody", "action", "fakeValue",
+ Node.TEXT_NODE, mockActionElementChildrenSingle, null);
+ Element mockActionElementMultiple = new MockElement("action", "fakeBody", "action", "fakeValue",
+ Node.TEXT_NODE, mockActionElementChildrenMultiple, null);
+ // Attempt the method using both types of Elements (single child and multiple child) and confirm
+ // the result is the same for both. Also confirm the results are as expected.
+ XmlConfigurationProvider prov = new XmlConfigurationProvider("com/opensymphony/xwork2/config/providers/xwork- test.xml", false);
+ Set<String> singleChildResult = prov.buildAllowedMethods(mockActionElementSingle, testPackageConfigBuilder);
+ Set<String> multipleChildResult = prov.buildAllowedMethods(mockActionElementMultiple, testPackageConfigBuilder);
+ assertNotNull("singleChildResult is null ?", singleChildResult);
+ assertNotNull("multipleChildResult is null ?", multipleChildResult);
+ assertEquals("singleChildResult not equal to multipleChildResult ?", singleChildResult, multipleChildResult);
+ // Since both Sets are equal, only need to test one to confirm contents are correct
+ assertEquals("result Sets not of length 3 ?", 3, multipleChildResult.size());
+ assertTrue("allowedMethod1 not present ?", multipleChildResult.contains("allowedMethod1"));
+ assertTrue("allowedMethod2 not present ?", multipleChildResult.contains("allowedMethod2"));
+ assertTrue("allowedMethod3 not present ?", multipleChildResult.contains("allowedMethod3"));
+ assertFalse("noSuchMethod is present ?", multipleChildResult.contains("noSuchMethod"));
+ }
+
+ /**
+ * Test loadGlobalAllowedMethods() to ensure consistent results for processing
+ * <global-allowed-methods/> in <package/> XML configuration elements.
+ *
+ * @throws Exception
+ */
+ public void testLoadGlobalAllowedMethods() throws Exception {
+ // Test introduced with WW-5029 fix.
+ // Set up test using two mock DOM Elements:
+ // 1) A mock "package" Element with a single "global-allowed-methods" child Element that contains a single
+ // TEXT_NODE Node. This simulates a typical result from a SAX parser parsing the global-allowed-methods
+ // tag body.
+ // 2) A mock "package" Element with a single "global-allowed-methods" child Element that contains multiple
+ // TEXT_NODE Nodes. This simulates an unusal result from a SAX parser parsing the global-allowed-methods
+ // tag body (as reported with WW-5029).
+ final String fakeBodyString = "allowedMethod1,allowedMethod2,allowedMethod3";
+ PackageConfig.Builder testPackageConfigBuilder = new PackageConfig.Builder("globalAllowedMethodsPackage");
+ List<String> singleStringList = new ArrayList(1);
+ List<String> multipleStringList = new ArrayList(4);
+ singleStringList.add(fakeBodyString);
+ multipleStringList.add("allowedMethod4,");
+ multipleStringList.add("allowed");
+ multipleStringList.add("Method5,");
+ multipleStringList.add("allowedMethod6");
+ NodeList mockNodeListSingleChild = new MockNodeList(singleStringList);
+ NodeList mockNodeListMultipleChild = new MockNodeList(multipleStringList);
+ Element mockSingleChildAllowedMethodsElement = new MockElement("global-allowed-methods", fakeBodyString,
+ "global-allowed-methods", fakeBodyString, Node.TEXT_NODE, mockNodeListSingleChild, null);
+ Element mockMultipleChildAllowedMethodsElement = new MockElement("global-allowed-methods", fakeBodyString,
+ "global-allowed-methods", fakeBodyString, Node.TEXT_NODE, mockNodeListMultipleChild, null);
+ MockNodeList mockPackageElementChildrenSingle = new MockNodeList();
+ mockPackageElementChildrenSingle.addToNodeList(mockSingleChildAllowedMethodsElement);
+ MockNodeList mockPackageElementChildrenMultiple = new MockNodeList();
+ mockPackageElementChildrenMultiple.addToNodeList(mockMultipleChildAllowedMethodsElement);
+ Element mockPackageElementSingle = new MockElement("package", "fakeBody", "package", "fakeValue",
+ Node.TEXT_NODE, mockPackageElementChildrenSingle, null);
+ Element mockPackageElementMultiple = new MockElement("package", "fakeBody", "package", "fakeValue",
+ Node.TEXT_NODE, mockPackageElementChildrenMultiple, null);
+ // Attempt the method using the single child Element and confirm the result is as expected.
+ XmlConfigurationProvider prov = new XmlConfigurationProvider("com/opensymphony/xwork2/config/providers/xwork- test.xml", false);
+ prov.loadGlobalAllowedMethods(testPackageConfigBuilder, mockPackageElementSingle);
+ Set<String> currentGlobalResult = testPackageConfigBuilder.getGlobalAllowedMethods();
+ assertNotNull("currentGlobalResult is null ?", currentGlobalResult);
+ assertEquals("currentGlobalResult Sets not of length 3 ?", 3, currentGlobalResult.size());
+ assertTrue("allowedMethod1 not present ?", currentGlobalResult.contains("allowedMethod1"));
+ assertTrue("allowedMethod2 not present ?", currentGlobalResult.contains("allowedMethod2"));
+ assertTrue("allowedMethod3 not present ?", currentGlobalResult.contains("allowedMethod3"));
+ assertFalse("noSuchMethod is present ?", currentGlobalResult.contains("noSuchMethod"));
+ // Attempt the method using the multiple child Element and confirm the result is as expected.
+ prov.loadGlobalAllowedMethods(testPackageConfigBuilder, mockPackageElementMultiple);
+ currentGlobalResult = testPackageConfigBuilder.getGlobalAllowedMethods();
+ assertNotNull("currentGlobalResult is null ?", currentGlobalResult);
+ assertEquals("currentGlobalResult Sets not of length 6 ?", 6, currentGlobalResult.size());
+ assertTrue("allowedMethod4 not present ?", currentGlobalResult.contains("allowedMethod4"));
+ assertTrue("allowedMethod5 not present ?", currentGlobalResult.contains("allowedMethod5"));
+ assertTrue("allowedMethod6 not present ?", currentGlobalResult.contains("allowedMethod6"));
+ assertFalse("noSuchMethod is present ?", currentGlobalResult.contains("snoSUchMethod"));
+ // Confirm the previously added elements are still present
+ assertTrue("allowedMethod1 not present ?", currentGlobalResult.contains("allowedMethod1"));
+ assertTrue("allowedMethod2 not present ?", currentGlobalResult.contains("allowedMethod2"));
+ assertTrue("allowedMethod3 not present ?", currentGlobalResult.contains("allowedMethod3"));
+ }
+
+ /**
+ * Test buildResults() to ensure consistent results for processing
+ * <result/> in <action/> XML configuration elements.
+ *
+ * @throws Exception
+ */
+ public void testBuildResults() throws Exception {
+ // Set up test using two mock DOM Elements:
+ // 1) A mock "action" Element with a two "result" child Elements that each contains a single
+ // TEXT_NODE Node. This simulates a typical result from a SAX parser parsing the result
+ // tag body.
+ // 2) A mock "action" Element with two "result" child Elements that each contain multiple
+ // TEXT_NODE Nodes. This simulates an unusal result from a SAX parser parsing the result
+ // tag body.
+ final String fakeBodyString = "/SomePath/SomePath/SomePath/SomeJSP.jsp";
+ final String fakeBodyString2 = "/SomePath2/SomePath2/SomePath2/SomeJSP2.jsp";
+ final String resultParam = "nonNullDefaultParam";
+ PackageConfig.Builder testPackageConfigBuilder = new PackageConfig.Builder("resultsPackage");
+ ResultTypeConfig.Builder resultTypeConfigBuilder = new ResultTypeConfig.Builder("dispatcher", (String) ServletDispatcherResult.class.getName());
+ resultTypeConfigBuilder.defaultResultParam(resultParam);
+ ResultTypeConfig resultTypeConfig = resultTypeConfigBuilder.build();
+ testPackageConfigBuilder.addResultTypeConfig(resultTypeConfig);
+ List<String> singleStringList = new ArrayList(1);
+ List<String> singleStringList2 = new ArrayList(1);
+ List<String> multipleStringList = new ArrayList(4);
+ List<String> multipleStringList2 = new ArrayList(4);
+ singleStringList.add(fakeBodyString);
+ singleStringList2.add(fakeBodyString2);
+ multipleStringList.add("/SomePath");
+ multipleStringList.add("/SomePath/");
+ multipleStringList.add("SomePath/");
+ multipleStringList.add("SomeJSP.jsp");
+ multipleStringList2.add("/SomePath2");
+ multipleStringList2.add("/SomePath2/");
+ multipleStringList2.add("SomePath2/");
+ multipleStringList2.add("SomeJSP2.jsp");
+ NodeList mockNodeListSingleChild = new MockNodeList(singleStringList);
+ NodeList mockNodeListSingleChild2 = new MockNodeList(singleStringList2);
+ NodeList mockNodeListMultipleChild = new MockNodeList(multipleStringList);
+ NodeList mockNodeListMultipleChild2 = new MockNodeList(multipleStringList2);
+ Element mockSingleChildResultElement = new MockElement("result", fakeBodyString,
+ "result", fakeBodyString, Node.TEXT_NODE, mockNodeListSingleChild, null);
+ mockSingleChildResultElement.setAttribute("name", "input");
+ mockSingleChildResultElement.setAttribute("type", "dispatcher");
+ Element mockSingleChildResultElement2 = new MockElement("result", fakeBodyString2,
+ "result", fakeBodyString2, Node.TEXT_NODE, mockNodeListSingleChild2, null);
+ mockSingleChildResultElement2.setAttribute("name", "success");
+ mockSingleChildResultElement2.setAttribute("type", "dispatcher");
+ Element mockMultipleChildAllowedMethodsElement = new MockElement("result", fakeBodyString,
+ "result", fakeBodyString, Node.TEXT_NODE, mockNodeListMultipleChild, null);
+ mockMultipleChildAllowedMethodsElement.setAttribute("name", "input");
+ mockMultipleChildAllowedMethodsElement.setAttribute("type", "dispatcher");
+ Element mockMultipleChildAllowedMethodsElement2 = new MockElement("result", fakeBodyString2,
+ "result", fakeBodyString2, Node.TEXT_NODE, mockNodeListMultipleChild2, null);
+ mockMultipleChildAllowedMethodsElement2.setAttribute("name", "success");
+ mockMultipleChildAllowedMethodsElement2.setAttribute("type", "dispatcher");
+ MockNodeList mockActionElementChildrenSingle = new MockNodeList();
+ mockActionElementChildrenSingle.addToNodeList(mockSingleChildResultElement);
+ mockActionElementChildrenSingle.addToNodeList(mockSingleChildResultElement2);
+ MockNodeList mockActionElementChildrenMultiple = new MockNodeList();
+ mockActionElementChildrenMultiple.addToNodeList(mockMultipleChildAllowedMethodsElement);
+ mockActionElementChildrenMultiple.addToNodeList(mockMultipleChildAllowedMethodsElement2);
+ Element mockActionElementSingle = new MockElement("action", "fakeBody", "action", "fakeValue",
+ Node.TEXT_NODE, mockActionElementChildrenSingle, null);
+ Element mockActionElementMultiple = new MockElement("action", "fakeBody", "action", "fakeValue",
+ Node.TEXT_NODE, mockActionElementChildrenMultiple, null);
+ // Attempt the method using both types of Elements (single child and multiple child) and confirm
+ // the result is the same for both. Also confirm the results are as expected.
+ XmlConfigurationProvider prov = new XmlConfigurationProvider("com/opensymphony/xwork2/config/providers/xwork- test.xml", false);
+ Map<String, ResultConfig> singleChildResult = prov.buildResults(mockActionElementSingle, testPackageConfigBuilder);
+ Map<String, ResultConfig> multipleChildResult = prov.buildResults(mockActionElementMultiple, testPackageConfigBuilder);
+ assertNotNull("singleChildResult is null ?", singleChildResult);
+ assertNotNull("multipleChildResult is null ?", multipleChildResult);
+ assertEquals("singleChildResult not equal to multipleChildResult ?", singleChildResult, multipleChildResult);
+ // Since both Maps are equal, only need to test one to confirm the contents of ONE are correct.contents are correct
+ // The multipleChildResult (constructed from the multiple child TEXT_NODES) will be checked for correctness.
+ assertEquals("result Maps not of size 2 ?", 2, multipleChildResult.size());
+ ResultConfig inputResult = multipleChildResult.get("input");
+ ResultConfig successResult = multipleChildResult.get("success");
+ assertNotNull("inputResult (multipleChildResult) is null ?", inputResult);
+ assertNotNull("successResult (multipleChildResult) is null ?", successResult);
+ Map<String, String> inputResultParams = inputResult.getParams();
+ Map<String, String> successResultParams = successResult.getParams();
+ assertNotNull("inputResultParams (multipleChildResult) is null ?", inputResultParams);
+ assertNotNull("successResultParams (multipleChildResult) is null ?", successResultParams);
+ assertEquals("inputResult (multipleChildResult) resultParam value not equal to fakeBodyString ?",
+ fakeBodyString, inputResultParams.get(resultParam));
+ assertEquals("successResult (multipleChildResult) resultParam value not equal to fakeBodyString2 ?",
+ fakeBodyString2, successResultParams.get(resultParam));
+ }
+
+ /**
+ * Test loadGlobalResults() to ensure consistent results for processing
+ * <global-results/> in <package/> XML configuration elements.
+ *
+ * @throws Exception
+ */
+ public void testLoadGlobalResults() throws Exception {
+ // Set up test using two mock DOM Elements:
+ // 1) A mock "package" Element containing a mock "global-results" Element with a two "result"
+ // child Elements that each contains a single TEXT_NODE Node. This simulates a typical result
+ // from a SAX parser parsing the result tag body.
+ // 2) A mock "package" Element containing a mock "global-results" Element with two "result"
+ // child Elements that each contain multiple TEXT_NODE Nodes. This simulates an unusal result
+ // from a SAX parser parsing the result tag body.
+ final String fakeBodyString = "/SomePath/SomePath/SomePath/SomeJSP.jsp";
+ final String fakeBodyString2 = "/SomePath2/SomePath2/SomePath2/SomeJSP2.jsp";
+ final String resultParam = "nonNullDefaultParam";
+ PackageConfig.Builder testPackageConfigBuilder = new PackageConfig.Builder("resultsPackage");
+ ResultTypeConfig.Builder resultTypeConfigBuilder = new ResultTypeConfig.Builder("dispatcher", (String) ServletDispatcherResult.class.getName());
+ resultTypeConfigBuilder.defaultResultParam(resultParam);
+ ResultTypeConfig resultTypeConfig = resultTypeConfigBuilder.build();
+ testPackageConfigBuilder.addResultTypeConfig(resultTypeConfig);
+ List<String> singleStringList = new ArrayList(1);
+ List<String> singleStringList2 = new ArrayList(1);
+ List<String> multipleStringList = new ArrayList(4);
+ List<String> multipleStringList2 = new ArrayList(4);
+ singleStringList.add(fakeBodyString);
+ singleStringList2.add(fakeBodyString2);
+ multipleStringList.add("/SomePath");
+ multipleStringList.add("/SomePath/");
+ multipleStringList.add("SomePath/");
+ multipleStringList.add("SomeJSP.jsp");
+ multipleStringList2.add("/SomePath2");
+ multipleStringList2.add("/SomePath2/");
+ multipleStringList2.add("SomePath2/");
+ multipleStringList2.add("SomeJSP2.jsp");
+ NodeList mockNodeListSingleChild = new MockNodeList(singleStringList);
+ NodeList mockNodeListSingleChild2 = new MockNodeList(singleStringList2);
+ NodeList mockNodeListMultipleChild = new MockNodeList(multipleStringList);
+ NodeList mockNodeListMultipleChild2 = new MockNodeList(multipleStringList2);
+ Element mockSingleChildResultElement = new MockElement("result", fakeBodyString,
+ "result", fakeBodyString, Node.TEXT_NODE, mockNodeListSingleChild, null);
+ mockSingleChildResultElement.setAttribute("name", "input");
+ mockSingleChildResultElement.setAttribute("type", "dispatcher");
+ Element mockSingleChildResultElement2 = new MockElement("result", fakeBodyString2,
+ "result", fakeBodyString2, Node.TEXT_NODE, mockNodeListSingleChild2, null);
+ mockSingleChildResultElement2.setAttribute("name", "success");
+ mockSingleChildResultElement2.setAttribute("type", "dispatcher");
+ Element mockMultipleChildAllowedMethodsElement = new MockElement("result", fakeBodyString,
+ "result", fakeBodyString, Node.TEXT_NODE, mockNodeListMultipleChild, null);
+ mockMultipleChildAllowedMethodsElement.setAttribute("name", "input2");
+ mockMultipleChildAllowedMethodsElement.setAttribute("type", "dispatcher");
+ Element mockMultipleChildAllowedMethodsElement2 = new MockElement("result", fakeBodyString,
+ "result", fakeBodyString2, Node.TEXT_NODE, mockNodeListMultipleChild2, null);
+ mockMultipleChildAllowedMethodsElement2.setAttribute("name", "success2");
+ mockMultipleChildAllowedMethodsElement2.setAttribute("type", "dispatcher");
+ MockNodeList mockGlobalResultsElementChildrenSingle = new MockNodeList();
+ mockGlobalResultsElementChildrenSingle.addToNodeList(mockSingleChildResultElement);
+ mockGlobalResultsElementChildrenSingle.addToNodeList(mockSingleChildResultElement2);
+ MockNodeList mockGlobalResultsElementChildrenMultiple = new MockNodeList();
+ mockGlobalResultsElementChildrenMultiple.addToNodeList(mockMultipleChildAllowedMethodsElement);
+ mockGlobalResultsElementChildrenMultiple.addToNodeList(mockMultipleChildAllowedMethodsElement2);
+ Element mockGlobalResultsElementSingle = new MockElement("global-results", "fakeBody", "global-results", "fakeValue",
+ Node.TEXT_NODE, mockGlobalResultsElementChildrenSingle, null);
+ Element mockGlobalResultsGlobalResultsElementMultiple = new MockElement("global-results", "fakeBody", "global-results", "fakeValue",
+ Node.TEXT_NODE, mockGlobalResultsElementChildrenMultiple, null);
+ MockNodeList mockPackageElementChildrenSingle = new MockNodeList();
+ mockPackageElementChildrenSingle.addToNodeList(mockGlobalResultsElementSingle);
+ MockNodeList mockPackageElementChildrenMultiple = new MockNodeList();
+ mockPackageElementChildrenMultiple.addToNodeList(mockGlobalResultsGlobalResultsElementMultiple);
+ Element mockPackageElementSingle = new MockElement("package", "fakeBody", "package", "fakeValue",
+ Node.TEXT_NODE, mockPackageElementChildrenSingle, null);
+ Element mockPackageElementMultiple = new MockElement("package", "fakeBody", "package", "fakeValue",
+ Node.TEXT_NODE, mockPackageElementChildrenMultiple, null);
+ // Attempt the global laod method using single child Elements first, and confirm the results are as expected.
+ XmlConfigurationProvider prov = new XmlConfigurationProvider("com/opensymphony/xwork2/config/providers/xwork- test.xml", false);
+ prov.loadGlobalResults(testPackageConfigBuilder, mockPackageElementSingle);
+ PackageConfig testPackageConfig = testPackageConfigBuilder.build();
+ Map<String, ResultConfig> currentGlobalResults = testPackageConfig.getAllGlobalResults();
+ assertNotNull("currentGlobalResults is null ?", currentGlobalResults);
+ assertEquals("currentGlobalResults size not 2 ?", 2, currentGlobalResults.size());
+ ResultConfig inputResult = currentGlobalResults.get("input");
+ ResultConfig successResult = currentGlobalResults.get("success");
+ assertNotNull("inputResult (currentGlobalResults - single) is null ?", inputResult);
+ assertNotNull("successResult (currentGlobalResults - single) is null ?", successResult);
+ Map<String, String> inputResultParams = inputResult.getParams();
+ Map<String, String> successResultParams = successResult.getParams();
+ assertNotNull("inputResultParams (currentGlobalResults - single) is null ?", inputResultParams);
+ assertNotNull("successResultParams (currentGlobalResults - single) is null ?", successResultParams);
+ assertEquals("inputResult (currentGlobalResults - single) resultParam value not equal to fakeBodyString ?",
+ fakeBodyString, inputResultParams.get(resultParam));
+ assertEquals("successResult (currentGlobalResults - single) resultParam value not equal to fakeBodyString2 ?",
+ fakeBodyString2, successResultParams.get(resultParam));
+ // Attempt the global laod method using mutliple child Elements next, and confirm the results are as expected.
+ prov.loadGlobalResults(testPackageConfigBuilder, mockPackageElementMultiple);
+ testPackageConfig = testPackageConfigBuilder.build();
+ currentGlobalResults = testPackageConfig.getAllGlobalResults();
+ assertNotNull("currentGlobalResults is null ?", currentGlobalResults);
+ assertEquals("currentGlobalResults size not 4 ?", 4, currentGlobalResults.size());
+ ResultConfig inputResult2 = currentGlobalResults.get("input2");
+ ResultConfig successResult2 = currentGlobalResults.get("success2");
+ assertNotNull("inputResult2 (currentGlobalResults - multiple) is null ?", inputResult2);
+ assertNotNull("successResult2 (currentGlobalResults - multiple) is null ?", successResult2);
+ Map<String, String> inputResultParams2 = inputResult2.getParams();
+ Map<String, String> successResultParams2 = successResult2.getParams();
+ assertNotNull("inputResultParams2 (currentGlobalResults - multiple) is null ?", inputResultParams2);
+ assertNotNull("successResultParams2 (currentGlobalResults - multiple) is null ?", successResultParams2);
+ assertEquals("inputResult2 (currentGlobalResults - multiple) resultParam value not equal to fakeBodyString ?",
+ fakeBodyString, inputResultParams2.get(resultParam));
+ assertEquals("successResult2 (currentGlobalResults - multiple) resultParam value not equal to fakeBodyString2 ?",
+ fakeBodyString2, successResultParams2.get(resultParam));
+ // Confirm the previous global results are still present
+ inputResult = currentGlobalResults.get("input");
+ successResult = currentGlobalResults.get("success");
+ assertNotNull("inputResult (currentGlobalResults - single) is null ?", inputResult);
+ assertNotNull("successResult (currentGlobalResults - single) is null ?", successResult);
+ inputResultParams = inputResult.getParams();
+ successResultParams = successResult.getParams();
+ assertNotNull("inputResultParams (currentGlobalResults - single) is null ?", inputResultParams);
+ assertNotNull("successResultParams (currentGlobalResults - single) is null ?", successResultParams);
+ assertEquals("inputResult (currentGlobalResults - single) resultParam value not equal to fakeBodyString ?",
+ fakeBodyString, inputResultParams.get(resultParam));
+ assertEquals("successResult (currentGlobalResults - single) resultParam value not equal to fakeBodyString2 ?",
+ fakeBodyString2, successResultParams.get(resultParam));
+ inputResult = currentGlobalResults.get("input");
+ successResult = currentGlobalResults.get("success");
+ assertNotNull("inputResult (currentGlobalResults - single) is null ?", inputResult);
+ assertNotNull("successResult (currentGlobalResults - single) is null ?", successResult);
+ inputResultParams = inputResult.getParams();
+ successResultParams = successResult.getParams();
+ assertNotNull("inputResultParams (currentGlobalResults - single) is null ?", inputResultParams);
+ assertNotNull("successResultParams (currentGlobalResults - single) is null ?", successResultParams);
+ assertEquals("inputResult (currentGlobalResults - single) resultParam value not equal to fakeBodyString ?",
+ fakeBodyString, inputResultParams.get(resultParam));
+ assertEquals("successResult (currentGlobalResults - single) resultParam value not equal to fakeBodyString2 ?",
+ fakeBodyString2, successResultParams.get(resultParam));
+ }
+
+ /**
+ * Mock NodeList.
+ *
+ * Provides minimal functionality to permit limited mock DOM testing.
+ */
+ protected class MockNodeList implements org.w3c.dom.NodeList {
+ List<Node> nodeList;
+
+ public MockNodeList() {
+ this.nodeList = new ArrayList(0);
+ }
+
+ /**
+ * Produces TEXT_NODE Nodes based on the input List of Strings. Node names
+ * follow a simple pattern "nodeX" where X is the index.
+ *
+ * @param stringList
+ */
+ public MockNodeList(List<String> stringList) {
+ if (stringList != null) {
+ final int nodeListLength = stringList.size();
+ this.nodeList = new ArrayList(nodeListLength);
+ for (int index = 0; index < nodeListLength; index++) {
+ this.nodeList.add(new MockNode("node" + index, stringList.get(index), Node.TEXT_NODE, null, null));
+ }
+ } else {
+ this.nodeList = new ArrayList(0);
+ }
+ }
+
+ public MockNodeList(NodeList nodeList) {
+ if (nodeList != null) {
+ final int nodeListLength = nodeList.getLength();
+ this.nodeList = new ArrayList(nodeListLength);
+ for (int index = 0; index < nodeListLength; index++) {
+ this.nodeList.add(nodeList.item(index));
+ }
+ } else {
+ this.nodeList = new ArrayList(0);
+ }
+ }
+
+ public void addToNodeList(List<Node> nodeList) {
+ if (nodeList != null) {
+ final int nodeListLength = nodeList.size();
+ for (int index = 0; index < nodeListLength; index++) {
+ this.nodeList.add(nodeList.get(index));
+ }
+ } else {
+ this.nodeList = new ArrayList(0);
+ }
+ }
+
+ public void addToNodeList(Node node) {
+ nodeList.add(node);
+ }
+
+ public void setParentForListNodes(Node parentNode) {
+ if (nodeList != null) {
+ final int nodeListLength = nodeList.size();
+ for (int index = 0; index < nodeListLength; index++) {
+ Node node = nodeList.get(index);
+ if (node instanceof MockNode) {
+ MockNode mockNode = (MockNode) node;
+ mockNode.setParentNode(parentNode);
+ }
+ }
+ }
+ }
+
+ @Override
+ public Node item(int index) {
+ return (nodeList != null ? nodeList.get(index) : null);
+ }
+
+ @Override
+ public int getLength() {
+ return (nodeList != null ? nodeList.size() : 0);
+ }
+ }
+
+ /**
+ * MockNode
+ *
+ * Provides minimal functionality to permit limited mock DOM testing.
+ */
+ protected class MockNode implements org.w3c.dom.Node {
+ final private String nodeName;
+ private String nodeValue;
+ final private short nodeType;
+ private Node parentNode;
+ final private NodeList childNodes;
+
+ public MockNode(String nodeName, String nodeValue, short nodeType, NodeList childNodes, Node parentNode) {
+ this.nodeName = nodeName;
+ this.nodeValue = nodeValue;
+ this.nodeType = nodeType;
+ this.childNodes = childNodes;
+ this.parentNode = parentNode;
+
+ if (childNodes instanceof MockNodeList) {
+ MockNodeList mockNodeList = (MockNodeList) childNodes;
+ mockNodeList.setParentForListNodes(this);
+ }
+ }
+
+ @Override
+ public String getNodeName() {
+ return nodeName;
+ }
+
+ @Override
+ public String getNodeValue() throws DOMException {
+ return nodeValue;
+ }
+
+ @Override
+ public void setNodeValue(String nodeValue) throws DOMException {
+ this.nodeValue = nodeValue;
+ }
+
+ @Override
+ public short getNodeType() {
+ return nodeType;
+ }
+
+ public void setParentNode(Node parentNode) {
+ this.parentNode = parentNode;
+ }
+
+ @Override
+ public Node getParentNode() {
+ return parentNode;
+ }
+
+ @Override
+ public NodeList getChildNodes() {
+ return childNodes;
+ }
+
+ @Override
+ public Node getFirstChild() {
+ if (childNodes != null) {
+ return childNodes.item(0);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Node getLastChild() {
+ if (childNodes != null) {
+ return childNodes.item(childNodes.getLength());
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Node getPreviousSibling() {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public Node getNextSibling() {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public NamedNodeMap getAttributes() {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public Document getOwnerDocument() {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public Node insertBefore(Node newChild, Node refChild) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public Node removeChild(Node oldChild) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public Node appendChild(Node newChild) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public boolean hasChildNodes() {
+ return (childNodes != null ? childNodes.getLength() > 0 : false);
+ }
+
+ @Override
+ public Node cloneNode(boolean deep) {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public void normalize() {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public boolean isSupported(String feature, String version) {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public String getNamespaceURI() {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public String getPrefix() {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public void setPrefix(String prefix) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public String getLocalName() {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public boolean hasAttributes() {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public String getBaseURI() {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public short compareDocumentPosition(Node other) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public String getTextContent() throws DOMException {
+ return nodeValue;
+ }
+
+ @Override
+ public void setTextContent(String textContent) throws DOMException {
+ setNodeValue(textContent);
+ }
+
+ @Override
+ public boolean isSameNode(Node other) {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public String lookupPrefix(String namespaceURI) {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public boolean isDefaultNamespace(String namespaceURI) {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public String lookupNamespaceURI(String prefix) {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public boolean isEqualNode(Node arg) {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public Object getFeature(String feature, String version) {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public Object setUserData(String key, Object data, UserDataHandler handler) {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public Object getUserData(String key) {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+ }
+
+ /**
+ * Mock Element.
+ *
+ * Provides minimal functionality to permit limited mock DOM testing.
+ */
+ protected class MockElement extends MockNode implements org.w3c.dom.Element {
+ final private String tagName;
+ final private String tagBody;
+ final private Map<String, String> attributes;
+
+ public MockElement(String tagName, String tagBody,
+ String nodeName, String nodeValue, short nodeType, NodeList childNodes, Node parentNode) {
+ super(nodeName, nodeValue, nodeType, childNodes, parentNode);
+ this.tagName = nodeName;
+ this.tagBody = nodeValue;
+ attributes = new HashMap<>();
+ }
+
+ @Override
+ public String getTagName() {
+ return tagName;
+ }
+
+ @Override
+ public String getAttribute(String name) {
+ return attributes.get(name);
+ }
+
+ @Override
+ public void setAttribute(String name, String value) throws DOMException {
+ attributes.put(name, value);
+ }
+
+ @Override
+ public void removeAttribute(String name) throws DOMException {
+ attributes.remove(name);
+ }
+
+ @Override
+ public Attr getAttributeNode(String name) {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public Attr setAttributeNode(Attr newAttr) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public Attr removeAttributeNode(Attr oldAttr) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public NodeList getElementsByTagName(String name) {
+ if (name != null) {
+ final NodeList tempChildren = getChildNodes();
+ final MockNodeList result = new MockNodeList();
+ if (tempChildren != null) {
+ final int nodeListLength = tempChildren.getLength();
+ for (int index = 0; index < nodeListLength; index++) {
+ Node node = tempChildren.item(index);
+ if (node instanceof Element) {
+ Element element = (Element) node;
+ if (name.equals(element.getTagName())) {
+ result.addToNodeList(element);
+ }
+ }
+ }
+ }
+ return result;
+ } else {
+ return new MockNodeList((NodeList) null);
+ }
+ }
+
+ @Override
+ public String getAttributeNS(String namespaceURI, String localName) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public void setAttributeNS(String namespaceURI, String qualifiedName, String value) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public void removeAttributeNS(String namespaceURI, String localName) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public Attr getAttributeNodeNS(String namespaceURI, String localName) throws DOMException {
+ return null; // Sufficient for Result processing
+ }
+
+ @Override
+ public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public NodeList getElementsByTagNameNS(String namespaceURI, String localName) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public boolean hasAttribute(String name) {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public boolean hasAttributeNS(String namespaceURI, String localName) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public TypeInfo getSchemaTypeInfo() {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public void setIdAttribute(String name, boolean isId) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+
+ @Override
+ public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException {
+ throw new UnsupportedOperationException("No mock support.");
+ }
+ }
+
}