mirror of
https://github.com/apache/struts.git
synced 2026-08-08 08:07:17 +00:00
Compare commits
103 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e8656d5737 | |||
| 7f10ed505f | |||
| 043814b774 | |||
| 0fabde9f97 | |||
| 4457f03c70 | |||
| 3d3512a399 | |||
| 59a6cbf6ca | |||
| 19802b0614 | |||
| e46e662a7a | |||
| 4786fba0d7 | |||
| e32bd7dba9 | |||
| 6e1d2add07 | |||
| 2eeac367fe | |||
| 30b43044a3 | |||
| 5c82f0246e | |||
| fff35cfd9d | |||
| 1526b36dd6 | |||
| 6d6a422db7 | |||
| 5cf57b9132 | |||
| f4c0135878 | |||
| 77cfae3084 | |||
| ec56290056 | |||
| 47c87bc62c | |||
| ce467b7fa5 | |||
| 73eb6ed189 | |||
| 80a91dc75f | |||
| a6edb0d5df | |||
| 3dfc5a4074 | |||
| fdfeb3233a | |||
| ae3ae2be76 | |||
| 8dface4fcb | |||
| 1348971d40 | |||
| dd6d206d78 | |||
| e2b644a4fb | |||
| 13cfba86f8 | |||
| d84d59f53c | |||
| 3651f55869 | |||
| 7ffa750c68 | |||
| 313876aa3c | |||
| 9d7a9f81db | |||
| fe98223724 | |||
| 1de94b2092 | |||
| 706bb560e4 | |||
| 12d4feaf8f | |||
| d88a8382d4 | |||
| 73809eae54 | |||
| 5b4b554d11 | |||
| fcbd29b7f9 | |||
| 220896a0cf | |||
| 632f19eab3 | |||
| 50a145152d | |||
| f7b191f782 | |||
| 4ae1a6a26d | |||
| 79e598f360 | |||
| 9216e8e22c | |||
| 651eac2c57 | |||
| a50af87644 | |||
| 9e01fbd2dd | |||
| d4dd3386cc | |||
| 0999fba8c4 | |||
| 3ac6835c5c | |||
| b0dd7c1c0d | |||
| a63beef1f8 | |||
| e74e5539dd | |||
| 2226fcc168 | |||
| 865b8a20df | |||
| 3c6956116e | |||
| bb9ce7582b | |||
| 11d373f8b4 | |||
| b23bfd42d2 | |||
| f94b681050 | |||
| fb38a919c9 | |||
| e25c826167 | |||
| 4815744eaf | |||
| f5a7776854 | |||
| f45d2752bb | |||
| 0262574095 | |||
| 30cb56a414 | |||
| 63dc85fd7a | |||
| 5b0ec3400d | |||
| d460d71498 | |||
| 53f64cdecf | |||
| aff4d46835 | |||
| a15c12a051 | |||
| e62155c460 | |||
| f7f4fbd47f | |||
| 2d81439553 | |||
| 7afe35cb96 | |||
| fdd1054070 | |||
| 32e88d1a2e | |||
| 6403de4516 | |||
| 13c517fc3c | |||
| 7242a87165 | |||
| 0323795d67 | |||
| 71267a9b4b | |||
| 5524c579d2 | |||
| 873ca8fa20 | |||
| 8988d57644 | |||
| 2e7cf63964 | |||
| 3eb68be674 | |||
| c9f279ec2e | |||
| 881e1b2580 | |||
| cb0ac7c440 |
+4
-3
@@ -1,3 +1,4 @@
|
||||
dist: trusty
|
||||
language: java
|
||||
sudo: false
|
||||
|
||||
@@ -8,12 +9,12 @@ jdk:
|
||||
- oraclejdk11
|
||||
|
||||
install: true
|
||||
script: mvn test -DskipAssembly
|
||||
script: mvn test -DskipAssembly -B
|
||||
|
||||
after_success:
|
||||
# TODO delete following if statement after fix of https://github.com/cobertura/cobertura/issues/271
|
||||
- if [ "$TRAVIS_JDK_VERSION" == "openjdk8" ] || [ "$TRAVIS_JDK_VERSION" == "oraclejdk8" ]; then
|
||||
mvn cobertura:cobertura org.eluder.coveralls:coveralls-maven-plugin:report com.updateimpact:updateimpact-maven-plugin:submit -Ptravis-coveralls,update-impact -DskipAssembly;
|
||||
mvn cobertura:cobertura org.eluder.coveralls:coveralls-maven-plugin:report com.updateimpact:updateimpact-maven-plugin:submit -Ptravis-coveralls,update-impact -DskipAssembly -B;
|
||||
else
|
||||
echo "Not reporting coverage for $TRAVIS_JDK_VERSION due to incompatibility or to save performance";
|
||||
fi;
|
||||
@@ -25,4 +26,4 @@ env:
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.m2
|
||||
|
||||
|
||||
|
||||
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
#!groovy
|
||||
pipeline {
|
||||
agent {
|
||||
label 'ubuntu'
|
||||
}
|
||||
options {
|
||||
buildDiscarder logRotator(daysToKeepStr: '14', numToKeepStr: '10')
|
||||
timeout(80)
|
||||
disableConcurrentBuilds()
|
||||
}
|
||||
tools {
|
||||
jdk 'JDK 1.7 (latest)'
|
||||
maven 'Maven 3 (latest)'
|
||||
}
|
||||
triggers {
|
||||
pollSCM 'H/15 * * * *'
|
||||
}
|
||||
environment {
|
||||
MAVEN_OPTS = '-Xmx1024m -XX:MaxPermSize=256m'
|
||||
}
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'mvn --version'
|
||||
sh 'mvn clean source:jar javadoc:jar install deploy -DskipWiki -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-rest-showcase</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
<name>Struts 2 Rest Showcase Webapp</name>
|
||||
<description>Struts 2 Rest Showcase Example</description>
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-showcase</artifactId>
|
||||
@@ -167,7 +167,7 @@
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>5.1.3.Final</version>
|
||||
<version>5.4.3.Final</version>
|
||||
</dependency>
|
||||
|
||||
<!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
|
||||
|
||||
+8
@@ -84,4 +84,12 @@ public class FileUploadAction extends ActionSupport {
|
||||
public void setCaption(String caption) {
|
||||
this.caption = caption;
|
||||
}
|
||||
|
||||
public long getUploadSize() {
|
||||
if (upload != null) {
|
||||
return upload.length();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@
|
||||
<validators>
|
||||
<field name="upload">
|
||||
<field-validator type="fieldexpression">
|
||||
<param name="expression"><![CDATA[upload.length() > 0]]></param>
|
||||
<param name="expression"><![CDATA[getUploadSize() > 0]]></param>
|
||||
<message>File cannot be empty</message>
|
||||
</field-validator>
|
||||
</field>
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
</action>
|
||||
|
||||
<action name="doMultipleUploadUsingList" class="org.apache.struts2.showcase.fileupload.MultipleFileUploadUsingListAction" method="upload">
|
||||
<result name="input">/WEB-INF/fileupload/multipleUploadUsingList.jsp</result>
|
||||
<result>/WEB-INF/fileupload/multiple-success.jsp</result>
|
||||
</action>
|
||||
|
||||
@@ -49,6 +50,7 @@
|
||||
</action>
|
||||
|
||||
<action name="doMultipleUploadUsingArray" class="org.apache.struts2.showcase.fileupload.MultipleFileUploadUsingArrayAction" method="upload">
|
||||
<result name="input">/WEB-INF/fileupload/multipleUploadUsingArray.jsp</result>
|
||||
<result>/WEB-INF/fileupload/multiple-success.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<interceptor-ref name="defaultStack"/>
|
||||
<interceptor-ref name="token"/>
|
||||
<result name="invalid.token">/WEB-INF/token/doublePost.jsp</result>
|
||||
<result name="success" type="redirect">/WEB-INF/token/transferDone.jsp</result>
|
||||
<result name="success">/WEB-INF/token/transferDone.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<interceptor-ref name="defaultStack"/>
|
||||
<interceptor-ref name="tokenSession"/>
|
||||
<result name="invalid.token">/WEB-INF/token/doublePost.jsp</result>
|
||||
<result name="success" type="redirect">/WEB-INF/token/transferDone.jsp</result>
|
||||
<result name="success">/WEB-INF/token/transferDone.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
|
||||
@@ -34,28 +34,28 @@
|
||||
|
||||
<package name="validation" extends="json-default" namespace="/validation">
|
||||
<action name="index">
|
||||
<result>/WEB-INF/validation/index.jsp</result>
|
||||
<result>index.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="quizBasic" class="org.apache.struts2.showcase.validation.QuizAction">
|
||||
<result name="input">quiz-basic.jsp</result>
|
||||
<result>quiz-success.jsp</result>
|
||||
<result name="input">/WEB-INF/validation/quiz-basic.jsp</result>
|
||||
<result>/WEB-INF/validation/quiz-success.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="quizClient" class="org.apache.struts2.showcase.validation.QuizAction">
|
||||
<result name="input">quiz-client.jsp</result>
|
||||
<result>quiz-success.jsp</result>
|
||||
<result name="input">/WEB-INF/validation/quiz-client.jsp</result>
|
||||
<result>/WEB-INF/validation/quiz-success.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="quizClientCss" class="org.apache.struts2.showcase.validation.QuizAction">
|
||||
<result name="input">quiz-client-css.jsp</result>
|
||||
<result>quiz-success.jsp</result>
|
||||
<result name="input">/WEB-INF/validation/quiz-client-css.jsp</result>
|
||||
<result>/WEB-INF/validation/quiz-success.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="quizAjax" class="org.apache.struts2.showcase.validation.QuizAction">
|
||||
<interceptor-ref name="jsonValidationWorkflowStack"/>
|
||||
<result name="input">quiz-ajax.jsp</result>
|
||||
<result>quiz-success.jsp</result>
|
||||
<result name="input">/WEB-INF/validation/quiz-ajax.jsp</result>
|
||||
<result>/WEB-INF/validation/quiz-success.jsp</result>
|
||||
</action>
|
||||
|
||||
<!-- =========================================== -->
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<!--
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<%@ page
|
||||
language="java"
|
||||
contentType="text/html; charset=UTF-8"
|
||||
pageEncoding="UTF-8"%>
|
||||
<%@ taglib prefix="s" uri="/struts-tags" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>Struts2 Showcase - Fileupload sample - Multiple fileupload</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="page-header">
|
||||
<h1>Fileupload sample - Multiple fileupload</h1>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<s:iterator var="counter" begin="1" end="3">
|
||||
<!-- Mechanism for display to work with upload both as an array and list in a single JSP (a bit ugly).
|
||||
Note: Output "index" doesn't always match if the input is "sparse". -->
|
||||
<s:if test="%{#counter <= upload.length}">
|
||||
<s:set var="displayContent" value="true" />
|
||||
</s:if>
|
||||
<s:elseif test="%{#counter <= upload.size}">
|
||||
<s:set var="displayContent" value="true" />
|
||||
</s:elseif>
|
||||
<s:else>
|
||||
<s:set var="displayContent" value="false" />
|
||||
</s:else>
|
||||
<s:if test="%{#displayContent == true}">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<b>File (<s:property value="#counter" />):</b>
|
||||
<ul>
|
||||
<li>ContentType: <s:property value="uploadContentType[#counter - 1]" /></li>
|
||||
<li>FileName: <s:property value="uploadFileName[#counter -1]" /></li>
|
||||
<li>File: <s:property value="upload[#counter - 1]" /></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</s:if>
|
||||
</s:iterator>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -39,7 +39,7 @@
|
||||
<div class="hero-unit">
|
||||
<h1>Welcome!</h1>
|
||||
<p>The Struts Showcase demonstrates a variety of use cases and tag usages. Essentially, the application exercises various framework features in isolation. The Showcase is not meant as a "best practices" example.</p>
|
||||
<p>For more "by example" solutions, see the <a class="btn btn-primary btn-large">Struts Cookbook »</a> pages.</p>
|
||||
<p>For more "by example" solutions, see the <a href="https://github.com/apache/struts-examples" class="btn btn-primary btn-large">Struts Examples »</a> pages.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<%@page import="org.apache.struts2.showcase.hangman.HangmanConstants" %>
|
||||
<%@taglib prefix="s" uri="/struts-tags" %>
|
||||
<html>
|
||||
<head>
|
||||
@@ -635,5 +636,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<p>
|
||||
A secondary test for this JSP visually verifies expression access to a public constant.
|
||||
A direct access to the same public constant via scriptlet provides secondary verification.
|
||||
</p>
|
||||
<br>
|
||||
<div>
|
||||
Test public static (constant) access (expression). Value: <s:property default="unavailable" value="@org.apache.struts2.showcase.hangman.HangmanConstants@HANGMAN_SESSION_KEY" />
|
||||
</div>
|
||||
<div>
|
||||
Test public static (constant) access (scriptlet). Value: <%=org.apache.struts2.showcase.hangman.HangmanConstants.HANGMAN_SESSION_KEY%>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
<@s.form action="transfer4">
|
||||
<@s.token/>
|
||||
<@s.textfield label="Amount" name="amount" required="true" value="400"/>
|
||||
<@s.textfield label="Amount" name="amount" required=true value="400"/>
|
||||
<@s.submit value="Transfer money" cssClass="btn btn-primary"/>
|
||||
</@s.form>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-assembly</artifactId>
|
||||
|
||||
+3
-3
@@ -30,7 +30,7 @@
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-bom</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Struts 2 Bill of Materials</name>
|
||||
@@ -45,7 +45,7 @@
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<struts-version.version>2.5.20</struts-version.version>
|
||||
<struts-version.version>2.5.23</struts-version.version>
|
||||
<maven.site.skip>true</maven.site.skip>
|
||||
<maven.site.deploy.skip>true</maven.site.deploy.skip>
|
||||
</properties>
|
||||
@@ -181,6 +181,6 @@
|
||||
</dependencyManagement>
|
||||
|
||||
<scm>
|
||||
<tag>STRUTS_2_5_20</tag>
|
||||
<tag>STRUTS_2_5_23</tag>
|
||||
</scm>
|
||||
</project>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-admin-bundle</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-demo-bundle</artifactId>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
|
||||
+3
-2
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
<artifactId>struts2-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
@@ -190,7 +190,8 @@
|
||||
<dependency>
|
||||
<groupId>com.sun</groupId>
|
||||
<artifactId>tools</artifactId>
|
||||
<version>1.5.0</version>
|
||||
<version>1.7.0</version>
|
||||
<!-- Match version of minimum compatible version -->
|
||||
<scope>system</scope>
|
||||
<systemPath>${java.home}/../lib/tools.jar</systemPath>
|
||||
</dependency>
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.opensymphony.xwork2.test.StubConfigurationProvider;
|
||||
import com.opensymphony.xwork2.util.XWorkTestCaseHelper;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
|
||||
/**
|
||||
* Base JUnit TestCase to extend for XWork specific JUnit tests. Uses
|
||||
@@ -78,16 +79,20 @@ public abstract class XWorkTestCase extends TestCase {
|
||||
@Override
|
||||
public void register(ContainerBuilder builder,
|
||||
LocatableProperties props) throws ConfigurationException {
|
||||
builder.factory(type, name, new Factory() {
|
||||
public Object create(Context context) throws Exception {
|
||||
return impl;
|
||||
}
|
||||
if (impl instanceof String || ClassUtils.isPrimitiveOrWrapper(impl.getClass())) {
|
||||
props.setProperty(name, "" + impl);
|
||||
} else {
|
||||
builder.factory(type, name, new Factory() {
|
||||
public Object create(Context context) throws Exception {
|
||||
return impl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class type() {
|
||||
return impl.getClass();
|
||||
}
|
||||
}, Scope.SINGLETON);
|
||||
@Override
|
||||
public Class type() {
|
||||
return impl.getClass();
|
||||
}
|
||||
}, Scope.SINGLETON);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -36,10 +36,8 @@ import java.util.*;
|
||||
* @since 2.1
|
||||
*/
|
||||
public abstract class AbstractMatcher<E> implements Serializable {
|
||||
/**
|
||||
* <p> The logging instance </p>
|
||||
*/
|
||||
private static final Logger log = LogManager.getLogger(AbstractMatcher.class);
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(AbstractMatcher.class);
|
||||
|
||||
/**
|
||||
* <p> Handles all wildcard pattern matching. </p>
|
||||
@@ -50,10 +48,34 @@ 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 named 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a matcher with {@link #appendNamedParameters} set to true to keep backward compatibility
|
||||
*
|
||||
* @param helper an instance of {@link PatternMatcher}
|
||||
* @deprecated use @{link {@link AbstractMatcher(PatternMatcher, boolean)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public AbstractMatcher(PatternMatcher<?> helper) {
|
||||
this(helper, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,17 +106,17 @@ public abstract class AbstractMatcher<E> implements Serializable {
|
||||
name = name.substring(1);
|
||||
}
|
||||
|
||||
log.debug("Compiling pattern '{}'", name);
|
||||
LOG.debug("Compiling pattern '{}'", name);
|
||||
|
||||
pattern = wildcard.compilePattern(name);
|
||||
compiledPatterns.add(new Mapping<E>(name, pattern, target));
|
||||
compiledPatterns.add(new Mapping<>(name, pattern, target));
|
||||
|
||||
if (looseMatch) {
|
||||
int lastStar = name.lastIndexOf('*');
|
||||
if (lastStar > 1 && lastStar == name.length() - 1) {
|
||||
if (name.charAt(lastStar - 1) != '*') {
|
||||
pattern = wildcard.compilePattern(name.substring(0, lastStar - 1));
|
||||
compiledPatterns.add(new Mapping<E>(name, pattern, target));
|
||||
compiledPatterns.add(new Mapping<>(name, pattern, target));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,12 +137,12 @@ public abstract class AbstractMatcher<E> implements Serializable {
|
||||
E config = null;
|
||||
|
||||
if (compiledPatterns.size() > 0) {
|
||||
log.debug("Attempting to match '{}' to a wildcard pattern, {} available", potentialMatch, compiledPatterns.size());
|
||||
LOG.debug("Attempting to match '{}' to a wildcard pattern, {} available", potentialMatch, compiledPatterns.size());
|
||||
|
||||
Map<String,String> vars = new LinkedHashMap<String,String>();
|
||||
Map<String,String> vars = new LinkedHashMap<>();
|
||||
for (Mapping<E> m : compiledPatterns) {
|
||||
if (wildcard.match(vars, potentialMatch, m.getPattern())) {
|
||||
log.debug("Value matches pattern '{}'", m.getOriginalPattern());
|
||||
LOG.debug("Value matches pattern '{}'", m.getOriginalPattern());
|
||||
config = convert(potentialMatch, m.getTarget(), vars);
|
||||
break;
|
||||
}
|
||||
@@ -152,20 +174,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));
|
||||
}
|
||||
|
||||
//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());
|
||||
|
||||
if (appendNamedParameters) {
|
||||
LOG.debug("Appending named parameters to the result 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;
|
||||
}
|
||||
|
||||
@@ -192,7 +217,7 @@ public abstract class AbstractMatcher<E> implements Serializable {
|
||||
c = val.charAt(x);
|
||||
if (x < len - 2 &&
|
||||
c == '{' && '}' == val.charAt(x+2)) {
|
||||
varVal = (String)vars.get(String.valueOf(val.charAt(x + 1)));
|
||||
varVal = vars.get(String.valueOf(val.charAt(x + 1)));
|
||||
if (varVal != null) {
|
||||
ret.append(varVal);
|
||||
}
|
||||
@@ -213,18 +238,18 @@ public abstract class AbstractMatcher<E> implements Serializable {
|
||||
/**
|
||||
* <p> The original pattern. </p>
|
||||
*/
|
||||
private String original;
|
||||
private final String original;
|
||||
|
||||
|
||||
/**
|
||||
* <p> The compiled pattern. </p>
|
||||
*/
|
||||
private Object pattern;
|
||||
private final Object pattern;
|
||||
|
||||
/**
|
||||
* <p> The original object. </p>
|
||||
*/
|
||||
private E config;
|
||||
private final E config;
|
||||
|
||||
/**
|
||||
* <p> Contructs a read-only Mapping instance. </p>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,18 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
+2
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+35
-14
@@ -93,12 +93,12 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
|
||||
private String configFileName;
|
||||
private ObjectFactory objectFactory;
|
||||
|
||||
private Set<String> loadedFileUrls = new HashSet<>();
|
||||
private final Set<String> loadedFileUrls = new HashSet<>();
|
||||
private boolean errorIfMissing;
|
||||
private Map<String, String> dtdMappings;
|
||||
private Configuration configuration;
|
||||
private boolean throwExceptionOnDuplicateBeans = true;
|
||||
private Map<String, Element> declaredPackages = new HashMap<>();
|
||||
private final Map<String, Element> declaredPackages = new HashMap<>();
|
||||
|
||||
private FileManager fileManager;
|
||||
private ValueSubstitutor valueSubstitutor;
|
||||
@@ -874,15 +874,24 @@ 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);
|
||||
if (allowedMethodsChildNode != null && allowedMethodsChildNode.getNodeType() == Node.TEXT_NODE) {
|
||||
String childNodeValue = 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 +946,23 @@ 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);
|
||||
if (globalAllowedMethodsChildNode != null && globalAllowedMethodsChildNode.getNodeType() == Node.TEXT_NODE) {
|
||||
String childNodeValue = 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);
|
||||
|
||||
@@ -164,7 +164,8 @@ class ContainerImpl implements Container {
|
||||
public FieldInjector(ContainerImpl container, Field field, String name)
|
||||
throws MissingDependencyException {
|
||||
this.field = field;
|
||||
if (!field.isAccessible()) {
|
||||
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()))
|
||||
&& !field.isAccessible()) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
try {
|
||||
if (sm != null) {
|
||||
@@ -256,7 +257,8 @@ class ContainerImpl implements Container {
|
||||
|
||||
public MethodInjector(ContainerImpl container, Method method, String name) throws MissingDependencyException {
|
||||
this.method = method;
|
||||
if (!method.isAccessible()) {
|
||||
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
|
||||
&& !method.isAccessible()) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
try {
|
||||
if (sm != null) {
|
||||
@@ -306,7 +308,8 @@ class ContainerImpl implements Container {
|
||||
this.implementation = implementation;
|
||||
|
||||
constructor = findConstructorIn(implementation);
|
||||
if (!constructor.isAccessible()) {
|
||||
if ((!Modifier.isPublic(constructor.getModifiers()) || !Modifier.isPublic(constructor.getDeclaringClass().getModifiers()))
|
||||
&& !constructor.isAccessible()) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
try {
|
||||
if (sm != null) {
|
||||
|
||||
@@ -25,13 +25,16 @@ import com.opensymphony.xwork2.XWorkConstants;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.*;
|
||||
import com.opensymphony.xwork2.util.ClearableValueStack;
|
||||
import com.opensymphony.xwork2.util.MemberAccessValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
@@ -100,8 +103,8 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
*/
|
||||
static final Comparator<String> rbCollator = new Comparator<String>() {
|
||||
public int compare(String s1, String s2) {
|
||||
int l1 = countOGNLCharacters(s1),
|
||||
l2 = countOGNLCharacters(s2);
|
||||
int l1 = countOGNLCharacters(s1);
|
||||
int l2 = countOGNLCharacters(s2);
|
||||
return l1 < l2 ? -1 : (l2 < l1 ? 1 : s1.compareTo(s2));
|
||||
}
|
||||
|
||||
@@ -185,7 +188,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
if (clearableStack) {
|
||||
//if the stack's context can be cleared, do that to prevent OGNL
|
||||
//from having access to objects in the stack, see XW-641
|
||||
((ClearableValueStack)newStack).clearContextValues();
|
||||
((ClearableValueStack) newStack).clearContextValues();
|
||||
Map<String, Object> context = newStack.getContext();
|
||||
ReflectionContextState.setCreatingNullObjects(context, true);
|
||||
ReflectionContextState.setDenyMethodExecution(context, true);
|
||||
@@ -228,7 +231,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
TextProvider tp = (TextProvider) action;
|
||||
developerNotification = tp.getText("devmode.notification",
|
||||
"Developer Notification:\n{0}",
|
||||
new String[]{ developerNotification }
|
||||
new String[]{developerNotification}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -245,7 +248,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
/**
|
||||
* Checks if name of parameter can be accepted or thrown away
|
||||
*
|
||||
* @param name parameter name
|
||||
* @param name parameter name
|
||||
* @param action current action
|
||||
* @return true if parameter is accepted
|
||||
*/
|
||||
@@ -289,27 +292,45 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
return accepted;
|
||||
}
|
||||
|
||||
protected boolean isWithinLengthLimit( String name ) {
|
||||
protected boolean isWithinLengthLimit(String name) {
|
||||
boolean matchLength = name.length() <= paramNameMaxLength;
|
||||
if (!matchLength) {
|
||||
LOG.debug("Parameter [{}] is too long, allowed length is [{}]", name, String.valueOf(paramNameMaxLength));
|
||||
if (devMode) { // warn only when in devMode
|
||||
LOG.warn("Parameter [{}] is too long, allowed length is [{}]. Use Interceptor Parameter Overriding " +
|
||||
"to override the limit, see more at\n" +
|
||||
"https://struts.apache.org/core-developers/interceptors.html#interceptor-parameter-overriding",
|
||||
name, paramNameMaxLength);
|
||||
} else {
|
||||
LOG.warn("Parameter [{}] is too long, allowed length is [{}]", name, paramNameMaxLength);
|
||||
}
|
||||
}
|
||||
return matchLength;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isAccepted(String paramName) {
|
||||
AcceptedPatternsChecker.IsAccepted result = acceptedPatterns.isAccepted(paramName);
|
||||
if (result.isAccepted()) {
|
||||
return true;
|
||||
} else if (devMode) { // warn only when in devMode
|
||||
LOG.warn("Parameter [{}] didn't match accepted pattern [{}]! See Accepted / Excluded patterns at\n" +
|
||||
"https://struts.apache.org/security/#accepted--excluded-patterns",
|
||||
paramName, result.getAcceptedPattern());
|
||||
} else {
|
||||
LOG.debug("Parameter [{}] didn't match accepted pattern [{}]!", paramName, result.getAcceptedPattern());
|
||||
}
|
||||
LOG.debug("Parameter [{}] didn't match accepted pattern [{}]!", paramName, result.getAcceptedPattern());
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isExcluded(String paramName) {
|
||||
ExcludedPatternsChecker.IsExcluded result = excludedPatterns.isExcluded(paramName);
|
||||
if (result.isExcluded()) {
|
||||
LOG.debug("Parameter [{}] matches excluded pattern [{}]!", paramName, result.getExcludedPattern());
|
||||
if (devMode) { // warn only when in devMode
|
||||
LOG.warn("Parameter [{}] matches excluded pattern [{}]! See Accepted / Excluded patterns at\n" +
|
||||
"https://struts.apache.org/security/#accepted--excluded-patterns",
|
||||
paramName, result.getExcludedPattern());
|
||||
} else {
|
||||
LOG.debug("Parameter [{}] matches excluded pattern [{}]!", paramName, result.getExcludedPattern());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -54,7 +54,7 @@ public class OgnlUtil {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(OgnlUtil.class);
|
||||
|
||||
private ConcurrentMap<String, Object> expressions = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<String, Object> expressions = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<Class, BeanInfo> beanInfoCache = new ConcurrentHashMap<>();
|
||||
private TypeConverter defaultConverter;
|
||||
|
||||
@@ -74,6 +74,9 @@ public class OgnlUtil {
|
||||
excludedClasses = new HashSet<>();
|
||||
excludedPackageNamePatterns = new HashSet<>();
|
||||
excludedPackageNames = new HashSet<>();
|
||||
excludedClasses = Collections.unmodifiableSet(excludedClasses);
|
||||
excludedPackageNamePatterns = Collections.unmodifiableSet(excludedPackageNamePatterns);
|
||||
excludedPackageNames = Collections.unmodifiableSet(excludedPackageNames);
|
||||
}
|
||||
|
||||
@Inject
|
||||
@@ -181,10 +184,98 @@ public class OgnlUtil {
|
||||
this.disallowProxyMemberAccess = Boolean.parseBoolean(disallowProxyMemberAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxLength Injects the Struts OGNL maximum expression length.
|
||||
*/
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH, required = false)
|
||||
protected void applyExpressionMaxLength(String maxLength) {
|
||||
try {
|
||||
if (maxLength == null || maxLength.isEmpty()) {
|
||||
// user is going to disable this functionality
|
||||
Ognl.applyExpressionMaxLength(null);
|
||||
} else {
|
||||
Ognl.applyExpressionMaxLength(Integer.parseInt(maxLength));
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Unable to set OGNL Expression Max Length {}.", maxLength); // Help configuration debugging.
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDisallowProxyMemberAccess() {
|
||||
return disallowProxyMemberAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience mechanism to clear the OGNL Runtime Cache via OgnlUtil. May be utilized
|
||||
* by applications that generate many unique OGNL expressions over time.
|
||||
*
|
||||
* Note: This call affects the global OGNL cache, see ({@link ognl.OgnlRuntime#clearCache()} for details.
|
||||
*
|
||||
* Warning: Frequent calling if this method may negatively impact performance, but may be required
|
||||
* to avoid memory exhaustion (resource leak) with too many OGNL expressions being cached.
|
||||
*
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public static void clearRuntimeCache() {
|
||||
OgnlRuntime.clearCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a mechanism to clear the OGNL expression cache. May be utilized by applications
|
||||
* that generate many unique OGNL expressions over time.
|
||||
*
|
||||
* Note: This call affects the current OgnlUtil instance. For Struts this is often a Singleton
|
||||
* instance so it can be "effectively global".
|
||||
*
|
||||
* Warning: Frequent calling if this method may negatively impact performance, but may be required
|
||||
* to avoid memory exhaustion (resource leak) with too many OGNL expressions being cached.
|
||||
*
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public void clearExpressionCache() {
|
||||
expressions.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the size of the expression cache (current number of elements).
|
||||
*
|
||||
* @return current number of elements in the expression cache.
|
||||
*
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public int expressionCacheSize() {
|
||||
return expressions.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a mechanism to clear the BeanInfo cache. May be utilized by applications
|
||||
* that request BeanInfo and/or PropertyDescriptors for many unique classes or objects over time
|
||||
* (especially dynamic objects).
|
||||
*
|
||||
* Note: This call affects the current OgnlUtil instance. For Struts this is often a Singleton
|
||||
* instance so it can be "effectively global".
|
||||
*
|
||||
* Warning: Frequent calling if this method may negatively impact performance, but may be required
|
||||
* to avoid memory exhaustion (resource leak) with too many BeanInfo elements being cached.
|
||||
*
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public void clearBeanInfoCache() {
|
||||
beanInfoCache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the size of the BeanInfo cache (current number of elements).
|
||||
*
|
||||
* @return current number of elements in the BeanInfo cache.
|
||||
*
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public int beanInfoCacheSize() {
|
||||
return beanInfoCache.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the object's properties using the default type converter, defaulting to not throw
|
||||
* exceptions for problems setting the properties.
|
||||
@@ -682,6 +773,9 @@ public class OgnlUtil {
|
||||
setValue(name, context, o, value);
|
||||
} catch (OgnlException e) {
|
||||
Throwable reason = e.getReason();
|
||||
if (reason instanceof SecurityException) {
|
||||
LOG.warn("Could not evaluate this expression due to security constraints: [{}]", name, e);
|
||||
}
|
||||
String msg = "Caught OgnlException while setting property '" + name + "' on type '" + o.getClass().getName() + "'.";
|
||||
Throwable exception = (reason == null) ? e : reason;
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
|
||||
private void trySetValue(String expr, Object value, boolean throwExceptionOnFailure, Map<String, Object> context) throws OgnlException {
|
||||
context.put(XWorkConverter.CONVERSION_PROPERTY_FULLNAME, expr);
|
||||
context.put(REPORT_ERRORS_ON_NO_PROP, (throwExceptionOnFailure) ? Boolean.TRUE : Boolean.FALSE);
|
||||
context.put(REPORT_ERRORS_ON_NO_PROP, throwExceptionOnFailure || logMissingProperties ? Boolean.TRUE : Boolean.FALSE);
|
||||
ognlUtil.setValue(expr, context, root, value);
|
||||
}
|
||||
|
||||
@@ -204,6 +204,9 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
}
|
||||
|
||||
protected void handleOgnlException(String expr, Object value, boolean throwExceptionOnFailure, OgnlException e) {
|
||||
if (e != null && e.getReason() instanceof SecurityException) {
|
||||
LOG.error("Could not evaluate this expression due to security constraints: [{}]", expr, e);
|
||||
}
|
||||
boolean shouldLog = shouldLogMissingPropertyWarning(e);
|
||||
String msg = null;
|
||||
if (throwExceptionOnFailure || shouldLog) {
|
||||
@@ -246,7 +249,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
}
|
||||
|
||||
protected void setupExceptionOnFailure(boolean throwExceptionOnFailure) {
|
||||
if (throwExceptionOnFailure) {
|
||||
if (throwExceptionOnFailure || logMissingProperties) {
|
||||
context.put(THROW_EXCEPTION_ON_FAILURE, true);
|
||||
}
|
||||
}
|
||||
@@ -326,7 +329,12 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
}
|
||||
|
||||
protected Object handleOgnlException(String expr, boolean throwExceptionOnFailure, OgnlException e) {
|
||||
Object ret = findInContext(expr);
|
||||
Object ret = null;
|
||||
if (e != null && e.getReason() instanceof SecurityException) {
|
||||
LOG.error("Could not evaluate this expression due to security constraints: [{}]", expr, e);
|
||||
} else {
|
||||
ret = findInContext(expr);
|
||||
}
|
||||
if (ret == null) {
|
||||
if (shouldLogMissingPropertyWarning(e)) {
|
||||
LOG.warn("Could not find property [{}]!", expr, e);
|
||||
@@ -339,8 +347,9 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
}
|
||||
|
||||
protected boolean shouldLogMissingPropertyWarning(OgnlException e) {
|
||||
return (e instanceof NoSuchPropertyException || e instanceof MethodFailedException)
|
||||
&& devMode && logMissingProperties;
|
||||
return (e instanceof NoSuchPropertyException ||
|
||||
(e instanceof MethodFailedException && e.getReason() instanceof NoSuchMethodException))
|
||||
&& logMissingProperties;
|
||||
}
|
||||
|
||||
private Object tryFindValue(String expr, Class asType) throws OgnlException {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package com.opensymphony.xwork2.ognl;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.XWorkConstants;
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.conversion.NullHandler;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
@@ -61,7 +62,7 @@ public class OgnlValueStackFactory implements ValueStackFactory {
|
||||
this.textProvider = textProvider;
|
||||
}
|
||||
|
||||
@Inject(value="allowStaticMethodAccess", required=false)
|
||||
@Inject(value = XWorkConstants.ALLOW_STATIC_METHOD_ACCESS, required = false)
|
||||
protected void setAllowStaticMethodAccess(String allowStaticMethodAccess) {
|
||||
this.allowStaticMethodAccess = BooleanUtils.toBoolean(allowStaticMethodAccess);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class SecurityMemberAccess extends DefaultMemberAccess {
|
||||
/**
|
||||
* SecurityMemberAccess
|
||||
* - access decisions based on whether member is static (or not)
|
||||
* - block or allow access to properties (configureable-after-construction)
|
||||
* - block or allow access to properties (configurable-after-construction)
|
||||
*
|
||||
* @param allowStaticMethodAccess
|
||||
*/
|
||||
|
||||
+16
-12
@@ -217,13 +217,14 @@ public class CompoundRootAccessor implements PropertyAccessor, MethodAccessor, C
|
||||
return null;
|
||||
}
|
||||
|
||||
Throwable reason = null;
|
||||
Class[] argTypes = getArgTypes(objects);
|
||||
for (Object o : root) {
|
||||
if (o == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Class clazz = o.getClass();
|
||||
Class[] argTypes = getArgTypes(objects);
|
||||
|
||||
MethodCall mc = null;
|
||||
|
||||
@@ -233,24 +234,27 @@ public class CompoundRootAccessor implements PropertyAccessor, MethodAccessor, C
|
||||
|
||||
if ((argTypes == null) || !invalidMethods.containsKey(mc)) {
|
||||
try {
|
||||
Object value = OgnlRuntime.callMethod((OgnlContext) context, o, name, objects);
|
||||
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
return OgnlRuntime.callMethod((OgnlContext) context, o, name, objects);
|
||||
} catch (OgnlException e) {
|
||||
// try the next one
|
||||
Throwable reason = e.getReason();
|
||||
reason = e.getReason();
|
||||
|
||||
if (!context.containsKey(OgnlValueStack.THROW_EXCEPTION_ON_FAILURE) && (mc != null) && (reason != null) && (reason.getClass() == NoSuchMethodException.class)) {
|
||||
invalidMethods.put(mc, Boolean.TRUE);
|
||||
} else if (reason != null) {
|
||||
throw new MethodFailedException(o, name, e.getReason());
|
||||
if (reason != null && !(reason instanceof NoSuchMethodException)) {
|
||||
// method has found but thrown an exception
|
||||
break;
|
||||
}
|
||||
|
||||
if ((mc != null) && (reason != null)) {
|
||||
invalidMethods.put(mc, Boolean.TRUE);
|
||||
}
|
||||
// continue and try the next one
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (context.containsKey(OgnlValueStack.THROW_EXCEPTION_ON_FAILURE)) {
|
||||
throw new MethodFailedException(target, name, reason);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+25
-6
@@ -25,6 +25,7 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -48,27 +49,39 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
|
||||
LOG.warn("Overriding accepted patterns [{}] with [{}], be aware that this affects all instances and safety of your application!",
|
||||
acceptedPatterns, acceptablePatterns);
|
||||
acceptedPatterns = new HashSet<>();
|
||||
for (String pattern : TextParseUtil.commaDelimitedStringToSet(acceptablePatterns)) {
|
||||
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
try {
|
||||
for (String pattern : TextParseUtil.commaDelimitedStringToSet(acceptablePatterns)) {
|
||||
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
acceptedPatterns = Collections.unmodifiableSet(acceptedPatterns);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(value = XWorkConstants.ADDITIONAL_ACCEPTED_PATTERNS, required = false)
|
||||
protected void setAdditionalAcceptedPatterns(String acceptablePatterns) {
|
||||
LOG.warn("Adding additional global patterns [{}] to accepted patterns!", acceptablePatterns);
|
||||
for (String pattern : TextParseUtil.commaDelimitedStringToSet(acceptablePatterns)) {
|
||||
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
acceptedPatterns = new HashSet<>(acceptedPatterns); // Make mutable before adding
|
||||
try {
|
||||
for (String pattern : TextParseUtil.commaDelimitedStringToSet(acceptablePatterns)) {
|
||||
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
acceptedPatterns = Collections.unmodifiableSet(acceptedPatterns);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(String commaDelimitedPatterns) {
|
||||
setAcceptedPatterns(TextParseUtil.commaDelimitedStringToSet(commaDelimitedPatterns));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(String[] additionalPatterns) {
|
||||
setAcceptedPatterns(new HashSet<>(Arrays.asList(additionalPatterns)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(Set<String> patterns) {
|
||||
if (acceptedPatterns == null) {
|
||||
// Limit unwanted log entries (for 1st call, acceptedPatterns null)
|
||||
@@ -78,11 +91,16 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
|
||||
acceptedPatterns, patterns);
|
||||
}
|
||||
acceptedPatterns = new HashSet<>(patterns.size());
|
||||
for (String pattern : patterns) {
|
||||
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
try {
|
||||
for (String pattern : patterns) {
|
||||
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
acceptedPatterns = Collections.unmodifiableSet(acceptedPatterns);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsAccepted isAccepted(String value) {
|
||||
for (Pattern acceptedPattern : acceptedPatterns) {
|
||||
if (acceptedPattern.matcher(value).matches()) {
|
||||
@@ -93,6 +111,7 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
|
||||
return IsAccepted.no(acceptedPatterns.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Pattern> getAcceptedPatterns() {
|
||||
return acceptedPatterns;
|
||||
}
|
||||
|
||||
+26
-7
@@ -27,6 +27,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -55,17 +56,26 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
|
||||
// Limit unwanted log entries (when excludedPatterns null/empty - usually 1st call)
|
||||
LOG.debug("Overriding excluded patterns with [{}]", excludePatterns);
|
||||
}
|
||||
excludedPatterns = new HashSet<Pattern>();
|
||||
for (String pattern : TextParseUtil.commaDelimitedStringToSet(excludePatterns)) {
|
||||
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
excludedPatterns = new HashSet<>();
|
||||
try {
|
||||
for (String pattern : TextParseUtil.commaDelimitedStringToSet(excludePatterns)) {
|
||||
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
excludedPatterns = Collections.unmodifiableSet(excludedPatterns);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(value = XWorkConstants.ADDITIONAL_EXCLUDED_PATTERNS, required = false)
|
||||
public void setAdditionalExcludePatterns(String excludePatterns) {
|
||||
LOG.debug("Adding additional global patterns [{}] to excluded patterns!", excludePatterns);
|
||||
for (String pattern : TextParseUtil.commaDelimitedStringToSet(excludePatterns)) {
|
||||
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
excludedPatterns = new HashSet<>(excludedPatterns); // Make mutable before adding
|
||||
try {
|
||||
for (String pattern : TextParseUtil.commaDelimitedStringToSet(excludePatterns)) {
|
||||
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
excludedPatterns = Collections.unmodifiableSet(excludedPatterns);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,14 +87,17 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(String commaDelimitedPatterns) {
|
||||
setExcludedPatterns(TextParseUtil.commaDelimitedStringToSet(commaDelimitedPatterns));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(String[] patterns) {
|
||||
setExcludedPatterns(new HashSet<>(Arrays.asList(patterns)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(Set<String> patterns) {
|
||||
if (excludedPatterns != null && excludedPatterns.size() > 0) {
|
||||
LOG.warn("Replacing excluded patterns [{}] with [{}], be aware that this affects all instances and safety of your application!",
|
||||
@@ -94,11 +107,16 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
|
||||
LOG.debug("Sets excluded patterns to [{}]", patterns);
|
||||
}
|
||||
excludedPatterns = new HashSet<>(patterns.size());
|
||||
for (String pattern : patterns) {
|
||||
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
try {
|
||||
for (String pattern : patterns) {
|
||||
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
excludedPatterns = Collections.unmodifiableSet(excludedPatterns);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IsExcluded isExcluded(String value) {
|
||||
for (Pattern excludedPattern : excludedPatterns) {
|
||||
if (excludedPattern.matcher(value).matches()) {
|
||||
@@ -109,6 +127,7 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
|
||||
return IsExcluded.no(excludedPatterns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Pattern> getExcludedPatterns() {
|
||||
return excludedPatterns;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
|
||||
public static final String STRUTS_MESSAGES_BUNDLE = "org/apache/struts2/struts-messages";
|
||||
|
||||
private static final String TOMCAT_RESOURCE_ENTRIES_FIELD = "resourceEntries";
|
||||
private final String RELOADED = "com.opensymphony.xwork2.util.LocalizedTextProvider.reloaded";
|
||||
private static final String RELOADED = "com.opensymphony.xwork2.util.LocalizedTextProvider.reloaded";
|
||||
|
||||
protected final ConcurrentMap<String, ResourceBundle> bundlesMap = new ConcurrentHashMap<>();
|
||||
protected boolean devMode = false;
|
||||
@@ -225,10 +225,45 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bundleName Removes the bundle from any cached "misses"
|
||||
* Clear a specific bundle from the <code>bundlesMap</code>
|
||||
*
|
||||
* Warning: This method <b>may be ineffective</b> due to the way the <code>bundlesMap</code>
|
||||
* is used in combination with locale. Descendants should use the method
|
||||
* {@link #clearBundle(java.lang.String, java.util.Locale)} instead.
|
||||
*
|
||||
* @param bundleName The bundle to remove from the bundle map
|
||||
*/
|
||||
public void clearBundle(final String bundleName) {
|
||||
bundlesMap.remove(getCurrentThreadContextClassLoader().hashCode() + bundleName);
|
||||
final ResourceBundle removedBundle = bundlesMap.remove(getCurrentThreadContextClassLoader().hashCode() + bundleName);
|
||||
LOG.debug("Clearing resource bundle [{}], result: [{}].", bundleName, Boolean.valueOf(removedBundle != null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear a specific bundle + locale combination from the <code>bundlesMap</code>.
|
||||
* Intended for descendants to use clear a bundle + locale combination.
|
||||
*
|
||||
* @param bundleName The bundle (combined with locale) to remove from the bundle map
|
||||
* @param locale Provides the locale to combine with the bundle to get the key
|
||||
*/
|
||||
protected void clearBundle(final String bundleName, Locale locale) {
|
||||
final String key = createMissesKey(String.valueOf(getCurrentThreadContextClassLoader().hashCode()), bundleName, locale);
|
||||
final ResourceBundle removedBundle = bundlesMap.remove(key);
|
||||
LOG.debug("Clearing resource bundle [{}], locale [{}], result: [{}].", bundleName, locale, Boolean.valueOf(removedBundle != null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the <code>missingBundles</code> contents. This allows descendants to
|
||||
* clear the <b>"missing bundles cache"</b> when desired (or needed).
|
||||
*
|
||||
* Note: This method may be used when the <code>bundlesMap</code> state has changed
|
||||
* in such a way that bundles that were previously "missing" may now be available
|
||||
* (e.g. after calling {@link #addDefaultResourceBundle(java.lang.String)} when the
|
||||
* {@link AbstractLocalizedTextProvider} has already been used for failed bundle
|
||||
* lookups of a given key, or some transitory state made a bundle lookup fail.
|
||||
*/
|
||||
protected void clearMissingBundlesCache() {
|
||||
missingBundles.clear();
|
||||
LOG.debug("Cleared the missing bundles cache.");
|
||||
}
|
||||
|
||||
protected void reloadBundles() {
|
||||
|
||||
@@ -82,13 +82,14 @@ public class ProxyUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given member is a proxy member of a proxy object.
|
||||
* Check whether the given member is a proxy member of a proxy object or is a static proxy member.
|
||||
* @param member the member to check
|
||||
* @param object the object to check
|
||||
*/
|
||||
public static boolean isProxyMember(Member member, Object object) {
|
||||
if (!isProxy(object))
|
||||
if (!Modifier.isStatic(member.getModifiers()) && !isProxy(object)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Boolean flag = isProxyMemberCache.get(member);
|
||||
if (flag != null) {
|
||||
|
||||
@@ -261,6 +261,9 @@ public final class StrutsConstants {
|
||||
/** Enables evaluation of OGNL expressions */
|
||||
public static final String STRUTS_ENABLE_OGNL_EVAL_EXPRESSION = "struts.ognl.enableOGNLEvalExpression";
|
||||
|
||||
/** The maximum length of an expression (OGNL) */
|
||||
public static final String STRUTS_OGNL_EXPRESSION_MAX_LENGTH = "struts.ognl.expressionMaxLength";
|
||||
|
||||
/** Disables {@link org.apache.struts2.dispatcher.StrutsRequestWrapper} request attribute value stack lookup (JSTL accessibility) */
|
||||
public static final String STRUTS_DISABLE_REQUEST_ATTRIBUTE_VALUE_STACK_LOOKUP = "struts.disableRequestAttributeValueStackLookup";
|
||||
|
||||
@@ -338,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 = "struts.matcher.appendNamedParameters";
|
||||
}
|
||||
|
||||
@@ -97,6 +97,10 @@ public class DefaultDispatcherErrorHandler implements DispatcherErrorHandler {
|
||||
response.sendError(code, e.getMessage());
|
||||
} catch (IOException e1) {
|
||||
// we're already sending an error, not much else we can do if more stuff breaks
|
||||
LOG.warn("Unable to send error response, code: {};", code, e1);
|
||||
} catch (IllegalStateException ise) {
|
||||
// Log illegalstate instead of passing unrecoverable exception to calling thread
|
||||
LOG.warn("Unable to send error response, code: {}; isCommited: {};", code, response.isCommitted(), ise);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +126,10 @@ public class DefaultDispatcherErrorHandler implements DispatcherErrorHandler {
|
||||
response.sendError(code, "Unable to show problem report:\n" + exp + "\n\n" + LocationUtils.getLocation(exp));
|
||||
} catch (IOException ex) {
|
||||
// we're already sending an error, not much else we can do if more stuff breaks
|
||||
LOG.warn("Unable to send error response, code: {};", code, ex);
|
||||
} catch (IllegalStateException ise) {
|
||||
// Log illegalstate instead of passing unrecoverable exception to calling thread
|
||||
LOG.warn("Unable to send error response, code: {}; isCommited: {};", code, response.isCommitted(), ise);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +218,15 @@ public class DefaultStaticContentLoader implements StaticContentLoader {
|
||||
}
|
||||
}
|
||||
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
try {
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
} catch (IOException e1) {
|
||||
// we're already sending an error, not much else we can do if more stuff breaks
|
||||
LOG.warn("Unable to send error response, code: {};", HttpServletResponse.SC_NOT_FOUND, e1);
|
||||
} catch (IllegalStateException ise) {
|
||||
// Log illegalstate instead of passing unrecoverable exception to calling thread
|
||||
LOG.warn("Unable to send error response, code: {}; isCommited: {};", HttpServletResponse.SC_NOT_FOUND, response.isCommitted(), ise);
|
||||
}
|
||||
}
|
||||
|
||||
protected void process(InputStream is, String path, HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
|
||||
@@ -85,7 +85,7 @@ public class Dispatcher {
|
||||
*/
|
||||
public static final String REQUEST_POST_METHOD = "POST";
|
||||
|
||||
public static final String MULTIPART_FORM_DATA_REGEX = "^multipart/form-data(; boundary=[0-9a-zA-Z'()+_,\\-./:=?]{1,70})?(;charset=[a-zA-Z\\-0-9]{3,14})?";
|
||||
public static final String MULTIPART_FORM_DATA_REGEX = "^multipart/form-data(?:\\s*;\\s*boundary=[0-9a-zA-Z'()+_,\\-./:=?]{1,70})?(?:\\s*;\\s*charset=[a-zA-Z\\-0-9]{3,14})?";
|
||||
|
||||
/**
|
||||
* Provide a thread local instance.
|
||||
@@ -582,8 +582,10 @@ public class Dispatcher {
|
||||
logConfigurationException(request, e);
|
||||
sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
if (handleException || devMode) {
|
||||
if (devMode) {
|
||||
LOG.debug("Dispatcher serviceAction failed", e);
|
||||
}
|
||||
sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
|
||||
} else {
|
||||
throw new ServletException(e);
|
||||
@@ -694,12 +696,23 @@ public class Dispatcher {
|
||||
try {
|
||||
locale = LocaleUtils.toLocale(defaultLocale);
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warn(new ParameterizedMessage("Cannot convert 'struts.locale' = [{}] to proper locale, defaulting to request locale [{}]",
|
||||
defaultLocale, request.getLocale()), e);
|
||||
locale = request.getLocale();
|
||||
try {
|
||||
locale = request.getLocale();
|
||||
LOG.warn(new ParameterizedMessage("Cannot convert 'struts.locale' = [{}] to proper locale, defaulting to request locale [{}]",
|
||||
defaultLocale, locale), e);
|
||||
} catch (RuntimeException rex) {
|
||||
LOG.warn(new ParameterizedMessage("Cannot convert 'struts.locale' = [{}] to proper locale, and cannot get locale from HTTP Request, falling back to system default locale",
|
||||
defaultLocale), rex);
|
||||
locale = Locale.getDefault();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
locale = request.getLocale();
|
||||
try {
|
||||
locale = request.getLocale();
|
||||
} catch (RuntimeException rex) {
|
||||
LOG.warn("Cannot get locale from HTTP Request, falling back to system default locale", rex);
|
||||
locale = Locale.getDefault();
|
||||
}
|
||||
}
|
||||
return locale;
|
||||
}
|
||||
|
||||
@@ -197,5 +197,28 @@ public class HttpParameters implements Map<String, Parameter>, Cloneable {
|
||||
|
||||
return new HttpParameters(parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternate Builder method which avoids wrapping any parameters that are already
|
||||
* a {@link Parameter} element within another {@link Parameter} wrapper.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public HttpParameters buildNoNestedWrapping() {
|
||||
Map<String, Parameter> parameters = (parent == null)
|
||||
? new HashMap<String, Parameter>()
|
||||
: new HashMap<>(parent.parameters);
|
||||
|
||||
for (Map.Entry<String, Object> entry : requestParameterMap.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
Parameter parameterValue = (value instanceof Parameter)
|
||||
? (Parameter) value
|
||||
: new Parameter.Request(name, value);
|
||||
parameters.put(name, parameterValue);
|
||||
}
|
||||
|
||||
return new HttpParameters(parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -74,6 +74,8 @@ import java.util.Map;
|
||||
public class ActionMappingParametersInterceptor extends ParametersInterceptor {
|
||||
|
||||
/**
|
||||
* Get the parameter map from ActionMapping associated with the provided ActionContext.
|
||||
*
|
||||
* @param ac The action context
|
||||
* @return the parameters from the action mapping in the context. If none found, returns an empty map.
|
||||
*/
|
||||
@@ -81,27 +83,25 @@ public class ActionMappingParametersInterceptor extends ParametersInterceptor {
|
||||
protected HttpParameters retrieveParameters(ActionContext ac) {
|
||||
ActionMapping mapping = (ActionMapping) ac.get(ServletActionContext.ACTION_MAPPING);
|
||||
if (mapping != null) {
|
||||
return HttpParameters.create(mapping.getParams()).build();
|
||||
return HttpParameters.create(mapping.getParams()).buildNoNestedWrapping();
|
||||
} else {
|
||||
return HttpParameters.create().build();
|
||||
return HttpParameters.create().buildNoNestedWrapping();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the parameters into context's ParameterMap
|
||||
* Adds the parameters into the current ActionContext's parameter map.
|
||||
*
|
||||
* Note: The method should avoid re-wrapping values which are already of type Parameter.
|
||||
*
|
||||
* @param ac The action context
|
||||
* @param newParams The parameter map to apply
|
||||
* <p>
|
||||
* In this class this is a no-op, since the parameters were fetched from the same location.
|
||||
* In subclasses both retrieveParameters() and addParametersToContext() should be overridden.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
protected void addParametersToContext(ActionContext ac, Map<String, ?> newParams) {
|
||||
HttpParameters previousParams = ac.getParameters();
|
||||
HttpParameters.Builder combinedParams = HttpParameters.create().withParent(previousParams).withExtraParams(newParams);
|
||||
|
||||
ac.setParameters(combinedParams.build());
|
||||
ac.setParameters(combinedParams.buildNoNestedWrapping());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import java.util.Map;
|
||||
/**
|
||||
* Just as the CheckboxInterceptor checks that if only the hidden field is present, so too does this interceptor. If
|
||||
* the "__multiselect_" request parameter is present and its visible counterpart is not, set a new request parameter to an
|
||||
* empty Sting.
|
||||
* empty String.
|
||||
*/
|
||||
public class MultiselectInterceptor extends AbstractInterceptor {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -37,7 +37,7 @@ public class MultiselectInterceptor extends AbstractInterceptor {
|
||||
/**
|
||||
* Just as the CheckboxInterceptor checks that if only the hidden field is present, so too does this interceptor.
|
||||
* If the "__multiselect_" request parameter is present and its visible counterpart is not, set a new request parameter
|
||||
* to an empty Sting.
|
||||
* to an empty String.
|
||||
*
|
||||
* @param ai ActionInvocation
|
||||
* @return the result of the action
|
||||
|
||||
+28
-4
@@ -112,6 +112,20 @@ public class TokenSessionStoreInterceptor extends TokenInterceptor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles processing of invalid tokens. If a previously stored invocation is
|
||||
* available, the method will attempt to return and render its result. Otherwise
|
||||
* it will return INVALID_TOKEN_CODE.
|
||||
*
|
||||
* Note: Because a stored (previously completed) invocation's PageContext will be closed,
|
||||
* this method must replace the stored PageContext with the current invocation's one (or a null).
|
||||
* See {@link org.apache.struts2.util.InvocationSessionStore#loadInvocation(String key, String token)} for details.
|
||||
*
|
||||
* @param invocation
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected String handleInvalidToken(ActionInvocation invocation) throws Exception {
|
||||
ActionContext ac = invocation.getInvocationContext();
|
||||
@@ -126,11 +140,11 @@ public class TokenSessionStoreInterceptor extends TokenInterceptor {
|
||||
params.remove(tokenName);
|
||||
params.remove(TokenHelper.TOKEN_NAME_FIELD);
|
||||
|
||||
String sessionTokenName = TokenHelper.buildTokenSessionAttributeName(tokenName);
|
||||
String sessionTokenName = TokenHelper.buildTokenSessionAttributeName(tokenName);
|
||||
ActionInvocation savedInvocation = InvocationSessionStore.loadInvocation(sessionTokenName, token);
|
||||
|
||||
if (savedInvocation != null) {
|
||||
// set the valuestack to the request scope
|
||||
// set the savedInvocation's valuestack to the request scope
|
||||
ValueStack stack = savedInvocation.getStack();
|
||||
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
|
||||
|
||||
@@ -153,13 +167,23 @@ public class TokenSessionStoreInterceptor extends TokenInterceptor {
|
||||
return INVALID_TOKEN_CODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles processing of valid tokens. Stores the current invocation for
|
||||
* later use by {@link handleInvalidToken}.
|
||||
* See {@link org.apache.struts2.util.InvocationSessionStore#storeInvocation(String key, String token, ActionInvocation invocation)} for details.
|
||||
*
|
||||
* @param invocation
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected String handleValidToken(ActionInvocation invocation) throws Exception {
|
||||
// we know the token name and token must be there
|
||||
String key = TokenHelper.getTokenName();
|
||||
String token = TokenHelper.getToken(key);
|
||||
String sessionTokenName = TokenHelper.buildTokenSessionAttributeName(key);
|
||||
InvocationSessionStore.storeInvocation(sessionTokenName, token, invocation);
|
||||
String sessionTokenName = TokenHelper.buildTokenSessionAttributeName(key);
|
||||
InvocationSessionStore.storeInvocation(sessionTokenName, token, invocation);
|
||||
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
@@ -250,13 +250,24 @@ public class ServletRedirectResult extends StrutsResultSupport implements Reflec
|
||||
* @throws IOException in case of IO errors
|
||||
*/
|
||||
protected void sendRedirect(HttpServletResponse response, String finalLocation) throws IOException {
|
||||
if (SC_FOUND == statusCode) {
|
||||
response.sendRedirect(finalLocation);
|
||||
} else {
|
||||
response.setStatus(statusCode);
|
||||
response.setHeader("Location", finalLocation);
|
||||
response.getWriter().write(finalLocation);
|
||||
response.getWriter().close();
|
||||
try {
|
||||
if (SC_FOUND == statusCode) {
|
||||
response.sendRedirect(finalLocation);
|
||||
} else {
|
||||
response.setStatus(statusCode);
|
||||
response.setHeader("Location", finalLocation);
|
||||
try {
|
||||
response.getWriter().write(finalLocation);
|
||||
} finally {
|
||||
response.getWriter().close();
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
LOG.warn("Unable to redirect to: {}, code: {}; {}", finalLocation, statusCode, ioe);
|
||||
throw ioe; // Re-throw required to preserve existing default behaviour (no stacktrace in above warn for this reason)
|
||||
} catch (IllegalStateException ise) {
|
||||
LOG.warn("Unable to redirect to: {}, code: {}; isCommited: {}; {}", finalLocation, statusCode, response.isCommitted(), ise);
|
||||
throw ise; // Re-throw required to preserve existing default behaviour (no stacktrace in above warn for this reason)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.apache.struts2.util;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
@@ -55,11 +56,20 @@ public class InvocationSessionStore {
|
||||
return null;
|
||||
}
|
||||
|
||||
ActionInvocation savedInvocation = null;
|
||||
if (invocationContext.invocation != null) {
|
||||
savedInvocation = invocationContext.invocation;
|
||||
ActionContext.setContext(savedInvocation.getInvocationContext());
|
||||
ActionContext.getContext().setValueStack(savedInvocation.getStack());
|
||||
final ActionInvocation savedInvocation = invocationContext.invocation;
|
||||
if (savedInvocation != null) {
|
||||
// WW-5026 - Preserve the previous PageContext (even if null) and restore it to the
|
||||
// ActionContext after loading the savedInvocation context. The saved context's PageContext
|
||||
// would already be closed at this point (causing failures if used for output).
|
||||
final ActionContext savedActionContext = savedInvocation.getInvocationContext();
|
||||
final ActionContext previousActionContext = ActionContext.getContext();
|
||||
ActionContext.setContext(savedActionContext);
|
||||
savedActionContext.setValueStack(savedInvocation.getStack());
|
||||
if (previousActionContext != null) {
|
||||
savedActionContext.put(ServletActionContext.PAGE_CONTEXT, previousActionContext.get(ServletActionContext.PAGE_CONTEXT));
|
||||
} else {
|
||||
savedActionContext.put(ServletActionContext.PAGE_CONTEXT, null);
|
||||
}
|
||||
}
|
||||
|
||||
return savedInvocation;
|
||||
|
||||
@@ -23,12 +23,16 @@ import ognl.OgnlException;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.ognl.OgnlUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* FIXME: remove?
|
||||
*/
|
||||
public class OgnlTool {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(OgnlTool.class);
|
||||
|
||||
private OgnlUtil ognlUtil;
|
||||
|
||||
public OgnlTool() {
|
||||
@@ -43,6 +47,9 @@ public class OgnlTool {
|
||||
try {
|
||||
return Ognl.getValue(ognlUtil.compile(expr), context);
|
||||
} catch (OgnlException e) {
|
||||
if (e.getReason() instanceof SecurityException) {
|
||||
LOG.warn("Could not evaluate this expression due to security constraints: [{}]", expr, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,4 +219,15 @@ struts.ognl.enableExpressionCache=true
|
||||
### Indicates if Dispatcher should handle unexpected exceptions by calling sendError()
|
||||
### or simply rethrow it as a ServletException to allow future processing by other frameworks like Spring Security
|
||||
struts.handle.exception=true
|
||||
|
||||
### Applies maximum length allowed on OGNL expressions for security enhancement (optional)
|
||||
###
|
||||
### **WARNING**: If developers enable this option (by configuration) they should make sure that they understand the implications of setting
|
||||
### struts.ognl.expressionMaxLength. They must choose a value large enough to permit ALL valid OGNL expressions used within the application.
|
||||
### Values larger than the 200-400 range have diminishing security value (at which point it is really only a "style guard" for long OGNL
|
||||
### expressions in an application. Setting a value of null or "" will also disable the feature.
|
||||
###
|
||||
### NOTE: The sample line below is *INTENTIONALLY* commented out, as this feature is disabled by default.
|
||||
# struts.ognl.expressionMaxLength=256
|
||||
|
||||
### END SNIPPET: complete_file
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
java.lang.ClassLoader,
|
||||
java.lang.Shutdown,
|
||||
java.lang.ProcessBuilder,
|
||||
sun.misc.Unsafe,
|
||||
com.opensymphony.xwork2.ActionContext" />
|
||||
|
||||
<!-- this must be valid regex, each '.' in package name must be escaped! -->
|
||||
@@ -55,13 +56,21 @@
|
||||
<constant name="struts.excludedPackageNames"
|
||||
value="
|
||||
ognl.,
|
||||
java.io.,
|
||||
java.net.,
|
||||
java.nio.,
|
||||
javax.,
|
||||
freemarker.core.,
|
||||
freemarker.template.,
|
||||
freemarker.ext.jsp.,
|
||||
freemarker.ext.rhino.,
|
||||
sun.misc.,
|
||||
sun.reflect.,
|
||||
javassist.,
|
||||
org.apache.velocity.,
|
||||
org.objectweb.asm.,
|
||||
org.springframework.context.,
|
||||
com.opensymphony.xwork2.inject.,
|
||||
com.opensymphony.xwork2.ognl.,
|
||||
com.opensymphony.xwork2.security.,
|
||||
com.opensymphony.xwork2.util." />
|
||||
|
||||
@@ -29,9 +29,12 @@
|
||||
<#if parameters.listValueKey??>
|
||||
<#-- checks the valueStack for the 'valueKey.' The valueKey is then looked-up in the locale
|
||||
file for it's localized value. This is then used as a label -->
|
||||
<#assign itemValue = stack.findString(parameters.listValueKey)/>
|
||||
<#-- FIXME: find a better way to get the value than a call to @s.text -->
|
||||
<#assign itemValue><@s.text name="${itemValue}"/></#assign>
|
||||
<#assign valueKey = stack.findString(parameters.listValueKey)!''/>
|
||||
<#if valueKey?has_content>
|
||||
<#assign itemValue = struts.getText(valueKey) />
|
||||
<#else>
|
||||
<#assign itemValue = parameters.listValueKey />
|
||||
</#if>
|
||||
<#elseif parameters.listValue??>
|
||||
<#assign itemValue = stack.findString(parameters.listValue)/>
|
||||
<#else>
|
||||
|
||||
@@ -70,8 +70,8 @@
|
||||
<#if parameters.listValueKey??>
|
||||
<#-- checks the valueStack for the 'valueKey.' The valueKey is then looked-up in the locale file for it's
|
||||
localized value. This is then used as a label -->
|
||||
<#assign valueKey = stack.findString(parameters.listValueKey) />
|
||||
<#if valueKey??>
|
||||
<#assign valueKey = stack.findString(parameters.listValueKey)!'' />
|
||||
<#if valueKey?has_content>
|
||||
<#assign itemValue = struts.getText(valueKey) />
|
||||
<#else>
|
||||
<#assign itemValue = parameters.listValueKey />
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.opensymphony.xwork2.config.entities.ExceptionMappingConfig;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorMapping;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.util.WildcardHelper;
|
||||
import org.apache.struts2.util.RegexPatternMatcher;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -142,6 +143,79 @@ 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 testReplaceParametersWithNoAppendingParams() {
|
||||
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, 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
|
||||
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
|
||||
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.getParams().get("one"));
|
||||
assertEquals("paramTwo", matched.getParams().get("two"));
|
||||
assertEquals("paramThree", matched.getParams().get("three"));
|
||||
assertEquals("paramOne", matched.getExceptionMappings().get(0).getParams().get("first"));
|
||||
assertEquals("paramOne", matched.getExceptionMappings().get(0).getParams().get("one"));
|
||||
assertEquals("paramTwo", matched.getExceptionMappings().get(0).getParams().get("two"));
|
||||
assertEquals("paramThree", matched.getExceptionMappings().get(0).getParams().get("three"));
|
||||
assertEquals("paramOne", matched.getResults().get("successparamOne").getParams().get("first"));
|
||||
}
|
||||
|
||||
private Map<String,ActionConfig> buildActionConfigMap() {
|
||||
Map<String, ActionConfig> map = new HashMap<>();
|
||||
|
||||
|
||||
+802
@@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,26 +19,39 @@
|
||||
package com.opensymphony.xwork2.ognl;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionProxyFactory;
|
||||
import com.opensymphony.xwork2.XWorkConstants;
|
||||
import com.opensymphony.xwork2.XWorkException;
|
||||
import com.opensymphony.xwork2.XWorkTestCase;
|
||||
import com.opensymphony.xwork2.config.ConfigurationManager;
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.interceptor.ChainingInterceptor;
|
||||
import com.opensymphony.xwork2.test.StubConfigurationProvider;
|
||||
import com.opensymphony.xwork2.test.User;
|
||||
import com.opensymphony.xwork2.util.*;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
|
||||
import java.beans.IntrospectionException;
|
||||
import ognl.*;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.DateFormat;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class OgnlUtilTest extends XWorkTestCase {
|
||||
|
||||
|
||||
// Fields for static field access test
|
||||
public static final String STATIC_FINAL_PUBLIC_ATTRIBUTE = "Static_Final_Public_Attribute";
|
||||
static final String STATIC_FINAL_PACKAGE_ATTRIBUTE = "Static_Final_Package_Attribute";
|
||||
protected static final String STATIC_FINAL_PROTECTED_ATTRIBUTE = "Static_Final_Protected_Attribute";
|
||||
private static final String STATIC_FINAL_PRIVATE_ATTRIBUTE = "Static_Final_Private_Attribute";
|
||||
public static String STATIC_PUBLIC_ATTRIBUTE = "Static_Public_Attribute";
|
||||
static String STATIC_PACKAGE_ATTRIBUTE = "Static_Package_Attribute";
|
||||
protected static String STATIC_PROTECTED_ATTRIBUTE = "Static_Protected_Attribute";
|
||||
private static String STATIC_PRIVATE_ATTRIBUTE = "Static_Private_Attribute";
|
||||
|
||||
private OgnlUtil ognlUtil;
|
||||
|
||||
@Override
|
||||
@@ -101,6 +114,84 @@ public class OgnlUtilTest extends XWorkTestCase {
|
||||
assertSame(expr0, expr2);
|
||||
}
|
||||
|
||||
public void testClearExpressionCache() throws OgnlException {
|
||||
ognlUtil.setEnableExpressionCache("true");
|
||||
// Test that the expression cache is functioning as expected.
|
||||
Object expr0 = ognlUtil.compile("test");
|
||||
Object expr1 = ognlUtil.compile("test");
|
||||
Object expr2 = ognlUtil.compile("test");
|
||||
// Cache in effect, so expr0, expr1, expr2 should be the same.
|
||||
assertSame(expr0, expr1);
|
||||
assertSame(expr0, expr2);
|
||||
assertTrue("Expression cache empty before clear ?", ognlUtil.expressionCacheSize() > 0);
|
||||
// Clear the Epxression cache and confirm subsequent requests are new.
|
||||
ognlUtil.clearExpressionCache();
|
||||
assertTrue("Expression cache not empty after clear ?", ognlUtil.expressionCacheSize() == 0);
|
||||
Object expr3 = ognlUtil.compile("test");
|
||||
Object expr4 = ognlUtil.compile("test");
|
||||
Object expr5 = ognlUtil.compile("test");
|
||||
// Cache cleared, expr3 should be a new instance.
|
||||
assertNotSame(expr0, expr3);
|
||||
// Cache still in effect, so expr3, expr4, expr5 should be the same.
|
||||
assertSame(expr3, expr4);
|
||||
assertSame(expr3, expr5);
|
||||
assertTrue("Expression cache empty after usage ?", ognlUtil.expressionCacheSize() > 0);
|
||||
}
|
||||
|
||||
public void testClearBeanInfoCache() throws IntrospectionException {
|
||||
final TestBean1 testBean1 = new TestBean1();
|
||||
final TestBean2 testBean2 = new TestBean2();
|
||||
// Test that the BeanInfo cache is functioning as expected.
|
||||
Object beanInfo1_1 = ognlUtil.getBeanInfo(testBean1);
|
||||
Object beanInfo1_2 = ognlUtil.getBeanInfo(testBean1);
|
||||
Object beanInfo1_3 = ognlUtil.getBeanInfo(testBean1);
|
||||
// Cache in effect, so beanInfo1_1, beanInfo1_2, beanInfo1_3 should be the same.
|
||||
assertSame(beanInfo1_1, beanInfo1_2);
|
||||
assertSame(beanInfo1_1, beanInfo1_3);
|
||||
Object beanInfo2_1 = ognlUtil.getBeanInfo(testBean2);
|
||||
Object beanInfo2_2 = ognlUtil.getBeanInfo(testBean2);
|
||||
Object beanInfo2_3 = ognlUtil.getBeanInfo(testBean2);
|
||||
// Cache in effect, so beanInfo2_1, beanInfo2_2, beanInfo2_3 should be the same.
|
||||
assertSame(beanInfo2_1, beanInfo2_2);
|
||||
assertSame(beanInfo2_1, beanInfo2_3);
|
||||
// BeanInfo for TestBean1 and TestBean2 should always be different.
|
||||
assertNotSame(beanInfo1_1, beanInfo2_1);
|
||||
assertTrue("BeanInfo cache empty before clear ?", ognlUtil.beanInfoCacheSize() > 0);
|
||||
// Clear the BeanInfo cache and confirm subsequent requests are new.
|
||||
ognlUtil.clearBeanInfoCache();
|
||||
assertTrue("BeanInfo cache not empty after clear ?", ognlUtil.beanInfoCacheSize() == 0);
|
||||
Object beanInfo1_4 = ognlUtil.getBeanInfo(testBean1);
|
||||
Object beanInfo1_5 = ognlUtil.getBeanInfo(testBean1);
|
||||
Object beanInfo1_6 = ognlUtil.getBeanInfo(testBean1);
|
||||
// Cache in effect, so beanInfo1_4, beanInfo1_5, beanInfo1_6 should be the same.
|
||||
assertSame(beanInfo1_4, beanInfo1_5);
|
||||
assertSame(beanInfo1_4, beanInfo1_6);
|
||||
// Cache was cleared in-between, so beanInfo1_1/beanInfo1_2/beanInfo1_3 should differ
|
||||
// from beanInfo1_4/beanInfo1_5/beanInfo1_6.
|
||||
assertNotSame(beanInfo1_1, beanInfo1_4);
|
||||
assertNotSame(beanInfo1_2, beanInfo1_5);
|
||||
assertNotSame(beanInfo1_3, beanInfo1_6);
|
||||
Object beanInfo2_4 = ognlUtil.getBeanInfo(testBean2);
|
||||
Object beanInfo2_5 = ognlUtil.getBeanInfo(testBean2);
|
||||
Object beanInfo2_6 = ognlUtil.getBeanInfo(testBean2);
|
||||
// Cache in effect, so beanInfo2_4, beanInfo2_5, beanInfo2_6 should be the same.
|
||||
assertSame(beanInfo2_4, beanInfo2_5);
|
||||
assertSame(beanInfo2_4, beanInfo2_6);
|
||||
// Cache was cleared in-between, so beanInfo2_1/beanInfo2_2/beanInfo2_3 should differ
|
||||
// from beanInfo2_4/beanInfo2_5/beanInfo2_6.
|
||||
assertNotSame(beanInfo2_1, beanInfo2_4);
|
||||
assertNotSame(beanInfo2_2, beanInfo2_5);
|
||||
assertNotSame(beanInfo2_3, beanInfo2_6);
|
||||
// BeanInfo for TestBean1 and TestBean2 should always be different.
|
||||
assertNotSame(beanInfo1_4, beanInfo2_4);
|
||||
assertTrue("BeanInfo cache empty after usage ?", ognlUtil.beanInfoCacheSize() > 0);
|
||||
}
|
||||
|
||||
public void testClearRuntimeCache() {
|
||||
// Confirm that no exceptions or failures arise when calling the convenience global clear method.
|
||||
OgnlUtil.clearRuntimeCache();
|
||||
}
|
||||
|
||||
public void testCacheDisabled() throws OgnlException {
|
||||
ognlUtil.setEnableExpressionCache("false");
|
||||
Object expr0 = ognlUtil.compile("test");
|
||||
@@ -940,37 +1031,358 @@ public class OgnlUtilTest extends XWorkTestCase {
|
||||
assertEquals(expected.getMessage(), "It isn't a simple method which can be called!");
|
||||
}
|
||||
|
||||
private void reloadTestContainerConfiguration(boolean devMode, boolean allowStatic) throws Exception {
|
||||
super.tearDown();
|
||||
public void testXworkTestCaseOgnlUtilExclusions() throws Exception {
|
||||
internalTestInitialEmptyOgnlUtilExclusions(ognlUtil);
|
||||
internalTestOgnlUtilExclusionsImmutable(ognlUtil);
|
||||
}
|
||||
|
||||
ConfigurationProvider configurationProvider;
|
||||
if (devMode == true && allowStatic == true) {
|
||||
configurationProvider = new XmlConfigurationProvider("com/opensymphony/xwork2/config/providers/xwork-test-allowstatic-devmode-true.xml", true);
|
||||
public void testDefaultOgnlUtilExclusions() throws Exception {
|
||||
OgnlUtil basicOgnlUtil = new OgnlUtil();
|
||||
|
||||
internalTestInitialEmptyOgnlUtilExclusions(basicOgnlUtil);
|
||||
internalTestOgnlUtilExclusionsImmutable(basicOgnlUtil);
|
||||
}
|
||||
|
||||
public void testOgnlUtilExcludedAdditivity() throws Exception {
|
||||
Set<Class<?>> excludedClasses;
|
||||
Set<Pattern> excludedPackageNamePatterns;
|
||||
Iterator<Pattern> excludedPackageNamePatternsIterator;
|
||||
Set<String> excludedPackageNames;
|
||||
Set<String> patternStrings = new HashSet<>();
|
||||
|
||||
ognlUtil.setExcludedClasses("java.lang.String,java.lang.Integer");
|
||||
internalTestOgnlUtilExclusionsImmutable(ognlUtil);
|
||||
excludedClasses = ognlUtil.getExcludedClasses();
|
||||
assertNotNull("initial exluded classes null?", excludedClasses);
|
||||
assertTrue("initial exluded classes size not 2 after adds?", excludedClasses.size() == 2);
|
||||
assertTrue("String not in exclusions?", excludedClasses.contains(String.class));
|
||||
assertTrue("Integer not in exclusions?", excludedClasses.contains(Integer.class));
|
||||
ognlUtil.setExcludedClasses("java.lang.Boolean,java.lang.Double");
|
||||
internalTestOgnlUtilExclusionsImmutable(ognlUtil);
|
||||
excludedClasses = ognlUtil.getExcludedClasses();
|
||||
assertNotNull("updated exluded classes null?", excludedClasses);
|
||||
assertTrue("updated exluded classes size not 4 after adds?", excludedClasses.size() == 4);
|
||||
assertTrue("String not in exclusions?", excludedClasses.contains(String.class));
|
||||
assertTrue("Integer not in exclusions?", excludedClasses.contains(Integer.class));
|
||||
assertTrue("String not in exclusions?", excludedClasses.contains(Boolean.class));
|
||||
assertTrue("Integer not in exclusions?", excludedClasses.contains(Double.class));
|
||||
|
||||
ognlUtil.setExcludedPackageNamePatterns("fakepackage1.*,fakepackage2.*");
|
||||
internalTestOgnlUtilExclusionsImmutable(ognlUtil);
|
||||
excludedPackageNamePatterns = ognlUtil.getExcludedPackageNamePatterns();
|
||||
assertNotNull("initial exluded package name patterns null?", excludedPackageNamePatterns);
|
||||
assertTrue("initial exluded package name patterns size not 2 after adds?", excludedPackageNamePatterns.size() == 2);
|
||||
excludedPackageNamePatternsIterator = excludedPackageNamePatterns.iterator();
|
||||
patternStrings.clear();
|
||||
while (excludedPackageNamePatternsIterator.hasNext()) {
|
||||
Pattern pattern = excludedPackageNamePatternsIterator.next();
|
||||
patternStrings.add(pattern.pattern());
|
||||
}
|
||||
else if (devMode == true && allowStatic == false) {
|
||||
configurationProvider = new XmlConfigurationProvider("com/opensymphony/xwork2/config/providers/xwork-test-devmode-true.xml", true);
|
||||
assertTrue("fakepackage1.* not in exclusions?", patternStrings.contains("fakepackage1.*"));
|
||||
assertTrue("fakepackage2.* not in exclusions?", patternStrings.contains("fakepackage2.*"));
|
||||
ognlUtil.setExcludedPackageNamePatterns("fakepackage3.*,fakepackage4.*");
|
||||
internalTestOgnlUtilExclusionsImmutable(ognlUtil);
|
||||
excludedPackageNamePatterns = ognlUtil.getExcludedPackageNamePatterns();
|
||||
assertNotNull("updated exluded package name patterns null?", excludedPackageNamePatterns);
|
||||
assertTrue("updated exluded package name patterns size not 4 after adds?", excludedPackageNamePatterns.size() == 4);
|
||||
excludedPackageNamePatternsIterator = excludedPackageNamePatterns.iterator();
|
||||
patternStrings.clear();
|
||||
while (excludedPackageNamePatternsIterator.hasNext()) {
|
||||
Pattern pattern = excludedPackageNamePatternsIterator.next();
|
||||
patternStrings.add(pattern.pattern());
|
||||
}
|
||||
else if (devMode == false && allowStatic == true) {
|
||||
configurationProvider = new XmlConfigurationProvider("com/opensymphony/xwork2/config/providers/xwork-test-allowstatic-true.xml", true);
|
||||
assertTrue("fakepackage1.* not in exclusions?", patternStrings.contains("fakepackage1.*"));
|
||||
assertTrue("fakepackage2.* not in exclusions?", patternStrings.contains("fakepackage2.*"));
|
||||
assertTrue("fakepackage3.* not in exclusions?", patternStrings.contains("fakepackage3.*"));
|
||||
assertTrue("fakepackage4.* not in exclusions?", patternStrings.contains("fakepackage4.*"));
|
||||
|
||||
ognlUtil.setExcludedPackageNames("fakepackage1.package,fakepackage2.package");
|
||||
internalTestOgnlUtilExclusionsImmutable(ognlUtil);
|
||||
excludedPackageNames = ognlUtil.getExcludedPackageNames();
|
||||
assertNotNull("initial exluded package names null?", excludedPackageNames);
|
||||
assertTrue("initial exluded package names not 2 after adds?", excludedPackageNames.size() == 2);
|
||||
assertTrue("fakepackage1.package not in exclusions?", excludedPackageNames.contains("fakepackage1.package"));
|
||||
assertTrue("fakepackage2.package not in exclusions?", excludedPackageNames.contains("fakepackage2.package"));
|
||||
ognlUtil.setExcludedPackageNames("fakepackage3.package,fakepackage4.package");
|
||||
internalTestOgnlUtilExclusionsImmutable(ognlUtil);
|
||||
excludedPackageNames = ognlUtil.getExcludedPackageNames();
|
||||
assertNotNull("updated exluded package names null?", excludedPackageNames);
|
||||
assertTrue("updated exluded package names not 4 after adds?", excludedPackageNames.size() == 4);
|
||||
assertTrue("fakepackage1.package not in exclusions?", excludedPackageNames.contains("fakepackage1.package"));
|
||||
assertTrue("fakepackage2.package not in exclusions?", excludedPackageNames.contains("fakepackage2.package"));
|
||||
assertTrue("fakepackage3.package not in exclusions?", excludedPackageNames.contains("fakepackage3.package"));
|
||||
assertTrue("fakepackage4.package not in exclusions?", excludedPackageNames.contains("fakepackage4.package"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure getValue permits public static field access, but prevents non-public static field access
|
||||
*/
|
||||
public void testStaticFieldGetValue() {
|
||||
OgnlContext context = null;
|
||||
Object accessedValue;
|
||||
|
||||
try {
|
||||
reloadTestContainerConfiguration(false, false); // Test with allow static methods false
|
||||
context = (OgnlContext) ognlUtil.createDefaultContext(null);
|
||||
} catch (Exception ex) {
|
||||
fail("unable to reload test configuration? Exception: " + ex);
|
||||
}
|
||||
else { // devMode, allowStatic both false
|
||||
configurationProvider = new XmlConfigurationProvider("com/opensymphony/xwork2/config/providers/xwork-test-allowstatic-devmode-false.xml", true);
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_FINAL_PUBLIC_ATTRIBUTE", context, null);
|
||||
assertEquals("accessed field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
|
||||
} catch (Exception ex) {
|
||||
fail("static final public field access failed ? Exception: " + ex);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_PUBLIC_ATTRIBUTE", context, null);
|
||||
assertEquals("accessed field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
|
||||
} catch (Exception ex) {
|
||||
fail("static public field access failed ? Exception: " + ex);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_FINAL_PACKAGE_ATTRIBUTE", context, null);
|
||||
fail("static final package field access succeeded?");
|
||||
} catch (Exception ex) {
|
||||
assertTrue("Exception not an OgnlException?", ex instanceof OgnlException);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_PACKAGE_ATTRIBUTE", context, null);
|
||||
fail("static package field access succeeded?");
|
||||
} catch (Exception ex) {
|
||||
assertTrue("Exception not an OgnlException?", ex instanceof OgnlException);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_FINAL_PROTECTED_ATTRIBUTE", context, null);
|
||||
fail("static final protected field access succeeded?");
|
||||
} catch (Exception ex) {
|
||||
assertTrue("Exception not an OgnlException?", ex instanceof OgnlException);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_PROTECTED_ATTRIBUTE", context, null);
|
||||
fail("static protected field access succeeded?");
|
||||
} catch (Exception ex) {
|
||||
assertTrue("Exception not an OgnlException?", ex instanceof OgnlException);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_FINAL_PRIVATE_ATTRIBUTE", context, null);
|
||||
fail("static final private field access succeeded?");
|
||||
} catch (Exception ex) {
|
||||
assertTrue("Exception not an OgnlException?", ex instanceof OgnlException);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_PRIVATE_ATTRIBUTE", context, null);
|
||||
fail("static private field access succeeded?");
|
||||
} catch (Exception ex) {
|
||||
assertTrue("Exception not an OgnlException?", ex instanceof OgnlException);
|
||||
}
|
||||
|
||||
configurationManager = new ConfigurationManager(Container.DEFAULT_NAME);
|
||||
configurationManager.addContainerProvider(configurationProvider);
|
||||
configuration = configurationManager.getConfiguration();
|
||||
container = configuration.getContainer();
|
||||
container.inject(configurationProvider);
|
||||
configurationProvider.init(configuration);
|
||||
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
|
||||
try {
|
||||
reloadTestContainerConfiguration(false, true); // Re-test with allow static methods true
|
||||
context = (OgnlContext) ognlUtil.createDefaultContext(null);
|
||||
} catch (Exception ex) {
|
||||
fail("unable to reload test configuration? Exception: " + ex);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_FINAL_PUBLIC_ATTRIBUTE", context, null);
|
||||
assertEquals("accessed value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
|
||||
} catch (Exception ex) {
|
||||
fail("static final public field access failed ? Exception: " + ex);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_PUBLIC_ATTRIBUTE", context, null);
|
||||
assertEquals("accessed value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
|
||||
} catch (Exception ex) {
|
||||
fail("static public field access failed ? Exception: " + ex);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_FINAL_PACKAGE_ATTRIBUTE", context, null);
|
||||
fail("static final package field access succeeded?");
|
||||
} catch (Exception ex) {
|
||||
assertTrue("Exception not an OgnlException?", ex instanceof OgnlException);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_PACKAGE_ATTRIBUTE", context, null);
|
||||
fail("static package field access succeeded?");
|
||||
} catch (Exception ex) {
|
||||
assertTrue("Exception not an OgnlException?", ex instanceof OgnlException);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_FINAL_PROTECTED_ATTRIBUTE", context, null);
|
||||
fail("static final protected field access succeeded?");
|
||||
} catch (Exception ex) {
|
||||
assertTrue("Exception not an OgnlException?", ex instanceof OgnlException);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_PROTECTED_ATTRIBUTE", context, null);
|
||||
fail("static protected field access succeeded?");
|
||||
} catch (Exception ex) {
|
||||
assertTrue("Exception not an OgnlException?", ex instanceof OgnlException);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_FINAL_PRIVATE_ATTRIBUTE", context, null);
|
||||
fail("static final private field access succeeded?");
|
||||
} catch (Exception ex) {
|
||||
assertTrue("Exception not an OgnlException?", ex instanceof OgnlException);
|
||||
}
|
||||
try {
|
||||
accessedValue = ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_PRIVATE_ATTRIBUTE", context, null);
|
||||
fail("static private field access succeeded?");
|
||||
} catch (Exception ex) {
|
||||
assertTrue("Exception not an OgnlException?", ex instanceof OgnlException);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the value stack
|
||||
ValueStack stack = container.getInstance(ValueStackFactory.class).createValueStack();
|
||||
stack.getContext().put(ActionContext.CONTAINER, container);
|
||||
ActionContext.setContext(new ActionContext(stack.getContext()));
|
||||
/**
|
||||
* Test OGNL Expression Max Length feature setting via OgnlUtil is disabled by default (in default.properties).
|
||||
*
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public void testDefaultExpressionMaxLengthDisabled() {
|
||||
final String LONG_OGNL_EXPRESSION = "true == ThisIsAReallyLongOGNLExpressionOfRepeatedGarbageText." + new String(new char[65535]).replace('\0', 'A'); // Expression larger than 64KB.
|
||||
try {
|
||||
Object compileResult = ognlUtil.compile(LONG_OGNL_EXPRESSION);
|
||||
assertNotNull("Long OGNL expression compilation produced a null result ?", compileResult);
|
||||
} catch (OgnlException oex) {
|
||||
if (oex.getReason() instanceof SecurityException) {
|
||||
fail ("Unable to compile expression (unexpected). 'struts.ognl.expressionMaxLength' may have accidentally been enabled by default. Exception: " + oex);
|
||||
} else {
|
||||
fail ("Unable to compile expression (unexpected). Exception: " + oex);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
fail ("Unable to compile expression (unexpected). Exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
ognlUtil = container.getInstance(OgnlUtil.class);
|
||||
/**
|
||||
* Test OGNL Expression Max Length feature setting via OgnlUtil.
|
||||
*
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public void testApplyExpressionMaxLength() {
|
||||
try {
|
||||
try {
|
||||
ognlUtil.applyExpressionMaxLength(null);
|
||||
} catch (Exception ex) {
|
||||
fail ("applyExpressionMaxLength did not accept null maxlength string (disable feature) ?");
|
||||
}
|
||||
try {
|
||||
ognlUtil.applyExpressionMaxLength("");
|
||||
} catch (Exception ex) {
|
||||
fail ("applyExpressionMaxLength did not accept empty maxlength string (disable feature) ?");
|
||||
}
|
||||
try {
|
||||
ognlUtil.applyExpressionMaxLength("-1");
|
||||
fail ("applyExpressionMaxLength accepted negative maxlength string ?");
|
||||
} catch (IllegalArgumentException iae) {
|
||||
// Expected rejection of -ive length.
|
||||
}
|
||||
try {
|
||||
ognlUtil.applyExpressionMaxLength("0");
|
||||
} catch (Exception ex) {
|
||||
fail ("applyExpressionMaxLength did not accept maxlength string 0 ?");
|
||||
}
|
||||
try {
|
||||
ognlUtil.applyExpressionMaxLength(Integer.toString(Integer.MAX_VALUE, 10));
|
||||
} catch (Exception ex) {
|
||||
fail ("applyExpressionMaxLength did not accept MAX_VALUE maxlength string ?");
|
||||
}
|
||||
} finally {
|
||||
// Reset expressionMaxLength value to default (disabled)
|
||||
ognlUtil.applyExpressionMaxLength(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void internalTestInitialEmptyOgnlUtilExclusions(OgnlUtil ognlUtilParam) throws Exception {
|
||||
Set<Class<?>> excludedClasses = ognlUtilParam.getExcludedClasses();
|
||||
assertNotNull("parameter (default) exluded classes null?", excludedClasses);
|
||||
assertTrue("parameter (default) exluded classes not empty?", excludedClasses.isEmpty());
|
||||
|
||||
Set<Pattern> excludedPackageNamePatterns = ognlUtilParam.getExcludedPackageNamePatterns();
|
||||
assertNotNull("parameter (default) exluded package name patterns null?", excludedPackageNamePatterns);
|
||||
assertTrue("parameter (default) exluded package name patterns not empty?", excludedPackageNamePatterns.isEmpty());
|
||||
|
||||
Set<String> excludedPackageNames = ognlUtilParam.getExcludedPackageNames();
|
||||
assertNotNull("parameter (default) exluded package names null?", excludedPackageNames);
|
||||
assertTrue("parameter (default) exluded package names not empty?", excludedPackageNames.isEmpty());
|
||||
}
|
||||
|
||||
private void internalTestOgnlUtilExclusionsImmutable(OgnlUtil ognlUtilParam) throws Exception {
|
||||
Pattern somePattern = Pattern.compile("SomeRegexPattern");
|
||||
Set<Class<?>> excludedClasses = ognlUtilParam.getExcludedClasses();
|
||||
assertNotNull("parameter exluded classes null?", excludedClasses);
|
||||
try {
|
||||
excludedClasses.clear();
|
||||
fail("parameter excluded classes modifiable?");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected failure
|
||||
}
|
||||
try {
|
||||
excludedClasses.add(Integer.class);
|
||||
fail("parameter excluded classes modifiable?");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected failure
|
||||
}
|
||||
try {
|
||||
excludedClasses.remove(Integer.class);
|
||||
fail("parameter excluded classes modifiable?");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected failure
|
||||
}
|
||||
|
||||
Set<Pattern> excludedPackageNamePatterns = ognlUtilParam.getExcludedPackageNamePatterns();
|
||||
assertNotNull("parameter exluded package name patterns null?", excludedPackageNamePatterns);
|
||||
try {
|
||||
excludedPackageNamePatterns.clear();
|
||||
fail("parameter excluded package name patterns modifiable?");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected failure
|
||||
}
|
||||
try {
|
||||
excludedPackageNamePatterns.add(somePattern);
|
||||
fail("parameter excluded package name patterns modifiable?");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected failure
|
||||
}
|
||||
try {
|
||||
excludedPackageNamePatterns.remove(somePattern);
|
||||
fail("parameter excluded package name patterns modifiable?");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected failure
|
||||
}
|
||||
|
||||
Set<String> excludedPackageNames = ognlUtilParam.getExcludedPackageNames();
|
||||
assertNotNull("parameter exluded package names null?", excludedPackageNames);
|
||||
try {
|
||||
excludedPackageNames.clear();
|
||||
fail("parameter excluded package names modifiable?");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected failure
|
||||
}
|
||||
try {
|
||||
excludedPackageNames.add("somepackagename");
|
||||
fail("parameter excluded package names modifiable?");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected failure
|
||||
}
|
||||
try {
|
||||
excludedPackageNames.remove("somepackagename");
|
||||
fail("parameter excluded package names modifiable?");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
// Expected failure
|
||||
}
|
||||
}
|
||||
|
||||
private void reloadTestContainerConfiguration(final boolean devMode, final boolean allowStatic) throws Exception {
|
||||
loadConfigurationProviders(new StubConfigurationProvider() {
|
||||
@Override
|
||||
public void register(ContainerBuilder builder,
|
||||
LocatableProperties props) throws ConfigurationException {
|
||||
props.setProperty(StrutsConstants.STRUTS_DEVMODE, "" + devMode);
|
||||
props.setProperty(XWorkConstants.DEV_MODE, "" + devMode);
|
||||
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, "" + allowStatic);
|
||||
props.setProperty(XWorkConstants.ALLOW_STATIC_METHOD_ACCESS, "" + allowStatic);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static class Email {
|
||||
@@ -1060,4 +1472,37 @@ public class OgnlUtilTest extends XWorkTestCase {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestBean1 {
|
||||
private String testBeanProperty;
|
||||
|
||||
public TestBean1() {
|
||||
testBeanProperty = "defaultTestBean1Property";
|
||||
}
|
||||
|
||||
public String getTestBeanProperty() {
|
||||
return testBeanProperty;
|
||||
}
|
||||
|
||||
public void setTestBeanProperty(String testBeanProperty) {
|
||||
this.testBeanProperty = testBeanProperty;
|
||||
}
|
||||
}
|
||||
|
||||
class TestBean2 {
|
||||
private String testBeanProperty;
|
||||
|
||||
public TestBean2() {
|
||||
testBeanProperty = "defaultTestBean2Property";
|
||||
}
|
||||
|
||||
public String getTestBeanProperty() {
|
||||
return testBeanProperty;
|
||||
}
|
||||
|
||||
public void setTestBeanProperty(String testBeanProperty) {
|
||||
this.testBeanProperty = testBeanProperty;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,23 +19,36 @@
|
||||
package com.opensymphony.xwork2.ognl;
|
||||
|
||||
import com.opensymphony.xwork2.*;
|
||||
import com.opensymphony.xwork2.config.ConfigurationManager;
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
|
||||
import com.opensymphony.xwork2.test.StubConfigurationProvider;
|
||||
import com.opensymphony.xwork2.test.TestBean2;
|
||||
import com.opensymphony.xwork2.util.*;
|
||||
import com.opensymphony.xwork2.util.Foo;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
|
||||
import ognl.OgnlException;
|
||||
import ognl.PropertyAccessor;
|
||||
|
||||
import java.io.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import ognl.ParseException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.core.LogEvent;
|
||||
import org.apache.logging.log4j.core.Logger;
|
||||
import org.apache.logging.log4j.core.appender.AbstractAppender;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.config.DefaultPropertiesProvider;
|
||||
|
||||
|
||||
/**
|
||||
@@ -43,10 +56,25 @@ import java.util.Map;
|
||||
*/
|
||||
public class OgnlValueStackTest extends XWorkTestCase {
|
||||
|
||||
// Fields for static field access test
|
||||
public static final String STATIC_FINAL_PUBLIC_ATTRIBUTE = "Static_Final_Public_Attribute";
|
||||
static final String STATIC_FINAL_PACKAGE_ATTRIBUTE = "Static_Final_Package_Attribute";
|
||||
protected static final String STATIC_FINAL_PROTECTED_ATTRIBUTE = "Static_Final_Protected_Attribute";
|
||||
private static final String STATIC_FINAL_PRIVATE_ATTRIBUTE = "Static_Final_Private_Attribute";
|
||||
public static String STATIC_PUBLIC_ATTRIBUTE = "Static_Public_Attribute";
|
||||
static String STATIC_PACKAGE_ATTRIBUTE = "Static_Package_Attribute";
|
||||
protected static String STATIC_PROTECTED_ATTRIBUTE = "Static_Protected_Attribute";
|
||||
private static String STATIC_PRIVATE_ATTRIBUTE = "Static_Private_Attribute";
|
||||
|
||||
|
||||
public static Integer staticNullMethod() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Integer staticInteger100Method() {
|
||||
return 100;
|
||||
}
|
||||
|
||||
private OgnlUtil ognlUtil;
|
||||
|
||||
@Override
|
||||
@@ -69,6 +97,33 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
return stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return current OgnlValueStackFactory instance from current container
|
||||
*/
|
||||
private OgnlValueStackFactory getValueStackFactory() {
|
||||
return (OgnlValueStackFactory) container.getInstance(ValueStackFactory.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads container and gets a new OgnlValueStackFactory with specified new configuration.
|
||||
* Intended for testing OgnlValueStack instance(s) that are minimally configured.
|
||||
* This should help ensure no underlying configuration/injection side-effects are responsible
|
||||
* for the behaviour of fundamental access control flags).
|
||||
*
|
||||
* @param allowStaticMethod new allowStaticMethod configuration
|
||||
* @return a new OgnlValueStackFactory with specified new configuration
|
||||
*/
|
||||
private OgnlValueStackFactory reloadValueStackFactory(Boolean allowStaticMethod) {
|
||||
try {
|
||||
reloadTestContainerConfiguration(allowStaticMethod);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
fail("Unable to reload container configuration and configure ognlValueStackFactory - exception: " + ex);
|
||||
}
|
||||
|
||||
return getValueStackFactory();
|
||||
}
|
||||
|
||||
public void testExpOverridesCanStackExpUp() throws Exception {
|
||||
Map expr1 = new LinkedHashMap();
|
||||
expr1.put("expr1", "'expr1value'");
|
||||
@@ -194,6 +249,95 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* monitors the resolution of WW-4999
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public void testLogMissingProperties() {
|
||||
testLogMissingProperties(true);
|
||||
testLogMissingProperties(false);
|
||||
}
|
||||
|
||||
private void testLogMissingProperties(boolean logMissingProperties) {
|
||||
OgnlValueStack vs = createValueStack();
|
||||
vs.setLogMissingProperties("" + logMissingProperties);
|
||||
|
||||
Dog dog = new Dog();
|
||||
vs.push(dog);
|
||||
|
||||
TestAppender testAppender = new TestAppender();
|
||||
Logger logger = (Logger) LogManager.getLogger(OgnlValueStack.class);
|
||||
logger.addAppender(testAppender);
|
||||
testAppender.start();
|
||||
|
||||
try {
|
||||
vs.setValue("missingProp1", "missingProp1Value", false);
|
||||
vs.findValue("missingProp2", false);
|
||||
vs.findValue("missingProp3", Integer.class, false);
|
||||
|
||||
if (logMissingProperties) {
|
||||
assertEquals(3, testAppender.logEvents.size());
|
||||
assertEquals("Error setting value [missingProp1Value] with expression [missingProp1]",
|
||||
testAppender.logEvents.get(0).getMessage().getFormattedMessage());
|
||||
assertEquals("Could not find property [missingProp2]!",
|
||||
testAppender.logEvents.get(1).getMessage().getFormattedMessage());
|
||||
assertEquals("Could not find property [missingProp3]!",
|
||||
testAppender.logEvents.get(2).getMessage().getFormattedMessage());
|
||||
} else {
|
||||
assertEquals(0, testAppender.logEvents.size());
|
||||
}
|
||||
} finally {
|
||||
testAppender.stop();
|
||||
logger.removeAppender(testAppender);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tests the correctness of distinguishing between user exception and NoSuchMethodException
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public void testNotLogUserExceptionsAsMissingProperties() {
|
||||
OgnlValueStack vs = createValueStack();
|
||||
vs.setLogMissingProperties("true");
|
||||
|
||||
Dog dog = new Dog();
|
||||
vs.push(dog);
|
||||
|
||||
TestAppender testAppender = new TestAppender();
|
||||
Logger logger = (Logger) LogManager.getLogger(OgnlValueStack.class);
|
||||
logger.addAppender(testAppender);
|
||||
testAppender.start();
|
||||
|
||||
try {
|
||||
vs.setValue("exception", "exceptionValue", false);
|
||||
vs.findValue("exception", false);
|
||||
vs.findValue("exception", String.class, false);
|
||||
vs.findValue("getException()", false);
|
||||
vs.findValue("getException()", String.class, false);
|
||||
vs.findValue("bite", false);
|
||||
vs.findValue("bite", void.class, false);
|
||||
vs.findValue("getBite()", false);
|
||||
vs.findValue("getBite()", void.class, false);
|
||||
|
||||
vs.setLogMissingProperties("false");
|
||||
|
||||
vs.setValue("exception", "exceptionValue", false);
|
||||
vs.findValue("exception", false);
|
||||
vs.findValue("exception", String.class, false);
|
||||
vs.findValue("getException()", false);
|
||||
vs.findValue("getException()", String.class, false);
|
||||
vs.findValue("bite", false);
|
||||
vs.findValue("bite", void.class, false);
|
||||
vs.findValue("getBite()", false);
|
||||
vs.findValue("getBite()", void.class, false);
|
||||
|
||||
assertEquals(0, testAppender.logEvents.size());
|
||||
} finally {
|
||||
testAppender.stop();
|
||||
logger.removeAppender(testAppender);
|
||||
}
|
||||
}
|
||||
|
||||
public void testFailOnMissingMethod() {
|
||||
OgnlValueStack vs = createValueStack();
|
||||
|
||||
@@ -207,6 +351,96 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testFailOnTooLongExpressionLongerThan192_ViaOverriddenProperty() {
|
||||
try {
|
||||
loadConfigurationProviders(new StubConfigurationProvider() {
|
||||
@Override
|
||||
public void register(ContainerBuilder builder,
|
||||
LocatableProperties props) throws ConfigurationException {
|
||||
props.setProperty(StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH, "192");
|
||||
}
|
||||
});
|
||||
Integer repeat = Integer.parseInt(
|
||||
container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH));
|
||||
|
||||
OgnlValueStack vs = createValueStack();
|
||||
try {
|
||||
vs.findValue(StringUtils.repeat('.', repeat + 1), true);
|
||||
fail("Failed to throw exception on too long expression");
|
||||
} catch (Exception ex) {
|
||||
assertTrue(ex.getCause() instanceof OgnlException);
|
||||
assertTrue(((OgnlException) ex.getCause()).getReason() instanceof SecurityException);
|
||||
}
|
||||
} finally {
|
||||
// Reset expressionMaxLength value to default (disabled)
|
||||
ognlUtil.applyExpressionMaxLength(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void testNotFailOnTooLongExpressionWithDefaultProperties() {
|
||||
loadConfigurationProviders(new DefaultPropertiesProvider());
|
||||
|
||||
Object defaultMaxLengthFromConfiguration = container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH);
|
||||
if (defaultMaxLengthFromConfiguration != null) {
|
||||
assertTrue("non-null defaultMaxLengthFromConfiguration not a String ?", defaultMaxLengthFromConfiguration instanceof String);
|
||||
assertTrue("non-null defaultMaxLengthFromConfiguration not empty string by default ?", ((String) defaultMaxLengthFromConfiguration).length() == 0);
|
||||
} else {
|
||||
assertNull("defaultMaxLengthFromConfiguration not null ?", defaultMaxLengthFromConfiguration);
|
||||
}
|
||||
// Original test logic was to confirm failure of exceeding the default value. Now the feature should be disabled by default,
|
||||
// so this test's expectations are now changed.
|
||||
Integer repeat = Integer.valueOf(256); // Since maxlength is disabled by default, just choose an arbitrary value for test
|
||||
|
||||
OgnlValueStack vs = createValueStack();
|
||||
try {
|
||||
vs.findValue(StringUtils.repeat('.', repeat + 1), true);
|
||||
fail("findValue did not throw any exception (should either fail as invalid expression syntax or security exception) ?");
|
||||
} catch (Exception ex) {
|
||||
// If STRUTS_OGNL_EXPRESSION_MAX_LENGTH feature is disabled (default), the parse should fail due to a reason of invalid expression syntax
|
||||
// with ParseException. Previously when it was enabled the reason for the failure would have been SecurityException.
|
||||
assertTrue(ex.getCause() instanceof OgnlException);
|
||||
assertTrue(((OgnlException) ex.getCause()).getReason() instanceof ParseException);
|
||||
}
|
||||
}
|
||||
|
||||
public void testNotFailOnTooLongValueWithDefaultProperties() {
|
||||
try {
|
||||
loadConfigurationProviders(new DefaultPropertiesProvider());
|
||||
|
||||
Object defaultMaxLengthFromConfiguration = container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH);
|
||||
if (defaultMaxLengthFromConfiguration != null) {
|
||||
assertTrue("non-null defaultMaxLengthFromConfiguration not a String ?", defaultMaxLengthFromConfiguration instanceof String);
|
||||
assertTrue("non-null defaultMaxLengthFromConfiguration not empty string by default ?", ((String) defaultMaxLengthFromConfiguration).length() == 0);
|
||||
} else {
|
||||
assertNull("defaultMaxLengthFromConfiguration not null ?", defaultMaxLengthFromConfiguration);
|
||||
}
|
||||
// Original test logic is unchanged (testing that values can be larger than maximum expression length), but since the feature is disabled by
|
||||
// default we will now have to enable it with an arbitrary value, test, and reset it to disabled.
|
||||
Integer repeat = Integer.valueOf(256); // Since maxlength is disabled by default, just choose an arbitrary value for test
|
||||
|
||||
// Apply a non-default value for expressionMaxLength (as it should be disabled by default)
|
||||
try {
|
||||
ognlUtil.applyExpressionMaxLength(repeat.toString());
|
||||
} catch (Exception ex) {
|
||||
fail ("applyExpressionMaxLength did not accept maxlength string " + repeat.toString() + " ?");
|
||||
}
|
||||
|
||||
OgnlValueStack vs = createValueStack();
|
||||
|
||||
Dog dog = new Dog();
|
||||
vs.push(dog);
|
||||
|
||||
String value = StringUtils.repeat('.', repeat + 1);
|
||||
|
||||
vs.setValue("name", value);
|
||||
|
||||
assertEquals(value, dog.getName());
|
||||
} finally {
|
||||
// Reset expressionMaxLength value to default (disabled)
|
||||
ognlUtil.applyExpressionMaxLength(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void testFailsOnMethodThatThrowsException() {
|
||||
SimpleAction action = new SimpleAction();
|
||||
OgnlValueStack stack = createValueStack();
|
||||
@@ -580,7 +814,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
OgnlValueStack stack = createValueStack();
|
||||
stack.push(dog);
|
||||
assertNull(stack.findValue("nullMethod()"));
|
||||
assertNull(stack.findValue("@com.opensymphony.xwork2.util.OgnlValueStackTest@staticNullMethod()"));
|
||||
assertNull(stack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticNullMethod()"));
|
||||
}
|
||||
|
||||
public void testPetSoarBug() {
|
||||
@@ -835,6 +1069,49 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
assertNull(vs.findValue("@com.nothing.here.Nothing@BLAH"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fails on 2.5.20 and earlier - tested on 2.5 (5/5/2016) and failed
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public void testNotThrowExceptionOnTopMissingProperty() {
|
||||
OgnlValueStack vs = createValueStack();
|
||||
|
||||
Dog dog = new Dog();
|
||||
dog.setName("Rover");
|
||||
vs.push(dog);
|
||||
|
||||
Cat cat = new Cat();
|
||||
vs.push(cat);
|
||||
|
||||
vs.setValue("age", 12, true);
|
||||
|
||||
assertEquals(12, vs.findValue("age", true));
|
||||
assertEquals(12, vs.findValue("age", Integer.class, true));
|
||||
assertEquals(12, vs.findValue("getAge()", true));
|
||||
assertEquals(12, vs.findValue("getAge()", Integer.class, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fails on 2.5.20 and earlier - tested on 2.5 (5/5/2016) and failed
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public void testNotSkipUserReturnedNullValues() {
|
||||
OgnlValueStack vs = createValueStack();
|
||||
|
||||
Dog dog = new Dog();
|
||||
dog.setName("Rover");
|
||||
vs.push(dog);
|
||||
|
||||
Cat cat = new Cat();
|
||||
vs.push(cat);
|
||||
|
||||
// should not skip returned null values from cat.name
|
||||
assertNull(vs.findValue("name", true));
|
||||
assertNull(vs.findValue("name", String.class, true));
|
||||
assertNull(vs.findValue("getName()", true));
|
||||
assertNull(vs.findValue("getName()", String.class, true));
|
||||
}
|
||||
|
||||
public void testTop() {
|
||||
OgnlValueStack vs = createValueStack();
|
||||
|
||||
@@ -972,36 +1249,170 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
assertEquals(null, stack.findValue("address.country.name", String.class));
|
||||
}
|
||||
|
||||
private void reloadTestContainerConfiguration(boolean devMode, boolean allowStatic) throws Exception {
|
||||
super.tearDown();
|
||||
/**
|
||||
* Test a default OgnlValueStackFactory and OgnlValueStack generated by it
|
||||
* when a default configuration is used.
|
||||
*/
|
||||
public void testOgnlValueStackFromOgnlValueStackFactoryDefaultConfig() {
|
||||
OgnlValueStackFactory ognlValueStackFactory = getValueStackFactory();
|
||||
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
|
||||
Object accessedValue;
|
||||
|
||||
ConfigurationProvider configurationProvider;
|
||||
if (devMode == true && allowStatic == true) {
|
||||
configurationProvider = new XmlConfigurationProvider("com/opensymphony/xwork2/config/providers/xwork-test-allowstatic-devmode-true.xml", true);
|
||||
}
|
||||
else if (devMode == true && allowStatic == false) {
|
||||
configurationProvider = new XmlConfigurationProvider("com/opensymphony/xwork2/config/providers/xwork-test-devmode-true.xml", true);
|
||||
}
|
||||
else if (devMode == false && allowStatic == true) {
|
||||
configurationProvider = new XmlConfigurationProvider("com/opensymphony/xwork2/config/providers/xwork-test-allowstatic-true.xml", true);
|
||||
}
|
||||
else { // devMode, allowStatic both false
|
||||
configurationProvider = new XmlConfigurationProvider("com/opensymphony/xwork2/config/providers/xwork-test-allowstatic-devmode-false.xml", true);
|
||||
}
|
||||
// An OgnlValueStackFactory using a container config with default (from XWorkConfigurationProvider)
|
||||
// static method access flag value present should prevent staticMethodAccess but allow staticFieldAccess.
|
||||
assertFalse("OgnlValueStackFactory staticMethodAccess (default flag) not false?", containerAllowsStaticMethodAccess(ognlValueStackFactory.container));
|
||||
// An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
|
||||
// but prevent non-public field access. It should also deny static method access.
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
|
||||
assertNull("able to access static method (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
|
||||
assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
|
||||
assertEquals("accessed static public field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
|
||||
assertNull("accessed final package field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
|
||||
assertNull("accessed package field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
|
||||
assertNull("accessed final protected field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
|
||||
assertNull("accessed protected field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
|
||||
assertNull("accessed final private field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
|
||||
assertNull("accessed private field (result not null) ?", accessedValue);
|
||||
}
|
||||
|
||||
configurationManager = new ConfigurationManager(Container.DEFAULT_NAME);
|
||||
configurationManager.addContainerProvider(configurationProvider);
|
||||
configuration = configurationManager.getConfiguration();
|
||||
container = configuration.getContainer();
|
||||
container.inject(configurationProvider);
|
||||
configurationProvider.init(configuration);
|
||||
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
|
||||
/**
|
||||
* Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
|
||||
* when no static method access flag is set (not present in configuration).
|
||||
*/
|
||||
public void testOgnlValueStackFromOgnlValueStackFactoryNoFlagsSet() {
|
||||
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(null);
|
||||
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
|
||||
Object accessedValue;
|
||||
|
||||
// Reset the value stack
|
||||
ValueStack stack = container.getInstance(ValueStackFactory.class).createValueStack();
|
||||
stack.getContext().put(ActionContext.CONTAINER, container);
|
||||
ActionContext.setContext(new ActionContext(stack.getContext()));
|
||||
// An OgnlValueStackFactory using a container config with no static method access flag value present
|
||||
// (such as from a DefaultConfiguration vs. XWorkConfigurationProvider) should
|
||||
// prevent staticMethodAccess and allow staticFieldAccess.
|
||||
// Note: Under normal circumstances, explicit static method access configuration flag should be present,
|
||||
// but this specific check verifies what happens if that configuration flags is not present.
|
||||
assertFalse("OgnlValueStackFactory staticMethodAccess (no flag present) not false?", containerAllowsStaticMethodAccess(ognlValueStackFactory.container));
|
||||
// An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
|
||||
// and prevent non-public field access. It should also deny static method access.
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
|
||||
assertNull("able to access static method (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
|
||||
assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
|
||||
assertEquals("accessed static public field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
|
||||
assertNull("accessed final package field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
|
||||
assertNull("accessed package field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
|
||||
assertNull("accessed final protected field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
|
||||
assertNull("accessed protected field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
|
||||
assertNull("accessed final private field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
|
||||
assertNull("accessed private field (result not null) ?", accessedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
|
||||
* when static method access flag is set to false.
|
||||
*/
|
||||
public void testOgnlValueStackFromOgnlValueStackFactoryNoStaticMethodAccess() {
|
||||
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(false);
|
||||
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
|
||||
Object accessedValue;
|
||||
|
||||
// An OgnlValueStackFactory using a container config with static method access flag set false should
|
||||
// prevent staticMethodAccess and allow staticFieldAccess.
|
||||
assertFalse("OgnlValueStackFactory staticMethodAccess (set false) not false?", containerAllowsStaticMethodAccess(ognlValueStackFactory.container));
|
||||
// An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
|
||||
// and prevent non-public field access. It should also deny static method access.
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
|
||||
assertNull("able to access static method (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
|
||||
assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
|
||||
assertEquals("accessed static public field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
|
||||
assertNull("accessed final package field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
|
||||
assertNull("accessed package field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
|
||||
assertNull("accessed final protected field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
|
||||
assertNull("accessed protected field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
|
||||
assertNull("accessed final private field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
|
||||
assertNull("accessed private field (result not null) ?", accessedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
|
||||
* when static method access flag set to true.
|
||||
*/
|
||||
public void testOgnlValueStackFromOgnlValueStackFactoryStaticMethodAccess() {
|
||||
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(true);
|
||||
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
|
||||
Object accessedValue;
|
||||
|
||||
// An OgnlValueStackFactory using a container config with static method access flag set true should
|
||||
// allow both staticMethodAccess and staticFieldAccess.
|
||||
assertTrue("OgnlValueStackFactory staticMethodAccess (set true) not true?", containerAllowsStaticMethodAccess(ognlValueStackFactory.container));
|
||||
// An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
|
||||
// but prevent non-public field access. It should also allow static method access.
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
|
||||
assertNotNull("unable to access static method (result null) ?", accessedValue);
|
||||
assertEquals("accessed static method result not equal to expected?", accessedValue, staticInteger100Method());
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
|
||||
assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
|
||||
assertEquals("accessed static public field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
|
||||
assertNull("accessed final package field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
|
||||
assertNull("accessed package field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
|
||||
assertNull("accessed final protected field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
|
||||
assertNull("accessed protected field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
|
||||
assertNull("accessed final private field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
|
||||
assertNull("accessed private field (result not null) ?", accessedValue);
|
||||
}
|
||||
|
||||
protected boolean containerAllowsStaticMethodAccess(Container checkContainer) {
|
||||
return Boolean.parseBoolean(checkContainer.getInstance(String.class, XWorkConstants.ALLOW_STATIC_METHOD_ACCESS));
|
||||
}
|
||||
|
||||
private void reloadTestContainerConfiguration(final Boolean allowStaticMethod) throws Exception {
|
||||
loadConfigurationProviders(new StubConfigurationProvider() {
|
||||
@Override
|
||||
public void register(ContainerBuilder builder,
|
||||
LocatableProperties props) throws ConfigurationException {
|
||||
// null values simulate undefined (by removing).
|
||||
// undefined values then should be evaluated to false
|
||||
if (props.containsKey(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS)) {
|
||||
props.remove(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS);
|
||||
}
|
||||
if (props.containsKey(XWorkConstants.ALLOW_STATIC_METHOD_ACCESS)) {
|
||||
props.remove(XWorkConstants.ALLOW_STATIC_METHOD_ACCESS);
|
||||
}
|
||||
if (allowStaticMethod != null) {
|
||||
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, "" + allowStaticMethod);
|
||||
props.setProperty(XWorkConstants.ALLOW_STATIC_METHOD_ACCESS, "" + allowStaticMethod);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
ognlUtil = container.getInstance(OgnlUtil.class);
|
||||
}
|
||||
|
||||
@@ -1115,6 +1526,19 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
}
|
||||
|
||||
class TestAppender extends AbstractAppender {
|
||||
List<LogEvent> logEvents = new ArrayList<>();
|
||||
|
||||
TestAppender() {
|
||||
super("TestAppender", null, null, false, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void append(LogEvent logEvent) {
|
||||
logEvents.add(logEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum MyNumbers {
|
||||
|
||||
+62
@@ -22,6 +22,8 @@ import com.opensymphony.xwork2.XWorkTestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class DefaultAcceptedPatternsCheckerTest extends XWorkTestCase {
|
||||
|
||||
@@ -82,4 +84,64 @@ public class DefaultAcceptedPatternsCheckerTest extends XWorkTestCase {
|
||||
assertTrue("Param with underscore wasn't accepted!", actual.isAccepted());
|
||||
}
|
||||
|
||||
public void testAcceptedPatternsImmutable() throws Exception {
|
||||
AcceptedPatternsChecker checker = new DefaultAcceptedPatternsChecker();
|
||||
|
||||
Set<Pattern> acceptedPatternSet = checker.getAcceptedPatterns();
|
||||
assertNotNull("default accepted patterns null?", acceptedPatternSet);
|
||||
assertFalse("default accepted patterns empty?", acceptedPatternSet.isEmpty());
|
||||
try {
|
||||
acceptedPatternSet.add(Pattern.compile("SomeRegexPattern") );
|
||||
fail ("accepted patterns modifiable?");
|
||||
} catch(UnsupportedOperationException uoe) {
|
||||
// Expected result
|
||||
}
|
||||
try {
|
||||
acceptedPatternSet.clear();
|
||||
fail ("accepted patterns modifiable?");
|
||||
} catch(UnsupportedOperationException uoe) {
|
||||
// Expected result
|
||||
}
|
||||
|
||||
checker.setAcceptedPatterns(DefaultAcceptedPatternsChecker.ACCEPTED_PATTERNS);
|
||||
acceptedPatternSet = checker.getAcceptedPatterns();
|
||||
assertNotNull("replaced default accepted patterns null?", acceptedPatternSet);
|
||||
assertFalse("replaced default accepted patterns empty?", acceptedPatternSet.isEmpty());
|
||||
try {
|
||||
acceptedPatternSet.add(Pattern.compile("SomeRegexPattern") );
|
||||
fail ("replaced accepted patterns modifiable?");
|
||||
} catch(UnsupportedOperationException uoe) {
|
||||
// Expected result
|
||||
}
|
||||
try {
|
||||
acceptedPatternSet.clear();
|
||||
fail ("accepted patterns modifiable?");
|
||||
} catch(UnsupportedOperationException uoe) {
|
||||
// Expected result
|
||||
}
|
||||
|
||||
String[] testPatternArray = {"exactmatch1", "exactmatch2", "exactmatch3", "exactmatch4"};
|
||||
checker.setAcceptedPatterns(testPatternArray);
|
||||
acceptedPatternSet = checker.getAcceptedPatterns();
|
||||
assertNotNull("replaced default accepted patterns null?", acceptedPatternSet);
|
||||
assertFalse("replaced default accepted patterns empty?", acceptedPatternSet.isEmpty());
|
||||
assertTrue("replaced default accepted patterns not size " + testPatternArray.length + "?",
|
||||
acceptedPatternSet.size() == testPatternArray.length);
|
||||
for (String testPatternArray1 : testPatternArray) {
|
||||
assertTrue(testPatternArray1 + " not accepted?", checker.isAccepted(testPatternArray1).isAccepted());
|
||||
}
|
||||
try {
|
||||
acceptedPatternSet.add(Pattern.compile("SomeRegexPattern") );
|
||||
fail ("replaced accepted patterns modifiable?");
|
||||
} catch(UnsupportedOperationException uoe) {
|
||||
// Expected result
|
||||
}
|
||||
try {
|
||||
acceptedPatternSet.clear();
|
||||
fail ("accepted patterns modifiable?");
|
||||
} catch(UnsupportedOperationException uoe) {
|
||||
// Expected result
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+63
@@ -23,6 +23,10 @@ import com.opensymphony.xwork2.XWorkTestCase;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import static junit.framework.TestCase.assertNotNull;
|
||||
import static junit.framework.TestCase.fail;
|
||||
|
||||
public class DefaultExcludedPatternsCheckerTest extends XWorkTestCase {
|
||||
|
||||
@@ -155,4 +159,63 @@ public class DefaultExcludedPatternsCheckerTest extends XWorkTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testExcludedPatternsImmutable() throws Exception {
|
||||
ExcludedPatternsChecker checker = new DefaultExcludedPatternsChecker();
|
||||
|
||||
Set<Pattern> excludedPatternSet = checker.getExcludedPatterns();
|
||||
assertNotNull("default excluded patterns null?", excludedPatternSet);
|
||||
assertFalse("default excluded patterns empty?", excludedPatternSet.isEmpty());
|
||||
try {
|
||||
excludedPatternSet.add(Pattern.compile("SomeRegexPattern") );
|
||||
fail ("excluded patterns modifiable?");
|
||||
} catch(UnsupportedOperationException uoe) {
|
||||
// Expected result
|
||||
}
|
||||
try {
|
||||
excludedPatternSet.clear();
|
||||
fail ("excluded patterns modifiable?");
|
||||
} catch(UnsupportedOperationException uoe) {
|
||||
// Expected result
|
||||
}
|
||||
|
||||
checker.setExcludedPatterns(DefaultExcludedPatternsChecker.EXCLUDED_PATTERNS);
|
||||
excludedPatternSet = checker.getExcludedPatterns();
|
||||
assertNotNull("default excluded patterns null?", excludedPatternSet);
|
||||
assertFalse("default excluded patterns empty?", excludedPatternSet.isEmpty());
|
||||
try {
|
||||
excludedPatternSet.add(Pattern.compile("SomeRegexPattern") );
|
||||
fail ("excluded patterns modifiable?");
|
||||
} catch(UnsupportedOperationException uoe) {
|
||||
// Expected result
|
||||
}
|
||||
try {
|
||||
excludedPatternSet.clear();
|
||||
fail ("excluded patterns modifiable?");
|
||||
} catch(UnsupportedOperationException uoe) {
|
||||
// Expected result
|
||||
}
|
||||
|
||||
String[] testPatternArray = {"exactmatch1", "exactmatch2", "exactmatch3", "exactmatch4"};
|
||||
checker.setExcludedPatterns(testPatternArray);
|
||||
excludedPatternSet = checker.getExcludedPatterns();
|
||||
assertNotNull("default excluded patterns null?", excludedPatternSet);
|
||||
assertFalse("default excluded patterns empty?", excludedPatternSet.isEmpty());
|
||||
assertTrue("replaced default accepted patterns not size " + testPatternArray.length + "?",
|
||||
excludedPatternSet.size() == testPatternArray.length);
|
||||
for (String testPatternArray1 : testPatternArray) {
|
||||
assertTrue(testPatternArray1 + " not excluded?", checker.isExcluded(testPatternArray1).isExcluded());
|
||||
}
|
||||
try {
|
||||
excludedPatternSet.add(Pattern.compile("SomeRegexPattern") );
|
||||
fail ("excluded patterns modifiable?");
|
||||
} catch(UnsupportedOperationException uoe) {
|
||||
// Expected result
|
||||
}
|
||||
try {
|
||||
excludedPatternSet.clear();
|
||||
fail ("excluded patterns modifiable?");
|
||||
} catch(UnsupportedOperationException uoe) {
|
||||
// Expected result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,6 +249,71 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
|
||||
assertEquals("Hallo", rbGermany.getString("hello"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Unit test to confirm expected behaviour of "clearing methods" provided to
|
||||
* StrutsLocalizedTextProvider (from AbstractLocalizedTextProvider).
|
||||
*/
|
||||
public void testLocalizedTextProviderClearingMethods() {
|
||||
TestStrutsLocalizedTextProvider testStrutsLocalizedTextProvider = new TestStrutsLocalizedTextProvider();
|
||||
assertTrue("testStrutsLocalizedTextProvider not instance of AbstractLocalizedTextProvider ?",
|
||||
testStrutsLocalizedTextProvider instanceof AbstractLocalizedTextProvider);
|
||||
assertEquals("testStrutsLocalizedTextProvider starting default bundle map size not 0 before any retrievals ?",
|
||||
0, testStrutsLocalizedTextProvider.currentBundlesMapSize());
|
||||
|
||||
// Access the two default bundles to populate their cache entries and test bundle map size
|
||||
ResourceBundle tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
|
||||
TestStrutsLocalizedTextProvider.XWORK_MESSAGES_BUNDLE, Locale.ENGLISH);
|
||||
assertNotNull("XWORK_MESSAGES_BUNDLE retrieval null ?", tempBundle);
|
||||
tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
|
||||
TestStrutsLocalizedTextProvider.STRUTS_MESSAGES_BUNDLE, Locale.ENGLISH);
|
||||
assertNotNull("STRUTS_MESSAGES_BUNDLE retrieval null ?", tempBundle);
|
||||
assertEquals("testStrutsLocalizedTextProvider bundle map size not 2 after retrievals ?",
|
||||
2, testStrutsLocalizedTextProvider.currentBundlesMapSize());
|
||||
|
||||
// Add and then access four test bundles to populate their cache entries and test bundle map size
|
||||
testStrutsLocalizedTextProvider.addDefaultResourceBundle("com/opensymphony/xwork2/util/LocalizedTextUtilTest");
|
||||
testStrutsLocalizedTextProvider.addDefaultResourceBundle("com/opensymphony/xwork2/util/FindMe");
|
||||
testStrutsLocalizedTextProvider.addDefaultResourceBundle("com/opensymphony/xwork2/SimpleAction");
|
||||
testStrutsLocalizedTextProvider.addDefaultResourceBundle("com/opensymphony/xwork2/test");
|
||||
tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
|
||||
"com/opensymphony/xwork2/util/LocalizedTextUtilTest", Locale.ENGLISH);
|
||||
assertNotNull("com/opensymphony/xwork2/util/LocalizedTextUtilTest retrieval null ?", tempBundle);
|
||||
tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
|
||||
"com/opensymphony/xwork2/util/FindMe", Locale.ENGLISH);
|
||||
assertNotNull("com/opensymphony/xwork2/util/FindMe retrieval null ?", tempBundle);
|
||||
tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
|
||||
"com/opensymphony/xwork2/SimpleAction", Locale.ENGLISH);
|
||||
assertNotNull("com/opensymphony/xwork2/SimpleAction retrieval null ?", tempBundle);
|
||||
tempBundle = testStrutsLocalizedTextProvider.findResourceBundle(
|
||||
"com/opensymphony/xwork2/test", Locale.ENGLISH);
|
||||
assertNotNull("com/opensymphony/xwork2/test retrieval null ?", tempBundle);
|
||||
assertEquals("testStrutsLocalizedTextProvider bundle map size not 6 after retrievals ?",
|
||||
6, testStrutsLocalizedTextProvider.currentBundlesMapSize());
|
||||
|
||||
// Expect the call to be ineffective due to no locale (but shouldn't throw an Exception or cause failure)
|
||||
testStrutsLocalizedTextProvider.callClearBundleNoLocale("com/opensymphony/xwork2/test");
|
||||
assertEquals("testStrutsLocalizedTextProvider bundle map size not 6 after non-locale clear call ?",
|
||||
6, testStrutsLocalizedTextProvider.currentBundlesMapSize());
|
||||
|
||||
// Expect the call to function with bundle name + locale. Remove all four of the non-default
|
||||
// bundles and confirm the bundle map size changes.
|
||||
testStrutsLocalizedTextProvider.callClearBundleWithLocale("com/opensymphony/xwork2/test", Locale.ENGLISH);
|
||||
assertEquals("testStrutsLocalizedTextProvider bundle map size not 5 after locale clear call ?",
|
||||
5, testStrutsLocalizedTextProvider.currentBundlesMapSize());
|
||||
testStrutsLocalizedTextProvider.callClearBundleWithLocale("com/opensymphony/xwork2/SimpleAction", Locale.ENGLISH);
|
||||
assertEquals("testStrutsLocalizedTextProvider bundle map size not 4 after locale clear call ?",
|
||||
4, testStrutsLocalizedTextProvider.currentBundlesMapSize());
|
||||
testStrutsLocalizedTextProvider.callClearBundleWithLocale("com/opensymphony/xwork2/util/FindMe", Locale.ENGLISH);
|
||||
assertEquals("testStrutsLocalizedTextProvider bundle map size not 3 after locale clear call ?",
|
||||
3, testStrutsLocalizedTextProvider.currentBundlesMapSize());
|
||||
testStrutsLocalizedTextProvider.callClearBundleWithLocale("com/opensymphony/xwork2/util/LocalizedTextUtilTest", Locale.ENGLISH);
|
||||
assertEquals("testStrutsLocalizedTextProvider bundle map size not 2 after locale clear call ?",
|
||||
2, testStrutsLocalizedTextProvider.currentBundlesMapSize());
|
||||
|
||||
// Confirm the missing bundles cache clearing method does not produce any Exceptions or failures.
|
||||
testStrutsLocalizedTextProvider.callClearMissingBundlesCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
@@ -267,4 +332,25 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
|
||||
localizedTextProvider = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic test class to allow specific testing of StrutsLocalizedTextProvider
|
||||
*/
|
||||
class TestStrutsLocalizedTextProvider extends StrutsLocalizedTextProvider {
|
||||
|
||||
public void callClearBundleNoLocale(String bundleName) {
|
||||
super.clearBundle(bundleName);
|
||||
}
|
||||
|
||||
public void callClearBundleWithLocale(String bundleName, Locale locale) {
|
||||
super.clearBundle(bundleName, locale);
|
||||
}
|
||||
|
||||
public void callClearMissingBundlesCache() {
|
||||
super.clearMissingBundlesCache();
|
||||
}
|
||||
|
||||
public int currentBundlesMapSize() {
|
||||
return super.bundlesMap.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ public class DateRangeValidatorTest extends XWorkTestCase {
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
params.put("date", date.getTime());
|
||||
context.put(ActionContext.PARAMETERS, HttpParameters.create(params).build());
|
||||
context.put(ActionContext.LOCALE, Locale.US); // Force US Locale for date conversion tests on JDK9+
|
||||
|
||||
ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.VALIDATION_ACTION_NAME, null, context);
|
||||
proxy.execute();
|
||||
|
||||
@@ -38,6 +38,7 @@ public class VisitorFieldValidatorTest extends XWorkTestCase {
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
ActionContext.getContext().put(ActionContext.LOCALE, Locale.US); // Force US Locale for date conversion tests on JDK9+
|
||||
action = container.inject(VisitorValidatorTestAction.class);
|
||||
|
||||
TestBean bean = action.getBean();
|
||||
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.dispatcher;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.struts2.views.freemarker.FreemarkerManager;
|
||||
import static org.easymock.EasyMock.anyInt;
|
||||
import static org.easymock.EasyMock.anyString;
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.expectLastCall;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
|
||||
public class DefaultDispatcherErrorHandlerTest extends StrutsInternalTestCase {
|
||||
private HttpServletRequest requestMock;
|
||||
private HttpServletResponse responseMock;
|
||||
|
||||
/**
|
||||
* Test to exercise the code path and prove handleError() will output
|
||||
* the desired log warning when an IOException is thrown with devMode false.
|
||||
*/
|
||||
public void testHandleErrorIOException() {
|
||||
DefaultDispatcherErrorHandler defaultDispatcherErrorHandler = new DefaultDispatcherErrorHandler();
|
||||
defaultDispatcherErrorHandler.setDevMode("false");
|
||||
defaultDispatcherErrorHandler.setFreemarkerManager(dispatcher.getContainer().getInstance(FreemarkerManager.class));
|
||||
defaultDispatcherErrorHandler.init(dispatcher.servletContext);
|
||||
Exception fakeException = new Exception("Fake Exception, devMode false");
|
||||
try {
|
||||
requestMock.setAttribute("javax.servlet.error.exception", fakeException);
|
||||
expectLastCall();
|
||||
requestMock.setAttribute("javax.servlet.jsp.jspException", fakeException);
|
||||
expectLastCall();
|
||||
responseMock.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, fakeException.getMessage());
|
||||
expectLastCall().andStubThrow(new IOException("Fake IO Exception (SC_INTERNAL_SERVER_ERROR, devMode false)"));
|
||||
replay(responseMock);
|
||||
} catch (IOException ioe) {
|
||||
fail("Mock sendError call setup failed. Ex: " + ioe);
|
||||
}
|
||||
defaultDispatcherErrorHandler.handleError(requestMock, responseMock, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, fakeException);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to exercise the code path and prove handleError() will output
|
||||
* the desired log warning when an IOException is thrown with devMode true.
|
||||
*/
|
||||
public void testHandleErrorIOExceptionDevMode() {
|
||||
DefaultDispatcherErrorHandler defaultDispatcherErrorHandler = new DefaultDispatcherErrorHandler();
|
||||
defaultDispatcherErrorHandler.setDevMode("true");
|
||||
defaultDispatcherErrorHandler.setFreemarkerManager(dispatcher.getContainer().getInstance(FreemarkerManager.class));
|
||||
defaultDispatcherErrorHandler.init(dispatcher.servletContext);
|
||||
Exception fakeException = new Exception("Fake Exception, devMode true");
|
||||
try {
|
||||
responseMock.setContentType("text/html");
|
||||
expectLastCall().andStubThrow(new IllegalStateException("Fake IllegalState Exception (report write)")); // Fake error during report write
|
||||
responseMock.sendError(anyInt(), anyString());
|
||||
expectLastCall().andStubThrow(new IOException("Fake IO Exception (SC_INTERNAL_SERVER_ERROR, devMode true)"));
|
||||
replay(responseMock);
|
||||
} catch (IOException ioe) {
|
||||
fail("Mock sendError call setup failed. Ex: " + ioe);
|
||||
}
|
||||
defaultDispatcherErrorHandler.handleError(requestMock, responseMock, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, fakeException);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to exercise the code path and prove handleError() will output
|
||||
* the desired log warning when an IllegalStateException is thrown with devMode false.
|
||||
*/
|
||||
public void testHandleErrorIllegalStateException() {
|
||||
DefaultDispatcherErrorHandler defaultDispatcherErrorHandler = new DefaultDispatcherErrorHandler();
|
||||
defaultDispatcherErrorHandler.setDevMode("false");
|
||||
defaultDispatcherErrorHandler.setFreemarkerManager(dispatcher.getContainer().getInstance(FreemarkerManager.class));
|
||||
defaultDispatcherErrorHandler.init(dispatcher.servletContext);
|
||||
Exception fakeException = new Exception("Fake Exception, devMode false");
|
||||
try {
|
||||
requestMock.setAttribute("javax.servlet.error.exception", fakeException);
|
||||
expectLastCall();
|
||||
requestMock.setAttribute("javax.servlet.jsp.jspException", fakeException);
|
||||
expectLastCall();
|
||||
expect(responseMock.isCommitted()).andStubReturn(Boolean.TRUE);
|
||||
responseMock.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, fakeException.getMessage());
|
||||
expectLastCall().andStubThrow(new IllegalStateException("Fake IllegalState Exception (SC_INTERNAL_SERVER_ERROR, devMode false)"));
|
||||
replay(responseMock);
|
||||
} catch (IOException ioe) {
|
||||
fail("Mock sendError call setup failed. Ex: " + ioe);
|
||||
}
|
||||
defaultDispatcherErrorHandler.handleError(requestMock, responseMock, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, fakeException);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to exercise the code path and prove handleError() will output
|
||||
* the desired log warning when an IllegalStateException is thrown with devMode true.
|
||||
*/
|
||||
public void testHandleErrorIllegalStateExceptionDevMode() {
|
||||
DefaultDispatcherErrorHandler defaultDispatcherErrorHandler = new DefaultDispatcherErrorHandler();
|
||||
defaultDispatcherErrorHandler.setDevMode("true");
|
||||
defaultDispatcherErrorHandler.setFreemarkerManager(dispatcher.getContainer().getInstance(FreemarkerManager.class));
|
||||
defaultDispatcherErrorHandler.init(dispatcher.servletContext);
|
||||
Exception fakeException = new Exception("Fake Exception, devMode true");
|
||||
try {
|
||||
expect(responseMock.isCommitted()).andStubReturn(Boolean.TRUE);
|
||||
responseMock.setContentType("text/html");
|
||||
expectLastCall().andStubThrow(new IllegalStateException("Fake IllegalState Exception (report write)")); // Fake error during report write
|
||||
responseMock.sendError(anyInt(), anyString());
|
||||
expectLastCall().andStubThrow(new IllegalStateException("Fake IllegalState Exception (SC_INTERNAL_SERVER_ERROR, devMode true)"));
|
||||
replay(responseMock);
|
||||
} catch (IOException ioe) {
|
||||
fail("Mock sendError call setup failed. Ex: " + ioe);
|
||||
}
|
||||
defaultDispatcherErrorHandler.handleError(requestMock, responseMock, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, fakeException);
|
||||
}
|
||||
|
||||
protected void setUp() {
|
||||
requestMock = (HttpServletRequest) createMock(HttpServletRequest.class);
|
||||
responseMock = (HttpServletResponse) createMock(HttpServletResponse.class);
|
||||
dispatcher = initDispatcher(Collections.<String, String>emptyMap());
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,22 @@
|
||||
*/
|
||||
package org.apache.struts2.dispatcher;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.expectLastCall;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
|
||||
public class DefaultStaticContentLoaderTest extends StrutsInternalTestCase {
|
||||
private HttpServletRequest requestMock;
|
||||
private HttpServletResponse responseMock;
|
||||
private HostConfig hostConfigMock;
|
||||
private DefaultStaticContentLoader defaultStaticContentLoader;
|
||||
|
||||
public void testParsePackages() throws Exception {
|
||||
|
||||
@@ -50,4 +61,55 @@ public class DefaultStaticContentLoaderTest extends StrutsInternalTestCase {
|
||||
assertEquals(result4.get(3), "foo/bar/package4/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to exercise the code path and prove findStaticResource() will output
|
||||
* the desired log warning when an IOException is thrown.
|
||||
*/
|
||||
public void testFindStaticResourceIOException() {
|
||||
expect(requestMock.getDateHeader("If-Modified-Since")).andStubReturn(0L);
|
||||
try {
|
||||
responseMock.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
expectLastCall().andStubThrow(new IOException("Fake IO Exception (SC_NOT_FOUND)"));
|
||||
replay(responseMock);
|
||||
} catch (IOException ioe) {
|
||||
fail("Mock sendError call setup failed. Ex: " + ioe);
|
||||
}
|
||||
try {
|
||||
defaultStaticContentLoader.findStaticResource("/static/fake.html", requestMock, responseMock);
|
||||
} catch (IOException ioe) {
|
||||
fail("DefaultStaticContentLoader.findStaticResource() call failed. Ex: " + ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to exercise the code path and prove findStaticResource() will output
|
||||
* the desired log warning when an IllegalStateException is thrown.
|
||||
*/
|
||||
public void testFindStaticResourceIllegalStateException() {
|
||||
expect(requestMock.getDateHeader("If-Modified-Since")).andStubReturn(0L);
|
||||
try {
|
||||
expect(responseMock.isCommitted()).andStubReturn(Boolean.TRUE);
|
||||
responseMock.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
expectLastCall().andStubThrow(new IllegalStateException("Fake IllegalState Exception (SC_NOT_FOUND)"));
|
||||
replay(responseMock);
|
||||
} catch (IOException ioe) {
|
||||
fail("Mock sendError call setup failed. Ex: " + ioe);
|
||||
}
|
||||
try {
|
||||
defaultStaticContentLoader.findStaticResource("/static/fake.html", requestMock, responseMock);
|
||||
} catch (IOException ioe) {
|
||||
fail("DefaultStaticContentLoader.findStaticResource() call failed. Ex: " + ioe);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setUp() {
|
||||
requestMock = (HttpServletRequest) createMock(HttpServletRequest.class);
|
||||
responseMock = (HttpServletResponse) createMock(HttpServletResponse.class);
|
||||
hostConfigMock = (HostConfig) createMock(HostConfig.class);
|
||||
expect(hostConfigMock.getInitParameter("packages")).andStubReturn(null);
|
||||
expect(hostConfigMock.getInitParameter("loggerFactory")).andStubReturn(null);
|
||||
defaultStaticContentLoader = new DefaultStaticContentLoader();
|
||||
defaultStaticContentLoader.setHostConfig(hostConfigMock);
|
||||
defaultStaticContentLoader.setEncoding("UTF-8");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.apache.struts2.dispatcher;
|
||||
|
||||
import com.mockobjects.dynamic.C;
|
||||
import com.mockobjects.dynamic.Mock;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.XWorkConstants;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
@@ -36,6 +37,7 @@ import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
|
||||
import org.apache.struts2.util.ObjectFactoryDestroyable;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -319,6 +321,260 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
req.setContentType("multipart/form-data; boundary=---------------------------207103069210263;charset=UTF-16LE");
|
||||
assertTrue(du.isMultipartRequest(req));
|
||||
|
||||
req.setContentType("multipart/form-data;boundary=---------------------------207103069210263;charset=UTF-16LE");
|
||||
assertTrue(du.isMultipartRequest(req));
|
||||
|
||||
req.setContentType("multipart/form-data;boundary=---------------------------207103069210263; charset=UTF-16LE");
|
||||
assertTrue(du.isMultipartRequest(req));
|
||||
|
||||
req.setContentType("multipart/form-data;boundary=---------------------------207103069210263 ;charset=UTF-16LE");
|
||||
assertTrue(du.isMultipartRequest(req));
|
||||
|
||||
req.setContentType("multipart/form-data;boundary=---------------------------207103069210263 ; charset=UTF-16LE");
|
||||
assertTrue(du.isMultipartRequest(req));
|
||||
|
||||
req.setContentType("multipart/form-data ;boundary=---------------------------207103069210263;charset=UTF-16LE");
|
||||
assertTrue(du.isMultipartRequest(req));
|
||||
|
||||
req.setContentType("multipart/form-data ; boundary=---------------------------207103069210263;charset=UTF-16LE");
|
||||
assertTrue(du.isMultipartRequest(req));
|
||||
|
||||
req.setContentType("Multipart/Form-Data ; boundary=---------------------------207103069210263;charset=UTF-16LE");
|
||||
assertTrue(du.isMultipartRequest(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify proper default (true) handleExceptionState for Dispatcher and that
|
||||
* it properly reflects a manually configured change to false.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testHandleException() throws Exception {
|
||||
Dispatcher du = initDispatcher(new HashMap<String, String>());
|
||||
assertTrue("Default Dispatcher handleException state not true ?", du.isHandleException());
|
||||
|
||||
Dispatcher du2 = initDispatcher(new HashMap<String, String>() {{
|
||||
put(StrutsConstants.STRUTS_HANDLE_EXCEPTION, "false");
|
||||
}});
|
||||
assertFalse("Modified Dispatcher handleException state not false ?", du2.isHandleException());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify proper default (false) devMode for Dispatcher and that
|
||||
* it properly reflects a manually configured change to true.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testDevMode() throws Exception {
|
||||
Dispatcher du = initDispatcher(new HashMap<String, String>());
|
||||
assertFalse("Default Dispatcher devMode state not false ?", du.isDevMode());
|
||||
|
||||
Dispatcher du2 = initDispatcher(new HashMap<String, String>() {{
|
||||
put(StrutsConstants.STRUTS_DEVMODE, "true");
|
||||
}});
|
||||
assertTrue("Modified Dispatcher devMode state not true ?", du2.isDevMode());
|
||||
}
|
||||
|
||||
public void testGetLocale_With_DefaultLocale_FromConfiguration() throws Exception {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
mock.expectAndReturn("getCharacterEncoding", "utf-8"); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getHeader", "X-Requested-With", ""); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getParameterMap", new HashMap<String, Object>()); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getSession", false, mockHttpSession); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getSession", true, mockHttpSession); // From createTestContextMap().
|
||||
HttpServletRequest request = (HttpServletRequest) mock.proxy();
|
||||
HttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
Dispatcher testDispatcher = initDispatcher(new HashMap<String, String>() {{
|
||||
put(StrutsConstants.STRUTS_I18N_ENCODING, "utf-8");
|
||||
// Not setting a Struts Locale here, so we should receive the default "de_DE" from the test configuration.
|
||||
}});
|
||||
|
||||
// When
|
||||
testDispatcher.prepare(request, response);
|
||||
Map<String, Object> contextMap = createTestContextMap(testDispatcher, request, response);
|
||||
|
||||
// Then
|
||||
assertEquals(Locale.GERMANY, contextMap.get(ActionContext.LOCALE)); // Expect the Dispatcher defaultLocale value "de_DE" from the test configuration.
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_DefaultLocale_fr_CA() throws Exception {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
mock.expectAndReturn("getCharacterEncoding", "utf-8"); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getHeader", "X-Requested-With", ""); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getParameterMap", new HashMap<String, Object>()); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getSession", false, mockHttpSession); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getSession", true, mockHttpSession); // From createTestContextMap().
|
||||
HttpServletRequest request = (HttpServletRequest) mock.proxy();
|
||||
HttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
Dispatcher testDispatcher = initDispatcher(new HashMap<String, String>() {{
|
||||
put(StrutsConstants.STRUTS_I18N_ENCODING, "utf-8");
|
||||
put(StrutsConstants.STRUTS_LOCALE, Locale.CANADA_FRENCH.toString()); // Set the Dispatcher defaultLocale to fr_CA.
|
||||
}});
|
||||
|
||||
// When
|
||||
testDispatcher.prepare(request, response);
|
||||
Map<String, Object> contextMap = createTestContextMap(testDispatcher, request, response);
|
||||
|
||||
// Then
|
||||
assertEquals(Locale.CANADA_FRENCH, contextMap.get(ActionContext.LOCALE)); // Expect the Dispatcher defaultLocale value.
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_BadDefaultLocale_RequestLocale_en_UK() throws Exception {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
mock.expectAndReturn("getCharacterEncoding", "utf-8"); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getHeader", "X-Requested-With", ""); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getLocale", Locale.UK); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getParameterMap", new HashMap<String, Object>()); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getSession", false, mockHttpSession); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getSession", true, mockHttpSession); // From createTestContextMap().
|
||||
mock.expectAndReturn("getLocale", Locale.UK); // From createTestContextMap().
|
||||
HttpServletRequest request = (HttpServletRequest) mock.proxy();
|
||||
HttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
Dispatcher testDispatcher = initDispatcher(new HashMap<String, String>() {{
|
||||
put(StrutsConstants.STRUTS_I18N_ENCODING, "utf-8");
|
||||
put(StrutsConstants.STRUTS_LOCALE, "This_is_not_a_valid_Locale_string"); // Set Dispatcher defaultLocale to an invalid value.
|
||||
}});
|
||||
|
||||
// When
|
||||
testDispatcher.prepare(request, response);
|
||||
Map<String, Object> contextMap = createTestContextMap(testDispatcher, request, response);
|
||||
|
||||
// Then
|
||||
assertEquals(Locale.UK, contextMap.get(ActionContext.LOCALE)); // Expect the request set value from Mock.
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_BadDefaultLocale_And_RuntimeException() throws Exception {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
mock.expectAndReturn("getCharacterEncoding", "utf-8"); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getHeader", "X-Requested-With", ""); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getLocale", Locale.UK); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getParameterMap", new HashMap<String, Object>()); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getSession", false, mockHttpSession); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getSession", true, mockHttpSession); // From createTestContextMap().
|
||||
mock.expectAndThrow("getLocale", new IllegalStateException("Test theoretical state preventing HTTP Request Locale access")); // From createTestContextMap().
|
||||
HttpServletRequest request = (HttpServletRequest) mock.proxy();
|
||||
HttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
Dispatcher testDispatcher = initDispatcher(new HashMap<String, String>() {{
|
||||
put(StrutsConstants.STRUTS_I18N_ENCODING, "utf-8");
|
||||
put(StrutsConstants.STRUTS_LOCALE, "This_is_not_a_valid_Locale_string"); // Set the Dispatcher defaultLocale to an invalid value.
|
||||
}});
|
||||
|
||||
// When
|
||||
testDispatcher.prepare(request, response);
|
||||
Map<String, Object> contextMap = createTestContextMap(testDispatcher, request, response);
|
||||
|
||||
// Then
|
||||
assertEquals(Locale.getDefault(), contextMap.get(ActionContext.LOCALE)); // Expect the system default value, when BOTH Dispatcher default Locale AND request access fail.
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_NullDefaultLocale() throws Exception {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
mock.expectAndReturn("getCharacterEncoding", "utf-8"); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getHeader", "X-Requested-With", ""); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getLocale", Locale.CANADA_FRENCH); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getParameterMap", new HashMap<String, Object>()); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getSession", false, mockHttpSession); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getSession", true, mockHttpSession); // From createTestContextMap().
|
||||
mock.expectAndReturn("getLocale", Locale.CANADA_FRENCH); // From createTestContextMap().
|
||||
HttpServletRequest request = (HttpServletRequest) mock.proxy();
|
||||
HttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
Dispatcher testDispatcher = initDispatcher(new HashMap<String, String>() {{
|
||||
put(StrutsConstants.STRUTS_I18N_ENCODING, "utf-8");
|
||||
// Attempting to set StrutsConstants.STRUTS_LOCALE to null here via parameters causes an NPE.
|
||||
}});
|
||||
|
||||
testDispatcher.setDefaultLocale(null); // Force a null Struts default locale, otherwise we receive the default "de_DE" from the test configuration.
|
||||
|
||||
// When
|
||||
testDispatcher.prepare(request, response);
|
||||
Map<String, Object> contextMap = createTestContextMap(testDispatcher, request, response);
|
||||
|
||||
// Then
|
||||
assertEquals(Locale.CANADA_FRENCH, contextMap.get(ActionContext.LOCALE)); // Expect the request set value from Mock.
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_NullDefaultLocale_And_RuntimeException() throws Exception {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
mock.expectAndReturn("getCharacterEncoding", "utf-8"); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getHeader", "X-Requested-With", ""); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getLocale", Locale.CANADA_FRENCH); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getParameterMap", new HashMap<String, Object>()); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getSession", false, mockHttpSession); // From Dispatcher prepare().
|
||||
mock.expectAndReturn("getSession", true, mockHttpSession); // From createTestContextMap().
|
||||
mock.expectAndThrow("getLocale", new IllegalStateException("Test some theoretical state preventing HTTP Request Locale access")); // From createTestContextMap().
|
||||
HttpServletRequest request = (HttpServletRequest) mock.proxy();
|
||||
HttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
Dispatcher testDispatcher = initDispatcher(new HashMap<String, String>() {{
|
||||
put(StrutsConstants.STRUTS_I18N_ENCODING, "utf-8");
|
||||
// Attempting to set StrutsConstants.STRUTS_LOCALE to null via parameters causes an NPE.
|
||||
}});
|
||||
|
||||
testDispatcher.setDefaultLocale(null); // Force a null Struts default locale, otherwise we receive the default "de_DE" from the test configuration.
|
||||
|
||||
// When
|
||||
testDispatcher.prepare(request, response);
|
||||
Map<String, Object> contextMap = createTestContextMap(testDispatcher, request, response);
|
||||
|
||||
// Then
|
||||
assertEquals(Locale.getDefault(), contextMap.get(ActionContext.LOCALE)); // Expect the system default value when Mock request access fails.
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a test context Map from a Dispatcher instance.
|
||||
*
|
||||
* The method directly calls getParameterMap() and getSession(true) on the HttpServletRequest.
|
||||
*
|
||||
* The method indirectly calls getLocale(request) on the Dispatcher instance, allowing a test of that code path.
|
||||
* The derived Struts Dispatcher Locale can be retrieved from the Map afterwards.
|
||||
*
|
||||
* @param dispatcher
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
protected static Map<String, Object> createTestContextMap(Dispatcher dispatcher,
|
||||
HttpServletRequest request, HttpServletResponse response) {
|
||||
if (dispatcher == null) {
|
||||
throw new IllegalArgumentException("Cannot create a test ContextMap from a null Dispatcher");
|
||||
}
|
||||
if (request == null) {
|
||||
throw new IllegalArgumentException("Cannot create a test ContextMap from a null HttpServletRequest");
|
||||
}
|
||||
if (response == null) {
|
||||
throw new IllegalArgumentException("Cannot create a test ContextMap from a null HttpServletResponse");
|
||||
}
|
||||
|
||||
return dispatcher.createContextMap(new RequestMap(request),
|
||||
HttpParameters.create(request.getParameterMap()).build(),
|
||||
new SessionMap(request),
|
||||
new ApplicationMap(request.getSession(true).getServletContext()),
|
||||
request,
|
||||
response);
|
||||
}
|
||||
|
||||
class InternalConfigurationManager extends ConfigurationManager {
|
||||
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.XWorkTestCase;
|
||||
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Unit test for {@link ActionMappingParametersInterceptor}.
|
||||
*
|
||||
* Adapted from ParametersInterceptor (@author Jason Carreira)
|
||||
*/
|
||||
public class ActionMappingParametersInterceptorTest extends XWorkTestCase {
|
||||
|
||||
/**
|
||||
* Confirm that ActionMappingParametersInterceptor processing methods avoid
|
||||
* nested wrapping of parameters.
|
||||
*/
|
||||
public void testParametersNoNestedWrapping() {
|
||||
final ActionMappingParametersInterceptor ampi = createActionMappingParametersInterceptor();
|
||||
final ActionContext ac = ActionContext.getContext();
|
||||
final Map<String, Object> parameters = new HashMap<String, Object>() {
|
||||
{
|
||||
put("fooKey", "fooValue");
|
||||
put("barKey", "barValue");
|
||||
}
|
||||
};
|
||||
final Map<String, Object> moreParameters = new HashMap<String, Object>() {
|
||||
{
|
||||
put("fooKey2", "fooValue2");
|
||||
put("barKey2", "barValue3");
|
||||
}
|
||||
};
|
||||
final Map<String, Object> evenMoreParameters = new HashMap<String, Object>() {
|
||||
{
|
||||
put("fooKey3", "fooValue3");
|
||||
put("barKey3", "barValue3");
|
||||
}
|
||||
};
|
||||
// Set up the initial ActionMapping with parameters in the context
|
||||
final HttpParameters wrappedParameters = HttpParameters.create(parameters).build();
|
||||
final ActionMapping actionMapping = new ActionMapping("testAction", "testNameSpace", "testMethod", parameters);
|
||||
ac.put(ServletActionContext.ACTION_MAPPING, actionMapping);
|
||||
|
||||
// Retrieve parameters and confirm both builder result equality and that the contained Object
|
||||
// values of each Parameter element are not of type Parameter (i.e. no double-wrapping).
|
||||
// Note: ampi.retrieveParameters() only ever returns the parameters associated with the ActionContext's
|
||||
// ActionMapping (not changed directly by ampi.addParametersToContext()).
|
||||
final HttpParameters retrievedParameters = ampi.retrieveParameters(ac);
|
||||
assertNotNull("retrievedParameters null ?", retrievedParameters);
|
||||
// Note: Cannot perform equality test on HttpParameters directly as hashCode values differ even
|
||||
// when the contents are equivalent. Instead we compare size and content equality.
|
||||
assertEquals("retrievedParameters size not equal to wrappedParameters size ?",
|
||||
retrievedParameters.size(), wrappedParameters.size());
|
||||
|
||||
for (String parameterName : retrievedParameters.keySet() ) {
|
||||
Parameter retrievedParameter = retrievedParameters.get(parameterName);
|
||||
Parameter wrappedParameter = wrappedParameters.get(parameterName);
|
||||
assertNotNull("retrievedParameter is null ?", retrievedParameter);
|
||||
assertNotNull("wrappedParameter is null ?", wrappedParameter);
|
||||
Object retrievedParameterValue = retrievedParameter.getObject();
|
||||
Object wrappedParameterValue = wrappedParameter.getObject();
|
||||
assertNotNull("retrievedParameterValue is null ?", retrievedParameterValue);
|
||||
assertNotNull("wrappedParameterValue is null ?", wrappedParameterValue);
|
||||
assertFalse("retrievedParameterValue is type Parameter ?", retrievedParameterValue instanceof Parameter);
|
||||
assertEquals("retrievedParameterValue not equal to wrappedParameterValue ?",
|
||||
retrievedParameterValue, wrappedParameterValue);
|
||||
}
|
||||
|
||||
// Set up the initial ActionMapping with (artificially) already-wrapped parameters in the context
|
||||
final Map<String, Object> wrappedParametersMap = new HashMap<>(wrappedParameters.size());
|
||||
for (String parameterName : wrappedParameters.keySet() ) {
|
||||
wrappedParametersMap.put(parameterName, wrappedParameters.get(parameterName));
|
||||
}
|
||||
final ActionMapping actionMappingWrapped = new ActionMapping("testAction", "testNameSpace", "testMethod", wrappedParametersMap);
|
||||
ac.put(ServletActionContext.ACTION_MAPPING, actionMappingWrapped);
|
||||
|
||||
// Retrieve parameters and confirm that the contained Object values of each Parameter
|
||||
// element are not of type Parameter (i.e. no double-wrapping).
|
||||
// Note: ampi.retrieveParameters() only ever returns the parameters associated with the ActionContext's
|
||||
// ActionMapping (not changed directly by ampi.addParametersToContext()).
|
||||
final HttpParameters retrievedWrappedParameters = ampi.retrieveParameters(ac);
|
||||
assertNotNull("retrievedWrappedParameters null ?", retrievedWrappedParameters);
|
||||
// Note: Cannot perform equality test on HttpParameters directly as hashCode values differ even
|
||||
// when the contents are equivalent. Instead we compare size and content equality.
|
||||
assertEquals("retrievedWrappedParameters size not equal to wrappedParametersMap size ?",
|
||||
retrievedWrappedParameters.size(), wrappedParametersMap.size());
|
||||
|
||||
for (String parameterName : retrievedWrappedParameters.keySet() ) {
|
||||
Parameter retrievedParameter = retrievedWrappedParameters.get(parameterName);
|
||||
Object wrappedParameter = wrappedParametersMap.get(parameterName);
|
||||
assertNotNull("retrievedParameter is null ?", retrievedParameter);
|
||||
assertNotNull("wrappedParameter is null ?", wrappedParameter);
|
||||
assertTrue("wrappedParameter is not a Parameter ?", wrappedParameter instanceof Parameter);
|
||||
Object retrievedParameterValue = retrievedParameter.getObject();
|
||||
Object wrappedParameterValue = ((Parameter) wrappedParameter).getObject();
|
||||
assertNotNull("retrievedParameterValue is null ?", retrievedParameterValue);
|
||||
assertNotNull("wrappedParameterValue is null ?", wrappedParameterValue);
|
||||
assertFalse("retrievedParameterValue is type Parameter ?", retrievedParameterValue instanceof Parameter);
|
||||
assertEquals("retrievedParameterValue not equal to wrappedParameterValue ?",
|
||||
retrievedParameterValue, wrappedParameterValue);
|
||||
}
|
||||
|
||||
// Add parameters to the context
|
||||
ampi.addParametersToContext(ac, parameters);
|
||||
|
||||
// Retrieve parameters and confirm the expected size and that the contained Object
|
||||
// values of each Parameter element are not of type Parameter (i.e. no double-wrapping).
|
||||
final HttpParameters retrievedACParameters = ac.getParameters();
|
||||
assertNotNull("retrievedACParameters null ?", retrievedACParameters);
|
||||
assertEquals("retrievedACParameters size not equal to parameters size ?",
|
||||
retrievedACParameters.size(), parameters.size());
|
||||
|
||||
for (String parameterName : retrievedACParameters.keySet() ) {
|
||||
Parameter retrievedACParameter = retrievedACParameters.get(parameterName);
|
||||
assertNotNull("retrievedACParameter is null ?", retrievedACParameter);
|
||||
Object parameterValue = retrievedACParameter.getObject();
|
||||
assertNotNull("parameterValue is null ?", parameterValue);
|
||||
assertFalse("parameterValue is of type Parameter ?", parameterValue instanceof Parameter);
|
||||
}
|
||||
|
||||
// Add additional parameters to the context
|
||||
ampi.addParametersToContext(ac, moreParameters);
|
||||
|
||||
// Retrieve parameters and confirm the expected size and that the contained Object
|
||||
// values of each Parameter element are not of type Parameter (i.e. no double-wrapping).
|
||||
final HttpParameters retrievedACMoreParameters = ac.getParameters();
|
||||
assertNotNull("retrievedACMoreParameters null ?", retrievedACMoreParameters);
|
||||
assertEquals("retrievedACMoreParameters size not equal to combined size (parameters + moreParameters) ?",
|
||||
retrievedACMoreParameters.size(), parameters.size() + moreParameters.size());
|
||||
|
||||
for (String parameterName : retrievedACMoreParameters.keySet() ) {
|
||||
Parameter retrievedACMoreParameter = retrievedACMoreParameters.get(parameterName);
|
||||
assertNotNull("retrievedACMoreParameter is null ?", retrievedACMoreParameter);
|
||||
Object parameterValue = retrievedACMoreParameter.getObject();
|
||||
assertNotNull("parameterValue (more) is null ?", parameterValue);
|
||||
assertFalse("parameterValue (more) is of type Parameter ?", parameterValue instanceof Parameter);
|
||||
}
|
||||
|
||||
// Build some "already wrapped" parameters and attempt to add them to the context
|
||||
final HttpParameters evenMoreWrappedParameters = HttpParameters.create(evenMoreParameters).build();
|
||||
assertNotNull("evenMoreWrappedParameters null ?", evenMoreWrappedParameters);
|
||||
assertEquals("evenMoreWrappedParameters size not equal to evenMoreParameters size ?",
|
||||
evenMoreWrappedParameters.size(), evenMoreParameters.size());
|
||||
ampi.addParametersToContext(ac, evenMoreWrappedParameters);
|
||||
|
||||
// Retrieve parameters and confirm the expected size and that the contained Object
|
||||
// values of each Parameter element are not of type Parameter (i.e. no double-wrapping).
|
||||
final HttpParameters retrievedACEvenMoreParameters = ac.getParameters();
|
||||
assertNotNull("retrievedACEvenMoreParameters null ?", retrievedACEvenMoreParameters);
|
||||
assertEquals("retrievedACEvenMoreParameters size not equal to combined size (parameters + moreParameters + evenMoreParameters) ?",
|
||||
retrievedACEvenMoreParameters.size(), parameters.size() + moreParameters.size() + evenMoreParameters.size());
|
||||
|
||||
for (String parameterName : retrievedACEvenMoreParameters.keySet() ) {
|
||||
Parameter retrievedACEvenMoreParameter = retrievedACEvenMoreParameters.get(parameterName);
|
||||
assertNotNull("retrievedACEvenMoreParameter is null ?", retrievedACEvenMoreParameter);
|
||||
Object parameterValue = retrievedACEvenMoreParameter.getObject();
|
||||
assertNotNull("parameterValue (even more) is null ?", parameterValue);
|
||||
assertFalse("parameterValue (even more) is of type Parameter ?", parameterValue instanceof Parameter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and configure an ActionMappingParametersInterceptor instance
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private ActionMappingParametersInterceptor createActionMappingParametersInterceptor() {
|
||||
ActionMappingParametersInterceptor ampi = new ActionMappingParametersInterceptor();
|
||||
container.inject(ampi);
|
||||
return ampi;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,6 +40,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -244,7 +245,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
|
||||
public void testNoContentMultipartRequest() throws Exception {
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
|
||||
req.setCharacterEncoding("text/html");
|
||||
req.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
req.setMethod("post");
|
||||
req.addHeader("Content-type", "multipart/form-data");
|
||||
req.setContent(null); // there is no content
|
||||
@@ -265,7 +266,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
|
||||
|
||||
public void testSuccessUploadOfATextFileMultipartRequest() throws Exception {
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
req.setCharacterEncoding("text/html");
|
||||
req.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
req.setMethod("post");
|
||||
req.addHeader("Content-type", "multipart/form-data; boundary=---1234");
|
||||
|
||||
@@ -322,7 +323,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
|
||||
final String endline = "\r\n";
|
||||
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
req.setCharacterEncoding("text/html");
|
||||
req.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
req.setMethod("POST");
|
||||
req.addHeader("Content-type", "multipart/form-data; boundary=" + bondary);
|
||||
StringBuilder content = new StringBuilder(128);
|
||||
@@ -371,7 +372,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
|
||||
|
||||
public void testMultipartRequestLocalizedError() throws Exception {
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
req.setCharacterEncoding("text/html");
|
||||
req.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
req.setMethod("post");
|
||||
req.addHeader("Content-type", "multipart/form-data; boundary=---1234");
|
||||
|
||||
|
||||
@@ -21,9 +21,12 @@ package org.apache.struts2.result;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_SEE_OTHER;
|
||||
import static org.easymock.EasyMock.createControl;
|
||||
import static org.easymock.EasyMock.createNiceMock;
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.expectLastCall;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -321,6 +324,122 @@ public class ServletRedirectResultTest extends StrutsInternalTestCase implements
|
||||
control.verify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to exercise the code path and prove sendRedirect() will output
|
||||
* the desired log warning when an IOException is thrown for statusCode SC_FOUND.
|
||||
*/
|
||||
public void testSendRedirectSCFoundIOException() {
|
||||
HttpServletResponse httpServletResponseMock = (HttpServletResponse) createMock(HttpServletResponse.class);
|
||||
boolean ioeCaught = false;
|
||||
view.setLocation("/bar/foo.jsp");
|
||||
view.setStatusCode(HttpServletResponse.SC_FOUND);
|
||||
try {
|
||||
httpServletResponseMock.sendRedirect(view.getLocation());
|
||||
expectLastCall().andStubThrow(new IOException("Fake IO Exception (SC_FOUND)"));
|
||||
replay(httpServletResponseMock);
|
||||
} catch (IOException ioe) {
|
||||
fail("Mock sendRedirect call setup failed. Ex: " + ioe);
|
||||
}
|
||||
try {
|
||||
view.sendRedirect(httpServletResponseMock, view.getLocation());
|
||||
} catch (IOException ioe) {
|
||||
ioeCaught = true; // Verify expected exception was thrown
|
||||
}
|
||||
if (!ioeCaught) {
|
||||
fail("sendRedirect (SC_FOUND) with forced IOException did not propagate from setLocation!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to exercise the code path and prove sendRedirect() will output
|
||||
* the desired log warning when an IOException is thrown for statusCode SC_MOVED_PERMANENTLY.
|
||||
*/
|
||||
public void testSendRedirectSCMovedPermanentlyIOException() {
|
||||
HttpServletResponse httpServletResponseMock = (HttpServletResponse) createMock(HttpServletResponse.class);
|
||||
boolean ioeCaught = false;
|
||||
view.setLocation("/bar/foo.jsp");
|
||||
view.setStatusCode(HttpServletResponse.SC_MOVED_PERMANENTLY); // Any non SC_FOUND will suffice
|
||||
try {
|
||||
httpServletResponseMock.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
|
||||
expectLastCall();
|
||||
httpServletResponseMock.setHeader("Location", view.getLocation());
|
||||
expectLastCall();
|
||||
expect(httpServletResponseMock.getWriter()).andStubThrow(new IOException("Fake IO Exception (SC_MOVED_PERMANENTLY)"));
|
||||
replay(httpServletResponseMock);
|
||||
} catch (IOException ioe) {
|
||||
fail("Mock getWriter call setup failed. Ex: " + ioe);
|
||||
}
|
||||
try {
|
||||
view.sendRedirect(httpServletResponseMock, view.getLocation());
|
||||
} catch (IOException ioe) {
|
||||
ioeCaught = true; // Verify expected exception was thrown
|
||||
}
|
||||
if (!ioeCaught) {
|
||||
fail("sendRedirect (SC_MOVED_PERMANENTLY) with forced IOException did not propagate from setLocation!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to exercise the code path and prove sendRedirect() will output
|
||||
* the desired log warning when an IllegalStateException is thrown for statusCode SC_FOUND.
|
||||
*/
|
||||
public void testSendRedirectSCFoundIllegalStateException() {
|
||||
HttpServletResponse httpServletResponseMock = (HttpServletResponse) createMock(HttpServletResponse.class);
|
||||
boolean iseCaught = false;
|
||||
view.setLocation("/bar/foo.jsp");
|
||||
view.setStatusCode(HttpServletResponse.SC_FOUND);
|
||||
try {
|
||||
httpServletResponseMock.sendRedirect(view.getLocation());
|
||||
expectLastCall().andStubThrow(new IllegalStateException("Fake IllegalState Exception (SC_FOUND)"));
|
||||
expect(httpServletResponseMock.isCommitted()).andStubReturn(Boolean.TRUE);
|
||||
replay(httpServletResponseMock);
|
||||
} catch (IOException ioe) {
|
||||
fail("Mock sendRedirect call setup failed. Ex: " + ioe);
|
||||
}
|
||||
try {
|
||||
view.sendRedirect(httpServletResponseMock, view.getLocation());
|
||||
} catch (IOException ioe) {
|
||||
iseCaught = false;
|
||||
} catch (IllegalStateException ise) {
|
||||
iseCaught = true; // Verify expected exception was thrown
|
||||
}
|
||||
if (!iseCaught) {
|
||||
fail("sendRedirect (SC_FOUND) with forced IllegalStateException did not propagate from setLocation!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to exercise the code path and prove sendRedirect() will output
|
||||
* the desired log warning when an IllegalStateException is thrown for statusCode SC_MOVED_PERMANENTLY.
|
||||
*/
|
||||
public void testSendRedirectSCMovedPermanentlyIllegalStateException() {
|
||||
HttpServletResponse httpServletResponseMock = (HttpServletResponse) createMock(HttpServletResponse.class);
|
||||
boolean iseCaught = false;
|
||||
view.setLocation("/bar/foo.jsp");
|
||||
view.setStatusCode(HttpServletResponse.SC_MOVED_PERMANENTLY); // Any non SC_FOUND will suffice
|
||||
try {
|
||||
httpServletResponseMock.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
|
||||
expectLastCall();
|
||||
httpServletResponseMock.setHeader("Location", view.getLocation());
|
||||
expectLastCall();
|
||||
expect(httpServletResponseMock.getWriter()).andStubThrow(new IllegalStateException("Fake IllegalState Exception (SC_MOVED_PERMANENTLY)"));
|
||||
expect(httpServletResponseMock.isCommitted()).andStubReturn(Boolean.TRUE);
|
||||
replay(httpServletResponseMock);
|
||||
} catch (IOException ioe) {
|
||||
fail("Mock getWriter call setup failed. Ex: " + ioe);
|
||||
}
|
||||
try {
|
||||
view.sendRedirect(httpServletResponseMock, view.getLocation());
|
||||
} catch (IOException ioe) {
|
||||
iseCaught = false;
|
||||
} catch (IllegalStateException ise) {
|
||||
iseCaught = true; // Verify expected exception was thrown
|
||||
}
|
||||
if (!iseCaught) {
|
||||
fail("sendRedirect (SC_MOVED_PERMANENTLY) with forced IllegalStateException did not propagate from setLocation!");
|
||||
}
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
configurationManager.getConfiguration().
|
||||
|
||||
@@ -246,12 +246,19 @@ public class StreamResultTest extends StrutsInternalTestCase {
|
||||
|
||||
public class MyImageAction implements Action {
|
||||
|
||||
public InputStream getStreamForImage() throws Exception {
|
||||
FileInputStream streamForImage;
|
||||
long contentLength;
|
||||
|
||||
public MyImageAction() throws Exception {
|
||||
// just use src/test/log4j2.xml as test file
|
||||
URL url = ClassLoaderUtil.getResource("log4j2.xml", StreamResultTest.class);
|
||||
File file = new File(new URI(url.toString()));
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
return fis;
|
||||
streamForImage = new FileInputStream(file);
|
||||
contentLength = file.length();
|
||||
}
|
||||
|
||||
public InputStream getStreamForImage() throws Exception {
|
||||
return streamForImage;
|
||||
}
|
||||
|
||||
public String execute() throws Exception {
|
||||
@@ -259,9 +266,7 @@ public class StreamResultTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
public long getContentLength() throws Exception {
|
||||
URL url = ClassLoaderUtil.getResource("log4j2.xml", StreamResultTest.class);
|
||||
File file = new File(new URI(url.toString()));
|
||||
return file.length();
|
||||
return contentLength;
|
||||
}
|
||||
|
||||
public String getStreamForImageAsString() {
|
||||
|
||||
@@ -31,6 +31,8 @@ import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.struts.mock.MockPageContext;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
|
||||
|
||||
/**
|
||||
@@ -100,6 +102,35 @@ public class InvocationSessionStoreTest extends StrutsInternalTestCase {
|
||||
assertNull(savedInvocation);//Currently we don't support invocation restore from serialized session
|
||||
}
|
||||
|
||||
public void testStoreAndLoadPreservesPageContext() {
|
||||
ActionContext actionContext = ActionContext.getContext();
|
||||
|
||||
// Create mock PageContext to put with the saved context (simulating a PageContext previously
|
||||
// used and closed after generating JSP output).
|
||||
MockPageContext mockSavedPageContext = new MockPageContext();
|
||||
actionContext.put(ServletActionContext.PAGE_CONTEXT, mockSavedPageContext);
|
||||
assertEquals(mockSavedPageContext, ActionContext.getContext().get(ServletActionContext.PAGE_CONTEXT));
|
||||
|
||||
InvocationSessionStore.storeInvocation(INVOCATION_KEY, TOKEN_VALUE, invocation);
|
||||
|
||||
ActionContext actionContext2 = new ActionContext(new HashMap<String, Object>());
|
||||
actionContext2.setSession(session);
|
||||
ActionContext.setContext(actionContext2);
|
||||
assertEquals(actionContext2, ActionContext.getContext());
|
||||
|
||||
// Create mock PageContext to put with the current context (simulating a PageContext
|
||||
// associated with the current (active) process flow). In real-world processing it
|
||||
// will usually be null, but if non-null it should be preserved/restored upon load of the
|
||||
// saved context.
|
||||
MockPageContext mockPreviousPageContext = new MockPageContext();
|
||||
actionContext2.put(ServletActionContext.PAGE_CONTEXT, mockPreviousPageContext);
|
||||
assertEquals(mockPreviousPageContext, ActionContext.getContext().get(ServletActionContext.PAGE_CONTEXT));
|
||||
|
||||
InvocationSessionStore.loadInvocation(INVOCATION_KEY, TOKEN_VALUE);
|
||||
assertEquals(actionContext, ActionContext.getContext());
|
||||
assertEquals(mockPreviousPageContext, ActionContext.getContext().get(ServletActionContext.PAGE_CONTEXT));
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
stack = ActionContext.getContext().getValueStack();
|
||||
|
||||
@@ -196,6 +196,21 @@ public class RadioTest extends AbstractUITagTest {
|
||||
verify(RadioTag.class.getResource("Radio-7.txt"));
|
||||
}
|
||||
|
||||
public void testNotExistingListValueKey() throws Exception {
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setName("myname");
|
||||
tag.setLabel("mylabel");
|
||||
tag.setList("#{'a':'aaa', 'b':'bbb', 'c':'ccc'}");
|
||||
tag.setListValueKey("notExistingProperty");
|
||||
|
||||
tag.setPageContext(pageContext);
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
verify(SelectTag.class.getResource("Radio-8.txt"));
|
||||
}
|
||||
|
||||
private void prepareTagGeneric(RadioTag tag) {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
|
||||
@@ -637,6 +637,21 @@ public class SelectTest extends AbstractUITagTest {
|
||||
verify(SelectTag.class.getResource("Select-13.txt"));
|
||||
}
|
||||
|
||||
public void testNotExistingListValueKey() throws Exception {
|
||||
SelectTag tag = new SelectTag();
|
||||
tag.setName("foo");
|
||||
tag.setLabel("mylabel");
|
||||
tag.setList("#{'a':'aaa', 'b':'bbb', 'c':'ccc'}");
|
||||
tag.setListValueKey("notExistingProperty");
|
||||
|
||||
tag.setPageContext(pageContext);
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
verify(SelectTag.class.getResource("Select-16.txt"));
|
||||
}
|
||||
|
||||
public class IdName {
|
||||
private String name;
|
||||
private Integer id;
|
||||
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE xwork PUBLIC
|
||||
"-//Apache Struts//XWork 2.5//EN"
|
||||
"http://struts.apache.org/dtds/xwork-2.5.dtd"
|
||||
>
|
||||
|
||||
<xwork>
|
||||
|
||||
<constant name="struts.devMode" value="false" />
|
||||
<constant name="devMode" value="false" />
|
||||
<constant name="struts.i18n.reload" value="false" />
|
||||
<constant name="logMissingProperties" value="false" />
|
||||
<constant name="enableOGNLExpressionCache" value="true" />
|
||||
<constant name="enableOGNLEvalExpression" value="false" />
|
||||
<constant name="reloadXmlConfiguration" value="false" />
|
||||
<constant name="struts.ognl.allowStaticMethodAccess" value="false" />
|
||||
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
|
||||
<constant name="struts.dispatcher.errorHandler" value="struts" />
|
||||
|
||||
<bean class="com.opensymphony.xwork2.ObjectFactory" name="default" />
|
||||
<bean class="org.apache.struts2.views.freemarker.FreemarkerThemeTemplateLoader" />
|
||||
<bean class="org.apache.struts2.views.freemarker.FreemarkerManager" name="default" />
|
||||
<bean class="org.apache.struts2.views.velocity.VelocityManager" name="default" optional="true" />
|
||||
<bean class="org.apache.struts2.components.template.TemplateEngineManager" />
|
||||
<bean class="com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter" />
|
||||
<bean class="com.opensymphony.xwork2.ognl.OgnlUtil" />
|
||||
<bean class="org.apache.struts2.views.jsp.ui.OgnlTool" />
|
||||
|
||||
<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="default" class="org.apache.struts2.factory.StrutsActionProxyFactory"/>
|
||||
<bean type="com.opensymphony.xwork2.FileManager" name="system" class="com.opensymphony.xwork2.util.fs.DefaultFileManager" scope="singleton"/>
|
||||
<bean type="com.opensymphony.xwork2.FileManagerFactory" name="default" class="com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory" scope="singleton"/>
|
||||
<bean type="com.opensymphony.xwork2.LocalizedTextProvider" name="global-only" class="com.opensymphony.xwork2.util.GlobalLocalizedTextProvider" scope="singleton" />
|
||||
<bean type="com.opensymphony.xwork2.LocalizedTextProvider" name="default" class="com.opensymphony.xwork2.util.StrutsLocalizedTextProvider" scope="singleton" />
|
||||
<bean type="com.opensymphony.xwork2.TextProvider" name="system" class="com.opensymphony.xwork2.DefaultTextProvider" scope="singleton" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultConversionAnnotationProcessor" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.ConversionFileProcessor" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultConversionFileProcessor" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.ObjectTypeDeterminer" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer"/>
|
||||
<bean type="com.opensymphony.xwork2.conversion.TypeConverterCreator" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterCreator" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.TypeConverterHolder" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterHolder" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.impl.XWorkConverter" name="default" class="com.opensymphony.xwork2.conversion.impl.XWorkConverter" />
|
||||
|
||||
<bean type="com.opensymphony.xwork2.factory.ActionFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultActionFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.ConverterFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultConverterFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.ResultFactory" name="default" class="org.apache.struts2.factory.StrutsResultFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.UnknownHandlerFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultUnknownHandlerFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.ValidatorFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultValidatorFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.InterceptorFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultInterceptorFactory" />
|
||||
<bean type="com.opensymphony.xwork2.util.ValueStackFactory" name="default" class="com.opensymphony.xwork2.ognl.OgnlValueStackFactory" />
|
||||
<bean type="com.opensymphony.xwork2.util.reflection.ReflectionProvider" name="default" class="com.opensymphony.xwork2.ognl.OgnlReflectionProvider" />
|
||||
|
||||
<bean type="ognl.MethodAccessor" name="java.lang.Object" class="com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor" />
|
||||
<bean type="ognl.MethodAccessor" name="com.opensymphony.xwork2.util.CompoundRoot" class="com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="com.opensymphony.xwork2.util.CompoundRoot" class="com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="org.apache.struts2.dispatcher.HttpParameters" class="com.opensymphony.xwork2.ognl.accessor.HttpParametersPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="com.opensymphony.xwork2.ognl.ObjectProxy" class="com.opensymphony.xwork2.ognl.accessor.ObjectProxyPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="org.apache.struts2.dispatcher.Parameter" class="com.opensymphony.xwork2.ognl.accessor.ParameterPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.ArrayList" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Collection" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Enumeration" class="com.opensymphony.xwork2.ognl.accessor.XWorkEnumerationAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.HashMap" class="com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.HashSet" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Iterator" class="com.opensymphony.xwork2.ognl.accessor.XWorkIteratorPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.List" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Map" class="com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.lang.Object" class="com.opensymphony.xwork2.ognl.accessor.ObjectAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Set" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
|
||||
|
||||
</xwork>
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE xwork PUBLIC
|
||||
"-//Apache Struts//XWork 2.5//EN"
|
||||
"http://struts.apache.org/dtds/xwork-2.5.dtd"
|
||||
>
|
||||
|
||||
<xwork>
|
||||
|
||||
<constant name="struts.devMode" value="true" />
|
||||
<constant name="devMode" value="true" />
|
||||
<constant name="struts.i18n.reload" value="false" />
|
||||
<constant name="logMissingProperties" value="false" />
|
||||
<constant name="enableOGNLExpressionCache" value="true" />
|
||||
<constant name="enableOGNLEvalExpression" value="false" />
|
||||
<constant name="reloadXmlConfiguration" value="false" />
|
||||
<constant name="struts.ognl.allowStaticMethodAccess" value="true" />
|
||||
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
|
||||
<constant name="struts.dispatcher.errorHandler" value="struts" />
|
||||
|
||||
<bean class="com.opensymphony.xwork2.ObjectFactory" name="default" />
|
||||
<bean class="org.apache.struts2.views.freemarker.FreemarkerThemeTemplateLoader" />
|
||||
<bean class="org.apache.struts2.views.freemarker.FreemarkerManager" name="default" />
|
||||
<bean class="org.apache.struts2.views.velocity.VelocityManager" name="default" optional="true" />
|
||||
<bean class="org.apache.struts2.components.template.TemplateEngineManager" />
|
||||
<bean class="com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter" />
|
||||
<bean class="com.opensymphony.xwork2.ognl.OgnlUtil" />
|
||||
<bean class="org.apache.struts2.views.jsp.ui.OgnlTool" />
|
||||
|
||||
<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="default" class="org.apache.struts2.factory.StrutsActionProxyFactory"/>
|
||||
<bean type="com.opensymphony.xwork2.FileManager" name="system" class="com.opensymphony.xwork2.util.fs.DefaultFileManager" scope="singleton"/>
|
||||
<bean type="com.opensymphony.xwork2.FileManagerFactory" name="default" class="com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory" scope="singleton"/>
|
||||
<bean type="com.opensymphony.xwork2.LocalizedTextProvider" name="global-only" class="com.opensymphony.xwork2.util.GlobalLocalizedTextProvider" scope="singleton" />
|
||||
<bean type="com.opensymphony.xwork2.LocalizedTextProvider" name="default" class="com.opensymphony.xwork2.util.StrutsLocalizedTextProvider" scope="singleton" />
|
||||
<bean type="com.opensymphony.xwork2.TextProvider" name="system" class="com.opensymphony.xwork2.DefaultTextProvider" scope="singleton" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultConversionAnnotationProcessor" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.ConversionFileProcessor" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultConversionFileProcessor" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.ObjectTypeDeterminer" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer"/>
|
||||
<bean type="com.opensymphony.xwork2.conversion.TypeConverterCreator" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterCreator" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.TypeConverterHolder" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterHolder" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.impl.XWorkConverter" name="default" class="com.opensymphony.xwork2.conversion.impl.XWorkConverter" />
|
||||
|
||||
<bean type="com.opensymphony.xwork2.factory.ActionFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultActionFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.ConverterFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultConverterFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.ResultFactory" name="default" class="org.apache.struts2.factory.StrutsResultFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.UnknownHandlerFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultUnknownHandlerFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.ValidatorFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultValidatorFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.InterceptorFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultInterceptorFactory" />
|
||||
<bean type="com.opensymphony.xwork2.util.ValueStackFactory" name="default" class="com.opensymphony.xwork2.ognl.OgnlValueStackFactory" />
|
||||
<bean type="com.opensymphony.xwork2.util.reflection.ReflectionProvider" name="default" class="com.opensymphony.xwork2.ognl.OgnlReflectionProvider" />
|
||||
|
||||
<bean type="ognl.MethodAccessor" name="java.lang.Object" class="com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor" />
|
||||
<bean type="ognl.MethodAccessor" name="com.opensymphony.xwork2.util.CompoundRoot" class="com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="com.opensymphony.xwork2.util.CompoundRoot" class="com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="org.apache.struts2.dispatcher.HttpParameters" class="com.opensymphony.xwork2.ognl.accessor.HttpParametersPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="com.opensymphony.xwork2.ognl.ObjectProxy" class="com.opensymphony.xwork2.ognl.accessor.ObjectProxyPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="org.apache.struts2.dispatcher.Parameter" class="com.opensymphony.xwork2.ognl.accessor.ParameterPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.ArrayList" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Collection" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Enumeration" class="com.opensymphony.xwork2.ognl.accessor.XWorkEnumerationAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.HashMap" class="com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.HashSet" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Iterator" class="com.opensymphony.xwork2.ognl.accessor.XWorkIteratorPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.List" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Map" class="com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.lang.Object" class="com.opensymphony.xwork2.ognl.accessor.ObjectAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Set" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
|
||||
|
||||
</xwork>
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE xwork PUBLIC
|
||||
"-//Apache Struts//XWork 2.5//EN"
|
||||
"http://struts.apache.org/dtds/xwork-2.5.dtd"
|
||||
>
|
||||
|
||||
<xwork>
|
||||
|
||||
<constant name="struts.devMode" value="false" />
|
||||
<constant name="devMode" value="false" />
|
||||
<constant name="struts.i18n.reload" value="false" />
|
||||
<constant name="logMissingProperties" value="false" />
|
||||
<constant name="enableOGNLExpressionCache" value="true" />
|
||||
<constant name="enableOGNLEvalExpression" value="false" />
|
||||
<constant name="reloadXmlConfiguration" value="false" />
|
||||
<constant name="struts.ognl.allowStaticMethodAccess" value="true" />
|
||||
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
|
||||
<constant name="struts.dispatcher.errorHandler" value="struts" />
|
||||
|
||||
<bean class="com.opensymphony.xwork2.ObjectFactory" name="default" />
|
||||
<bean class="org.apache.struts2.views.freemarker.FreemarkerThemeTemplateLoader" />
|
||||
<bean class="org.apache.struts2.views.freemarker.FreemarkerManager" name="default" />
|
||||
<bean class="org.apache.struts2.views.velocity.VelocityManager" name="default" optional="true" />
|
||||
<bean class="org.apache.struts2.components.template.TemplateEngineManager" />
|
||||
<bean class="com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter" />
|
||||
<bean class="com.opensymphony.xwork2.ognl.OgnlUtil" />
|
||||
<bean class="org.apache.struts2.views.jsp.ui.OgnlTool" />
|
||||
|
||||
<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="default" class="org.apache.struts2.factory.StrutsActionProxyFactory"/>
|
||||
<bean type="com.opensymphony.xwork2.FileManager" name="system" class="com.opensymphony.xwork2.util.fs.DefaultFileManager" scope="singleton"/>
|
||||
<bean type="com.opensymphony.xwork2.FileManagerFactory" name="default" class="com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory" scope="singleton"/>
|
||||
<bean type="com.opensymphony.xwork2.LocalizedTextProvider" name="global-only" class="com.opensymphony.xwork2.util.GlobalLocalizedTextProvider" scope="singleton" />
|
||||
<bean type="com.opensymphony.xwork2.LocalizedTextProvider" name="default" class="com.opensymphony.xwork2.util.StrutsLocalizedTextProvider" scope="singleton" />
|
||||
<bean type="com.opensymphony.xwork2.TextProvider" name="system" class="com.opensymphony.xwork2.DefaultTextProvider" scope="singleton" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultConversionAnnotationProcessor" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.ConversionFileProcessor" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultConversionFileProcessor" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.ObjectTypeDeterminer" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer"/>
|
||||
<bean type="com.opensymphony.xwork2.conversion.TypeConverterCreator" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterCreator" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.TypeConverterHolder" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterHolder" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.impl.XWorkConverter" name="default" class="com.opensymphony.xwork2.conversion.impl.XWorkConverter" />
|
||||
|
||||
<bean type="com.opensymphony.xwork2.factory.ActionFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultActionFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.ConverterFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultConverterFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.ResultFactory" name="default" class="org.apache.struts2.factory.StrutsResultFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.UnknownHandlerFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultUnknownHandlerFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.ValidatorFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultValidatorFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.InterceptorFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultInterceptorFactory" />
|
||||
<bean type="com.opensymphony.xwork2.util.ValueStackFactory" name="default" class="com.opensymphony.xwork2.ognl.OgnlValueStackFactory" />
|
||||
<bean type="com.opensymphony.xwork2.util.reflection.ReflectionProvider" name="default" class="com.opensymphony.xwork2.ognl.OgnlReflectionProvider" />
|
||||
|
||||
<bean type="ognl.MethodAccessor" name="java.lang.Object" class="com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor" />
|
||||
<bean type="ognl.MethodAccessor" name="com.opensymphony.xwork2.util.CompoundRoot" class="com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="com.opensymphony.xwork2.util.CompoundRoot" class="com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="org.apache.struts2.dispatcher.HttpParameters" class="com.opensymphony.xwork2.ognl.accessor.HttpParametersPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="com.opensymphony.xwork2.ognl.ObjectProxy" class="com.opensymphony.xwork2.ognl.accessor.ObjectProxyPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="org.apache.struts2.dispatcher.Parameter" class="com.opensymphony.xwork2.ognl.accessor.ParameterPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.ArrayList" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Collection" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Enumeration" class="com.opensymphony.xwork2.ognl.accessor.XWorkEnumerationAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.HashMap" class="com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.HashSet" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Iterator" class="com.opensymphony.xwork2.ognl.accessor.XWorkIteratorPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.List" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Map" class="com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.lang.Object" class="com.opensymphony.xwork2.ognl.accessor.ObjectAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Set" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
|
||||
|
||||
</xwork>
|
||||
-88
@@ -1,88 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE xwork PUBLIC
|
||||
"-//Apache Struts//XWork 2.5//EN"
|
||||
"http://struts.apache.org/dtds/xwork-2.5.dtd"
|
||||
>
|
||||
|
||||
<xwork>
|
||||
|
||||
<constant name="struts.devMode" value="true" />
|
||||
<constant name="devMode" value="true" />
|
||||
<constant name="struts.i18n.reload" value="false" />
|
||||
<constant name="logMissingProperties" value="false" />
|
||||
<constant name="enableOGNLExpressionCache" value="true" />
|
||||
<constant name="enableOGNLEvalExpression" value="false" />
|
||||
<constant name="reloadXmlConfiguration" value="false" />
|
||||
<constant name="struts.ognl.allowStaticMethodAccess" value="false" />
|
||||
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
|
||||
<constant name="struts.dispatcher.errorHandler" value="struts" />
|
||||
|
||||
<bean class="com.opensymphony.xwork2.ObjectFactory" name="default" />
|
||||
<bean class="org.apache.struts2.views.freemarker.FreemarkerThemeTemplateLoader" />
|
||||
<bean class="org.apache.struts2.views.freemarker.FreemarkerManager" name="default" />
|
||||
<bean class="org.apache.struts2.views.velocity.VelocityManager" name="default" optional="true" />
|
||||
<bean class="org.apache.struts2.components.template.TemplateEngineManager" />
|
||||
<bean class="com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter" />
|
||||
<bean class="com.opensymphony.xwork2.ognl.OgnlUtil" />
|
||||
<bean class="org.apache.struts2.views.jsp.ui.OgnlTool" />
|
||||
|
||||
<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="default" class="org.apache.struts2.factory.StrutsActionProxyFactory"/>
|
||||
<bean type="com.opensymphony.xwork2.FileManager" name="system" class="com.opensymphony.xwork2.util.fs.DefaultFileManager" scope="singleton"/>
|
||||
<bean type="com.opensymphony.xwork2.FileManagerFactory" name="default" class="com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory" scope="singleton"/>
|
||||
<bean type="com.opensymphony.xwork2.LocalizedTextProvider" name="global-only" class="com.opensymphony.xwork2.util.GlobalLocalizedTextProvider" scope="singleton" />
|
||||
<bean type="com.opensymphony.xwork2.LocalizedTextProvider" name="default" class="com.opensymphony.xwork2.util.StrutsLocalizedTextProvider" scope="singleton" />
|
||||
<bean type="com.opensymphony.xwork2.TextProvider" name="system" class="com.opensymphony.xwork2.DefaultTextProvider" scope="singleton" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultConversionAnnotationProcessor" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.ConversionFileProcessor" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultConversionFileProcessor" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.ObjectTypeDeterminer" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer"/>
|
||||
<bean type="com.opensymphony.xwork2.conversion.TypeConverterCreator" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterCreator" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.TypeConverterHolder" name="default" class="com.opensymphony.xwork2.conversion.impl.DefaultTypeConverterHolder" />
|
||||
<bean type="com.opensymphony.xwork2.conversion.impl.XWorkConverter" name="default" class="com.opensymphony.xwork2.conversion.impl.XWorkConverter" />
|
||||
|
||||
<bean type="com.opensymphony.xwork2.factory.ActionFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultActionFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.ConverterFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultConverterFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.ResultFactory" name="default" class="org.apache.struts2.factory.StrutsResultFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.UnknownHandlerFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultUnknownHandlerFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.ValidatorFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultValidatorFactory" />
|
||||
<bean type="com.opensymphony.xwork2.factory.InterceptorFactory" name="default" class="com.opensymphony.xwork2.factory.DefaultInterceptorFactory" />
|
||||
<bean type="com.opensymphony.xwork2.util.ValueStackFactory" name="default" class="com.opensymphony.xwork2.ognl.OgnlValueStackFactory" />
|
||||
<bean type="com.opensymphony.xwork2.util.reflection.ReflectionProvider" name="default" class="com.opensymphony.xwork2.ognl.OgnlReflectionProvider" />
|
||||
|
||||
<bean type="ognl.MethodAccessor" name="java.lang.Object" class="com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor" />
|
||||
<bean type="ognl.MethodAccessor" name="com.opensymphony.xwork2.util.CompoundRoot" class="com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="com.opensymphony.xwork2.util.CompoundRoot" class="com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="org.apache.struts2.dispatcher.HttpParameters" class="com.opensymphony.xwork2.ognl.accessor.HttpParametersPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="com.opensymphony.xwork2.ognl.ObjectProxy" class="com.opensymphony.xwork2.ognl.accessor.ObjectProxyPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="org.apache.struts2.dispatcher.Parameter" class="com.opensymphony.xwork2.ognl.accessor.ParameterPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.ArrayList" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Collection" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Enumeration" class="com.opensymphony.xwork2.ognl.accessor.XWorkEnumerationAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.HashMap" class="com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.HashSet" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Iterator" class="com.opensymphony.xwork2.ognl.accessor.XWorkIteratorPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.List" class="com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Map" class="com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.lang.Object" class="com.opensymphony.xwork2.ognl.accessor.ObjectAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Set" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
|
||||
|
||||
</xwork>
|
||||
@@ -29,6 +29,5 @@
|
||||
<Root level="info">
|
||||
<AppenderRef ref="STDOUT"/>
|
||||
</Root>
|
||||
<Logger name="org.apache.struts2.views.xslt" level="debug"/>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
@@ -0,0 +1,8 @@
|
||||
<tr>
|
||||
<td class="tdLabel"><label for="myname" class="label">mylabel:</label></td>
|
||||
<td class="tdInput">
|
||||
<input type="radio" name="myname" id="mynamea" value="a"/><label for="mynamea">notExistingProperty</label>
|
||||
<input type="radio" name="myname" id="mynameb" value="b"/><label for="mynameb">notExistingProperty</label>
|
||||
<input type="radio" name="myname" id="mynamec" value="c"/><label for="mynamec">notExistingProperty</label>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -0,0 +1,10 @@
|
||||
<tr>
|
||||
<td class="tdLabel"><label for="foo" class="label">mylabel:</label></td>
|
||||
<td class="tdInput">
|
||||
<select name="foo" id="foo">
|
||||
<option value="a">notExistingProperty</option>
|
||||
<option value="b">notExistingProperty</option>
|
||||
<option value="c">notExistingProperty</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>5.1.3.Final</version>
|
||||
<version>5.4.3.Final</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-cdi-plugin</artifactId>
|
||||
@@ -47,7 +47,7 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.weld</groupId>
|
||||
<groupId>org.jboss.weld.se</groupId>
|
||||
<artifactId>weld-se</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-config-browser-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-convention-plugin</artifactId>
|
||||
|
||||
+2
-2
@@ -475,7 +475,7 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
private ClassFinder classFinder;
|
||||
|
||||
public InfoBuildingVisitor(ClassFinder classFinder) {
|
||||
super(Opcodes.ASM5);
|
||||
super(Opcodes.ASM7);
|
||||
this.classFinder = classFinder;
|
||||
}
|
||||
|
||||
@@ -556,7 +556,7 @@ public class DefaultClassFinder implements ClassFinder {
|
||||
private Info info;
|
||||
|
||||
public InfoBuildingMethodVisitor() {
|
||||
super(Opcodes.ASM5);
|
||||
super(Opcodes.ASM7);
|
||||
}
|
||||
|
||||
public InfoBuildingMethodVisitor(Info info) {
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-dwr-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-embeddedjsp-plugin</artifactId>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-gxp-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-jasperreports-plugin</artifactId>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-javatemplates-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-jfreechart-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-json-plugin</artifactId>
|
||||
|
||||
@@ -71,13 +71,6 @@ public class JSONInterceptor extends AbstractInterceptor {
|
||||
private String jsonContentType = "application/json";
|
||||
private String jsonRpcContentType = "application/json-rpc";
|
||||
|
||||
private JSONUtil jsonUtil;
|
||||
|
||||
@Inject
|
||||
public void setJsonUtil(JSONUtil jsonUtil) {
|
||||
this.jsonUtil = jsonUtil;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
HttpServletRequest request = ServletActionContext.getRequest();
|
||||
@@ -175,6 +168,8 @@ public class JSONInterceptor extends AbstractInterceptor {
|
||||
result = rpcResponse;
|
||||
}
|
||||
|
||||
JSONUtil jsonUtil = invocation.getInvocationContext().getContainer().getInstance(JSONUtil.class);
|
||||
|
||||
String json = jsonUtil.serialize(result, excludeProperties, getIncludeProperties(),
|
||||
ignoreHierarchy, excludeNullProperties);
|
||||
json = addCallbackIfApplicable(request, json);
|
||||
|
||||
@@ -93,9 +93,6 @@ public class JSONInterceptorTest extends StrutsTestCase {
|
||||
this.request.addHeader("Content-Type", "application/json-rpc");
|
||||
|
||||
JSONInterceptor interceptor = new JSONInterceptor();
|
||||
JSONUtil jsonUtil = new JSONUtil();
|
||||
jsonUtil.setWriter(new DefaultJSONWriter());
|
||||
interceptor.setJsonUtil(jsonUtil);
|
||||
SMDActionTest1 action = new SMDActionTest1();
|
||||
|
||||
this.invocation.setAction(action);
|
||||
@@ -116,9 +113,6 @@ public class JSONInterceptorTest extends StrutsTestCase {
|
||||
|
||||
JSONInterceptor interceptor = new JSONInterceptor();
|
||||
interceptor.setEnableSMD(true);
|
||||
JSONUtil jsonUtil = new JSONUtil();
|
||||
jsonUtil.setWriter(new DefaultJSONWriter());
|
||||
interceptor.setJsonUtil(jsonUtil);
|
||||
SMDActionTest2 action = new SMDActionTest2();
|
||||
|
||||
this.invocation.setAction(action);
|
||||
@@ -137,9 +131,6 @@ public class JSONInterceptorTest extends StrutsTestCase {
|
||||
|
||||
JSONInterceptor interceptor = new JSONInterceptor();
|
||||
interceptor.setEnableSMD(true);
|
||||
JSONUtil jsonUtil = new JSONUtil();
|
||||
jsonUtil.setWriter(new DefaultJSONWriter());
|
||||
interceptor.setJsonUtil(jsonUtil);
|
||||
SMDActionTest2 action = new SMDActionTest2();
|
||||
|
||||
this.invocation.setAction(action);
|
||||
@@ -158,9 +149,6 @@ public class JSONInterceptorTest extends StrutsTestCase {
|
||||
|
||||
JSONInterceptor interceptor = new JSONInterceptor();
|
||||
interceptor.setEnableSMD(true);
|
||||
JSONUtil jsonUtil = new JSONUtil();
|
||||
jsonUtil.setWriter(new DefaultJSONWriter());
|
||||
interceptor.setJsonUtil(jsonUtil);
|
||||
SMDActionTest1 action = new SMDActionTest1();
|
||||
|
||||
this.invocation.setAction(action);
|
||||
@@ -206,9 +194,6 @@ public class JSONInterceptorTest extends StrutsTestCase {
|
||||
|
||||
JSONInterceptor interceptor = new JSONInterceptor();
|
||||
interceptor.setEnableSMD(true);
|
||||
JSONUtil jsonUtil = new JSONUtil();
|
||||
jsonUtil.setWriter(new DefaultJSONWriter());
|
||||
interceptor.setJsonUtil(jsonUtil);
|
||||
SMDActionTest1 action = new SMDActionTest1();
|
||||
|
||||
this.invocation.setAction(action);
|
||||
@@ -244,9 +229,6 @@ public class JSONInterceptorTest extends StrutsTestCase {
|
||||
|
||||
JSONInterceptor interceptor = new JSONInterceptor();
|
||||
interceptor.setEnableSMD(true);
|
||||
JSONUtil jsonUtil = new JSONUtil();
|
||||
jsonUtil.setWriter(new DefaultJSONWriter());
|
||||
interceptor.setJsonUtil(jsonUtil);
|
||||
SMDActionTest2 action = new SMDActionTest2();
|
||||
|
||||
this.invocation.setAction(action);
|
||||
@@ -272,9 +254,6 @@ public class JSONInterceptorTest extends StrutsTestCase {
|
||||
|
||||
JSONInterceptor interceptor = new JSONInterceptor();
|
||||
interceptor.setEnableSMD(true);
|
||||
JSONUtil jsonUtil = new JSONUtil();
|
||||
jsonUtil.setWriter(new DefaultJSONWriter());
|
||||
interceptor.setJsonUtil(jsonUtil);
|
||||
SMDActionTest1 action = new SMDActionTest1();
|
||||
|
||||
this.invocation.setAction(action);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-junit-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-oval-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-pell-multipart-plugin</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-plexus-plugin</artifactId>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-plugins</artifactId>
|
||||
<version>2.5.20</version>
|
||||
<version>2.5.23</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-portlet-tiles-plugin</artifactId>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user