mirror of
https://github.com/apache/struts.git
synced 2026-08-09 00:27:04 +00:00
Compare commits
99 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6536dc65d8 | |||
| 915386816b | |||
| 80c2de9e92 | |||
| b62e583646 | |||
| 8b359383a1 | |||
| 11e716f979 | |||
| 71c7064f29 | |||
| 09472808aa | |||
| d119ba8e13 | |||
| 86b45e96fc | |||
| 3c9465b857 | |||
| 0c73cf2e05 | |||
| 6785997412 | |||
| 5a7fce066f | |||
| 4fbada4cd9 | |||
| 3119eb65db | |||
| de3dabbe44 | |||
| 82f7904206 | |||
| 42e3da550f | |||
| f3cb89202d | |||
| 836a27692e | |||
| 6312572331 | |||
| e7db7ade62 | |||
| b77c2f476a | |||
| e6c1cec7f8 | |||
| a781b5a27b | |||
| b71732fa14 | |||
| 3f79d64e6a | |||
| 039fd9f4ee | |||
| 393d5be50c | |||
| cb59974903 | |||
| ecfdee137d | |||
| 8c37b1523f | |||
| 62b83021a2 | |||
| f3f2d52a1c | |||
| 61ded9a3e7 | |||
| d639b59f6d | |||
| 8e468a368e | |||
| ebe1b80ed2 | |||
| 957292ecdb | |||
| 06290cef91 | |||
| a6a4529503 | |||
| 64d054221f | |||
| dc4e403d30 | |||
| e6bc93daf2 | |||
| 0e4d5962e1 | |||
| 69102e9075 | |||
| 1c2b491a27 | |||
| 5af840b160 | |||
| b6b74a46ea | |||
| fc2aebd10a | |||
| ba041e1ee6 | |||
| 0c3534e8b4 | |||
| 9a2996f9b7 | |||
| 3825229f44 | |||
| 4b3ee53f93 | |||
| 68fb49c10e | |||
| 77c175c7be | |||
| 65b7e8c36f | |||
| 735bbc283e | |||
| 981885fd6a | |||
| 07b88fcc35 | |||
| 2cbe47297e | |||
| 545add9365 | |||
| ebecc7d39d | |||
| 226a1d49ce | |||
| 075ef7c4e1 | |||
| 1237110652 | |||
| 3f2518afa8 | |||
| 9f9edf4705 | |||
| 7e912742ed | |||
| c98b60cd9a | |||
| 5ae9688ae8 | |||
| b72200aabf | |||
| 16e7c9b459 | |||
| bea1c6f09f | |||
| 888884cc51 | |||
| b387abae01 | |||
| 059a2a6117 | |||
| c0a3be9fd8 | |||
| 4a7cae029a | |||
| 9873a7f56b | |||
| 086b514d59 | |||
| 6024dd6fa4 | |||
| 4eb2ee8384 | |||
| 8e49362bf8 | |||
| 7541d9ab35 | |||
| c82fdb5e76 | |||
| f40f9f15e5 | |||
| 2d9cdb73a5 | |||
| d07a496d5c | |||
| bef1f67d4a | |||
| e2718aa482 | |||
| b73fec4de0 | |||
| c2795d2e30 | |||
| a987e31a0e | |||
| 6aff5b7faa | |||
| 5b40f9f48e | |||
| e9d0a5518c |
@@ -1,3 +1,4 @@
|
||||
# Documentation https://s.apache.org/asfyaml
|
||||
notifications:
|
||||
commits: commits@struts.apache.org
|
||||
# Send all issue emails (new, closed, comments) to issues@
|
||||
@@ -8,3 +9,6 @@ notifications:
|
||||
pullrequests_comment: issues@struts.apache.org
|
||||
# Link opened PRs with JIRA
|
||||
jira_options: link label worklog
|
||||
|
||||
github:
|
||||
del_branch_on_merge: true
|
||||
|
||||
+1
-1
@@ -14,5 +14,5 @@
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
|
||||
|
||||
+8
-11
@@ -1,10 +1,10 @@
|
||||
dist: trusty
|
||||
dist: jammy
|
||||
language: java
|
||||
sudo: false
|
||||
|
||||
jdk:
|
||||
- oraclejdk9
|
||||
- oraclejdk11
|
||||
- openjdk11
|
||||
- openjdk17
|
||||
|
||||
install: true
|
||||
|
||||
@@ -13,18 +13,15 @@ global:
|
||||
- secure: iI7IpfDtS+LUyS2yNuRCR3KelNyvBHuoMQ3gb1UNmR5SSL7jO/p3olQWrQROs28FJ+dpE3lHyIjoHrebKQGJHHAgTG2XWxn+G3fDsf+wSSFSLoDGj0o2SgGXooBbR2dccnNZHCyQaOyE2cIPWaOxrQZFE4No70LQB4mrP/gdkoc=
|
||||
matrix:
|
||||
include:
|
||||
- jdk: oraclejdk8
|
||||
env: STRUTS_IT=true # do integration tests and coverage reports when jdk7,9 and 11 tests prospered
|
||||
- jdk: openjdk8
|
||||
env: STRUTS_IT=true # do integration tests and coverage reports when jdk 11 and 17 tests prospered
|
||||
|
||||
script:
|
||||
- if [ "$STRUTS_IT" == "true" ]; then
|
||||
./mvnw clean verify org.jacoco:jacoco-maven-plugin:report org.jacoco:jacoco-maven-plugin:report-integration org.eluder.coveralls:coveralls-maven-plugin:report -Ptravis-coveralls -DskipAssembly -B;
|
||||
./mvnw clean install -DskipTests -DskipAssembly -B;
|
||||
./mvnw test org.jacoco:jacoco-maven-plugin:report org.jacoco:jacoco-maven-plugin:report-integration org.eluder.coveralls:coveralls-maven-plugin:report -Ptravis-coveralls -DskipAssembly -B;
|
||||
else
|
||||
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
|
||||
./mvnw test -DskipAssembly -B;
|
||||
else
|
||||
./mvnw test -DskipAssembly -Dupdate-impact -B;
|
||||
fi;
|
||||
./mvnw clean package test -DskipAssembly -B;
|
||||
fi;
|
||||
|
||||
cache:
|
||||
|
||||
Vendored
+10
-10
@@ -39,12 +39,12 @@ pipeline {
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'mvn -B clean install -DskipTests -DskipAssembly'
|
||||
sh './mvnw -B clean install -DskipTests -DskipAssembly'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh 'mvn -B test'
|
||||
sh './mvnw -B test'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
@@ -74,12 +74,12 @@ pipeline {
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'mvn -B clean install -DskipTests -DskipAssembly'
|
||||
sh './mvnw -B clean install -DskipTests -DskipAssembly'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh 'mvn -B test'
|
||||
sh './mvnw -B test'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
@@ -94,7 +94,7 @@ pipeline {
|
||||
}
|
||||
steps {
|
||||
withCredentials([string(credentialsId: 'asf-struts-sonarcloud', variable: 'SONARCLOUD_TOKEN')]) {
|
||||
sh 'mvn sonar:sonar -DskipAssembly -Dsonar.login=${SONARCLOUD_TOKEN}'
|
||||
sh './mvnw sonar:sonar -DskipAssembly -Dsonar.login=${SONARCLOUD_TOKEN}'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,12 +119,12 @@ pipeline {
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'mvn -B clean install -DskipTests -DskipAssembly'
|
||||
sh './mvnw -B clean install -DskipTests -DskipAssembly'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh 'mvn -B test'
|
||||
sh './mvnw -B test'
|
||||
// step([$class: 'JiraIssueUpdater', issueSelector: [$class: 'DefaultIssueSelector'], scm: scm])
|
||||
}
|
||||
post {
|
||||
@@ -142,7 +142,7 @@ pipeline {
|
||||
dir("local-snapshots-dir/") {
|
||||
deleteDir()
|
||||
}
|
||||
sh 'mvn -B source:jar javadoc:jar -DskipAssembbly'
|
||||
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly'
|
||||
}
|
||||
}
|
||||
stage('Deploy Snapshot') {
|
||||
@@ -151,7 +151,7 @@ pipeline {
|
||||
}
|
||||
steps {
|
||||
withCredentials([file(credentialsId: 'lukaszlenart-repository-access-token', variable: 'CUSTOM_SETTINGS')]) {
|
||||
sh 'mvn -s \${CUSTOM_SETTINGS} deploy'
|
||||
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,7 +165,7 @@ pipeline {
|
||||
configName: 'Nightlies',
|
||||
transfers: [
|
||||
sshTransfer(
|
||||
remoteDirectory: '/x1/dist/struts',
|
||||
remoteDirectory: '/struts/snapshot',
|
||||
removePrefix: 'assembly/target/assembly/out',
|
||||
sourceFiles: 'assembly/target/assembly/out/struts-*.zip'
|
||||
)
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<version>6.0.1</version>
|
||||
</parent>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<version>6.0.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-rest-showcase</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<version>6.0.1</version>
|
||||
<name>Struts 2 Rest Showcase Webapp</name>
|
||||
<description>Struts 2 Rest Showcase Example</description>
|
||||
|
||||
@@ -108,9 +108,9 @@
|
||||
<finalName>struts2-rest-showcase</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
<version>8.1.16.v20140903</version>
|
||||
<version>9.4.46.v20220331</version>
|
||||
<configuration>
|
||||
<stopKey>CTRL+C</stopKey>
|
||||
<stopPort>8999</stopPort>
|
||||
|
||||
@@ -19,13 +19,14 @@
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<web-app id="starter" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
|
||||
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||
version="3.1">
|
||||
|
||||
<display-name>Struts 2 Rest Example</display-name>
|
||||
|
||||
|
||||
<!-- Filters -->
|
||||
<!-- START SNIPPET: filter -->
|
||||
<filter>
|
||||
|
||||
+20
-25
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<version>6.0.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-showcase</artifactId>
|
||||
@@ -101,7 +101,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -121,6 +121,11 @@
|
||||
<artifactId>log4j-jcl</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>opensymphony</groupId>
|
||||
@@ -144,24 +149,15 @@
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.htmlunit</groupId>
|
||||
<artifactId>htmlunit</artifactId>
|
||||
<version>2.39.0</version>
|
||||
<version>2.61.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- BeanValidation Example -->
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<version>6.1.2.Final</version>
|
||||
</dependency>
|
||||
|
||||
<!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
|
||||
This is only necessary in tests-->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>test</scope>
|
||||
<version>${hibernate-validator.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
@@ -171,11 +167,14 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>3.0.0-M4</version>
|
||||
<version>3.0.0-M6</version>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>it.org.apache.struts2.showcase.*Test</include>
|
||||
</includes>
|
||||
<systemPropertyVariables>
|
||||
<http.port>8090</http.port>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
@@ -193,22 +192,21 @@
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
<version>8.1.16.v20140903</version>
|
||||
<version>9.4.46.v20220331</version>
|
||||
<configuration>
|
||||
<stopKey>CTRL+C</stopKey>
|
||||
<stopPort>8999</stopPort>
|
||||
<systemProperties>
|
||||
<systemProperty>
|
||||
<name>log4j.configuration</name>
|
||||
<value>file:${basedir}/src/main/resources/log4j.properties</value>
|
||||
</systemProperty>
|
||||
<systemProperty>
|
||||
<name>slf4j</name>
|
||||
<value>false</value>
|
||||
</systemProperty>
|
||||
</systemProperties>
|
||||
<httpConnector>
|
||||
<port>8090</port>
|
||||
</httpConnector>
|
||||
<scanIntervalSeconds>10</scanIntervalSeconds>
|
||||
<webAppSourceDirectory>${basedir}/src/main/webapp/</webAppSourceDirectory>
|
||||
<webAppConfig>
|
||||
@@ -223,11 +221,8 @@
|
||||
<goals>
|
||||
<!-- stop any previous instance to free up the port -->
|
||||
<goal>stop</goal>
|
||||
<goal>run-forked</goal>
|
||||
<goal>start</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<waitForChild>false</waitForChild>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop-jetty</id>
|
||||
|
||||
+158
-171
@@ -22,16 +22,13 @@ package org.apache.struts2.showcase.source;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import com.opensymphony.xwork2.util.ClassLoaderUtil;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.action.ServletContextAware;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -42,202 +39,192 @@ import java.util.List;
|
||||
*/
|
||||
public class ViewSourceAction extends ActionSupport implements ServletContextAware {
|
||||
|
||||
private String page;
|
||||
private String className;
|
||||
private String config;
|
||||
private String page;
|
||||
private String className;
|
||||
private String config;
|
||||
|
||||
private List pageLines;
|
||||
private List classLines;
|
||||
private List configLines;
|
||||
private List<String> pageLines;
|
||||
private List<String> classLines;
|
||||
private List<String> configLines;
|
||||
|
||||
private int configLine;
|
||||
private int padding = 10;
|
||||
private int configLine;
|
||||
private int padding = 10;
|
||||
|
||||
private ServletContext servletContext;
|
||||
private ServletContext servletContext;
|
||||
|
||||
public String execute() throws MalformedURLException, IOException {
|
||||
public String execute() throws IOException {
|
||||
|
||||
if (page != null) {
|
||||
if (page != null) {
|
||||
|
||||
InputStream in = ClassLoaderUtil.getResourceAsStream(page.substring(page.indexOf("//") + 1), getClass());
|
||||
page = page.replace("//", "/");
|
||||
InputStream in = ClassLoaderUtil.getResourceAsStream(page.substring(page.indexOf("//") + 1), getClass());
|
||||
page = page.replace("//", "/");
|
||||
|
||||
if (in == null) {
|
||||
in = servletContext.getResourceAsStream(page);
|
||||
while (in == null && page.indexOf('/', 1) > 0) {
|
||||
page = page.substring(page.indexOf('/', 1));
|
||||
in = servletContext.getResourceAsStream(page);
|
||||
}
|
||||
}
|
||||
pageLines = read(in, -1);
|
||||
if (in == null) {
|
||||
in = servletContext.getResourceAsStream(page);
|
||||
while (in == null && page.indexOf('/', 1) > 0) {
|
||||
page = page.substring(page.indexOf('/', 1));
|
||||
in = servletContext.getResourceAsStream(page);
|
||||
}
|
||||
}
|
||||
pageLines = read(in, -1);
|
||||
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (className != null) {
|
||||
className = "/" + className.replace('.', '/') + ".java";
|
||||
InputStream in = getClass().getResourceAsStream(className);
|
||||
if (in == null) {
|
||||
in = servletContext.getResourceAsStream("/WEB-INF/src" + className);
|
||||
}
|
||||
classLines = read(in, -1);
|
||||
if (className != null) {
|
||||
className = "/" + className.replace('.', '/') + ".java";
|
||||
InputStream in = getClass().getResourceAsStream(className);
|
||||
if (in == null) {
|
||||
in = servletContext.getResourceAsStream("/WEB-INF/src/java" + className);
|
||||
}
|
||||
classLines = read(in, -1);
|
||||
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
final String rootPath = ServletActionContext.getServletContext().getRealPath("/");
|
||||
final String rootPathUnix = (rootPath != null ? rootPath.replace(File.separator, "/") : null); // Make path Unix-like for comparison (e.g. on Windows)
|
||||
final String rootPathFileURI = "file://" + rootPathUnix;
|
||||
final String collapsedRootPathFileURI = rootPathFileURI.replace("//", "/"); // Config string may have been transformed
|
||||
final String rootPathWarFileURI = "war:file://" + rootPathUnix;
|
||||
final String collapsedRootPathWarFileURI = rootPathWarFileURI.replace("//", "/"); // Config string may have been transformed
|
||||
|
||||
if (config != null && (rootPath == null || config.startsWith(rootPath) ||
|
||||
config.startsWith(rootPathFileURI) || config.startsWith(collapsedRootPathFileURI) ||
|
||||
config.startsWith(rootPathWarFileURI) || config.startsWith(collapsedRootPathWarFileURI))) {
|
||||
int pos = config.lastIndexOf(':');
|
||||
configLine = Integer.parseInt(config.substring(pos + 1));
|
||||
config = config.substring(0, pos).replace("//", "/");
|
||||
configLines = read(new URL(config).openStream(), configLine);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
if (config != null && config.startsWith("file:/")) {
|
||||
int pos = config.lastIndexOf(':');
|
||||
configLine = Integer.parseInt(config.substring(pos + 1));
|
||||
configLines = read(new URL(config.substring(0, pos)).openStream(), configLine);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param className the className to set
|
||||
*/
|
||||
public void setClassName(String className) {
|
||||
if (className != null && className.trim().length() > 0) {
|
||||
this.className = className;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param className the className to set
|
||||
*/
|
||||
public void setClassName(String className) {
|
||||
if (className != null && className.trim().length() > 0) {
|
||||
this.className = className;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param config the config to set
|
||||
*/
|
||||
public void setConfig(String config) {
|
||||
if (config != null && config.trim().length() > 0) {
|
||||
this.config = config;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param config the config to set
|
||||
*/
|
||||
public void setConfig(String config) {
|
||||
if (config != null && config.trim().length() > 0) {
|
||||
this.config = config;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param page the page to set
|
||||
*/
|
||||
public void setPage(String page) {
|
||||
if (page != null && page.trim().length() > 0) {
|
||||
this.page = page;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param page the page to set
|
||||
*/
|
||||
public void setPage(String page) {
|
||||
if (page != null && page.trim().length() > 0) {
|
||||
this.page = page;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param padding the padding to set
|
||||
*/
|
||||
public void setPadding(int padding) {
|
||||
this.padding = padding;
|
||||
}
|
||||
/**
|
||||
* @param padding the padding to set
|
||||
*/
|
||||
public void setPadding(int padding) {
|
||||
this.padding = padding;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the classLines
|
||||
*/
|
||||
public List getClassLines() {
|
||||
return classLines;
|
||||
}
|
||||
/**
|
||||
* @return the classLines
|
||||
*/
|
||||
public List<String> getClassLines() {
|
||||
return classLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the configLines
|
||||
*/
|
||||
public List getConfigLines() {
|
||||
return configLines;
|
||||
}
|
||||
/**
|
||||
* @return the configLines
|
||||
*/
|
||||
public List<String> getConfigLines() {
|
||||
return configLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the pageLines
|
||||
*/
|
||||
public List getPageLines() {
|
||||
return pageLines;
|
||||
}
|
||||
/**
|
||||
* @return the pageLines
|
||||
*/
|
||||
public List<String> getPageLines() {
|
||||
return pageLines;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the className
|
||||
*/
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
/**
|
||||
* @return the className
|
||||
*/
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the config
|
||||
*/
|
||||
public String getConfig() {
|
||||
return config;
|
||||
}
|
||||
/**
|
||||
* @return the config
|
||||
*/
|
||||
public String getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the page
|
||||
*/
|
||||
public String getPage() {
|
||||
return page;
|
||||
}
|
||||
/**
|
||||
* @return the page
|
||||
*/
|
||||
public String getPage() {
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the configLine
|
||||
*/
|
||||
public int getConfigLine() {
|
||||
return configLine;
|
||||
}
|
||||
/**
|
||||
* @return the configLine
|
||||
*/
|
||||
public int getConfigLine() {
|
||||
return configLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the padding
|
||||
*/
|
||||
public int getPadding() {
|
||||
return padding;
|
||||
}
|
||||
/**
|
||||
* @return the padding
|
||||
*/
|
||||
public int getPadding() {
|
||||
return padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in a stream, optionally only including the target line number
|
||||
* and its padding
|
||||
*
|
||||
* @param in The input stream
|
||||
* @param targetLineNumber The target line number, negative to read all
|
||||
* @return A list of lines
|
||||
*/
|
||||
private List read(InputStream in, int targetLineNumber) {
|
||||
List snippet = null;
|
||||
if (in != null) {
|
||||
snippet = new ArrayList();
|
||||
int startLine = 0;
|
||||
int endLine = Integer.MAX_VALUE;
|
||||
if (targetLineNumber > 0) {
|
||||
startLine = targetLineNumber - padding;
|
||||
endLine = targetLineNumber + padding;
|
||||
}
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
/**
|
||||
* Reads in a stream, optionally only including the target line number
|
||||
* and its padding
|
||||
*
|
||||
* @param in The input stream
|
||||
* @param targetLineNumber The target line number, negative to read all
|
||||
* @return A list of lines
|
||||
*/
|
||||
private List<String> read(InputStream in, int targetLineNumber) {
|
||||
List<String> snippet = null;
|
||||
if (in != null) {
|
||||
snippet = new ArrayList<>();
|
||||
int startLine = 0;
|
||||
int endLine = Integer.MAX_VALUE;
|
||||
if (targetLineNumber > 0) {
|
||||
startLine = targetLineNumber - padding;
|
||||
endLine = targetLineNumber + padding;
|
||||
}
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
|
||||
int lineno = 0;
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
lineno++;
|
||||
if (lineno >= startLine && lineno <= endLine) {
|
||||
snippet.add(line);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// ignoring as snippet not available isn't a big deal
|
||||
}
|
||||
}
|
||||
return snippet;
|
||||
}
|
||||
int lineno = 0;
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
lineno++;
|
||||
if (lineno >= startLine && lineno <= endLine) {
|
||||
snippet.add(line);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// ignoring as snippet not available isn't a big deal
|
||||
}
|
||||
}
|
||||
return snippet;
|
||||
}
|
||||
|
||||
public void withServletContext(ServletContext arg0) {
|
||||
this.servletContext = arg0;
|
||||
}
|
||||
public void withServletContext(ServletContext arg0) {
|
||||
this.servletContext = arg0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -22,15 +22,14 @@
|
||||
<Configuration>
|
||||
<Appenders>
|
||||
<Console name="STDOUT" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
|
||||
<PatternLayout pattern="[%-5p] %C{2} (%F:%L) - %m%n"/>
|
||||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Logger name="com.opensymphony.xwork2" level="info"/>
|
||||
<Logger name="org.apache.struts2" level="info"/>
|
||||
<Logger name="org.springframework" level="info"/>
|
||||
<Root level="info">
|
||||
<AppenderRef ref="STDOUT"/>
|
||||
</Root>
|
||||
<Logger name="org.apache.struts2" level="info"/>
|
||||
<Logger name="com.opensymphony.xwork2" level="info"/>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
</Configuration>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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 struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="dispatcher" extends="struts-default" namespace="/dispatcher">
|
||||
|
||||
<action name="dispatch">
|
||||
<result type="dispatcher">
|
||||
/WEB-INF/dispatcher/dispatch-result.jsp
|
||||
</result>
|
||||
</action>
|
||||
|
||||
<action name="forward">
|
||||
<result type="dispatcher">/dispatcher/dispatch.action</result>
|
||||
</action>
|
||||
|
||||
</package>
|
||||
</struts>
|
||||
@@ -78,6 +78,8 @@
|
||||
|
||||
<include file="struts-async.xml" />
|
||||
|
||||
<include file="struts-dispatcher.xml" />
|
||||
|
||||
<package name="default" extends="struts-default">
|
||||
<interceptors>
|
||||
<interceptor-stack name="crudStack">
|
||||
|
||||
@@ -45,66 +45,46 @@
|
||||
</bean>
|
||||
|
||||
<bean id="chatLoginAction" class="org.apache.struts2.showcase.chat.ChatLoginAction" scope="prototype">
|
||||
<constructor-arg index="0">
|
||||
<ref local="chatService"/>
|
||||
</constructor-arg>
|
||||
<constructor-arg index="0" ref="chatService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="chatLogoutAction" class="org.apache.struts2.showcase.chat.ChatLogoutAction" scope="prototype">
|
||||
<constructor-arg index="0">
|
||||
<ref local="chatService"/>
|
||||
</constructor-arg>
|
||||
<constructor-arg index="0" ref="chatService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="usersAvailableAction" class="org.apache.struts2.showcase.chat.UsersAvailableAction" scope="prototype">
|
||||
<constructor-arg index="0">
|
||||
<ref local="chatService"/>
|
||||
</constructor-arg>
|
||||
<constructor-arg index="0" ref="chatService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="roomsAvailableAction" class="org.apache.struts2.showcase.chat.RoomsAvailableAction" scope="prototype">
|
||||
<constructor-arg index="0">
|
||||
<ref local="chatService"/>
|
||||
</constructor-arg>
|
||||
<constructor-arg index="0" ref="chatService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="crudRoomAction" class="org.apache.struts2.showcase.chat.CrudRoomAction" scope="prototype">
|
||||
<constructor-arg index="0">
|
||||
<ref local="chatService"/>
|
||||
</constructor-arg>
|
||||
<constructor-arg index="0" ref="chatService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="enterRoomAction" class="org.apache.struts2.showcase.chat.EnterRoomAction" scope="prototype">
|
||||
<constructor-arg index="0">
|
||||
<ref local="chatService"/>
|
||||
</constructor-arg>
|
||||
<constructor-arg index="0" ref="chatService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="messagesAvailableInRoomAction" class="org.apache.struts2.showcase.chat.MessagesAvailableInRoomAction"
|
||||
scope="prototype">
|
||||
<constructor-arg index="0">
|
||||
<ref local="chatService"/>
|
||||
</constructor-arg>
|
||||
<constructor-arg index="0" ref="chatService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="sendMessageToRoomAction" class="org.apache.struts2.showcase.chat.SendMessageToRoomAction"
|
||||
scope="prototype">
|
||||
<constructor-arg index="0">
|
||||
<ref local="chatService"/>
|
||||
</constructor-arg>
|
||||
<constructor-arg index="0" ref="chatService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="usersAvailableInRoomAction" class="org.apache.struts2.showcase.chat.UsersAvailableInRoomAction"
|
||||
scope="prototype">
|
||||
<constructor-arg index="0">
|
||||
<ref local="chatService"/>
|
||||
</constructor-arg>
|
||||
<constructor-arg index="0" ref="chatService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="exitRoomAction" class="org.apache.struts2.showcase.chat.ExitRoomAction" scope="prototype">
|
||||
<constructor-arg index="0">
|
||||
<ref local="chatService"/>
|
||||
</constructor-arg>
|
||||
<constructor-arg index="0" ref="chatService"/>
|
||||
</bean>
|
||||
|
||||
|
||||
@@ -129,9 +109,7 @@
|
||||
</bean>
|
||||
|
||||
<bean id="startHangmanAction" class="org.apache.struts2.showcase.hangman.StartHangmanAction" scope="prototype">
|
||||
<constructor-arg index="0">
|
||||
<ref local="hangmanService"/>
|
||||
</constructor-arg>
|
||||
<constructor-arg index="0" ref="hangmanService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="guessCharacterAction" class="org.apache.struts2.showcase.hangman.GuessCharacterAction" scope="prototype"/>
|
||||
|
||||
@@ -244,6 +244,8 @@
|
||||
<li><s:url var="url" namespace="/modelDriven" action="modelDriven"/><s:a
|
||||
href="%{url}">Model Driven</s:a></li>
|
||||
<li><s:a value="/async/index.html">Async</s:a></li>
|
||||
<li><s:a value="/dispatcher/dispatch.action">Dispatcher result - dispatch</s:a></li>
|
||||
<li><s:a value="/dispatcher/forward.action">Dispatcher result - forward</s:a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<!--
|
||||
/*
|
||||
* 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 contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
|
||||
<%@ taglib prefix="s" uri="/struts-tags" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>Struts2 Showcase - Dispatcher result Example</title>
|
||||
<s:head theme="xhtml"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="page-header">
|
||||
<h1>Dispatcher Result Example</h1>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div id="dispatcher-result" class="col-md-12">
|
||||
This page is a result of "dispatching" to it from an action
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,19 +1,19 @@
|
||||
<!--
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* 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
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
@@ -26,49 +26,46 @@
|
||||
<body>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1>View Sources</h1>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1>View Sources</h1>
|
||||
|
||||
<ul class="nav nav-tabs" id="codeTab">
|
||||
<li class="active"><a href="#page">Page</a></li>
|
||||
<li><a href="#config">Configuration</a></li>
|
||||
<li><a href="#java">Java Action</a></li>
|
||||
</ul>
|
||||
<ul class="nav nav-tabs" id="codeTab">
|
||||
<li class="active"><a href="#page">Page</a></li>
|
||||
<li><a href="#config">Configuration</a></li>
|
||||
<li><a href="#java">Java Action</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="page">
|
||||
<h3><s:property default="Unknown page" value="page"/></h3>
|
||||
<pre class="prettyprint lang-html linenums">
|
||||
<s:iterator value="pageLines" status="row">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="page">
|
||||
<h3><s:property default="Unknown page" value="page"/></h3>
|
||||
<pre class="prettyprint lang-html linenums"><s:iterator value="pageLines" status="row">
|
||||
<s:property/></s:iterator>
|
||||
</pre>
|
||||
</div>
|
||||
<div class="tab-pane" id="config">
|
||||
<h3><s:property default="Unknown configuration" value="config"/></h3>
|
||||
<pre class="prettyprint lang-xml linenums">
|
||||
<s:iterator value="configLines" status="row">
|
||||
</pre>
|
||||
</div>
|
||||
<div class="tab-pane" id="config">
|
||||
<h3><s:property default="Unknown configuration" value="config"/></h3>
|
||||
<pre class="prettyprint lang-xml linenums"><s:iterator value="configLines" status="row">
|
||||
<s:property/></s:iterator>
|
||||
</pre>
|
||||
</div>
|
||||
<div class="tab-pane" id="java">
|
||||
<h3><s:property default="Unknown or unavailable Action class" value="className"/></h3>
|
||||
<pre class="prettyprint lang-java linenums">
|
||||
<s:iterator value="classLines" status="row">
|
||||
</pre>
|
||||
</div>
|
||||
<div class="tab-pane" id="java">
|
||||
<h3><s:property default="Unknown or unavailable Action class" value="className"/></h3>
|
||||
<pre class="prettyprint lang-java linenums"><s:iterator value="classLines" status="row">
|
||||
<s:property/></s:iterator>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<s:script>
|
||||
$('#codeTab a').click(function (e) {
|
||||
e.preventDefault();
|
||||
$(this).tab('show');
|
||||
})
|
||||
$('#codeTab a').click(function (e) {
|
||||
e.preventDefault();
|
||||
$(this).tab('show');
|
||||
})
|
||||
</s:script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?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
|
||||
@@ -16,20 +17,16 @@
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<web-app id="starter" version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
|
||||
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||
version="3.1">
|
||||
|
||||
<display-name>Struts Showcase Application</display-name>
|
||||
|
||||
<context-param>
|
||||
<param-name>org.apache.tiles.definition.DefinitionsFactory.DEFINITIONS_CONFIG</param-name>
|
||||
<param-value>
|
||||
/WEB-INF/tiles.xml
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
<filter>
|
||||
<filter-name>async</filter-name>
|
||||
<filter-class>org.apache.struts2.showcase.async.AsyncFilter</filter-class>
|
||||
@@ -39,18 +36,20 @@
|
||||
<filter>
|
||||
<filter-name>struts-prepare</filter-name>
|
||||
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareFilter</filter-class>
|
||||
<async-supported>true</async-supported>
|
||||
</filter>
|
||||
|
||||
<filter>
|
||||
<filter-name>struts-execute</filter-name>
|
||||
<filter-class>org.apache.struts2.dispatcher.filter.StrutsExecuteFilter</filter-class>
|
||||
<async-supported>true</async-supported>
|
||||
</filter>
|
||||
|
||||
|
||||
<filter>
|
||||
<filter-name>sitemesh</filter-name>
|
||||
<filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
|
||||
</filter>
|
||||
<filter>
|
||||
<filter-name>sitemesh</filter-name>
|
||||
<filter-class>com.opensymphony.sitemesh.webapp.SiteMeshFilter</filter-class>
|
||||
<async-supported>true</async-supported>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>async</filter-name>
|
||||
@@ -60,16 +59,22 @@
|
||||
<filter-mapping>
|
||||
<filter-name>struts-prepare</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
<dispatcher>FORWARD</dispatcher>
|
||||
<dispatcher>REQUEST</dispatcher>
|
||||
</filter-mapping>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>sitemesh</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
<dispatcher>FORWARD</dispatcher>
|
||||
<dispatcher>REQUEST</dispatcher>
|
||||
</filter-mapping>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>struts-execute</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
<dispatcher>FORWARD</dispatcher>
|
||||
<dispatcher>REQUEST</dispatcher>
|
||||
</filter-mapping>
|
||||
|
||||
<listener>
|
||||
@@ -81,18 +86,18 @@
|
||||
org.apache.struts2.tiles.StrutsTilesListener
|
||||
</listener-class>
|
||||
</listener>
|
||||
|
||||
|
||||
<!-- Chat Example in Showcase -->
|
||||
<listener>
|
||||
<listener-class>
|
||||
org.apache.struts2.showcase.chat.ChatSessionListener
|
||||
</listener-class>
|
||||
<listener-class>
|
||||
org.apache.struts2.showcase.chat.ChatSessionListener
|
||||
</listener-class>
|
||||
</listener>
|
||||
|
||||
<listener>
|
||||
<listener-class>org.apache.struts2.dispatcher.listener.StrutsListener</listener-class>
|
||||
</listener>
|
||||
|
||||
|
||||
<!-- SNIPPET START: dwr -->
|
||||
|
||||
<servlet>
|
||||
@@ -103,13 +108,20 @@
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>JspSupportServlet</servlet-name>
|
||||
<servlet-class>org.apache.struts2.views.JspSupportServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>JspSupportServlet</servlet-name>
|
||||
<servlet-class>org.apache.struts2.views.JspSupportServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<!-- Sitemesh Freemarker and Velocity Decorator Servlets. Shares configuration with Struts.-->
|
||||
<servlet>
|
||||
<servlet-name>strutsServlet</servlet-name>
|
||||
<servlet-class>org.apache.struts2.dispatcher.servlet.StrutsServlet</servlet-class>
|
||||
<load-on-startup>2</load-on-startup>
|
||||
<async-supported>true</async-supported>
|
||||
</servlet>
|
||||
|
||||
<!-- Sitemesh Freemarker and Velocity Decorator Servlets. Shares configuration with Struts.-->
|
||||
<servlet>
|
||||
<servlet-name>sitemesh-freemarker</servlet-name>
|
||||
<servlet-class>org.apache.struts2.sitemesh.FreemarkerDecoratorServlet</servlet-class>
|
||||
@@ -117,7 +129,7 @@
|
||||
<param-name>default_encoding</param-name>
|
||||
<param-value>UTF-8</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
<load-on-startup>3</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
@@ -127,14 +139,7 @@
|
||||
<param-name>default_encoding</param-name>
|
||||
<param-value>UTF-8</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>strutsServlet</servlet-name>
|
||||
<servlet-class>org.apache.struts2.dispatcher.servlet.StrutsServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
<async-supported>true</async-supported>
|
||||
<load-on-startup>4</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
|
||||
@@ -32,7 +32,7 @@ public class ActionChainingTest {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/actionchaining/actionChain1!input");
|
||||
|
||||
final String pageAsText = page.asText();
|
||||
final String pageAsText = page.asNormalizedText();
|
||||
Assert.assertTrue(pageAsText.contains("Action Chain 1 Property 1: Property Set In Action Chain 1"));
|
||||
Assert.assertTrue(pageAsText.contains("Action Chain 2 Property 1: Property Set in Action Chain 2"));
|
||||
Assert.assertTrue(pageAsText.contains("Action Chain 3 Property 1: Property set in Action Chain 3"));
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ public class ActionTagExampleTest {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/tags/ui/actionTagExample!input.action");
|
||||
|
||||
final String pageAsText = page.asText();
|
||||
final String pageAsText = page.asNormalizedText();
|
||||
Assert.assertTrue(pageAsText.contains("This text is from the called class"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class AsyncTest {
|
||||
|
||||
final DomElement msgs = page2.getElementById("msgs");
|
||||
|
||||
Assert.assertEquals("hello", msgs.asText());
|
||||
Assert.assertEquals("hello", msgs.asNormalizedText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class CRUDTest {
|
||||
|
||||
final HtmlSubmitInput button = form.getInputByValue("Save");
|
||||
final HtmlPage page2 = button.click();
|
||||
final String page2Text = page2.asText();
|
||||
final String page2Text = page2.asNormalizedText();
|
||||
|
||||
Assert.assertTrue(page2Text.contains("somename1"));
|
||||
Assert.assertTrue(page2Text.contains("somedescription1"));
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ public class ComponentTagExampleTest {
|
||||
final HtmlPage page = webClient
|
||||
.getPage(ParameterUtils.getBaseUrl() + "/tags/ui/componentTagExample.action");
|
||||
|
||||
final String pageAsText = page.asText();
|
||||
final String pageAsText = page.asNormalizedText();
|
||||
Assert.assertTrue(pageAsText.contains("Freemarker Custom Template - parameter 'paramName' - paramValue1"));
|
||||
Assert.assertTrue(pageAsText.contains("Freemarker Custom Template - parameter 'paramName' - paramValue4"));
|
||||
Assert.assertTrue(pageAsText.contains("JSP Custom Template - parameter 'paramName' - paramValue2"));
|
||||
|
||||
@@ -46,7 +46,7 @@ public class ConversionTest {
|
||||
|
||||
final HtmlSubmitInput button = form.getInputByValue("Submit");
|
||||
final HtmlPage page2 = button.click();
|
||||
final String page2Text = page2.asText();
|
||||
final String page2Text = page2.asNormalizedText();
|
||||
|
||||
Assert.assertTrue(page2Text.contains("SET 0 Name: name0"));
|
||||
Assert.assertTrue(page2Text.contains("SET 0 Age: 0"));
|
||||
@@ -71,7 +71,7 @@ public class ConversionTest {
|
||||
|
||||
final HtmlSubmitInput button = form.getInputByValue("Submit");
|
||||
final HtmlPage page2 = button.click();
|
||||
final String page2Text = page2.asText();
|
||||
final String page2Text = page2.asNormalizedText();
|
||||
|
||||
Assert.assertTrue(page2Text.contains("id0 -> address0"));
|
||||
Assert.assertTrue(page2Text.contains("id1 -> address1"));
|
||||
@@ -92,7 +92,7 @@ public class ConversionTest {
|
||||
|
||||
final HtmlSubmitInput button = form.getInputByValue("Submit");
|
||||
final HtmlPage page2 = button.click();
|
||||
final String page2Text = page2.asText();
|
||||
final String page2Text = page2.asNormalizedText();
|
||||
|
||||
Assert.assertTrue(page2Text.contains("ADD"));
|
||||
Assert.assertTrue(page2Text.contains("MINUS"));
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 it.org.apache.struts2.showcase;
|
||||
|
||||
import com.gargoylesoftware.htmlunit.WebClient;
|
||||
import com.gargoylesoftware.htmlunit.html.DomElement;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DispatcherResultTest {
|
||||
|
||||
@Test
|
||||
public void testDispatchingToJSP() throws Exception {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/dispatcher/dispatch.action");
|
||||
|
||||
DomElement div = page.getElementById("dispatcher-result");
|
||||
|
||||
Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDispatchingToAction() throws Exception {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/dispatcher/forward.action");
|
||||
|
||||
//DomElement div = page.getElementById("dispatcher-result");
|
||||
//Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
// support for forwarding to another action is broken on StrutsPrepareFilter/StrutsExecuteFilter
|
||||
// it only works in StrutsPrepareAndExecuteFilter
|
||||
// this will be fixed in Struts 6.1.x
|
||||
|
||||
Assert.assertEquals(404, page.getWebResponse().getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,12 +43,12 @@ public class ExecAndWaitTest {
|
||||
final HtmlSubmitInput button = form.getInputByValue("submit");
|
||||
final HtmlPage page2 = button.click();
|
||||
|
||||
Assert.assertTrue(page2.asText().contains("We are processing your request. Please wait."));
|
||||
Assert.assertTrue(page2.asNormalizedText().contains("We are processing your request. Please wait."));
|
||||
|
||||
// hit it again
|
||||
final HtmlPage page3 = webClient
|
||||
.getPage(ParameterUtils.getBaseUrl() + "/wait/longProcess1.action?time=1000");
|
||||
Assert.assertTrue(page3.asText().contains("We are processing your request. Please wait."));
|
||||
Assert.assertTrue(page3.asNormalizedText().contains("We are processing your request. Please wait."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ public class FileDownloadTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZip() throws Exception {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
final Page page = webClient.getPage(ParameterUtils.getBaseUrl() + "/filedownload/download2.action");
|
||||
|
||||
+2
-2
@@ -36,11 +36,11 @@ public class FreeMarkerManagerTest {
|
||||
|
||||
final DomElement date = page.getElementById("todaysDate");
|
||||
Assert.assertNotNull(date);
|
||||
Assert.assertTrue(date.asText().length() > 0);
|
||||
Assert.assertTrue(date.asNormalizedText().length() > 0);
|
||||
|
||||
final DomElement time = page.getElementById("timeNow");
|
||||
Assert.assertNotNull(time);
|
||||
Assert.assertTrue(time.asText().length() > 0);
|
||||
Assert.assertTrue(time.asNormalizedText().length() > 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,26 +33,23 @@ public class StaticContentTest {
|
||||
webClient.getPage(ParameterUtils.getBaseUrl() + "/struts..");
|
||||
Assert.fail("Previous request should have failed");
|
||||
} catch (FailingHttpStatusCodeException e) {
|
||||
Assert.assertEquals("Not Found", e.getStatusMessage());
|
||||
Assert.assertEquals(404, e.getStatusCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidRersources2() throws Exception {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
try {
|
||||
webClient.getPage(ParameterUtils.getBaseUrl() + "/static/..%252f");
|
||||
Assert.fail("Previous request should have failed");
|
||||
} catch (FailingHttpStatusCodeException e) {
|
||||
Assert.assertEquals("Not Found", e.getStatusMessage());
|
||||
Assert.assertEquals(404, e.getStatusCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*public void testInvalidRersources3() throws IOException {
|
||||
try {
|
||||
beginAt("/static/..%252f..%252f..%252fWEB-INF/classes/org/apache/struts2/showcase/action/EmployeeAction.class/");
|
||||
fail("Previous request should have failed");
|
||||
} catch (TestingEngineResponseException ex) {
|
||||
// ok
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -65,11 +65,11 @@ public class UITagExampleTest {
|
||||
final HtmlSubmitInput button = form.getInputByValue("Submit");
|
||||
final HtmlPage page2 = button.click();
|
||||
|
||||
Assert.assertEquals("name", page2.getElementById("name").asText());
|
||||
Assert.assertEquals("bio", page2.getElementById("bio").asText());
|
||||
Assert.assertEquals("Red", page2.getElementById("favouriteColor").asText());
|
||||
Assert.assertEquals("[Patrick, Jason]", page2.getElementById("friends").asText());
|
||||
Assert.assertEquals("true", page2.getElementById("legalAge").asText());
|
||||
Assert.assertEquals("name", page2.getElementById("name").asNormalizedText());
|
||||
Assert.assertEquals("bio", page2.getElementById("bio").asNormalizedText());
|
||||
Assert.assertEquals("Red", page2.getElementById("favouriteColor").asNormalizedText());
|
||||
Assert.assertEquals("[Patrick, Jason]", page2.getElementById("friends").asNormalizedText());
|
||||
Assert.assertEquals("true", page2.getElementById("legalAge").asNormalizedText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class ValidationTest {
|
||||
|
||||
final HtmlSubmitInput button = form.getInputByValue("Submit");
|
||||
final HtmlPage page2 = button.click();
|
||||
final String page2Text = page2.asText();
|
||||
final String page2Text = page2.asNormalizedText();
|
||||
|
||||
Assert.assertTrue(page2Text.contains("Invalid field value for field \"dateValidatorField\""));
|
||||
Assert.assertTrue(page2Text.contains("Invalid field value for field \"integerValidatorField\""));
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<version>6.0.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-assembly</artifactId>
|
||||
|
||||
+13
-3
@@ -29,7 +29,7 @@
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-bom</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<version>6.0.1</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Struts 2 Bill of Materials</name>
|
||||
@@ -44,7 +44,7 @@
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<struts-version.version>6.0.0-SNAPSHOT</struts-version.version>
|
||||
<struts-version.version>6.0.1</struts-version.version>
|
||||
<maven.site.skip>true</maven.site.skip>
|
||||
<maven.site.deploy.skip>true</maven.site.deploy.skip>
|
||||
</properties>
|
||||
@@ -56,6 +56,11 @@
|
||||
<artifactId>struts2-core</artifactId>
|
||||
<version>${struts-version.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-async-plugin</artifactId>
|
||||
<version>${struts-version.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-bean-validation-plugin</artifactId>
|
||||
@@ -171,11 +176,16 @@
|
||||
<artifactId>struts2-tiles-plugin</artifactId>
|
||||
<version>${struts-version.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-velocity-plugin</artifactId>
|
||||
<version>${struts-version.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<scm>
|
||||
<tag>HEAD</tag>
|
||||
<tag>STRUTS_6_0_1</tag>
|
||||
<connection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</connection>
|
||||
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</developerConnection>
|
||||
<url>https://github.com/apache/struts/</url>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<version>6.0.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-admin-bundle</artifactId>
|
||||
<packaging>bundle</packaging>
|
||||
<name>DEPRECATED: Struts 2 OSGi Admin Bundle - since 2.6</name>
|
||||
<name>DEPRECATED: Struts 2 OSGi Admin Bundle - since 6.0.0</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<version>6.0.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-demo-bundle</artifactId>
|
||||
<packaging>bundle</packaging>
|
||||
<name>DEPRECATED: Struts 2 OSGi Demo Bundle - since 2.6</name>
|
||||
<name>DEPRECATED: Struts 2 OSGi Demo Bundle - since 6.0.0</name>
|
||||
|
||||
<dependencies>
|
||||
|
||||
|
||||
+3
-5
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<version>6.0.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>DEPRECATED: Struts 2 OSGi Bundles - since 2.6</name>
|
||||
<name>DEPRECATED: Struts 2 OSGi Bundles - since 6.0.0</name>
|
||||
|
||||
<modules>
|
||||
<module>admin</module>
|
||||
@@ -53,12 +53,10 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.4</version>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
<reporting>
|
||||
|
||||
+13
-12
@@ -24,14 +24,14 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.0.0-SNAPSHOT</version>
|
||||
<version>6.0.1</version>
|
||||
</parent>
|
||||
<artifactId>struts2-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Struts 2 Core</name>
|
||||
|
||||
<properties>
|
||||
<tlib.version>2.6</tlib.version>
|
||||
<tlib.version>6.0</tlib.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
@@ -188,7 +188,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -242,6 +242,16 @@
|
||||
<artifactId>spring-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
@@ -345,15 +355,6 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
|
||||
This is only necessary in tests-->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-validator</groupId>
|
||||
<artifactId>commons-validator</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.concurrent.Callable;
|
||||
* Adds support for invoke async actions. This allows us to support action methods that return {@link Callable}
|
||||
* as well as invoking them in separate not-container thread then executing the result in another container thread.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public interface AsyncManager {
|
||||
boolean hasAsyncActionResult();
|
||||
|
||||
-1
@@ -244,7 +244,6 @@ public class StrutsDefaultConfigurationProvider implements ConfigurationProvider
|
||||
props.setProperty(StrutsConstants.STRUTS_OGNL_ENABLE_EXPRESSION_CACHE, Boolean.TRUE.toString());
|
||||
props.setProperty(StrutsConstants.STRUTS_OGNL_ENABLE_EVAL_EXPRESSION, Boolean.FALSE.toString());
|
||||
props.setProperty(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, Boolean.FALSE.toString());
|
||||
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, Boolean.FALSE.toString());
|
||||
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, Boolean.TRUE.toString());
|
||||
props.setProperty(StrutsConstants.STRUTS_MATCHER_APPEND_NAMED_PARAMETERS, Boolean.TRUE.toString());
|
||||
}
|
||||
|
||||
@@ -18,28 +18,36 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.conversion.impl;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.conversion.TypeConversionException;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Member;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.conversion.TypeConversionException;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
|
||||
public class DateConverter extends DefaultTypeConverter {
|
||||
|
||||
private final static Logger LOG = LogManager.getLogger(DateConverter.class);
|
||||
|
||||
@Override
|
||||
public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType) {
|
||||
public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName,
|
||||
Object value, Class toType) {
|
||||
Date result = null;
|
||||
|
||||
if (value instanceof String && ((String) value).length() > 0) {
|
||||
@@ -52,15 +60,12 @@ public class DateConverter extends DefaultTypeConverter {
|
||||
} else if (java.sql.Timestamp.class == toType) {
|
||||
Date check = null;
|
||||
SimpleDateFormat dtfmt = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT,
|
||||
DateFormat.MEDIUM,
|
||||
locale);
|
||||
SimpleDateFormat fullfmt = new SimpleDateFormat(dtfmt.toPattern() + MILLISECOND_FORMAT,
|
||||
locale);
|
||||
DateFormat.MEDIUM, locale);
|
||||
SimpleDateFormat fullfmt = new SimpleDateFormat(dtfmt.toPattern() + MILLISECOND_FORMAT, locale);
|
||||
|
||||
SimpleDateFormat dfmt = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT,
|
||||
locale);
|
||||
SimpleDateFormat dfmt = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, locale);
|
||||
|
||||
SimpleDateFormat[] fmts = {fullfmt, dtfmt, dfmt};
|
||||
SimpleDateFormat[] fmts = { fullfmt, dtfmt, dfmt };
|
||||
for (SimpleDateFormat fmt : fmts) {
|
||||
try {
|
||||
check = fmt.parse(sa);
|
||||
@@ -85,8 +90,39 @@ public class DateConverter extends DefaultTypeConverter {
|
||||
} catch (ParseException ignore) {
|
||||
}
|
||||
}
|
||||
} else if (java.time.LocalDateTime.class == toType || java.time.LocalDate.class == toType
|
||||
|| java.time.LocalTime.class == toType) {
|
||||
DateTimeFormatter dtf = null;
|
||||
TemporalAccessor check = null;
|
||||
DateTimeFormatter[] dfs = getDateTimeFormats(ActionContext.of(context), locale);
|
||||
|
||||
for (DateTimeFormatter df1 : dfs) {
|
||||
try {
|
||||
check = df1.parseBest(sa, LocalDateTime::from, LocalDate::from, LocalTime::from);
|
||||
dtf = df1;
|
||||
if (check != null) {
|
||||
break;
|
||||
}
|
||||
} catch (DateTimeParseException ignore) {
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (dtf != null && check instanceof LocalDateTime) {
|
||||
return LocalDateTime.parse(sa, dtf);
|
||||
} else if (dtf != null && check instanceof LocalDate) {
|
||||
return LocalDate.parse(sa, dtf);
|
||||
} else if (dtf != null && check instanceof LocalTime) {
|
||||
return LocalTime.parse(sa, dtf);
|
||||
} else {
|
||||
throw new TypeConversionException("Could not parse date");
|
||||
}
|
||||
} catch (DateTimeParseException e) {
|
||||
throw new TypeConversionException("Could not parse date", e);
|
||||
}
|
||||
|
||||
}
|
||||
//final fallback for dates without time
|
||||
|
||||
// final fallback for dates without time
|
||||
if (df == null) {
|
||||
df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
|
||||
}
|
||||
@@ -95,15 +131,17 @@ public class DateConverter extends DefaultTypeConverter {
|
||||
result = df.parse(sa);
|
||||
if (!(Date.class == toType)) {
|
||||
try {
|
||||
Constructor<?> constructor = toType.getConstructor(new Class[]{long.class});
|
||||
return constructor.newInstance(new Object[]{Long.valueOf(result.getTime())});
|
||||
Constructor<?> constructor = toType.getConstructor(new Class[] { long.class });
|
||||
return constructor.newInstance(new Object[] { Long.valueOf(result.getTime()) });
|
||||
} catch (Exception e) {
|
||||
throw new TypeConversionException("Couldn't create class " + toType + " using default (long) constructor", e);
|
||||
throw new TypeConversionException(
|
||||
"Couldn't create class " + toType + " using default (long) constructor", e);
|
||||
}
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
throw new TypeConversionException("Could not parse date", e);
|
||||
}
|
||||
|
||||
} else if (Date.class.isAssignableFrom(value.getClass())) {
|
||||
result = (Date) value;
|
||||
}
|
||||
@@ -111,16 +149,16 @@ public class DateConverter extends DefaultTypeConverter {
|
||||
}
|
||||
|
||||
/**
|
||||
* The user defined global date format,
|
||||
* see {@link org.apache.struts2.components.Date#DATETAG_PROPERTY}
|
||||
* The user defined global date format, see
|
||||
* {@link org.apache.struts2.components.Date#DATETAG_PROPERTY}
|
||||
*
|
||||
* @param context current ActionContext
|
||||
* @param locale current Locale to convert to
|
||||
* @return defined global format
|
||||
*
|
||||
* @return defined global date string format
|
||||
*/
|
||||
protected DateFormat getGlobalDateFormat(ActionContext context, Locale locale) {
|
||||
protected String getGlobalDateString(ActionContext context) {
|
||||
final String dateTagProperty = org.apache.struts2.components.Date.DATETAG_PROPERTY;
|
||||
SimpleDateFormat globalDateFormat = null;
|
||||
String globalDateString = null;
|
||||
|
||||
final TextProvider tp = findProviderInStack(context.getValueStack());
|
||||
|
||||
@@ -130,23 +168,28 @@ public class DateConverter extends DefaultTypeConverter {
|
||||
// is the same as input = DATETAG_PROPERTY
|
||||
if (globalFormat != null && !dateTagProperty.equals(globalFormat)) {
|
||||
LOG.debug("Found \"{}\" as \"{}\"", dateTagProperty, globalFormat);
|
||||
globalDateFormat = new SimpleDateFormat(globalFormat, locale);
|
||||
globalDateString = globalFormat;
|
||||
} else {
|
||||
LOG.debug("\"{}\" has not been defined, ignoring it", dateTagProperty);
|
||||
}
|
||||
}
|
||||
|
||||
return globalDateFormat;
|
||||
return globalDateString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of date formats to be used when converting dates
|
||||
*
|
||||
* @param context the current ActionContext
|
||||
* @param locale the current locale of the action
|
||||
* @param locale the current locale of the action
|
||||
* @return a list of DateFormat to be used for date conversion
|
||||
*/
|
||||
private DateFormat[] getDateFormats(ActionContext context, Locale locale) {
|
||||
DateFormat globalDateFormat = getGlobalDateFormat(context, locale);
|
||||
DateFormat globalDateFormat = null;
|
||||
String globalFormat = getGlobalDateString(context);
|
||||
if (globalFormat != null) {
|
||||
globalDateFormat = new SimpleDateFormat(globalFormat, locale);
|
||||
}
|
||||
|
||||
DateFormat dt1 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, locale);
|
||||
DateFormat dt2 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale);
|
||||
@@ -156,15 +199,46 @@ public class DateConverter extends DefaultTypeConverter {
|
||||
DateFormat d2 = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
|
||||
DateFormat d3 = DateFormat.getDateInstance(DateFormat.LONG, locale);
|
||||
|
||||
DateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||
DateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
|
||||
DateFormat rfc3339dateOnly = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
final DateFormat[] dateFormats;
|
||||
|
||||
if (globalDateFormat == null) {
|
||||
dateFormats = new DateFormat[]{dt1, dt2, dt3, rfc3339, d1, d2, d3, rfc3339dateOnly};
|
||||
dateFormats = new DateFormat[] { dt1, dt2, dt3, rfc3339, d1, d2, d3, rfc3339dateOnly };
|
||||
} else {
|
||||
dateFormats = new DateFormat[]{globalDateFormat, dt1, dt2, dt3, rfc3339, d1, d2, d3, rfc3339dateOnly};
|
||||
dateFormats = new DateFormat[] { globalDateFormat, dt1, dt2, dt3, rfc3339, d1, d2, d3, rfc3339dateOnly };
|
||||
}
|
||||
|
||||
return dateFormats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of date time formats to be used when converting dates
|
||||
*
|
||||
* @param context the current ActionContext
|
||||
* @param locale the current locale of the action
|
||||
*
|
||||
* @return a list of DateTimeFormatter to be used for date conversion
|
||||
*/
|
||||
protected DateTimeFormatter[] getDateTimeFormats(ActionContext context, Locale locale) {
|
||||
|
||||
DateTimeFormatter globalDateFormat = null;
|
||||
String globalFormat = getGlobalDateString(context);
|
||||
if (globalFormat != null) {
|
||||
globalDateFormat = DateTimeFormatter.ofPattern(globalFormat, locale);
|
||||
}
|
||||
|
||||
DateTimeFormatter df1 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
||||
DateTimeFormatter df2 = DateTimeFormatter.ISO_LOCAL_DATE;
|
||||
DateTimeFormatter df3 = DateTimeFormatter.ISO_LOCAL_TIME;
|
||||
|
||||
final DateTimeFormatter[] dateFormats;
|
||||
|
||||
if (globalDateFormat == null) {
|
||||
dateFormats = new DateTimeFormatter[] { df1, df2, df3 };
|
||||
} else {
|
||||
dateFormats = new DateTimeFormatter[] { globalDateFormat, df1, df2, df3 };
|
||||
}
|
||||
|
||||
return dateFormats;
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.opensymphony.xwork2.inject.Inject;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
@@ -99,6 +100,8 @@ public class XWorkBasicConverter extends DefaultTypeConverter {
|
||||
result = doConvertToArray(context, o, member, propertyName, value, toType);
|
||||
} else if (Date.class.isAssignableFrom(toType)) {
|
||||
result = doConvertToDate(context, value, toType);
|
||||
} else if (LocalDateTime.class.isAssignableFrom(toType)) {
|
||||
result = doConvertToDate(context, value, toType);
|
||||
} else if (Calendar.class.isAssignableFrom(toType)) {
|
||||
result = doConvertToCalendar(context, value);
|
||||
} else if (Collection.class.isAssignableFrom(toType)) {
|
||||
|
||||
@@ -201,7 +201,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
ReflectionContextState.setReportingConversionErrors(context, true);
|
||||
|
||||
//keep locale from original context
|
||||
newStack.getActionContext().withLocale(stack.getActionContext().getLocale());
|
||||
newStack.getActionContext().withLocale(stack.getActionContext().getLocale()).withValueStack(stack);
|
||||
}
|
||||
|
||||
boolean memberAccessStack = newStack instanceof MemberAccessValueStack;
|
||||
|
||||
@@ -73,7 +73,6 @@ public class OgnlUtil {
|
||||
|
||||
private Container container;
|
||||
private boolean allowStaticFieldAccess = true;
|
||||
private boolean allowStaticMethodAccess;
|
||||
private boolean disallowProxyMemberAccess;
|
||||
|
||||
/**
|
||||
@@ -250,11 +249,6 @@ public class OgnlUtil {
|
||||
this.allowStaticFieldAccess = BooleanUtils.toBoolean(allowStaticFieldAccess);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, required = false)
|
||||
protected void setAllowStaticMethodAccess(String allowStaticMethodAccess) {
|
||||
this.allowStaticMethodAccess = BooleanUtils.toBoolean(allowStaticMethodAccess);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_DISALLOW_PROXY_MEMBER_ACCESS, required = false)
|
||||
protected void setDisallowProxyMemberAccess(String disallowProxyMemberAccess) {
|
||||
this.disallowProxyMemberAccess = BooleanUtils.toBoolean(disallowProxyMemberAccess);
|
||||
@@ -836,7 +830,7 @@ public class OgnlUtil {
|
||||
resolver = container.getInstance(CompoundRootAccessor.class);
|
||||
}
|
||||
|
||||
SecurityMemberAccess memberAccess = new SecurityMemberAccess(allowStaticMethodAccess, allowStaticFieldAccess);
|
||||
SecurityMemberAccess memberAccess = new SecurityMemberAccess(allowStaticFieldAccess);
|
||||
memberAccess.setDisallowProxyMemberAccess(disallowProxyMemberAccess);
|
||||
|
||||
if (devMode) {
|
||||
|
||||
@@ -72,13 +72,13 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
private boolean devMode;
|
||||
private boolean logMissingProperties;
|
||||
|
||||
protected OgnlValueStack(XWorkConverter xworkConverter, CompoundRootAccessor accessor, TextProvider prov, boolean allowStaticMethodAccess, boolean allowStaticFieldAccess) {
|
||||
setRoot(xworkConverter, accessor, new CompoundRoot(), allowStaticMethodAccess, allowStaticFieldAccess);
|
||||
protected OgnlValueStack(XWorkConverter xworkConverter, CompoundRootAccessor accessor, TextProvider prov, boolean allowStaticFieldAccess) {
|
||||
setRoot(xworkConverter, accessor, new CompoundRoot(), allowStaticFieldAccess);
|
||||
push(prov);
|
||||
}
|
||||
|
||||
protected OgnlValueStack(ValueStack vs, XWorkConverter xworkConverter, CompoundRootAccessor accessor, boolean allowStaticMethodAccess, boolean allowStaticFieldAccess) {
|
||||
setRoot(xworkConverter, accessor, new CompoundRoot(vs.getRoot()), allowStaticMethodAccess, allowStaticFieldAccess);
|
||||
protected OgnlValueStack(ValueStack vs, XWorkConverter xworkConverter, CompoundRootAccessor accessor, boolean allowStaticFieldAccess) {
|
||||
setRoot(xworkConverter, accessor, new CompoundRoot(vs.getRoot()), allowStaticFieldAccess);
|
||||
}
|
||||
|
||||
@Inject
|
||||
@@ -90,10 +90,9 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
securityMemberAccess.setDisallowProxyMemberAccess(ognlUtil.isDisallowProxyMemberAccess());
|
||||
}
|
||||
|
||||
protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot,
|
||||
boolean allowStaticMethodAccess, boolean allowStaticFieldAccess) {
|
||||
protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot, boolean allowStaticFieldAccess) {
|
||||
this.root = compoundRoot;
|
||||
this.securityMemberAccess = new SecurityMemberAccess(allowStaticMethodAccess, allowStaticFieldAccess);
|
||||
this.securityMemberAccess = new SecurityMemberAccess(allowStaticFieldAccess);
|
||||
this.context = Ognl.createDefaultContext(this.root, securityMemberAccess, accessor, new OgnlTypeConverterWrapper(xworkConverter));
|
||||
context.put(VALUE_STACK, this);
|
||||
((OgnlContext) context).setTraceEvaluations(false);
|
||||
@@ -219,7 +218,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
if (shouldLog) {
|
||||
LOG.warn(msg, e);
|
||||
}
|
||||
|
||||
|
||||
if (throwExceptionOnFailure) {
|
||||
throw new StrutsException(msg, e);
|
||||
}
|
||||
@@ -462,11 +461,10 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
XWorkConverter xworkConverter = cont.getInstance(XWorkConverter.class);
|
||||
CompoundRootAccessor accessor = (CompoundRootAccessor) cont.getInstance(PropertyAccessor.class, CompoundRoot.class.getName());
|
||||
TextProvider prov = cont.getInstance(TextProvider.class, "system");
|
||||
final boolean allowStaticMethod = BooleanUtils.toBoolean(cont.getInstance(String.class, StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS));
|
||||
final boolean allowStaticField = BooleanUtils.toBoolean(cont.getInstance(String.class, StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS));
|
||||
OgnlValueStack aStack = new OgnlValueStack(xworkConverter, accessor, prov, allowStaticMethod, allowStaticField);
|
||||
OgnlValueStack aStack = new OgnlValueStack(xworkConverter, accessor, prov, allowStaticField);
|
||||
aStack.setOgnlUtil(cont.getInstance(OgnlUtil.class));
|
||||
aStack.setRoot(xworkConverter, accessor, this.root, allowStaticMethod, allowStaticField);
|
||||
aStack.setRoot(xworkConverter, accessor, this.root, allowStaticField);
|
||||
|
||||
return aStack;
|
||||
}
|
||||
|
||||
@@ -43,8 +43,6 @@ import java.util.Set;
|
||||
*/
|
||||
public class OgnlValueStackFactory implements ValueStackFactory {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(OgnlValueStackFactory.class);
|
||||
|
||||
protected XWorkConverter xworkConverter;
|
||||
protected CompoundRootAccessor compoundRootAccessor;
|
||||
protected TextProvider textProvider;
|
||||
@@ -61,8 +59,7 @@ public class OgnlValueStackFactory implements ValueStackFactory {
|
||||
}
|
||||
|
||||
public ValueStack createValueStack() {
|
||||
ValueStack stack = new OgnlValueStack(xworkConverter, compoundRootAccessor, textProvider,
|
||||
containerAllowsStaticMethodAccess(), containerAllowsStaticFieldAccess());
|
||||
ValueStack stack = new OgnlValueStack(xworkConverter, compoundRootAccessor, textProvider, containerAllowsStaticFieldAccess());
|
||||
container.inject(stack);
|
||||
return stack.getActionContext()
|
||||
.withContainer(container)
|
||||
@@ -71,8 +68,7 @@ public class OgnlValueStackFactory implements ValueStackFactory {
|
||||
}
|
||||
|
||||
public ValueStack createValueStack(ValueStack stack) {
|
||||
ValueStack result = new OgnlValueStack(stack, xworkConverter, compoundRootAccessor,
|
||||
containerAllowsStaticMethodAccess(), containerAllowsStaticFieldAccess());
|
||||
ValueStack result = new OgnlValueStack(stack, xworkConverter, compoundRootAccessor, containerAllowsStaticFieldAccess());
|
||||
container.inject(result);
|
||||
return result.getActionContext()
|
||||
.withContainer(container)
|
||||
@@ -84,32 +80,23 @@ public class OgnlValueStackFactory implements ValueStackFactory {
|
||||
protected void setContainer(Container container) throws ClassNotFoundException {
|
||||
Set<String> names = container.getInstanceNames(PropertyAccessor.class);
|
||||
for (String name : names) {
|
||||
Class cls = Class.forName(name);
|
||||
if (cls != null) {
|
||||
if (Map.class.isAssignableFrom(cls)) {
|
||||
PropertyAccessor acc = container.getInstance(PropertyAccessor.class, name);
|
||||
}
|
||||
OgnlRuntime.setPropertyAccessor(cls, container.getInstance(PropertyAccessor.class, name));
|
||||
if (compoundRootAccessor == null && CompoundRoot.class.isAssignableFrom(cls)) {
|
||||
compoundRootAccessor = (CompoundRootAccessor) container.getInstance(PropertyAccessor.class, name);
|
||||
}
|
||||
Class<?> cls = Class.forName(name);
|
||||
OgnlRuntime.setPropertyAccessor(cls, container.getInstance(PropertyAccessor.class, name));
|
||||
if (compoundRootAccessor == null && CompoundRoot.class.isAssignableFrom(cls)) {
|
||||
compoundRootAccessor = (CompoundRootAccessor) container.getInstance(PropertyAccessor.class, name);
|
||||
}
|
||||
}
|
||||
|
||||
names = container.getInstanceNames(MethodAccessor.class);
|
||||
for (String name : names) {
|
||||
Class cls = Class.forName(name);
|
||||
if (cls != null) {
|
||||
OgnlRuntime.setMethodAccessor(cls, container.getInstance(MethodAccessor.class, name));
|
||||
}
|
||||
Class<?> cls = Class.forName(name);
|
||||
OgnlRuntime.setMethodAccessor(cls, container.getInstance(MethodAccessor.class, name));
|
||||
}
|
||||
|
||||
names = container.getInstanceNames(NullHandler.class);
|
||||
for (String name : names) {
|
||||
Class cls = Class.forName(name);
|
||||
if (cls != null) {
|
||||
OgnlRuntime.setNullHandler(cls, new OgnlNullHandlerWrapper(container.getInstance(NullHandler.class, name)));
|
||||
}
|
||||
Class<?> cls = Class.forName(name);
|
||||
OgnlRuntime.setNullHandler(cls, new OgnlNullHandlerWrapper(container.getInstance(NullHandler.class, name)));
|
||||
}
|
||||
if (compoundRootAccessor == null) {
|
||||
throw new IllegalStateException("Couldn't find the compound root accessor");
|
||||
@@ -117,19 +104,8 @@ public class OgnlValueStackFactory implements ValueStackFactory {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve allowsStaticMethodAccess state from the container (allows for lazy fetching)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected boolean containerAllowsStaticMethodAccess() {
|
||||
return BooleanUtils.toBoolean(container.getInstance(String.class, StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve allowStaticFieldAccess state from the container (allows for lazy fetching)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected boolean containerAllowsStaticFieldAccess() {
|
||||
return BooleanUtils.toBoolean(container.getInstance(String.class, StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS));
|
||||
|
||||
@@ -42,7 +42,6 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
private static final Logger LOG = LogManager.getLogger(SecurityMemberAccess.class);
|
||||
|
||||
private final boolean allowStaticFieldAccess;
|
||||
private final boolean allowStaticMethodAccess;
|
||||
private Set<Pattern> excludeProperties = Collections.emptySet();
|
||||
private Set<Pattern> acceptProperties = Collections.emptySet();
|
||||
private Set<Class<?>> excludedClasses = Collections.emptySet();
|
||||
@@ -52,25 +51,15 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
|
||||
/**
|
||||
* SecurityMemberAccess
|
||||
* - access decisions based on whether member is static (or not)
|
||||
* - block or allow access to properties (configurable-after-construction)
|
||||
*
|
||||
* @param allowStaticMethodAccess
|
||||
* @param allowStaticFieldAccess
|
||||
* - access decisions based on whether member is static (or not)
|
||||
* - block or allow access to properties (configurable-after-construction)
|
||||
*
|
||||
* @param allowStaticFieldAccess if set to true static fields (constants) will be accessible
|
||||
*/
|
||||
public SecurityMemberAccess(boolean allowStaticMethodAccess, boolean allowStaticFieldAccess) {
|
||||
this.allowStaticMethodAccess = allowStaticMethodAccess;
|
||||
public SecurityMemberAccess(boolean allowStaticFieldAccess) {
|
||||
this.allowStaticFieldAccess = allowStaticFieldAccess;
|
||||
}
|
||||
|
||||
public final boolean getAllowStaticMethodAccess() {
|
||||
return allowStaticMethodAccess;
|
||||
}
|
||||
|
||||
public final boolean getAllowStaticFieldAccess() {
|
||||
return allowStaticFieldAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object setup(Map context, Object target, Member member, String propertyName) {
|
||||
Object result = null;
|
||||
@@ -90,13 +79,12 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
public void restore(Map context, Object target, Member member, String propertyName, Object state) {
|
||||
if (state != null) {
|
||||
final AccessibleObject accessible = (AccessibleObject) member;
|
||||
final boolean stateboolean = ((Boolean) state).booleanValue(); // Using twice (avoid unboxing)
|
||||
if (!stateboolean) {
|
||||
accessible.setAccessible(stateboolean);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Improper restore state [" + stateboolean + "] for target [" + target +
|
||||
"], member [" + member + "], propertyName [" + propertyName + "]");
|
||||
final boolean stateBoolean = ((Boolean) state).booleanValue(); // Using twice (avoid unboxing)
|
||||
if (!stateBoolean) {
|
||||
accessible.setAccessible(stateBoolean);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Improper restore state [" + stateBoolean + "] for target [" + target +
|
||||
"], member [" + member + "], propertyName [" + propertyName + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,6 +105,7 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
return false;
|
||||
}
|
||||
|
||||
// it needs to be before calling #checkStaticMethodAccess()
|
||||
if (checkEnumAccess(target, member)) {
|
||||
LOG.trace("Allowing access to enum: target [{}], member [{}]", target, member);
|
||||
return true;
|
||||
@@ -127,7 +116,7 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Class memberClass = member.getDeclaringClass();
|
||||
final Class<?> memberClass = member.getDeclaringClass();
|
||||
|
||||
if (isClassExcluded(memberClass)) {
|
||||
LOG.warn("Declaring class of member type [{}] is excluded!", member);
|
||||
@@ -135,11 +124,11 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
}
|
||||
|
||||
// target can be null in case of accessing static fields, since OGNL 3.2.8
|
||||
final Class targetClass = Modifier.isStatic(memberModifiers) ? memberClass : target.getClass();
|
||||
final Class<?> targetClass = Modifier.isStatic(memberModifiers) ? memberClass : target.getClass();
|
||||
|
||||
if (isPackageExcluded(targetClass.getPackage(), memberClass.getPackage())) {
|
||||
LOG.warn("Package [{}] of target class [{}] of target [{}] or package [{}] of member [{}] are excluded!", targetClass.getPackage(), targetClass,
|
||||
target, memberClass.getPackage(), member);
|
||||
target, memberClass.getPackage(), member);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -158,33 +147,25 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
|
||||
/**
|
||||
* Check access for static method (via modifiers).
|
||||
*
|
||||
*
|
||||
* Note: For non-static members, the result is always true.
|
||||
*
|
||||
*
|
||||
* @param member
|
||||
* @param memberModifiers
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected boolean checkStaticMethodAccess(Member member, int memberModifiers) {
|
||||
if (Modifier.isStatic(memberModifiers) && !(member instanceof Field)) {
|
||||
if (allowStaticMethodAccess) {
|
||||
LOG.debug("Support for accessing static methods [member: {}] is deprecated!", member);
|
||||
}
|
||||
return allowStaticMethodAccess;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return !Modifier.isStatic(memberModifiers) || member instanceof Field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check access for static field (via modifiers).
|
||||
*
|
||||
* <p>
|
||||
* Note: For non-static members, the result is always true.
|
||||
*
|
||||
*
|
||||
* @param member
|
||||
* @param memberModifiers
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected boolean checkStaticFieldAccess(Member member, int memberModifiers) {
|
||||
@@ -195,13 +176,12 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Check access for public members (via modifiers)
|
||||
*
|
||||
* <p>
|
||||
* Returns true if-and-only-if the member is public.
|
||||
*
|
||||
*
|
||||
* @param memberModifiers
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected boolean checkPublicMemberAccess(int memberModifiers) {
|
||||
@@ -210,10 +190,8 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
|
||||
protected boolean checkEnumAccess(Object target, Member member) {
|
||||
if (target instanceof Class) {
|
||||
final Class clazz = (Class) target;
|
||||
if (Enum.class.isAssignableFrom(clazz) && member.getName().equals("values")) {
|
||||
return true;
|
||||
}
|
||||
final Class<?> clazz = (Class<?>) target;
|
||||
return Enum.class.isAssignableFrom(clazz) && member.getName().equals("values");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -222,7 +200,7 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
if (targetPackage == null || memberPackage == null) {
|
||||
LOG.warn("The use of the default (unnamed) package is discouraged!");
|
||||
}
|
||||
|
||||
|
||||
String targetPackageName = targetPackage == null ? "" : targetPackage.getName();
|
||||
String memberPackageName = memberPackage == null ? "" : memberPackage.getName();
|
||||
|
||||
@@ -235,7 +213,7 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
targetPackageName = targetPackageName + ".";
|
||||
memberPackageName = memberPackageName + ".";
|
||||
|
||||
for (String packageName: excludedPackageNames) {
|
||||
for (String packageName : excludedPackageNames) {
|
||||
if (targetPackageName.startsWith(packageName) || memberPackageName.startsWith(packageName)) {
|
||||
return true;
|
||||
}
|
||||
@@ -245,7 +223,7 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
}
|
||||
|
||||
protected boolean isClassExcluded(Class<?> clazz) {
|
||||
if (clazz == Object.class || (clazz == Class.class && !allowStaticMethodAccess)) {
|
||||
if (clazz == Object.class || (clazz == Class.class && !allowStaticFieldAccess)) {
|
||||
return true;
|
||||
}
|
||||
for (Class<?> excludedClass : excludedClasses) {
|
||||
|
||||
@@ -36,7 +36,7 @@ import java.util.Map;
|
||||
* @author tmjee
|
||||
*/
|
||||
public class XWorkMethodAccessor extends ObjectMethodAccessor {
|
||||
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(XWorkMethodAccessor.class);
|
||||
|
||||
@Override
|
||||
@@ -58,9 +58,9 @@ public class XWorkMethodAccessor extends ObjectMethodAccessor {
|
||||
//so that property strings are not cleared
|
||||
//i.e. OgnlUtil should be used initially, OgnlRuntime
|
||||
//thereafter
|
||||
|
||||
|
||||
Object propVal=OgnlRuntime.getProperty(ogContext, object, string);
|
||||
//use the Collection property accessor instead of the individual property accessor, because
|
||||
//use the Collection property accessor instead of the individual property accessor, because
|
||||
//in the case of Lists otherwise the index property could be used
|
||||
PropertyAccessor accessor=OgnlRuntime.getPropertyAccessor(Collection.class);
|
||||
ReflectionContextState.setGettingByKeyProperty(ogContext,true);
|
||||
@@ -83,8 +83,8 @@ public class XWorkMethodAccessor extends ObjectMethodAccessor {
|
||||
return callMethodWithDebugInfo(context, object, string, objects);
|
||||
}
|
||||
}
|
||||
Boolean exec = (Boolean) context.get(ReflectionContextState.DENY_METHOD_EXECUTION);
|
||||
boolean e = ((exec == null) ? false : exec.booleanValue());
|
||||
Boolean exec = ReflectionContextState.isDenyMethodExecution(context);
|
||||
boolean e = (exec != null && exec);
|
||||
|
||||
if (!e) {
|
||||
return callMethodWithDebugInfo(context, object, string, objects);
|
||||
@@ -110,7 +110,7 @@ public class XWorkMethodAccessor extends ObjectMethodAccessor {
|
||||
|
||||
@Override
|
||||
public Object callStaticMethod(Map context, Class aClass, String string, Object[] objects) throws MethodFailedException {
|
||||
Boolean exec = (Boolean) context.get(ReflectionContextState.DENY_METHOD_EXECUTION);
|
||||
Boolean exec = ReflectionContextState.isDenyMethodExecution(context);
|
||||
boolean e = ((exec == null) ? false : exec.booleanValue());
|
||||
|
||||
if (!e) {
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ package com.opensymphony.xwork2.security;
|
||||
/**
|
||||
* Used across different places to check if given string is not excluded and is accepted
|
||||
* @see <a href="https://securitylab.github.com/research/apache-struts-double-evaluation/">here</a>
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public interface NotExcludedAcceptedPatternsChecker extends ExcludedPatternsChecker, AcceptedPatternsChecker {
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
|
||||
*
|
||||
* @param bundleName The bundle to remove from the bundle map
|
||||
*
|
||||
* @deprecated A "no-op" since 2.6. Use {@link #clearBundle(java.lang.String, java.util.Locale)} instead.
|
||||
* @deprecated A "no-op" since 6.0.0. Use {@link #clearBundle(java.lang.String, java.util.Locale)} instead.
|
||||
*/
|
||||
public void clearBundle(final String bundleName) {
|
||||
LOG.debug("No-op. Did NOT clear resource bundle [{}], result: false.", bundleName);
|
||||
@@ -248,7 +248,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
|
||||
* @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
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
protected void clearBundle(final String bundleName, Locale locale) {
|
||||
final String key = createMissesKey(String.valueOf(getCurrentThreadContextClassLoader().hashCode()), bundleName, locale);
|
||||
@@ -266,7 +266,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
|
||||
* {@link AbstractLocalizedTextProvider} has already been used for failed bundle
|
||||
* lookups of a given key, or some transitory state made a bundle lookup fail.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
protected void clearMissingBundlesCache() {
|
||||
missingBundles.clear();
|
||||
@@ -313,7 +313,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
|
||||
* The <code>clearCache()</code> methods have been available since Java 1.6, so
|
||||
* it is anticipated the logic will work on any subsequent JVM versions.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
private void clearResourceBundleClassloaderCaches() {
|
||||
final ClassLoader ccl = getCurrentThreadContextClassLoader();
|
||||
@@ -436,7 +436,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
|
||||
*
|
||||
* @param searchDefaultBundlesFirst provide {@link String} "true" or "false" to set the flag state accordingly.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
@Inject(value = StrutsConstants.STRUTS_I18N_SEARCH_DEFAULTBUNDLES_FIRST, required = false)
|
||||
public void setSearchDefaultBundlesFirst(String searchDefaultBundlesFirst) {
|
||||
|
||||
@@ -29,11 +29,11 @@ import java.util.List;
|
||||
/**
|
||||
* ClassFinder searches the classpath of the specified ClassLoaderInterface for
|
||||
* packages, classes, constructors, methods, or fields with specific annotations.
|
||||
*
|
||||
* <p>
|
||||
* For security reasons ASM is used to find the annotations. Classes are not
|
||||
* loaded unless they match the requirements of a called findAnnotated* method.
|
||||
* Once loaded, these classes are cached.
|
||||
*
|
||||
* <p>
|
||||
* The getClassesNotLoaded() method can be used immediately after any find*
|
||||
* method to get a list of classes which matched the find requirements (i.e.
|
||||
* contained the annotation), but were unable to be loaded.
|
||||
@@ -67,32 +67,32 @@ public interface ClassFinder {
|
||||
|
||||
List<Package> findAnnotatedPackages(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Class> findAnnotatedClasses(Class<? extends Annotation> annotation);
|
||||
List<Class<?>> findAnnotatedClasses(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Method> findAnnotatedMethods(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Constructor> findAnnotatedConstructors(Class<? extends Annotation> annotation);
|
||||
List<Constructor<?>> findAnnotatedConstructors(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Field> findAnnotatedFields(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Class> findClassesInPackage(String packageName, boolean recursive);
|
||||
List<Class<?>> findClassesInPackage(String packageName, boolean recursive);
|
||||
|
||||
List<Class> findClasses(Test<ClassInfo> test);
|
||||
List<Class<?>> findClasses(Test<ClassInfo> test);
|
||||
|
||||
List<Class> findClasses();
|
||||
List<Class<?>> findClasses();
|
||||
|
||||
ClassLoaderInterface getClassLoaderInterface();
|
||||
|
||||
public static interface Info {
|
||||
interface Info {
|
||||
String getName();
|
||||
|
||||
List<AnnotationInfo> getAnnotations();
|
||||
}
|
||||
|
||||
public class AnnotationInfo extends Annotatable implements Info {
|
||||
class AnnotationInfo extends Annotatable implements Info {
|
||||
private final String name;
|
||||
|
||||
public AnnotationInfo(Annotation annotation){
|
||||
public AnnotationInfo(Annotation annotation) {
|
||||
this(annotation.getClass().getName());
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ public interface ClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
public class Annotatable {
|
||||
class Annotatable {
|
||||
private final List<AnnotationInfo> annotations = new ArrayList<>();
|
||||
|
||||
public Annotatable(AnnotatedElement element) {
|
||||
@@ -134,12 +134,12 @@ public interface ClassFinder {
|
||||
|
||||
}
|
||||
|
||||
public class PackageInfo extends Annotatable implements Info {
|
||||
class PackageInfo extends Annotatable implements Info {
|
||||
private final String name;
|
||||
private final ClassInfo info;
|
||||
private final Package pkg;
|
||||
|
||||
public PackageInfo(Package pkg){
|
||||
public PackageInfo(Package pkg) {
|
||||
super(pkg);
|
||||
this.pkg = pkg;
|
||||
this.name = pkg.getName();
|
||||
@@ -157,11 +157,11 @@ public interface ClassFinder {
|
||||
}
|
||||
|
||||
public Package get() throws ClassNotFoundException {
|
||||
return (pkg != null)?pkg:info.get().getPackage();
|
||||
return (pkg != null) ? pkg : info.get().getPackage();
|
||||
}
|
||||
}
|
||||
|
||||
public class ClassInfo extends Annotatable implements Info {
|
||||
class ClassInfo extends Annotatable implements Info {
|
||||
private final String name;
|
||||
private final List<MethodInfo> methods = new ArrayList<>();
|
||||
private final List<MethodInfo> constructors = new ArrayList<>();
|
||||
@@ -169,17 +169,18 @@ public interface ClassFinder {
|
||||
private final List<String> interfaces = new ArrayList<>();
|
||||
private final List<String> superInterfaces = new ArrayList<>();
|
||||
private final List<FieldInfo> fields = new ArrayList<>();
|
||||
private final ClassFinder classFinder;
|
||||
|
||||
private Class<?> clazz;
|
||||
private ClassFinder classFinder;
|
||||
private ClassNotFoundException notFound;
|
||||
|
||||
public ClassInfo(Class clazz, ClassFinder classFinder) {
|
||||
public ClassInfo(Class<?> clazz, ClassFinder classFinder) {
|
||||
super(clazz);
|
||||
this.clazz = clazz;
|
||||
this.classFinder = classFinder;
|
||||
this.name = clazz.getName();
|
||||
Class superclass = clazz.getSuperclass();
|
||||
this.superType = superclass != null ? superclass.getName(): null;
|
||||
Class<?> superclass = clazz.getSuperclass();
|
||||
this.superType = superclass != null ? superclass.getName() : null;
|
||||
}
|
||||
|
||||
public ClassInfo(String name, String superType, ClassFinder classFinder) {
|
||||
@@ -188,8 +189,8 @@ public interface ClassFinder {
|
||||
this.classFinder = classFinder;
|
||||
}
|
||||
|
||||
public String getPackageName(){
|
||||
return name.indexOf('.') > 0 ? name.substring(0, name.lastIndexOf('.')) : "" ;
|
||||
public String getPackageName() {
|
||||
return name.indexOf('.') > 0 ? name.substring(0, name.lastIndexOf('.')) : "";
|
||||
}
|
||||
|
||||
public List<MethodInfo> getConstructors() {
|
||||
@@ -220,7 +221,7 @@ public interface ClassFinder {
|
||||
return superType;
|
||||
}
|
||||
|
||||
public Class get() throws ClassNotFoundException {
|
||||
public Class<?> get() throws ClassNotFoundException {
|
||||
if (clazz != null) return clazz;
|
||||
if (notFound != null) throw notFound;
|
||||
try {
|
||||
@@ -239,20 +240,20 @@ public interface ClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodInfo extends Annotatable implements Info {
|
||||
class MethodInfo extends Annotatable implements Info {
|
||||
private final ClassInfo declaringClass;
|
||||
private final String returnType;
|
||||
private final String name;
|
||||
private final List<List<AnnotationInfo>> parameterAnnotations = new ArrayList<>();
|
||||
|
||||
public MethodInfo(ClassInfo info, Constructor constructor){
|
||||
public MethodInfo(ClassInfo info, Constructor<?> constructor) {
|
||||
super(constructor);
|
||||
this.declaringClass = info;
|
||||
this.name = "<init>";
|
||||
this.returnType = Void.TYPE.getName();
|
||||
}
|
||||
|
||||
public MethodInfo(ClassInfo info, Method method){
|
||||
public MethodInfo(ClassInfo info, Method method) {
|
||||
super(method);
|
||||
this.declaringClass = info;
|
||||
this.name = method.getName();
|
||||
@@ -297,12 +298,12 @@ public interface ClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
public class FieldInfo extends Annotatable implements Info {
|
||||
class FieldInfo extends Annotatable implements Info {
|
||||
private final String name;
|
||||
private final String type;
|
||||
private final ClassInfo declaringClass;
|
||||
|
||||
public FieldInfo(ClassInfo info, Field field){
|
||||
public FieldInfo(ClassInfo info, Field field) {
|
||||
super(field);
|
||||
this.declaringClass = info;
|
||||
this.name = field.getName();
|
||||
|
||||
@@ -43,7 +43,7 @@ public final class StrutsConstants {
|
||||
* Note: This control flag may not be meaningful to all provider implementations, and should be false by default.
|
||||
* </p>
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_I18N_SEARCH_DEFAULTBUNDLES_FIRST = "struts.i18n.search.defaultbundles.first";
|
||||
|
||||
@@ -226,9 +226,6 @@ public final class StrutsConstants {
|
||||
/** The name of the parameter to determine whether static field access will be allowed in OGNL expressions or not */
|
||||
public static final String STRUTS_ALLOW_STATIC_FIELD_ACCESS = "struts.ognl.allowStaticFieldAccess";
|
||||
|
||||
/** The name of the parameter to determine whether static method access will be allowed in OGNL expressions or not */
|
||||
public static final String STRUTS_ALLOW_STATIC_METHOD_ACCESS = "struts.ognl.allowStaticMethodAccess";
|
||||
|
||||
/** The com.opensymphony.xwork2.validator.ActionValidatorManager implementation class */
|
||||
public static final String STRUTS_ACTIONVALIDATORMANAGER = "struts.actionValidatorManager";
|
||||
|
||||
@@ -257,7 +254,7 @@ public final class StrutsConstants {
|
||||
* Specifies an OGNL expression cache factory implementation. A default implementation is provided, but
|
||||
* could be replaced by a custom one if desired.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_EXPRESSION_CACHE_FACTORY = "struts.ognl.expressionCacheFactory";
|
||||
|
||||
@@ -265,7 +262,7 @@ public final class StrutsConstants {
|
||||
* Specifies an OGNL BeanInfo cache factory implementation. A default implementation is provided, but
|
||||
* could be replaced by a custom one if desired.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_BEANINFO_CACHE_FACTORY = "struts.ognl.beanInfoCacheFactory";
|
||||
|
||||
@@ -278,7 +275,7 @@ public final class StrutsConstants {
|
||||
* For the optional LRU cache, once the maximum is reached, the least-recently-used (LRU) entry will be
|
||||
* removed when a new entry needs to be added (cache is fully-utilized).
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE = "struts.ognl.beanInfoCacheMaxSize";
|
||||
|
||||
@@ -290,32 +287,32 @@ public final class StrutsConstants {
|
||||
* Note: When enabling LRU cache mode you must also set a maximum size (via {@link #STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE})
|
||||
* for it to be effective. Otherwise, there is no condition to evict a LRU entry (cache has no limit).
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_BEANINFO_CACHE_LRU_MODE = "struts.ognl.beanInfoCacheLRUMode";
|
||||
|
||||
/**
|
||||
* Logs properties that are not found (very verbose)
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_LOG_MISSING_PROPERTIES = "struts.ognl.logMissingProperties";
|
||||
|
||||
/**
|
||||
* Logs properties that are not found (very verbose)
|
||||
* @deprecated as of 2.6. Use {@link #STRUTS_OGNL_LOG_MISSING_PROPERTIES} instead.
|
||||
* @deprecated as of 6.0.0. Use {@link #STRUTS_OGNL_LOG_MISSING_PROPERTIES} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String STRUTS_LOG_MISSING_PROPERTIES = STRUTS_OGNL_LOG_MISSING_PROPERTIES;
|
||||
|
||||
/**
|
||||
* Enables caching of parsed OGNL expressions
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_ENABLE_EXPRESSION_CACHE = "struts.ognl.enableExpressionCache";
|
||||
|
||||
/**
|
||||
* Enables caching of parsed OGNL expressions
|
||||
* @deprecated as of 2.6. Use {@link #STRUTS_OGNL_ENABLE_EXPRESSION_CACHE} instead.
|
||||
* @deprecated as of 6.0.0. Use {@link #STRUTS_OGNL_ENABLE_EXPRESSION_CACHE} instead.
|
||||
*/
|
||||
public static final String STRUTS_ENABLE_OGNL_EXPRESSION_CACHE = STRUTS_OGNL_ENABLE_EXPRESSION_CACHE;
|
||||
|
||||
@@ -328,7 +325,7 @@ public final class StrutsConstants {
|
||||
* For the optional LRU cache, once the maximum is reached, the least-recently-used (LRU) entry will be
|
||||
* removed when a new entry needs to be added (cache is fully-utilized).
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE = "struts.ognl.expressionCacheMaxSize";
|
||||
|
||||
@@ -340,19 +337,19 @@ public final class StrutsConstants {
|
||||
* Note: When enabling LRU cache mode you must also set a maximum size (via {@link #STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE})
|
||||
* for it to be effective. Otherwise, there is no condition to evict a LRU entry (cache has no limit).
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_EXPRESSION_CACHE_LRU_MODE = "struts.ognl.expressionCacheLRUMode";
|
||||
|
||||
/**
|
||||
* Enables evaluation of OGNL expressions
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static final String STRUTS_OGNL_ENABLE_EVAL_EXPRESSION = "struts.ognl.enableEvalExpression";
|
||||
|
||||
/**
|
||||
* Enables evaluation of OGNL expressions
|
||||
* @deprecated as of 2.6. Use {@link #STRUTS_OGNL_ENABLE_EVAL_EXPRESSION} instead.
|
||||
* @deprecated as of 6.0.0. Use {@link #STRUTS_OGNL_ENABLE_EVAL_EXPRESSION} instead.
|
||||
*/
|
||||
public static final String STRUTS_ENABLE_OGNL_EVAL_EXPRESSION = STRUTS_OGNL_ENABLE_EVAL_EXPRESSION;
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import java.util.Map;
|
||||
* Please note that the {@link CookieInterceptor} needs to be
|
||||
* activated to receive a cookies map.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public interface CookiesAware {
|
||||
/**
|
||||
@@ -37,4 +37,4 @@ public interface CookiesAware {
|
||||
* @param cookies the cookies
|
||||
*/
|
||||
void withCookies(Map<String, String> cookies);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.apache.struts2.dispatcher.HttpParameters;
|
||||
* One common use for this is to have the action propagate parameters to internally instantiated data
|
||||
* objects.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public interface ParametersAware {
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import javax.servlet.ServletContext;
|
||||
/**
|
||||
* For components that have a dependence on the Servlet context.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public interface ServletContextAware {
|
||||
|
||||
|
||||
@@ -538,7 +538,7 @@ public class Component {
|
||||
* Override to set if body content should be HTML-escaped.
|
||||
*
|
||||
* @return always true (default) for this component.
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public boolean escapeHtmlBody() {
|
||||
return escapeHtmlBody;
|
||||
@@ -600,7 +600,7 @@ public class Component {
|
||||
*
|
||||
* @param expression of the component
|
||||
* @return true|false
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
protected boolean isAcceptableExpression(String expression) {
|
||||
NotExcludedAcceptedPatternsChecker.IsAllowed isAllowed = notExcludedAcceptedPatterns.isAllowed(expression);
|
||||
|
||||
@@ -59,7 +59,7 @@ import java.util.List;
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note</b>: Since Struts 2.6 a new Java 8 API has been used to format the Date, it's based on
|
||||
* <b>Note</b>: Since Struts 6.0.0 a new Java 8 API has been used to format the Date, it's based on
|
||||
* <a href="https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html">DateTimeFormatter</a>
|
||||
* which uses a bit different patterns.
|
||||
* </p>
|
||||
@@ -293,7 +293,9 @@ public class Date extends ContextBean {
|
||||
final ZoneId tz = getTimeZone();
|
||||
// find the name on the valueStack
|
||||
Object dateObject = findValue(name);
|
||||
if (dateObject instanceof java.util.Date) {
|
||||
if (dateObject instanceof java.sql.Date) {
|
||||
date = ((java.sql.Date) dateObject).toLocalDate().atStartOfDay(tz);
|
||||
} else if (dateObject instanceof java.util.Date) {
|
||||
date = ((java.util.Date) dateObject).toInstant().atZone(tz);
|
||||
} else if (dateObject instanceof Calendar) {
|
||||
date = ((Calendar) dateObject).toInstant().atZone(tz);
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.RequestUtils;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.util.FastByteArrayOutputStream;
|
||||
import org.apache.struts2.views.annotations.StrutsTag;
|
||||
import org.apache.struts2.views.annotations.StrutsTagAttribute;
|
||||
@@ -33,6 +34,7 @@ import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.WriteListener;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
@@ -296,6 +298,19 @@ public class Include extends Component {
|
||||
buffer = new FastByteArrayOutputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWriteListener(WriteListener writeListener) {
|
||||
try {
|
||||
writeListener.onWritePossible();
|
||||
} catch (IOException e) {
|
||||
throw new StrutsException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all data that has been written to this OutputStream.
|
||||
|
||||
@@ -80,4 +80,8 @@ public class Radio extends ListUIBean {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Class<?> getValueClassType() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
* @param parameters component parameters
|
||||
* @param contextParameters request parameters
|
||||
*/
|
||||
protected void mergeRequestParameters(String value, Map<String, Object> parameters, Map<String, Object> contextParameters) {
|
||||
protected void mergeRequestParameters(String value, Map<String, Object> parameters, Map<String, ?> contextParameters) {
|
||||
|
||||
Map<String, Object> mergedParams = new LinkedHashMap<>(contextParameters);
|
||||
|
||||
@@ -333,7 +333,7 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
String queryString = value.substring(value.indexOf('?') + 1);
|
||||
|
||||
mergedParams = urlHelper.parseQueryString(queryString, false);
|
||||
for (Map.Entry<String, Object> entry : contextParameters.entrySet()) {
|
||||
for (Map.Entry<String, ?> entry : contextParameters.entrySet()) {
|
||||
if (!mergedParams.containsKey(entry.getKey())) {
|
||||
mergedParams.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
@@ -83,14 +83,14 @@ public class StrutsXmlConfigurationProvider extends XmlConfigurationProvider {
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN", "struts-2.1.7.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.3//EN", "struts-2.3.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.5//EN", "struts-2.5.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.6//EN", "struts-2.6.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 6.0//EN", "struts-6.0.dtd");
|
||||
setDtdMappings(dtdMappings);
|
||||
File file = new File(filename);
|
||||
if (file.getParent() != null) {
|
||||
this.baseDir = file.getParentFile();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.opensymphony.xwork2.config.providers.XmlConfigurationProvider#register(com.opensymphony.xwork2.inject.ContainerBuilder, java.util.Properties)
|
||||
*/
|
||||
@@ -175,7 +175,7 @@ public class StrutsXmlConfigurationProvider extends XmlConfigurationProvider {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return ("Struts XML configuration provider ("+filename+")");
|
||||
}
|
||||
|
||||
@@ -90,7 +90,6 @@ public class ConstantConfig {
|
||||
private BeanConfig localeProviderFactory;
|
||||
private String mapperIdParameterName;
|
||||
private Boolean ognlAllowStaticFieldAccess;
|
||||
private Boolean ognlAllowStaticMethodAccess;
|
||||
private BeanConfig actionValidatorManager;
|
||||
private BeanConfig valueStackFactory;
|
||||
private BeanConfig reflectionProvider;
|
||||
@@ -222,7 +221,6 @@ public class ConstantConfig {
|
||||
map.put(StrutsConstants.STRUTS_LOCALE_PROVIDER_FACTORY, beanConfToString(localeProviderFactory));
|
||||
map.put(StrutsConstants.STRUTS_ID_PARAMETER_NAME, mapperIdParameterName);
|
||||
map.put(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, Objects.toString(ognlAllowStaticFieldAccess, null));
|
||||
map.put(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, Objects.toString(ognlAllowStaticMethodAccess, null));
|
||||
map.put(StrutsConstants.STRUTS_ACTIONVALIDATORMANAGER, beanConfToString(actionValidatorManager));
|
||||
map.put(StrutsConstants.STRUTS_VALUESTACKFACTORY, beanConfToString(valueStackFactory));
|
||||
map.put(StrutsConstants.STRUTS_REFLECTIONPROVIDER, beanConfToString(reflectionProvider));
|
||||
@@ -810,14 +808,6 @@ public class ConstantConfig {
|
||||
this.ognlAllowStaticFieldAccess = ognlAllowStaticFieldAccess;
|
||||
}
|
||||
|
||||
public Boolean getOgnlAllowStaticMethodAccess() {
|
||||
return ognlAllowStaticMethodAccess;
|
||||
}
|
||||
|
||||
public void setOgnlAllowStaticMethodAccess(Boolean ognlAllowStaticMethodAccess) {
|
||||
this.ognlAllowStaticMethodAccess = ognlAllowStaticMethodAccess;
|
||||
}
|
||||
|
||||
public BeanConfig getActionValidatorManager() {
|
||||
return actionValidatorManager;
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -612,20 +613,12 @@ public class Dispatcher {
|
||||
}
|
||||
|
||||
try {
|
||||
String namespace = mapping.getNamespace();
|
||||
String name = mapping.getName();
|
||||
String method = mapping.getMethod();
|
||||
String actionNamespace = mapping.getNamespace();
|
||||
String actionName = mapping.getName();
|
||||
String actionMethod = mapping.getMethod();
|
||||
|
||||
ActionProxy proxy;
|
||||
|
||||
//check if we are probably in an async resuming
|
||||
ActionInvocation invocation = ActionContext.getContext().getActionInvocation();
|
||||
if (invocation == null || invocation.isExecuted()) {
|
||||
proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method,
|
||||
extraContext, true, false);
|
||||
} else {
|
||||
proxy = invocation.getProxy();
|
||||
}
|
||||
LOG.trace("Processing action, namespace: {}, name: {}, method: {}", actionNamespace, actionName, actionMethod);
|
||||
ActionProxy proxy = prepareActionProxy(extraContext, actionNamespace, actionName, actionMethod);
|
||||
|
||||
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
|
||||
|
||||
@@ -656,6 +649,36 @@ public class Dispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
private ActionProxy prepareActionProxy(Map<String, Object> extraContext, String actionNamespace, String actionName, String actionMethod) {
|
||||
ActionProxy proxy;
|
||||
//check if we are probably in an async resuming
|
||||
ActionInvocation invocation = ActionContext.getContext().getActionInvocation();
|
||||
if (invocation == null || invocation.isExecuted()) {
|
||||
LOG.trace("Creating a new action, namespace: {}, name: {}, method: {}", actionNamespace, actionName, actionMethod);
|
||||
proxy = createActionProxy(actionNamespace, actionName, actionMethod, extraContext);
|
||||
} else {
|
||||
proxy = invocation.getProxy();
|
||||
if (isSameAction(proxy, actionNamespace, actionName, actionMethod)) {
|
||||
LOG.trace("Proxy: {} matches requested action, namespace: {}, name: {}, method: {} - reusing proxy", proxy, actionNamespace, actionName, actionMethod);
|
||||
} else {
|
||||
LOG.trace("Proxy: {} doesn't match action namespace: {}, name: {}, method: {} - creating new proxy", proxy, actionNamespace, actionName, actionMethod);
|
||||
proxy = createActionProxy(actionNamespace, actionName, actionMethod, extraContext);
|
||||
}
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
private ActionProxy createActionProxy(String namespace, String name, String method, Map<String, Object> extraContext) {
|
||||
ActionProxyFactory actionProxyFactory = getContainer().getInstance(ActionProxyFactory.class);
|
||||
return actionProxyFactory.createActionProxy(namespace, name, method, extraContext, true, false);
|
||||
}
|
||||
|
||||
private boolean isSameAction(ActionProxy actionProxy, String namespace, String actionName, String method) {
|
||||
return Objects.equals(namespace, actionProxy.getNamespace())
|
||||
&& Objects.equals(actionName, actionProxy.getActionName())
|
||||
&& Objects.equals(method, actionProxy.getMethod());
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs logging of missing action/result configuration exception
|
||||
*
|
||||
|
||||
+4
-4
@@ -126,18 +126,18 @@ public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {
|
||||
LOG.trace("Checking if {} is a static resource", uri);
|
||||
boolean handled = execute.executeStaticResourceRequest(request, response);
|
||||
if (!handled) {
|
||||
LOG.trace("Assuming uri {} as a normal action", uri);
|
||||
LOG.trace("Uri {} is not a static resource, assuming action", uri);
|
||||
prepare.setEncodingAndLocale(request, response);
|
||||
prepare.createActionContext(request, response);
|
||||
prepare.assignDispatcherToThread();
|
||||
request = prepare.wrapRequest(request);
|
||||
ActionMapping mapping = prepare.findActionMapping(request, response, true);
|
||||
HttpServletRequest wrappedRequest = prepare.wrapRequest(request);
|
||||
ActionMapping mapping = prepare.findActionMapping(wrappedRequest, response, true);
|
||||
if (mapping == null) {
|
||||
LOG.trace("Cannot find mapping for {}, passing to other filters", uri);
|
||||
chain.doFilter(request, response);
|
||||
} else {
|
||||
LOG.trace("Found mapping {} for {}", mapping, uri);
|
||||
execute.executeAction(request, response, mapping);
|
||||
execute.executeAction(wrappedRequest, response, mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ package org.apache.struts2.dispatcher.mapper;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationManager;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.config.entities.PackageConfig;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
@@ -29,7 +30,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.RequestUtils;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.util.PrefixTrie;
|
||||
|
||||
@@ -115,7 +115,7 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
protected boolean allowDynamicMethodCalls = false;
|
||||
protected boolean allowSlashesInActionNames = false;
|
||||
protected boolean alwaysSelectFullNamespace = false;
|
||||
protected PrefixTrie prefixTrie = null;
|
||||
protected PrefixTrie prefixTrie;
|
||||
|
||||
protected Pattern allowedNamespaceNames = Pattern.compile("[a-zA-Z0-9._/\\-]*");
|
||||
protected String defaultNamespaceName = "/";
|
||||
@@ -139,39 +139,35 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
public DefaultActionMapper() {
|
||||
prefixTrie = new PrefixTrie() {
|
||||
{
|
||||
put(METHOD_PREFIX, new ParameterAction() {
|
||||
public void execute(String key, ActionMapping mapping) {
|
||||
if (allowDynamicMethodCalls) {
|
||||
mapping.setMethod(cleanupMethodName(key.substring(METHOD_PREFIX.length())));
|
||||
}
|
||||
put(METHOD_PREFIX, (ParameterAction) (key, mapping) -> {
|
||||
if (allowDynamicMethodCalls) {
|
||||
mapping.setMethod(cleanupMethodName(key.substring(METHOD_PREFIX.length())));
|
||||
}
|
||||
});
|
||||
|
||||
put(ACTION_PREFIX, new ParameterAction() {
|
||||
public void execute(final String key, ActionMapping mapping) {
|
||||
if (allowActionPrefix) {
|
||||
String name = key.substring(ACTION_PREFIX.length());
|
||||
if (allowDynamicMethodCalls) {
|
||||
int bang = name.indexOf('!');
|
||||
if (bang != -1) {
|
||||
String method = cleanupMethodName(name.substring(bang + 1));
|
||||
mapping.setMethod(method);
|
||||
name = name.substring(0, bang);
|
||||
}
|
||||
put(ACTION_PREFIX, (ParameterAction) (key, mapping) -> {
|
||||
if (allowActionPrefix) {
|
||||
String name = key.substring(ACTION_PREFIX.length());
|
||||
if (allowDynamicMethodCalls) {
|
||||
int bang = name.indexOf('!');
|
||||
if (bang != -1) {
|
||||
String method = cleanupMethodName(name.substring(bang + 1));
|
||||
mapping.setMethod(method);
|
||||
name = name.substring(0, bang);
|
||||
}
|
||||
String actionName = cleanupActionName(name);
|
||||
if (allowSlashesInActionNames && !allowActionCrossNamespaceAccess) {
|
||||
if (actionName.startsWith("/")) {
|
||||
actionName = actionName.substring(1);
|
||||
}
|
||||
}
|
||||
if (!allowSlashesInActionNames && !allowActionCrossNamespaceAccess) {
|
||||
if (actionName.lastIndexOf('/') != -1) {
|
||||
actionName = actionName.substring(actionName.lastIndexOf('/') + 1);
|
||||
}
|
||||
}
|
||||
mapping.setName(actionName);
|
||||
}
|
||||
String actionName = cleanupActionName(name);
|
||||
if (allowSlashesInActionNames && !allowActionCrossNamespaceAccess) {
|
||||
if (actionName.startsWith("/")) {
|
||||
actionName = actionName.substring(1);
|
||||
}
|
||||
}
|
||||
if (!allowSlashesInActionNames && !allowActionCrossNamespaceAccess) {
|
||||
if (actionName.lastIndexOf('/') != -1) {
|
||||
actionName = actionName.substring(actionName.lastIndexOf('/') + 1);
|
||||
}
|
||||
}
|
||||
mapping.setName(actionName);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -293,6 +289,7 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
}
|
||||
|
||||
parseNameAndNamespace(uri, mapping, configManager);
|
||||
extractMethodName(mapping, configManager);
|
||||
handleSpecialParameters(request, mapping);
|
||||
return parseActionName(mapping);
|
||||
}
|
||||
@@ -324,9 +321,8 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
public void handleSpecialParameters(HttpServletRequest request, ActionMapping mapping) {
|
||||
// handle special parameter prefixes.
|
||||
Set<String> uniqueParameters = new HashSet<>();
|
||||
Map parameterMap = request.getParameterMap();
|
||||
for (Object o : parameterMap.keySet()) {
|
||||
String key = (String) o;
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
for (String key : parameterMap.keySet()) {
|
||||
|
||||
// Strip off the image button location info, if found
|
||||
if (key.endsWith(".x") || key.endsWith(".y")) {
|
||||
@@ -353,33 +349,33 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
* @param configManager configuration manager
|
||||
*/
|
||||
protected void parseNameAndNamespace(String uri, ActionMapping mapping, ConfigurationManager configManager) {
|
||||
String namespace, name;
|
||||
String actionNamespace, actionName;
|
||||
int lastSlash = uri.lastIndexOf('/');
|
||||
if (lastSlash == -1) {
|
||||
namespace = "";
|
||||
name = uri;
|
||||
actionNamespace = "";
|
||||
actionName = uri;
|
||||
} else if (lastSlash == 0) {
|
||||
// ww-1046, assume it is the root namespace, it will fallback to
|
||||
// default
|
||||
// namespace anyway if not found in root namespace.
|
||||
namespace = "/";
|
||||
name = uri.substring(lastSlash + 1);
|
||||
actionNamespace = "/";
|
||||
actionName = uri.substring(lastSlash + 1);
|
||||
} else if (alwaysSelectFullNamespace) {
|
||||
// Simply select the namespace as everything before the last slash
|
||||
namespace = uri.substring(0, lastSlash);
|
||||
name = uri.substring(lastSlash + 1);
|
||||
actionNamespace = uri.substring(0, lastSlash);
|
||||
actionName = uri.substring(lastSlash + 1);
|
||||
} else {
|
||||
// Try to find the namespace in those defined, defaulting to ""
|
||||
Configuration config = configManager.getConfiguration();
|
||||
String prefix = uri.substring(0, lastSlash);
|
||||
namespace = "";
|
||||
actionNamespace = "";
|
||||
boolean rootAvailable = false;
|
||||
// Find the longest matching namespace, defaulting to the default
|
||||
for (PackageConfig cfg : config.getPackageConfigs().values()) {
|
||||
String ns = cfg.getNamespace();
|
||||
if (ns != null && prefix.startsWith(ns) && (prefix.length() == ns.length() || prefix.charAt(ns.length()) == '/')) {
|
||||
if (ns.length() > namespace.length()) {
|
||||
namespace = ns;
|
||||
if (ns.length() > actionNamespace.length()) {
|
||||
actionNamespace = ns;
|
||||
}
|
||||
}
|
||||
if ("/".equals(ns)) {
|
||||
@@ -387,23 +383,23 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
}
|
||||
}
|
||||
|
||||
name = uri.substring(namespace.length() + 1);
|
||||
actionName = uri.substring(actionNamespace.length() + 1);
|
||||
|
||||
// Still none found, use root namespace if found
|
||||
if (rootAvailable && "".equals(namespace)) {
|
||||
namespace = "/";
|
||||
if (rootAvailable && "".equals(actionNamespace)) {
|
||||
actionNamespace = "/";
|
||||
}
|
||||
}
|
||||
|
||||
if (!allowSlashesInActionNames) {
|
||||
int pos = name.lastIndexOf('/');
|
||||
if (pos > -1 && pos < name.length() - 1) {
|
||||
name = name.substring(pos + 1);
|
||||
int pos = actionName.lastIndexOf('/');
|
||||
if (pos > -1 && pos < actionName.length() - 1) {
|
||||
actionName = actionName.substring(pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
mapping.setNamespace(cleanupNamespaceName(namespace));
|
||||
mapping.setName(cleanupActionName(name));
|
||||
mapping.setNamespace(cleanupNamespaceName(actionNamespace));
|
||||
mapping.setName(cleanupActionName(actionName));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,6 +450,30 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads defined method name for a given action from configuration
|
||||
*
|
||||
* @param mapping current instance of {@link ActionMapping}
|
||||
* @param configurationManager current instance of {@link ConfigurationManager}
|
||||
*/
|
||||
protected void extractMethodName(ActionMapping mapping, ConfigurationManager configurationManager) {
|
||||
String methodName = null;
|
||||
for (PackageConfig cfg : configurationManager.getConfiguration().getPackageConfigs().values()) {
|
||||
if (cfg.getNamespace().equals(mapping.getNamespace())) {
|
||||
ActionConfig actionCfg = cfg.getActionConfigs().get(mapping.getName());
|
||||
if (actionCfg != null) {
|
||||
methodName = actionCfg.getMethodName();
|
||||
LOG.trace("Using method: {} for action mapping: {}", methodName, mapping);
|
||||
} else {
|
||||
LOG.debug("No action config for action mapping: {}", mapping);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mapping.setMethod(methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops the extension from the action name, storing it in the mapping for later use
|
||||
*
|
||||
@@ -551,7 +571,7 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
String extension = lookupExtension(mapping.getExtension());
|
||||
|
||||
if (extension != null) {
|
||||
if (extension.length() == 0 || (extension.length() > 0 && uri.indexOf('.' + extension) == -1)) {
|
||||
if (extension.length() == 0 || uri.indexOf('.' + extension) == -1) {
|
||||
if (extension.length() > 0) {
|
||||
uri.append(".").append(extension);
|
||||
}
|
||||
|
||||
@@ -18,16 +18,15 @@
|
||||
*/
|
||||
package org.apache.struts2.interceptor.csp;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link CspSettings}.
|
||||
@@ -37,36 +36,30 @@ import java.util.Map;
|
||||
* @see CspInterceptor
|
||||
*/
|
||||
public class DefaultCspSettings implements CspSettings {
|
||||
private final SecureRandom sRand = new SecureRandom();
|
||||
// this lazy supplier computes a policy format the first time it's called and caches the result
|
||||
// to reduce string operations when attaching policies to HTTP responses
|
||||
private final Supplier<String> lazyPolicyBuilder = new Supplier<String>() {
|
||||
boolean hasBeenCalled;
|
||||
String policyFormat;
|
||||
|
||||
private final SecureRandom sRand = new SecureRandom();
|
||||
|
||||
// this supplier computes a policy format
|
||||
private final Supplier<String> lazyPolicyBuilder = new Supplier<String>() {
|
||||
@Override
|
||||
public String get() {
|
||||
if (!hasBeenCalled) {
|
||||
StringBuilder policyFormatBuilder = new StringBuilder()
|
||||
.append(OBJECT_SRC)
|
||||
.append(format(" '%s'; ", NONE))
|
||||
.append(SCRIPT_SRC)
|
||||
.append(" 'nonce-%s' ") // nonce placeholder
|
||||
.append(format("'%s' ", STRICT_DYNAMIC))
|
||||
.append(format("%s %s; ", HTTP, HTTPS))
|
||||
.append(BASE_URI)
|
||||
.append(format(" '%s'; ", NONE));
|
||||
StringBuilder policyFormatBuilder = new StringBuilder()
|
||||
.append(OBJECT_SRC)
|
||||
.append(format(" '%s'; ", NONE))
|
||||
.append(SCRIPT_SRC)
|
||||
.append(" 'nonce-%s' ") // nonce placeholder
|
||||
.append(format("'%s' ", STRICT_DYNAMIC))
|
||||
.append(format("%s %s; ", HTTP, HTTPS))
|
||||
.append(BASE_URI)
|
||||
.append(format(" '%s'; ", NONE));
|
||||
|
||||
if (reportUri != null) {
|
||||
policyFormatBuilder
|
||||
.append(REPORT_URI)
|
||||
.append(format(" %s", reportUri));
|
||||
}
|
||||
|
||||
policyFormat = policyFormatBuilder.toString();
|
||||
if (reportUri != null) {
|
||||
policyFormatBuilder
|
||||
.append(REPORT_URI)
|
||||
.append(format(" %s", reportUri));
|
||||
}
|
||||
|
||||
return format(policyFormat, getNonceString());
|
||||
return format(policyFormatBuilder.toString(), getNonceString());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -295,7 +295,7 @@ public class StreamResult extends StrutsResultSupport {
|
||||
*
|
||||
* @param expression of result
|
||||
* @return true|false
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
protected boolean isAcceptableExpression(String expression) {
|
||||
NotExcludedAcceptedPatternsChecker.IsAllowed isAllowed = notExcludedAcceptedPatterns.isAllowed(expression);
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* A bean that can be used to format dates
|
||||
*
|
||||
* FIXME: remove or use to format Dates
|
||||
*/
|
||||
public class DateFormatter {
|
||||
|
||||
Date date;
|
||||
DateFormat format;
|
||||
|
||||
// Attributes ----------------------------------------------------
|
||||
DateFormat parser;
|
||||
|
||||
|
||||
// Public --------------------------------------------------------
|
||||
public DateFormatter() {
|
||||
this.parser = new SimpleDateFormat();
|
||||
this.format = new SimpleDateFormat();
|
||||
this.date = new Date();
|
||||
}
|
||||
|
||||
|
||||
public void setDate(String date) {
|
||||
try {
|
||||
this.date = parser.parse(date);
|
||||
} catch (ParseException e) {
|
||||
throw new IllegalArgumentException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
this.date = (date == null) ? null : (Date)date.clone();
|
||||
}
|
||||
|
||||
public void setDate(int date) {
|
||||
setDate(Integer.toString(date));
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return this.date;
|
||||
}
|
||||
|
||||
public void setFormat(String format) {
|
||||
this.format = new SimpleDateFormat(format);
|
||||
}
|
||||
|
||||
public void setFormat(DateFormat format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public String getFormattedDate() {
|
||||
return format.format(date);
|
||||
}
|
||||
|
||||
public void setParseFormat(String format) {
|
||||
this.parser = new SimpleDateFormat(format);
|
||||
}
|
||||
|
||||
public void setParser(DateFormat parser) {
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
public void setTime(long time) {
|
||||
date.setTime(time);
|
||||
}
|
||||
}
|
||||
@@ -24,11 +24,13 @@ import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.views.jsp.ui.OgnlTool;
|
||||
import org.apache.struts2.views.util.UrlHelper;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.WriteListener;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
@@ -278,6 +280,20 @@ public class StrutsUtil {
|
||||
public void write(int aByte) {
|
||||
writer.write(aByte);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWriteListener(WriteListener writeListener) {
|
||||
try {
|
||||
writeListener.onWritePossible();
|
||||
} catch (IOException e) {
|
||||
throw new StrutsException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
package org.apache.struts2.util;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.views.util.DefaultUrlHelper;
|
||||
import org.apache.struts2.views.util.UrlHelper;
|
||||
|
||||
@@ -58,20 +57,10 @@ public class URLBean {
|
||||
|
||||
public String getURL() {
|
||||
// all this trickier with maps is to reduce the number of objects created
|
||||
Map<String, Object> fullParams = null;
|
||||
|
||||
if (params != null) {
|
||||
fullParams = new HashMap<String, Object>();
|
||||
}
|
||||
Map<String, Object> fullParams = new HashMap<>();
|
||||
|
||||
if (page == null) {
|
||||
// No particular page requested, so go to "same page"
|
||||
// Add query params to parameters
|
||||
if (fullParams != null) {
|
||||
fullParams.putAll(request.getParameterMap());
|
||||
} else {
|
||||
fullParams = request.getParameterMap();
|
||||
}
|
||||
fullParams.putAll(request.getParameterMap());
|
||||
}
|
||||
|
||||
// added parameters override, just like in URLTag
|
||||
@@ -84,7 +73,7 @@ public class URLBean {
|
||||
|
||||
public URLBean addParameter(String name, Object value) {
|
||||
if (params == null) {
|
||||
params = new HashMap<String, String>();
|
||||
params = new HashMap<>();
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
|
||||
@@ -154,7 +154,7 @@ public class AnchorTag extends AbstractClosingTag {
|
||||
*
|
||||
* @param escapeHtmlBody
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public void setEscapeHtmlBody(String escapeHtmlBody) {
|
||||
this.escapeHtmlBody = escapeHtmlBody;
|
||||
|
||||
@@ -81,7 +81,7 @@ public class SubmitTag extends AbstractClosingTag {
|
||||
*
|
||||
* @param escapeHtmlBody
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public void setEscapeHtmlBody(boolean escapeHtmlBody) {
|
||||
this.escapeHtmlBody = escapeHtmlBody;
|
||||
|
||||
@@ -73,7 +73,7 @@ public class TextareaTag extends AbstractUITag {
|
||||
public void setWrap(String wrap) {
|
||||
this.wrap = wrap;
|
||||
}
|
||||
|
||||
|
||||
public void setMaxlength(String maxlength) {
|
||||
this.maxlength = maxlength;
|
||||
}
|
||||
@@ -100,6 +100,8 @@ public class TextareaTag extends AbstractUITag {
|
||||
this.readonly = null;
|
||||
this.rows = null;
|
||||
this.wrap = null;
|
||||
this.maxlength = null;
|
||||
this.minlength = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -266,13 +266,12 @@ 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
|
||||
### **WARNING**: If developers change 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.
|
||||
struts.ognl.expressionMaxLength=256
|
||||
|
||||
### Defines which named instance of DateFormatter to use, there are two instances:
|
||||
### - simpleDateFormatter (based on SimpleDateFormat)
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
Use the following DOCTYPE
|
||||
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.6//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.6.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"http://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
-->
|
||||
|
||||
<!ELEMENT struts ((package|include|bean|constant)*,bean-selection?, unknown-handler-stack?)>
|
||||
@@ -31,8 +31,8 @@
|
||||
and {@link com.opensymphony.xwork2.inject.Inject}
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.6//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.6.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"struts-6.0.dtd">
|
||||
|
||||
<struts>
|
||||
|
||||
|
||||
@@ -45,6 +45,12 @@
|
||||
<#if parameters.title?has_content>
|
||||
title="${parameters.title}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.maxlength?has_content>
|
||||
maxlength="${parameters.maxlength}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.minlength?has_content>
|
||||
minlength="${parameters.minlength}"<#rt/>
|
||||
</#if>
|
||||
<#include "/${parameters.templateDir}/${parameters.expandTheme}/scripting-events.ftl" />
|
||||
<#include "/${parameters.templateDir}/${parameters.expandTheme}/common-attributes.ftl" />
|
||||
<#include "/${parameters.templateDir}/${parameters.expandTheme}/dynamic-attributes.ftl" />
|
||||
@@ -52,10 +58,4 @@
|
||||
<#if parameters.nameValue??>
|
||||
<@s.property value="parameters.nameValue"/><#t/>
|
||||
</#if>
|
||||
<#if parameters.maxlength?has_content>
|
||||
maxlength="${parameters.maxlength}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.minlength?has_content>
|
||||
minlength="${parameters.minlength}"<#rt/>
|
||||
</#if>
|
||||
</textarea>
|
||||
</textarea>
|
||||
|
||||
@@ -28,6 +28,9 @@ import org.apache.struts2.conversion.TypeConversionException;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.DateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
@@ -43,14 +46,20 @@ public class DateConverterTest extends StrutsInternalTestCase {
|
||||
private final static String DATE_STR = "2020-03-20";
|
||||
private final static String DATE_CONVERTED = "Fri Mar 20 00:00:00";
|
||||
private final static String INVALID_DATE = "99/99/2010";
|
||||
private final static String LOCALDATETIME_STR = "2020-03-20T00:00:00.000000";
|
||||
private final static String LOCALDATETIME1_STR = "12:00 AM Fri Mar 20, 2020";
|
||||
private final static String LOCALDATETIME_CONVERTED = "2020-03-20T00:00";
|
||||
private final static String LOCALDATE_STR = "2020-03-20";
|
||||
private final static String LOCALTIME_STR = "01:59:10";
|
||||
|
||||
private final static String INVALID_LOCALDATETIME = "2010-99-99T00:00";
|
||||
private final static String MESSAGE_PARSE_ERROR = "Could not parse date";
|
||||
private final static String MESSAGE_DEFAULT_CONSTRUCTOR_ERROR = "Couldn't create class null using default (long) constructor";
|
||||
|
||||
public void testSqlTimeType() {
|
||||
DateConverter converter = new DateConverter();
|
||||
|
||||
ActionContext context = ActionContext.of(new HashMap<>())
|
||||
.withLocale(mxLocale);
|
||||
ActionContext context = ActionContext.of(new HashMap<>()).withLocale(mxLocale);
|
||||
|
||||
Object value = converter.convertValue(context.getContextMap(), null, null, null, TIME_01_59_10, Time.class);
|
||||
assertEquals("01:59:10", value.toString());
|
||||
@@ -59,10 +68,10 @@ public class DateConverterTest extends StrutsInternalTestCase {
|
||||
public void testSqlTimestampType() {
|
||||
DateConverter converter = new DateConverter();
|
||||
|
||||
ActionContext context = ActionContext.of(new HashMap<>())
|
||||
.withLocale(mxLocale);
|
||||
ActionContext context = ActionContext.of(new HashMap<>()).withLocale(mxLocale);
|
||||
|
||||
Object value = converter.convertValue(context.getContextMap(), null, null, null, INPUT_TIME_STAMP_STR, Timestamp.class);
|
||||
Object value = converter.convertValue(context.getContextMap(), null, null, null, INPUT_TIME_STAMP_STR,
|
||||
Timestamp.class);
|
||||
assertEquals(RES_TIME_STAMP_STR, value.toString());
|
||||
}
|
||||
|
||||
@@ -74,9 +83,8 @@ public class DateConverterTest extends StrutsInternalTestCase {
|
||||
ValueStack stack = new StubValueStack();
|
||||
stack.push(new StubTextProvider(map));
|
||||
|
||||
ActionContext context = ActionContext.of(new HashMap<>())
|
||||
.withLocale(new Locale("es_MX", "MX"))
|
||||
.withValueStack(stack);
|
||||
ActionContext context = ActionContext.of(new HashMap<>()).withLocale(new Locale("es_MX", "MX"))
|
||||
.withValueStack(stack);
|
||||
|
||||
Object value = converter.convertValue(context.getContextMap(), null, null, null, DATE_STR, Date.class);
|
||||
assertTrue(value.toString().startsWith(DATE_CONVERTED));
|
||||
@@ -90,9 +98,8 @@ public class DateConverterTest extends StrutsInternalTestCase {
|
||||
ValueStack stack = new StubValueStack();
|
||||
stack.push(new StubTextProvider(map));
|
||||
|
||||
ActionContext context = ActionContext.of(new HashMap<>())
|
||||
.withLocale(new Locale("es_MX", "MX"))
|
||||
.withValueStack(stack);
|
||||
ActionContext context = ActionContext.of(new HashMap<>()).withLocale(new Locale("es_MX", "MX"))
|
||||
.withValueStack(stack);
|
||||
|
||||
try {
|
||||
converter.convertValue(context.getContextMap(), null, null, null, INVALID_DATE, Date.class);
|
||||
@@ -106,8 +113,7 @@ public class DateConverterTest extends StrutsInternalTestCase {
|
||||
public void testTypeConversionExceptionWhenUsingLongConstructor() {
|
||||
DateConverter converter = new DateConverter();
|
||||
|
||||
ActionContext context = ActionContext.of(new HashMap<>())
|
||||
.withLocale(mxLocale);
|
||||
ActionContext context = ActionContext.of(new HashMap<>()).withLocale(mxLocale);
|
||||
|
||||
try {
|
||||
converter.convertValue(context.getContextMap(), null, null, null, INPUT_WHEN_LONG_CONSTRUCTOR_STR, null);
|
||||
@@ -118,12 +124,73 @@ public class DateConverterTest extends StrutsInternalTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testLocalDateTimeType() {
|
||||
DateConverter converter = new DateConverter();
|
||||
|
||||
ActionContext context = ActionContext.of(new HashMap<>());
|
||||
|
||||
Object value = converter.convertValue(context.getContextMap(), null, null, null, LOCALDATETIME_STR,
|
||||
LocalDateTime.class);
|
||||
assertTrue(value.toString().startsWith(LOCALDATETIME_CONVERTED));
|
||||
}
|
||||
|
||||
public void testLocalDateTime1Type() {
|
||||
DateConverter converter = new DateConverter();
|
||||
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put(org.apache.struts2.components.Date.DATETAG_PROPERTY, "hh:mm a EEE MMM dd, yyyy");
|
||||
ValueStack stack = new StubValueStack();
|
||||
stack.push(new StubTextProvider(map));
|
||||
|
||||
ActionContext context = ActionContext.of(new HashMap<>()).withLocale(mxLocale)
|
||||
.withValueStack(stack);
|
||||
|
||||
Object value = converter.convertValue(context.getContextMap(), null, null, null, LOCALDATETIME1_STR,
|
||||
LocalDateTime.class);
|
||||
assertTrue(value.toString().startsWith(LOCALDATETIME_CONVERTED));
|
||||
}
|
||||
|
||||
public void testLocalDateTimeTypeConversionExceptionWhenParseError() {
|
||||
DateConverter converter = new DateConverter();
|
||||
|
||||
ActionContext context = ActionContext.of(new HashMap<>());
|
||||
|
||||
try {
|
||||
converter.convertValue(context.getContextMap(), null, null, null, INVALID_LOCALDATETIME,
|
||||
LocalDateTime.class);
|
||||
fail("TypeConversionException expected - Conversion error occurred");
|
||||
} catch (Exception ex) {
|
||||
assertEquals(TypeConversionException.class, ex.getClass());
|
||||
assertEquals(MESSAGE_PARSE_ERROR, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testLocalDateType() {
|
||||
DateConverter converter = new DateConverter();
|
||||
|
||||
ActionContext context = ActionContext.of(new HashMap<>());
|
||||
|
||||
Object value = converter.convertValue(context.getContextMap(), null, null, null, LOCALDATE_STR,
|
||||
LocalDate.class);
|
||||
assertTrue(value.toString().startsWith(LOCALDATE_STR));
|
||||
}
|
||||
|
||||
public void testLocalTimeType() {
|
||||
DateConverter converter = new DateConverter();
|
||||
|
||||
ActionContext context = ActionContext.of(new HashMap<>());
|
||||
|
||||
Object value = converter.convertValue(context.getContextMap(), null, null, null, LOCALTIME_STR,
|
||||
LocalTime.class);
|
||||
assertTrue(value.toString().startsWith(LOCALTIME_STR));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
//Due to JEP 252: Use CLDR Locale Data by Default
|
||||
// Due to JEP 252: Use CLDR Locale Data by Default
|
||||
DateFormat dFormat = DateFormat.getDateInstance(DateFormat.SHORT, mxLocale);
|
||||
if (dFormat.format(new Date()).contains("-")) { // Format when Java 9 or greater
|
||||
if (dFormat.format(new Date()).contains("-")) { // Format when Java 9 or greater
|
||||
INPUT_TIME_STAMP_STR = "2020-03-20 00:00:00.000";
|
||||
INPUT_WHEN_LONG_CONSTRUCTOR_STR = "2020-03-20";
|
||||
} else {// Format when Java 8 or lower
|
||||
|
||||
+10
-5
@@ -39,13 +39,17 @@ import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
|
||||
import ognl.OgnlContext;
|
||||
import ognl.PropertyAccessor;
|
||||
import org.apache.struts2.config.StrutsXmlConfigurationProvider;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.junit.Assert;
|
||||
import org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -335,8 +339,8 @@ public class ParametersInterceptorTest extends XWorkTestCase {
|
||||
// given
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("blah", "This is blah");
|
||||
params.put("('\\u0023_memberAccess[\\'allowStaticMethodAccess\\']')(meh)", "true");
|
||||
params.put("('(aaa)(('\\u0023context[\\'xwork.MethodAccessor.denyMethodExecution\\']\\u003d\\u0023foo')(\\u0023foo\\u003dnew java.lang.Boolean(\"false\")))", "");
|
||||
params.put("('\\u0023_memberAccess[\\'allowStaticFieldAccess\\']')(meh)", "true");
|
||||
params.put("('(aaa)(('\\u0023context[\\'xwork.MethodAccessor.denyMethodExecution\\']\\u003d\\u0023foo')(\\u0023foo\\u003dnew java.lang.Boolean(\"true\")))", "");
|
||||
params.put("(asdf)(('\\u0023rt.exit(1)')(\\u0023rt\\u003d@java.lang.Runtime@getRuntime()))", "1");
|
||||
|
||||
HashMap<String, Object> extraContext = new HashMap<>();
|
||||
@@ -351,8 +355,9 @@ public class ParametersInterceptorTest extends XWorkTestCase {
|
||||
|
||||
//then
|
||||
assertEquals("This is blah", ((SimpleAction) proxy.getAction()).getBlah());
|
||||
boolean allowMethodAccess = ((SecurityMemberAccess) ((OgnlContext) stack.getContext()).getMemberAccess()).getAllowStaticMethodAccess();
|
||||
assertFalse(allowMethodAccess);
|
||||
Field field = ReflectionContextState.class.getField("DENY_METHOD_EXECUTION");
|
||||
boolean allowStaticFieldAccess = ((OgnlContext) stack.getContext()).getMemberAccess().isAccessible(stack.getContext(), proxy.getAction(), field, "");
|
||||
assertFalse(allowStaticFieldAccess);
|
||||
}
|
||||
|
||||
public void testParameters() throws Exception {
|
||||
@@ -806,7 +811,7 @@ public class ParametersInterceptorTest extends XWorkTestCase {
|
||||
ValueStack stack = new OgnlValueStack(
|
||||
container.getInstance(XWorkConverter.class),
|
||||
(CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()),
|
||||
container.getInstance(TextProvider.class, "system"), true, true) {
|
||||
container.getInstance(TextProvider.class, "system"), true) {
|
||||
@Override
|
||||
public void setValue(String expr, Object value) {
|
||||
actual.put(expr, value);
|
||||
|
||||
@@ -1900,13 +1900,13 @@ public class OgnlUtilTest extends XWorkTestCase {
|
||||
return result;
|
||||
}
|
||||
|
||||
private void reloadTestContainerConfiguration(boolean devMode, boolean allowStaticMethod) {
|
||||
private void reloadTestContainerConfiguration(boolean devMode, boolean allowStaticFieldAccess) {
|
||||
loadConfigurationProviders(new StubConfigurationProvider() {
|
||||
@Override
|
||||
public void register(ContainerBuilder builder,
|
||||
LocatableProperties props) throws ConfigurationException {
|
||||
props.setProperty(StrutsConstants.STRUTS_DEVMODE, "" + devMode);
|
||||
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, "" + allowStaticMethod);
|
||||
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, "" + allowStaticFieldAccess);
|
||||
}
|
||||
});
|
||||
ognlUtil = container.getInstance(OgnlUtil.class);
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.ognl;
|
||||
|
||||
import com.opensymphony.xwork2.*;
|
||||
import com.opensymphony.xwork2.SimpleAction;
|
||||
import com.opensymphony.xwork2.TestBean;
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.XWorkTestCase;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.conversion.impl.ConversionData;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
@@ -26,22 +29,17 @@ 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.Bar;
|
||||
import com.opensymphony.xwork2.util.BarJunior;
|
||||
import com.opensymphony.xwork2.util.Cat;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.Dog;
|
||||
import com.opensymphony.xwork2.util.Foo;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
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;
|
||||
@@ -51,10 +49,18 @@ import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.config.DefaultPropertiesProvider;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Unit test for OgnlValueStack.
|
||||
*/
|
||||
public class OgnlValueStackTest extends XWorkTestCase {
|
||||
|
||||
// Fields for static field access test
|
||||
@@ -85,16 +91,15 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
}
|
||||
|
||||
private OgnlValueStack createValueStack() {
|
||||
return createValueStack(true, true);
|
||||
return createValueStack(true);
|
||||
}
|
||||
|
||||
private OgnlValueStack createValueStack(boolean allowStaticMethodAccess, boolean allowStaticFieldAccess) {
|
||||
private OgnlValueStack createValueStack(boolean allowStaticFieldAccess) {
|
||||
OgnlValueStack stack = new OgnlValueStack(
|
||||
container.getInstance(XWorkConverter.class),
|
||||
(CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()),
|
||||
container.getInstance(TextProvider.class, "system"), allowStaticMethodAccess, allowStaticFieldAccess);
|
||||
container.getInstance(XWorkConverter.class),
|
||||
(CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()),
|
||||
container.getInstance(TextProvider.class, "system"), allowStaticFieldAccess);
|
||||
container.inject(stack);
|
||||
ognlUtil.setAllowStaticMethodAccess(Boolean.toString(allowStaticMethodAccess));
|
||||
ognlUtil.setAllowStaticFieldAccess(Boolean.toString(allowStaticFieldAccess));
|
||||
return stack;
|
||||
}
|
||||
@@ -111,16 +116,14 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
* 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
|
||||
*
|
||||
* @param allowStaticField new allowStaticField configuration
|
||||
* @return a new OgnlValueStackFactory with specified new configuration
|
||||
*/
|
||||
private OgnlValueStackFactory reloadValueStackFactory(Boolean allowStaticMethod, Boolean allowStaticField) {
|
||||
private OgnlValueStackFactory reloadValueStackFactory(Boolean allowStaticField) {
|
||||
try {
|
||||
reloadTestContainerConfiguration(allowStaticMethod, allowStaticField);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
reloadTestContainerConfiguration(allowStaticField);
|
||||
} catch (Exception ex) {
|
||||
fail("Unable to reload container configuration and configure ognlValueStackFactory - exception: " + ex);
|
||||
}
|
||||
|
||||
@@ -210,7 +213,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
vs.findValue("barJunior.title", true);
|
||||
}
|
||||
|
||||
public void testSuccessFailOnErrorOnInheritedPropertiesWithMethods() {
|
||||
public void testSuccessFailOnErrorOnInheritedPropertiesWithMethods() {
|
||||
//this shuld not fail as the property is defined on a parent class
|
||||
OgnlValueStack vs = createValueStack();
|
||||
|
||||
@@ -254,6 +257,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
|
||||
/**
|
||||
* monitors the resolution of WW-4999
|
||||
*
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public void testLogMissingProperties() {
|
||||
@@ -281,11 +285,11 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
if (logMissingProperties) {
|
||||
assertEquals(3, testAppender.logEvents.size());
|
||||
assertEquals("Error setting value [missingProp1Value] with expression [missingProp1]",
|
||||
testAppender.logEvents.get(0).getMessage().getFormattedMessage());
|
||||
testAppender.logEvents.get(0).getMessage().getFormattedMessage());
|
||||
assertEquals("Could not find property [missingProp2]!",
|
||||
testAppender.logEvents.get(1).getMessage().getFormattedMessage());
|
||||
testAppender.logEvents.get(1).getMessage().getFormattedMessage());
|
||||
assertEquals("Could not find property [missingProp3]!",
|
||||
testAppender.logEvents.get(2).getMessage().getFormattedMessage());
|
||||
testAppender.logEvents.get(2).getMessage().getFormattedMessage());
|
||||
} else {
|
||||
assertEquals(0, testAppender.logEvents.size());
|
||||
}
|
||||
@@ -297,6 +301,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
|
||||
/**
|
||||
* tests the correctness of distinguishing between user exception and NoSuchMethodException
|
||||
*
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public void testNotLogUserExceptionsAsMissingProperties() {
|
||||
@@ -364,7 +369,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
}
|
||||
});
|
||||
Integer repeat = Integer.parseInt(
|
||||
container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH));
|
||||
container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH));
|
||||
|
||||
OgnlValueStack vs = createValueStack();
|
||||
try {
|
||||
@@ -383,65 +388,40 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
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
|
||||
String defaultMaxLengthFromConfiguration = container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH);
|
||||
assertNotNull(defaultMaxLengthFromConfiguration);
|
||||
|
||||
int defaultValue = 256;
|
||||
|
||||
OgnlValueStack vs = createValueStack();
|
||||
try {
|
||||
vs.findValue(StringUtils.repeat('.', repeat + 1), true);
|
||||
vs.findValue(StringUtils.repeat('.', defaultValue + 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);
|
||||
assertTrue(((OgnlException) ex.getCause()).getReason() instanceof SecurityException);
|
||||
assertTrue(((OgnlException) ex.getCause()).getReason().getMessage().startsWith("This expression exceeded maximum allowed length"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testNotFailOnTooLongValueWithDefaultProperties() {
|
||||
try {
|
||||
loadConfigurationProviders(new DefaultPropertiesProvider());
|
||||
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
|
||||
Object defaultMaxLengthFromConfiguration = container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH);
|
||||
assertNotNull(defaultMaxLengthFromConfiguration);
|
||||
|
||||
// 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() + " ?");
|
||||
}
|
||||
int defaultValue = 256;
|
||||
|
||||
OgnlValueStack vs = createValueStack();
|
||||
OgnlValueStack vs = createValueStack();
|
||||
|
||||
Dog dog = new Dog();
|
||||
vs.push(dog);
|
||||
Dog dog = new Dog();
|
||||
vs.push(dog);
|
||||
|
||||
String value = StringUtils.repeat('.', repeat + 1);
|
||||
String value = StringUtils.repeat('.', defaultValue);
|
||||
|
||||
vs.setValue("name", value);
|
||||
vs.setValue("name", value);
|
||||
|
||||
assertEquals(value, dog.getName());
|
||||
} finally {
|
||||
// Reset expressionMaxLength value to default (disabled)
|
||||
ognlUtil.applyExpressionMaxLength(null);
|
||||
}
|
||||
assertEquals(value, dog.getName());
|
||||
}
|
||||
|
||||
public void testFailsOnMethodThatThrowsException() {
|
||||
@@ -502,7 +482,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
Dog dog = new Dog();
|
||||
dog.setDeity("fido");
|
||||
vs.push(dog);
|
||||
assertEquals("fido", vs.findValue("@com.opensymphony.xwork2.util.Dog@getDeity()", String.class));
|
||||
assertNull(vs.findValue("@com.opensymphony.xwork2.util.Dog@getDeity()", String.class));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -517,7 +497,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
}
|
||||
|
||||
public void testStaticMethodDisallow() {
|
||||
OgnlValueStack vs = createValueStack(false, true);
|
||||
OgnlValueStack vs = createValueStack(true);
|
||||
|
||||
Dog dog = new Dog();
|
||||
dog.setDeity("fido");
|
||||
@@ -845,8 +825,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
try {
|
||||
stack.setValue("bar", "3x");
|
||||
fail("Attempt to set 'bar' int property to '3x' should result in RuntimeException");
|
||||
}
|
||||
catch (RuntimeException re) {
|
||||
} catch (RuntimeException re) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
@@ -1082,6 +1061,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
|
||||
/**
|
||||
* Fails on 2.5.20 and earlier - tested on 2.5 (5/5/2016) and failed
|
||||
*
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public void testNotThrowExceptionOnTopMissingProperty() {
|
||||
@@ -1104,6 +1084,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
|
||||
/**
|
||||
* Fails on 2.5.20 and earlier - tested on 2.5 (5/5/2016) and failed
|
||||
*
|
||||
* @since 2.5.21
|
||||
*/
|
||||
public void testNotSkipUserReturnedNullValues() {
|
||||
@@ -1187,8 +1168,8 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
stack.push("Hello World");
|
||||
|
||||
OgnlValueStack stack2 = new OgnlValueStack(stack,
|
||||
container.getInstance(XWorkConverter.class),
|
||||
(CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()), true, true);
|
||||
container.getInstance(XWorkConverter.class),
|
||||
(CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()), true);
|
||||
container.inject(stack2);
|
||||
|
||||
assertEquals(stack.getRoot(), stack2.getRoot());
|
||||
@@ -1260,7 +1241,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
assertNull(stack.findValue("address.country.name", String.class));
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Test a default OgnlValueStackFactory and OgnlValueStack generated by it
|
||||
* when a default configuration is used.
|
||||
*/
|
||||
@@ -1271,7 +1252,6 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
|
||||
// An OgnlValueStackFactory using a container config with default (from XWorkConfigurationProvider)
|
||||
// static access flag values present should prevent staticMethodAccess but allow staticFieldAccess.
|
||||
assertFalse("OgnlValueStackFactory staticMethodAccess (default flags) not false?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
|
||||
assertTrue("OgnlValueStackFactory staticFieldAccess (default flags) not true?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
|
||||
// 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.
|
||||
@@ -1300,7 +1280,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
* when no static access flags are set (not present in configuration).
|
||||
*/
|
||||
public void testOgnlValueStackFromOgnlValueStackFactoryNoFlagsSet() {
|
||||
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(null, null);
|
||||
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(null);
|
||||
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
|
||||
Object accessedValue;
|
||||
|
||||
@@ -1309,7 +1289,6 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
// prevent staticMethodAccess AND prevent staticFieldAccess.
|
||||
// Note: Under normal circumstances, explicit static access configuration flags should be present,
|
||||
// but this specific check verifies what happens if those configuration flags are not present.
|
||||
assertFalse("OgnlValueStackFactory staticMethodAccess (no flag present) not false?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
|
||||
assertFalse("OgnlValueStackFactory staticFieldAccess (no flag present) not false?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
|
||||
// An OgnlValueStack created from the above OgnlValueStackFactory should prevent public field access,
|
||||
// and prevent non-public field access. It should also deny static method access.
|
||||
@@ -1335,16 +1314,15 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
|
||||
/**
|
||||
* Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
|
||||
* when both static access flags are set to false.
|
||||
* when static access flag is set to false.
|
||||
*/
|
||||
public void testOgnlValueStackFromOgnlValueStackFactoryNoStaticAccess() {
|
||||
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(false, false);
|
||||
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(false);
|
||||
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
|
||||
Object accessedValue;
|
||||
|
||||
// An OgnlValueStackFactory using a container config with both static access flags set false should
|
||||
// prevent staticMethodAccess AND prevent staticFieldAccess.
|
||||
assertFalse("OgnlValueStackFactory staticMethodAccess (set false) not false?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
|
||||
assertFalse("OgnlValueStackFactory staticFieldAccess (set false) not false?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
|
||||
// An OgnlValueStack created from the above OgnlValueStackFactory should prevent public field access,
|
||||
// and prevent non-public field access. It should also deny static method access.
|
||||
@@ -1370,22 +1348,20 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
|
||||
/**
|
||||
* Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
|
||||
* when both static access flags are set to true.
|
||||
* when static access flag is set to true.
|
||||
*/
|
||||
public void testOgnlValueStackFromOgnlValueStackFactoryAllStaticAccess() {
|
||||
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(true, true);
|
||||
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(true);
|
||||
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
|
||||
Object accessedValue;
|
||||
|
||||
// An OgnlValueStackFactory using a container config with both static access flags set true should
|
||||
// allow both staticMethodAccess AND staticFieldAccess.
|
||||
assertTrue("OgnlValueStackFactory staticMethodAccess (set true) not true?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
|
||||
assertTrue("OgnlValueStackFactory staticFieldAccess (set true) not true?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
|
||||
// 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());
|
||||
assertNull("able to access static method (result non-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");
|
||||
@@ -1404,93 +1380,14 @@ public class OgnlValueStackTest extends XWorkTestCase {
|
||||
assertNull("accessed private field (result not null) ?", accessedValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
|
||||
* when static method access flag is true, static field access flag is false.
|
||||
*/
|
||||
public void testOgnlValueStackFromOgnlValueStackFactoryOnlyStaticMethodAccess() {
|
||||
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(true, false);
|
||||
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
|
||||
Object accessedValue;
|
||||
|
||||
// An OgnlValueStackFactory using a container config with static method access flag true, static field access false should
|
||||
// allow staticMethodAccess but deny staticFieldAccess.
|
||||
assertTrue("OgnlValueStackFactory staticMethodAccess (set true) not true?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
|
||||
assertFalse("OgnlValueStackFactory staticFieldAccess (set false) not false?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
|
||||
// An OgnlValueStack created from the above OgnlValueStackFactory should deny public field access,
|
||||
// and also 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");
|
||||
assertNull("able to access static final public field (result not null) ?", accessedValue);
|
||||
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
|
||||
assertNull("able to access static public field (result not null) ?", accessedValue);
|
||||
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 false, static field access flag is true.
|
||||
*/
|
||||
public void testOgnlValueStackFromOgnlValueStackFactoryOnlyStaticFieldAccess() {
|
||||
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(false, true);
|
||||
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
|
||||
Object accessedValue;
|
||||
|
||||
// An OgnlValueStackFactory using a container config with static method access flag false, static field access true should
|
||||
// deny staticMethodAccess but allow staticFieldAccess.
|
||||
assertFalse("OgnlValueStackFactory staticMethodAccess (set false) not false?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
|
||||
assertTrue("OgnlValueStackFactory staticFieldAccess (set true) not true?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
|
||||
// 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);
|
||||
}
|
||||
|
||||
private void reloadTestContainerConfiguration(Boolean allowStaticMethod, Boolean allowStaticField) throws Exception {
|
||||
private void reloadTestContainerConfiguration(Boolean allowStaticField) 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(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS)) {
|
||||
props.remove(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS);
|
||||
}
|
||||
if (allowStaticMethod != null) {
|
||||
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, "" + allowStaticMethod);
|
||||
}
|
||||
props.remove(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS);
|
||||
if (allowStaticField != null) {
|
||||
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, "" + allowStaticField);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import junit.framework.TestCase;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -45,7 +44,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testWithoutClassExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "stringField";
|
||||
Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
|
||||
@@ -59,7 +58,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testClassExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "stringField";
|
||||
Member member = FooBar.class.getDeclaredMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
|
||||
@@ -77,7 +76,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testObjectClassExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "toString";
|
||||
Member member = FooBar.class.getMethod(propertyName);
|
||||
@@ -91,7 +90,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testObjectOverwrittenMethodsExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "hashCode";
|
||||
Member member = FooBar.class.getMethod(propertyName);
|
||||
@@ -105,7 +104,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testInterfaceInheritanceExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "barLogic";
|
||||
Member member = BarInterface.class.getMethod(propertyName);
|
||||
@@ -123,7 +122,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testMiddleOfInheritanceExclusion1() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "fooLogic";
|
||||
Member member = FooBar.class.getMethod(propertyName);
|
||||
@@ -141,7 +140,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testMiddleOfInheritanceExclusion3() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "barLogic";
|
||||
Member member = BarInterface.class.getMethod(propertyName);
|
||||
@@ -155,7 +154,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testMiddleOfInheritanceExclusion4() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "barLogic";
|
||||
Member member = BarInterface.class.getMethod(propertyName);
|
||||
@@ -173,7 +172,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testPackageExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
Set<Pattern> excluded = new HashSet<>();
|
||||
excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*"));
|
||||
@@ -188,10 +187,10 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
// then
|
||||
assertFalse("stringField is accessible!", actual);
|
||||
}
|
||||
|
||||
|
||||
public void testPackageNameExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
Set<String> excluded = new HashSet<>();
|
||||
excluded.add(FooBar.class.getPackage().getName());
|
||||
@@ -209,27 +208,27 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testDefaultPackageExclusion() {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
Set<Pattern> excluded = new HashSet<>();
|
||||
excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*"));
|
||||
sma.setExcludedPackageNamePatterns(excluded);
|
||||
|
||||
|
||||
// when
|
||||
boolean actual = sma.isPackageExcluded(null, null);
|
||||
|
||||
// then
|
||||
assertFalse("default package is excluded!", actual);
|
||||
}
|
||||
|
||||
|
||||
public void testDefaultPackageExclusion2() {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
Set<Pattern> excluded = new HashSet<>();
|
||||
excluded.add(Pattern.compile("^$"));
|
||||
sma.setExcludedPackageNamePatterns(excluded);
|
||||
|
||||
|
||||
// when
|
||||
boolean actual = sma.isPackageExcluded(null, null);
|
||||
|
||||
@@ -239,7 +238,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testAccessEnum() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
// when
|
||||
Member values = MyValues.class.getMethod("values");
|
||||
@@ -249,23 +248,23 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
assertTrue("Access to enums is blocked!", actual);
|
||||
}
|
||||
|
||||
public void testAccessStatic() throws Exception {
|
||||
public void testAccessStaticMethod() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true, true);
|
||||
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
Member method = StaticTester.class.getMethod("sayHello");
|
||||
boolean actual = sma.isAccessible(context, Class.class, method, null);
|
||||
|
||||
// then
|
||||
assertTrue("Access to static is blocked!", actual);
|
||||
assertFalse("Access to static method is not blocked!", actual);
|
||||
}
|
||||
|
||||
public void testAccessStaticField() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true, true);
|
||||
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
Member method = StaticTester.class.getField("MAX_VALUE");
|
||||
@@ -277,8 +276,8 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testBlockedStaticFieldWhenFlagIsFalse() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
Member method = StaticTester.class.getField("MAX_VALUE");
|
||||
@@ -289,8 +288,8 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
// public static final test
|
||||
// given
|
||||
sma = new SecurityMemberAccess(false, true);
|
||||
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
|
||||
sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
method = StaticTester.class.getField("MIN_VALUE");
|
||||
@@ -301,8 +300,8 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
// package static test
|
||||
// given
|
||||
sma = new SecurityMemberAccess(false, true);
|
||||
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
|
||||
sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
method = StaticTester.getFieldByName("PACKAGE_STRING");
|
||||
@@ -313,8 +312,8 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
// package final static test
|
||||
// given
|
||||
sma = new SecurityMemberAccess(false, true);
|
||||
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
|
||||
sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
method = StaticTester.getFieldByName("FINAL_PACKAGE_STRING");
|
||||
@@ -325,8 +324,8 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
// protected static test
|
||||
// given
|
||||
sma = new SecurityMemberAccess(false, true);
|
||||
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
|
||||
sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
method = StaticTester.getFieldByName("PROTECTED_STRING");
|
||||
@@ -337,8 +336,8 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
// protected final static test
|
||||
// given
|
||||
sma = new SecurityMemberAccess(false, true);
|
||||
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
|
||||
sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
method = StaticTester.getFieldByName("FINAL_PROTECTED_STRING");
|
||||
@@ -349,8 +348,8 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
// private static test
|
||||
// given
|
||||
sma = new SecurityMemberAccess(false, true);
|
||||
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
|
||||
sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
method = StaticTester.getFieldByName("PRIVATE_STRING");
|
||||
@@ -361,8 +360,8 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
// private final static test
|
||||
// given
|
||||
sma = new SecurityMemberAccess(false, true);
|
||||
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
|
||||
sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
method = StaticTester.getFieldByName("FINAL_PRIVATE_STRING");
|
||||
@@ -374,7 +373,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testBlockedStaticFieldWhenClassIsExcluded() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Arrays.asList(Class.class, StaticTester.class)));
|
||||
|
||||
// when
|
||||
@@ -385,10 +384,10 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
assertFalse("Access to static field isn't blocked!", actual);
|
||||
}
|
||||
|
||||
public void testBlockStaticAccess() throws Exception {
|
||||
public void testBlockStaticMethodAccess() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
Member method = StaticTester.class.getMethod("sayHello");
|
||||
@@ -400,8 +399,8 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testBlockStaticAccessIfClassIsExcluded() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
Member method = Class.class.getMethod("getClassLoader");
|
||||
@@ -413,8 +412,8 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testAllowStaticAccessIfClassIsNotExcluded() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true, true);
|
||||
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(ClassLoader.class)));
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(ClassLoader.class)));
|
||||
|
||||
// when
|
||||
Member method = Class.class.getMethod("getClassLoader");
|
||||
@@ -426,7 +425,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testAccessPrimitiveInt() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("java.lang.,ognl,javax"));
|
||||
|
||||
String propertyName = "intField";
|
||||
@@ -441,7 +440,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testAccessPrimitiveDoubleWithNames() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("ognl.,javax."));
|
||||
|
||||
|
||||
@@ -493,7 +492,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testAccessPrimitiveDoubleWithPackageRegExs() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
Set<Pattern> patterns = new HashSet<>();
|
||||
patterns.add(Pattern.compile("^java\\.lang\\..*"));
|
||||
sma.setExcludedPackageNamePatterns(patterns);
|
||||
@@ -510,7 +509,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testAccessMemberAccessIsAccessible() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
Set<Class<?>> excluded = new HashSet<>();
|
||||
excluded.add(ognl.MemberAccess.class);
|
||||
sma.setExcludedClasses(excluded);
|
||||
@@ -528,7 +527,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testAccessMemberAccessIsBlocked() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
Set<Class<?>> excluded = new HashSet<>();
|
||||
excluded.add(SecurityMemberAccess.class);
|
||||
sma.setExcludedClasses(excluded);
|
||||
@@ -546,7 +545,7 @@ public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
public void testPackageNameExclusionAsCommaDelimited() {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
|
||||
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("java.lang."));
|
||||
|
||||
@@ -46,9 +46,9 @@ import java.util.*;
|
||||
* @author tm_jee
|
||||
*/
|
||||
public class SetPropertiesTest extends XWorkTestCase {
|
||||
|
||||
|
||||
private OgnlUtil ognlUtil;
|
||||
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
@@ -57,7 +57,7 @@ public class SetPropertiesTest extends XWorkTestCase {
|
||||
}
|
||||
public void testOgnlUtilEmptyStringAsLong() {
|
||||
Bar bar = new Bar();
|
||||
Map context = Ognl.createDefaultContext(bar, new SecurityMemberAccess(false, true));
|
||||
Map context = Ognl.createDefaultContext(bar, new SecurityMemberAccess(true));
|
||||
context.put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE);
|
||||
bar.setId(null);
|
||||
|
||||
@@ -110,7 +110,7 @@ public class SetPropertiesTest extends XWorkTestCase {
|
||||
assertEquals(Cat.class, foo.getCats().get(0).getClass());
|
||||
assertEquals(Cat.class, foo.getCats().get(1).getClass());
|
||||
}
|
||||
|
||||
|
||||
public void testValueStackSetValueEmptyStringAsLong() {
|
||||
Bar bar = new Bar();
|
||||
ValueStack vs = ActionContext.getContext().getValueStack();
|
||||
@@ -193,11 +193,11 @@ public class SetPropertiesTest extends XWorkTestCase {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void testAddingToMapsWithObjectsTrue() throws Exception {
|
||||
doTestAddingToMapsWithObjects(true);
|
||||
}
|
||||
|
||||
|
||||
public void testAddingToMapsWithObjectsFalse() throws Exception {
|
||||
doTestAddingToMapsWithObjects(false);
|
||||
|
||||
@@ -227,8 +227,8 @@ public class SetPropertiesTest extends XWorkTestCase {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void testAddingAndModifyingCollectionWithObjectsSet() {
|
||||
doTestAddingAndModifyingCollectionWithObjects(new HashSet());
|
||||
}
|
||||
|
||||
+3
-3
@@ -264,7 +264,7 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
|
||||
* Unit test to confirm expected behaviour of "clearing methods" provided to
|
||||
* StrutsLocalizedTextProvider (from AbstractLocalizedTextProvider).
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public void testLocalizedTextProviderClearingMethods() {
|
||||
TestStrutsLocalizedTextProvider testStrutsLocalizedTextProvider = new TestStrutsLocalizedTextProvider();
|
||||
@@ -331,7 +331,7 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
|
||||
* Unit test to confirm the basic behaviour of bundle reload methods provided to
|
||||
* StrutsLocalizedTextProvider (from AbstractLocalizedTextProvider).
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public void testLocalizedTextProviderReloadMethods() {
|
||||
TestStrutsLocalizedTextProvider testStrutsLocalizedTextProvider = new TestStrutsLocalizedTextProvider();
|
||||
@@ -582,7 +582,7 @@ public class StrutsLocalizedTextProviderTest extends XWorkTestCase {
|
||||
/**
|
||||
* Basic test class to allow specific testing of StrutsLocalizedTextProvider.
|
||||
*
|
||||
* @since 2.6
|
||||
* @since 6.0.0
|
||||
*/
|
||||
class TestStrutsLocalizedTextProvider extends StrutsLocalizedTextProvider {
|
||||
|
||||
|
||||
@@ -0,0 +1,651 @@
|
||||
/*
|
||||
* 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 com.test;
|
||||
|
||||
import com.opensymphony.xwork2.ognl.SecurityMemberAccess;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class SecurityMemberAccessTest extends TestCase {
|
||||
|
||||
private Map context;
|
||||
private FooBar target;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
context = new HashMap();
|
||||
target = new FooBar();
|
||||
}
|
||||
|
||||
public void testWithoutClassExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "stringField";
|
||||
Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
|
||||
|
||||
// when
|
||||
boolean accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertTrue(accessible);
|
||||
}
|
||||
|
||||
public void testClassExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "stringField";
|
||||
Member member = FooBar.class.getDeclaredMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
|
||||
|
||||
Set<Class<?>> excluded = new HashSet<>();
|
||||
excluded.add(FooBar.class);
|
||||
sma.setExcludedClasses(excluded);
|
||||
|
||||
// when
|
||||
boolean accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertFalse(accessible);
|
||||
}
|
||||
|
||||
public void testObjectClassExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "toString";
|
||||
Member member = FooBar.class.getMethod(propertyName);
|
||||
|
||||
// when
|
||||
boolean accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertFalse("toString() from Object is accessible!!!", accessible);
|
||||
}
|
||||
|
||||
public void testObjectOverwrittenMethodsExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "hashCode";
|
||||
Member member = FooBar.class.getMethod(propertyName);
|
||||
|
||||
// when
|
||||
boolean accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertTrue("hashCode() from FooBar isn't accessible!!!", accessible);
|
||||
}
|
||||
|
||||
public void testInterfaceInheritanceExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "barLogic";
|
||||
Member member = BarInterface.class.getMethod(propertyName);
|
||||
|
||||
Set<Class<?>> excluded = new HashSet<>();
|
||||
excluded.add(BarInterface.class);
|
||||
sma.setExcludedClasses(excluded);
|
||||
|
||||
// when
|
||||
boolean accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertFalse("barLogic() from BarInterface is accessible!!!", accessible);
|
||||
}
|
||||
|
||||
public void testMiddleOfInheritanceExclusion1() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "fooLogic";
|
||||
Member member = FooBar.class.getMethod(propertyName);
|
||||
|
||||
Set<Class<?>> excluded = new HashSet<>();
|
||||
excluded.add(BarInterface.class);
|
||||
sma.setExcludedClasses(excluded);
|
||||
|
||||
// when
|
||||
boolean accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertTrue("fooLogic() from FooInterface isn't accessible!!!", accessible);
|
||||
}
|
||||
|
||||
public void testMiddleOfInheritanceExclusion3() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "barLogic";
|
||||
Member member = BarInterface.class.getMethod(propertyName);
|
||||
|
||||
// when
|
||||
boolean accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertTrue("barLogic() from BarInterface isn't accessible!!!", accessible);
|
||||
}
|
||||
|
||||
public void testMiddleOfInheritanceExclusion4() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
String propertyName = "barLogic";
|
||||
Member member = BarInterface.class.getMethod(propertyName);
|
||||
|
||||
Set<Class<?>> excluded = new HashSet<>();
|
||||
excluded.add(FooBarInterface.class);
|
||||
sma.setExcludedClasses(excluded);
|
||||
|
||||
// when
|
||||
boolean accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertFalse("barLogic() from BarInterface is accessible!!!", accessible);
|
||||
}
|
||||
|
||||
public void testPackageExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
Set<Pattern> excluded = new HashSet<>();
|
||||
excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*"));
|
||||
sma.setExcludedPackageNamePatterns(excluded);
|
||||
|
||||
String propertyName = "stringField";
|
||||
Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
|
||||
|
||||
// when
|
||||
boolean actual = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertFalse("stringField is accessible!", actual);
|
||||
}
|
||||
|
||||
public void testPackageNameExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
Set<String> excluded = new HashSet<>();
|
||||
excluded.add(FooBar.class.getPackage().getName());
|
||||
sma.setExcludedPackageNames(excluded);
|
||||
|
||||
String propertyName = "stringField";
|
||||
Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
|
||||
|
||||
// when
|
||||
boolean actual = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertFalse("stringField is accessible!", actual);
|
||||
}
|
||||
|
||||
public void testDefaultPackageExclusion() {
|
||||
// given
|
||||
TestSecurityMemberAccess sma = new TestSecurityMemberAccess(true);
|
||||
|
||||
Set<Pattern> excluded = new HashSet<>();
|
||||
excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*"));
|
||||
sma.setExcludedPackageNamePatterns(excluded);
|
||||
|
||||
// when
|
||||
boolean actual = sma.isPackageExcluded(null, null);
|
||||
|
||||
// then
|
||||
assertFalse("default package is excluded!", actual);
|
||||
}
|
||||
|
||||
public void testDefaultPackageExclusion2() {
|
||||
// given
|
||||
TestSecurityMemberAccess sma = new TestSecurityMemberAccess(true);
|
||||
|
||||
Set<Pattern> excluded = new HashSet<>();
|
||||
excluded.add(Pattern.compile("^$"));
|
||||
sma.setExcludedPackageNamePatterns(excluded);
|
||||
|
||||
// when
|
||||
boolean actual = sma.isPackageExcluded(null, null);
|
||||
|
||||
// then
|
||||
assertTrue("default package isn't excluded!", actual);
|
||||
}
|
||||
|
||||
public void testAccessEnum() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
// when
|
||||
Member values = MyValues.class.getMethod("values");
|
||||
boolean actual = sma.isAccessible(context, MyValues.class, values, null);
|
||||
|
||||
// then
|
||||
assertTrue("Access to enums is blocked!", actual);
|
||||
}
|
||||
|
||||
public void testAccessStaticMethod() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
Member method = StaticTester.class.getMethod("sayHello");
|
||||
boolean actual = sma.isAccessible(context, Class.class, method, null);
|
||||
|
||||
// then
|
||||
assertFalse("Access to static method is not blocked!", actual);
|
||||
}
|
||||
|
||||
public void testAccessStaticField() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
Member method = StaticTester.class.getField("MAX_VALUE");
|
||||
boolean actual = sma.isAccessible(context, null, method, null);
|
||||
|
||||
// then
|
||||
assertTrue("Access to static field is blocked!", actual);
|
||||
}
|
||||
|
||||
public void testBlockedStaticFieldWhenFlagIsFalse() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
Member method = StaticTester.class.getField("MAX_VALUE");
|
||||
boolean actual = sma.isAccessible(context, null, method, null);
|
||||
|
||||
// then
|
||||
assertTrue("Access to public static field is blocked?", actual);
|
||||
|
||||
// public static final test
|
||||
// given
|
||||
sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
method = StaticTester.class.getField("MIN_VALUE");
|
||||
actual = sma.isAccessible(context, null, method, null);
|
||||
|
||||
// then
|
||||
assertTrue("Access to public final static field is blocked?", actual);
|
||||
|
||||
// package static test
|
||||
// given
|
||||
sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
method = StaticTester.getFieldByName("PACKAGE_STRING");
|
||||
actual = sma.isAccessible(context, null, method, null);
|
||||
|
||||
// then
|
||||
assertFalse("Access to package static field is allowed?", actual);
|
||||
|
||||
// package final static test
|
||||
// given
|
||||
sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
method = StaticTester.getFieldByName("FINAL_PACKAGE_STRING");
|
||||
actual = sma.isAccessible(context, null, method, null);
|
||||
|
||||
// then
|
||||
assertFalse("Access to package final static field is allowed?", actual);
|
||||
|
||||
// protected static test
|
||||
// given
|
||||
sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
method = StaticTester.getFieldByName("PROTECTED_STRING");
|
||||
actual = sma.isAccessible(context, null, method, null);
|
||||
|
||||
// then
|
||||
assertFalse("Access to protected static field is allowed?", actual);
|
||||
|
||||
// protected final static test
|
||||
// given
|
||||
sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
method = StaticTester.getFieldByName("FINAL_PROTECTED_STRING");
|
||||
actual = sma.isAccessible(context, null, method, null);
|
||||
|
||||
// then
|
||||
assertFalse("Access to protected final static field is allowed?", actual);
|
||||
|
||||
// private static test
|
||||
// given
|
||||
sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
method = StaticTester.getFieldByName("PRIVATE_STRING");
|
||||
actual = sma.isAccessible(context, null, method, null);
|
||||
|
||||
// then
|
||||
assertFalse("Access to private static field is allowed?", actual);
|
||||
|
||||
// private final static test
|
||||
// given
|
||||
sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
method = StaticTester.getFieldByName("FINAL_PRIVATE_STRING");
|
||||
actual = sma.isAccessible(context, null, method, null);
|
||||
|
||||
// then
|
||||
assertFalse("Access to private final static field is allowed?", actual);
|
||||
}
|
||||
|
||||
public void testBlockedStaticFieldWhenClassIsExcluded() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Arrays.asList(Class.class, StaticTester.class)));
|
||||
|
||||
// when
|
||||
Member method = StaticTester.class.getField("MAX_VALUE");
|
||||
boolean actual = sma.isAccessible(context, null, method, null);
|
||||
|
||||
// then
|
||||
assertFalse("Access to static field isn't blocked!", actual);
|
||||
}
|
||||
|
||||
public void testBlockStaticAccess() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
Member method = StaticTester.class.getMethod("sayHello");
|
||||
boolean actual = sma.isAccessible(context, Class.class, method, null);
|
||||
|
||||
// then
|
||||
assertFalse("Access to static isn't blocked!", actual);
|
||||
}
|
||||
|
||||
public void testBlockStaticAccessIfClassIsExcluded() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
|
||||
|
||||
// when
|
||||
Member method = Class.class.getMethod("getClassLoader");
|
||||
boolean actual = sma.isAccessible(context, Class.class, method, null);
|
||||
|
||||
// then
|
||||
assertFalse("Access to static method of excluded class isn't blocked!", actual);
|
||||
}
|
||||
|
||||
public void testAllowStaticAccessIfClassIsNotExcluded() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(ClassLoader.class)));
|
||||
|
||||
// when
|
||||
Member method = Class.class.getMethod("getClassLoader");
|
||||
boolean actual = sma.isAccessible(context, Class.class, method, null);
|
||||
|
||||
// then
|
||||
assertTrue("Invalid test! Access to static method of excluded class is blocked!", actual);
|
||||
}
|
||||
|
||||
public void testAccessPrimitiveInt() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("java.lang.,ognl,javax"));
|
||||
|
||||
String propertyName = "intField";
|
||||
Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
|
||||
|
||||
// when
|
||||
boolean accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertTrue(accessible);
|
||||
}
|
||||
|
||||
public void testAccessPrimitiveDoubleWithNames() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("ognl.,javax."));
|
||||
|
||||
|
||||
Set<Class<?>> excluded = new HashSet<>();
|
||||
excluded.add(Object.class);
|
||||
excluded.add(Runtime.class);
|
||||
excluded.add(System.class);
|
||||
excluded.add(Class.class);
|
||||
excluded.add(ClassLoader.class);
|
||||
sma.setExcludedClasses(excluded);
|
||||
|
||||
String propertyName = "doubleValue";
|
||||
Member member = Double.class.getMethod(propertyName);
|
||||
|
||||
// when
|
||||
boolean accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertTrue(accessible);
|
||||
|
||||
// given
|
||||
propertyName = "exit";
|
||||
member = System.class.getMethod(propertyName, int.class);
|
||||
|
||||
// when
|
||||
accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertFalse(accessible);
|
||||
|
||||
// given
|
||||
propertyName = "intField";
|
||||
member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
|
||||
|
||||
// when
|
||||
accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
// then
|
||||
assertTrue(accessible);
|
||||
|
||||
// given
|
||||
propertyName = "doubleField";
|
||||
member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
|
||||
|
||||
// when
|
||||
accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
// then
|
||||
assertTrue(accessible);
|
||||
}
|
||||
|
||||
public void testAccessPrimitiveDoubleWithPackageRegExs() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
Set<Pattern> patterns = new HashSet<>();
|
||||
patterns.add(Pattern.compile("^java\\.lang\\..*"));
|
||||
sma.setExcludedPackageNamePatterns(patterns);
|
||||
|
||||
String propertyName = "doubleValue";
|
||||
Member member = Double.class.getMethod(propertyName);
|
||||
|
||||
// when
|
||||
boolean accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertTrue(accessible);
|
||||
}
|
||||
|
||||
public void testAccessMemberAccessIsAccessible() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
Set<Class<?>> excluded = new HashSet<>();
|
||||
excluded.add(ognl.MemberAccess.class);
|
||||
sma.setExcludedClasses(excluded);
|
||||
|
||||
String propertyName = "excludedClasses";
|
||||
String setter = "setExcludedClasses";
|
||||
Member member = SecurityMemberAccess.class.getMethod(setter, Set.class);
|
||||
|
||||
// when
|
||||
boolean accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertTrue(accessible);
|
||||
}
|
||||
|
||||
public void testAccessMemberAccessIsBlocked() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
Set<Class<?>> excluded = new HashSet<>();
|
||||
excluded.add(SecurityMemberAccess.class);
|
||||
sma.setExcludedClasses(excluded);
|
||||
|
||||
String propertyName = "excludedClasses";
|
||||
String setter = "setExcludedClasses";
|
||||
Member member = SecurityMemberAccess.class.getMethod(setter, Set.class);
|
||||
|
||||
// when
|
||||
boolean accessible = sma.isAccessible(context, target, member, propertyName);
|
||||
|
||||
// then
|
||||
assertFalse(accessible);
|
||||
}
|
||||
|
||||
public void testPackageNameExclusionAsCommaDelimited() {
|
||||
// given
|
||||
TestSecurityMemberAccess sma = new TestSecurityMemberAccess(true);
|
||||
|
||||
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("java.lang."));
|
||||
|
||||
// when
|
||||
boolean actual = sma.isPackageExcluded(String.class.getPackage(), null);
|
||||
actual &= sma.isPackageExcluded(null, String.class.getPackage());
|
||||
|
||||
// then
|
||||
assertTrue("package java.lang. is accessible!", actual);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FooBar implements FooBarInterface {
|
||||
|
||||
private String stringField;
|
||||
|
||||
private int intField;
|
||||
|
||||
private Double doubleField;
|
||||
|
||||
public String getStringField() {
|
||||
return stringField;
|
||||
}
|
||||
|
||||
public void setStringField(String stringField) {
|
||||
this.stringField = stringField;
|
||||
}
|
||||
|
||||
public String fooLogic() {
|
||||
return "fooLogic";
|
||||
}
|
||||
|
||||
public String barLogic() {
|
||||
return "barLogic";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int getIntField() {
|
||||
return intField;
|
||||
}
|
||||
|
||||
public void setIntField(int intField) {
|
||||
this.intField = intField;
|
||||
}
|
||||
|
||||
public Double getDoubleField() {
|
||||
return doubleField;
|
||||
}
|
||||
|
||||
public void setDoubleField(Double doubleField) {
|
||||
this.doubleField = doubleField;
|
||||
}
|
||||
}
|
||||
|
||||
interface FooInterface {
|
||||
|
||||
String fooLogic();
|
||||
|
||||
}
|
||||
|
||||
interface BarInterface {
|
||||
|
||||
String barLogic();
|
||||
|
||||
}
|
||||
|
||||
interface FooBarInterface extends FooInterface, BarInterface {
|
||||
|
||||
}
|
||||
|
||||
enum MyValues {
|
||||
ONE, TWO, THREE
|
||||
}
|
||||
|
||||
class StaticTester {
|
||||
|
||||
public static int MAX_VALUE = 0;
|
||||
public static final int MIN_VALUE = 0;
|
||||
static String PACKAGE_STRING = "package_string";
|
||||
static final String FINAL_PACKAGE_STRING = "final_package_string";
|
||||
static String PROTECTED_STRING = "protected_string";
|
||||
static final String FINAL_PROTECTED_STRING = "final_protected_string";
|
||||
static String PRIVATE_STRING = "private_string";
|
||||
static final String FINAL_PRIVATE_STRING = "final_private_string";
|
||||
|
||||
public static String sayHello() {
|
||||
return "Hello";
|
||||
}
|
||||
|
||||
protected static Field getFieldByName(String fieldName) throws NoSuchFieldException {
|
||||
if (fieldName != null && fieldName.length() > 0) {
|
||||
return StaticTester.class.getDeclaredField(fieldName);
|
||||
} else {
|
||||
throw new NoSuchFieldException("field: " + fieldName + " does not exist");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 com.test;
|
||||
|
||||
import com.opensymphony.xwork2.ognl.SecurityMemberAccess;
|
||||
|
||||
class TestSecurityMemberAccess extends SecurityMemberAccess {
|
||||
|
||||
TestSecurityMemberAccess(boolean allowStaticFieldAccess) {
|
||||
super(allowStaticFieldAccess);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPackageExcluded(Package targetPackage, Package memberPackage) {
|
||||
return super.isPackageExcluded(targetPackage, memberPackage);
|
||||
}
|
||||
}
|
||||
@@ -27,11 +27,12 @@ import com.opensymphony.xwork2.validator.annotations.Validations;
|
||||
import com.opensymphony.xwork2.validator.annotations.ValidatorType;
|
||||
import org.apache.struts2.views.jsp.ui.User;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public class TestAction extends ActionSupport {
|
||||
|
||||
private static final long serialVersionUID = -8891365561914451494L;
|
||||
@@ -50,22 +51,22 @@ public class TestAction extends ActionSupport {
|
||||
private SomeEnum status = SomeEnum.COMPLETED;
|
||||
private Float floatNumber;
|
||||
private Long id;
|
||||
private List<SomeEnum> enumList;
|
||||
private List<Integer> intList;
|
||||
|
||||
private final Map<String, String> texts = new HashMap<String, String>();
|
||||
private final Map<String, String> texts = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Define a text resource within this action that will be returned by the getText methods
|
||||
* here before delegating to the default TextProvider
|
||||
*
|
||||
* call
|
||||
* @param key
|
||||
* @param value
|
||||
* here before delegating to the default TextProvider call
|
||||
*/
|
||||
public void setText(String key, String value) {
|
||||
this.texts.put(key, value);
|
||||
}
|
||||
|
||||
/** Returns the test value if defined otherwise delegates to the default TextProvider */
|
||||
/**
|
||||
* Returns the test value if defined otherwise delegates to the default TextProvider
|
||||
*/
|
||||
public String getText(String key) {
|
||||
if (this.texts.containsKey(key)) {
|
||||
return this.texts.get(key);
|
||||
@@ -73,8 +74,10 @@ public class TestAction extends ActionSupport {
|
||||
return super.getText(key);
|
||||
}
|
||||
|
||||
/** This is the method invoked by the {@link org.apache.struts2.util.TextProviderHelper}.
|
||||
* Returns the test value if defined otherwise delegates to the default TextProvider */
|
||||
/**
|
||||
* This is the method invoked by the {@link org.apache.struts2.util.TextProviderHelper}.
|
||||
* Returns the test value if defined otherwise delegates to the default TextProvider
|
||||
*/
|
||||
public String getText(String key, String defaultValue, List<?> args, ValueStack stack) {
|
||||
if (this.texts.containsKey(key)) {
|
||||
return this.texts.get(key);
|
||||
@@ -180,20 +183,21 @@ public class TestAction extends ActionSupport {
|
||||
}
|
||||
|
||||
@Validations(
|
||||
requiredFields = {
|
||||
@RequiredFieldValidator(type = ValidatorType.SIMPLE, fieldName = "status", message = "You must enter a value for field.")
|
||||
},
|
||||
requiredStrings = {
|
||||
@RequiredStringValidator(type = ValidatorType.SIMPLE, fieldName = "result", message = "You must enter a value for field.")
|
||||
}
|
||||
requiredFields = {
|
||||
@RequiredFieldValidator(type = ValidatorType.SIMPLE, fieldName = "status", message = "You must enter a value for field.")
|
||||
},
|
||||
requiredStrings = {
|
||||
@RequiredStringValidator(type = ValidatorType.SIMPLE, fieldName = "result", message = "You must enter a value for field.")
|
||||
}
|
||||
)
|
||||
public String annotatedExecute1() throws Exception {
|
||||
return Action.SUCCESS;
|
||||
}
|
||||
|
||||
@Validations(
|
||||
requiredFields = {
|
||||
@RequiredFieldValidator(type = ValidatorType.SIMPLE, fieldName = "status", message = "You must enter a value for field.")
|
||||
}
|
||||
requiredFields = {
|
||||
@RequiredFieldValidator(type = ValidatorType.SIMPLE, fieldName = "status", message = "You must enter a value for field.")
|
||||
}
|
||||
)
|
||||
public String annotatedExecute2() throws Exception {
|
||||
return Action.SUCCESS;
|
||||
@@ -207,16 +211,16 @@ public class TestAction extends ActionSupport {
|
||||
return INPUT;
|
||||
}
|
||||
|
||||
public SomeEnum getStatus() {
|
||||
return status;
|
||||
}
|
||||
public SomeEnum getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(SomeEnum status) {
|
||||
this.status = status;
|
||||
}
|
||||
public void setStatus(SomeEnum status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public List<SomeEnum> getStatusList() {
|
||||
return Arrays.asList(SomeEnum.values());
|
||||
return Arrays.asList(SomeEnum.values());
|
||||
}
|
||||
|
||||
public Float getFloatNumber() {
|
||||
@@ -235,4 +239,19 @@ public class TestAction extends ActionSupport {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<SomeEnum> getEnumList() {
|
||||
return enumList;
|
||||
}
|
||||
|
||||
public void setEnumList(List<SomeEnum> enumList) {
|
||||
this.enumList = enumList;
|
||||
}
|
||||
|
||||
public List<Integer> getIntList() {
|
||||
return intList;
|
||||
}
|
||||
|
||||
public void setIntList(List<Integer> intList) {
|
||||
this.intList = intList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,28 @@ public class DateTest extends StrutsInternalTestCase {
|
||||
assertEquals(expected, writer.toString());
|
||||
}
|
||||
|
||||
public void testJavaSqlDate() {
|
||||
// given
|
||||
Date date = new Date(stack);
|
||||
date.setDateFormatter(new SimpleDateFormatAdapter());
|
||||
|
||||
java.sql.Date now = new java.sql.Date(System.currentTimeMillis());
|
||||
|
||||
String expected = SimpleDateFormat.getDateInstance(DateFormat.MEDIUM, ActionContext.getContext().getLocale()).format(now);
|
||||
context.put("myDate", now);
|
||||
|
||||
Writer writer = new StringWriter();
|
||||
|
||||
// when
|
||||
date.setName("myDate");
|
||||
date.setNice(false);
|
||||
date.start(writer);
|
||||
date.end(writer, "");
|
||||
|
||||
// then
|
||||
assertEquals(expected, writer.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
@@ -21,6 +21,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.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.StubValueStack;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
@@ -30,7 +31,6 @@ import com.opensymphony.xwork2.config.entities.InterceptorStackConfig;
|
||||
import com.opensymphony.xwork2.config.entities.PackageConfig;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.mock.MockActionInvocation;
|
||||
import com.opensymphony.xwork2.mock.MockActionProxy;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
@@ -54,24 +54,23 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* Test case for Dispatcher.
|
||||
*
|
||||
*/
|
||||
public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
public void testDefaultResurceBundlePropertyLoaded() throws Exception {
|
||||
public void testDefaultResourceBundlePropertyLoaded() {
|
||||
LocalizedTextProvider localizedTextProvider = container.getInstance(LocalizedTextProvider.class);
|
||||
|
||||
// some i18n messages from xwork-messages.properties
|
||||
assertEquals(localizedTextProvider.findDefaultText("xwork.error.action.execution", Locale.US),
|
||||
"Error during Action invocation");
|
||||
"Error during Action invocation");
|
||||
|
||||
// some i18n messages from struts-messages.properties
|
||||
assertEquals(localizedTextProvider.findDefaultText("struts.messages.error.uploading", Locale.US,
|
||||
new Object[] { "some error messages" }),
|
||||
"Error uploading: some error messages");
|
||||
new Object[]{"some error messages"}),
|
||||
"Error uploading: some error messages");
|
||||
}
|
||||
|
||||
public void testPrepareSetEncodingProperly() throws Exception {
|
||||
public void testPrepareSetEncodingProperly() {
|
||||
HttpServletRequest req = new MockHttpServletRequest();
|
||||
HttpServletResponse res = new MockHttpServletResponse();
|
||||
|
||||
@@ -84,7 +83,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
assertEquals(res.getCharacterEncoding(), "utf-8");
|
||||
}
|
||||
|
||||
public void testEncodingForXMLHttpRequest() throws Exception {
|
||||
public void testEncodingForXMLHttpRequest() {
|
||||
// given
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
req.addHeader("X-Requested-With", "XMLHttpRequest");
|
||||
@@ -103,7 +102,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
assertEquals(res.getCharacterEncoding(), "UTF-8");
|
||||
}
|
||||
|
||||
public void testSetEncodingIfDiffer() throws Exception {
|
||||
public void testSetEncodingIfDiffer() {
|
||||
// given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
mock.expectAndReturn("getCharacterEncoding", "utf-8");
|
||||
@@ -127,7 +126,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testPrepareSetEncodingPropertyWithMultipartRequest() throws Exception {
|
||||
public void testPrepareSetEncodingPropertyWithMultipartRequest() {
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||
|
||||
@@ -147,7 +146,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
req.setMethod("post");
|
||||
req.setContentType("multipart/form-data; boundary=asdcvb345asd");
|
||||
Dispatcher du = initDispatcher(Collections.<String, String>emptyMap());
|
||||
Dispatcher du = initDispatcher(Collections.emptyMap());
|
||||
du.prepare(req, res);
|
||||
HttpServletRequest wrapped = du.wrapRequest(req);
|
||||
|
||||
@@ -160,7 +159,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
req.setMethod("post");
|
||||
req.setContentType("multipart/form-data; boundary=01=23a.bC:D((e)d'z?p+o_r,e-");
|
||||
Dispatcher du = initDispatcher(Collections.<String, String>emptyMap());
|
||||
Dispatcher du = initDispatcher(Collections.emptyMap());
|
||||
du.prepare(req, res);
|
||||
HttpServletRequest wrapped = du.wrapRequest(req);
|
||||
|
||||
@@ -173,46 +172,46 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
req.setMethod("post");
|
||||
req.setContentType("multipart/form-data; boundary=01=2;3a.bC:D((e)d'z?p+o_r,e-");
|
||||
Dispatcher du = initDispatcher(Collections.<String, String>emptyMap());
|
||||
Dispatcher du = initDispatcher(Collections.emptyMap());
|
||||
du.prepare(req, res);
|
||||
HttpServletRequest wrapped = du.wrapRequest(req);
|
||||
|
||||
assertFalse(wrapped instanceof MultiPartRequestWrapper);
|
||||
}
|
||||
|
||||
public void testDispatcherListener() throws Exception {
|
||||
public void testDispatcherListener() {
|
||||
|
||||
final DispatcherListenerState state = new DispatcherListenerState();
|
||||
final DispatcherListenerState state = new DispatcherListenerState();
|
||||
|
||||
Dispatcher.addDispatcherListener(new DispatcherListener() {
|
||||
public void dispatcherDestroyed(Dispatcher du) {
|
||||
state.isDestroyed = true;
|
||||
}
|
||||
public void dispatcherInitialized(Dispatcher du) {
|
||||
state.isInitialized = true;
|
||||
}
|
||||
});
|
||||
Dispatcher.addDispatcherListener(new DispatcherListener() {
|
||||
public void dispatcherDestroyed(Dispatcher du) {
|
||||
state.isDestroyed = true;
|
||||
}
|
||||
|
||||
public void dispatcherInitialized(Dispatcher du) {
|
||||
state.isInitialized = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
assertFalse(state.isDestroyed);
|
||||
assertFalse(state.isInitialized);
|
||||
assertFalse(state.isDestroyed);
|
||||
assertFalse(state.isInitialized);
|
||||
|
||||
Dispatcher du = initDispatcher(new HashMap<String, String>() );
|
||||
Dispatcher du = initDispatcher(new HashMap<>());
|
||||
|
||||
assertTrue(state.isInitialized);
|
||||
assertTrue(state.isInitialized);
|
||||
|
||||
du.cleanup();
|
||||
du.cleanup();
|
||||
|
||||
assertTrue(state.isDestroyed);
|
||||
assertTrue(state.isDestroyed);
|
||||
}
|
||||
|
||||
|
||||
public void testConfigurationManager() {
|
||||
Dispatcher du;
|
||||
final InternalConfigurationManager configurationManager = new InternalConfigurationManager(Container.DEFAULT_NAME);
|
||||
try {
|
||||
du = new MockDispatcher(new MockServletContext(), new HashMap<String, String>(), configurationManager);
|
||||
du.init();
|
||||
Dispatcher du;
|
||||
final InternalConfigurationManager configurationManager = new InternalConfigurationManager(Container.DEFAULT_NAME);
|
||||
try {
|
||||
du = new MockDispatcher(new MockServletContext(), new HashMap<>(), configurationManager);
|
||||
du.init();
|
||||
Dispatcher.setInstance(du);
|
||||
|
||||
assertFalse(configurationManager.destroyConfiguration);
|
||||
@@ -221,18 +220,17 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
assertTrue(configurationManager.destroyConfiguration);
|
||||
|
||||
}
|
||||
finally {
|
||||
Dispatcher.setInstance(null);
|
||||
}
|
||||
} finally {
|
||||
Dispatcher.setInstance(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInitLoadsDefaultConfig() {
|
||||
Dispatcher du = new Dispatcher(new MockServletContext(), new HashMap<String, String>());
|
||||
Dispatcher du = new Dispatcher(new MockServletContext(), new HashMap<>());
|
||||
du.init();
|
||||
Configuration config = du.getConfigurationManager().getConfiguration();
|
||||
assertNotNull(config);
|
||||
HashSet<String> expected = new HashSet<String>();
|
||||
HashSet<String> expected = new HashSet<>();
|
||||
expected.add("struts-default.xml");
|
||||
expected.add("struts-plugin.xml");
|
||||
expected.add("struts.xml");
|
||||
@@ -243,17 +241,17 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
assertTrue(packageConfig.getResultTypeConfigs().size() > 0);
|
||||
}
|
||||
|
||||
public void testObjectFactoryDestroy() throws Exception {
|
||||
public void testObjectFactoryDestroy() {
|
||||
|
||||
ConfigurationManager cm = new ConfigurationManager(Container.DEFAULT_NAME);
|
||||
Dispatcher du = new MockDispatcher(new MockServletContext(), new HashMap<String, String>(), cm);
|
||||
Dispatcher du = new MockDispatcher(new MockServletContext(), new HashMap<>(), cm);
|
||||
Mock mockConfiguration = new Mock(Configuration.class);
|
||||
cm.setConfiguration((Configuration)mockConfiguration.proxy());
|
||||
cm.setConfiguration((Configuration) mockConfiguration.proxy());
|
||||
|
||||
Mock mockContainer = new Mock(Container.class);
|
||||
String reloadConfigs = container.getInstance(String.class, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD);
|
||||
mockContainer.expectAndReturn("getInstance", C.args(C.eq(String.class), C.eq(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD)),
|
||||
reloadConfigs);
|
||||
reloadConfigs);
|
||||
final InnerDestroyableObjectFactory destroyedObjectFactory = new InnerDestroyableObjectFactory();
|
||||
destroyedObjectFactory.setContainer((Container) mockContainer.proxy());
|
||||
mockContainer.expectAndReturn("getInstance", C.args(C.eq(ObjectFactory.class)), destroyedObjectFactory);
|
||||
@@ -271,7 +269,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mockContainer.verify();
|
||||
}
|
||||
|
||||
public void testInterceptorDestroy() throws Exception {
|
||||
public void testInterceptorDestroy() {
|
||||
Mock mockInterceptor = new Mock(Interceptor.class);
|
||||
mockInterceptor.matchAndReturn("hashCode", 0);
|
||||
mockInterceptor.expect("destroy");
|
||||
@@ -282,14 +280,14 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
PackageConfig packageConfig = new PackageConfig.Builder("test").addInterceptorStackConfig(isc).build();
|
||||
|
||||
Map<String, PackageConfig> packageConfigs = new HashMap<String, PackageConfig>();
|
||||
Map<String, PackageConfig> packageConfigs = new HashMap<>();
|
||||
packageConfigs.put("test", packageConfig);
|
||||
|
||||
Mock mockContainer = new Mock(Container.class);
|
||||
mockContainer.matchAndReturn("getInstance", C.args(C.eq(ObjectFactory.class)), new ObjectFactory());
|
||||
String reloadConfigs = container.getInstance(String.class, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD);
|
||||
mockContainer.expectAndReturn("getInstance", C.args(C.eq(String.class), C.eq(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD)),
|
||||
reloadConfigs);
|
||||
reloadConfigs);
|
||||
|
||||
Mock mockConfiguration = new Mock(Configuration.class);
|
||||
mockConfiguration.matchAndReturn("getPackageConfigs", packageConfigs);
|
||||
@@ -299,7 +297,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
ConfigurationManager configurationManager = new ConfigurationManager(Container.DEFAULT_NAME);
|
||||
configurationManager.setConfiguration((Configuration) mockConfiguration.proxy());
|
||||
|
||||
Dispatcher dispatcher = new MockDispatcher(new MockServletContext(), new HashMap<String, String>(), configurationManager);
|
||||
Dispatcher dispatcher = new MockDispatcher(new MockServletContext(), new HashMap<>(), configurationManager);
|
||||
dispatcher.init();
|
||||
dispatcher.cleanup();
|
||||
|
||||
@@ -308,22 +306,22 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mockConfiguration.verify();
|
||||
}
|
||||
|
||||
public void testMultipartSupportEnabledByDefault() throws Exception {
|
||||
public void testMultipartSupportEnabledByDefault() {
|
||||
HttpServletRequest req = new MockHttpServletRequest();
|
||||
HttpServletResponse res = new MockHttpServletResponse();
|
||||
|
||||
Dispatcher du = initDispatcher(Collections.<String, String>emptyMap());
|
||||
Dispatcher du = initDispatcher(Collections.emptyMap());
|
||||
du.prepare(req, res);
|
||||
|
||||
assertTrue(du.isMultipartSupportEnabled(req));
|
||||
}
|
||||
|
||||
public void testIsMultipartRequest() throws Exception {
|
||||
public void testIsMultipartRequest() {
|
||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||
HttpServletResponse res = new MockHttpServletResponse();
|
||||
|
||||
req.setMethod("POST");
|
||||
Dispatcher du = initDispatcher(Collections.<String, String>emptyMap());
|
||||
Dispatcher du = initDispatcher(Collections.emptyMap());
|
||||
du.prepare(req, res);
|
||||
|
||||
req.setContentType("multipart/form-data");
|
||||
@@ -370,7 +368,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
public void testServiceActionResumePreviousProxy() throws Exception {
|
||||
Dispatcher du = initDispatcher(Collections.<String, String>emptyMap());
|
||||
Dispatcher du = initDispatcher(Collections.emptyMap());
|
||||
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
ActionContext.getContext().withActionInvocation(mai);
|
||||
@@ -393,14 +391,41 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
assertTrue("should execute previous proxy", actionProxy.isExecutedCalled());
|
||||
}
|
||||
|
||||
public void testServiceActionCreatesNewProxyIfDifferentMapping() throws Exception {
|
||||
Dispatcher du = initDispatcher(Collections.emptyMap());
|
||||
container.inject(du);
|
||||
|
||||
MockActionInvocation mai = new MockActionInvocation();
|
||||
ActionContext.getContext().withActionInvocation(mai);
|
||||
|
||||
MockActionProxy previousActionProxy = new MockActionProxy();
|
||||
previousActionProxy.setActionName("first-action");
|
||||
previousActionProxy.setNamespace("namespace1");
|
||||
previousActionProxy.setInvocation(mai);
|
||||
mai.setProxy(previousActionProxy);
|
||||
|
||||
mai.setStack(new StubValueStack());
|
||||
|
||||
HttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, mai.getStack());
|
||||
|
||||
HttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
assertFalse(previousActionProxy.isExecutedCalled());
|
||||
|
||||
ActionMapping newActionMapping = new ActionMapping();
|
||||
newActionMapping.setName("hello");
|
||||
du.serviceAction(request, response, newActionMapping);
|
||||
|
||||
assertFalse(previousActionProxy.isExecutedCalled());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>());
|
||||
public void testHandleException() {
|
||||
Dispatcher du = initDispatcher(new HashMap<>());
|
||||
assertTrue("Default Dispatcher handleException state not true ?", du.isHandleException());
|
||||
|
||||
Dispatcher du2 = initDispatcher(new HashMap<String, String>() {{
|
||||
@@ -412,11 +437,9 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
/**
|
||||
* 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>());
|
||||
public void testDevMode() {
|
||||
Dispatcher du = initDispatcher(new HashMap<>());
|
||||
assertFalse("Default Dispatcher devMode state not false ?", du.isDevMode());
|
||||
|
||||
Dispatcher du2 = initDispatcher(new HashMap<String, String>() {{
|
||||
@@ -425,7 +448,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
assertTrue("Modified Dispatcher devMode state not true ?", du2.isDevMode());
|
||||
}
|
||||
|
||||
public void testGetLocale_With_DefaultLocale_FromConfiguration() throws Exception {
|
||||
public void testGetLocale_With_DefaultLocale_FromConfiguration() {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
@@ -451,7 +474,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_DefaultLocale_fr_CA() throws Exception {
|
||||
public void testGetLocale_With_DefaultLocale_fr_CA() {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
@@ -477,7 +500,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_BadDefaultLocale_RequestLocale_en_UK() throws Exception {
|
||||
public void testGetLocale_With_BadDefaultLocale_RequestLocale_en_UK() {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
@@ -505,7 +528,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_BadDefaultLocale_And_RuntimeException() throws Exception {
|
||||
public void testGetLocale_With_BadDefaultLocale_And_RuntimeException() {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
@@ -533,7 +556,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_NullDefaultLocale() throws Exception {
|
||||
public void testGetLocale_With_NullDefaultLocale() {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
@@ -563,7 +586,7 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
mock.verify();
|
||||
}
|
||||
|
||||
public void testGetLocale_With_NullDefaultLocale_And_RuntimeException() throws Exception {
|
||||
public void testGetLocale_With_NullDefaultLocale_And_RuntimeException() {
|
||||
// Given
|
||||
Mock mock = new Mock(HttpServletRequest.class);
|
||||
MockHttpSession mockHttpSession = new MockHttpSession();
|
||||
@@ -595,19 +618,14 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
|
||||
/**
|
||||
* Create a test context Map from a Dispatcher instance.
|
||||
*
|
||||
* <p>
|
||||
* The method directly calls getParameterMap() and getSession(true) on the HttpServletRequest.
|
||||
*
|
||||
* <p>
|
||||
* 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) {
|
||||
HttpServletRequest request, HttpServletResponse response) {
|
||||
if (dispatcher == null) {
|
||||
throw new IllegalArgumentException("Cannot create a test ContextMap from a null Dispatcher");
|
||||
}
|
||||
@@ -619,31 +637,31 @@ public class DispatcherTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
return dispatcher.createContextMap(new RequestMap(request),
|
||||
HttpParameters.create(request.getParameterMap()).build(),
|
||||
new SessionMap(request),
|
||||
new ApplicationMap(request.getSession(true).getServletContext()),
|
||||
request,
|
||||
response);
|
||||
HttpParameters.create(request.getParameterMap()).build(),
|
||||
new SessionMap(request),
|
||||
new ApplicationMap(request.getSession(true).getServletContext()),
|
||||
request,
|
||||
response);
|
||||
}
|
||||
|
||||
class InternalConfigurationManager extends ConfigurationManager {
|
||||
public boolean destroyConfiguration = false;
|
||||
static class InternalConfigurationManager extends ConfigurationManager {
|
||||
public boolean destroyConfiguration = false;
|
||||
|
||||
public InternalConfigurationManager(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void destroyConfiguration() {
|
||||
super.destroyConfiguration();
|
||||
destroyConfiguration = true;
|
||||
}
|
||||
public synchronized void destroyConfiguration() {
|
||||
super.destroyConfiguration();
|
||||
destroyConfiguration = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DispatcherListenerState {
|
||||
public boolean isInitialized = false;
|
||||
public boolean isDestroyed = false;
|
||||
static class DispatcherListenerState {
|
||||
public boolean isInitialized = false;
|
||||
public boolean isDestroyed = false;
|
||||
}
|
||||
|
||||
public static class InnerDestroyableObjectFactory extends ObjectFactory implements ObjectFactoryDestroyable {
|
||||
|
||||
@@ -18,25 +18,26 @@
|
||||
*/
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.DefaultExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.mock.MockActionInvocation;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
import static org.easymock.EasyMock.*;
|
||||
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import com.opensymphony.xwork2.mock.MockActionInvocation;
|
||||
import com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.DefaultExcludedPatternsChecker;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.EasyMock.replay;
|
||||
import static org.easymock.EasyMock.verify;
|
||||
|
||||
public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
|
||||
@@ -44,9 +45,9 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
public void testIntercepDefault() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setCookies(
|
||||
new Cookie("cookie1", "cookie1value"),
|
||||
new Cookie("cookie2", "cookie2value"),
|
||||
new Cookie("cookie3", "cookie3value")
|
||||
new Cookie("cookie1", "cookie1value"),
|
||||
new Cookie("cookie2", "cookie2value"),
|
||||
new Cookie("cookie3", "cookie3value")
|
||||
);
|
||||
ServletActionContext.setRequest(request);
|
||||
|
||||
@@ -55,7 +56,7 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
ActionContext.getContext().getValueStack().push(action);
|
||||
|
||||
ActionInvocation invocation = (ActionInvocation) createMock(ActionInvocation.class);
|
||||
|
||||
|
||||
expect(invocation.getAction()).andReturn(action);
|
||||
expect(invocation.invoke()).andReturn(Action.SUCCESS);
|
||||
|
||||
@@ -75,16 +76,16 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
assertNull(ActionContext.getContext().getValueStack().findValue("cookie1"));
|
||||
assertNull(ActionContext.getContext().getValueStack().findValue("cookie2"));
|
||||
assertNull(ActionContext.getContext().getValueStack().findValue("cookie3"));
|
||||
|
||||
|
||||
verify(invocation);
|
||||
}
|
||||
|
||||
public void testInterceptAll1() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setCookies(
|
||||
new Cookie("cookie1", "cookie1value"),
|
||||
new Cookie("cookie2", "cookie2value"),
|
||||
new Cookie("cookie3", "cookie3value")
|
||||
new Cookie("cookie1", "cookie1value"),
|
||||
new Cookie("cookie2", "cookie2value"),
|
||||
new Cookie("cookie3", "cookie3value")
|
||||
);
|
||||
ServletActionContext.setRequest(request);
|
||||
|
||||
@@ -93,7 +94,7 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
ActionContext.getContext().getValueStack().push(action);
|
||||
|
||||
ActionInvocation invocation = (ActionInvocation) createMock(ActionInvocation.class);
|
||||
|
||||
|
||||
expect(invocation.getAction()).andReturn(action);
|
||||
expect(invocation.invoke()).andReturn(Action.SUCCESS);
|
||||
|
||||
@@ -117,7 +118,7 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie1"), "cookie1value");
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie2"), "cookie2value");
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie3"), "cookie3value");
|
||||
|
||||
|
||||
verify(invocation);
|
||||
}
|
||||
|
||||
@@ -125,9 +126,9 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
public void testInterceptAll2() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setCookies(
|
||||
new Cookie("cookie1", "cookie1value"),
|
||||
new Cookie("cookie2", "cookie2value"),
|
||||
new Cookie("cookie3", "cookie3value")
|
||||
new Cookie("cookie1", "cookie1value"),
|
||||
new Cookie("cookie2", "cookie2value"),
|
||||
new Cookie("cookie3", "cookie3value")
|
||||
);
|
||||
ServletActionContext.setRequest(request);
|
||||
|
||||
@@ -159,16 +160,16 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie1"), "cookie1value");
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie2"), "cookie2value");
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie3"), "cookie3value");
|
||||
|
||||
|
||||
verify(invocation);
|
||||
}
|
||||
|
||||
public void testInterceptSelectedCookiesNameOnly1() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setCookies(
|
||||
new Cookie("cookie1", "cookie1value"),
|
||||
new Cookie("cookie2", "cookie2value"),
|
||||
new Cookie("cookie3", "cookie3value")
|
||||
new Cookie("cookie1", "cookie1value"),
|
||||
new Cookie("cookie2", "cookie2value"),
|
||||
new Cookie("cookie3", "cookie3value")
|
||||
);
|
||||
ServletActionContext.setRequest(request);
|
||||
|
||||
@@ -200,16 +201,16 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie1"), "cookie1value");
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie2"), null);
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie3"), "cookie3value");
|
||||
|
||||
|
||||
verify(invocation);
|
||||
}
|
||||
|
||||
public void testInterceptSelectedCookiesNameOnly2() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setCookies(
|
||||
new Cookie("cookie1", "cookie1value"),
|
||||
new Cookie("cookie2", "cookie2value"),
|
||||
new Cookie("cookie3", "cookie3value")
|
||||
new Cookie("cookie1", "cookie1value"),
|
||||
new Cookie("cookie2", "cookie2value"),
|
||||
new Cookie("cookie3", "cookie3value")
|
||||
);
|
||||
ServletActionContext.setRequest(request);
|
||||
|
||||
@@ -218,7 +219,7 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
ActionContext.getContext().getValueStack().push(action);
|
||||
|
||||
ActionInvocation invocation = (ActionInvocation) createMock(ActionInvocation.class);
|
||||
|
||||
|
||||
expect(invocation.getAction()).andReturn(action);
|
||||
expect(invocation.invoke()).andReturn(Action.SUCCESS);
|
||||
|
||||
@@ -242,16 +243,16 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie1"), "cookie1value");
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie2"), null);
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie3"), "cookie3value");
|
||||
|
||||
|
||||
verify(invocation);
|
||||
}
|
||||
|
||||
public void testInterceptSelectedCookiesNameOnly3() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setCookies(
|
||||
new Cookie("cookie1", "cookie1value"),
|
||||
new Cookie("cookie2", "cookie2value"),
|
||||
new Cookie("cookie3", "cookie3value")
|
||||
new Cookie("cookie1", "cookie1value"),
|
||||
new Cookie("cookie2", "cookie2value"),
|
||||
new Cookie("cookie3", "cookie3value")
|
||||
);
|
||||
ServletActionContext.setRequest(request);
|
||||
|
||||
@@ -283,7 +284,7 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie1"), "cookie1value");
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie2"), null);
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie3"), "cookie3value");
|
||||
|
||||
|
||||
verify(invocation);
|
||||
}
|
||||
|
||||
@@ -291,9 +292,9 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
public void testInterceptSelectedCookiesNameAndValue() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setCookies(
|
||||
new Cookie("cookie1", "cookie1value"),
|
||||
new Cookie("cookie2", "cookie2value"),
|
||||
new Cookie("cookie3", "cookie3value")
|
||||
new Cookie("cookie1", "cookie1value"),
|
||||
new Cookie("cookie2", "cookie2value"),
|
||||
new Cookie("cookie3", "cookie3value")
|
||||
);
|
||||
ServletActionContext.setRequest(request);
|
||||
|
||||
@@ -325,7 +326,7 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie1"), "cookie1value");
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie2"), null);
|
||||
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie3"), null);
|
||||
|
||||
|
||||
verify(invocation);
|
||||
}
|
||||
|
||||
@@ -338,20 +339,44 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
String pollution5 = "model[\"class\"]['classLoader']['jarPath']";
|
||||
String pollution6 = "class[\"classLoader\"]['jarPath']";
|
||||
|
||||
try {
|
||||
new Cookie(pollution1, "pollution1");
|
||||
fail("It shouldn't be possible to create cookie: " + pollution1);
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals(e.getMessage(), "Cookie name \"" + pollution1 + "\" is a reserved token");
|
||||
}
|
||||
|
||||
try {
|
||||
new Cookie(pollution4, "pollution4");
|
||||
fail("It shouldn't be possible to create cookie: " + pollution4);
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals(e.getMessage(), "Cookie name \"" + pollution4 + "\" is a reserved token");
|
||||
}
|
||||
|
||||
try {
|
||||
new Cookie(pollution5, "pollution5");
|
||||
fail("It shouldn't be possible to create cookie: " + pollution5);
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals(e.getMessage(), "Cookie name \"" + pollution5 + "\" is a reserved token");
|
||||
}
|
||||
|
||||
try {
|
||||
new Cookie(pollution6, "pollution6");
|
||||
fail("It shouldn't be possible to create cookie: " + pollution6);
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals(e.getMessage(), "Cookie name \"" + pollution6 + "\" is a reserved token");
|
||||
}
|
||||
|
||||
request.setCookies(
|
||||
new Cookie(pollution1, "pollution1"),
|
||||
new Cookie("pollution1", pollution1),
|
||||
new Cookie(pollution2, "pollution2"),
|
||||
new Cookie("pollution2", pollution2),
|
||||
new Cookie(pollution3, "pollution3"),
|
||||
new Cookie("pollution3", pollution3),
|
||||
new Cookie(pollution4, "pollution4"),
|
||||
new Cookie("pollution4", pollution4),
|
||||
new Cookie(pollution5, "pollution5"),
|
||||
new Cookie("pollution5", pollution5),
|
||||
new Cookie(pollution6, "pollution6"),
|
||||
new Cookie("pollution6", pollution6)
|
||||
);
|
||||
new Cookie("pollution1", pollution1),
|
||||
new Cookie(pollution2, "pollution2"),
|
||||
new Cookie("pollution2", pollution2),
|
||||
new Cookie(pollution3, "pollution3"),
|
||||
new Cookie("pollution3", pollution3),
|
||||
new Cookie("pollution4", pollution4),
|
||||
new Cookie("pollution5", pollution5),
|
||||
new Cookie("pollution6", pollution6)
|
||||
);
|
||||
ServletActionContext.setRequest(request);
|
||||
|
||||
final Map<String, Boolean> excludedName = new HashMap<String, Boolean>();
|
||||
@@ -375,12 +400,12 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
|
||||
interceptor.intercept(invocation);
|
||||
|
||||
assertFalse(excludedName.get(pollution1));
|
||||
//assertFalse(excludedName.get(pollution1));
|
||||
assertFalse(excludedName.get(pollution2));
|
||||
assertFalse(excludedName.get(pollution3));
|
||||
assertFalse(excludedName.get(pollution4));
|
||||
assertFalse(excludedName.get(pollution5));
|
||||
assertFalse(excludedName.get(pollution6));
|
||||
//assertFalse(excludedName.get(pollution4));
|
||||
//assertFalse(excludedName.get(pollution5));
|
||||
// assertFalse(excludedName.get(pollution6));
|
||||
}
|
||||
|
||||
public void testCookiesWithStrutsInternalsAccess() throws Exception {
|
||||
@@ -393,13 +418,13 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
String reqCookieValue = "request.userId=1";
|
||||
|
||||
request.setCookies(
|
||||
new Cookie(sessionCookieName, "1"),
|
||||
new Cookie("1", sessionCookieValue),
|
||||
new Cookie(appCookieName, "1"),
|
||||
new Cookie("1", appCookieValue),
|
||||
new Cookie(reqCookieName, "1"),
|
||||
new Cookie("1", reqCookieValue)
|
||||
);
|
||||
new Cookie(sessionCookieName, "1"),
|
||||
new Cookie("1", sessionCookieValue),
|
||||
new Cookie(appCookieName, "1"),
|
||||
new Cookie("1", appCookieValue),
|
||||
new Cookie(reqCookieName, "1"),
|
||||
new Cookie("1", reqCookieValue)
|
||||
);
|
||||
ServletActionContext.setRequest(request);
|
||||
|
||||
final Map<String, Boolean> excludedName = new HashMap<String, Boolean>();
|
||||
@@ -436,13 +461,13 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
String reqCookieValue = "request.userId=1";
|
||||
|
||||
request.setCookies(
|
||||
new Cookie(sessionCookieName, "1"),
|
||||
new Cookie("1", sessionCookieValue),
|
||||
new Cookie(appCookieName, "1"),
|
||||
new Cookie("1", appCookieValue),
|
||||
new Cookie(reqCookieName, "1"),
|
||||
new Cookie("1", reqCookieValue)
|
||||
);
|
||||
new Cookie(sessionCookieName, "1"),
|
||||
new Cookie("1", sessionCookieValue),
|
||||
new Cookie(appCookieName, "1"),
|
||||
new Cookie("1", appCookieValue),
|
||||
new Cookie(reqCookieName, "1"),
|
||||
new Cookie("1", reqCookieValue)
|
||||
);
|
||||
ServletActionContext.setRequest(request);
|
||||
|
||||
final Map<String, Boolean> excludedName = new HashMap<>();
|
||||
@@ -486,14 +511,29 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
return this.cookies;
|
||||
}
|
||||
|
||||
public String getCookie1() { return cookie1; }
|
||||
public void setCookie1(String cookie1) { this.cookie1 = cookie1; }
|
||||
public String getCookie1() {
|
||||
return cookie1;
|
||||
}
|
||||
|
||||
public String getCookie2() { return cookie2; }
|
||||
public void setCookie2(String cookie2) { this.cookie2 = cookie2; }
|
||||
public void setCookie1(String cookie1) {
|
||||
this.cookie1 = cookie1;
|
||||
}
|
||||
|
||||
public String getCookie3() { return cookie3; }
|
||||
public void setCookie3(String cookie3) { this.cookie3 = cookie3; }
|
||||
public String getCookie2() {
|
||||
return cookie2;
|
||||
}
|
||||
|
||||
public void setCookie2(String cookie2) {
|
||||
this.cookie2 = cookie2;
|
||||
}
|
||||
|
||||
public String getCookie3() {
|
||||
return cookie3;
|
||||
}
|
||||
|
||||
public void setCookie3(String cookie3) {
|
||||
this.cookie3 = cookie3;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MockActionWithActionCookieAware extends ActionSupport implements org.apache.struts2.action.CookiesAware {
|
||||
@@ -511,14 +551,29 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
|
||||
return this.cookies;
|
||||
}
|
||||
|
||||
public String getCookie1() { return cookie1; }
|
||||
public void setCookie1(String cookie1) { this.cookie1 = cookie1; }
|
||||
public String getCookie1() {
|
||||
return cookie1;
|
||||
}
|
||||
|
||||
public String getCookie2() { return cookie2; }
|
||||
public void setCookie2(String cookie2) { this.cookie2 = cookie2; }
|
||||
public void setCookie1(String cookie1) {
|
||||
this.cookie1 = cookie1;
|
||||
}
|
||||
|
||||
public String getCookie3() { return cookie3; }
|
||||
public void setCookie3(String cookie3) { this.cookie3 = cookie3; }
|
||||
public String getCookie2() {
|
||||
return cookie2;
|
||||
}
|
||||
|
||||
public void setCookie2(String cookie2) {
|
||||
this.cookie2 = cookie2;
|
||||
}
|
||||
|
||||
public String getCookie3() {
|
||||
return cookie3;
|
||||
}
|
||||
|
||||
public void setCookie3(String cookie3) {
|
||||
this.cookie3 = cookie3;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public class PlainResultTest extends StrutsInternalTestCase {
|
||||
result.execute(invocation);
|
||||
|
||||
assertEquals("{ 'value': 'test' }", response.getContentAsString());
|
||||
assertEquals("application/json", response.getContentType());
|
||||
assertEquals("application/json;charset=UTF-8", response.getContentType());
|
||||
}
|
||||
|
||||
public void testWriteContentTypeCsvWithCookie() throws Exception {
|
||||
@@ -72,7 +72,7 @@ public class PlainResultTest extends StrutsInternalTestCase {
|
||||
result.execute(invocation);
|
||||
|
||||
assertEquals("name;value\nline;1\nline;2", response.getContentAsString());
|
||||
assertEquals("text/csv", response.getContentType());
|
||||
assertEquals("text/csv;charset=UTF-8", response.getContentType());
|
||||
}
|
||||
|
||||
public void testHeaders() throws Exception {
|
||||
@@ -146,4 +146,4 @@ public class PlainResultTest extends StrutsInternalTestCase {
|
||||
|
||||
ActionContext.getContext().withServletResponse(response).withActionInvocation(invocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class SecurityMemberAccessInServletsTest extends StrutsInternalTestCase {
|
||||
|
||||
public void testJavaxServletPackageAccess() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
Set<Pattern> excluded = new HashSet<Pattern>();
|
||||
excluded.add(Pattern.compile("^(?!javax\\.servlet\\..+)(javax\\..+)"));
|
||||
@@ -59,7 +59,7 @@ public class SecurityMemberAccessInServletsTest extends StrutsInternalTestCase {
|
||||
|
||||
public void testJavaxServletPackageExclusion() throws Exception {
|
||||
// given
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
|
||||
SecurityMemberAccess sma = new SecurityMemberAccess(true);
|
||||
|
||||
Set<Pattern> excluded = new HashSet<Pattern>();
|
||||
excluded.add(Pattern.compile("^javax\\..+"));
|
||||
|
||||
@@ -18,36 +18,31 @@
|
||||
*/
|
||||
package org.apache.struts2.views.jsp;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.jsp.JspWriter;
|
||||
|
||||
import com.mockobjects.dynamic.Mock;
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
import org.apache.struts2.TestAction;
|
||||
import org.apache.struts2.dispatcher.ApplicationMap;
|
||||
import org.apache.struts2.dispatcher.Dispatcher;
|
||||
import org.apache.struts2.dispatcher.MockDispatcher;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.MockDispatcher;
|
||||
import org.apache.struts2.dispatcher.RequestMap;
|
||||
import org.apache.struts2.dispatcher.SessionMap;
|
||||
|
||||
import com.mockobjects.dynamic.Mock;
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.jsp.JspWriter;
|
||||
import java.io.File;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base class to extend for unit testing UI Tags.
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractTagTest extends StrutsInternalTestCase {
|
||||
protected Action action;
|
||||
@@ -62,7 +57,7 @@ public abstract class AbstractTagTest extends StrutsInternalTestCase {
|
||||
protected StrutsMockHttpServletRequest request;
|
||||
protected StrutsMockPageContext pageContext;
|
||||
protected HttpServletResponse response;
|
||||
|
||||
|
||||
protected Mock mockContainer;
|
||||
|
||||
/**
|
||||
@@ -114,11 +109,11 @@ public abstract class AbstractTagTest extends StrutsInternalTestCase {
|
||||
Dispatcher.setInstance(du);
|
||||
session = new SessionMap<>(request);
|
||||
Map<String, Object> extraContext = du.createContextMap(new RequestMap(request),
|
||||
HttpParameters.create(request.getParameterMap()).build(),
|
||||
session,
|
||||
new ApplicationMap(pageContext.getServletContext()),
|
||||
request,
|
||||
response);
|
||||
HttpParameters.create(request.getParameterMap()).build(),
|
||||
session,
|
||||
new ApplicationMap(pageContext.getServletContext()),
|
||||
request,
|
||||
response);
|
||||
// let's not set the locale -- there is a test that checks if Dispatcher actually picks this up...
|
||||
// ... but generally we want to just use no locale (let it stay system default)
|
||||
extraContext = ActionContext.of(extraContext).withLocale(null).getContextMap();
|
||||
@@ -149,18 +144,18 @@ public abstract class AbstractTagTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare if two component tags are considered equal according to their fields as accessed
|
||||
* Compare if two component tags are considered equal according to their fields as accessed
|
||||
* via reflection.
|
||||
*
|
||||
* Utilizes {@link EqualsBuilder#reflectionEquals(java.lang.Object, java.lang.Object, boolean)} to perform
|
||||
* <p>
|
||||
* Utilizes {@link EqualsBuilder#reflectionEquals(java.lang.Object, java.lang.Object, boolean)} to perform
|
||||
* the check, and compares transient fields as well. This may fail when run while a security manager is
|
||||
* active, due to a need to user reflection.
|
||||
*
|
||||
* <p>
|
||||
* This method may be useful for checking if the state of a tag is what is expected after a given set of operations,
|
||||
* or after clearing state such as for calls involving {@link StrutsBodyTagSupport#clearTagStateForTagPoolingServers()}
|
||||
* has taken place following {@link StrutsBodyTagSupport#doEndTag()} processing. When making comparisons, keep in mind the
|
||||
* pageContext and parent Tag state are not cleared by clearTagStateForTagPoolingServers().
|
||||
*
|
||||
*
|
||||
* @param tag1 the first {@link StrutsBodyTagSupport} to compare against the other.
|
||||
* @param tag2 the second {@link StrutsBodyTagSupport} to compare against the other.
|
||||
* @return true if the Tags are equal based on field comparisons by reflection, false otherwise.
|
||||
@@ -170,15 +165,16 @@ public abstract class AbstractTagTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to simplify setting the performClearTagStateForTagPoolingServers state for a
|
||||
* {@link ComponentTagSupport} tag's {@link Component} to match expectations for the test.
|
||||
*
|
||||
* Helper method to simplify setting the performClearTagStateForTagPoolingServers state for a
|
||||
* {@link ComponentTagSupport} tag's {@link import org.apache.struts2.components.Component} to match expectations
|
||||
* for the test.
|
||||
* <p>
|
||||
* The component reference is not available to the tag until after the doStartTag() method is called.
|
||||
* We need to ensure the component's {@link Component#performClearTagStateForTagPoolingServers} state matches
|
||||
* what we set for the Tag when a non-default (true) value is used, so this method accesses the component instance,
|
||||
* sets the value specified and forces the tag's parameters to be repopulated again.
|
||||
*
|
||||
* @param tag The ComponentTagSupport tag upon whose component we will set the performClearTagStateForTagPoolingServers state.
|
||||
* We need to ensure the component's {@link import org.apache.struts2.components.Component#performClearTagStateForTagPoolingServers}
|
||||
* state matches what we set for the Tag when a non-default (true) value is used, so this method accesses
|
||||
* the component instance, sets the value specified and forces the tag's parameters to be repopulated again.
|
||||
*
|
||||
* @param tag The ComponentTagSupport tag upon whose component we will set the performClearTagStateForTagPoolingServers state.
|
||||
* @param performClearTagStateForTagPoolingServers true to clear tag state, false otherwise
|
||||
*/
|
||||
protected void setComponentTagClearTagState(ComponentTagSupport tag, boolean performClearTagStateForTagPoolingServers) {
|
||||
|
||||
@@ -23,14 +23,21 @@ import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.EventListener;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterRegistration;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRegistration;
|
||||
import javax.servlet.SessionCookieConfig;
|
||||
import javax.servlet.SessionTrackingMode;
|
||||
import javax.servlet.descriptor.JspConfigDescriptor;
|
||||
|
||||
|
||||
/**
|
||||
@@ -42,12 +49,12 @@ public class StrutsMockServletContext implements ServletContext {
|
||||
String realPath;
|
||||
String servletInfo;
|
||||
String contextPath;
|
||||
Map initParams = new HashMap();
|
||||
Map attributes = new HashMap();
|
||||
Map<String, String> initParams = new HashMap<>();
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
InputStream resourceAsStream;
|
||||
|
||||
public void setInitParameter(String name, String value) {
|
||||
initParams.put(name, value);
|
||||
public boolean setInitParameter(String name, String value) {
|
||||
return initParams.put(name, value) != null;
|
||||
}
|
||||
|
||||
public void setRealPath(String value) {
|
||||
@@ -74,7 +81,7 @@ public class StrutsMockServletContext implements ServletContext {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Set getResourcePaths(String s) {
|
||||
public Set<String> getResourcePaths(String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -105,11 +112,11 @@ public class StrutsMockServletContext implements ServletContext {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Enumeration getServlets() {
|
||||
public Enumeration<Servlet> getServlets() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Enumeration getServletNames() {
|
||||
public Enumeration<String> getServletNames() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -130,7 +137,7 @@ public class StrutsMockServletContext implements ServletContext {
|
||||
return (String) initParams.get(s);
|
||||
}
|
||||
|
||||
public Enumeration getInitParameterNames() {
|
||||
public Enumeration<String> getInitParameterNames() {
|
||||
return Collections.enumeration(initParams.keySet());
|
||||
}
|
||||
|
||||
@@ -138,7 +145,7 @@ public class StrutsMockServletContext implements ServletContext {
|
||||
return attributes.get(s);
|
||||
}
|
||||
|
||||
public Enumeration getAttributeNames() {
|
||||
public Enumeration<String> getAttributeNames() {
|
||||
return Collections.enumeration(attributes.keySet());
|
||||
}
|
||||
|
||||
@@ -157,12 +164,142 @@ public class StrutsMockServletContext implements ServletContext {
|
||||
public void setServletInfo(String servletInfo) {
|
||||
this.servletInfo = servletInfo;
|
||||
}
|
||||
|
||||
|
||||
public String getContextPath() {
|
||||
return contextPath;
|
||||
}
|
||||
}
|
||||
|
||||
public void setContextPath(String contextPath) {
|
||||
this.contextPath = contextPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEffectiveMajorVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEffectiveMinorVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletRegistration.Dynamic addServlet(String servletName, String className) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Servlet> T createServlet(Class<T> clazz) throws ServletException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletRegistration getServletRegistration(String servletName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends ServletRegistration> getServletRegistrations() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterRegistration.Dynamic addFilter(String filterName, String className) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterRegistration.Dynamic addFilter(String filterName, Class<? extends Filter> filterClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Filter> T createFilter(Class<T> clazz) throws ServletException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilterRegistration getFilterRegistration(String filterName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionCookieConfig getSessionCookieConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(String className) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends EventListener> void addListener(T t) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(Class<? extends EventListener> listenerClass) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JspConfigDescriptor getJspConfigDescriptor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void declareRoles(String... roleNames) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVirtualServerName() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,77 +18,82 @@
|
||||
*/
|
||||
package org.apache.struts2.views.jsp.ui;
|
||||
|
||||
import org.apache.struts2.SomeEnum;
|
||||
import org.apache.struts2.TestAction;
|
||||
import org.apache.struts2.views.jsp.AbstractUITagTest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class RadioTest extends AbstractUITagTest {
|
||||
|
||||
public void testMapWithBooleanAsKey() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
HashMap map = new LinkedHashMap();
|
||||
map.put(Boolean.TRUE, "male");
|
||||
map.put(Boolean.FALSE, "female");
|
||||
testAction.setMap(map);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setLabel("mylabel");
|
||||
tag.setName("myname");
|
||||
tag.setValue("%{true}");
|
||||
tag.setList("map");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-3.txt"));
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
public void testMapWithBooleanAsKey() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
public void testMapWithBooleanAsKey_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
Map<Boolean, String> map = new LinkedHashMap<>();
|
||||
map.put(Boolean.TRUE, "male");
|
||||
map.put(Boolean.FALSE, "female");
|
||||
testAction.setMap(map);
|
||||
|
||||
HashMap map = new LinkedHashMap();
|
||||
map.put(Boolean.TRUE, "male");
|
||||
map.put(Boolean.FALSE, "female");
|
||||
testAction.setMap(map);
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setLabel("mylabel");
|
||||
tag.setName("myname");
|
||||
tag.setValue("%{true}");
|
||||
tag.setList("map");
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setLabel("mylabel");
|
||||
tag.setName("myname");
|
||||
tag.setValue("%{true}");
|
||||
tag.setList("map");
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
tag.doStartTag();
|
||||
setComponentTagClearTagState(tag, true); // Ensure component tag state clearing is set true (to match tag).
|
||||
tag.doEndTag();
|
||||
verify(RadioTag.class.getResource("Radio-3.txt"));
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-3.txt"));
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPerformClearTagStateForTagPoolingServers(true);
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
public void testMapWithBooleanAsKey_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
Map<Boolean, String> map = new LinkedHashMap<>();
|
||||
map.put(Boolean.TRUE, "male");
|
||||
map.put(Boolean.FALSE, "female");
|
||||
testAction.setMap(map);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setLabel("mylabel");
|
||||
tag.setName("myname");
|
||||
tag.setValue("%{true}");
|
||||
tag.setList("map");
|
||||
|
||||
tag.doStartTag();
|
||||
setComponentTagClearTagState(tag, true); // Ensure component tag state clearing is set true (to match tag).
|
||||
tag.doEndTag();
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-3.txt"));
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPerformClearTagStateForTagPoolingServers(true);
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapChecked() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
@@ -103,7 +108,7 @@ public class RadioTest extends AbstractUITagTest {
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setLabel("mylabel");
|
||||
tag.setName("myname");
|
||||
tag.setValue("\"1\"");
|
||||
tag.setValue("1");
|
||||
tag.setList("map");
|
||||
tag.setListKey("key");
|
||||
tag.setListValue("value");
|
||||
@@ -118,7 +123,7 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapChecked_clearTagStateSet() throws Exception {
|
||||
@@ -135,7 +140,7 @@ public class RadioTest extends AbstractUITagTest {
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setLabel("mylabel");
|
||||
tag.setName("myname");
|
||||
tag.setValue("\"1\"");
|
||||
tag.setValue("1");
|
||||
tag.setList("map");
|
||||
tag.setListKey("key");
|
||||
tag.setListValue("value");
|
||||
@@ -152,14 +157,122 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapCheckedUsingEnum() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
List<SomeEnum> enumList = new ArrayList<>(Arrays.asList(SomeEnum.values()));
|
||||
testAction.setEnumList(enumList);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setTheme("simple");
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setName("status");
|
||||
tag.setValue("INIT");
|
||||
tag.setList("enumList");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-9.txt"));
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapCheckedUsingEnum_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
List<SomeEnum> enumList = new ArrayList<>(Arrays.asList(SomeEnum.values()));
|
||||
testAction.setEnumList(enumList);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
|
||||
tag.setTheme("simple");
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setName("status");
|
||||
tag.setValue("INIT");
|
||||
tag.setList("enumList");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-9.txt"));
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPerformClearTagStateForTagPoolingServers(true);
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapCheckedUsingInteger() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
List<Integer> intList = new ArrayList<>(Arrays.asList(1, 2));
|
||||
testAction.setIntList(intList);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setTheme("simple");
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setName("status");
|
||||
tag.setValue("2");
|
||||
tag.setList("intList");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-10.txt"));
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapCheckedUsingInt_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
|
||||
List<Integer> intList = new ArrayList<>(Arrays.asList(1, 2));
|
||||
testAction.setIntList(intList);
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
|
||||
tag.setTheme("simple");
|
||||
tag.setPageContext(pageContext);
|
||||
tag.setName("status");
|
||||
tag.setValue("2");
|
||||
tag.setList("intList");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
verify(RadioTag.class.getResource("Radio-10.txt"));
|
||||
|
||||
// Basic sanity check of clearTagStateForTagPoolingServers() behaviour for Struts Tags after doEndTag().
|
||||
RadioTag freshTag = new RadioTag();
|
||||
freshTag.setPerformClearTagStateForTagPoolingServers(true);
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapCheckedNull() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
|
||||
HashMap map = new HashMap();
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("1", "One");
|
||||
map.put("2", "Two");
|
||||
testAction.setMap(map);
|
||||
@@ -181,14 +294,14 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testMapCheckedNull_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
|
||||
HashMap map = new HashMap();
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("1", "One");
|
||||
map.put("2", "Two");
|
||||
testAction.setMap(map);
|
||||
@@ -213,15 +326,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testSimple() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
testAction.setList(new String[][]{
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
@@ -243,15 +356,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testSimple_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
testAction.setList(new String[][]{
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
@@ -276,13 +389,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testSimpleWithStringMap() throws Exception {
|
||||
final Map<String, String> myMap = new TreeMap<String, String>();
|
||||
final Map<String, String> myMap = new TreeMap<>();
|
||||
myMap.put("name", "Std.");
|
||||
stack.push(new HashMap() {{ put ("myMap", myMap); }});
|
||||
stack.push(new HashMap<String, Map<String, String>>() {{
|
||||
put("myMap", myMap);
|
||||
}});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPageContext(pageContext);
|
||||
@@ -298,13 +413,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testSimpleWithStringMap_clearTagStateSet() throws Exception {
|
||||
final Map<String, String> myMap = new TreeMap<String, String>();
|
||||
final Map<String, String> myMap = new TreeMap<>();
|
||||
myMap.put("name", "Std.");
|
||||
stack.push(new HashMap() {{ put ("myMap", myMap); }});
|
||||
stack.push(new HashMap<String, Map<String, String>>() {{
|
||||
put("myMap", myMap);
|
||||
}});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
tag.setPerformClearTagStateForTagPoolingServers(true); // Explicitly request tag state clearing.
|
||||
@@ -323,15 +440,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testSimpleWithLabelSeparator() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
testAction.setList(new String[][]{
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
@@ -354,15 +471,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testSimpleWithLabelSeparator_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
testAction.setList(new String[][]{
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
@@ -388,27 +505,27 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testGenericSimple() throws Exception {
|
||||
RadioTag tag = new RadioTag();
|
||||
prepareTagGeneric(tag);
|
||||
verifyGenericProperties(tag, "simple", new String[]{"id","value"});
|
||||
verifyGenericProperties(tag, "simple", new String[]{"id", "value"});
|
||||
}
|
||||
|
||||
public void testGenericXhtml() throws Exception {
|
||||
RadioTag tag = new RadioTag();
|
||||
prepareTagGeneric(tag);
|
||||
verifyGenericProperties(tag, "xhtml", new String[]{"id","value"});
|
||||
verifyGenericProperties(tag, "xhtml", new String[]{"id", "value"});
|
||||
}
|
||||
|
||||
public void testDynamicAttributes() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
testAction.setList(new String[][]{
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
@@ -431,15 +548,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testDynamicAttributes_clearTagStateSet() throws Exception {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
testAction.setList(new String[][]{
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
});
|
||||
|
||||
RadioTag tag = new RadioTag();
|
||||
@@ -465,7 +582,7 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testNotExistingListValueKey() throws Exception {
|
||||
@@ -487,7 +604,7 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testNotExistingListValueKey_clearTagStateSet() throws Exception {
|
||||
@@ -512,15 +629,15 @@ public class RadioTest extends AbstractUITagTest {
|
||||
freshTag.setPageContext(pageContext);
|
||||
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
|
||||
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
private void prepareTagGeneric(RadioTag tag) {
|
||||
TestAction testAction = (TestAction) action;
|
||||
testAction.setFoo("bar");
|
||||
testAction.setList(new String[][]{
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
{"hello", "world"},
|
||||
{"foo", "bar"}
|
||||
});
|
||||
tag.setList("list");
|
||||
tag.setListKey("top[0]");
|
||||
|
||||
@@ -47,6 +47,8 @@ public class TextareaTest extends AbstractUITagTest {
|
||||
tag.setId("the_id");
|
||||
tag.setOnkeyup("alert('hello');");
|
||||
tag.setReadonly("true");
|
||||
tag.setMaxlength("100");
|
||||
tag.setMinlength("10");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
@@ -81,6 +83,8 @@ public class TextareaTest extends AbstractUITagTest {
|
||||
tag.setId("the_id");
|
||||
tag.setOnkeyup("alert('hello');");
|
||||
tag.setReadonly("true");
|
||||
tag.setMaxlength("100");
|
||||
tag.setMinlength("10");
|
||||
|
||||
tag.doStartTag();
|
||||
setComponentTagClearTagState(tag, true); // Ensure component tag state clearing is set true (to match tag).
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.6//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.6.dtd">
|
||||
<struts />
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"struts-6.0.dtd">
|
||||
<struts/>
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
-->
|
||||
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.6//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.6.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"struts-6.0.dtd">
|
||||
|
||||
<struts>
|
||||
|
||||
<!-- CUSTOM ACTION MAPPER -->
|
||||
<bean type="org.apache.struts2.dispatcher.mapper.ActionMapper"
|
||||
name="WW3090" class="org.apache.struts2.views.jsp.URLTagTest$RedBlueActionMapper" />
|
||||
<constant name="struts.mapper.class" value="WW3090" />
|
||||
<!-- CUSTOM ACTION MAPPER -->
|
||||
<bean type="org.apache.struts2.dispatcher.mapper.ActionMapper"
|
||||
name="WW3090" class="org.apache.struts2.views.jsp.URLTagTest$RedBlueActionMapper"/>
|
||||
<constant name="struts.mapper.class" value="WW3090"/>
|
||||
|
||||
</struts>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<input type="radio" name="status" id="status1" value="1"/>
|
||||
<label for="status1">1</label>
|
||||
<input type="radio" name="status" id="status2" checked="checked" value="2"/>
|
||||
<label for="status2">2</label>
|
||||
@@ -0,0 +1,4 @@
|
||||
<input type="radio" name="status" id="statusINIT" checked="checked" value="INIT"/>
|
||||
<label for="statusINIT">INIT</label>
|
||||
<input type="radio" name="status" id="statusCOMPLETED" value="COMPLETED"/>
|
||||
<label for="statusCOMPLETED">COMPLETED</label>
|
||||
@@ -1,4 +1,4 @@
|
||||
<tr>
|
||||
<td class="tdLabel"><label for="the_id" class="label">mylabel:</label></td>
|
||||
<td class="tdInput"><textarea name="myname" cols="20" rows="30" disabled="disabled" readonly="readonly" tabindex="5" id="the_id" title="mytitle" onclick="alert('onclick');" onkeyup="alert('hello');" onchange="alert('goodbye');">bar</textarea></td>
|
||||
<td class="tdInput"><textarea name="myname" cols="20" rows="30" disabled="disabled" readonly="readonly" tabindex="5" id="the_id" title="mytitle" maxlength="100" minlength="10" onclick="alert('onclick');" onkeyup="alert('hello');" onchange="alert('goodbye');">bar</textarea></td>
|
||||
</tr>
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.6//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.6.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"struts-6.0.dtd">
|
||||
<struts>
|
||||
<constant name="struts.ui.escapeHtmlBody" value="true"/>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user