Compare commits

..

133 Commits

Author SHA1 Message Date
Lukasz Lenart 9c5c80d173 [maven-release-plugin] prepare release STRUTS_6_4_0 2024-04-07 11:22:06 +02:00
Lukasz Lenart a6d6d918fa Reverts release and fixes issue with assembly 2024-04-07 11:14:44 +02:00
Lukasz Lenart 5e8b81b382 [maven-release-plugin] prepare for next development iteration 2024-04-07 08:13:17 +02:00
Lukasz Lenart f8381fbdbf [maven-release-plugin] prepare release STRUTS_6_4_0 2024-04-07 08:13:07 +02:00
Lukasz Lenart 0f6d5dbb2f Merge pull request #903 from apache/fix/WW-5390-assembly
WW-5390 Fixes creating assembly and attaching sources when preparing a new release
2024-04-07 07:08:19 +02:00
Lukasz Lenart db725518ee WW-5390 Fixes creating assembly and attaching sources when preparing a new release 2024-04-06 19:36:14 +02:00
Lukasz Lenart ee38cd5b14 Merge pull request #902 from apache/dependabot/maven/log4j2.version-2.23.1
WW-5404 Bump log4j2.version from 2.21.1 to 2.23.1
2024-04-06 18:45:12 +02:00
dependabot[bot] 7a79576bb3 Bump log4j2.version from 2.21.1 to 2.23.1
Bumps `log4j2.version` from 2.21.1 to 2.23.1.

Updates `org.apache.logging.log4j:log4j-api` from 2.21.1 to 2.23.1

Updates `org.apache.logging.log4j:log4j-core` from 2.21.1 to 2.23.1

Updates `org.apache.logging.log4j:log4j-jcl` from 2.21.1 to 2.23.1

Updates `org.apache.logging.log4j:log4j-slf4j-impl` from 2.21.1 to 2.23.1

---
updated-dependencies:
- dependency-name: org.apache.logging.log4j:log4j-api
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.logging.log4j:log4j-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.logging.log4j:log4j-jcl
  dependency-type: direct:development
  update-type: version-update:semver-minor
- dependency-name: org.apache.logging.log4j:log4j-slf4j-impl
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-04 10:01:09 +00:00
Lukasz Lenart 5cf746f538 Merge pull request #901 from apache/fix/branch-protction
Uses proper context name in branch protection rule
2024-04-02 15:01:10 +02:00
Lukasz Lenart 689d17d274 Merge pull request #896 from apache/feature/WW-5402-autoload-classptah
WW-5402 Auto loads Tiles definitions from classpath
2024-04-02 08:53:49 +02:00
Lukasz Lenart c7ae614824 WW-5402 Auto loads Tiles definitions from classpath 2024-03-31 11:52:59 +02:00
Lukasz Lenart 273c3a1a99 Uses proper context name in branch protection rule 2024-03-31 11:36:49 +02:00
Lukasz Lenart c774e23ef9 Merge pull request #900 from apache/WW-5251-retrofit-compat
WW-5251 Fix deprecated interface method signature
2024-03-31 11:35:52 +02:00
Kusal Kithul-Godage 93c11aaf62 WW-5251 Fix deprecated interface method signature 2024-03-31 00:10:39 +11:00
Lukasz Lenart 66c1ac431f Merge pull request #899 from apache/feature/codeowners-review
Enables required review by codeowners
2024-03-30 10:33:53 +01:00
Lukasz Lenart 7281d7e2ee Merge pull request #898 from apache/WW-5251-retrofit-compat
WW-5251 Reinstate deleted interfaces with transparent compat
2024-03-30 08:52:41 +01:00
Lukasz Lenart 6950fcb75f Enables required review by codeowners 2024-03-30 08:36:50 +01:00
Kusal Kithul-Godage dc774c484f WW-5251 Reinstate RequestAware 2024-03-29 21:35:08 +11:00
Kusal Kithul-Godage 19698e1fd2 WW-5251 Fix ParameterAware 2024-03-29 21:01:35 +11:00
Kusal Kithul-Godage cda2a2b231 WW-5251 Reinstate deleted interfaces with transparent compat 2024-03-27 18:41:24 +11:00
Lukasz Lenart cdc931e26f Merge pull request #895 from apache/fix/file-uploads
Converts multiple file uploads example to use Action based upload
2024-03-24 09:06:46 +01:00
Lukasz Lenart db0bd43855 Converts multiple file uploads example to use Action based upload 2024-03-17 17:45:32 +01:00
Kusal Kithul-Godage 86aee4b0ea Merge pull request #894 from apache/WW-5364-npe
WW-5364 Fix potential NPE in XmlDocConfigurationProvider
2024-03-14 15:48:48 +11:00
Kusal Kithul-Godage 29422e47fe WW-5364 Fix potential NPE in XmlDocConfigurationProvider 2024-03-13 21:49:27 +11:00
Lukasz Lenart e08f637be9 Merge pull request #892 from apache/feature/WW-5401-logging
[WW-5401] Improves logging around wrapping request and detecting multipart request
2024-03-11 13:45:09 +01:00
Lukasz Lenart ac6c88ad4b WW-5401 Uses same message approach
Co-authored-by: Sebastian Peters <sebastian.peters@gmail.com>
2024-03-06 14:36:11 +01:00
Lukasz Lenart c320181275 WW-5401 Fixes typo
Co-authored-by: Sebastian Peters <sebastian.peters@gmail.com>
2024-03-06 14:35:53 +01:00
Lukasz Lenart f459981022 WW-5401 Improves logging around wrapping request and detecting multipart request 2024-03-06 08:09:09 +01:00
Lukasz Lenart 6648cbdb23 Merge pull request #886 from apache/dependabot/maven/maven-surefire-plugin.version-3.2.5
Bump maven-surefire-plugin.version from 3.0.0-M7 to 3.2.5
2024-02-26 07:13:55 +01:00
dependabot[bot] ac6095d1ae Bump maven-surefire-plugin.version from 3.0.0-M7 to 3.2.5
Bumps `maven-surefire-plugin.version` from 3.0.0-M7 to 3.2.5.

Updates `org.apache.maven.surefire:surefire-junit47` from 3.0.0-M7 to 3.2.5

Updates `org.apache.maven.plugins:maven-surefire-plugin` from 3.0.0-M7 to 3.2.5
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.0.0-M7...surefire-3.2.5)

---
updated-dependencies:
- dependency-name: org.apache.maven.surefire:surefire-junit47
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-26 01:35:59 +00:00
Lukasz Lenart 154132d469 Merge pull request #884 from apache/dependabot/maven/org.apache.commons-commons-compress-1.26.0
[WW-5399] Bump org.apache.commons:commons-compress from 1.25.0 to 1.26.0
2024-02-21 08:04:47 +01:00
dependabot[bot] 43f1197961 Bump org.apache.commons:commons-compress from 1.25.0 to 1.26.0
Bumps org.apache.commons:commons-compress from 1.25.0 to 1.26.0.

---
updated-dependencies:
- dependency-name: org.apache.commons:commons-compress
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-21 00:18:54 +00:00
Lukasz Lenart 0c4e21145d Merge pull request #882 from apache/dependabot/maven/commons-validator-commons-validator-1.8.0
WW-5398 Bump commons-validator:commons-validator from 1.6 to 1.8.0
2024-02-19 07:31:18 +01:00
Lukasz Lenart 3aa63e8cbb Merge pull request #883 from apache/dependabot/maven/org.apache.maven.doxia-doxia-module-markdown-1.12.0
Bump org.apache.maven.doxia:doxia-module-markdown from 1.9.1 to 1.12.0
2024-02-19 07:29:23 +01:00
Lukasz Lenart 82491eff87 Merge pull request #880 from apache/dependabot/maven/slf4j.version-2.0.12
Bump slf4j.version from 2.0.11 to 2.0.12
2024-02-19 07:28:39 +01:00
Lukasz Lenart d9ed77d3f8 Merge pull request #879 from apache/dependabot/maven/org.apache.maven.doxia-doxia-core-1.12.0
Bump org.apache.maven.doxia:doxia-core from 1.9.1 to 1.12.0
2024-02-19 07:28:06 +01:00
dependabot[bot] 8283ded5e2 Bump org.apache.maven.doxia:doxia-module-markdown from 1.9.1 to 1.12.0
Bumps org.apache.maven.doxia:doxia-module-markdown from 1.9.1 to 1.12.0.

---
updated-dependencies:
- dependency-name: org.apache.maven.doxia:doxia-module-markdown
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-19 01:46:51 +00:00
dependabot[bot] 1ddf446f78 Bump commons-validator:commons-validator from 1.6 to 1.8.0
Bumps commons-validator:commons-validator from 1.6 to 1.8.0.

---
updated-dependencies:
- dependency-name: commons-validator:commons-validator
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-19 01:46:43 +00:00
dependabot[bot] 94b2ee7ce5 Bump slf4j.version from 2.0.11 to 2.0.12
Bumps `slf4j.version` from 2.0.11 to 2.0.12.

Updates `org.slf4j:slf4j-api` from 2.0.11 to 2.0.12

Updates `org.slf4j:slf4j-simple` from 2.0.11 to 2.0.12

---
updated-dependencies:
- dependency-name: org.slf4j:slf4j-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.slf4j:slf4j-simple
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-19 01:44:27 +00:00
dependabot[bot] 43d180f362 Bump org.apache.maven.doxia:doxia-core from 1.9.1 to 1.12.0
Bumps [org.apache.maven.doxia:doxia-core](https://github.com/apache/maven-doxia) from 1.9.1 to 1.12.0.
- [Release notes](https://github.com/apache/maven-doxia/releases)
- [Commits](https://github.com/apache/maven-doxia/compare/doxia-1.9.1...doxia-1.12.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.doxia:doxia-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-19 01:44:05 +00:00
Lukasz Lenart 93fa72ee13 Merge pull request #878 from apache/fix/build-status 2024-02-18 13:58:25 +01:00
Lukasz Lenart 9d2a7649c5 Updates link to build status on Jenkins 2024-02-17 08:31:57 +01:00
Lukasz Lenart c553c93fab Merge pull request #843 from apache/dependabot/maven/net.sf.jasperreports-jasperreports-6.21.0
WW-5397 Bump net.sf.jasperreports:jasperreports from 6.20.6 to 6.21.0
2024-02-16 09:43:26 +01:00
Lukasz Lenart a84f85798b Merge pull request #876 from gregh3269/fix-for-WW-5396
s:file shows server/file location WW-5396
2024-02-16 08:29:54 +01:00
Greg Huber bb3edaec06 s:file shows server/file location WW-5396 2024-02-14 12:00:53 +00:00
Greg Huber 1c59b45a23 s:file shows server/file location WW-5396 2024-02-14 11:52:38 +00:00
Greg Huber de9aacef61 s:file shows server/file location WW-5396 2024-02-14 11:04:43 +00:00
Greg Huber e3ca240b70 s:file shows server/file location WW-5396 2024-02-14 10:50:50 +00:00
Lukasz Lenart 0a2861b8a3 Merge pull request #872 from aleksandr-m/feature/rest_encoding
WW-5394 Use request encoding
2024-02-13 16:18:04 +01:00
Lukasz Lenart 694b97cc3c Merge pull request #874 from apache/dependabot/maven/commons-logging-commons-logging-1.3.0
WW-5395 Bump commons-logging:commons-logging from 1.2 to 1.3.0
2024-02-12 07:44:20 +01:00
Lukasz Lenart 42e8ad1cc2 Merge pull request #875 from apache/dependabot/github_actions/actions/upload-artifact-4.3.1
Bump actions/upload-artifact from 4.3.0 to 4.3.1
2024-02-12 07:42:40 +01:00
dependabot[bot] e9eae281c3 Bump actions/upload-artifact from 4.3.0 to 4.3.1
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.3.0 to 4.3.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/26f96dfa697d77e81fd5907df203aa23a56210a8...5d5d22a31266ced268874388b861e4b58bb5c2f3)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-12 01:53:45 +00:00
dependabot[bot] 07f0d1eddb Bump commons-logging:commons-logging from 1.2 to 1.3.0
Bumps commons-logging:commons-logging from 1.2 to 1.3.0.

---
updated-dependencies:
- dependency-name: commons-logging:commons-logging
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-12 01:50:29 +00:00
Aleksandr Mashchenko 6d6097c729 WW-5394 Use request encoding 2024-02-10 15:48:06 +02:00
Kusal Kithul-Godage 4aa1cbc56b Merge pull request #867 from apache/WW-5391-velocity-ext-point
WW-5391 Add interface for VelocityManager extension point
2024-02-05 13:39:08 +11:00
Lukasz Lenart ce24675221 Merge pull request #863 from sepe81/feature/dependency-updates
various dependency updates for master
2024-02-03 16:04:35 +01:00
Kusal Kithul-Godage 889a4180cd WW-5391 Fix serialisation warnings 2024-02-03 13:18:02 +11:00
Kusal Kithul-Godage 93f0a5116b WW-5391 Fix bean definition 2024-02-02 17:48:14 +11:00
Kusal Kithul-Godage b5fca66ad0 WW-5391 Migrate other usages 2024-02-02 17:42:56 +11:00
Kusal Kithul-Godage ace6a713c4 WW-5391 Fix VelocityDecoratorServlet 2024-02-02 17:34:58 +11:00
Kusal Kithul-Godage 9328ae7ec1 WW-5391 Add interface for VelocityManager extension point 2024-02-02 17:25:17 +11:00
Lukasz Lenart eb469779f7 Merge pull request #864 from apache/dependabot/github_actions/actions/upload-artifact-4.3.0
Bump actions/upload-artifact from 4.2.0 to 4.3.0
2024-01-29 06:49:05 +01:00
dependabot[bot] 372aad2c6c Bump actions/upload-artifact from 4.2.0 to 4.3.0
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.2.0 to 4.3.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/694cdabd8bdb0f10b2cea11669e1bf5453eed0a6...26f96dfa697d77e81fd5907df203aa23a56210a8)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-29 01:48:45 +00:00
Lukasz Lenart b836072956 Merge pull request #852 from apache/fix/WW-5360-iterator
[WW-5360] Introduces additional countStr & indexStr to allow to ignore conversion
2024-01-28 09:31:40 +01:00
Lukasz Lenart a358db5853 WW-5360 Introduces additional countStr & indexStr to allow to ignore conversion 2024-01-27 14:43:22 +01:00
Sebastian Peters abd824fdd2 Update commons-text to 1.11.0 2024-01-27 11:10:16 +01:00
Sebastian Peters 218e634bf1 Update commons-io to 2.15.1 2024-01-27 11:09:42 +01:00
Sebastian Peters fd7e74867c Update commons-lang3 to 3.14.0 2024-01-27 11:09:12 +01:00
Sebastian Peters 27f0b56966 Update maven-enforcer-plugin to 3.4.1 2024-01-27 11:06:15 +01:00
Sebastian Peters 8ef55db35f Update maven-dependency-plugin to 3.6.1 2024-01-27 11:05:31 +01:00
Sebastian Peters fd2cf91601 Update log4j2 to 2.21.1 2024-01-27 10:18:30 +01:00
Sebastian Peters f8a8172a3e Update spring to 5.3.31 2024-01-26 12:49:46 +01:00
Sebastian Peters 71d28ed90d Update jackson to 2.16.1 2024-01-26 12:49:09 +01:00
Sebastian Peters 77285186df Update slf4j to 2.0.11 2024-01-26 12:48:45 +01:00
Sebastian Peters 028fedd306 Update assertj to 3.25.2 2024-01-26 12:45:17 +01:00
Sebastian Peters 8087ba97ee Update maven-site-plugin to 3.12.1 2024-01-26 12:45:01 +01:00
Sebastian Peters e299bba112 Update maven-war-plugin to 3.4.0 2024-01-26 12:44:36 +01:00
Kusal Kithul-Godage bd783a0e19 Merge pull request #832 from apache/WW-5352-parameter-annotation-3 2024-01-26 11:00:16 +11:00
Lukasz Lenart 5057aeac83 Merge pull request #862 from apache/lukaszlenart-patch-1
Stops running sonar.yml on forks
2024-01-24 18:02:22 +01:00
Lukasz Lenart 7843cd5e1c Merge pull request #854 from sepe81/feature/update-security-policy
Small spelling and MD fixes (IntelliJ assisted)
2024-01-24 17:32:44 +01:00
Lukasz Lenart 2513fcb292 Stops running sonar.yml on forks 2024-01-24 17:28:52 +01:00
Sebastian Peters 644bd1f8ca Mention just the maintenance branches for supported versions
b/c https://struts.apache.org/releases.html#prior-releases
has further details.
2024-01-24 15:14:09 +01:00
Sebastian Peters e7a13b9637 Small spelling and MD fixes (IntelliJ assisted) 2024-01-24 15:14:01 +01:00
Lukasz Lenart 2de30e72a9 Merge pull request #859 from apache/fix/sped-up-build
Drops JDK11 build and fixes duplicated steps
2024-01-22 11:04:08 +01:00
Lukasz Lenart 65c0427eae Merge pull request #858 from apache/fix/plexus-exclusion
Fixes excluding Plexus container in OWASP scan
2024-01-22 10:09:58 +01:00
Lukasz Lenart 9f4b67a9a2 Drops JDK11 build and fixes duplicated steps 2024-01-22 10:08:59 +01:00
Lukasz Lenart cf74a4450c Fixes excluding Plexus container in OWASP scan 2024-01-22 09:28:14 +01:00
Lukasz Lenart ec18f0eef1 Merge pull request #855 from apache/dependabot/github_actions/actions/upload-artifact-4.2.0
Bump actions/upload-artifact from 4.1.0 to 4.2.0
2024-01-22 06:26:24 +01:00
dependabot[bot] cde86457ab Bump actions/upload-artifact from 4.1.0 to 4.2.0
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.1.0 to 4.2.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/1eb3cb2b3e0f29609092a73eb033bb759a334595...694cdabd8bdb0f10b2cea11669e1bf5453eed0a6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-22 01:38:19 +00:00
Lukasz Lenart 1e56b7ce68 Merge pull request #853 from sepe81/feature/upgrade-maven-to-3.9.6
Upgrade maven to 3.9.6 and wrapper to 3.2.0 (cherry-pick from 7.x)
2024-01-21 18:23:55 +01:00
Sebastian Peters 775febbdfa Upgrade maven to 3.9.6 and wrapper to 3.2.0
* `mvn wrapper:wrapper -Dmaven=3.9.6`
* remove outdated MavenWrapperDownloader from takari
* remove duplicate definition for maven-wrapper-plugin
  b/c it is already defined under pluginManagement

(cherry picked from commit 54a7c7094f)
2024-01-21 12:01:29 +01:00
Lukasz Lenart a763071d21 Merge pull request #848 from apache/fix/WW-5357-disabled
[WW-5357] Adds support for disabled attribute to anchor tag
2024-01-19 11:48:38 +01:00
Lukasz Lenart dd0f0b05a5 Merge pull request #849 from apache/fix/longer-sleep
Extends sleep period to avoid breaking a build
2024-01-19 11:48:26 +01:00
Lukasz Lenart 9a6411c8c5 Extends sleep period to avoid breaking a build 2024-01-19 07:44:53 +01:00
Lukasz Lenart 3ec313aa0b WW-5357 Adds support for disabled attribute to anchor tag 2024-01-19 07:35:09 +01:00
Lukasz Lenart 3a1a89a547 Merge pull request #845 from apache/fix/WW-5374-context
[WW-5374] Allows to prepend reportUri with Servlet context
2024-01-19 07:13:52 +01:00
Kusal Kithul-Godage 71d77df3f3 WW-5352 Normalise parameter name 2024-01-18 21:24:36 +11:00
Lukasz Lenart 790c663ddd WW-5374 Adds additional test case to cover disabling prepending context 2024-01-18 11:24:34 +01:00
Lukasz Lenart d5932f82fa WW-5374 Uses @code instead of <tt/> 2024-01-18 11:24:08 +01:00
Lukasz Lenart 5ee3811824 Merge pull request #847 from apache/fix/WW-5369-min-lib
[WW-5369] Re-define minimal library set
2024-01-18 10:25:14 +01:00
Kusal Kithul-Godage b50616942b WW-5352 Acceptance test coverage 2024-01-18 19:54:54 +11:00
Lukasz Lenart 72f551f40b WW-5369 Re-define minimal library set 2024-01-18 06:48:12 +01:00
Lukasz Lenart fdd996c686 Merge pull request #844 from apache/fix/WW-5387-remove
[WW-5387] Fixes remove() signature
2024-01-17 13:23:29 +01:00
Lukasz Lenart dc96c257d4 WW-5374 Allows to prepend reportUri with Servlet context 2024-01-17 13:22:09 +01:00
Kusal Kithul-Godage 728d695ce1 WW-5352 Add debug logging for parameter rejections 2024-01-17 19:26:03 +11:00
Lukasz Lenart e9738698a4 WW-5387 Fixes remove() signature 2024-01-16 20:36:00 +01:00
Lukasz Lenart d0ac76b9a4 Merge pull request #820 from apache/dependabot/maven/org.apache.commons-commons-compress-1.25.0
Bump org.apache.commons:commons-compress from 1.23.0 to 1.25.0
2024-01-15 13:00:47 +01:00
Kusal Kithul-Godage bdcedc55b3 Merge pull request #841 from apache/WW-5352-ognlvaluestack
WW-5352 Clean up OgnlValueStackTest
2024-01-15 18:44:01 +11:00
Lukasz Lenart 0a94b50bcc Merge pull request #842 from apache/dependabot/github_actions/actions/upload-artifact-4.1.0
Bump actions/upload-artifact from 4.0.0 to 4.1.0
2024-01-15 06:32:27 +01:00
dependabot[bot] ceb0a9a737 Bump net.sf.jasperreports:jasperreports from 6.20.6 to 6.21.0
Bumps [net.sf.jasperreports:jasperreports](https://github.com/TIBCOSoftware/jasperreports) from 6.20.6 to 6.21.0.
- [Release notes](https://github.com/TIBCOSoftware/jasperreports/releases)
- [Commits](https://github.com/TIBCOSoftware/jasperreports/commits)

---
updated-dependencies:
- dependency-name: net.sf.jasperreports:jasperreports
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-15 01:39:27 +00:00
dependabot[bot] 686189c1b3 Bump actions/upload-artifact from 4.0.0 to 4.1.0
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/c7d193f32edcb7bfad88892161225aeda64e9392...1eb3cb2b3e0f29609092a73eb033bb759a334595)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-15 01:30:13 +00:00
Kusal Kithul-Godage 9b5cb2d7b5 WW-5352 Move method to XWorkTestCase 2024-01-14 18:13:57 +11:00
Kusal Kithul-Godage 3c8fff46d4 WW-5352 Clean up OgnlValueStackTest 2024-01-14 16:37:14 +11:00
Kusal Kithul-Godage 49b9c0c78c WW-5352 Ensure superclasses and interfaces allowlisted 2024-01-14 16:15:46 +11:00
Lukasz Lenart d8dc720d4b Merge pull request #835 from apache/fix/WW-5365-radio-value
[WW-5365] Reverts changes introduced in WW-5192 to allow evaluate the value attribute of Radio tag
2024-01-09 18:59:51 +01:00
Kusal Kithul-Godage 56d8361b41 WW-5352 Implement transition mode 2024-01-09 22:53:52 +11:00
Kusal Kithul-Godage bf7737fa07 WW-5352 Add unit test coverage for generics 2024-01-09 22:30:40 +11:00
Kusal Kithul-Godage f106b20983 WW-5352 Map-like type support 2024-01-09 21:23:18 +11:00
Kusal Kithul-Godage 6df80041e3 WW-5352 Auto allowlist parameterized types! 2024-01-09 20:54:15 +11:00
Kusal Kithul-Godage 770d311105 WW-5352 Mild optimisation 2024-01-09 20:23:44 +11:00
Kusal Kithul-Godage 0a71e2c3b9 WW-5352 Implement auto-allowlisting for Iterator component 2024-01-09 20:23:44 +11:00
Kusal Kithul-Godage a57c2882e7 WW-5352 Reinstate manual allowlist for generic types 2024-01-09 18:42:15 +11:00
Kusal Kithul-Godage b2c7542265 WW-5352 Dispatcher should up thread allowlist 2024-01-09 17:52:09 +11:00
Kusal Kithul-Godage 4c60f39c7a WW-5352 Enable annotations for showcase 2024-01-09 17:21:21 +11:00
Kusal Kithul-Godage 5d79301235 WW-5352 Fix missing curved bracket 2024-01-09 17:21:02 +11:00
Kusal Kithul-Godage e9154b922c Merge branch 'master' into WW-5352-parameter-annotation-3 2024-01-09 16:12:40 +11:00
Kusal Kithul-Godage 4c5f2b0266 WW-5352 Add full unit test coverage 2024-01-09 15:56:46 +11:00
Kusal Kithul-Godage bf3f407b5f WW-5352 Ensure allowlist is cleared if in unexpected state 2024-01-09 15:48:35 +11:00
Lukasz Lenart 55ca7a5b34 WW-5365 Reverts changes introduced in WW-5192 to allow evaluate the value attribute 2024-01-07 11:37:10 +01:00
Kusal Kithul-Godage 4255da3ee9 WW-5352 First draft implementation 2024-01-07 14:14:29 +11:00
Kusal Kithul-Godage ad576f0fd5 WW-5352 Introduce ThreadAllowlist bean 2024-01-07 14:13:23 +11:00
Kusal Kithul-Godage eca0666f0a WW-5352 Introduce StrutsParameter annotation 2024-01-07 14:13:23 +11:00
dependabot[bot] 96618ebbdf Bump org.apache.commons:commons-compress from 1.23.0 to 1.25.0
Bumps org.apache.commons:commons-compress from 1.23.0 to 1.25.0.

---
updated-dependencies:
- dependency-name: org.apache.commons:commons-compress
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-01 09:58:53 +00:00
140 changed files with 3596 additions and 1639 deletions
+7 -1
View File
@@ -13,7 +13,13 @@ notifications:
github:
del_branch_on_merge: true
protected_branches:
master: { }
master:
# contexts are the names of checks that must pass.
contexts:
- build
required_pull_request_reviews:
require_code_owner_reviews: true
required_approving_review_count: 1
autolink_jira:
- WW
dependabot_alerts: true
+1 -1
View File
@@ -57,7 +57,7 @@ jobs:
publish_results: true
- name: "Upload artifact"
uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # 4.0.0
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # 4.3.1
with:
name: SARIF file
path: results.sarif
+1
View File
@@ -31,6 +31,7 @@ jobs:
sonarcloud:
name: Scan
runs-on: ubuntu-latest
if: ${{ !github.event.pull_request.head.repo.fork }}
steps:
- uses: actions/checkout@v4
with:
-117
View File
@@ -1,117 +0,0 @@
/*
* Copyright 2007-present the original author or authors.
*
* Licensed 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.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if(mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if(mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}
+4 -4
View File
@@ -5,14 +5,14 @@
# 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.
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
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
Vendored
+11 -51
View File
@@ -67,14 +67,9 @@ pipeline {
MAVEN_OPTS = "-Xmx1024m"
}
stages {
stage('Build') {
stage('Test & Coverage') {
steps {
sh './mvnw -B -DskipAssembly verify --no-transfer-progress'
}
}
stage('Test') {
steps {
sh './mvnw -B verify -Pcoverage -DskipAssembly'
sh './mvnw -B verify -Pcoverage -DskipAssembly --no-transfer-progress'
}
post {
always {
@@ -91,7 +86,7 @@ pipeline {
}
steps {
withCredentials([string(credentialsId: 'asf-struts-sonarcloud', variable: 'SONARCLOUD_TOKEN')]) {
sh './mvnw -B -Pcoverage -DskipAssembly -Dsonar.login=${SONARCLOUD_TOKEN} verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar'
sh './mvnw -B -Pcoverage -DskipAssembly -Dsonar.login=${SONARCLOUD_TOKEN} verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar --no-transfer-progress'
}
}
}
@@ -103,7 +98,7 @@ pipeline {
dir("local-snapshots-dir/") {
deleteDir()
}
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly'
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly --no-transfer-progress'
}
}
stage('Deploy Snapshot') {
@@ -112,7 +107,7 @@ pipeline {
}
steps {
withCredentials([file(credentialsId: 'lukaszlenart-repository-access-token', variable: 'CUSTOM_SETTINGS')]) {
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly'
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly --no-transfer-progress'
}
}
}
@@ -121,7 +116,7 @@ pipeline {
branch 'release/struts-7-0-x'
}
steps {
sh './mvnw -B package -DskipTests'
sh './mvnw -B package -DskipTests --no-transfer-progress'
sshPublisher(publishers: [
sshPublisherDesc(
configName: 'Nightlies',
@@ -145,41 +140,6 @@ pipeline {
}
}
}
stage('JDK 11') {
agent {
label 'ubuntu'
}
tools {
jdk 'jdk_11_latest'
maven 'maven_3_latest'
}
environment {
MAVEN_OPTS = "-Xmx1024m"
}
stages {
stage('Build') {
steps {
sh './mvnw -B -DskipAssembly verify --no-transfer-progress'
}
}
stage('Test') {
steps {
sh './mvnw -B test'
}
post {
always {
junit(testResults: '**/surefire-reports/*.xml', allowEmptyResults: true)
junit(testResults: '**/failsafe-reports/*.xml', allowEmptyResults: true)
}
}
}
}
post {
always {
cleanWs deleteDirs: true, patterns: [[pattern: '**/target/**', type: 'INCLUDE']]
}
}
}
stage('JDK 8') {
agent {
label 'ubuntu'
@@ -194,12 +154,12 @@ pipeline {
stages {
stage('Build') {
steps {
sh './mvnw -B clean install -DskipTests -DskipAssembly'
sh './mvnw -B clean install -DskipTests -DskipAssembly --no-transfer-progress'
}
}
stage('Test') {
steps {
sh './mvnw -B test'
sh './mvnw -B verify --no-transfer-progress'
}
post {
always {
@@ -216,7 +176,7 @@ pipeline {
dir("local-snapshots-dir/") {
deleteDir()
}
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly'
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly --no-transfer-progress'
}
}
stage('Deploy Snapshot') {
@@ -225,7 +185,7 @@ pipeline {
}
steps {
withCredentials([file(credentialsId: 'lukaszlenart-repository-access-token', variable: 'CUSTOM_SETTINGS')]) {
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly'
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly --no-transfer-progress'
}
}
}
@@ -234,7 +194,7 @@ pipeline {
branch 'master'
}
steps {
sh './mvnw -B package -DskipTests'
sh './mvnw -B package -DskipTests --no-transfer-progress'
sshPublisher(publishers: [
sshPublisherDesc(
configName: 'Nightlies',
+1 -1
View File
@@ -17,7 +17,7 @@
The Apache Struts web framework
-------------------------------
[![Jenkins Build](https://builds.apache.org/buildStatus/icon?job=Struts%2FStruts+Core%2Fmaster)](https://ci-builds.apache.org/job/Struts/job/Struts%20Core/job/master/)
[![Build Status](https://ci-builds.apache.org/buildStatus/icon?job=Struts%2FStruts+Core%2Fmaster)](https://ci-builds.apache.org/job/Struts/job/Struts%20Core/job/master/)
[![Java Build](https://github.com/apache/struts/actions/workflows/maven.yml/badge.svg)](https://github.com/apache/struts/actions/workflows/maven.yml)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.struts/struts2-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.apache.struts/struts2-core/)
[![Javadocs](https://javadoc.io/badge/org.apache.struts/struts2-core.svg)](https://javadoc.io/doc/org.apache.struts/struts2-core)
+6 -6
View File
@@ -2,13 +2,13 @@
## Supported Versions
Please vist the [Releases](https://struts.apache.org/releases.html#prior-releases) page to see full information about each version
Please visit the [Releases](https://struts.apache.org/releases.html#prior-releases) page to see full information about each version
and what potential vulnerability it can have:
| Version | Supported |
| ------- | ------------------ |
| 6.0.0 | :white_check_mark: |
| 2.5.30 | :white_check_mark: |
|---------|--------------------|
| 6.x | :white_check_mark: |
| 2.5.x | :white_check_mark: |
## Reporting New Security Issues with thr Apache Struts
@@ -28,8 +28,8 @@ All mail sent to this address that does not relate to security problems in the A
```
Note that all networked servers are subject to denial of service attacks, and we cannot promise magic
workarounds to generic problems (such as a client streaming lots of data to your server, or re-requesting
the same URL repeatedly). In general our philosophy is to avoid any attacks which can cause the server
workarounds to generic problems (such as a client streaming lots of data to your server, or requesting
the same URL repeatedly). In general, our philosophy is to avoid any attacks that can cause the server
to consume resources in a non-linear relationship to the size of inputs.
The mailing address is: [security@struts.apache.org](mailto:security@struts.apache.org)
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-apps</artifactId>
<packaging>pom</packaging>
+2 -2
View File
@@ -24,12 +24,12 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-apps</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-rest-showcase</artifactId>
<packaging>war</packaging>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
<name>Struts 2 Rest Showcase Webapp</name>
<description>Struts 2 Rest Showcase Example</description>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-apps</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-showcase</artifactId>
@@ -24,9 +24,15 @@ import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Validateable;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import java.io.File;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*/
@@ -89,6 +95,7 @@ public class UITagExample extends ActionSupport implements Validateable {
return leftSideCartoonCharacters;
}
@StrutsParameter
public void setLeftSideCartoonCharacters(List leftSideCartoonCharacters) {
this.leftSideCartoonCharacters = leftSideCartoonCharacters;
}
@@ -98,6 +105,7 @@ public class UITagExample extends ActionSupport implements Validateable {
return rightSideCartoonCharacters;
}
@StrutsParameter
public void setRightSideCartoonCharacters(List rightSideCartoonCharacters) {
this.rightSideCartoonCharacters = rightSideCartoonCharacters;
}
@@ -107,6 +115,7 @@ public class UITagExample extends ActionSupport implements Validateable {
return favouriteVehicalType;
}
@StrutsParameter
public void setFavouriteVehicalType(String favouriteVehicalType) {
this.favouriteVehicalType = favouriteVehicalType;
}
@@ -115,6 +124,7 @@ public class UITagExample extends ActionSupport implements Validateable {
return favouriteVehicalSpecific;
}
@StrutsParameter
public void setFavouriteVehicalSpecific(String favouriteVehicalSpecific) {
this.favouriteVehicalSpecific = favouriteVehicalSpecific;
}
@@ -145,6 +155,7 @@ public class UITagExample extends ActionSupport implements Validateable {
return name;
}
@StrutsParameter
public void setName(String name) {
this.name = name;
}
@@ -153,6 +164,7 @@ public class UITagExample extends ActionSupport implements Validateable {
return birthday;
}
@StrutsParameter
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@@ -161,6 +173,7 @@ public class UITagExample extends ActionSupport implements Validateable {
return bio;
}
@StrutsParameter
public void setBio(String bio) {
this.bio = bio;
}
@@ -169,6 +182,7 @@ public class UITagExample extends ActionSupport implements Validateable {
return favouriteColor;
}
@StrutsParameter
public void setFavouriteColor(String favoriteColor) {
this.favouriteColor = favoriteColor;
}
@@ -177,6 +191,7 @@ public class UITagExample extends ActionSupport implements Validateable {
return friends;
}
@StrutsParameter
public void setFriends(List friends) {
this.friends = friends;
}
@@ -193,6 +208,7 @@ public class UITagExample extends ActionSupport implements Validateable {
return legalAge;
}
@StrutsParameter
public void setLegalAge(boolean legalAge) {
this.legalAge = legalAge;
}
@@ -201,6 +217,7 @@ public class UITagExample extends ActionSupport implements Validateable {
return state;
}
@StrutsParameter
public void setState(String state) {
this.state = state;
}
@@ -209,6 +226,7 @@ public class UITagExample extends ActionSupport implements Validateable {
return region;
}
@StrutsParameter
public void setRegion(String region) {
this.region = region;
}
@@ -229,6 +247,7 @@ public class UITagExample extends ActionSupport implements Validateable {
this.pictureFileName = pictureFileName;
}
@StrutsParameter
public void setFavouriteLanguage(String favouriteLanguage) {
this.favouriteLanguage = favouriteLanguage;
}
@@ -237,7 +256,7 @@ public class UITagExample extends ActionSupport implements Validateable {
return favouriteLanguage;
}
@StrutsParameter
public void setThoughts(String thoughts) {
this.thoughts = thoughts;
}
@@ -250,6 +269,7 @@ public class UITagExample extends ActionSupport implements Validateable {
return wakeup;
}
@StrutsParameter
public void setWakeup(Date wakeup) {
this.wakeup = wakeup;
}
@@ -0,0 +1,133 @@
/*
* 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.showcase.action;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import org.apache.struts2.showcase.model.MyDto;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
/**
* This class supports {@link com.atlassian.confluence.stateless.webdriver.selenium3.security.StrutsParametersTest}
* which prevents critical security regressions. Do NOT modify without understanding the motivation behind the tests and
* the implications of any changes.
*/
public class ParamsAnnotationAction extends ActionSupport {
@StrutsParameter
public String varToPrint;
public String publicField = "no";
@StrutsParameter
public String publicFieldAnnotated = "no";
private String privateField = "no";
public int[] publicArray = new int[]{0};
@StrutsParameter(depth = 1)
public int[] publicArrayAnnotated = new int[]{0};
public List<String> publicList = new ArrayList<>(singletonList("no"));
@StrutsParameter(depth = 1)
public List<String> publicListAnnotated = new ArrayList<>(singletonList("no"));
private List<String> privateList = new ArrayList<>(singletonList("no"));
public Map<String, String> publicMap = new HashMap<>(singletonMap("key", "no"));
@StrutsParameter(depth = 1)
public Map<String, String> publicMapAnnotated = new HashMap<>(singletonMap("key", "no"));
public MyDto publicMyDto = new MyDto();
@StrutsParameter(depth = 2)
public MyDto publicMyDtoAnnotated = new MyDto();
@StrutsParameter(depth = 1)
public MyDto publicMyDtoAnnotatedDepthOne = new MyDto();
private MyDto privateMyDto = new MyDto();
public void setPrivateFieldMethod(String privateField) {
this.privateField = privateField;
}
@StrutsParameter
public void setPrivateFieldMethodAnnotated(String privateField) {
this.privateField = privateField;
}
public List<String> getPrivateListMethod() {
return privateList;
}
@StrutsParameter(depth = 1)
public List<String> getPrivateListMethodAnnotated() {
return privateList;
}
public MyDto getUnsafeMethodMyDto() {
return privateMyDto;
}
@StrutsParameter(depth = 2)
public MyDto getSafeMethodMyDto() {
return privateMyDto;
}
@StrutsParameter(depth = 1)
public MyDto getSafeMethodMyDtoDepthOne() {
return privateMyDto;
}
public String renderVarToPrint() throws ReflectiveOperationException {
if (varToPrint == null) {
return "null";
}
Field field = this.getClass().getDeclaredField(varToPrint);
field.setAccessible(true);
try {
return String.format("%s{%s}", varToPrint,
field.getType().isArray() ? stringifyArray(field.get(this)) : field.get(this));
} finally {
field.setAccessible(false);
}
}
private String stringifyArray(Object array) {
switch (array.getClass().getComponentType().getName()) {
case "int":
return Arrays.toString((int[]) array);
default:
return "TODO";
}
}
}
@@ -21,6 +21,7 @@ package org.apache.struts2.showcase.action;
import com.opensymphony.xwork2.Preparable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import org.apache.struts2.showcase.dao.Dao;
import org.apache.struts2.showcase.dao.SkillDao;
import org.apache.struts2.showcase.model.Skill;
@@ -71,6 +72,7 @@ public class SkillAction extends AbstractCRUDAction implements Preparable {
return skillDao;
}
@StrutsParameter(depth = 1)
public Skill getCurrentSkill() {
return currentSkill;
}
@@ -19,6 +19,7 @@
package org.apache.struts2.showcase.async;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import java.util.ArrayList;
import java.util.List;
@@ -34,10 +35,12 @@ public class ChatRoomAction extends ActionSupport {
private static final List<String> messages = new ArrayList<>();
@StrutsParameter
public void setMessage(String message) {
this.message = message;
}
@StrutsParameter
public void setLastIndex(Integer lastIndex) {
this.lastIndex = lastIndex;
}
@@ -21,6 +21,7 @@
package org.apache.struts2.showcase.conversion;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -30,7 +31,7 @@ import java.util.Set;
*/
public class AddressAction extends ActionSupport {
private Set<Address> addresses = new LinkedHashSet<Address>();
private Set<Address> addresses = new LinkedHashSet<>();
public String input() throws Exception {
return SUCCESS;
@@ -41,6 +42,7 @@ public class AddressAction extends ActionSupport {
return SUCCESS;
}
@StrutsParameter(depth = 2)
public Set<Address> getAddresses() {
return addresses;
}
@@ -21,6 +21,7 @@
package org.apache.struts2.showcase.conversion;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import java.util.Arrays;
import java.util.LinkedList;
@@ -47,6 +48,7 @@ public class OperationsEnumAction extends ActionSupport {
return this.selectedOperations;
}
@StrutsParameter
public void setSelectedOperations(List<OperationsEnum> selectedOperations) {
this.selectedOperations = selectedOperations;
}
@@ -21,6 +21,7 @@
package org.apache.struts2.showcase.conversion;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import java.util.List;
@@ -36,6 +37,7 @@ public class PersonAction extends ActionSupport {
return SUCCESS;
}
@StrutsParameter(depth = 2)
public List<Person> getPersons() {
return persons;
}
@@ -22,6 +22,7 @@ package org.apache.struts2.showcase.filedownload;
import com.opensymphony.xwork2.Action;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import java.io.InputStream;
@@ -38,6 +39,7 @@ public class FileDownloadAction implements Action {
return SUCCESS;
}
@StrutsParameter
public void setInputPath(String value) {
inputPath = sanitizeInputPath(value);
}
@@ -23,6 +23,7 @@ package org.apache.struts2.showcase.fileupload;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.action.UploadedFilesAware;
import org.apache.struts2.dispatcher.multipart.UploadedFile;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import java.util.List;
@@ -65,6 +66,7 @@ public class FileUploadAction extends ActionSupport implements UploadedFilesAwar
return caption;
}
@StrutsParameter
public void setCaption(String caption) {
this.caption = caption;
}
@@ -22,61 +22,51 @@
package org.apache.struts2.showcase.fileupload;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.action.UploadedFilesAware;
import org.apache.struts2.dispatcher.multipart.UploadedFile;
import java.io.File;
import java.util.List;
/**
* Showcase action - mutiple file upload using array.
*
* @version $Date$ $Id$
*/
public class MultipleFileUploadUsingArrayAction extends ActionSupport {
public class MultipleFileUploadUsingArrayAction extends ActionSupport implements UploadedFilesAware {
private File[] uploads = new File[0];
private String[] uploadFileNames = new String[0];
private String[] uploadContentTypes = new String[0];
private List<UploadedFile> uploadedFiles;
public String upload() throws Exception {
System.out.println("\n\n upload2");
System.out.println("files:");
for (UploadedFile u : uploadedFiles) {
System.out.println("*** " + u + "\t" + u.length());
}
System.out.println("filenames:");
for (String n : getUploadFileNames()) {
System.out.println("*** " + n);
}
System.out.println("content types:");
for (String c : getUploadContentTypes()) {
System.out.println("*** " + c);
}
System.out.println("\n\n");
return SUCCESS;
}
public String upload() throws Exception {
System.out.println("\n\n upload2");
System.out.println("files:");
for (File u : uploads) {
System.out.println("*** " + u + "\t" + u.length());
}
System.out.println("filenames:");
for (String n : uploadFileNames) {
System.out.println("*** " + n);
}
System.out.println("content types:");
for (String c : uploadContentTypes) {
System.out.println("*** " + c);
}
System.out.println("\n\n");
return SUCCESS;
}
@Override
public void withUploadedFiles(List<UploadedFile> uploadedFiles) {
this.uploadedFiles = uploadedFiles;
}
public File[] getUpload() {
return this.uploads;
}
private String[] getUploadFileNames() {
return this.uploadedFiles.stream()
.map(UploadedFile::getOriginalName)
.toArray(String[]::new);
}
public void setUpload(File[] upload) {
this.uploads = upload;
}
private String[] getUploadContentTypes() {
return this.uploadedFiles.stream()
.map(UploadedFile::getContentType)
.toArray(String[]::new);
}
public String[] getUploadFileName() {
return this.uploadFileNames;
}
public void setUploadFileName(String[] uploadFileName) {
this.uploadFileNames = uploadFileName;
}
public String[] getUploadContentType() {
return this.uploadContentTypes;
}
public void setUploadContentType(String[] uploadContentType) {
this.uploadContentTypes = uploadContentType;
}
}
// END SNIPPET: entire-file
@@ -22,64 +22,56 @@
package org.apache.struts2.showcase.fileupload;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.action.UploadedFilesAware;
import org.apache.struts2.dispatcher.multipart.UploadedFile;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* Showcase action - multiple file upload using List
*
* @version $Date$ $Id$
*/
public class MultipleFileUploadUsingListAction extends ActionSupport {
public class MultipleFileUploadUsingListAction extends ActionSupport implements UploadedFilesAware {
private List<File> uploads = new ArrayList<>();
private List<String> uploadFileNames = new ArrayList<>();
private List<String> uploadContentTypes = new ArrayList<>();
private List<UploadedFile> uploads = new ArrayList<>();
public List<UploadedFile> getUpload() {
return this.uploads;
}
public List<File> getUpload() {
return this.uploads;
}
@Override
public void withUploadedFiles(List<UploadedFile> uploads) {
this.uploads = uploads;
}
public void setUpload(List<File> uploads) {
this.uploads = uploads;
}
private List<String> getUploadFileNames() {
return this.uploads.stream()
.map(UploadedFile::getOriginalName)
.collect(Collectors.toList());
}
public List<String> getUploadFileName() {
return this.uploadFileNames;
}
private List<String> getUploadContentTypes() {
return this.uploads.stream()
.map(UploadedFile::getContentType)
.collect(Collectors.toList());
}
public void setUploadFileName(List<String> uploadFileNames) {
this.uploadFileNames = uploadFileNames;
}
public List<String> getUploadContentType() {
return this.uploadContentTypes;
}
public void setUploadContentType(List<String> contentTypes) {
this.uploadContentTypes = contentTypes;
}
public String upload() throws Exception {
System.out.println("\n\n upload1");
System.out.println("files:");
for (File u : uploads) {
System.out.println("*** " + u + "\t" + u.length());
}
System.out.println("filenames:");
for (String n : uploadFileNames) {
System.out.println("*** " + n);
}
System.out.println("content types:");
for (String c : uploadContentTypes) {
System.out.println("*** " + c);
}
System.out.println("\n\n");
return SUCCESS;
}
}
// END SNIPPET: entire-file
public String upload() throws Exception {
System.out.println("\n\n upload1");
System.out.println("files:");
for (UploadedFile u : uploads) {
System.out.println("*** " + u + "\t" + u.length());
}
System.out.println("filenames:");
for (String n : getUploadFileNames()) {
System.out.println("*** " + n);
}
System.out.println("content types:");
for (String c : getUploadContentTypes()) {
System.out.println("*** " + c);
}
System.out.println("\n\n");
return SUCCESS;
}
}
@@ -0,0 +1,38 @@
/*
* 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.showcase.model;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import static java.util.Collections.singletonMap;
public class MyDto {
public String str = "no";
public Map<String, String> map = new HashMap<>(singletonMap("key", "no"));
public int[] array = new int[]{0};
@Override
public String toString() {
return "str=" + str + ", map=" + map + ", array=" + Arrays.toString(array);
}
}
@@ -20,6 +20,8 @@
*/
package org.apache.struts2.showcase.validation;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
import java.sql.Date;
/**
@@ -44,6 +46,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
return dateValidatorField;
}
@StrutsParameter
public void setDateValidatorField(Date dateValidatorField) {
this.dateValidatorField = dateValidatorField;
}
@@ -52,6 +55,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
return emailValidatorField;
}
@StrutsParameter
public void setEmailValidatorField(String emailValidatorField) {
this.emailValidatorField = emailValidatorField;
}
@@ -60,6 +64,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
return integerValidatorField;
}
@StrutsParameter
public void setIntegerValidatorField(Integer integerValidatorField) {
this.integerValidatorField = integerValidatorField;
}
@@ -68,6 +73,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
return regexValidatorField;
}
@StrutsParameter
public void setRegexValidatorField(String regexValidatorField) {
this.regexValidatorField = regexValidatorField;
}
@@ -76,6 +82,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
return requiredStringValidatorField;
}
@StrutsParameter
public void setRequiredStringValidatorField(String requiredStringValidatorField) {
this.requiredStringValidatorField = requiredStringValidatorField;
}
@@ -84,6 +91,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
return requiredValidatorField;
}
@StrutsParameter
public void setRequiredValidatorField(String requiredValidatorField) {
this.requiredValidatorField = requiredValidatorField;
}
@@ -92,6 +100,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
return stringLengthValidatorField;
}
@StrutsParameter
public void setStringLengthValidatorField(String stringLengthValidatorField) {
this.stringLengthValidatorField = stringLengthValidatorField;
}
@@ -100,6 +109,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
return fieldExpressionValidatorField;
}
@StrutsParameter
public void setFieldExpressionValidatorField(
String fieldExpressionValidatorField) {
this.fieldExpressionValidatorField = fieldExpressionValidatorField;
@@ -109,6 +119,7 @@ public class FieldValidatorsExampleAction extends AbstractValidationActionSuppor
return urlValidatorField;
}
@StrutsParameter
public void setUrlValidatorField(String urlValidatorField) {
this.urlValidatorField = urlValidatorField;
}
@@ -21,6 +21,7 @@
package org.apache.struts2.showcase.wait;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.interceptor.parameter.StrutsParameter;
/**
* Example to illustrate the <code>execAndWait</code> interceptor.
@@ -41,6 +42,7 @@ public class LongProcessAction extends ActionSupport {
return time;
}
@StrutsParameter
public void setTime(int time) {
this.time = time;
}
@@ -0,0 +1,32 @@
<?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 6.0//EN"
"https://struts.apache.org/dtds/struts-6.0.dtd">
<struts>
<package name="params-annotation" extends="velocity-default" namespace="/paramsannotation">
<action name="test" class="org.apache.struts2.showcase.action.ParamsAnnotationAction">
<result type="velocity">/WEB-INF/paramsannotation.vm</result>
</action>
</package>
</struts>
+3 -11
View File
@@ -35,17 +35,7 @@
<constant name="struts.action.extension" value="action,," />
<constant name="struts.allowlist.enable" value="true" />
<constant name="struts.allowlist.packageNames"
value="
org.apache.struts2.showcase.model,
org.apache.struts2.showcase.conversion
"/>
<constant name="struts.allowlist.classes"
value="
org.apache.struts2.showcase.UITagExample$Language,
org.apache.struts2.showcase.UITagExample$VehicalType,
org.apache.struts2.showcase.UITagExample$VehicalSpecific
"/>
<constant name="struts.parameters.requireAnnotations" value="true" />
<constant name="struts.convention.package.locators.basePackage" value="org.apache.struts2.showcase" />
<constant name="struts.convention.result.path" value="/WEB-INF" />
@@ -93,6 +83,8 @@
<include file="struts-dispatcher.xml" />
<include file="struts-params-annotation.xml" />
<package name="default" extends="struts-default">
<interceptors>
<interceptor-stack name="crudStack">
@@ -0,0 +1,19 @@
#*
* 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.
*#
<div id="output">$action.renderVarToPrint()</div>
@@ -0,0 +1,239 @@
/*
* 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.HtmlPage;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.web.util.UriComponentsBuilder;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
public class StrutsParametersTest {
private WebClient webClient;
@Before
public void setUp() throws Exception {
webClient = new WebClient();
}
@After
public void tearDown() throws Exception {
webClient.close();
}
@Test
public void public_StringField_WithoutGetterSetter_FieldNotAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("publicField", "yes");
params.put("varToPrint", "publicField");
assertText(params, "publicField{no}");
}
@Test
public void public_StringField_WithoutGetterSetter_FieldAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("publicFieldAnnotated", "yes");
params.put("varToPrint", "publicFieldAnnotated");
assertText(params, "publicFieldAnnotated{yes}");
}
@Test
public void private_StringField_WithSetter_MethodNotAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("privateFieldMethod", "yes");
params.put("varToPrint", "privateField");
assertText(params, "privateField{no}");
}
@Test
public void private_StringField_WithSetter_MethodAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("privateFieldMethodAnnotated", "yes");
params.put("varToPrint", "privateField");
assertText(params, "privateField{yes}");
}
@Test
public void public_ArrayField_WithoutGetterSetter_FieldNotAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("publicArray[0]", "1");
params.put("varToPrint", "publicArray");
assertText(params, "publicArray{[0]}");
}
@Test
public void public_ArrayField_WithoutGetterSetter_FieldAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("publicArrayAnnotated[0]", "1");
params.put("varToPrint", "publicArrayAnnotated");
assertText(params, "publicArrayAnnotated{[1]}");
}
@Test
public void public_ListField_WithoutGetterSetter_FieldNotAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("publicList[0]", "yes");
params.put("varToPrint", "publicList");
assertText(params, "publicList{[no]}");
}
@Test
public void public_ListField_WithoutGetterSetter_FieldAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("publicListAnnotated[0]", "yes");
params.put("varToPrint", "publicListAnnotated");
assertText(params, "publicListAnnotated{[yes]}");
}
@Test
public void private_ListField_WithGetterNoSetter_MethodNotAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("privateListMethod[0]", "yes");
params.put("varToPrint", "privateList");
assertText(params, "privateList{[no]}");
}
@Test
public void private_ListField_WithGetterNoSetter_MethodAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("privateListMethodAnnotated[0]", "yes");
params.put("varToPrint", "privateList");
assertText(params, "privateList{[yes]}");
}
@Test
public void public_MapField_WithoutGetterSetter_FieldNotAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("publicMap['key']", "yes");
params.put("varToPrint", "publicMap");
assertText(params, "publicMap{{key=no}}");
}
@Test
public void public_MapField_WithoutGetterSetter_FieldAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("publicMapAnnotated['key']", "yes");
params.put("varToPrint", "publicMapAnnotated");
assertText(params, "publicMapAnnotated{{key=yes}}");
}
@Test
public void public_MapField_Insert_WithoutGetterSetter_FieldNotAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("publicMap[999]", "yes");
params.put("varToPrint", "publicMap");
assertText(params, "publicMap{{key=no}}");
}
@Test
public void public_MapField_Insert_WithoutGetterSetter_FieldAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("publicMapAnnotated[999]", "yes");
params.put("varToPrint", "publicMapAnnotated");
assertText(params, "publicMapAnnotated{{999=yes, key=no}}");
}
@Test
public void public_MyDtoField_WithoutGetter_FieldNotAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("publicMyDto.str", "yes");
params.put("publicMyDto.map['key']", "yes");
params.put("publicMyDto.array[0]", "1");
params.put("varToPrint", "publicMyDto");
assertText(params, "publicMyDto{str=no, map={key=no}, array=[0]}");
}
@Test
public void public_MyDtoField_WithoutGetter_FieldAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("publicMyDtoAnnotated.str", "yes");
params.put("publicMyDtoAnnotated.map['key']", "yes");
params.put("publicMyDtoAnnotated.array[0]", "1");
params.put("varToPrint", "publicMyDtoAnnotated");
assertText(params, "publicMyDtoAnnotated{str=yes, map={key=yes}, array=[1]}");
}
@Test
public void public_MyDtoField_WithoutGetter_FieldAnnotatedDepthOne() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("publicMyDtoAnnotatedDepthOne.str", "yes");
params.put("publicMyDtoAnnotatedDepthOne.map['key']", "yes");
params.put("publicMyDtoAnnotatedDepthOne.array[0]", "1");
params.put("varToPrint", "publicMyDtoAnnotatedDepthOne");
assertText(params, "publicMyDtoAnnotatedDepthOne{str=yes, map={key=no}, array=[0]}");
}
@Test
public void private_MyDtoField_WithGetter_MethodNotAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("unsafeMethodMyDto.str", "yes");
params.put("unsafeMethodMyDto.map['key']", "yes");
params.put("unsafeMethodMyDto.array[0]", "1");
params.put("varToPrint", "privateMyDto");
assertText(params, "privateMyDto{str=no, map={key=no}, array=[0]}");
}
@Test
public void private_MyDtoField_WithGetter_MethodNotAnnotated_Alternate() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("unsafeMethodMyDto['str']", "yes");
params.put("unsafeMethodMyDto['map']['key']", "yes");
params.put("unsafeMethodMyDto['map'][999]", "yes");
params.put("unsafeMethodMyDto['array'][0]", "1");
params.put("varToPrint", "privateMyDto");
assertText(params, "privateMyDto{str=no, map={key=no}, array=[0]}");
}
@Test
public void private_MyDtoField_WithGetter_MethodAnnotated() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("safeMethodMyDto.str", "yes");
params.put("safeMethodMyDto.map['key']", "yes");
params.put("safeMethodMyDto.array[0]", "1");
params.put("varToPrint", "privateMyDto");
assertText(params, "privateMyDto{str=yes, map={key=yes}, array=[1]}");
}
@Test
public void private_MyDtoField_WithGetter_MethodAnnotatedDepthOne() throws Exception {
Map<String, String> params = new HashMap<>();
params.put("safeMethodMyDtoDepthOne.str", "yes");
params.put("safeMethodMyDtoDepthOne.map['key']", "yes");
params.put("safeMethodMyDtoDepthOne.array[0]", "1");
params.put("varToPrint", "privateMyDto");
assertText(params, "privateMyDto{str=yes, map={key=no}, array=[0]}");
}
private void assertText(Map<String, String> params, String text) throws IOException {
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(ParameterUtils.getBaseUrl()).path("/paramsannotation/test.action");
params.forEach(builder::queryParam);
String url = builder.toUriString();
HtmlPage page = webClient.getPage(url);
String output = page.getElementById("output").asNormalizedText();
assertEquals(text, output);
}
}
+3 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-assembly</artifactId>
@@ -104,7 +104,9 @@
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>make-assembly</id>
+2
View File
@@ -41,6 +41,8 @@
<include>ognl:ognl</include>
<include>commons-fileupload:commons-fileupload</include>
<include>org.apache.commons:commons-io</include>
<include>com.github.ben-manes.caffeine:caffeine</include>
<include>org.javassist:javassist</include>
</includes>
</dependencySet>
</dependencySets>
+4 -4
View File
@@ -25,11 +25,11 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-bom</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
<packaging>pom</packaging>
<name>Struts 2 Bill of Materials</name>
@@ -44,7 +44,7 @@
</licenses>
<properties>
<struts-version.version>6.4.0-SNAPSHOT</struts-version.version>
<struts-version.version>6.4.0</struts-version.version>
<maven.site.skip>true</maven.site.skip>
<maven.site.deploy.skip>true</maven.site.deploy.skip>
</properties>
@@ -190,7 +190,7 @@
</dependencyManagement>
<scm>
<tag>STRUTS_6_3_0_1</tag>
<tag>STRUTS_6_4_0</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>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-osgi-bundles</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-osgi-admin-bundle</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-osgi-bundles</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-osgi-demo-bundle</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-osgi-bundles</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-core</artifactId>
<packaging>jar</packaging>
@@ -73,6 +73,16 @@ public abstract class XWorkTestCase extends TestCase {
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
}
protected void loadButSet(Map<String, ?> properties) {
loadConfigurationProviders(new StubConfigurationProvider() {
@Override
public void register(ContainerBuilder builder,
LocatableProperties props) throws ConfigurationException {
properties.forEach((k, v) -> props.setProperty(k, String.valueOf(v)));
}
});
}
protected <T> void loadButAdd(final Class<T> type, final T impl) {
loadButAdd(type, Container.DEFAULT_NAME, impl);
}
@@ -112,6 +112,7 @@ import org.apache.struts2.conversion.StrutsTypeConverterHolder;
import org.apache.struts2.ognl.OgnlGuard;
import org.apache.struts2.ognl.ProviderAllowlist;
import org.apache.struts2.ognl.StrutsOgnlGuard;
import org.apache.struts2.ognl.ThreadAllowlist;
import java.util.ArrayList;
import java.util.Collections;
@@ -395,6 +396,7 @@ public class DefaultConfiguration implements Configuration {
.factory(SecurityMemberAccess.class, Scope.PROTOTYPE)
.factory(OgnlGuard.class, StrutsOgnlGuard.class, Scope.SINGLETON)
.factory(ProviderAllowlist.class, Scope.SINGLETON)
.factory(ThreadAllowlist.class, Scope.SINGLETON)
.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON);
}
@@ -142,7 +142,9 @@ public abstract class XmlDocConfigurationProvider implements ConfigurationProvid
@Override
public void destroy() {
providerAllowlist.clearAllowlist(this);
if (providerAllowlist != null) {
providerAllowlist.clearAllowlist(this);
}
}
protected Class<?> allowAndLoadClass(String className) throws ClassNotFoundException {
@@ -26,6 +26,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.ognl.ProviderAllowlist;
import org.apache.struts2.ognl.ThreadAllowlist;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
@@ -75,6 +76,7 @@ public class SecurityMemberAccess implements MemberAccess {
)));
private final ProviderAllowlist providerAllowlist;
private final ThreadAllowlist threadAllowlist;
private boolean allowStaticFieldAccess = true;
private Set<Pattern> excludeProperties = emptySet();
private Set<Pattern> acceptProperties = emptySet();
@@ -89,8 +91,9 @@ public class SecurityMemberAccess implements MemberAccess {
private boolean disallowDefaultPackageAccess = false;
@Inject
public SecurityMemberAccess(@Inject ProviderAllowlist providerAllowlist) {
public SecurityMemberAccess(@Inject ProviderAllowlist providerAllowlist, @Inject ThreadAllowlist threadAllowlist) {
this.providerAllowlist = providerAllowlist;
this.threadAllowlist = threadAllowlist;
}
/**
@@ -99,11 +102,11 @@ public class SecurityMemberAccess implements MemberAccess {
* - block or allow access to properties (configurable-after-construction)
*
* @param allowStaticFieldAccess if set to true static fields (constants) will be accessible
* @deprecated since 6.4.0, use {@link #SecurityMemberAccess(ProviderAllowlist)} instead.
* @deprecated since 6.4.0, use {@link #SecurityMemberAccess(ProviderAllowlist, ThreadAllowlist)} instead.
*/
@Deprecated
public SecurityMemberAccess(boolean allowStaticFieldAccess) {
this(null);
this(null, null);
useAllowStaticFieldAccess(String.valueOf(allowStaticFieldAccess));
}
@@ -223,6 +226,7 @@ public class SecurityMemberAccess implements MemberAccess {
return allowlistClasses.contains(clazz)
|| ALLOWLIST_REQUIRED_CLASSES.contains(clazz)
|| (providerAllowlist != null && providerAllowlist.getProviderAllowlist().contains(clazz))
|| (threadAllowlist != null && threadAllowlist.getAllowlist().contains(clazz))
|| isClassBelongsToPackages(clazz, ALLOWLIST_REQUIRED_PACKAGES)
|| isClassBelongsToPackages(clazz, allowlistPackageNames);
}
@@ -25,12 +25,14 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableSet;
import static java.util.stream.Collectors.joining;
public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
private static final Logger LOG = LogManager.getLogger(DefaultAcceptedPatternsChecker.class);
@@ -39,6 +41,12 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
"\\w+((\\.\\w+)|(\\[\\d+])|(\\(\\d+\\))|(\\['(\\w-?|[\\u4e00-\\u9fa5]-?)+'])|(\\('(\\w-?|[\\u4e00-\\u9fa5]-?)+'\\)))*"
};
/**
* Must match {@link #ACCEPTED_PATTERNS} RegEx. Signifies characters which result in a nested lookup via OGNL.
*/
public static final Set<Character> NESTING_CHARS = unmodifiableSet(new HashSet<>(asList('.', '[', '(')));
public static final String NESTING_CHARS_STR = NESTING_CHARS.stream().map(String::valueOf).collect(joining());
public static final String[] DMI_AWARE_ACCEPTED_PATTERNS = {
"\\w+([:]?\\w+)?((\\.\\w+)|(\\[\\d+])|(\\(\\d+\\))|(\\['(\\w-?|[\\u4e00-\\u9fa5]-?)+'])|(\\('(\\w-?|[\\u4e00-\\u9fa5]-?)+'\\)))*([!]?\\w+)?"
};
@@ -74,7 +82,7 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
newAcceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
}
} finally {
acceptedPatterns = Collections.unmodifiableSet(newAcceptedPatterns);
acceptedPatterns = unmodifiableSet(newAcceptedPatterns);
}
}
@@ -85,7 +93,7 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
@Override
public void setAcceptedPatterns(String[] additionalPatterns) {
setAcceptedPatterns(new HashSet<>(Arrays.asList(additionalPatterns)));
setAcceptedPatterns(new HashSet<>(asList(additionalPatterns)));
}
@Override
@@ -97,7 +105,7 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
newAcceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
}
} finally {
acceptedPatterns = Collections.unmodifiableSet(newAcceptedPatterns);
acceptedPatterns = unmodifiableSet(newAcceptedPatterns);
}
}
@@ -469,6 +469,9 @@ public final class StrutsConstants {
public static final String STRUTS_ADDITIONAL_EXCLUDED_PATTERNS = "struts.additional.excludedPatterns";
public static final String STRUTS_ADDITIONAL_ACCEPTED_PATTERNS = "struts.additional.acceptedPatterns";
public static final String STRUTS_PARAMETERS_REQUIRE_ANNOTATIONS = "struts.parameters.requireAnnotations";
public static final String STRUTS_PARAMETERS_REQUIRE_ANNOTATIONS_TRANSITION = "struts.parameters.requireAnnotations.transitionMode";
public static final String STRUTS_CONTENT_TYPE_MATCHER = "struts.contentTypeMatcher";
public static final String STRUTS_SMI_METHOD_REGEX = "struts.strictMethodInvocation.methodRegex";
@@ -99,4 +99,10 @@ public class File extends UIBean {
public void setSize(String size) {
this.size = size;
}
@Override
@StrutsTagAttribute(description="Ignored during file upload")
public void setValue(String value) {
// ignores provided value
}
}
@@ -18,9 +18,11 @@
*/
package org.apache.struts2.components;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.ognl.ThreadAllowlist;
import org.apache.struts2.util.MakeIterator;
import org.apache.struts2.views.annotations.StrutsTag;
import org.apache.struts2.views.annotations.StrutsTagAttribute;
@@ -188,8 +190,8 @@ import java.util.List;
* <!-- START SNIPPET: example6description -->
*
* <p>Another way to create a simple loop, similar to JSTL's
* &lt;c:forEach begin="..." end="..." ...&gt; is to use some
* OGNL magic, which provides some under-the-covers magic to
* &lt;c:forEach begin="..." end="..." ...&gt; is to use some
* OGNL magic, which provides some under-the-covers magic to
* make 0-n loops trivial. This example also loops five times.</p>
*
* <!-- END SNIPPET: example6description -->
@@ -237,11 +239,17 @@ public class IteratorComponent extends ContextBean {
protected Integer end;
protected String stepStr;
protected Integer step;
private ThreadAllowlist threadAllowlist;
public IteratorComponent(ValueStack stack) {
super(stack);
}
@Inject
public void setThreadAllowlist(ThreadAllowlist threadAllowlist) {
this.threadAllowlist = threadAllowlist;
}
public boolean start(Writer writer) {
//Create an iterator status if the status attribute was set.
if (statusAttr != null) {
@@ -298,6 +306,7 @@ public class IteratorComponent extends ContextBean {
if ((iterator != null) && iterator.hasNext()) {
Object currentValue = iterator.next();
stack.push(currentValue);
threadAllowlist.allowClass(currentValue.getClass());
String var = getVar();
@@ -66,10 +66,6 @@ public class Radio extends ListUIBean {
return TEMPLATE;
}
public void evaluateExtraParams() {
super.evaluateExtraParams();
}
/**
* Radio tag requires lazy evaluation as list of tags is dynamically generated using <s:iterator/>
*
@@ -80,8 +76,4 @@ public class Radio extends ListUIBean {
return true;
}
protected Class<?> getValueClassType() {
return String.class;
}
}
@@ -151,11 +151,16 @@ public class ApplicationMap extends AbstractMap<String, Object> implements Seria
* @param key the attribute to remove.
* @return the entry that was just removed.
*/
public Object remove(final String key) {
@Override
public Object remove(Object key) {
if (key == null) {
return null;
}
entries = null;
Object value = get(key);
context.removeAttribute(key);
context.removeAttribute(key.toString());
return value;
}
@@ -68,6 +68,7 @@ import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.dispatcher.multipart.MultiPartRequest;
import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
import org.apache.struts2.ognl.ThreadAllowlist;
import org.apache.struts2.util.ObjectFactoryDestroyable;
import org.apache.struts2.util.fs.JBossFileManager;
@@ -199,6 +200,7 @@ public class Dispatcher {
private LocaleProviderFactory localeProviderFactory;
private StaticContentLoader staticContentLoader;
private ActionMapper actionMapper;
private ThreadAllowlist threadAllowlist;
/**
* Provide the dispatcher instance for the current thread.
@@ -404,6 +406,11 @@ public class Dispatcher {
return actionMapper;
}
@Inject
public void setThreadAllowlist(ThreadAllowlist threadAllowlist) {
this.threadAllowlist = threadAllowlist;
}
/**
* Releases all instances bound to this dispatcher instance.
*/
@@ -979,10 +986,12 @@ public class Dispatcher {
public HttpServletRequest wrapRequest(HttpServletRequest request) throws IOException {
// don't wrap more than once
if (request instanceof StrutsRequestWrapper) {
LOG.debug("Request already wrapped with: {}", StrutsRequestWrapper.class.getSimpleName());
return request;
}
if (isMultipartSupportEnabled(request) && isMultipartRequest(request)) {
LOG.debug("Wrapping multipart request with: {}", MultiPartRequestWrapper.class.getSimpleName());
request = new MultiPartRequestWrapper(
getMultiPartRequest(),
request,
@@ -991,6 +1000,7 @@ public class Dispatcher {
disableRequestAttributeValueStackLookup
);
} else {
LOG.debug("Wrapping request using: {}", StrutsRequestWrapper.class.getSimpleName());
request = new StrutsRequestWrapper(request, disableRequestAttributeValueStackLookup);
}
@@ -1005,6 +1015,7 @@ public class Dispatcher {
* @since 2.5.11
*/
protected boolean isMultipartSupportEnabled(HttpServletRequest request) {
LOG.debug("Support for multipart request is enabled: {}", multipartSupportEnabled);
return multipartSupportEnabled;
}
@@ -1019,9 +1030,12 @@ public class Dispatcher {
String httpMethod = request.getMethod();
String contentType = request.getContentType();
return REQUEST_POST_METHOD.equalsIgnoreCase(httpMethod) &&
contentType != null &&
multipartValidationPattern.matcher(contentType.toLowerCase(Locale.ENGLISH)).matches();
boolean isPostRequest = REQUEST_POST_METHOD.equalsIgnoreCase(httpMethod);
boolean isProperContentType = contentType != null && multipartValidationPattern.matcher(contentType.toLowerCase(Locale.ENGLISH)).matches();
LOG.debug("Validating if this is a proper Multipart request. Request is POST: {} and ContentType matches pattern ({}): {}",
isPostRequest, multipartValidationPattern, isProperContentType);
return isPostRequest && isProperContentType;
}
/**
@@ -1042,6 +1056,7 @@ public class Dispatcher {
*/
public void cleanUpRequest(HttpServletRequest request) {
ContainerHolder.clear();
threadAllowlist.clearAllowlist();
if (!(request instanceof MultiPartRequestWrapper)) {
return;
}
@@ -125,11 +125,16 @@ public class RequestMap extends AbstractMap<String, Object> implements Serializa
* @param key the name of the attribute to remove.
* @return the value that was removed or <tt>null</tt> if the value was not found (and hence, not removed).
*/
public Object remove(final String key) {
@Override
public Object remove(final Object key) {
if (key == null) {
return null;
}
entries = null;
Object value = get(key);
request.removeAttribute(key);
request.removeAttribute(key.toString());
return value;
}
@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.interceptor;
import java.util.Map;
@Deprecated
public interface ApplicationAware extends org.apache.struts2.action.ApplicationAware {
void setApplication(Map<String, Object> application);
@Override
default void withApplication(Map<String, Object> application) {
setApplication(application);
}
}
@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.interceptor;
import org.apache.struts2.dispatcher.HttpParameters;
@Deprecated
public interface HttpParametersAware extends org.apache.struts2.action.ParametersAware {
void setParameters(HttpParameters parameters);
@Override
default void withParameters(HttpParameters parameters) {
setParameters(parameters);
}
}
@@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.interceptor;
import org.apache.struts2.dispatcher.HttpParameters;
import java.util.Map;
import static java.util.stream.Collectors.toMap;
@Deprecated
public interface ParameterAware extends org.apache.struts2.action.ParametersAware {
void setParameters(Map<String, String[]> map);
@Override
default void withParameters(HttpParameters parameters) {
setParameters(parameters.entrySet().stream().collect(toMap(Map.Entry::getKey, e -> e.getValue().getMultipleValues())));
}
}
@@ -0,0 +1,30 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.interceptor;
@Deprecated
public interface PrincipalAware extends org.apache.struts2.action.PrincipalAware {
void setPrincipalProxy(PrincipalProxy principalProxy);
@Override
default void withPrincipalProxy(PrincipalProxy principalProxy) {
setPrincipalProxy(principalProxy);
}
}
@@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.interceptor;
import org.apache.struts2.dispatcher.RequestMap;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
@Deprecated
public interface RequestAware extends ServletRequestAware {
@Override
default void setServletRequest(HttpServletRequest httpServletRequest) {
// default no-op
}
@Override
default void withServletRequest(HttpServletRequest request) {
ServletRequestAware.super.withServletRequest(request);
setRequest(new RequestMap(request));
}
void setRequest(Map<String, Object> request);
}
@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.interceptor;
import javax.servlet.http.HttpServletRequest;
@Deprecated
public interface ServletRequestAware extends org.apache.struts2.action.ServletRequestAware {
void setServletRequest(HttpServletRequest httpServletRequest);
@Override
default void withServletRequest(HttpServletRequest request) {
setServletRequest(request);
}
}
@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.interceptor;
import javax.servlet.http.HttpServletResponse;
@Deprecated
public interface ServletResponseAware extends org.apache.struts2.action.ServletResponseAware {
void setServletResponse(HttpServletResponse httpServletResponse);
@Override
default void withServletResponse(HttpServletResponse response) {
setServletResponse(response);
}
}
@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.interceptor;
import java.util.Map;
@Deprecated
public interface SessionAware extends org.apache.struts2.action.SessionAware {
void setSession(Map<String, Object> session);
@Override
default void withSession(Map<String, Object> session) {
setSession(session);
}
}
@@ -43,7 +43,8 @@ public final class CspInterceptor extends AbstractInterceptor {
private static final Logger LOG = LogManager.getLogger(CspInterceptor.class);
private Boolean enforcingMode;
private boolean prependServletContext = true;
private boolean enforcingMode;
private String reportUri;
@Override
@@ -60,18 +61,23 @@ public final class CspInterceptor extends AbstractInterceptor {
}
private void applySettings(ActionInvocation invocation, CspSettings cspSettings) {
if (enforcingMode != null) {
LOG.trace("Applying: {} to enforcingMode", enforcingMode);
cspSettings.setEnforcingMode(enforcingMode);
}
if (reportUri != null) {
LOG.trace("Applying: {} to reportUri", reportUri);
cspSettings.setReportUri(reportUri);
}
HttpServletRequest request = invocation.getInvocationContext().getServletRequest();
HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
LOG.trace("Applying: {} to enforcingMode", enforcingMode);
cspSettings.setEnforcingMode(enforcingMode);
if (reportUri != null) {
LOG.trace("Applying: {} to reportUri", reportUri);
String finalReportUri = reportUri;
if (prependServletContext && (request.getContextPath() != null) && (!request.getContextPath().isEmpty())) {
finalReportUri = request.getContextPath() + finalReportUri;
}
cspSettings.setReportUri(finalReportUri);
}
invocation.addPreResultListener((actionInvocation, resultCode) -> {
LOG.trace("Applying CSP header: {} to the request", cspSettings);
cspSettings.addCspHeaders(request, response);
@@ -99,8 +105,23 @@ public final class CspInterceptor extends AbstractInterceptor {
}
}
public void setEnforcingMode(String value) {
this.enforcingMode = Boolean.parseBoolean(value);
/**
* Enables enforcing mode, by default all exceptions are only reported
*
* @param enforcingMode {@code true} to enable enforcing mode, {@code false} to keep reporting mode.
*/
public void setEnforcingMode(boolean enforcingMode) {
this.enforcingMode = enforcingMode;
}
/**
* Sets whether to prepend the servlet context path to the {@link #reportUri}.
*
* @param prependServletContext {@code true} to prepend the location with the servlet context path,
* {@code false} otherwise.
*/
public void setPrependServletContext(boolean prependServletContext) {
this.prependServletContext = prependServletContext;
}
}
@@ -25,6 +25,7 @@ import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
import com.opensymphony.xwork2.interceptor.ValidationAware;
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
import com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker;
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
import com.opensymphony.xwork2.util.ClearableValueStack;
import com.opensymphony.xwork2.util.MemberAccessValueStack;
@@ -33,6 +34,7 @@ import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.ValueStackFactory;
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ClassUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
@@ -41,17 +43,33 @@ import org.apache.struts2.action.ParameterNameAware;
import org.apache.struts2.action.ParameterValueAware;
import org.apache.struts2.dispatcher.HttpParameters;
import org.apache.struts2.dispatcher.Parameter;
import org.apache.struts2.ognl.ThreadAllowlist;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Pattern;
import static com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker.NESTING_CHARS;
import static com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker.NESTING_CHARS_STR;
import static java.util.Collections.unmodifiableSet;
import static java.util.stream.Collectors.joining;
import static org.apache.commons.lang3.StringUtils.indexOfAny;
import static org.apache.commons.lang3.StringUtils.normalizeSpace;
/**
@@ -70,8 +88,11 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
private boolean dmiEnabled = false;
protected boolean ordered = false;
protected boolean requireAnnotations = false;
protected boolean requireAnnotationsTransitionMode = false;
private ValueStackFactory valueStackFactory;
protected ThreadAllowlist threadAllowlist;
private ExcludedPatternsChecker excludedPatterns;
private AcceptedPatternsChecker acceptedPatterns;
private Set<Pattern> excludedValuePatterns = null;
@@ -82,11 +103,35 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
this.valueStackFactory = valueStackFactory;
}
@Inject
public void setThreadAllowlist(ThreadAllowlist threadAllowlist) {
this.threadAllowlist = threadAllowlist;
}
@Inject(StrutsConstants.STRUTS_DEVMODE)
public void setDevMode(String mode) {
this.devMode = BooleanUtils.toBoolean(mode);
}
@Inject(value = StrutsConstants.STRUTS_PARAMETERS_REQUIRE_ANNOTATIONS, required = false)
public void setRequireAnnotations(String requireAnnotations) {
this.requireAnnotations = BooleanUtils.toBoolean(requireAnnotations);
}
/**
* When 'Transition Mode' is enabled, parameters that are not 'nested' will be accepted without annotations. What
* this means in practice is that all public setters on an Action will be exposed for parameter injection again, and
* only 'nested' parameters, i.e. public getters on an Action, will require annotations.
* <p>
* In this mode, the OGNL auto-allowlisting capability is not degraded in any way, and as such, it offers a
* convenient option for applications to enable the OGNL allowlist capability whilst they work through the process
* of annotating all their Action parameters.
*/
@Inject(value = StrutsConstants.STRUTS_PARAMETERS_REQUIRE_ANNOTATIONS_TRANSITION, required = false)
public void setRequireAnnotationsTransitionMode(String transitionMode) {
this.requireAnnotationsTransitionMode = BooleanUtils.toBoolean(transitionMode);
}
@Inject
public void setExcludedPatterns(ExcludedPatternsChecker excludedPatterns) {
this.excludedPatterns = excludedPatterns;
@@ -295,13 +340,168 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
* @return true if parameter is accepted
*/
protected boolean isAcceptableParameter(String name, Object action) {
return acceptableName(name) && isAcceptableParameterNameAware(name, action);
return acceptableName(name) && isAcceptableParameterNameAware(name, action) && isParameterAnnotatedAndAllowlist(name, action);
}
protected boolean isAcceptableParameterNameAware(String name, Object action) {
return !(action instanceof ParameterNameAware) || ((ParameterNameAware) action).acceptableParameterName(name);
}
/**
* Checks if the Action class member corresponding to a parameter is appropriately annotated with
* {@link StrutsParameter} and OGNL allowlists any necessary classes.
* <p>
* Note that this logic relies on the use of {@link DefaultAcceptedPatternsChecker#NESTING_CHARS} and may also
* be adversely impacted by the use of custom OGNL property accessors.
*/
protected boolean isParameterAnnotatedAndAllowlist(String name, Object action) {
if (!requireAnnotations) {
return true;
}
long paramDepth = name.codePoints().mapToObj(c -> (char) c).filter(NESTING_CHARS::contains).count();
if (requireAnnotationsTransitionMode && paramDepth == 0) {
return true;
}
int nestingIndex = indexOfAny(name, NESTING_CHARS_STR);
String rootProperty = nestingIndex == -1 ? name : name.substring(0, nestingIndex);
String normalisedRootProperty = Character.toLowerCase(rootProperty.charAt(0)) + rootProperty.substring(1);
return hasValidAnnotatedMember(normalisedRootProperty, action, paramDepth);
}
/**
* Note that we check for a public field last or only if there is no valid, annotated property descriptor. This is
* because this check is likely to fail more often than not, as the relative use of public fields is low - so we
* save computation by checking this last.
*/
protected boolean hasValidAnnotatedMember(String rootProperty, Object action, long paramDepth) {
BeanInfo beanInfo = getBeanInfo(action);
if (beanInfo == null) {
return hasValidAnnotatedField(action, rootProperty, paramDepth);
}
Optional<PropertyDescriptor> propDescOpt = Arrays.stream(beanInfo.getPropertyDescriptors())
.filter(desc -> desc.getName().equals(rootProperty)).findFirst();
if (!propDescOpt.isPresent()) {
return hasValidAnnotatedField(action, rootProperty, paramDepth);
}
if (hasValidAnnotatedPropertyDescriptor(propDescOpt.get(), paramDepth)) {
return true;
}
return hasValidAnnotatedField(action, rootProperty, paramDepth);
}
protected boolean hasValidAnnotatedPropertyDescriptor(PropertyDescriptor propDesc, long paramDepth) {
Method relevantMethod = paramDepth == 0 ? propDesc.getWriteMethod() : propDesc.getReadMethod();
if (relevantMethod == null) {
return false;
}
if (getPermittedInjectionDepth(relevantMethod) < paramDepth) {
LOG.debug(
"Parameter injection for method [{}] on action [{}] rejected. Ensure it is annotated with @StrutsParameter with an appropriate 'depth'.",
relevantMethod.getName(),
relevantMethod.getDeclaringClass().getName());
return false;
}
if (paramDepth >= 1) {
allowlistClass(relevantMethod.getReturnType());
}
if (paramDepth >= 2) {
allowlistReturnTypeIfParameterized(relevantMethod);
}
return true;
}
protected void allowlistReturnTypeIfParameterized(Method method) {
allowlistParameterizedTypeArg(method.getGenericReturnType());
}
protected void allowlistParameterizedTypeArg(Type genericType) {
if (!(genericType instanceof ParameterizedType)) {
return;
}
Type[] paramTypes = ((ParameterizedType) genericType).getActualTypeArguments();
allowlistParamType(paramTypes[0]);
if (paramTypes.length > 1) {
// Probably useful for Map or Map-like classes
allowlistParamType(paramTypes[1]);
}
}
protected void allowlistParamType(Type paramType) {
if (paramType instanceof Class) {
allowlistClass((Class<?>) paramType);
}
}
protected void allowlistClass(Class<?> clazz) {
threadAllowlist.allowClass(clazz);
ClassUtils.getAllSuperclasses(clazz).forEach(threadAllowlist::allowClass);
ClassUtils.getAllInterfaces(clazz).forEach(threadAllowlist::allowClass);
}
protected boolean hasValidAnnotatedField(Object action, String fieldName, long paramDepth) {
Field field;
try {
field = action.getClass().getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
return false;
}
if (!Modifier.isPublic(field.getModifiers())) {
return false;
}
if (getPermittedInjectionDepth(field) < paramDepth) {
LOG.debug(
"Parameter injection for field [{}] on action [{}] rejected. Ensure it is annotated with @StrutsParameter with an appropriate 'depth'.",
fieldName,
action.getClass().getName());
return false;
}
if (paramDepth >= 1) {
allowlistClass(field.getType());
}
if (paramDepth >= 2) {
allowlistFieldIfParameterized(field);
}
return true;
}
protected void allowlistFieldIfParameterized(Field field) {
allowlistParameterizedTypeArg(field.getGenericType());
}
/**
* @return permitted injection depth where -1 indicates not permitted
*/
protected int getPermittedInjectionDepth(AnnotatedElement element) {
StrutsParameter annotation = getParameterAnnotation(element);
if (annotation == null) {
return -1;
}
return annotation.depth();
}
/**
* Annotation retrieval logic. Can be overridden to support extending annotations or some other form of annotation
* inheritance.
*/
protected StrutsParameter getParameterAnnotation(AnnotatedElement element) {
return element.getAnnotation(StrutsParameter.class);
}
protected BeanInfo getBeanInfo(Object action) {
try {
return Introspector.getBeanInfo(action.getClass());
} catch (IntrospectionException e) {
LOG.warn("Error introspecting Action {} for parameter injection validation", action.getClass(), e);
return null;
}
}
/**
* Checks if parameter value can be accepted or thrown away
*
@@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.interceptor.parameter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Used to annotate public getter/setter methods or fields on {@link com.opensymphony.xwork2.Action} classes that are
* intended for parameter injection by the {@link ParametersInterceptor}.
*
* @since 6.4.0
*/
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface StrutsParameter {
/**
* The depth to which parameter injection is permitted, where a depth of 0 only allows setters/fields directly on
* the action class. Setting within a POJO on an action will require a depth of 1 or more depending on the level of
* nesting within the POJO.
* <p>
* In a practical sense, the depth dictates the number of periods or brackets that can appear in the parameter name.
*/
int depth() default 0;
}
@@ -0,0 +1,51 @@
/*
* 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.ognl;
import java.util.HashSet;
import java.util.Set;
import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableSet;
/**
* Allows any bean to allowlist a class for use in OGNL expressions, for the current thread only. The allowlist can be
* cleared once any desired OGNL expressions have been evaluated.
*
* @since 6.4.0
*/
public class ThreadAllowlist {
private final ThreadLocal<Set<Class<?>>> allowlist = new ThreadLocal<>();
public void allowClass(Class<?> clazz) {
if (allowlist.get() == null) {
allowlist.set(new HashSet<>());
}
allowlist.get().add(clazz);
}
public void clearAllowlist() {
allowlist.remove();
}
public Set<Class<?>> getAllowlist() {
return allowlist.get() != null ? unmodifiableSet(allowlist.get()) : emptySet();
}
}
@@ -0,0 +1,32 @@
/*
* 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 javax.servlet.ServletContext;
@Deprecated
public interface ServletContextAware extends org.apache.struts2.action.ServletContextAware {
void setServletContext(ServletContext context);
@Override
default void withServletContext(ServletContext context) {
setServletContext(context);
}
}
@@ -18,16 +18,14 @@
*/
package org.apache.struts2.views.jsp;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.struts2.components.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import com.opensymphony.xwork2.ActionContext;
import org.apache.struts2.components.Component;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.util.ValueStack;
/**
*/
public abstract class ComponentTagSupport extends StrutsBodyTagSupport {
@@ -39,8 +37,7 @@ public abstract class ComponentTagSupport extends StrutsBodyTagSupport {
public int doEndTag() throws JspException {
component.end(pageContext.getOut(), getBody());
component = null; // Always clear component reference (since clearTagStateForTagPoolingServers() is conditional).
clearTagStateForTagPoolingServers();
return EVAL_PAGE;
return super.doEndTag();
}
@Override
@@ -49,7 +46,7 @@ public abstract class ComponentTagSupport extends StrutsBodyTagSupport {
component = getBean(stack, (HttpServletRequest) pageContext.getRequest(), (HttpServletResponse) pageContext.getResponse());
Container container = stack.getActionContext().getContainer();
container.inject(component);
populateParams();
boolean evalBody = component.start(pageContext.getOut());
@@ -62,7 +59,7 @@ public abstract class ComponentTagSupport extends StrutsBodyTagSupport {
/**
* Define method to populate component state based on the Tag parameters.
*
* <p>
* Descendants should override this method for custom behaviour, but should <em>always</em> call the ancestor method when doing so.
*/
protected void populateParams() {
@@ -71,7 +68,7 @@ public abstract class ComponentTagSupport extends StrutsBodyTagSupport {
/**
* Specialized method to populate the performClearTagStateForTagPoolingServers state of the Component to match the value set in the Tag.
*
* <p>
* Generally only unit tests would call this method directly, to avoid calling the whole populateParams() chain again after doStartTag()
* has been called. Doing that can break tag / component state behaviour, but unit tests still need a way to set the
* performClearTagStateForTagPoolingServers state for the component (which only comes into being after doStartTag() is called).
@@ -26,23 +26,29 @@ package org.apache.struts2.views.jsp;
* <li>count: iterations so far, starts on 1. count is always index + 1</li>
* <li>first: true if index == 0</li>
* <li>even: true if (index + 1) % 2 == 0</li>
* <li>last: true if current iteration is the last iteration</li>
* <li>last: true if current iteration is the last iteration</li>
* <li>odd: true if (index + 1) % 2 == 1</li>
* </ul>
* <p>Example</p>
* <pre>
* &lt;s:iterator status="status" value='{0, 1}'&gt;
* Index: &lt;s:property value="%{#status.index}" /&gt; &lt;br /&gt;
* Count: &lt;s:property value="%{#status.count}" /&gt; &lt;br /&gt;
* Index Str: &lt;s:property value="%{#status.indexStr}" /&gt; &lt;br /&gt;
* Count: &lt;s:property value="%{#status.count}" /&gt; &lt;br /&gt;
* Count Str: &lt;s:property value="%{#status.countStr}" /&gt; &lt;br /&gt;
* &lt;/s:iterator&gt;
* </pre>
*
*
* <p>will print</p>
* <pre>
* Index: 0
* Index Str: 0
* Count: 1
* Count Str: 1
* Index: 1
* Index Str: 1
* Count: 2
* Count Str: 2
* </pre>
*/
public class IteratorStatus {
@@ -56,6 +62,10 @@ public class IteratorStatus {
return state.index + 1;
}
public String getCountStr() {
return String.valueOf(state.index + 1);
}
public boolean isEven() {
return ((state.index + 1) % 2) == 0;
}
@@ -68,6 +78,10 @@ public class IteratorStatus {
return state.index;
}
public String getIndexStr() {
return String.valueOf(state.index);
}
public boolean isLast() {
return state.last;
}
+1
View File
@@ -170,6 +170,7 @@
<bean type="org.apache.struts2.ognl.OgnlGuard" name="struts"
class="org.apache.struts2.ognl.StrutsOgnlGuard"/>
<bean class="org.apache.struts2.ognl.ProviderAllowlist"/>
<bean class="org.apache.struts2.ognl.ThreadAllowlist"/>
<bean type="com.opensymphony.xwork2.util.TextParser" name="struts"
class="com.opensymphony.xwork2.util.OgnlTextParser" scope="singleton"/>
@@ -25,6 +25,9 @@
<#if parameters.href??>
href="${parameters.href?no_esc}"<#rt/>
</#if>
<#if parameters.disabled!false>
disabled="disabled"<#rt/>
</#if>
<#if parameters.tabindex??>
tabindex="${parameters.tabindex}"<#rt/>
</#if>
@@ -371,6 +371,6 @@
<td class="tag-attribute"></td>
<td class="tag-attribute">false</td>
<td class="tag-attribute">String</td>
<td class="tag-attribute">Preset the value of input element.</td>
<td class="tag-attribute">Ignored during file upload</td>
</tr>
</table>
@@ -90,43 +90,27 @@ public class OgnlValueStackTest extends XWorkTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
refreshContainerFields();
}
protected void refreshContainerFields() {
ognlUtil = container.getInstance(OgnlUtil.class);
vs = createValueStack(true);
}
private OgnlValueStack createValueStack(boolean allowStaticFieldAccess) {
OgnlValueStack stack = new OgnlValueStack(
container.getInstance(XWorkConverter.class),
(CompoundRootAccessor) container.getInstance(RootAccessor.class),
container.getInstance(TextProvider.class, "system"), allowStaticFieldAccess);
container.inject(stack);
return stack;
vs = (OgnlValueStack) container.getInstance(ValueStackFactory.class).createValueStack();
}
/**
* @return current OgnlValueStackFactory instance from current container
*/
private OgnlValueStackFactory getValueStackFactory() {
return (OgnlValueStackFactory) container.getInstance(ValueStackFactory.class);
}
/**
* Reloads container and gets a new OgnlValueStackFactory with specified new configuration.
* Reloads container and sets a new OgnlValueStackFactory with specified new configuration.
* Intended for testing OgnlValueStack instance(s) that are minimally configured.
* This should help ensure no underlying configuration/injection side-effects are responsible
* for the behaviour of fundamental access control flags).
*
* @param allowStaticField new allowStaticField configuration
* @return a new OgnlValueStackFactory with specified new configuration
*/
private OgnlValueStackFactory reloadValueStackFactory(boolean allowStaticField) {
try {
reloadTestContainerConfiguration(allowStaticField);
} catch (Exception ex) {
fail("Unable to reload container configuration and configure ognlValueStackFactory - exception: " + ex);
}
return getValueStackFactory();
private void reloadContainer(boolean allowStaticField) {
Map<String, String> properties = new HashMap<>();
properties.put(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, Boolean.toString(allowStaticField));
loadButSet(properties);
refreshContainerFields();
}
public void testExpOverridesCanStackExpUp() throws Exception {
@@ -1159,31 +1143,29 @@ public class OgnlValueStackTest extends XWorkTestCase {
* when a default configuration is used.
*/
public void testOgnlValueStackFromOgnlValueStackFactoryDefaultConfig() throws IllegalAccessException {
OgnlValueStackFactory ognlValueStackFactory = getValueStackFactory();
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
Object accessedValue;
assertTrue("OgnlValueStackFactory staticFieldAccess (default flags) not true?",
reflectField(ognlValueStack.securityMemberAccess, "allowStaticFieldAccess"));
reflectField(vs.securityMemberAccess, "allowStaticFieldAccess"));
// 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()");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
assertNull("accessed private field (result not null) ?", accessedValue);
}
@@ -1192,31 +1174,30 @@ public class OgnlValueStackTest extends XWorkTestCase {
* when static access flag is set to false.
*/
public void testOgnlValueStackFromOgnlValueStackFactoryNoStaticAccess() throws IllegalAccessException {
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(false);
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
reloadContainer(false);
Object accessedValue;
assertFalse("OgnlValueStackFactory staticFieldAccess (set false) not false?",
reflectField(ognlValueStack.securityMemberAccess, "allowStaticFieldAccess"));
reflectField(vs.securityMemberAccess, "allowStaticFieldAccess"));
// 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.
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
assertNull("accessed private field (result not null) ?", accessedValue);
}
@@ -1225,45 +1206,33 @@ public class OgnlValueStackTest extends XWorkTestCase {
* when static access flag is set to true.
*/
public void testOgnlValueStackFromOgnlValueStackFactoryAllStaticAccess() throws IllegalAccessException {
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(true);
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
reloadContainer(true);
Object accessedValue;
assertTrue("OgnlValueStackFactory staticFieldAccess (set true) not true?",
reflectField(ognlValueStack.securityMemberAccess, "allowStaticFieldAccess"));
reflectField(vs.securityMemberAccess, "allowStaticFieldAccess"));
// 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()");
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
assertNull("able to access static method (result non-null)!!!", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.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");
accessedValue = vs.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
assertNull("accessed private field (result not null) ?", accessedValue);
}
private void reloadTestContainerConfiguration(boolean allowStaticField) throws Exception {
loadConfigurationProviders(new StubConfigurationProvider() {
@Override
public void register(ContainerBuilder builder,
LocatableProperties props) throws ConfigurationException {
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, String.valueOf(allowStaticField));
}
});
ognlUtil = container.getInstance(OgnlUtil.class);
}
static class BadJavaBean {
private int count;
private int count2;
@@ -25,6 +25,7 @@ import com.opensymphony.xwork2.util.Foo;
import ognl.MemberAccess;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.struts2.ognl.ProviderAllowlist;
import org.apache.struts2.ognl.ThreadAllowlist;
import org.junit.Before;
import org.junit.Test;
@@ -54,18 +55,21 @@ public class SecurityMemberAccessTest {
private FooBar target;
protected SecurityMemberAccess sma;
private ProviderAllowlist mockedProviderAllowlist;
private ThreadAllowlist mockedThreadAllowlist;
@Before
public void setUp() throws Exception {
context = new HashMap<>();
target = new FooBar();
mockedProviderAllowlist = mock(ProviderAllowlist.class);
mockedThreadAllowlist = mock(ThreadAllowlist.class);
assignNewSma(true);
}
protected void assignNewSma(boolean allowStaticFieldAccess) {
when(mockedProviderAllowlist.getProviderAllowlist()).thenReturn(new HashSet<>());
sma = new SecurityMemberAccess(mockedProviderAllowlist);
when(mockedThreadAllowlist.getAllowlist()).thenReturn(new HashSet<>());
sma = new SecurityMemberAccess(mockedProviderAllowlist, mockedThreadAllowlist);
sma.useAllowStaticFieldAccess(String.valueOf(allowStaticFieldAccess));
}
@@ -37,6 +37,12 @@ public class User implements UserMarker {
private String email2;
private String name;
public User() {
}
public User(String name) {
this.name = name;
}
public void setCollection(Collection collection) {
this.collection = collection;
@@ -45,6 +45,7 @@ public class TestAction extends ActionSupport {
private String result;
private User user;
private String[] array;
private Object[] objectArray;
private String[][] list;
private List list2;
private List list3;
@@ -53,6 +54,7 @@ public class TestAction extends ActionSupport {
private Long id;
private List<SomeEnum> enumList;
private List<Integer> intList;
private Boolean someBool;
private final Map<String, String> texts = new HashMap<>();
@@ -134,6 +136,14 @@ public class TestAction extends ActionSupport {
this.array = array;
}
public Object[] getObjectArray() {
return objectArray;
}
public void setObjectArray(Object[] arrayObject) {
this.objectArray = arrayObject;
}
public String[][] getList() {
return list;
}
@@ -254,4 +264,12 @@ public class TestAction extends ActionSupport {
public void setIntList(List<Integer> intList) {
this.intList = intList;
}
public Boolean getSomeBool() {
return someBool;
}
public void setSomeBool(Boolean someBool) {
this.someBool = someBool;
}
}
@@ -19,23 +19,38 @@
package org.apache.struts2.components;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.test.User;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.struts2.StrutsInternalTestCase;
import org.apache.struts2.ognl.ThreadAllowlist;
import org.apache.struts2.TestAction;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
public class IteratorComponentTest extends StrutsInternalTestCase {
private ValueStack stack;
private IteratorComponent ic;
@Override
public void setUp() throws Exception {
super.setUp();
stack = ActionContext.getContext().getValueStack();
ic = new IteratorComponent(stack);
ThreadAllowlist threadAllowlist = new ThreadAllowlist();
ic.setThreadAllowlist(threadAllowlist);
}
public void testIterator() throws Exception {
// given
final ValueStack stack = ActionContext.getContext().getValueStack();
stack.push(new FooAction());
StringWriter out = new StringWriter();
IteratorComponent ic = new IteratorComponent(stack);
ic.setValue("items");
ic.setVar("val");
@@ -62,14 +77,53 @@ public class IteratorComponentTest extends StrutsInternalTestCase {
assertEquals("item1 item2 item3 item4 ", out.getBuffer().toString());
}
public void testIteratorWithBegin() throws Exception {
public void testSimpleIterator() {
// given
stack.push(new FooAction());
StringWriter out = new StringWriter();
ic.setBegin("1");
ic.setEnd("8");
ic.setStep("2");
ic.setStatus("status");
Property prop = new Property(stack);
Property status = new Property(stack);
status.setValue("#status.index");
ic.getComponentStack().push(prop);
ic.getComponentStack().push(status);
ic.getComponentStack().push(prop);
ic.getComponentStack().push(status);
ic.getComponentStack().push(prop);
ic.getComponentStack().push(status);
ic.getComponentStack().push(prop);
ic.getComponentStack().push(status);
String body = " ";
// when
assertTrue(ic.start(out));
for (int i = 0; i < 4; i++) {
status.start(out);
status.end(out, body);
prop.start(out);
prop.end(out, body);
ic.end(out, null);
}
// then
assertEquals("0 1 1 3 2 5 3 7 ", out.getBuffer().toString());
}
public void testIteratorWithBegin() {
// given
final ValueStack stack = ActionContext.getContext().getValueStack();
stack.push(new FooAction());
StringWriter out = new StringWriter();
IteratorComponent ic = new IteratorComponent(stack);
ic.setValue("items");
ic.setVar("val");
ic.setBegin("1");
@@ -94,20 +148,18 @@ public class IteratorComponentTest extends StrutsInternalTestCase {
assertEquals("item2 item3 item4 ", out.getBuffer().toString());
}
public void testIteratorWithNulls() throws Exception {
public void testIteratorWithNulls() {
// given
final ValueStack stack = ActionContext.getContext().getValueStack();
stack.push(new FooAction() {
private List items = Arrays.asList("1", "2", null, "4");
private final List<String> items = Arrays.asList("1", "2", null, "4");
public List getItems() {
public List<String> getItems() {
return items;
}
});
StringWriter out = new StringWriter();
IteratorComponent ic = new IteratorComponent(stack);
ic.setValue("items");
ic.setVar("val");
Property prop = new Property(stack);
@@ -132,15 +184,147 @@ public class IteratorComponentTest extends StrutsInternalTestCase {
assertEquals("1, 2, , 4, ", out.getBuffer().toString());
}
public void testIteratorWithDifferentLocale() {
// given
ActionContext.getContext().withLocale(new Locale("fa_IR"));
stack.push(new FooAction());
StringWriter out = new StringWriter();
ic.setBegin("1");
ic.setEnd("3");
ic.setStatus("status");
Property prop = new Property(stack);
Property status = new Property(stack);
status.setValue("#status.count");
ic.getComponentStack().push(prop);
ic.getComponentStack().push(status);
ic.getComponentStack().push(prop);
ic.getComponentStack().push(status);
ic.getComponentStack().push(prop);
ic.getComponentStack().push(status);
String body = ",";
// when
assertTrue(ic.start(out));
for (int i = 0; i < 3; i++) {
status.start(out);
status.end(out, body);
prop.start(out);
prop.end(out, body);
ic.end(out, null);
}
// then
assertEquals("1,1,2,2,3,3,", out.getBuffer().toString());
}
public void testListOfBeansIterator() {
// given
TestAction action = new TestAction();
action.setList2(new ArrayList<User>() {{
add(new User("Anton"));
add(new User("Tym"));
add(new User("Luk"));
}});
stack.push(action);
StringWriter out = new StringWriter();
ic.setValue("list2");
ic.setStatus("status");
Property prop = new Property(stack);
prop.setValue("name");
Property status = new Property(stack);
status.setValue("#status.indexStr");
ic.getComponentStack().push(status);
ic.getComponentStack().push(prop);
ic.getComponentStack().push(status);
ic.getComponentStack().push(prop);
ic.getComponentStack().push(status);
ic.getComponentStack().push(prop);
String body = ",";
// when
assertTrue(ic.start(out));
for (int i = 0; i < 3; i++) {
status.start(out);
status.end(out, body);
prop.start(out);
prop.end(out, body);
ic.end(out, null);
}
// then
assertEquals("0,Anton,1,Tym,2,Luk,", out.getBuffer().toString());
}
public void testArrayOfBeansIterator() {
// given
TestAction action = new TestAction();
action.setObjectArray(new ArrayList<User>() {{
add(new User("Anton"));
add(new User("Tym"));
add(new User("Luk"));
}}.toArray());
stack.push(action);
StringWriter out = new StringWriter();
ic.setValue("objectArray");
ic.setStatus("status");
Property prop = new Property(stack);
prop.setValue("name");
Property status = new Property(stack);
status.setValue("#status.countStr");
ic.getComponentStack().push(status);
ic.getComponentStack().push(prop);
ic.getComponentStack().push(status);
ic.getComponentStack().push(prop);
ic.getComponentStack().push(status);
ic.getComponentStack().push(prop);
String body = " ";
// when
assertTrue(ic.start(out));
for (int i = 0; i < 3; i++) {
status.start(out);
status.end(out, body);
prop.start(out);
prop.end(out, body);
ic.end(out, null);
}
// then
assertEquals("1 Anton 2 Tym 3 Luk ", out.getBuffer().toString());
}
static class FooAction {
private List items;
private final List<String> items;
public FooAction() {
items = Arrays.asList("item1", "item2", "item3", "item4");
}
public List getItems() {
public List<String> getItems() {
return items;
}
}
@@ -22,6 +22,7 @@ import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.mock.MockActionInvocation;
import org.apache.logging.log4j.util.Strings;
import org.apache.struts2.StrutsInternalTestCase;
import org.apache.struts2.TestAction;
import org.apache.struts2.action.CspSettingsAware;
import org.apache.struts2.dispatcher.SessionMap;
import org.apache.struts2.interceptor.csp.CspInterceptor;
@@ -45,7 +46,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
public void test_whenRequestReceived_thenNonceIsSetInSession_andCspHeaderContainsIt() throws Exception {
String reportUri = "/barfoo";
String reporting = "false";
boolean reporting = false;
interceptor.setReportUri(reportUri);
interceptor.setEnforcingMode(reporting);
@@ -58,7 +59,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
public void test_whenNonceAlreadySetInSession_andRequestReceived_thenNewNonceIsSet() throws Exception {
String reportUri = "https://www.google.com/";
String enforcingMode = "true";
boolean enforcingMode = true;
interceptor.setReportUri(reportUri);
interceptor.setEnforcingMode(enforcingMode);
session.setAttribute("nonce", "foo");
@@ -73,7 +74,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
public void testEnforcingCspHeadersSet() throws Exception {
String reportUri = "/csp-reports";
String enforcingMode = "true";
boolean enforcingMode = true;
interceptor.setReportUri(reportUri);
interceptor.setEnforcingMode(enforcingMode);
session.setAttribute("nonce", "foo");
@@ -88,7 +89,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
public void testReportingCspHeadersSet() throws Exception {
String reportUri = "/csp-reports";
String enforcingMode = "false";
boolean enforcingMode = false;
interceptor.setReportUri(reportUri);
interceptor.setEnforcingMode(enforcingMode);
session.setAttribute("nonce", "foo");
@@ -101,7 +102,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
}
public void test_uriSetOnlyWhenSetIsCalled() throws Exception {
String enforcingMode = "false";
boolean enforcingMode = false;
interceptor.setEnforcingMode(enforcingMode);
interceptor.intercept(mai);
@@ -115,7 +116,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
}
public void testCannotParseUri() {
String enforcingMode = "false";
boolean enforcingMode = false;
interceptor.setEnforcingMode(enforcingMode);
try {
@@ -127,7 +128,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
}
public void testCannotParseRelativeUri() {
String enforcingMode = "false";
boolean enforcingMode = false;
interceptor.setEnforcingMode(enforcingMode);
try {
@@ -139,13 +140,41 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
}
public void testCustomPreResultListener() throws Exception {
boolean enforcingMode = false;
mai.setAction(new CustomerCspAction("/report-uri"));
interceptor.setEnforcingMode("false");
interceptor.setEnforcingMode(enforcingMode);
interceptor.intercept(mai);
checkHeader("/report-uri", "false");
checkHeader("/report-uri", enforcingMode);
}
public void checkHeader(String reportUri, String enforcingMode) {
public void testPrependContext() throws Exception {
boolean enforcingMode = true;
mai.setAction(new TestAction());
request.setContextPath("/app");
interceptor.setEnforcingMode(enforcingMode);
interceptor.setReportUri("/report-uri");
interceptor.intercept(mai);
checkHeader("/app/report-uri", enforcingMode);
}
public void testNoPrependContext() throws Exception {
boolean enforcingMode = true;
mai.setAction(new TestAction());
request.setContextPath("/app");
interceptor.setEnforcingMode(enforcingMode);
interceptor.setReportUri("/report-uri");
interceptor.setPrependServletContext(false);
interceptor.intercept(mai);
checkHeader("/report-uri", enforcingMode);
}
public void checkHeader(String reportUri, boolean enforcingMode) {
String expectedCspHeader;
if (Strings.isEmpty(reportUri)) {
expectedCspHeader = String.format("%s '%s'; %s 'nonce-%s' '%s' %s %s; %s '%s'; ",
@@ -163,7 +192,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
}
String header;
if (enforcingMode.equals("true")) {
if (enforcingMode) {
header = response.getHeader(CspSettings.CSP_ENFORCE_HEADER);
} else {
header = response.getHeader(CspSettings.CSP_REPORT_HEADER);
@@ -112,7 +112,7 @@ public class StrutsBackgroundProcessTest extends StrutsInternalTestCase {
executor.execute(bp);
}
Thread.sleep(500);
Thread.sleep(800);
for (BackgroundProcess bp : bps) {
assertTrue("Process is still active: " + bp, bp.isDone());
@@ -0,0 +1,348 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.interceptor.parameter;
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
import org.apache.commons.lang3.ClassUtils;
import org.apache.struts2.dispatcher.HttpParameters;
import org.apache.struts2.dispatcher.Parameter;
import org.apache.struts2.ognl.ThreadAllowlist;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class StrutsParameterAnnotationTest {
private ParametersInterceptor parametersInterceptor;
private ThreadAllowlist threadAllowlist;
@Before
public void setUp() throws Exception {
parametersInterceptor = new ParametersInterceptor();
parametersInterceptor.setRequireAnnotations(Boolean.TRUE.toString());
threadAllowlist = new ThreadAllowlist();
parametersInterceptor.setThreadAllowlist(threadAllowlist);
NotExcludedAcceptedPatternsChecker checker = mock(NotExcludedAcceptedPatternsChecker.class);
when(checker.isAccepted(anyString())).thenReturn(AcceptedPatternsChecker.IsAccepted.yes(""));
when(checker.isExcluded(anyString())).thenReturn(NotExcludedAcceptedPatternsChecker.IsExcluded.no(new HashSet<>()));
parametersInterceptor.setAcceptedPatterns(checker);
parametersInterceptor.setExcludedPatterns(checker);
}
@After
public void tearDown() throws Exception {
threadAllowlist.clearAllowlist();
}
private void testParameter(Object action, String paramName, boolean shouldContain) {
Map<String, String[]> requestParamMap = new HashMap<>();
requestParamMap.put(paramName, new String[]{"value"});
HttpParameters httpParameters = HttpParameters.create(requestParamMap).build();
Map<String, Parameter> acceptedParameters = parametersInterceptor.toAcceptableParameters(httpParameters, action);
if (shouldContain) {
assertThat(acceptedParameters).containsOnlyKeys(paramName);
} else {
assertThat(acceptedParameters).isEmpty();
assertThat(threadAllowlist.getAllowlist()).isEmpty();
}
}
private Set<Class<?>> getParentClasses(Class<?> ...clazzes) {
Set<Class<?>> set = new HashSet<>();
for (Class<?> clazz : clazzes) {
set.add(clazz);
set.addAll(ClassUtils.getAllSuperclasses(clazz));
set.addAll(ClassUtils.getAllInterfaces(clazz));
}
return set;
}
@Test
public void privateStrAnnotated() {
testParameter(new FieldAction(), "privateStr", false);
}
@Test
public void publicStrAnnotated() {
testParameter(new FieldAction(), "publicStr", true);
assertThat(threadAllowlist.getAllowlist()).isEmpty();
}
@Test
public void publicStrNotAnnotated() {
testParameter(new FieldAction(), "publicStrNotAnnotated", false);
}
@Test
public void privatePojoAnnotated() {
testParameter(new FieldAction(), "privatePojo.key", false);
}
@Test
public void publicPojoDepthZero() {
testParameter(new FieldAction(), "publicPojoDepthZero.key", false);
}
@Test
public void publicPojoDepthOne() {
testParameter(new FieldAction(), "publicPojoDepthOne.key", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
}
@Test
public void publicPojoDepthOne_sqrBracket() {
testParameter(new FieldAction(), "publicPojoDepthOne['key']", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
}
@Test
public void publicPojoDepthOne_bracket() {
testParameter(new FieldAction(), "publicPojoDepthOne('key')", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
}
@Test
public void publicNestedPojoDepthOne() {
testParameter(new FieldAction(), "publicPojoDepthOne.key.key", false);
}
@Test
public void publicPojoDepthTwo() {
testParameter(new FieldAction(), "publicPojoDepthTwo.key", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
}
@Test
public void publicNestedPojoDepthTwo() {
testParameter(new FieldAction(), "publicPojoDepthTwo.key.key", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
}
@Test
public void publicNestedPojoDepthTwo_sqrBracket() {
testParameter(new FieldAction(), "publicPojoDepthTwo['key']['key']", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
}
@Test
public void publicNestedPojoDepthTwo_bracket() {
testParameter(new FieldAction(), "publicPojoDepthTwo('key')('key')", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
}
@Test
public void privateStrAnnotatedMethod() {
testParameter(new MethodAction(), "privateStr", false);
}
@Test
public void publicStrAnnotatedMethod() {
testParameter(new MethodAction(), "publicStr", true);
assertThat(threadAllowlist.getAllowlist()).isEmpty();
}
@Test
public void publicStrNotAnnotatedMethod() {
testParameter(new MethodAction(), "publicStrNotAnnotated", false);
}
@Test
public void privatePojoAnnotatedMethod() {
testParameter(new MethodAction(), "privatePojo.key", false);
}
@Test
public void publicPojoDepthZeroMethod() {
testParameter(new MethodAction(), "publicPojoDepthZero.key", false);
}
@Test
public void publicPojoDepthOneMethod() {
testParameter(new MethodAction(), "publicPojoDepthOne.key", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
}
@Test
public void publicNestedPojoDepthOneMethod() {
testParameter(new MethodAction(), "publicPojoDepthOne.key.key", false);
}
@Test
public void publicPojoDepthTwoMethod() {
testParameter(new MethodAction(), "publicPojoDepthTwo.key", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
}
@Test
public void publicNestedPojoDepthTwoMethod() {
testParameter(new MethodAction(), "publicPojoDepthTwo.key.key", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Pojo.class));
}
@Test
public void publicPojoListDepthOne() {
testParameter(new FieldAction(), "publicPojoListDepthOne[0].key", false);
}
@Test
public void publicPojoListDepthTwo() {
testParameter(new FieldAction(), "publicPojoListDepthTwo[0].key", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(List.class, Pojo.class));
}
@Test
public void publicPojoMapDepthTwo() {
testParameter(new FieldAction(), "publicPojoMapDepthTwo['a'].key", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Map.class, String.class, Pojo.class));
}
@Test
public void publicPojoListDepthOneMethod() {
testParameter(new MethodAction(), "publicPojoListDepthOne[0].key", false);
}
@Test
public void publicPojoListDepthTwoMethod() {
testParameter(new MethodAction(), "publicPojoListDepthTwo[0].key", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(List.class, Pojo.class));
}
@Test
public void publicPojoMapDepthTwoMethod() {
testParameter(new MethodAction(), "publicPojoMapDepthTwo['a'].key", true);
assertThat(threadAllowlist.getAllowlist()).containsExactlyInAnyOrderElementsOf(getParentClasses(Map.class, String.class, Pojo.class));
}
@Test
public void publicStrNotAnnotated_transitionMode() {
parametersInterceptor.setRequireAnnotationsTransitionMode(Boolean.TRUE.toString());
testParameter(new FieldAction(), "publicStrNotAnnotated", true);
}
@Test
public void publicStrNotAnnotatedMethod_transitionMode() {
parametersInterceptor.setRequireAnnotationsTransitionMode(Boolean.TRUE.toString());
testParameter(new MethodAction(), "publicStrNotAnnotated", true);
}
class FieldAction {
@StrutsParameter
private String privateStr;
@StrutsParameter
public String publicStr;
public String publicStrNotAnnotated;
@StrutsParameter(depth = 1)
private Pojo privatePojo;
@StrutsParameter
public Pojo publicPojoDepthZero;
@StrutsParameter(depth = 1)
public Pojo publicPojoDepthOne ;
@StrutsParameter(depth = 2)
public Pojo publicPojoDepthTwo;
@StrutsParameter(depth = 1)
public List<Pojo> publicPojoListDepthOne;
@StrutsParameter(depth = 2)
public List<Pojo> publicPojoListDepthTwo;
@StrutsParameter(depth = 2)
public Map<String, Pojo> publicPojoMapDepthTwo;
}
class MethodAction {
@StrutsParameter
private void setPrivateStr(String str) {
}
@StrutsParameter
public void setPublicStr(String str) {
}
public void setPublicStrNotAnnotated(String str) {
}
@StrutsParameter(depth = 1)
private Pojo getPrivatePojo() {
return null;
}
@StrutsParameter
public Pojo getPublicPojoDepthZero() {
return null;
}
@StrutsParameter
public void setPublicPojoDepthZero() {
}
@StrutsParameter(depth = 1)
public Pojo getPublicPojoDepthOne() {
return null;
}
@StrutsParameter(depth = 2)
public Pojo getPublicPojoDepthTwo() {
return null;
}
@StrutsParameter(depth = 1)
public List<Pojo> getPublicPojoListDepthOne() {
return null;
}
@StrutsParameter(depth = 2)
public List<Pojo> getPublicPojoListDepthTwo() {
return null;
}
@StrutsParameter(depth = 2)
public Map<String, Pojo> getPublicPojoMapDepthTwo() {
return null;
}
}
class Pojo {
}
}
@@ -20,6 +20,7 @@ package org.apache.struts2.views.jsp;
import com.mockobjects.servlet.MockBodyContent;
import com.mockobjects.servlet.MockJspWriter;
import com.opensymphony.xwork2.ActionContext;
import org.apache.commons.collections.ListUtils;
import javax.servlet.jsp.JspException;
@@ -29,20 +30,15 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* Test Case for Iterator Tag
*
*/
public class IteratorTagTest extends AbstractUITagTest {
IteratorTag tag;
private IteratorTag tag;
public void testIteratingWithIdSpecified() throws Exception {
List list = new ArrayList();
List<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
@@ -104,12 +100,12 @@ public class IteratorTagTest extends AbstractUITagTest {
IteratorTag freshTag = new IteratorTag();
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.",
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testIteratingWithIdSpecified_clearTagStateSet() throws Exception {
List list = new ArrayList();
List<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
@@ -174,12 +170,12 @@ public class IteratorTagTest extends AbstractUITagTest {
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.",
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testIteratingWithIdSpecifiedAndNullElementOnCollection() throws Exception {
List list = new ArrayList();
List<String> list = new ArrayList<>();
list.add("one");
list.add(null);
list.add("three");
@@ -224,12 +220,12 @@ public class IteratorTagTest extends AbstractUITagTest {
IteratorTag freshTag = new IteratorTag();
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.",
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testIteratingWithIdSpecifiedAndNullElementOnCollection_clearTagStateSet() throws Exception {
List list = new ArrayList();
List<String> list = new ArrayList<>();
list.add("one");
list.add(null);
list.add("three");
@@ -277,7 +273,7 @@ public class IteratorTagTest extends AbstractUITagTest {
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.",
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
@@ -294,7 +290,7 @@ public class IteratorTagTest extends AbstractUITagTest {
public void testCollectionIterator() {
Foo foo = new Foo();
ArrayList list = new ArrayList();
List<String> list = new ArrayList<>();
list.add("test1");
list.add("test2");
list.add("test3");
@@ -314,7 +310,7 @@ public class IteratorTagTest extends AbstractUITagTest {
public void testMapIterator() {
Foo foo = new Foo();
HashMap map = new HashMap();
HashMap<String, String> map = new HashMap<>();
map.put("test1", "123");
map.put("test2", "456");
map.put("test3", "789");
@@ -329,8 +325,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doStartTag();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_INCLUDE, result);
@@ -340,8 +335,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doAfterBody();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
@@ -351,8 +345,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doAfterBody();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
@@ -362,8 +355,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doAfterBody();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.SKIP_BODY, result);
@@ -372,8 +364,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doEndTag();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_PAGE, result);
@@ -382,13 +373,13 @@ public class IteratorTagTest extends AbstractUITagTest {
IteratorTag freshTag = new IteratorTag();
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.",
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testMapIterator_clearTagStateSet() {
Foo foo = new Foo();
HashMap map = new HashMap();
HashMap<String, String> map = new HashMap<>();
map.put("test1", "123");
map.put("test2", "456");
map.put("test3", "789");
@@ -405,8 +396,7 @@ public class IteratorTagTest extends AbstractUITagTest {
result = tag.doStartTag();
setComponentTagClearTagState(tag, true); // Ensure component tag state clearing is set true (to match tag).
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_INCLUDE, result);
@@ -416,8 +406,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doAfterBody();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
@@ -427,8 +416,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doAfterBody();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
@@ -438,8 +426,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doAfterBody();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.SKIP_BODY, result);
@@ -448,8 +435,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doEndTag();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_PAGE, result);
@@ -459,7 +445,7 @@ public class IteratorTagTest extends AbstractUITagTest {
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.",
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
@@ -477,8 +463,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doStartTag();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_INCLUDE, result);
@@ -490,15 +475,16 @@ public class IteratorTagTest extends AbstractUITagTest {
assertFalse(status.isLast());
assertTrue(status.isFirst());
assertEquals(0, status.getIndex());
assertEquals("0", status.getIndexStr());
assertEquals(1, status.getCount());
assertEquals("1", status.getCountStr());
assertTrue(status.isOdd());
assertFalse(status.isEven());
try {
result = tag.doAfterBody();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
@@ -517,8 +503,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doAfterBody();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
@@ -537,8 +522,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doEndTag();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_PAGE, result);
@@ -547,7 +531,7 @@ public class IteratorTagTest extends AbstractUITagTest {
IteratorTag freshTag = new IteratorTag();
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.",
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
@@ -567,8 +551,7 @@ public class IteratorTagTest extends AbstractUITagTest {
result = tag.doStartTag();
setComponentTagClearTagState(tag, true); // Ensure component tag state clearing is set true (to match tag).
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_INCLUDE, result);
@@ -587,8 +570,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doAfterBody();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
@@ -607,8 +589,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doAfterBody();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
@@ -627,8 +608,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doEndTag();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_PAGE, result);
@@ -638,7 +618,7 @@ public class IteratorTagTest extends AbstractUITagTest {
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.",
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
@@ -666,7 +646,7 @@ public class IteratorTagTest extends AbstractUITagTest {
public void testEmptyCollection() {
Foo foo = new Foo();
foo.setList(new ArrayList());
foo.setList(new ArrayList<>());
stack.push(foo);
@@ -692,17 +672,41 @@ public class IteratorTagTest extends AbstractUITagTest {
validateCounter(new Integer[]{0, 1, 2, 3, 4, 5});
}
public void testCounterWithStackValues() throws JspException {
public void testCounterWithDifferentLocale() throws JspException {
stack.getActionContext().withLocale(new Locale("fa_IR"));
tag.setVar("it");
tag.setBegin("0");
tag.setEnd("5");
List<String> expectedValues = Arrays.asList("0", "1", "2", "3", "4", "5");
ArrayList<String> values = new ArrayList<>();
try {
int result = tag.doStartTag();
assertEquals(TagSupport.EVAL_BODY_INCLUDE, result);
values.add((String) stack.findValue("it", String.class));
} catch (JspException e) {
fail(e.getMessage());
}
while (tag.doAfterBody() == TagSupport.EVAL_BODY_AGAIN) {
values.add((String) stack.findValue("top", String.class));
}
assertEquals(expectedValues.size(), values.size());
assertEquals(expectedValues, values);
}
public void testCounterWithStackValues() throws JspException {
stack.getContext().put("begin", 0);
stack.getContext().put("end", 5);
tag.setBegin("%{#begin}");
tag.setEnd("%{#end}");
tag.setBegin("begin");
tag.setEnd("end");
validateCounter(new Integer[]{0, 1, 2, 3, 4, 5});
}
public void testCounterWithList() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
@@ -720,7 +724,6 @@ public class IteratorTagTest extends AbstractUITagTest {
public void testCounterWithArray() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
foo.setArray(new String[]{"a", "b", "c", "d"});
stack.push(foo);
@@ -735,7 +738,7 @@ public class IteratorTagTest extends AbstractUITagTest {
public void testCounterWithListNoEnd() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
@@ -752,7 +755,6 @@ public class IteratorTagTest extends AbstractUITagTest {
public void testCounterWithArrayNoEnd() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
foo.setArray(new String[]{"a", "b", "c", "d"});
stack.push(foo);
@@ -765,7 +767,7 @@ public class IteratorTagTest extends AbstractUITagTest {
public void testCounterWithList2() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
@@ -783,7 +785,6 @@ public class IteratorTagTest extends AbstractUITagTest {
public void testCounterWithArray2() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
foo.setArray(new String[]{"a", "b", "c", "d"});
stack.push(foo);
@@ -797,7 +798,7 @@ public class IteratorTagTest extends AbstractUITagTest {
public void testCounterWithListNoEnd2() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
@@ -812,9 +813,8 @@ public class IteratorTagTest extends AbstractUITagTest {
validateCounter(new String[]{"c", "d"});
}
public void testCounterWithArrayNoEnd2() throws JspException {
public void testCounterWithArrayNoEnd2() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
foo.setArray(new String[]{"a", "b", "c", "d"});
stack.push(foo);
@@ -838,9 +838,9 @@ public class IteratorTagTest extends AbstractUITagTest {
validateCounter(new Integer[]{0, 2, 4});
}
public void testCounterWithListAndStep() throws JspException {
public void testCounterWithListAndStep() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
@@ -858,9 +858,8 @@ public class IteratorTagTest extends AbstractUITagTest {
validateCounter(new String[]{"a", "c"});
}
public void testCounterWithArrayAndStep() throws JspException {
public void testCounterWithArrayAndStep() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
foo.setArray(new String[]{"a", "b", "c", "d"});
stack.push(foo);
@@ -876,7 +875,7 @@ public class IteratorTagTest extends AbstractUITagTest {
public void testCounterWithListAndStepNoEnd() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
@@ -895,7 +894,6 @@ public class IteratorTagTest extends AbstractUITagTest {
public void testCounterWithArrayAndStepNoEnd() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
foo.setArray(new String[]{"a", "b", "c", "d"});
stack.push(foo);
@@ -917,7 +915,7 @@ public class IteratorTagTest extends AbstractUITagTest {
public void testCounterWithListAndNegativeStep() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
@@ -937,7 +935,7 @@ public class IteratorTagTest extends AbstractUITagTest {
public void testCounterWithListAndNegativeStepNoEnd() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
@@ -954,9 +952,9 @@ public class IteratorTagTest extends AbstractUITagTest {
validateCounter(new String[]{"d", "c", "b", "a"});
}
public void testCounterWithArrayAndNegativeStep() throws JspException {
public void testCounterWithArrayAndNegativeStep() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
@@ -976,7 +974,7 @@ public class IteratorTagTest extends AbstractUITagTest {
public void testCounterWithArrayAndNegativeStepNoEnd() throws JspException {
Foo foo = new Foo();
ArrayList list = new ArrayList();
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
@@ -994,14 +992,13 @@ public class IteratorTagTest extends AbstractUITagTest {
}
protected void validateCounter(Object[] expectedValues) throws JspException {
List values = new ArrayList();
ArrayList<Object> values = new ArrayList<>();
try {
int result = tag.doStartTag();
assertEquals(TagSupport.EVAL_BODY_INCLUDE, result);
values.add(stack.getRoot().peek());
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
while (tag.doAfterBody() == TagSupport.EVAL_BODY_AGAIN) {
@@ -1009,7 +1006,7 @@ public class IteratorTagTest extends AbstractUITagTest {
}
assertEquals(expectedValues.length, values.size());
ListUtils.isEqualList(Arrays.asList(expectedValues), values);
assertTrue(ListUtils.isEqualList(Arrays.asList(expectedValues), values));
}
@Override
@@ -1033,8 +1030,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doStartTag();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_INCLUDE, result);
@@ -1044,8 +1040,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doAfterBody();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
@@ -1055,8 +1050,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doAfterBody();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_BODY_AGAIN, result);
@@ -1066,8 +1060,7 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doAfterBody();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.SKIP_BODY, result);
@@ -1080,16 +1073,14 @@ public class IteratorTagTest extends AbstractUITagTest {
try {
result = tag.doStartTag();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.SKIP_BODY, result);
try {
result = tag.doEndTag();
} catch (JspException e) {
e.printStackTrace();
fail();
fail(e.getMessage());
}
assertEquals(TagSupport.EVAL_PAGE, result);
@@ -1098,13 +1089,13 @@ public class IteratorTagTest extends AbstractUITagTest {
IteratorTag freshTag = new IteratorTag();
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.",
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
class Foo {
private Collection list;
private Map map;
static class Foo {
private Collection<String> list;
private Map<String, String> map;
private String[] array;
public void setArray(String[] array) {
@@ -1115,24 +1106,24 @@ public class IteratorTagTest extends AbstractUITagTest {
return array;
}
public void setList(Collection list) {
public void setList(Collection<String> list) {
this.list = list;
}
public Collection getList() {
public Collection<String> getList() {
return list;
}
public void setMap(Map map) {
public void setMap(Map<String, String> map) {
this.map = map;
}
public Map getMap() {
public Map<String, String> getMap() {
return map;
}
}
class TestMockBodyContent extends MockBodyContent {
static class TestMockBodyContent extends MockBodyContent {
public String getString() {
return ".-.";
}
@@ -276,6 +276,23 @@ public class AnchorTest extends AbstractUITagTest {
verifyResource("href-5.txt");
}
public void testSimpleDisabled() throws Exception {
createAction();
AnchorTag tag = createTag();
tag.setHref("a");
tag.setDisabled("true");
StrutsBodyContent body = new StrutsBodyContent(null);
body.print("should have disabled attribute");
tag.setBodyContent(body);
tag.doStartTag();
tag.doEndTag();
verifyResource("href-6.txt");
}
public void testInjectEscapeHtmlBodyFlag() throws Exception {
// given
initDispatcherWithConfigs("struts-default.xml, struts-escape-body.xml");
@@ -64,6 +64,37 @@ public class RadioTest extends AbstractUITagTest {
strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testMapWithBooleanAsKeyWithoutForceValue() 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);
testAction.setSomeBool(false);
RadioTag tag = new RadioTag();
tag.setPageContext(pageContext);
tag.setLabel("mylabel");
tag.setName("myname");
tag.setValue("someBool");
tag.setList("map");
tag.setTheme("simple");
tag.doStartTag();
tag.doEndTag();
verify(RadioTag.class.getResource("Radio-11.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_clearTagStateSet() throws Exception {
TestAction testAction = (TestAction) action;
@@ -165,12 +196,13 @@ public class RadioTest extends AbstractUITagTest {
List<SomeEnum> enumList = new ArrayList<>(Arrays.asList(SomeEnum.values()));
testAction.setEnumList(enumList);
testAction.setStatus(SomeEnum.INIT);
RadioTag tag = new RadioTag();
tag.setTheme("simple");
tag.setPageContext(pageContext);
tag.setName("status");
tag.setValue("INIT");
tag.setValue("status");
tag.setList("enumList");
tag.doStartTag();
@@ -191,13 +223,14 @@ public class RadioTest extends AbstractUITagTest {
List<SomeEnum> enumList = new ArrayList<>(Arrays.asList(SomeEnum.values()));
testAction.setEnumList(enumList);
testAction.setStatus(SomeEnum.INIT);
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.setValue("status");
tag.setList("enumList");
tag.doStartTag();
@@ -0,0 +1,4 @@
<input type="radio" name="myname" id="mynametrue" value="true"/>
<label for="mynametrue">male</label>
<input type="radio" name="myname" id="mynamefalse" checked="checked" value="false"/>
<label for="mynamefalse">female</label>
@@ -0,0 +1 @@
<a id="mylink" href="a" disabled="disabled">should have disabled attribute</a>
Vendored
+105 -113
View File
@@ -19,7 +19,7 @@
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven Start Up Batch script
# Apache Maven Wrapper startup batch script, version 3.2.0
#
# Required ENV vars:
# ------------------
@@ -27,7 +27,6 @@
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@@ -54,7 +53,7 @@ fi
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
case "$(uname)" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
@@ -62,9 +61,9 @@ case "`uname`" in
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
else
export JAVA_HOME="/Library/Java/Home"
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
fi
fi
;;
@@ -72,68 +71,38 @@ esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
JAVA_HOME=$(java-config --jre-home)
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
javaExecutable="$(which javac)"
if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
readLink=$(which readlink)
if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
javaHome="$(dirname "\"$javaExecutable\"")"
javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
javaExecutable="$(readlink -f "\"$javaExecutable\"")"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
javaHome="$(dirname "\"$javaExecutable\"")"
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
@@ -149,7 +118,7 @@ if [ -z "$JAVACMD" ] ; then
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`\\unset -f command; \\command -v java`"
JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
fi
fi
@@ -163,12 +132,9 @@ if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
@@ -184,96 +150,99 @@ find_maven_basedir() {
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
wdir=$(cd "$wdir/.." || exit 1; pwd)
fi
# end of workaround
done
echo "${basedir}"
printf '%s' "$(cd "$basedir" || exit 1; pwd)"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
# Remove \r in case we run on Windows within Git Bash
# and check out the repository with auto CRLF management
# enabled. Otherwise, we may read lines that are delimited with
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
# splitting rules.
tr -s '\r\n' ' ' < "$1"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
log() {
if [ "$MVNW_VERBOSE" = true ]; then
printf '%s\n' "$1"
fi
}
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
log "$MAVEN_PROJECTBASEDIR"
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
if [ -r "$wrapperJarPath" ]; then
log "Found $wrapperJarPath"
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
log "Couldn't find $wrapperJarPath, downloading it ..."
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
while IFS="=" read -r key value; do
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
safeValue=$(echo "$value" | tr -d '\r')
case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
log "Downloading from: $wrapperUrl"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
log "Found wget ... using wget"
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
log "Found curl ... using curl"
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
log "Falling back to using Java to download"
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
javaSource=$(cygpath --path --windows "$javaSource")
javaClass=$(cygpath --path --windows "$javaClass")
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
if [ -e "$javaSource" ]; then
if [ ! -e "$javaClass" ]; then
log " - Compiling MavenWrapperDownloader.java ..."
("$JAVA_HOME/bin/javac" "$javaSource")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
if [ -e "$javaClass" ]; then
log " - Running MavenWrapperDownloader.java ..."
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
fi
fi
fi
@@ -282,35 +251,58 @@ fi
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
wrapperSha256Sum=""
while IFS="=" read -r key value; do
case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
esac
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
if [ -n "$wrapperSha256Sum" ]; then
wrapperSha256Result=false
if command -v sha256sum > /dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
wrapperSha256Result=true
fi
elif command -v shasum > /dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
wrapperSha256Result=true
fi
else
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
exit 1
fi
if [ $wrapperSha256Result = false ]; then
echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
exit 1
fi
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
# shellcheck disable=SC2086 # safe args
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
Vendored
+24 -7
View File
@@ -18,13 +18,12 @@
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven Start Up Batch script
@REM Apache Maven Wrapper startup batch script, version 3.2.0
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@@ -120,10 +119,10 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@@ -134,11 +133,11 @@ if exist %WRAPPER_JAR% (
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
echo Downloading from: %WRAPPER_URL%
)
powershell -Command "&{"^
@@ -146,7 +145,7 @@ if exist %WRAPPER_JAR% (
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
@@ -154,6 +153,24 @@ if exist %WRAPPER_JAR% (
)
@REM End of extension
@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
SET WRAPPER_SHA_256_SUM=""
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
)
IF NOT %WRAPPER_SHA_256_SUM%=="" (
powershell -Command "&{"^
"$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
"If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
" Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
" Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
" Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
" exit 1;"^
"}"^
"}"
if ERRORLEVEL 1 goto error
)
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-async-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-cdi-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-config-browser-plugin</artifactId>
@@ -30,7 +30,7 @@ import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.dispatcher.multipart.MultiPartRequest;
import org.apache.struts2.views.freemarker.FreemarkerManager;
import org.apache.struts2.views.velocity.VelocityConstants;
import org.apache.struts2.views.velocity.VelocityManager;
import org.apache.struts2.views.velocity.VelocityManagerInterface;
import java.util.Map;
import java.util.Set;
@@ -56,7 +56,7 @@ public class ShowBeansAction extends ActionNamesAction {
bindings.put(ActionMapper.class.getName(), addBindings(container, ActionMapper.class, StrutsConstants.STRUTS_MAPPER_CLASS));
bindings.put(MultiPartRequest.class.getName(), addBindings(container, MultiPartRequest.class, StrutsConstants.STRUTS_MULTIPART_PARSER));
bindings.put(FreemarkerManager.class.getName(), addBindings(container, FreemarkerManager.class, StrutsConstants.STRUTS_FREEMARKER_MANAGER_CLASSNAME));
bindings.put(VelocityManager.class.getName(), addBindings(container, VelocityManager.class, VelocityConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME));
bindings.put(VelocityManagerInterface.class.getName(), addBindings(container, VelocityManagerInterface.class, VelocityConstants.STRUTS_VELOCITY_MANAGER_CLASSNAME));
bindings.put(UrlRenderer.class.getName(), addBindings(container, UrlRenderer.class, StrutsConstants.STRUTS_URL_RENDERER));
}
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-convention-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-dwr-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-embeddedjsp-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-gxp-plugin</artifactId>
+2 -2
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-jasperreports-plugin</artifactId>
@@ -35,7 +35,7 @@
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>6.20.6</version>
<version>6.21.0</version>
<scope>provided</scope>
<exclusions>
<!-- not necessary to compile and it force dependency convergence issues -->
+1 -1
View File
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-javatemplates-plugin</artifactId>
@@ -33,7 +33,6 @@ public class FileHandler extends AbstractTagHandler implements TagGenerator {
a.addDefaultToEmpty("name", params.get("name"))
.add("type", "file")
.addIfExists("size", params.get("size"))
.addIfExists("value", params.get("nameValue"))
.addIfTrue("disabled", params.get("disabled"))
.addIfExists("accept", params.get("accept"))
.addIfExists("tabindex", params.get("tabindex"))
@@ -28,7 +28,6 @@ public class FileTest extends AbstractCommonAttributesTest {
public void testRenderTextField() {
tag.setName("name");
tag.setValue("val1");
tag.setSize("10");
tag.setDisabled("true");
tag.setAccept("accept_");
@@ -43,7 +42,7 @@ public class FileTest extends AbstractCommonAttributesTest {
map.putAll(tag.getParameters());
theme.renderTag(getTagName(), context);
String output = writer.getBuffer().toString();
String expected = s("<input name='name' type='file' size='10' value='val1' disabled='disabled' accept='accept_' tabindex='1' id='id1' class='class1' style='style1' title='title'></input>");
String expected = s("<input name='name' type='file' size='10' disabled='disabled' accept='accept_' tabindex='1' id='id1' class='class1' style='style1' title='title'></input>");
assertEquals(expected, output);
}
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-jfreechart-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-json-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-junit-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-osgi-plugin</artifactId>
@@ -24,15 +24,15 @@ import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.config.Configuration;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.config.PackageProvider;
import com.opensymphony.xwork2.config.entities.PackageConfig;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.finder.ClassLoaderInterface;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.osgi.host.OsgiHost;
import org.apache.struts2.osgi.loaders.VelocityBundleResourceLoader;
import org.apache.struts2.views.velocity.VelocityManager;
import org.apache.struts2.views.velocity.VelocityManagerInterface;
import org.apache.velocity.app.Velocity;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
@@ -40,7 +40,6 @@ import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import javax.servlet.ServletContext;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
@@ -255,9 +254,12 @@ public class OsgiConfigurationProvider implements PackageProvider, BundleListene
}
@Inject
public void setVelocityManager(VelocityManager vm) {
LOG.trace("OSGi ConfigurationProvider - setVelocityManager() called - VelocityManager: [{}]", vm);
public void setVelocityManager(VelocityManagerInterface vmi) {
LOG.trace("OSGi ConfigurationProvider - setVelocityManager() called - VelocityManager: [{}]", vmi);
if (!(vmi instanceof VelocityManager)) {
return;
}
VelocityManager vm = (VelocityManager) vmi;
Properties props = new Properties();
props.setProperty("osgi.resource.loader.description", "OSGI bundle loader");
props.setProperty("osgi.resource.loader.class", VelocityBundleResourceLoader.class.getName());
@@ -265,6 +267,14 @@ public class OsgiConfigurationProvider implements PackageProvider, BundleListene
vm.setVelocityProperties(props);
}
/**
* @deprecated since 6.4.0
*/
@Deprecated
public void setVelocityManager(VelocityManager mgr) {
setVelocityManager((VelocityManagerInterface) mgr);
}
@Inject
public void setServletContext(ServletContext servletContext) {
LOG.trace("OSGi ConfigurationProvider - setServletContext() called - ServletContext: [{}]", servletContext);
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.4.0-SNAPSHOT</version>
<version>6.4.0</version>
</parent>
<artifactId>struts2-oval-plugin</artifactId>

Some files were not shown because too many files have changed in this diff Show More