Compare commits

...

99 Commits

Author SHA1 Message Date
Lukasz Lenart 6536dc65d8 [maven-release-plugin] prepare release STRUTS_6_0_1 2022-08-12 17:26:47 +02:00
Lukasz Lenart 915386816b Merge pull request #588 from apache/WW-5203-lazy-builder
[WW-5203] Re-builds policy string on each call
2022-08-11 13:43:18 +02:00
Lukasz Lenart 80c2de9e92 Merge pull request #586 from apache/WW-5207-asm-9
[WW-5207] Uses ASM 9 by default
2022-08-11 13:43:01 +02:00
Lukasz Lenart b62e583646 WW-5203 Re-builds policy string on each call 2022-08-09 15:19:02 +02:00
Lukasz Lenart 8b359383a1 Merge pull request #587 from sepe81/update-maven-surefire-plugin-to-3.0.0-M7
Update maven-surefire-plugin to 3.0.0-M7
2022-08-09 15:01:08 +02:00
Lukasz Lenart 11e716f979 Merge pull request #584 from sepe81/update-travis
Add openjdk17 to build, remove oraclejdk9 (EOL) and switch from oraclejdk to openjdk to fix Travis CI build
2022-08-09 15:00:34 +02:00
Sebastian Peters 71c7064f29 Update maven-surefire-plugin to 3.0.0-M7
see https://github.com/apache/maven-surefire/releases/tag/surefire-3.0.0-M7
2022-08-08 22:27:47 +02:00
Sebastian Peters 09472808aa Add openjdk17 to build, remove oraclejdk9 (EOL)
and switch from oraclejdk to openjdk
to fix Travis CI build
2022-08-08 22:20:53 +02:00
Sebastian Peters d119ba8e13 Migrate vom ubuntu trusty to jammy
see https://docs.travis-ci.com/user/reference/jammy/
2022-08-08 22:20:52 +02:00
Lukasz Lenart 86b45e96fc WW-5207 Uses ASM 9 by default 2022-08-08 17:00:42 +02:00
Lukasz Lenart 3c9465b857 Merge pull request #580 from rproserpio/patch-1
[WW-5205] - Reverting injection refactor of internal bean
2022-08-08 16:37:43 +02:00
Lukasz Lenart 0c73cf2e05 Merge pull request #583 from sepe81/update-hibernate-validator-to.6.2.x
WW-5208 Update hibernate-validator to 6.2.4
2022-08-07 10:47:38 +02:00
Lukasz Lenart 6785997412 Merge pull request #582 from sepe81/update-mvn-to-3.8.6
Update maven wrapper to 3.8.6
2022-08-07 10:45:12 +02:00
Sebastian Peters 5a7fce066f WW-5208 Update hibernate-validator to 6.2.4
b/c 6.1 has reached its end-of-life according to
https://hibernate.org/validator/releases/6.1/

6.2 is compatible with the given Java and Jakarta
versions and supports `javax.validation.*` according to
https://hibernate.org/validator/releases/6.2/
2022-08-06 14:33:00 +02:00
Sebastian Peters 4fbada4cd9 Update maven wrapper to 3.8.6 2022-08-06 14:09:54 +02:00
rproserpio 3119eb65db Reverting injection refactor of internal bean
In commit e9d0a5518c ContentTypeHandlerManager has been changed from setter-injected to constructor-injected.
However, at least with spring as the object factory, that bean was an internal bean not available from the factory, injected post construction.
In the 6.0.0 implementation ContentTypeInterceptor cannot be instantiated since its dependency cannot be resolved:
```
org.springframework.beans.factory.UnsatisfiedDependencyException

Error creating bean with name 'org.apache.struts2.rest.ContentTypeInterceptor': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.apache.struts2.rest.ContentTypeHandlerManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
```
This commit attempts to revert that change.
2022-07-25 01:11:46 +02:00
Lukasz Lenart de3dabbe44 Merge pull request #579 from apache/WW-5204-ognl-3-3-3
[WW-5204] Upgrades OGNL to version 3.3.3
2022-07-11 10:49:38 +02:00
Lukasz Lenart 82f7904206 WW-5204 Upgrades OGNL to version 3.3.3 2022-07-11 10:28:58 +02:00
Lukasz Lenart 42e3da550f Merge pull request #577 from apache/WW-5192-radio
[WW-5192] Fixes broken radio tag when using with enums
2022-07-11 10:27:06 +02:00
Lukasz Lenart f3cb89202d Merge pull request #571 from apache/WW-5190-match-action-proxy
[WW-5190] Fixes StackOverflowException when dispatching request
2022-07-11 10:25:16 +02:00
Lukasz Lenart 836a27692e Merge pull request #578 from sepe81/update-jasperreports
WW-5202 Update jasperreports to 6.19.1 and exclude optional itext from jasperreports
2022-07-08 17:19:41 +02:00
Sebastian Peters 6312572331 Exclude itext from jasperreports
b/c it's an optional dependency
and version 2.1.7.js9 is missing on maven central
2022-07-08 14:09:47 +02:00
Sebastian Peters e7db7ade62 Update jasperreports to 6.19.1 2022-07-08 14:08:46 +02:00
Lukasz Lenart b77c2f476a Uses different port for Jetty during integration testing to avoid clash 2022-07-08 08:21:16 +02:00
Lukasz Lenart e6c1cec7f8 WW-5192 Fixes brok radio tag when using with enums 2022-07-07 21:34:43 +02:00
Lukasz Lenart a781b5a27b Merge pull request #576 from apache/hiberante-validator
[WW-5193] Uses proper org.hibernate.validator groupId and upgrade to version 6.1.3.Final
2022-07-07 15:11:35 +02:00
Lukasz Lenart b71732fa14 WW-5193 Uses proper org.hibernate.validator groupId and upgrade to version 6.1.3.Final 2022-07-07 14:55:19 +02:00
Lukasz Lenart 3f79d64e6a Merge pull request #575 from apache/upgrade-log4j
[WW-5201] Upgrades log4j2 to version 2.18.0
2022-07-07 14:54:08 +02:00
Lukasz Lenart 039fd9f4ee WW-5201 Upgrades log4j2 to version 2.18.0 2022-07-07 14:12:12 +02:00
Lukasz Lenart 393d5be50c Merge pull request #574 from tobiasstadler/WW-5197
WW-5197 Adds support for java.sql.Date
2022-07-07 14:06:22 +02:00
Lukasz Lenart cb59974903 WW-5190 Marks all Struts related filters with <async-supported/> 2022-06-27 09:44:51 +02:00
Lukasz Lenart ecfdee137d WW-5190 Disables test which won't pass without refactoring the prepare and execute filters 2022-06-27 09:37:17 +02:00
Lukasz Lenart 8c37b1523f WW-5190 Uses proper order of servlets and filters 2022-06-22 07:58:12 +02:00
Lukasz Lenart 62b83021a2 Merge pull request #569 from apache/WW-5188-since-6
[WW-5188] Replaces since 2.6 with 6.0
2022-06-21 10:39:47 +02:00
Tobias Stadler f3f2d52a1c Added test case for java.sql.Date 2022-06-21 10:23:17 +02:00
Tobias Stadler 61ded9a3e7 WW-5197 Adds support for java.sql.Date 2022-06-21 10:09:31 +02:00
Lukasz Lenart d639b59f6d Merge branch 'master' into WW-5190-match-action-proxy 2022-06-18 09:45:20 +02:00
Lukasz Lenart 8e468a368e WW-5190 Defines two examples with Dispatcher result and integration tests 2022-06-18 09:45:10 +02:00
Lukasz Lenart ebe1b80ed2 WW-5190 Adds a new test to cover new logic of comparing ActionProxies 2022-06-18 08:12:29 +02:00
Lukasz Lenart 957292ecdb Simplifies logging pattern in Showcase app 2022-06-18 07:27:32 +02:00
Lukasz Lenart 06290cef91 Fixes showing configuration of an action in Showcase app 2022-06-18 07:26:13 +02:00
Lukasz Lenart a6a4529503 Fixes logging in Showcase app 2022-06-18 07:25:26 +02:00
Yasser Zamani 64d054221f Merge pull request #566 from apache/WW-5185-struts-resource
[WW-5185] Reintroduces proper implementation of Tiles resource to support wildcard matching of Tiles definitions
2022-06-17 11:16:38 +04:30
Yasser Zamani dc4e403d30 Merge pull request #570 from apache/WW-5187-velocity
[WW-5187] Comments out Velocity based PageFilter
2022-06-17 11:15:21 +04:30
Yasser Zamani e6bc93daf2 Merge pull request #572 from apache/WW-5191-textarea-max-length
[WW-5191] Fixes placement of maxLength and minLength attributes in <s:textarea/> tag
2022-06-17 11:13:09 +04:30
Lukasz Lenart 0e4d5962e1 WW-5191 Fixes placement of maxLength and minLength attributes in <s:textarea/> tag 2022-06-15 15:18:46 +02:00
Lukasz Lenart 69102e9075 WW-5190 Uses wrapped request only when processing request by Struts 2022-06-15 11:07:53 +02:00
Lukasz Lenart 1c2b491a27 WW-5190 Reuses action proxy if namespace, name and method are match 2022-06-15 11:07:29 +02:00
Lukasz Lenart 5af840b160 WW-5190 Extracts method name from config for known action name 2022-06-15 11:06:45 +02:00
Lukasz Lenart b6b74a46ea WW-5188 Replaces since 2.6 with 6.0 2022-06-14 13:34:27 +02:00
Lukasz Lenart fc2aebd10a WW-5187 Comments out Velocity based PageFilter 2022-06-14 13:17:19 +02:00
Lukasz Lenart ba041e1ee6 Merge pull request #568 from tobiasstadler/master
Add async and velocity plugin to bom
2022-06-14 11:43:49 +02:00
Tobias Stadler 0c3534e8b4 Added async and velocity plugin to bom 2022-06-14 09:53:10 +02:00
Lukasz Lenart 9a2996f9b7 Uses proper Servlet API 3.1 headers 2022-06-10 16:06:27 +02:00
Lukasz Lenart 3825229f44 WW-5185 Reintroduces proper implementation of Tiles resource to support wildcard matching of Tiles definitions
It was broken after refactoring related to WW-5011
2022-06-10 16:06:10 +02:00
Lukasz Lenart 4b3ee53f93 [maven-release-plugin] prepare for next development iteration 2022-06-02 09:11:11 +02:00
Lukasz Lenart 68fb49c10e [maven-release-plugin] prepare release STRUTS_6_0_0 2022-06-02 09:11:02 +02:00
Lukasz Lenart 77c175c7be Merge pull request #555 from hboutemy/patch-4
upgrade Felix m-bundle-p: reproducible builds
2022-05-25 10:42:55 +02:00
Hervé Boutemy 65b7e8c36f upgrade Felix m-bundle-p: reproducible builds 2022-05-25 10:00:15 +02:00
Lukasz Lenart 735bbc283e [maven-release-plugin] prepare for next development iteration 2022-05-24 13:59:32 +02:00
Lukasz Lenart 981885fd6a [maven-release-plugin] prepare release STRUTS_6_0_0_RC4 2022-05-24 13:59:22 +02:00
Lukasz Lenart 07b88fcc35 Upgrades integration tests config to match Spring and Jetty 2022-05-24 09:51:42 +02:00
Lukasz Lenart 2cbe47297e Merge pull request #554 from gregh3269/More_localdatetime_support
Add basic LocalDateTime support WW-5175
2022-05-23 07:35:43 +02:00
Lukasz Lenart 545add9365 Merge pull request #553 from apache/WW-5179-max-length
[WW-5179] Set default value of struts.ognl.expressionMaxLength to 256
2022-05-23 07:34:17 +02:00
Lukasz Lenart ebecc7d39d Merge pull request #552 from apache/WW-5165-upgrade-spring
[WW-5165] Upgrades Spring to version 5.3.20
2022-05-23 07:34:05 +02:00
Greg Huber 226a1d49ce Add basic LocalDateTime support WW-5175 2022-05-20 11:47:08 +01:00
Greg Huber 075ef7c4e1 Add basic LocalDateTime support WW-5175 2022-05-19 10:30:36 +01:00
Lukasz Lenart 1237110652 WW-5179 Adjusts test to match new default value 2022-05-17 21:17:56 +02:00
Lukasz Lenart 3f2518afa8 WW-5179 Set default value of struts.ognl.expressionMaxLength to 256 2022-05-17 20:59:51 +02:00
Lukasz Lenart 9f9edf4705 WW-5165 Upgrades Spring to version 5.3.20 2022-05-17 07:37:39 +02:00
gregh3269 7e912742ed Basic LocalDateTime support (#532)
* Basic LocalDateTime support

* Basic LocalDateTime support

* Basic LocalDateTime support

* Basic LocalDateTime support

* Basic LocalDateTime support

Co-authored-by: Greg Huber <ghuber@guestales.co.uk>
Co-authored-by: Greg Huber <ghuber@apache.org>
2022-05-17 07:31:30 +02:00
Lukasz Lenart c98b60cd9a Merge pull request #528 from JCgH4164838Gh792C124B5/localS2_26_OgnlUtilOptionalCache1
Potential expression cache enhancement for 2.6 series
2022-05-16 07:38:59 +02:00
Lukasz Lenart 5ae9688ae8 Merge pull request #551 from apache/dependabot/maven/xerces-xercesImpl-2.12.2
Bump xercesImpl from 2.12.0 to 2.12.2
2022-05-16 07:18:03 +02:00
Lukasz Lenart b72200aabf Merge branch 'master' into localS2_26_OgnlUtilOptionalCache1
# Conflicts:
#	core/src/test/java/com/opensymphony/xwork2/ognl/OgnlUtilTest.java
2022-05-16 07:16:03 +02:00
JCgH4164838Gh792C124B5 16e7c9b459 Merge pull request #1 from apache/use-extension-point
Ties cache extension points with implementation
2022-05-15 19:01:17 -04:00
Yasser Zamani bea1c6f09f Merge pull request #549 from apache/WW-5181-static-methods
[WW-5181] Blocks permanently access to static methods
2022-05-15 14:40:12 +04:30
dependabot[bot] 888884cc51 Bump xercesImpl from 2.12.0 to 2.12.2
Bumps xercesImpl from 2.12.0 to 2.12.2.

---
updated-dependencies:
- dependency-name: xerces:xercesImpl
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-15 10:02:32 +00:00
Yasser Zamani b387abae01 Merge pull request #550 from apache/servlet-3
[WW-5182] Upgrade to Servlet API 3.1
2022-05-15 14:27:47 +04:30
Lukasz Lenart 059a2a6117 WW-5182 Upgrade to Servlet API 3.1 2022-05-14 09:12:42 +02:00
Lukasz Lenart c0a3be9fd8 Uses two step build process on Travis similar to Jenkins pipeline 2022-05-10 07:41:34 +02:00
Lukasz Lenart 4a7cae029a Uses proper package to match Jetty Eclipse 2022-05-08 12:31:40 +02:00
Lukasz Lenart 9873a7f56b Tries to fix Travis build 2022-05-06 08:35:06 +02:00
Lukasz Lenart 086b514d59 Adjusts Travis build to be aligned with Jenkins pipeline 2022-05-06 07:47:12 +02:00
Lukasz Lenart 6024dd6fa4 Skips test during deploy 2022-05-06 07:29:29 +02:00
Lukasz Lenart 4eb2ee8384 Fixes typo in deploy step 2022-05-06 07:24:29 +02:00
Lukasz Lenart 8e49362bf8 Uses Maven Wrapper in Jenkins pipeline 2022-05-06 07:15:13 +02:00
Lukasz Lenart 7541d9ab35 WW-5181 Blocks permanently access to static methods 2022-05-05 12:28:09 +02:00
Lukasz Lenart c82fdb5e76 Upgrades Maven Wrapper 2022-05-05 12:27:51 +02:00
Lukasz Lenart f40f9f15e5 Merge pull request #547 from apache/dependabot/maven/junit-junit-4.13.1
Bump junit from 4.13 to 4.13.1
2022-05-04 11:18:43 +02:00
dependabot[bot] 2d9cdb73a5 Bump junit from 4.13 to 4.13.1
Bumps [junit](https://github.com/junit-team/junit4) from 4.13 to 4.13.1.
- [Release notes](https://github.com/junit-team/junit4/releases)
- [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.13.1.md)
- [Commits](https://github.com/junit-team/junit4/compare/r4.13...r4.13.1)

---
updated-dependencies:
- dependency-name: junit:junit
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-04 08:52:18 +00:00
Lukasz Lenart d07a496d5c Uses common Maven Compiler plugin to set proper source and target version 2022-05-04 10:45:02 +02:00
Lukasz Lenart bef1f67d4a Upgrades Maven Jetty Plugin to work with JDK8+ 2022-05-04 10:44:54 +02:00
Lukasz Lenart e2718aa482 Enables branch autodeleting after PR has been merged 2022-04-07 14:43:38 +02:00
Lukasz Lenart b73fec4de0 Drops unused class 2022-04-04 17:12:33 +02:00
Lukasz Lenart c2795d2e30 Uses project specific folder 2022-03-28 13:09:21 +02:00
Lukasz Lenart a987e31a0e Upgrades OWASP Dependency Check plugin to version 7.0.1 2022-03-28 07:45:51 +02:00
Lukasz Lenart 6aff5b7faa WW-5174 Upgrades Jackson-Core to version 2.13.2 and Jackson-Databind to 2.13.2.1 2022-03-28 07:26:50 +02:00
Lukasz Lenart 5b40f9f48e WW-5172 Upgrades Freemarker to 2.3.31 version 2022-03-15 14:32:02 +01:00
Lukasz Lenart e9d0a5518c Cleans up code 2022-03-15 14:27:57 +01:00
153 changed files with 3255 additions and 1869 deletions
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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>
+4 -4
View File
@@ -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
View File
@@ -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>
@@ -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;
}
}
+4 -5
View File
@@ -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 &quot;dispatching&quot; 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>
+39 -34
View File
@@ -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"));
@@ -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"));
@@ -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");
@@ -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
View File
@@ -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
View File
@@ -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>
+2 -2
View File
@@ -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>
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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();
@@ -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) {
@@ -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
*
@@ -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?)>
+2 -2
View File
@@ -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
@@ -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());
}
@@ -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