Compare commits

...

235 Commits

Author SHA1 Message Date
Lukasz Lenart 96c38b27e4 [maven-release-plugin] prepare release STRUTS_2_5_20 2019-01-09 08:59:40 +01:00
Lukasz Lenart e9108f0feb Merge pull request #310 from aleksandr-m/feature/WW-4998_i18ninterceptor
WW-4998 I18nInterceptor's default storage should store locale
2019-01-09 08:45:23 +01:00
Lukasz Lenart 3653f6e9e1 Merge pull request #309 from JCgH4164838Gh792C124B5/localS2_25x_B1
Address devMode log flooding concern raised by Greg Huber (on Dev List)
2019-01-09 08:43:49 +01:00
JCgH4164838Gh792C124B5 5a2323a19f Update after comments by Y. Zamani and L. Lenart
- Reverted the 6 modified files back to 2.5.19 baseline.
- Removed most of the logging added in PR#291.
- Left the added logging for the setExcludedPatterns and setAcceptedPatterns methods in their respective modules.
  L. Lenart's comment indicated their benefit outweighs overhead (not something that changes often).
  Made the if-else blocks consistent with preferred styling for the log blocks.
- Removed a dangling "/**" start comment tag with no proper close (and the whitespace between it and the next "/**"
  in the OgnlValueStack module.
(Note: Amended previous commit)
2019-01-07 23:29:32 -05:00
Aleksandr Mashchenko ea09a8828b WW-4998 I18nInterceptor's default storage should store locale 2019-01-07 17:29:46 +02:00
JCgH4164838Gh792C124B5 17fe42c0f7 Update revision after comments by A. Mashchenko and S. Peters.
- Change to produce only one warn before switching to trace mode.
- Moved literal string to constant DEVMODE_WARN_STR to avoid duplication.
- Replaced two duplicate strings in logLookupFailure() with EXCEPTION_EVALUATING_EXPRESSION_STR to avoid duplication.
2019-01-05 15:34:38 -05:00
JCgH4164838Gh792C124B5 87fa5bddf2 Address dev<Mode log flooding concern raised by Greg Huber
in the Struts Dev List review of 2.5.19.
- Introduce a static count-limiter for the devMode set warning in
OgnlValueStack.  Limit warnings to 250 total, after which it switches
to trace level logs to avoid log flooding.
2019-01-04 16:31:06 -05:00
Lukasz Lenart 45161e88f9 [maven-release-plugin] prepare for next development iteration 2018-12-30 15:24:15 +01:00
Lukasz Lenart 4456620b51 [maven-release-plugin] prepare release STRUTS_2_5_19 2018-12-30 15:23:53 +01:00
Yasser Zamani f4a8f42ca4 Merge pull request #304 from lukaszlenart/WW-4975-struts25x
[WW-4975] Upgrades commons-fileupload to version 1.4 - Struts 2.5.x
2018-12-29 20:20:12 +03:30
Lukasz Lenart a6f8895c90 WW-4975 Upgrades commons-fileupload to version 1.4 2018-12-29 17:11:45 +01:00
Aleksandr Mashchenko 46dbdbe018 Add generated tag html 2018-12-21 21:30:31 +02:00
JCgH4164838Gh792C124B5 6f176cc5a7 Enhancement for s:set tag for 2.5.x to allow better tag body whitespace control. (#296)
WW-4995 Add trimBody attribute to set tag
2018-12-20 17:59:30 +02:00
JCgH4164838Gh792C124B5 db085dbeef Updates and cleanup for some configuration-related items (2.5.x). (#291)
* Updates and cleanup for some configuration-related items.
- Made several attributes final.
- Added limiter logic to the setting of certain configuration elements, and increased logging around them.
- Updated unit tests impacted by the limiter logic, including minor typo fixes and locale consistency.
- Minor cleanup while making the changes.

* Update core/src/main/java/com/opensymphony/xwork2/ognl/OgnlValueStackFactory.java

Whitespace cleanup

Co-Authored-By: JCgH4164838Gh792C124B5 <43964333+JCgH4164838Gh792C124B5@users.noreply.github.com>

* Updates and cleanup for some configuration-related items (1st revision).
- Reworked this PR, taking into account feedback and suggestions.
- Removed the if LOG.isxxxEnabled level checks that were added.
- Removed the limiter logic and instead reduced access level of most of the injectable methods to protected.
- Updated the previous unit test changes following removal of limiter logic.

* Minor correction to two debug log statements (as requested by reviewer).

* Update debug messages for pattern checkers, as requested by reviewers.
Avoids confusing users when replacing an empty exclusion set (which improves safety).
Still provides a (slightly milder) message when replacing an empty accepted set (which can reduce safety).
2018-12-20 15:25:34 +03:30
Lukasz Lenart c3205888b4 Merge pull request #293 from JCgH4164838Gh792C124B5/local_25x_LibUpd
Update Struts 2.5.19 to use latest OGNL 3.1.x release available.
2018-12-17 15:42:52 +01:00
JCgH4164838Gh792C124B5 ce9789c4c9 Update Struts 2.5.19 to use latest OGNL 3.1.x release available. 2018-12-13 23:52:29 -05:00
Aleksandr Mashchenko b431755332 Improve optgroup list attributes test
(cherry picked from commit 48d40ae6ac)
2018-12-13 22:42:53 +02:00
Aleksandr Mashchenko c694c6fdfb Improve optgroup template
(cherry picked from commit 60dfc4d141)
2018-12-13 22:42:52 +02:00
Aleksandr Mashchenko 1d49a06272 Add listTitle to optgroup tag
(cherry picked from commit 123a0906ce)
2018-12-13 22:42:52 +02:00
Aleksandr Mashchenko 264e03b7ed Add listCssStyle to optgroup tag
(cherry picked from commit 3c24bae87f)
2018-12-13 22:42:51 +02:00
Aleksandr Mashchenko 2f99110189 WW-4987 Add test for listCssClass in optgroup tag
(cherry picked from commit 94210a02e7)
2018-12-13 22:42:51 +02:00
Aleksandr Mashchenko d33930f3bd WW-4987 Add listCssClass to optgroup tag 2018-12-13 22:42:11 +02:00
Sebastian Peters 360927931c Enhance after_success for Travis CI
Use default bash if-then-else block with semicolon after each command
and fix spelling for "incompatibility".

Don't do `mvn clean` b/c we need the test results for the following
tasks and don't need to rebuild everything.

(cherry picked from commit 352f509)
2018-11-22 14:26:21 +03:30
Lukasz Lenart bff033e6a3 Merge pull request #281 from JCgH4164838Gh792C124B5/localS2_2_5_x_Branch
Minor update to Struts 2.5.x SecurityMemberAccess.
2018-11-22 08:31:34 +01:00
JCgH4164838Gh792C124B5 536d2db4b8 Minor update to Struts 2.5.x SecurityMemberAccess.
Code changes:
- updated SecurityMemberAccess for compatibility with future OGNL 3.1.19+ versions
- updated SecurityMemberAccess constructor (minor cleanup and added comment)
2018-11-21 23:45:13 -05:00
Yasser Zamani 32c8f6f811 [WW-4981] Adds support for JDK11 (#270) 2018-11-19 14:27:21 +03:30
Yasser Zamani 06e5dfc2ab delete not-supported picked from master system property test 2018-11-18 16:30:54 +03:30
Sebastian Peters fe630db5f2 Refactor environment dependant tests
* use org.apache.commons.lang3.SystemUtils for env detection
* use assertThat for more concise assertions
* move setup code to setUp
* some formatting

(cherry picked from commit 8d341df)
2018-11-18 16:01:44 +03:30
Lukasz Lenart b75c0ba5e1 WW-4866 Includes 9+ JDKs
(cherry picked from commit af3ee07)
2018-11-18 15:57:03 +03:30
Lukasz Lenart 8ab102209f WW-4866 Includes 1.8+ JDKs
(cherry picked from commit 2d86cc6)
2018-11-18 15:56:54 +03:30
ORDTesters d7a7c909ea [WW-4977] Fixing flaky test in Jsr168DispatcherTest and Jsr286DispatcherTest.
(cherry picked from commit 2d4e26f)
2018-11-18 15:39:41 +03:30
Yasser Zamani 24e151143e Merge pull request #271 from JCgH4164838Gh792C124B5/localS2_2_5_x_Branch
Back-port enhancement/fix to 2.5.19 unit tests (permits build on Windows)
2018-11-18 12:55:48 +03:30
JCgH4164838Gh792C124B5 c5272d2a0d Backport enhancement/fix from 2.6 to 2.5.19 unit tests to allow Struts 2.5.x build to complete sucessfully on Windows.
- Involves changes to: EnvsValueSubstitutorTest, XmlConfigurationProviderEnvsSubstitutionTest, xwork-test-envs-substitution.xml.
- Note: 2.5.x EnvValueSubstitutor doesn't support system properties (only env properties) so some tests were not backported.
2018-11-17 13:21:20 -05:00
Yasser Zamani 11de8810e4 satisfy coveralls via testing with a not URLClassLoader
See also WW-4845

(cherry picked from commit 02abab3)
2018-11-16 17:30:27 +03:30
Yasser Zamani 75dc4c00d2 pass all current tests with java 9
See also WW-4845

(cherry picked from commit a5d888a)
2018-11-16 17:29:37 +03:30
Lukasz Lenart 415ce3e165 Merge pull request #264 from JCgH4164838Gh792C124B5/localS2_2_5_x_Branch
Update Struts 2.5.19 build with some newer (compatible) library versions
2018-11-14 20:54:19 +01:00
JCgH4164838Gh792C124B5 fe6257b995 Merge branch 'localS2_2_5_x_Branch' of https://github.com/JCgH4164838Gh792C124B5/struts into localS2_2_5_x_Branch
# Conflicts:
#	pom.xml
2018-11-12 15:13:18 -05:00
JCgH4164838Gh792C124B5 3b81a9edaa Update Struts 2.5.19 build with some newer (compatible) library versions.
- Fix SCM tag entry typo in main pom.xml.
- Enhance main pom.xml maven-surefire-plugin configuration to avoid some test-ng related duplication failures:  "Cannot find JUnit method class junit.framework.TestSuite$1.warning".
- Remove unnecessary plugins/embeddedjsp/pom.xml (struts2-embeddedjsp-plugin) maven-surefire-plugin version override (noted with preceding change).
- Update Struts 2.5.19 build to use some newer (compatible) library versions.
  Change the main pom.xml library versions for the following:
  - spring.platformVersion 4.3.13.RELEASE -> 4.3.20.RELEASE
  - ognl 3.1.15 -> 3.1.18  (Note: newest version that passes unit tests)
  - oval 1.31 -> 1.90      (Note: required unit test fix for OValValidationInterceptorTest.java)
  - tiles 3.0.7 -> 3.0.8
  - tiles-request 1.0.6 -> 1.0.7
  - log4j 2.10.0 -> 2.11.1
  - jackson 2.9.5 -> 2.9.7
  - fluido-skin.version 1.6 -> 1.7
  - slf4j 1.7.12 -> 1.7.25
  - xtream 1.4.10 -> 1.4.11.1
  - jetty 6.1.9 -> 6.1.26 (last in 6.1.x line)
  - xerces 2.10.0 - > 2.12.0
  - org.owasp 3.1.1 -> 3.3.4
  - versions-maven-plugin 2.5 -> 2.7
  - doxia-core 1.7 -> 1.8
  - doxia-markdown 1.3 -> 1.7
  - freemarker 2.3.26-incubating -> 2.3.28
  - org.apache.felix.main 4.0.3 -> 4.6.1  (Note: most recent 4.x)
  - easymock 3.4 -> 3.5.1
  - javax.el 3.0 -> 3.0.1-b10
  - jasper 6.0.18 -> 6.0.53  (Note: most recent 6.0.x)
  - juli 6.0.18 -> 6.0.53    (Note: most recent 6.0.x)
  - commons-logging 1.1.3 -> 1.2
  - commons-collections4 4.1 -> 4.2
  - commons-io 2.5 -> 2.6
  - commons-lang 3.6 -> 3.8.1
  - commons-beanutils 1.9.2 -> 1.9.3
  - commons-validator 1.5.1 -> 1.6
  - mockito 1.9.5 -> 1.10.19            (Note: most recent 1.x)
  - cdi-api 1.0-SP1 -> 1.0-SP4          (Note: most recent 1.0.x)
  - weld-core 1.0.1-Final -> 1.0.1-SP4  (Note: most recent 1.0.x)
  Note for cglib-nodep:  Build succeeded with cglib-nodep 2.2.2 and 3.2.5.  Although
    cglib 3.2.5 matches ASM 5.2, jmock-cglib 1.2.0 identifies cglib-nodep 2.1_3 as its
    requirement (on the JMock http://jmock.org/download.html download page) so it should
    remain as long as JMock 1.2.0 is used.
2018-11-12 14:49:56 -05:00
JCgH4164838Gh792C124B5 478a9b8f1c Update Struts 2.5.19 build to use some newer (compatible) library versions.
- Fix SCM tag entry typo in main pom.xml.
- Enhance main pom.xml maven-surefire-plugin configuration to avoid some test-ng related duplication failures:
  "Cannot find JUnit method class junit.framework.TestSuite$1.warning".
- Remove unnecessary plugins/embeddedjsp/pom.xml (struts2-embeddedjsp-plugin) maven-surefire-plugin version override (noted with preceding change).
- Update Struts 2.5.19 build to use some newer (compatible) library versions.
  Change the main pom.xml library versions for the following:
  - spring.platformVersion 4.3.13.RELEASE -> 4.3.20.RELEASE
  - ognl 3.1.15 -> 3.1.18 (Note: newest version that passes unit tests)
  - oval 1.31 -> 1.90     (required unit test fix for OValValidationInterceptorTest.java)
  - tiles 3.0.7 -> 3.0.8
  - tiles-request 1.0.6 -> 1.0.7
  - log4j 2.10.0 -> 2.11.1
  - jackson 2.9.5 -> 2.9.7
  - fluido-skin.version 1.6 -> 1.7
  - slf4j 1.7.12 -> 1.7.25
  - xtream 1.4.10 -> 1.4.11.1
  - jetty 6.1.9 -> 6.1.26 (last in 6.1.x line)
  - xerces 2.10.0 - > 2.12.0
  - org.owasp 3.1.1 -> 3.3.4
  - versions-maven-plugin 2.5 -> 2.7
  - doxia-core 1.7 -> 1.8
  - doxia-markdown 1.3 -> 1.7
  - freemarker 2.3.26-incubating -> 2.3.28
  - org.apache.felix.main 4.0.3 -> 4.6.1  (most recent 4.x)
  - cglib 2.1_3 -> 3.2.5 (match for ASM 5.2)
  - easymock 3.4 -> 3.5.1
  - javax.el 3.0 -> 3.0.1-b10
  - jasper 6.0.18 -> 6.0.53 (most recent 6.0.x)
  - juli 6.0.18 -> 6.0.53 (most recent 6.0.x)
  - commons-logging 1.1.3 -> 1.2
  - commons-collections4 4.1 -> 4.2
  - commons-io 2.5 -> 2.6
  - commons-lang 3.6 -> 3.8.1
  - commons-beanutils 1.9.2 -> 1.9.3
  - commons-validator 1.5.1 -> 1.6
  - mockito 1.9.5 -> 1.10.19 (most recent 1.x)
  - cdi-api 1.0-SP1 -> 1.0-SP4 (most recent 1.0.x)
  - weld-core 1.0.1-Final -> 1.0.1-SP4 (most recent 1.0.x)
2018-11-12 13:49:51 -05:00
Lukasz Lenart 12c3d23bdf Merge pull request #260 from yasserzamani/WW-4974
WW-4974 monitor not-monitored loaded files on demand
2018-11-03 10:47:09 +01:00
Aleksandr Mashchenko 8293add6aa Merge pull request #257 from JCgH4164838Gh792C124B5/localS2_2_5_x_Branch
Fix WW-4971 (broken includes for non-UTF8 content).
2018-11-01 21:53:04 +02:00
Yasser Zamani ecb7beef38 not miss container provided fileUrl and ...
lazy monitoring for performance. Fix and test stopping reload configs at runtime.

Fixes WW-4974
2018-11-01 15:17:02 +03:30
Yasser Zamani bac0f2953c monitor not-monitored loaded files on demand
See WW-4974
2018-10-31 19:51:37 +03:30
JCgH4164838Gh792C124B5 7bca98205d Fix typos and whitespace (on top of WW-4971 Fix broken s:includes for non-UTF8 content). 2018-10-25 00:13:35 -04:00
JCgH4164838Gh792C124B5 567fae9dfc WW-4971 Fix broken s:includes for non-UTF8 content. The low-risk fix retains existing behaviour by default, but provides a configuration flag users can set (to true) in order to enable usage of response (page) encoding for s:include tags. A WARN level log output is also generated for failed FastByteArrayOutputStream decoding (can be suppressed by log configuration). 2018-10-24 23:41:38 -04:00
Lukasz Lenart f4d7dbe88e [maven-release-plugin] prepare for next development iteration 2018-09-18 11:23:59 +02:00
Lukasz Lenart 289782c583 [maven-release-plugin] prepare release STRUTS_2_5_18 2018-09-18 11:23:36 +02:00
Lukasz Lenart 1e33df947a WW-4951 Upgrades to the latest struts master to support SHA256/512 2018-09-18 09:49:27 +02:00
Lukasz Lenart de1a42d34a Merge pull request #250 from yasserzamani/WW-4948
WW-4948 delete temp files on close instead of on JVM exists
2018-09-17 08:02:35 +02:00
Yasser Zamani b816cc1374 monitor file only if needed
See also: WW-4948
2018-09-10 18:18:42 +04:30
Yasser Zamani b802baa4a9 delete temp files on close instead of on JVM exists 2018-09-06 12:59:21 +04:30
Aleksandr Mashchenko daac47ee62 Improve log messages in SecurityMemberAccess
(cherry picked from commit be1a93b0d5)
2018-09-03 21:51:30 +03:00
Aleksandr Mashchenko b1709c5208 Better logging message (for WW-4954)
(cherry picked from commit b213d58f54)
2018-09-03 21:51:17 +03:00
Yasser Zamani daf6f6f749 Merge pull request #244 from apache/WW-4954
WW-4954 Moves XWorkList out of util package
2018-08-31 16:23:02 +04:30
Lukasz Lenart 029892d656 WW-4954 Moves XWorkList out of util package 2018-08-30 08:39:11 +02:00
Lukasz Lenart 65fb0d4a44 Merge pull request #242 from benelog/fix-log-2-5-x
Fix logging  message (for 2.5.x)
2018-08-27 14:17:38 +02:00
Sanghyuk Jung 58d87025e9 Fix logging messages 2018-08-27 20:59:00 +09:00
Yaser Zamani 83c0f1cd1e [maven-release-plugin] prepare for next development iteration 2018-08-13 17:13:52 +04:30
Yaser Zamani eacc002334 [maven-release-plugin] prepare release STRUTS_2_5_17 2018-08-13 17:12:34 +04:30
Yasser Zamani 45effc3822 add an extra unit test 2018-06-29 16:28:23 +04:30
Lukasz Lenart bad9a49060 Fixes how dependencies are injected into constructor 2018-06-27 08:15:21 +02:00
Yasser Zamani a75eddb515 delete redundant code for performance 2018-06-21 12:00:46 +04:30
Lukasz Lenart 6e87474f9a Validates action, namespace and method in the same way 2018-06-21 09:19:57 +02:00
Lukasz Lenart 9fcbd912bc Adds more general exclusion 2018-06-21 08:20:11 +02:00
Lukasz Lenart fbc780e779 Adds proper handling of primitive types 2018-06-20 11:47:53 +02:00
Lukasz Lenart 6eb83016e3 Fixes wrong version in bom 2018-06-15 09:31:57 +02:00
Lukasz Lenart 3ec7fa9d80 Makes OgnlUtil more immutable 2018-05-29 12:58:44 +02:00
Lukasz Lenart f9806ee4e1 Adds Maven wrapper to allow use the latest Maven version 2018-05-29 11:48:39 +02:00
Lukasz Lenart d175836757 Changes version to snapshot 2018-05-02 08:45:44 +02:00
Lukasz Lenart e55ad3fb45 Upgrades Jackson libs to version 2.9.5 2018-05-02 08:35:52 +02:00
Lukasz Lenart 6efaf900d4 Increases scope when location parsing is avoided 2018-05-02 08:25:06 +02:00
Lukasz Lenart b3bad5ea44 Avoids parsing namespace when using existing namespace 2018-05-02 08:04:15 +02:00
Lukasz Lenart 1fec084542 [maven-release-plugin] prepare release STRUTS_2_5_16 2018-03-02 12:59:53 +01:00
Yasser Zamani 26babb6fdf Merge pull request #210 from lukaszlenart/jackson-xml
WW-4922: Jackson XML
2018-03-02 13:17:38 +03:30
Lukasz Lenart 6e691ffdbf Merge pull request #212 from zepernick/master
WW-4923 Null check to avoid NPE when not passing a JDBC connection
2018-02-28 10:16:06 +01:00
Yasser Zamani 4b540f1ab4 fix location with full path of resource 2018-02-28 11:24:31 +03:30
Lukasz Lenart a292920462 Merge pull request #211 from yasserzamani/struts_user_mbox_201802
WW-4920 fix java.net.JarURLConnection#parseSpecs
2018-02-28 08:12:43 +01:00
Paul Zepernick 10ba97f08f Merge pull request #1 from yasserzamani/WW-4923
WW-4923 add test if connection close after result
2018-02-27 11:00:39 -05:00
Lukasz Lenart 54fa3f7b04 Merge pull request #214 from yasserzamani/WW-4921
WW-4921 initialize session like WW-3442
2018-02-27 12:04:12 +01:00
Yasser Zamani a448b8a91b make newly added methods protected to allow users to override them
See also WW-4921, WW-3442
2018-02-27 14:18:46 +03:30
Lukasz Lenart 6c5b79c204 Adds explanation how to use the commented configuration 2018-02-27 11:13:39 +01:00
Yasser Zamani b806c11ea5 initialize session
See also WW-4921
2018-02-27 13:20:33 +03:30
Yasser Zamani a64b8b27fb add test if connection close after result
See also WW-4923
2018-02-27 08:45:27 +03:30
Lukasz Lenart b4ca6ceec9 Fixes suppression file 2018-02-26 09:27:26 +01:00
Lukasz Lenart 7619ed3076 Cleans up suppression file and uses full path 2018-02-23 17:15:03 +01:00
Paul Zepernick 8bf6605e6b WW-4923 Null check to avoid NPE when not passing a JDBC connection to the jasper report 2018-02-22 10:13:14 -05:00
Yasser Zamani 8d91536b17 fix javadoc to being consistent with WW-3915 changes
See also WW-3915
2018-02-20 17:32:45 +03:30
Lukasz Lenart 02c347afd4 Upgrades OWASP Dependency Check plugin to the latest version
and reduces CVSS to 7 to detect other important vulnerable libraries
2018-02-20 07:07:28 +01:00
Lukasz Lenart ce1ac9d381 Adds example how to use the handler 2018-02-20 06:50:06 +01:00
Lukasz Lenart 9260720568 Adds test to cover basic functionality 2018-02-20 06:49:50 +01:00
Lukasz Lenart 67ecf3a216 Defines a new handler using Jackson XML 2018-02-20 06:49:25 +01:00
Lukasz Lenart 4260bee634 Adds Jackson XML binding dependency 2018-02-20 06:48:48 +01:00
Yasser Zamani f929673a91 replace sun.net.www.ParseUtil#decode
See also WW-4920
2018-02-17 11:22:24 +03:30
Yasser Zamani 4718dccd1c comment jira issue id and fix a few typos
See also WW-4920
2018-02-16 14:14:21 +03:30
Yasser Zamani 155dff745e fix java.net.JarURLConnection#parseSpecs
See also WW-4920
2018-02-16 14:01:38 +03:30
Lukasz Lenart def4adacd6 [maven-release-plugin] prepare for next development iteration 2018-02-09 09:36:39 +01:00
Lukasz Lenart 2c0facc3aa [maven-release-plugin] prepare release STRUTS_2_5_15 2018-02-09 09:36:18 +01:00
Aleksandr Mashchenko 6ae63d7669 use NumberUtils.isCreatable instead of deprecated NumberUtils.isNumber 2018-02-06 18:22:40 +02:00
Aleksandr Mashchenko eed364fe28 Use managed surefire version in core 2018-02-05 18:39:12 +02:00
Aleksandr Mashchenko 56c6456c61 WW-4914 Update Log4j2 to 2.10.0 2018-02-05 18:31:56 +02:00
Yasser Zamani 20a7b6503f Merge pull request #207 from lukaszlenart/sessionless
WW-4741: Do not create session
2018-01-31 16:48:17 +03:30
Lukasz Lenart 2eb809144a Merge pull request #3 from yasserzamani/sessionless
test not create when no session
2018-01-31 12:16:30 +01:00
Lukasz Lenart 8ef8581d0c Merge pull request #2 from yasserzamani/sessionless
test no session but with locale parameter
2018-01-31 11:27:59 +01:00
Yasser Zamani caeea2145f test not create when no session
See also WW-4741
2018-01-31 13:57:21 +03:30
Yasser Zamani b5cfccace3 test no session but with locale parameter
See also WW-4741
2018-01-31 13:33:44 +03:30
Lukasz Lenart 95a24c87a4 Adds autogenerated file 2018-01-31 07:22:27 +01:00
Lukasz Lenart 92e931d169 WW-4741 Improves tests to cover the new logic 2018-01-31 07:21:53 +01:00
Lukasz Lenart e9a4bcd776 WW-4741 Does not create session if it doesn't exist 2018-01-31 07:21:35 +01:00
Yasser Zamani 9b892cc7fd Merge pull request #206 from lukaszlenart/scan-deeper
WW-4912: scan package-info and class at the same time
2018-01-30 13:17:09 +03:30
Lukasz Lenart 74460831dc Merge pull request #1 from yasserzamani/scan-deeper
Scan even deeper :)
2018-01-30 10:08:11 +01:00
Yasser Zamani 8d4194bbf7 allow duplicate in AnnotationUtils.findAnnotations result
See also WW-4912
2018-01-30 12:21:33 +03:30
Yasser Zamani cf71e0f34f add support finding annotations on interfaces and their packages
See also WW-4912
2018-01-30 11:35:16 +03:30
Yasser Zamani 97012c78a9 Merge pull request #189 from lukaszlenart/upgrade-spring
WW-4899: upgrade Spring
2018-01-30 10:47:04 +03:30
zalsaeed f34cf78ae3 Initial test dedicated for the DefaultUnknownHandlerManager (#205)
* Initial test dedicated for the DefaultUnknownHandlerManager

* fixed the licensing and authore comments issues that causes build to fail

* follow good practice when initializing objects

* use TestCase to enhance performance
2018-01-29 12:39:18 +03:30
Lukasz Lenart 72058bf4c6 Reverts findAnnotation to its previous state 2018-01-29 09:04:03 +01:00
Lukasz Lenart 46462b3d00 Rephrases JavaDoc to better express function's meaning 2018-01-29 08:51:17 +01:00
Lukasz Lenart a9899b6622 Introduces new method find all annotations 2018-01-26 11:47:10 +01:00
Lukasz Lenart a3180e3069 Adds test to cover searching down the hierarchy 2018-01-25 12:28:09 +01:00
Lukasz Lenart d5926b7a21 Searches hierarchy down to Object class for annotation 2018-01-25 12:27:54 +01:00
Yasser Zamani 9beb940136 Merge pull request #201 from HedjuHor/WW-4891
WW-4891 Debug tag should not display anything when not in dev mode
2018-01-20 09:39:32 +03:30
Hedju Hor 17b598433d WW-4891 PrepareOperations overrideDevMode for explicitly switch on for this action only 2018-01-18 23:10:25 +01:00
Lukasz Lenart 86baf21098 Merge pull request #203 from yasserzamani/init_test_scopes
add tests for initializable to cover more scopes
2018-01-17 10:28:47 +01:00
Yasser Zamani bba17b6496 add tests for initializable to cover more scopes 2018-01-16 14:23:41 +03:30
Yasser Zamani c3b85aef7c Merge pull request #202 from lukaszlenart/limitable-extendable
WW-4909: Renames a constant and adds a test
2018-01-16 10:49:16 +03:30
Lukasz Lenart 355e4b517f Adds additional test to cover deprecated option 2018-01-15 18:00:42 +01:00
Lukasz Lenart 1ec1e71d41 Adds test to cover the new constant 2018-01-15 17:32:34 +01:00
Lukasz Lenart e23197ab1b Uses the new constant and makes an old one deprecated 2018-01-15 17:32:24 +01:00
Lukasz Lenart c21fb94921 Defines a new constant to limit collection auto growth 2018-01-15 17:31:26 +01:00
Lukasz Lenart 9bf89f82dc Merge pull request #200 from HedjuHor/BeanValidation_GroupingConstraints
WW-4907 support JSR 303 Validation Groups in BeanValidation-Plugin
2018-01-15 12:38:27 +01:00
Lukasz Lenart 29e1847f64 Merge pull request #199 from yasserzamani/WW-4906
fix conversion by annotation and WW-4906
2018-01-15 11:50:46 +01:00
Hedju Hor 02b61b2c05 WW-4891 Debug tag should not display anything when not in dev mode 2018-01-14 15:54:41 +01:00
Hedju Hor d1df216b32 change default behavior 2018-01-13 10:59:06 +01:00
Hedju Hor 7518e809dd fixed
getValidationGroups get called if not skipped Validation
removed unnecessary LOG.isDebugEnabled()
2018-01-12 18:36:08 +01:00
Hedju Hor 2b2de35519 Revert "fixed some Logger calls. Hint:https://logging.apache.org/log4j/2.0/manual/api.html"
This reverts commit 87b2bd8
2018-01-12 18:26:27 +01:00
Hedju Hor 87b2bd8138 fixed some Logger calls.
Hint:https://logging.apache.org/log4j/2.0/manual/api.html
2018-01-11 21:04:22 +01:00
Hedju Hor 215eb627d4 refactoring ValidateGroup -> ValidationGroup 2018-01-11 19:47:14 +01:00
Yasser Zamani 29b29a9c64 Merge pull request #196 from lukaszlenart/init-like-a-boss
WW-4905: Allows Initializable interface on implementing class instead of interface
2018-01-10 12:09:14 +03:30
Yasser Zamani 5e237e0fd3 fix and add test for lazy and early initialization of prototypes 2018-01-09 21:39:34 +03:30
Lukasz Lenart 23077d3ee9 Loads classes in advance 2018-01-09 16:02:33 +01:00
Lukasz Lenart 4fbded7147 Fixes test to run under JDK8 2018-01-09 15:39:10 +01:00
Lukasz Lenart f9f0f36d29 Increases class visibility 2018-01-09 14:25:13 +01:00
Lukasz Lenart f60095bae9 Fixes failing tests 2018-01-09 13:53:45 +01:00
Lukasz Lenart e4a3669061 Moves wrapping factories into Scope 2018-01-09 13:50:57 +01:00
Hedju Hor 5e4b385984 support Constraints Group in BeanValidation-Plugin 2018-01-09 12:58:42 +01:00
Yasser Zamani 38450c9a70 improve tests for lazy and early initialization 2018-01-09 11:34:58 +03:30
Yasser Zamani df4a18107f add tests for lazy and early initialization 2018-01-08 14:42:03 +03:30
Yasser Zamani 9739291d79 change tests to cover more
Note: Also will delete CLASS from annotation type because it is already the default value
2018-01-07 17:15:36 +03:30
Yasser Zamani 4394238b7e un-deprecate TypeConversion.converter plus some improvements
See WW-4906
2018-01-07 15:49:33 +03:30
Yasser Zamani ff903e7754 add tests if conversion can get annotation from supers 2018-01-07 13:36:31 +03:30
Yasser Zamani 77cbafb74d fix conversion by annotation 2018-01-07 12:48:28 +03:30
Yasser Zamani faf50183e0 add conversion by annotation missing tests 2018-01-07 12:34:55 +03:30
Lukasz Lenart 67bdf68419 Normalises name of property with Spring version 2018-01-06 10:13:59 +01:00
Lukasz Lenart cf19d5130c Adds missing test dependency 2018-01-06 09:07:16 +01:00
Stefaan Dutry a66f92c66d Merge pull request #198 from sdutry/formatting-changes
add tests to UIBean class
2018-01-05 20:25:24 +01:00
Stefaan Dutry 08c058ea65 add test for setStyle method
Verified that the value is added as the cssStyle parameter.
2018-01-05 18:32:32 +01:00
Stefaan Dutry cd0773fb1b add test for setClass method
Verified that the value is added as the cssClass parameter.
2018-01-05 18:24:19 +01:00
Lukasz Lenart f803ddb16e Merge pull request #197 from sdutry/formatting-changes
Minor Formatting changes
2018-01-05 18:08:41 +01:00
Stefaan Dutry 0deea3f9e4 remove old subversion comments 2018-01-05 17:28:47 +01:00
Stefaan Dutry 2fd2cb5f97 add test for parameter with name "value"
Verified that the value parameter is added as the nameValue parameter.
2018-01-04 23:20:45 +01:00
Stefaan Dutry 7df1e67bac add test for setting acceskey
Verified that the value is added to the parameters after they have
been evaluated.
2018-01-04 23:08:12 +01:00
Stefaan Dutry dd76d39224 add tests for getTemplateDir method
Verified that:
- explicit templateDirectory gets precedence
- attribute templateDir gets picked if no explitit one is given
- defaultTemplateDirectory gets picked if there is no explicit one and
    an attribute templateDid
- "template" is returned as default value
2018-01-04 19:39:48 +01:00
Stefaan Dutry 476697f99a add test for buildTemplateName method
Verified that:
- default template name gets picked when no specific one is given
- specific template gets precedence over default one
2018-01-04 18:39:48 +01:00
Stefaan Dutry 0bfdc5e643 add test for mergeTemplate method
Test that a ConfigurationException is thrown when the
TemplateEngineManager returns null instead of a TemplateEngine
instance.
2018-01-04 16:32:21 +01:00
Stefaan Dutry a29051c835 add missing @Override annotation 2018-01-03 22:59:52 +01:00
Stefaan Dutry 7a251ddca9 add curly brackets (formatting)
- add curly brackets around single line conditional statements
2018-01-03 22:53:02 +01:00
Stefaan Dutry 38e3734930 change tabs into spaces (formatting) 2018-01-03 22:50:23 +01:00
Stefaan Dutry fe65910e0e change tabs into spaces (formatting) 2018-01-03 22:44:07 +01:00
Stefaan Dutry 1d0b375afd add curly brackets (formatting)
- add curly brackets around single line conditional statements
- place finally statement on same line as closing catch bracket
2018-01-03 22:26:36 +01:00
Stefaan Dutry 0713da431c add missing @Override annotations 2018-01-03 22:15:54 +01:00
Stefaan Dutry 79951db2aa change tabs into spaces (formatting) 2018-01-03 22:14:07 +01:00
Lukasz Lenart d64365770d Uses the new interface to initialise object when setting up the framework 2018-01-03 10:45:56 +01:00
Lukasz Lenart b04683181c Adjusts builder to handle the new interfaces 2018-01-03 10:45:30 +01:00
Lukasz Lenart fad603c49b Adds a dedicated interfaces to clearly tell CI which beans must be
instantiated early
2018-01-03 10:45:14 +01:00
Lukasz Lenart 87c2746fc7 Introduces dedicated factory to perform object's initialisation 2018-01-03 10:44:25 +01:00
Lukasz Lenart 49ef41c218 Drops unneeded JavaDoc formatting 2018-01-02 09:33:59 +01:00
Lukasz Lenart e1767d9525 Moves Initializable interface into implementing class instead of interface 2018-01-02 09:27:24 +01:00
Lukasz Lenart 67b7fc3f3e Avoids initialising singletons once marked as Initializable 2018-01-02 09:26:39 +01:00
Lukasz Lenart a4183b63f8 Adjusts class to the new Initializable mechanism 2018-01-01 15:51:39 +01:00
Lukasz Lenart 74dd8d6990 Adds implementation of the type() method 2018-01-01 15:47:48 +01:00
Lukasz Lenart 4152cbc71c Uses factory's type to detect Initilizable interfaces 2018-01-01 15:47:48 +01:00
Lukasz Lenart dd8ba56425 Extends factories to allow return implementing type 2018-01-01 15:47:48 +01:00
Yasser Zamani 8eb282f76b Merge pull request #195 from lukaszlenart/fix-prefix-based-factory
WW-4903: fixes PrefixBasedActionProxyFactory
2018-01-01 17:30:05 +03:30
Lukasz Lenart eabf4eda21 Verifies licenses before building a package 2018-01-01 10:15:03 +01:00
Lukasz Lenart 809d8968ca WW-4903 Adds missing header with license 2018-01-01 09:52:31 +01:00
Lukasz Lenart 033573e8fb WW-4903 Reverts to previous initialise mechanism 2018-01-01 09:50:53 +01:00
Lukasz Lenart 7cdc319b41 WW-4903 Extends test of empty prefix 2017-12-31 15:36:59 +01:00
Lukasz Lenart 7116ac8801 WW-4903 Uses StrutsActionProxyFactory as a default factory 2017-12-28 17:35:27 +01:00
Lukasz Lenart a2710a6f04 WW-4903 Covers fallback to default factory with unit test 2017-12-28 17:34:28 +01:00
Lukasz Lenart 457f7c2f57 WW-4903 Adds a unit test to cover the new functionality 2017-12-28 16:56:30 +01:00
Lukasz Lenart 6fc695970f WW-4903 Uses Initializable to properly initialise the factory 2017-12-28 16:56:09 +01:00
Lukasz Lenart 15e6be1d66 WW-4903 Drops injecting defined factory to avoid mapping exception 2017-12-28 16:24:48 +01:00
Lukasz Lenart eddab32e75 Merge pull request #194 from sdutry/sonar/string-optimize-single-characters
used char instead of a single character string
2017-12-21 07:29:48 +01:00
Stefaan Dutry fb23b719f2 used char instead of a single character string 2017-12-20 22:08:33 +01:00
Lukasz Lenart c4bd87e510 Merge pull request #193 from yasserzamani/defaultActionInvocation_coverage
Increases the coverage of DefaultActionInvocation
2017-12-18 08:24:40 +01:00
Yasser Zamani 004b4981a1 Increases the coverage of DefaultActionInvocation 2017-12-16 19:57:39 +03:30
Lukasz Lenart 8b608e334a Merge pull request #192 from yasserzamani/WW-4873_2
WW-4873 Makes ActionInvocation not serializable and InvocationSessionStore$InvocationContext transient
2017-12-16 10:44:52 +01:00
Lukasz Lenart 031bd1aceb Adds empty line to kick Travis build 2017-12-16 09:07:49 +01:00
Lukasz Lenart 9078422496 Adds cache to speed up build on Travis 2017-12-16 08:50:11 +01:00
Lukasz Lenart 278a2112b9 Merge pull request #190 from yasserzamani/WW-4901
WW-4901 Decouples from URL.openConnection implementation of container
2017-12-14 09:18:28 +01:00
Yasser Zamani 2941416a18 WW-4873 Makes InvocationSessionStore$InvocationContext transient 2017-12-14 11:05:05 +03:30
Yasser Zamani 4738d1d802 WW-4873 Makes ActionInvocation not serializable 2017-12-13 19:34:54 +03:30
Lukasz Lenart d4b620d06d Merge pull request #191 from yasserzamani/WW-4900
WW-4900 Makes BackgroundProcess transient
2017-12-13 14:30:25 +01:00
Lukasz Lenart cf8ba17454 Kicks Coveralls to build on master 2017-12-13 13:40:28 +01:00
Yasser Zamani a8ecd9bd29 WW-4900 Fixes BackgroundProcessTest via synchronization 2017-12-13 14:58:54 +03:30
Yasser Zamani 6b131550a6 WW-4900 Reverts BackgroundProcess access modifiers 2017-12-13 13:11:35 +03:30
Yasser Zamani dda3facc26 WW-4900 Makes BackgroundProcess transient 2017-12-13 12:41:22 +03:30
Yasser Zamani d082aaca2a WW-4901 Falls back if JarURLConnection was present already 2017-12-12 16:24:17 +03:30
Yasser Zamani 94758b699c WW-4901 Decouples Struts from URL.openConnection implementation of container 2017-12-12 00:26:44 +03:30
Lukasz Lenart bfa119c7db Uses proper date format 2017-12-04 08:29:54 +01:00
Lukasz Lenart 7058872723 Adds missing dependency 2017-12-04 08:29:44 +01:00
Lukasz Lenart 6c3316a14a Fixes test 2017-12-04 08:29:29 +01:00
Lukasz Lenart e717e469a4 Uses the latest Spring version 2017-12-04 08:29:12 +01:00
Stefaan Dutry 80698ed516 Merge pull request #186 from sdutry/sonar-entrySet
changed Map iterations to use entrySet when both key and value are used
2017-12-01 20:46:00 +01:00
Lukasz Lenart 9b9bd212ed [maven-release-plugin] prepare for next development iteration 2017-11-29 08:35:58 +01:00
Lukasz Lenart 0856157e27 [maven-release-plugin] prepare release STRUTS_2_5_14_1 2017-11-29 08:35:37 +01:00
Lukasz Lenart bea5537e9e Fixes issue with accessing the Central
relates to https://github.com/jeremylong/DependencyCheck/issues/978
2017-11-28 09:36:21 +01:00
Lukasz Lenart 7c7d5be441 Merge pull request #187 from lukaszlenart/jackson-5
WW-4892 WW-4893: Use Jackson to handle JSON request
2017-11-28 08:15:13 +01:00
Lukasz Lenart a728c74f21 Merge pull request #183 from lukaszlenart/pimp-my-struts
Pimp my struts
2017-11-28 08:14:40 +01:00
Lukasz Lenart 76d0bc5ff4 Adds support to generate a report with outdated dependencies 2017-11-27 15:47:35 +01:00
Lukasz Lenart ad98881dd5 Adds support for UpdateImpact 2017-11-27 15:38:22 +01:00
Lukasz Lenart 0207c09b11 Adds missing license header 2017-11-27 10:28:14 +01:00
Lukasz Lenart 5ef7687259 Suppresses some false positives on OWASP Dependency Check 2017-11-27 08:19:15 +01:00
Lukasz Lenart 794cd5e141 WW-4892 Marks handler as deprecated 2017-11-17 09:34:22 +01:00
Lukasz Lenart a2824b7c87 WW-4892 Makes json-lib optional 2017-11-17 09:33:00 +01:00
Lukasz Lenart 941374ecdb WW-4892 Uses Jackson handler as a default one to handle JSON 2017-11-17 09:32:43 +01:00
Lukasz Lenart 0d42ff50ac WW-4893 Upgrades Jackson to version 2.9.2 2017-11-17 09:32:06 +01:00
Stefaan Dutry 00b5f43c8a changed tabs into spaces 2017-11-15 13:58:15 +01:00
Stefaan Dutry 87967b9f84 changed Map iteration to use entrySet 2017-11-15 13:54:20 +01:00
Lukasz Lenart d36ec579fc [maven-release-plugin] prepare for next development iteration 2017-11-14 07:43:35 +01:00
Stefaan Dutry 0bde78cc36 changed Map iterations to use entrySet when both key and value are used 2017-11-13 21:13:27 +01:00
Lukasz Lenart c14dca5be3 Uses full plugin name 2017-11-11 10:11:06 +01:00
Lukasz Lenart 7c4f30f619 Drops unneeded property 2017-11-11 10:10:54 +01:00
Lukasz Lenart c956d1a40d Adds support for coveralls 2017-11-11 09:42:29 +01:00
Lukasz Lenart a92eb529a9 Adds proper header and some links 2017-11-11 09:28:58 +01:00
Lukasz Lenart 882a6e803e Adds Coverage status 2017-11-11 09:20:28 +01:00
239 changed files with 5800 additions and 1030 deletions
+1
View File
@@ -62,3 +62,4 @@ bundles/target
plugins/target
target
plugins/testng/test-output
test-output
+110
View File
@@ -0,0 +1,110 @@
/*
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.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
/**
* 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/0.4.0/maven-wrapper-0.4.0.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 direcrory '" + 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 {
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();
}
}
BIN
View File
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip
+20 -1
View File
@@ -4,6 +4,25 @@ sudo: false
jdk:
- openjdk7
- oraclejdk8
- oraclejdk9
- oraclejdk11
install: true
script: mvn test -DskipAssembly
script: mvn test -DskipAssembly
after_success:
# TODO delete following if statement after fix of https://github.com/cobertura/cobertura/issues/271
- if [ "$TRAVIS_JDK_VERSION" == "openjdk8" ] || [ "$TRAVIS_JDK_VERSION" == "oraclejdk8" ]; then
mvn cobertura:cobertura org.eluder.coveralls:coveralls-maven-plugin:report com.updateimpact:updateimpact-maven-plugin:submit -Ptravis-coveralls,update-impact -DskipAssembly;
else
echo "Not reporting coverage for $TRAVIS_JDK_VERSION due to incompatibility or to save performance";
fi;
env:
global:
secure: DusDFL9cuX+mj64tXQfrYVbUVYnxlXmad4nuIMj0/lgDbwJ6kxYasJmR99bdvwu08gS9D5b7a+m7WJTN0FNATzEiiGDXcM+TiDPlYDh7dcalU4QGiLmMuCCEw1r7hp2XE4BWVgDfFhCsHhStgjE4RXzHIyPowoPXr4ugPf8at6w=
cache:
directories:
- $HOME/.m2
+73 -16
View File
@@ -1,41 +1,98 @@
<!---
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.
-->
The Apache Struts web framework
-------------------------------
[![Build Status @ Jenkins](https://builds.apache.org/buildStatus/icon?job=Struts-master-JDK7)](https://builds.apache.org/view/S-Z/view/Struts/job/Struts-master-JDK7/)
[![Build Status @ Travis](https://travis-ci.org/apache/struts.svg?branch=master)](https://travis-ci.org/apache/struts)
[![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/)
[![Coverage Status](https://coveralls.io/repos/github/apache/struts/badge.svg)](https://coveralls.io/github/apache/struts)
[![Dependencies](https://app.updateimpact.com/badge/713283867011846144/Struts%202.svg?config=test)](https://app.updateimpact.com/latest/713283867011846144/Struts%202)
[![License](http://img.shields.io/:license-apache-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0.html)
The Apache Struts web framework is a free open-source solution for creating Java web applications.
Web applications differ from conventional websites in that web applications can create a dynamic response. Many websites deliver only static pages. A web application can interact with databases and business logic engines to customize a response.
## Documentation
Web applications based on JavaServer Pages sometimes commingle database code, page design code, and control flow code. In practice, we find that unless these concerns are separated, larger applications become difficult to maintain.
More information can be found on the [homepage](https://struts.apache.org/). Please read the [Security Guide](https://struts.apache.org/security/)
and the [JavaDocs](https://struts.apache.org/maven/struts2-core/apidocs/index.html) can be browsed.
Questions related to the usage of the Apache Struts should be posted to the [user mailing list](https://struts.apache.org/mail.html).
One way to separate concerns in a software application is to use a Model-View-Controller (MVC) architecture. The Model represents the business or database code, the View represents the page design code, and the Controller represents the navigational code. The Struts framework is designed to help developers create web applications that utilize a MVC architecture.
## Description
Web applications differ from conventional websites in that web applications can create a dynamic response. Many websites
deliver only static pages. A web application can interact with databases and business logic engines to customize a response.
Web applications based on JavaServer Pages sometimes commingle database code, page design code, and control flow code.
In practice, we find that unless these concerns are separated, larger applications become difficult to maintain.
One way to separate concerns in a software application is to use a Model-View-Controller (MVC) architecture. The Model
represents the business or database code, the View represents the page design code, and the Controller represents
the navigational code. The Struts framework is designed to help developers create web applications that utilize
a MVC architecture.
The framework provides three key components:
A “request” handler provided by the application developer that is mapped to a standard URI. A “response” handler that transfers control to another resource which completes the response. A tag library that helps developers create interactive form-based applications with server pages. The frameworks architecture and tags are buzzword compliant. Struts works well with conventional REST applications and with technologies like SOAP and AJAX.
A “request” handler provided by the application developer that is mapped to a standard URI. A “response” handler that
transfers control to another resource which completes the response. A tag library that helps developers create interactive
form-based applications with server pages. The frameworks architecture and tags are buzzword compliant. Struts works well
with conventional REST applications and with technologies like SOAP and AJAX.
The Apache Struts Project
-------------------------
## The Apache Struts Project
The Apache Struts Project is the open source community that creates and maintains the Apache Struts framework. The project consists of a diverse group of volunteers who share common values regarding collaborative, community-based open source development. The Apache Struts Project is proud to share these values with our parent organization: The Apache Software Foundation.
The Apache Struts Project is the open source community that creates and maintains the Apache Struts framework.
The project consists of a diverse group of volunteers who share common values regarding collaborative, community-based
open source development. The Apache Struts Project is proud to share these values with our parent organization:
The Apache Software Foundation.
The project is called “Struts” because the framework is meant to furnish the “invisible underpinnings” that support professional application development. Struts provides the glue that joins the various elements of the standard Java platform into a coherent whole. Our goal is to leverage existing standards by producing the missing pieces we need to create enterprise-grade applications that are easy to maintain over time.
The project is called “Struts” because the framework is meant to furnish the “invisible underpinnings” that support
professional application development. Struts provides the glue that joins the various elements of the standard Java
platform into a coherent whole. Our goal is to leverage existing standards by producing the missing pieces we need to create
enterprise-grade applications that are easy to maintain over time.
The Apache Struts Project offered two major versions of the Struts framework. Currently we are only maintaining the Struts 2 version. It is recommended to upgrade all Struts 1.x application to Struts 2. Please do not start new application development using Struts 1.x, as we are no longer issuing security patches.
The Apache Struts Project offered two major versions of the Struts framework. Currently we are only maintaining the Struts 2
version. It is recommended to upgrade all Struts 1.x application to Struts 2. Please do not start new application development
using Struts 1.x, as we are no longer issuing security patches.
Struts 2 was originally known as WebWork 2. After working independently for several years, the WebWork and Struts communities joined forces to create Struts 2. The 2.x framework is the best choice for teams who value elegant solutions to difficult problems.
Struts 2 was originally known as WebWork 2. After working independently for several years, the WebWork and Struts
communities joined forces to create Struts 2. The 2.x framework is the best choice for teams who value elegant solutions
to difficult problems.
Why should you use Apache Struts?
---------------------------------
## Why should you use Apache Struts?
Apache Struts is a modern, maintained and full-featured web framework. It has been there for years and give the huge user base it is unlikely it will go away anytime soon in the future. Not only that we have dedicated users and developers on the project. Apache Struts is licensed to the Apache License 2.0 and this will not change. We maintain a clean IP and you are “safe” to use the project. Sometimes you are not “safe” to use a project when a company controls the SCM. Access to Source Code doesnt mean it is free. With Apache Struts, you are not only free to “do what you want with it”, you can even contribute (which is not always the case). And best of it: you can become a part of the core team too.
Apache Struts is a modern, maintained and full-featured web framework. It has been there for years and give the huge user
base it is unlikely it will go away anytime soon in the future. Not only that we have dedicated users and developers
on the project. Apache Struts is licensed to the Apache License 2.0 and this will not change. We maintain a clean IP
and you are “safe” to use the project. Sometimes you are not “safe” to use a project when a company controls the SCM.
Access to Source Code doesnt mean it is free. With Apache Struts, you are not only free to “do what you want with it”,
you can even contribute (which is not always the case). And best of it: you can become a part of the core team too.
It is usually very easy to integrate other technologies with Apache Struts. If you are using an ORM like Apache Cayenne, Hibernate or JDBC you will not have any restrictions. Apache Struts is not even tied too much to a frontend technology. In old days it was JSP, then came Velocity and Freemarker. Nowadays you might build your web application with just static HTML and AngularJS. Or you want to use Sitemesh or Tiles. This all is no problem due to Struts elegant and easy to use extension mechanisms.
It is usually very easy to integrate other technologies with Apache Struts. If you are using an ORM like Apache Cayenne,
Hibernate or JDBC you will not have any restrictions. Apache Struts is not even tied too much to a frontend technology.
In old days it was JSP, then came Velocity and Freemarker. Nowadays you might build your web application with just static
HTML and AngularJS. Or you want to use Sitemesh or Tiles. This all is no problem due to Struts elegant and easy to use
extension mechanisms.
Unlike other, component oriented frameworks, we do not aim to hide the stateless nature of the web. We think it is perfectly acceptable to build upon a Request/Response cycle. We also think the MVC pattern is not so bad, just because it is old. In fact, we believe the Apache Struts architecture is clean and easy to understand.
Unlike other, component oriented frameworks, we do not aim to hide the stateless nature of the web. We think it is
perfectly acceptable to build upon a Request/Response cycle. We also think the MVC pattern is not so bad, just because
it is old. In fact, we believe the Apache Struts architecture is clean and easy to understand.
Of course, if you wish to build components on the server side which render on the front end side, you are most likely wrong with Struts. This is a different approach which promises to reduce the amount of HTML/JavaScript knowledge needed and to create reusable components for the view layer. Projects like Wicket and Tapestry serve this purpose very well. As with every framework you need to decide if it makes sense for you to build components or if you are better with the Struts-approach.
Of course, if you wish to build components on the server side which render on the front end side, you are most likely
wrong with Struts. This is a different approach which promises to reduce the amount of HTML/JavaScript knowledge needed
and to create reusable components for the view layer. Projects like Wicket and Tapestry serve this purpose very well.
As with every framework you need to decide if it makes sense for you to build components or if you are better with
the Struts-approach.
+2 -2
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.5.14</version>
<version>2.5.20</version>
</parent>
<artifactId>struts2-apps</artifactId>
<packaging>pom</packaging>
@@ -99,7 +99,7 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${struts2.springPlatformVersion}</version>
<version>${spring.platformVersion}</version>
<scope>test</scope>
</dependency>
</dependencies>
+7 -2
View File
@@ -24,12 +24,12 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-apps</artifactId>
<version>2.5.14</version>
<version>2.5.20</version>
</parent>
<artifactId>struts2-rest-showcase</artifactId>
<packaging>war</packaging>
<version>2.5.14</version>
<version>2.5.20</version>
<name>Struts 2 Rest Showcase Webapp</name>
<description>Struts 2 Rest Showcase Example</description>
@@ -47,6 +47,11 @@
<artifactId>struts2-config-browser-plugin</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
@@ -32,6 +32,12 @@
<constant name="struts.convention.package.locators" value="example"/>
<!-- Uncomment the lines below to use Jackson XML bindings instead of the XStream library to handle XML serialisations -->
<!--
<bean name="jacksonXml" type="org.apache.struts2.rest.handler.ContentTypeHandler" class="org.apache.struts2.rest.handler.JacksonXmlHandler" />
<constant name="struts.rest.handlerOverride.xml" value="jacksonXml"/>
-->
<package name="rest-showcase" extends="rest-default">
<global-allowed-methods>index,show,create,update,destroy,deleteConfirm,edit,editNew</global-allowed-methods>
</package>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-apps</artifactId>
<version>2.5.14</version>
<version>2.5.20</version>
</parent>
<artifactId>struts2-showcase</artifactId>
@@ -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.showcase.tag.nonui.debugtag;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.dispatcher.PrepareOperations;
public class DebugTagAction extends ActionSupport {
public String execute() throws Exception {
PrepareOperations.overrideDevMode(true); // Just for Showcase, explicitly switch on for this action only
return SUCCESS;
}
}
@@ -151,7 +151,7 @@
<action name="date">
<result>/WEB-INF/tags/non-ui/date.jsp</result>
</action>
<action name="debugTagDemo">
<action name="debugTagDemo" class="org.apache.struts2.showcase.tag.nonui.debugtag.DebugTagAction">
<result>/WEB-INF/tags/non-ui/debug.jsp</result>
</action>
</package>
+2 -2
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.5.14</version>
<version>2.5.20</version>
</parent>
<artifactId>struts2-assembly</artifactId>
@@ -111,7 +111,7 @@
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>attached</goal>
<goal>single</goal>
</goals>
</execution>
</executions>
+6 -6
View File
@@ -1,6 +1,6 @@
http://struts.apache.org/getting-started/
http://struts.apache.org/security/
http://struts.apache.org/core-developers/
http://struts.apache.org/tag-developers/
http://struts.apache.org/maven-archetypes/
http://struts.apache.org/plugins/
https://struts.apache.org/getting-started/
https://struts.apache.org/security/
https://struts.apache.org/core-developers/
https://struts.apache.org/tag-developers/
https://struts.apache.org/maven-archetypes/
https://struts.apache.org/plugins/
+3 -3
View File
@@ -30,7 +30,7 @@
</parent>
<artifactId>struts2-bom</artifactId>
<version>2.5.14</version>
<version>2.5.20</version>
<packaging>pom</packaging>
<name>Struts 2 Bill of Materials</name>
@@ -45,7 +45,7 @@
</licenses>
<properties>
<struts-version.version>2.5.14</struts-version.version>
<struts-version.version>2.5.20</struts-version.version>
<maven.site.skip>true</maven.site.skip>
<maven.site.deploy.skip>true</maven.site.deploy.skip>
</properties>
@@ -181,6 +181,6 @@
</dependencyManagement>
<scm>
<tag>STRUTS_2_5_14</tag>
<tag>STRUTS_2_5_20</tag>
</scm>
</project>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-osgi-bundles</artifactId>
<version>2.5.14</version>
<version>2.5.20</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>2.5.14</version>
<version>2.5.20</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>2.5.14</version>
<version>2.5.20</version>
</parent>
<artifactId>struts2-osgi-bundles</artifactId>
+1 -3
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.5.14</version>
<version>2.5.20</version>
</parent>
<artifactId>struts2-core</artifactId>
<packaging>jar</packaging>
@@ -40,7 +40,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.6</version>
<configuration>
<argLine>-Duser.language=en -Duser.region=US</argLine>
<properties>
@@ -65,7 +64,6 @@
<exclude>**/TestBean2.java</exclude>
<exclude>**/TestInterceptor.java</exclude>
<exclude>**/AnnotatedTestBean.java</exclude>
<exclude>**/ContainerImplTest.java</exclude>
<exclude>**/DefaultFileManagerTest.java</exclude>
</excludes>
</configuration>
@@ -201,13 +201,10 @@ public class ActionChainResult implements Result {
* @param invocation the DefaultActionInvocation calling the action call stack
*/
public void execute(ActionInvocation invocation) throws Exception {
// if the finalNamespace wasn't explicitly defined, assume the current one
if (this.namespace == null) {
this.namespace = invocation.getProxy().getNamespace();
}
ValueStack stack = ActionContext.getContext().getValueStack();
String finalNamespace = TextParseUtil.translateVariables(namespace, stack);
String finalNamespace = this.namespace != null
? TextParseUtil.translateVariables(namespace, stack)
: invocation.getProxy().getNamespace();
String finalActionName = TextParseUtil.translateVariables(actionName, stack);
String finalMethodName = this.methodName != null
? TextParseUtil.translateVariables(this.methodName, stack)
@@ -21,8 +21,6 @@ package com.opensymphony.xwork2;
import com.opensymphony.xwork2.interceptor.PreResultListener;
import com.opensymphony.xwork2.util.ValueStack;
import java.io.Serializable;
/**
* An {@link ActionInvocation} represents the execution state of an {@link Action}. It holds the Interceptors and the Action instance.
* By repeated re-entrant execution of the <code>invoke()</code> method, initially by the {@link ActionProxy}, then by the Interceptors, the
@@ -31,7 +29,7 @@ import java.io.Serializable;
* @author Jason Carreira
* @see com.opensymphony.xwork2.ActionProxy
*/
public interface ActionInvocation extends Serializable {
public interface ActionInvocation {
/**
* Get the Action associated with this ActionInvocation.
@@ -178,20 +176,4 @@ public interface ActionInvocation extends Serializable {
void init(ActionProxy proxy) ;
/**
* Prepares instance of ActionInvocation to be serializable,
* which simple means removing all unserializable fields, eg. Container
*
* @return ActionInvocation which can be serialize (eg. into HttpSession)
*/
ActionInvocation serialize();
/**
* Performs opposite process to restore back ActionInvocation after deserialisation
*
* @param actionContext current {@link ActionContext}
* @return fully operational ActionInvocation
*/
ActionInvocation deserialize(ActionContext actionContext);
}
@@ -500,27 +500,4 @@ public class DefaultActionInvocation implements ActionInvocation {
}
}
/**
* Version ready to be serialize
*
* @return instance without reference to {@link Container}
*/
public ActionInvocation serialize() {
DefaultActionInvocation that = this;
that.container = null;
return that;
}
/**
* Restoring Container
*
* @param actionContext current {@link ActionContext}
* @return instance which can be used to invoke action
*/
public ActionInvocation deserialize(ActionContext actionContext) {
DefaultActionInvocation that = this;
that.container = actionContext.getContainer();
return that;
}
}
@@ -36,7 +36,7 @@ public interface FileManager {
void setReloadingConfigs(boolean reloadingConfigs);
/**
* Checks if given file changed and must be reloaded if {@link #setReloadingConfigs(boolean)} is true
* Checks if given file changed and must be reloaded
*
* @param fileName to check
* @return true if file changed
@@ -44,7 +44,7 @@ public interface FileManager {
boolean fileNeedsReloading(String fileName);
/**
* Checks if file represented by provided URL should be reloaded
* Checks if file represented by provided URL changed and must be reloaded
*
* @param fileUrl url to a file
* @return true if file exists and should be reloaded, if url is null return false
@@ -61,7 +61,7 @@ public interface FileManager {
InputStream loadFile(URL fileUrl);
/**
* Adds file to list of monitored files if {@link #setReloadingConfigs(boolean)} is true
* Adds file to list of monitored files
*
* @param fileUrl {@link URL} to file to be monitored
*/
@@ -74,6 +74,10 @@ public abstract class XWorkJUnit4TestCase {
return impl;
}
@Override
public Class type() {
return impl.getClass();
}
}, Scope.SINGLETON);
}
});
@@ -82,7 +82,11 @@ public abstract class XWorkTestCase extends TestCase {
public Object create(Context context) throws Exception {
return impl;
}
@Override
public Class type() {
return impl.getClass();
}
}, Scope.SINGLETON);
}
});
@@ -56,7 +56,7 @@ public class AllowedMethods {
if (isPattern && !method.startsWith("regex:") && !strictMethodInvocation) {
allowedMethods.add(new PatternAllowedMethod(methodPattern.toString(), method));
} else if (method.startsWith("regex:")) {
String pattern = method.substring(method.indexOf(":") + 1);
String pattern = method.substring(method.indexOf(':') + 1);
allowedMethods.add(new PatternAllowedMethod(pattern, method));
} else if (method.contains("*") && !method.startsWith("regex:") && !strictMethodInvocation) {
String pattern = method.replace("*", defaultRegex);
@@ -154,15 +154,15 @@ public abstract class AbstractMatcher<E> implements Serializable {
Map<String, String> map = new LinkedHashMap<>();
//this will set the group index references, like {1}
for (String key : orig.keySet()) {
map.put(key, convertParam(orig.get(key), vars));
for (Map.Entry<String,String> entry : orig.entrySet()) {
map.put(entry.getKey(), convertParam(entry.getValue(), vars));
}
//the values map will contain entries like name->"Lex Luthor" and 1->"Lex Luthor"
//now add the non-numeric values
for (String key: vars.keySet()) {
if (!NumberUtils.isNumber(key)) {
map.put(key, vars.get(key));
for (Map.Entry<String,String> entry: vars.entrySet()) {
if (!NumberUtils.isCreatable(entry.getKey())) {
map.put(entry.getKey(), entry.getValue());
}
}
@@ -59,8 +59,8 @@ public class ActionConfigMatcher extends AbstractMatcher<ActionConfig> implement
Map<String, ActionConfig> configs,
boolean looseMatch) {
super(patternMatcher);
for (String name : configs.keySet()) {
addPattern(name, configs.get(name), looseMatch);
for (Map.Entry<String, ActionConfig> entry : configs.entrySet()) {
addPattern(entry.getKey(), entry.getValue(), looseMatch);
}
}
@@ -172,6 +172,11 @@ public class DefaultConfiguration implements Configuration {
public Configuration create(Context context) throws Exception {
return DefaultConfiguration.this;
}
@Override
public Class<? extends Configuration> type() {
return DefaultConfiguration.this.getClass();
}
});
ActionContext oldContext = ActionContext.getContext();
@@ -419,8 +424,8 @@ public class DefaultConfiguration implements Configuration {
this.namespaceActionConfigMatchers = new LinkedHashMap<>();
this.namespaceMatcher = new NamespaceMatcher(matcher, namespaceActionConfigs.keySet());
for (String ns : namespaceActionConfigs.keySet()) {
namespaceActionConfigMatchers.put(ns, new ActionConfigMatcher(matcher, namespaceActionConfigs.get(ns), true));
for (Map.Entry<String, Map<String, ActionConfig>> entry : namespaceActionConfigs.entrySet()) {
namespaceActionConfigMatchers.put(entry.getKey(), new ActionConfigMatcher(matcher, entry.getValue(), true));
}
}
@@ -496,11 +501,11 @@ public class DefaultConfiguration implements Configuration {
public String toString() {
StringBuilder buff = new StringBuilder("RuntimeConfiguration - actions are\n");
for (String namespace : namespaceActionConfigs.keySet()) {
Map<String, ActionConfig> actionConfigs = namespaceActionConfigs.get(namespace);
for (Map.Entry<String, Map<String, ActionConfig>> entry : namespaceActionConfigs.entrySet()) {
Map<String, ActionConfig> actionConfigs = entry.getValue();
for (String s : actionConfigs.keySet()) {
buff.append(namespace).append("/").append(s).append("\n");
buff.append(entry.getKey()).append("/").append(s).append("\n");
}
}
@@ -36,7 +36,12 @@ public class LocatableConstantFactory<T> extends Located implements Factory {
public T create(Context ignored) {
return constant;
}
@Override
public Class type() {
return constant.getClass();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
@@ -51,6 +51,11 @@ public class LocatableFactory<T> extends Located implements Factory<T> {
return (T) obj;
}
@Override
public Class<? extends T> type() {
return implementation;
}
@Override
public String toString() {
String fields = new LinkedHashMap<String, Object>() {
@@ -130,8 +130,8 @@ public class InterceptorBuilder {
* interceptorStack1 -> [interceptor1.param1 -> someValue, interceptor1.param2 -> anotherValue]
*
*/
for (String key : refParams.keySet()) {
String value = refParams.get(key);
for (Map.Entry<String, String> entry : refParams.entrySet()) {
String key = entry.getKey();
try {
String name = key.substring(0, key.indexOf('.'));
@@ -144,7 +144,7 @@ public class InterceptorBuilder {
map = new LinkedHashMap<>();
}
map.put(key, value);
map.put(key, entry.getValue());
params.put(name, map);
} catch (Exception e) {
@@ -154,9 +154,9 @@ public class InterceptorBuilder {
result = new ArrayList<>(stackConfig.getInterceptors());
for (String key : params.keySet()) {
Map<String, String> map = params.get(key);
for (Map.Entry<String, Map<String, String>> entry : params.entrySet()) {
String key = entry.getKey();
Map<String, String> map = entry.getValue();
Object interceptorCfgObj = interceptorLocator.getInterceptorConfig(key);
@@ -113,6 +113,7 @@ import ognl.PropertyAccessor;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.dispatcher.HttpParameters;
import org.apache.struts2.dispatcher.Parameter;
import org.apache.struts2.factory.PrefixBasedActionProxyFactory;
import java.util.ArrayList;
import java.util.Collection;
@@ -225,6 +226,7 @@ public class XWorkConfigurationProvider implements ConfigurationProvider {
props.setProperty(XWorkConstants.ENABLE_OGNL_EXPRESSION_CACHE, Boolean.TRUE.toString());
props.setProperty(XWorkConstants.ENABLE_OGNL_EVAL_EXPRESSION, Boolean.FALSE.toString());
props.setProperty(XWorkConstants.RELOAD_XML_CONFIGURATION, Boolean.FALSE.toString());
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, Boolean.FALSE.toString());
}
}
@@ -18,12 +18,10 @@
*/
package com.opensymphony.xwork2.conversion;
import com.opensymphony.xwork2.inject.Initializable;
/**
* Used to read converters from Properties file
*/
public interface ConversionPropertiesProcessor extends Initializable {
public interface ConversionPropertiesProcessor {
/**
* Process given property to load converters as not required (Properties file doesn't have to exist)
@@ -82,15 +82,15 @@ import java.lang.annotation.Target;
* </tr>
* <tr>
* <td>converter</td>
* <td>DEPRECATED: either this or value</td>
* <td>either this or value</td>
* <td>&nbsp;</td>
* <td>The class name of the TypeConverter to be used as converter.</td>
* <td>The class or bean name of the TypeConverter to be used as converter.</td>
* </tr>
* <tr>
* <td>converterClass</td>
* <td>either this or value</td>
* <td>&nbsp;</td>
* <td>The class of the TypeConverter to be used as converter. XWorkBasicConverter by default.</td>
* <td>XWorkBasicConverter</td>
* <td>The class of the TypeConverter to be used as converter.</td>
* </tr>
* <tr>
* <td>value</td>
@@ -181,14 +181,13 @@ public @interface TypeConversion {
ConversionRule rule() default ConversionRule.PROPERTY;
/**
* The class of the TypeConverter to be used as converter.
* The class or bean name of the TypeConverter to be used as converter.
*
* Note: This can not be used with ConversionRule.KEY_PROPERTY!
*
* @return class of the TypeConverter to be used as converter
* @deprecated user {@link #converterClass()} instead
* @return class or bean name of the TypeConverter to be used as converter
* @see {@link #converterClass()}
*/
@Deprecated
String converter() default "";
/**
@@ -21,7 +21,6 @@ package com.opensymphony.xwork2.conversion.impl;
import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
import com.opensymphony.xwork2.conversion.TypeConverter;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.XWorkList;
import java.lang.reflect.Member;
import java.util.Collection;
@@ -26,6 +26,7 @@ import com.opensymphony.xwork2.conversion.annotations.ConversionRule;
import com.opensymphony.xwork2.conversion.annotations.ConversionType;
import com.opensymphony.xwork2.conversion.annotations.TypeConversion;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.ClassLoaderUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -69,7 +70,7 @@ public class DefaultConversionAnnotationProcessor implements ConversionAnnotatio
mapping.put(key, tc.value());
}
//for properties of classes
else if (tc.rule() != ConversionRule.ELEMENT || tc.rule() == ConversionRule.KEY || tc.rule() == ConversionRule.COLLECTION) {
else if (tc.rule() != ConversionRule.ELEMENT && tc.rule() != ConversionRule.KEY && tc.rule() != ConversionRule.COLLECTION) {
if (StringUtils.isNoneEmpty(tc.converter())) {
mapping.put(key, converterCreator.createTypeConverter(tc.converter()));
} else {
@@ -80,18 +81,22 @@ public class DefaultConversionAnnotationProcessor implements ConversionAnnotatio
else if (tc.rule() == ConversionRule.KEY) {
Class<?> converterClass;
if (StringUtils.isNoneEmpty(tc.converter())) {
converterClass = Thread.currentThread().getContextClassLoader().loadClass(tc.converter());
//check if the converter is a type converter if it is one
//then just put it in the map as is. Otherwise
//put a value in for the type converter of the class
converterClass = ClassLoaderUtil.loadClass(tc.converter(), this.getClass());
} else {
converterClass = tc.converterClass();
}
LOG.debug("Converter class: [{}]", converterClass);
//check if the converter is a type converter if it is one
//then just put it in the map as is. Otherwise
//put a value in for the type converter of the class
if (converterClass.isAssignableFrom(TypeConverter.class)) {
mapping.put(key, converterCreator.createTypeConverter(tc.converter()));
if (StringUtils.isNoneEmpty(tc.converter())) {
mapping.put(key, converterCreator.createTypeConverter(tc.converter()));
} else {
mapping.put(key, converterCreator.createTypeConverter(tc.converterClass()));
}
} else {
mapping.put(key, converterClass);
LOG.debug("Object placed in mapping for key [{}] is [{}]", key, mapping.get(key));
@@ -100,7 +105,7 @@ public class DefaultConversionAnnotationProcessor implements ConversionAnnotatio
//elements(values) of maps / lists
else {
if (StringUtils.isNoneEmpty(tc.converter())) {
mapping.put(key, Thread.currentThread().getContextClassLoader().loadClass(tc.converter()));
mapping.put(key, ClassLoaderUtil.loadClass(tc.converter(), this.getClass()));
} else {
mapping.put(key, tc.converterClass());
}
@@ -86,7 +86,7 @@ public class DefaultConversionFileProcessor implements ConversionFileProcessor {
//for keys of Maps
else if (key.startsWith(DefaultObjectTypeDeterminer.KEY_PREFIX)) {
Class converterClass = Thread.currentThread().getContextClassLoader().loadClass((String) entry.getValue());
Class converterClass = ClassLoaderUtil.loadClass((String) entry.getValue(), this.getClass());
//check if the converter is a type converter if it is one
//then just put it in the map as is. Otherwise
@@ -102,7 +102,7 @@ public class DefaultConversionFileProcessor implements ConversionFileProcessor {
}
//elements(values) of maps / lists
else {
Class _c = Thread.currentThread().getContextClassLoader().loadClass((String) entry.getValue());
Class _c = ClassLoaderUtil.loadClass((String) entry.getValue(), this.getClass());
LOG.debug("\t{}:{} [treated as Class {}]", key, entry.getValue(), _c);
mapping.put(key, _c);
}
@@ -23,6 +23,8 @@ import com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor;
import com.opensymphony.xwork2.conversion.TypeConverter;
import com.opensymphony.xwork2.conversion.TypeConverterCreator;
import com.opensymphony.xwork2.conversion.TypeConverterHolder;
import com.opensymphony.xwork2.inject.EarlyInitializable;
import com.opensymphony.xwork2.inject.Initializable;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.ClassLoaderUtil;
import org.apache.logging.log4j.Logger;
@@ -34,7 +36,7 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
public class DefaultConversionPropertiesProcessor implements ConversionPropertiesProcessor {
public class DefaultConversionPropertiesProcessor implements ConversionPropertiesProcessor, EarlyInitializable {
private static final Logger LOG = LogManager.getLogger(DefaultConversionPropertiesProcessor.class);
@@ -412,8 +412,8 @@ public class XWorkConverter extends DefaultTypeConverter {
Object converter = mapping.get(property);
if (converter == null && LOG.isDebugEnabled()) {
LOG.debug("Converter is null for property [{}]. Mapping size [{}]:", property, mapping.size());
for (String next : mapping.keySet()) {
LOG.debug("{}:{}", next, mapping.get(next));
for (Map.Entry<String, Object> entry : mapping.entrySet()) {
LOG.debug("{}:{}", entry.getKey(), entry.getValue());
}
}
return converter;
@@ -500,15 +500,32 @@ public class XWorkConverter extends DefaultTypeConverter {
for (Annotation annotation : annotations) {
if (annotation instanceof TypeConversion) {
TypeConversion tc = (TypeConversion) annotation;
if (mapping.containsKey(tc.key())) {
break;
}
String key = tc.key();
// Default to the property name
// Default to the property name with prefix
if (StringUtils.isEmpty(key)) {
key = AnnotationUtils.resolvePropertyName(method);
switch (tc.rule()) {
case COLLECTION:
key = DefaultObjectTypeDeterminer.DEPRECATED_ELEMENT_PREFIX + key;
break;
case CREATE_IF_NULL:
key = DefaultObjectTypeDeterminer.CREATE_IF_NULL_PREFIX + key;
break;
case ELEMENT:
key = DefaultObjectTypeDeterminer.ELEMENT_PREFIX + key;
break;
case KEY:
key = DefaultObjectTypeDeterminer.KEY_PREFIX + key;
break;
case KEY_PROPERTY:
key = DefaultObjectTypeDeterminer.KEY_PROPERTY_PREFIX + key;
break;
}
LOG.debug("Retrieved key [{}] from method name [{}]", key, method.getName());
}
if (mapping.containsKey(key)) {
break;
}
annotationProcessor.process(mapping, tc, key);
}
}
@@ -16,13 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
package com.opensymphony.xwork2.util;
package com.opensymphony.xwork2.conversion.impl;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.XWorkException;
import com.opensymphony.xwork2.conversion.TypeConverter;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -47,7 +47,7 @@ public final class ContainerBuilder {
final Map<Key<?>, InternalFactory<?>> factories = new HashMap<>();
final List<InternalFactory<?>> singletonFactories = new ArrayList<>();
final List<InternalFactory<?>> initializableFactories = new ArrayList<>();
final List<InternalFactory<?>> earlyInitializableFactories = new ArrayList<>();
final List<Class<?>> staticInjections = new ArrayList<>();
boolean created;
boolean allowDuplicates = false;
@@ -57,6 +57,11 @@ public final class ContainerBuilder {
public Container create(InternalContext context) {
return context.getContainer();
}
@Override
public Class<? extends Container> type() {
return Container.class;
}
};
private static final InternalFactory<Logger> LOGGER_FACTORY =
@@ -66,6 +71,11 @@ public final class ContainerBuilder {
return member == null ? Logger.getAnonymousLogger()
: Logger.getLogger(member.getDeclaringClass().getName());
}
@Override
public Class<? extends Logger> type() {
return Logger.class;
}
};
/**
@@ -89,12 +99,14 @@ public final class ContainerBuilder {
checkKey(key);
final InternalFactory<? extends T> scopedFactory = scope.scopeFactory(key.getType(), key.getName(), factory);
factories.put(key, scopedFactory);
if (scope == Scope.SINGLETON) {
singletonFactories.add(createCallableFactory(key, scopedFactory));
}
if (Initializable.class.isAssignableFrom(key.getType())) {
initializableFactories.add(createCallableFactory(key, scopedFactory));
InternalFactory<T> callableFactory = createCallableFactory(key, scopedFactory);
if (EarlyInitializable.class.isAssignableFrom(factory.type())) {
earlyInitializableFactories.add(callableFactory);
} else if (scope == Scope.SINGLETON) {
singletonFactories.add(callableFactory);
}
return this;
}
@@ -108,6 +120,11 @@ public final class ContainerBuilder {
context.setExternalContext(null);
}
}
@Override
public Class<? extends T> type() {
return scopedFactory.type();
}
};
}
@@ -145,6 +162,11 @@ public final class ContainerBuilder {
}
}
@Override
public Class<? extends T> type() {
return factory.type();
}
@Override
public String toString() {
return new LinkedHashMap<String, Object>() {{
@@ -231,6 +253,11 @@ public final class ContainerBuilder {
return (T) constructor.construct(context, type);
}
@Override
public Class<? extends T> type() {
return implementation;
}
@Override
public String toString() {
return new LinkedHashMap<String, Object>() {{
@@ -515,6 +542,11 @@ public final class ContainerBuilder {
return value;
}
@Override
public Class<? extends T> type() {
return (Class<? extends T>) value.getClass();
}
@Override
public String toString() {
return new LinkedHashMap<String, Object>() {
@@ -587,13 +619,13 @@ public final class ContainerBuilder {
}
});
}
container.callInContext(new ContainerImpl.ContextualCallable<Void>() {
public Void call(InternalContext context) {
for (InternalFactory<?> factory : initializableFactories) {
Initializable instance = (Initializable) factory.create(context);
instance.init();
}
return null;
for (InternalFactory<?> factory : earlyInitializableFactories) {
factory.create(context);
}
return null;
}
});
@@ -1,23 +1,18 @@
/**
/*
* Copyright (C) 2006 Google Inc.
*
* <p>
* 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
* </p>
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* <p>
* 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.
* </p>
*/
package com.opensymphony.xwork2.inject;
import com.opensymphony.xwork2.inject.util.ReferenceCache;
@@ -0,0 +1,22 @@
/*
* Copyright 2002-2006,2009 The Apache Software Foundation.
*
* 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.
*/
package com.opensymphony.xwork2.inject;
/**
* A marking interface that will tell CI to initialise the bean when instating the whole objects' graph
*/
public interface EarlyInitializable extends Initializable {
}
@@ -1,4 +1,4 @@
/**
/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.inject;
/**
@@ -23,12 +22,20 @@ package com.opensymphony.xwork2.inject;
*/
public interface Factory<T> {
/**
* Creates an object to be injected.
*
* @param context of this injection
* @return instance to be injected
* @throws Exception if unable to create object
*/
T create(Context context) throws Exception;
/**
* Creates an object to be injected.
*
* @param context of this injection
* @return instance to be injected
* @throws Exception if unable to create object
*/
T create(Context context) throws Exception;
/**
* Returns a class of <T>
*
* @return class of the object
*/
Class<? extends T> type();
}
@@ -0,0 +1,56 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.opensymphony.xwork2.inject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
class InitializableFactory<T> implements InternalFactory<T> {
private static final Logger LOG = LogManager.getLogger(InitializableFactory.class);
private InternalFactory<T> internalFactory;
private InitializableFactory(InternalFactory<T> internalFactory) {
this.internalFactory = internalFactory;
}
public static <T> InternalFactory<T> wrapIfNeeded(InternalFactory<T> internalFactory) {
if (Initializable.class.isAssignableFrom(internalFactory.type())) {
return new InitializableFactory<>(internalFactory);
}
return internalFactory;
}
@Override
public T create(InternalContext context) {
T instance = internalFactory.create(context);
if (Initializable.class.isAssignableFrom(instance.getClass())) {
Initializable.class.cast(instance).init();
} else {
LOG.error("Class {} is not marked as {}!", internalFactory.getClass().getName(), Initializable.class.getName());
}
return instance;
}
@Override
public Class<? extends T> type() {
return internalFactory.type();
}
}
@@ -1,4 +1,4 @@
/**
/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.inject;
import java.io.Serializable;
@@ -25,11 +24,19 @@ import java.io.Serializable;
*/
interface InternalFactory<T> extends Serializable {
/**
* Creates an object to be injected.
*
* @param context of this injection
* @return instance to be injected
*/
T create(InternalContext context);
/**
* Creates an object to be injected.
*
* @param context of this injection
* @return instance to be injected
*/
T create(InternalContext context);
/**
* Returns a class of <T>
*
* @return class of the object
*/
Class<? extends T> type();
}
@@ -33,7 +33,7 @@ public enum Scope {
@Override
<T> InternalFactory<? extends T> scopeFactory(Class<T> type, String name,
InternalFactory<? extends T> factory) {
return factory;
return InitializableFactory.wrapIfNeeded(factory);
}
},
@@ -49,12 +49,17 @@ public enum Scope {
public T create(InternalContext context) {
synchronized (context.getContainer()) {
if (instance == null) {
instance = factory.create(context);
instance = InitializableFactory.wrapIfNeeded(factory).create(context);
}
return instance;
}
}
@Override
public Class<? extends T> type() {
return factory.type();
}
@Override
public String toString() {
return factory.toString();
@@ -83,12 +88,17 @@ public enum Scope {
public T create(final InternalContext context) {
T t = threadLocal.get();
if (t == null) {
t = factory.create(context);
t = InitializableFactory.wrapIfNeeded(factory).create(context);
threadLocal.set(t);
}
return t;
}
@Override
public Class<? extends T> type() {
return factory.type();
}
@Override
public String toString() {
return factory.toString();
@@ -114,6 +124,11 @@ public enum Scope {
}
}
@Override
public Class<? extends T> type() {
return factory.type();
}
@Override
public String toString() {
return factory.toString();
@@ -139,6 +154,11 @@ public enum Scope {
}
}
@Override
public Class<? extends T> type() {
return factory.type();
}
@Override
public String toString() {
return factory.toString();
@@ -164,6 +184,11 @@ public enum Scope {
}
}
@Override
public Class<? extends T> type() {
return factory.type();
}
@Override
public String toString() {
return factory.toString();
@@ -176,7 +201,7 @@ public enum Scope {
final InternalFactory<? extends T> factory) {
return new Callable<T>() {
public T call() throws Exception {
return factory.create(context);
return InitializableFactory.wrapIfNeeded(factory).create(context);
}
};
}
@@ -118,11 +118,13 @@ public class ParameterFilterInterceptor extends AbstractInterceptor {
for (String param : parameters.keySet()) {
boolean currentAllowed = !isDefaultBlock();
for (String currRule : includesExcludesMap.keySet()) {
for (Map.Entry<String, Boolean> entry : includesExcludesMap.entrySet()) {
String currRule = entry.getKey();
if (param.startsWith(currRule) &&
(param.length() == currRule.length() || isPropertySeparator(param.charAt(currRule.length())))
) {
currentAllowed = includesExcludesMap.get(currRule);
currentAllowed = entry.getValue();
}
}
if (!currentAllowed) {
@@ -172,10 +172,11 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
acceptableParameters = new TreeMap<>();
}
for (String name : params.keySet()) {
Parameter parameter = params.get(name);
if (isAcceptableParameter(name, action)) {
acceptableParameters.put(name, parameter);
for (Map.Entry<String, Parameter> entry : params.entrySet()) {
String parameterName = entry.getKey();
if (isAcceptableParameter(parameterName, action)) {
acceptableParameters.put(parameterName, entry.getValue());
}
}
@@ -270,10 +271,10 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
}
StringBuilder logEntry = new StringBuilder();
for (String name : parameters.keySet()) {
logEntry.append(String.valueOf(name));
for (Map.Entry<String, Parameter> entry : parameters.entrySet()) {
logEntry.append(entry.getKey());
logEntry.append(" => ");
logEntry.append(parameters.get(name).getValue());
logEntry.append(entry.getValue().getValue());
logEntry.append(" ");
}
@@ -124,12 +124,4 @@ public class MockActionInvocation implements ActionInvocation {
public void init(ActionProxy proxy) {
}
public ActionInvocation serialize() {
return this;
}
public ActionInvocation deserialize(ActionContext actionContext) {
return this;
}
}
@@ -23,7 +23,7 @@ package com.opensymphony.xwork2.ognl;
*/
public class ErrorMessageBuilder {
private StringBuilder message = new StringBuilder();
private final StringBuilder message = new StringBuilder();
public static ErrorMessageBuilder create() {
return new ErrorMessageBuilder();
@@ -24,7 +24,7 @@ import java.util.Map;
public class OgnlNullHandlerWrapper implements ognl.NullHandler {
private NullHandler wrapped;
private final NullHandler wrapped;
public OgnlNullHandlerWrapper(NullHandler target) {
this.wrapped = target;
@@ -28,7 +28,7 @@ import java.util.Map;
*/
public class OgnlTypeConverterWrapper implements ognl.TypeConverter {
private TypeConverter typeConverter;
private final TypeConverter typeConverter;
public OgnlTypeConverterWrapper(TypeConverter converter) {
if (converter == null) {
@@ -58,44 +58,57 @@ public class OgnlUtil {
private final ConcurrentMap<Class, BeanInfo> beanInfoCache = new ConcurrentHashMap<>();
private TypeConverter defaultConverter;
private boolean devMode = false;
private boolean devMode;
private boolean enableExpressionCache = true;
private boolean enableEvalExpression;
private Set<Class<?>> excludedClasses = Collections.emptySet();
private Set<Pattern> excludedPackageNamePatterns = Collections.emptySet();
private Set<String> excludedPackageNames = Collections.emptySet();
private Set<Class<?>> excludedClasses;
private Set<Pattern> excludedPackageNamePatterns;
private Set<String> excludedPackageNames;
private Container container;
private boolean allowStaticMethodAccess;
private boolean disallowProxyMemberAccess;
public OgnlUtil() {
excludedClasses = new HashSet<>();
excludedPackageNamePatterns = new HashSet<>();
excludedPackageNames = new HashSet<>();
}
@Inject
public void setXWorkConverter(XWorkConverter conv) {
protected void setXWorkConverter(XWorkConverter conv) {
this.defaultConverter = new OgnlTypeConverterWrapper(conv);
}
@Inject(XWorkConstants.DEV_MODE)
public void setDevMode(String mode) {
protected void setDevMode(String mode) {
this.devMode = BooleanUtils.toBoolean(mode);
}
@Inject(XWorkConstants.ENABLE_OGNL_EXPRESSION_CACHE)
public void setEnableExpressionCache(String cache) {
protected void setEnableExpressionCache(String cache) {
enableExpressionCache = BooleanUtils.toBoolean(cache);
}
@Inject(value = XWorkConstants.ENABLE_OGNL_EVAL_EXPRESSION, required = false)
public void setEnableEvalExpression(String evalExpression) {
enableEvalExpression = "true".equals(evalExpression);
if(enableEvalExpression){
protected void setEnableEvalExpression(String evalExpression) {
this.enableEvalExpression = BooleanUtils.toBoolean(evalExpression);
if (this.enableEvalExpression) {
LOG.warn("Enabling OGNL expression evaluation may introduce security risks " +
"(see http://struts.apache.org/release/2.3.x/docs/s2-013.html for further details)");
}
}
@Inject(value = XWorkConstants.OGNL_EXCLUDED_CLASSES, required = false)
public void setExcludedClasses(String commaDelimitedClasses) {
protected void setExcludedClasses(String commaDelimitedClasses) {
Set<Class<?>> excludedClasses = new HashSet<>();
excludedClasses.addAll(this.excludedClasses);
excludedClasses.addAll(parseExcludedClasses(commaDelimitedClasses));
this.excludedClasses = Collections.unmodifiableSet(excludedClasses);
}
private Set<Class<?>> parseExcludedClasses(String commaDelimitedClasses) {
Set<String> classNames = TextParseUtil.commaDelimitedStringToSet(commaDelimitedClasses);
Set<Class<?>> classes = new HashSet<>();
@@ -107,11 +120,18 @@ public class OgnlUtil {
}
}
excludedClasses = Collections.unmodifiableSet(classes);
return classes;
}
@Inject(value = XWorkConstants.OGNL_EXCLUDED_PACKAGE_NAME_PATTERNS, required = false)
public void setExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) {
protected void setExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) {
Set<Pattern> excludedPackageNamePatterns = new HashSet<>();
excludedPackageNamePatterns.addAll(this.excludedPackageNamePatterns);
excludedPackageNamePatterns.addAll(parseExcludedPackageNamePatterns(commaDelimitedPackagePatterns));
this.excludedPackageNamePatterns = Collections.unmodifiableSet(excludedPackageNamePatterns);
}
private Set<Pattern> parseExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) {
Set<String> packagePatterns = TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackagePatterns);
Set<Pattern> packageNamePatterns = new HashSet<>();
@@ -119,12 +139,19 @@ public class OgnlUtil {
packageNamePatterns.add(Pattern.compile(pattern));
}
excludedPackageNamePatterns = Collections.unmodifiableSet(packageNamePatterns);
return packageNamePatterns;
}
@Inject(value = XWorkConstants.OGNL_EXCLUDED_PACKAGE_NAMES, required = false)
public void setExcludedPackageNames(String commaDelimitedPackageNames) {
excludedPackageNames = Collections.unmodifiableSet(TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackageNames));
protected void setExcludedPackageNames(String commaDelimitedPackageNames) {
Set<String> excludedPackageNames = new HashSet<>();
excludedPackageNames.addAll(this.excludedPackageNames);
excludedPackageNames.addAll(parseExcludedPackageNames(commaDelimitedPackageNames));
this.excludedPackageNames = Collections.unmodifiableSet(excludedPackageNames);
}
private Set<String> parseExcludedPackageNames(String commaDelimitedPackageNames) {
return TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackageNames);
}
public Set<Class<?>> getExcludedClasses() {
@@ -140,17 +167,17 @@ public class OgnlUtil {
}
@Inject
public void setContainer(Container container) {
protected void setContainer(Container container) {
this.container = container;
}
@Inject(value = XWorkConstants.ALLOW_STATIC_METHOD_ACCESS, required = false)
public void setAllowStaticMethodAccess(String allowStaticMethodAccess) {
this.allowStaticMethodAccess = Boolean.parseBoolean(allowStaticMethodAccess);
protected void setAllowStaticMethodAccess(String allowStaticMethodAccess) {
this.allowStaticMethodAccess = BooleanUtils.toBoolean(allowStaticMethodAccess);
}
@Inject(value = StrutsConstants.STRUTS_DISALLOW_PROXY_MEMBER_ACCESS, required = false)
public void setDisallowProxyMemberAccess(String disallowProxyMemberAccess) {
protected void setDisallowProxyMemberAccess(String disallowProxyMemberAccess) {
this.disallowProxyMemberAccess = Boolean.parseBoolean(disallowProxyMemberAccess);
}
@@ -404,7 +431,7 @@ public class OgnlUtil {
final T exec = task.execute(tree);
// if cache is enabled and it's a valid expression, puts it in
if(enableExpressionCache) {
if (enableExpressionCache) {
expressions.putIfAbsent(expression, tree);
}
return exec;
@@ -425,7 +452,7 @@ public class OgnlUtil {
final T exec = task.execute(tree);
// if cache is enabled and it's a valid expression, puts it in
if(enableExpressionCache) {
if (enableExpressionCache) {
expressions.putIfAbsent(expression, tree);
}
return exec;
@@ -641,8 +668,7 @@ public class OgnlUtil {
*/
public BeanInfo getBeanInfo(Class clazz) throws IntrospectionException {
synchronized (beanInfoCache) {
BeanInfo beanInfo;
beanInfo = beanInfoCache.get(clazz);
BeanInfo beanInfo = beanInfoCache.get(clazz);
if (beanInfo == null) {
beanInfo = Introspector.getBeanInfo(clazz, Object.class);
beanInfoCache.putIfAbsent(clazz, beanInfo);
@@ -82,7 +82,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
}
@Inject
public void setOgnlUtil(OgnlUtil ognlUtil) {
protected void setOgnlUtil(OgnlUtil ognlUtil) {
this.ognlUtil = ognlUtil;
securityMemberAccess.setExcludedClasses(ognlUtil.getExcludedClasses());
securityMemberAccess.setExcludedPackageNamePatterns(ognlUtil.getExcludedPackageNamePatterns());
@@ -102,12 +102,12 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
}
@Inject(XWorkConstants.DEV_MODE)
public void setDevMode(String mode) {
protected void setDevMode(String mode) {
this.devMode = BooleanUtils.toBoolean(mode);
}
@Inject(value = "logMissingProperties", required = false)
public void setLogMissingProperties(String logMissingProperties) {
protected void setLogMissingProperties(String logMissingProperties) {
this.logMissingProperties = BooleanUtils.toBoolean(logMissingProperties);
}
@@ -157,8 +157,6 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
setValue(expr, value, devMode);
}
/**
/**
* @see com.opensymphony.xwork2.util.ValueStack#setValue(java.lang.String, java.lang.Object)
*/
@@ -379,7 +377,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
* @param e The thrown exception.
*/
private void logLookupFailure(String expr, Exception e) {
if (devMode && LOG.isWarnEnabled()) {
if (devMode) {
LOG.warn("Caught an exception while evaluating expression '{}' against value stack", expr, e);
LOG.warn("NOTE: Previous warning message was issued due to devMode set to true.");
} else {
@@ -475,7 +473,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
}
@Inject
public void setXWorkConverter(final XWorkConverter converter) {
protected void setXWorkConverter(final XWorkConverter converter) {
this.converter = converter;
}
}
@@ -32,6 +32,8 @@ import ognl.MethodAccessor;
import ognl.OgnlRuntime;
import ognl.PropertyAccessor;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Map;
import java.util.Set;
@@ -41,24 +43,26 @@ import java.util.Set;
*/
public class OgnlValueStackFactory implements ValueStackFactory {
private static final Logger LOG = LogManager.getLogger(OgnlValueStackFactory.class);
protected XWorkConverter xworkConverter;
protected CompoundRootAccessor compoundRootAccessor;
protected TextProvider textProvider;
protected Container container;
protected boolean allowStaticMethodAccess;
private boolean allowStaticMethodAccess;
@Inject
public void setXWorkConverter(XWorkConverter converter) {
protected void setXWorkConverter(XWorkConverter converter) {
this.xworkConverter = converter;
}
@Inject("system")
public void setTextProvider(TextProvider textProvider) {
protected void setTextProvider(TextProvider textProvider) {
this.textProvider = textProvider;
}
@Inject(value="allowStaticMethodAccess", required=false)
public void setAllowStaticMethodAccess(String allowStaticMethodAccess) {
protected void setAllowStaticMethodAccess(String allowStaticMethodAccess) {
this.allowStaticMethodAccess = BooleanUtils.toBoolean(allowStaticMethodAccess);
}
@@ -77,7 +81,7 @@ public class OgnlValueStackFactory implements ValueStackFactory {
}
@Inject
public void setContainer(Container container) throws ClassNotFoundException {
protected void setContainer(Container container) throws ClassNotFoundException {
Set<String> names = container.getInstanceNames(PropertyAccessor.class);
for (String name : names) {
Class cls = Class.forName(name);
@@ -46,9 +46,16 @@ public class SecurityMemberAccess extends DefaultMemberAccess {
private Set<String> excludedPackageNames = Collections.emptySet();
private boolean disallowProxyMemberAccess;
public SecurityMemberAccess(boolean method) {
/**
* SecurityMemberAccess
* - access decisions based on whether member is static (or not)
* - block or allow access to properties (configureable-after-construction)
*
* @param allowStaticMethodAccess
*/
public SecurityMemberAccess(boolean allowStaticMethodAccess) {
super(false);
allowStaticMethodAccess = method;
this.allowStaticMethodAccess = allowStaticMethodAccess;
}
public boolean getAllowStaticMethodAccess() {
@@ -59,28 +66,30 @@ public class SecurityMemberAccess extends DefaultMemberAccess {
public boolean isAccessible(Map context, Object target, Member member, String propertyName) {
LOG.debug("Checking access for [target: {}, member: {}, property: {}]", target, member, propertyName);
final Class memberClass = member.getDeclaringClass();
Class targetClass = (target != null ? target.getClass() : memberClass); // Note: target,propertyName may be null (static field checks OGNL 3.1.19+)
if (checkEnumAccess(target, member)) {
LOG.trace("Allowing access to enum: {}", target);
LOG.trace("Allowing access to enum: target class [{}] of target [{}], member [{}]", targetClass, target, member);
return true;
}
Class targetClass = target.getClass();
Class memberClass = member.getDeclaringClass();
if (Modifier.isStatic(member.getModifiers()) && allowStaticMethodAccess) {
LOG.debug("Support for accessing static methods [target: {}, member: {}, property: {}] is deprecated!", target, member, propertyName);
if (!isClassExcluded(member.getDeclaringClass())) {
targetClass = member.getDeclaringClass();
LOG.debug("Support for accessing static methods [target: {}, targetClass: {}, member: {}, property: {}] is deprecated!",
target, targetClass, member, propertyName);
if (!isClassExcluded(memberClass)) {
targetClass = memberClass;
}
}
if (isPackageExcluded(targetClass.getPackage(), memberClass.getPackage())) {
LOG.warn("Package of target [{}] or package of member [{}] are excluded!", target, member);
LOG.warn("Package [{}] of target class [{}] of target [{}] or package [{}] of member [{}] are excluded!", targetClass.getPackage(), targetClass,
target, memberClass.getPackage(), member);
return false;
}
if (isClassExcluded(targetClass)) {
LOG.warn("Target class [{}] is excluded!", target);
LOG.warn("Target class [{}] of target [{}] is excluded!", targetClass, target);
return false;
}
@@ -90,7 +99,7 @@ public class SecurityMemberAccess extends DefaultMemberAccess {
}
if (disallowProxyMemberAccess && ProxyUtil.isProxyMember(member, target)) {
LOG.warn("Access to proxy [{}] is blocked!", member);
LOG.warn("Access to proxy is blocked! Target class [{}] of target [{}], member [{}]", targetClass, target, member);
return false;
}
@@ -133,8 +142,8 @@ public class SecurityMemberAccess extends DefaultMemberAccess {
LOG.warn("The use of the default (unnamed) package is discouraged!");
}
final String targetPackageName = targetPackage == null ? "" : targetPackage.getName();
final String memberPackageName = memberPackage == null ? "" : memberPackage.getName();
String targetPackageName = targetPackage == null ? "" : targetPackage.getName();
String memberPackageName = memberPackage == null ? "" : memberPackage.getName();
for (Pattern pattern : excludedPackageNamePatterns) {
if (pattern.matcher(targetPackageName).matches() || pattern.matcher(memberPackageName).matches()) {
@@ -142,9 +151,11 @@ public class SecurityMemberAccess extends DefaultMemberAccess {
}
}
targetPackageName = targetPackageName + ".";
memberPackageName = memberPackageName + ".";
for (String packageName: excludedPackageNames) {
if (targetPackageName.startsWith(packageName) || targetPackageName.equals(packageName)
|| memberPackageName.startsWith(packageName) || memberPackageName.equals(packageName)) {
if (targetPackageName.startsWith(packageName) || memberPackageName.startsWith(packageName)) {
return true;
}
}
@@ -28,7 +28,7 @@ import java.util.Map;
*/
public class XWorkTypeConverterWrapper implements TypeConverter {
private ognl.TypeConverter typeConverter;
private final ognl.TypeConverter typeConverter;
public XWorkTypeConverterWrapper(ognl.TypeConverter conv) {
this.typeConverter = conv;
@@ -63,10 +63,10 @@ public class CompoundRootAccessor implements PropertyAccessor, MethodAccessor, C
private final static Logger LOG = LogManager.getLogger(CompoundRootAccessor.class);
private final static Class[] EMPTY_CLASS_ARRAY = new Class[0];
private static Map<MethodCall, Boolean> invalidMethods = new ConcurrentHashMap<>();
private boolean devMode = false;
private boolean devMode;
@Inject(XWorkConstants.DEV_MODE)
public void setDevMode(String mode) {
protected void setDevMode(String mode) {
this.devMode = BooleanUtils.toBoolean(mode);
}
@@ -48,7 +48,7 @@ public class XWorkCollectionPropertyAccessor extends SetPropertyAccessor {
//use a basic object Ognl property accessor here
//to access properties of the objects in the Set
//so that nothing is put in the context to screw things up
private ObjectPropertyAccessor _accessor = new ObjectPropertyAccessor();
private final ObjectPropertyAccessor _accessor = new ObjectPropertyAccessor();
private XWorkConverter xworkConverter;
private ObjectFactory objectFactory;
@@ -30,7 +30,7 @@ import java.util.Map;
*/
public class XWorkEnumerationAccessor extends EnumerationPropertyAccessor {
ObjectPropertyAccessor opa = new ObjectPropertyAccessor();
private final ObjectPropertyAccessor opa = new ObjectPropertyAccessor();
@Override
public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException {
@@ -30,7 +30,7 @@ import java.util.Map;
*/
public class XWorkIteratorPropertyAccessor extends IteratorPropertyAccessor {
ObjectPropertyAccessor opa = new ObjectPropertyAccessor();
private final ObjectPropertyAccessor opa = new ObjectPropertyAccessor();
@Override
public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException {
@@ -28,6 +28,7 @@ import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
import ognl.ListPropertyAccessor;
import ognl.OgnlException;
import ognl.PropertyAccessor;
import org.apache.struts2.StrutsConstants;
import java.util.Collection;
import java.util.List;
@@ -49,12 +50,18 @@ public class XWorkListPropertyAccessor extends ListPropertyAccessor {
private ObjectTypeDeterminer objectTypeDeterminer;
private OgnlUtil ognlUtil;
private int autoGrowCollectionLimit = 255;
@Deprecated()
@Inject(value = "xwork.autoGrowCollectionLimit", required = false)
public void setAutoGrowCollectionLimit(String value) {
this.autoGrowCollectionLimit = Integer.valueOf(value);
}
public void setDeprecatedAutoGrowCollectionLimit(String value) {
this.autoGrowCollectionLimit = Integer.valueOf(value);
}
@Inject(value = StrutsConstants.STRUTS_OGNL_AUTO_GROWTH_COLLECTION_LIMIT, required = false)
public void setAutoGrowCollectionLimit(String value) {
this.autoGrowCollectionLimit = Integer.parseInt(value);
}
@Inject("java.util.Collection")
public void setXWorkCollectionPropertyAccessor(PropertyAccessor acc) {
this._sAcc = (XWorkCollectionPropertyAccessor) acc;
@@ -44,9 +44,9 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
}
@Inject(value = XWorkConstants.OVERRIDE_ACCEPTED_PATTERNS, required = false)
public void setOverrideAcceptedPatterns(String acceptablePatterns) {
protected void setOverrideAcceptedPatterns(String acceptablePatterns) {
LOG.warn("Overriding accepted patterns [{}] with [{}], be aware that this affects all instances and safety of your application!",
XWorkConstants.OVERRIDE_ACCEPTED_PATTERNS, acceptablePatterns);
acceptedPatterns, acceptablePatterns);
acceptedPatterns = new HashSet<>();
for (String pattern : TextParseUtil.commaDelimitedStringToSet(acceptablePatterns)) {
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
@@ -54,7 +54,7 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
}
@Inject(value = XWorkConstants.ADDITIONAL_ACCEPTED_PATTERNS, required = false)
public void setAdditionalAcceptedPatterns(String acceptablePatterns) {
protected void setAdditionalAcceptedPatterns(String acceptablePatterns) {
LOG.warn("Adding additional global patterns [{}] to accepted patterns!", acceptablePatterns);
for (String pattern : TextParseUtil.commaDelimitedStringToSet(acceptablePatterns)) {
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
@@ -70,7 +70,13 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
}
public void setAcceptedPatterns(Set<String> patterns) {
LOG.trace("Sets accepted patterns [{}]", patterns);
if (acceptedPatterns == null) {
// Limit unwanted log entries (for 1st call, acceptedPatterns null)
LOG.debug("Sets accepted patterns to [{}], note this impacts the safety of your application!", patterns);
} else {
LOG.warn("Replacing accepted patterns [{}] with [{}], be aware that this affects all instances and safety of your application!",
acceptedPatterns, patterns);
}
acceptedPatterns = new HashSet<>(patterns.size());
for (String pattern : patterns) {
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
@@ -47,9 +47,14 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
}
@Inject(value = XWorkConstants.OVERRIDE_EXCLUDED_PATTERNS, required = false)
public void setOverrideExcludePatterns(String excludePatterns) {
LOG.warn("Overriding excluded patterns [{}] with [{}], be aware that this affects all instances and safety of your application!",
XWorkConstants.OVERRIDE_EXCLUDED_PATTERNS, excludePatterns);
protected void setOverrideExcludePatterns(String excludePatterns) {
if (excludedPatterns != null && excludedPatterns.size() > 0) {
LOG.warn("Overriding excluded patterns [{}] with [{}], be aware that this affects all instances and safety of your application!",
excludedPatterns, excludePatterns);
} else {
// Limit unwanted log entries (when excludedPatterns null/empty - usually 1st call)
LOG.debug("Overriding excluded patterns with [{}]", excludePatterns);
}
excludedPatterns = new HashSet<Pattern>();
for (String pattern : TextParseUtil.commaDelimitedStringToSet(excludePatterns)) {
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
@@ -65,8 +70,8 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
}
@Inject(StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION)
public void setDynamicMethodInvocation(String dmiValue) {
if (!BooleanUtils.toBoolean(dmiValue)) {
protected void setDynamicMethodInvocation(String dmiValue) {
if (BooleanUtils.toBoolean(dmiValue) == false) {
LOG.debug("DMI is disabled, adding DMI related excluded patterns");
setAdditionalExcludePatterns("^(action|method):.*");
}
@@ -81,7 +86,13 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
}
public void setExcludedPatterns(Set<String> patterns) {
LOG.trace("Sets excluded patterns [{}]", patterns);
if (excludedPatterns != null && excludedPatterns.size() > 0) {
LOG.warn("Replacing excluded patterns [{}] with [{}], be aware that this affects all instances and safety of your application!",
excludedPatterns, patterns);
} else {
// Limit unwanted log entries (when excludedPatterns null/empty - usually 1st call)
LOG.debug("Sets excluded patterns to [{}]", patterns);
}
excludedPatterns = new HashSet<>(patterns.size());
for (String pattern : patterns) {
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
@@ -18,9 +18,12 @@
*/
package com.opensymphony.xwork2.util;
import org.apache.commons.lang3.ClassUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
@@ -129,7 +132,7 @@ public class AnnotationUtils {
}
/**
* Returns the annotation on the given class or the package of the class. This searchs up the
* Returns the annotation on the given class or the package of the class. This searches up the
* class hierarchy and the package hierarchy for the closest match.
*
* @param <T> class type
@@ -154,4 +157,36 @@ public class AnnotationUtils {
return ann;
}
/**
* Returns a list of the annotation on the given class or the package of the class.
* This searches up the class hierarchy and the package hierarchy.
*
* @param <T> class type
* @param clazz The class to search for the annotation.
* @param annotationClass The Class of the annotation.
* @return List of the annotations or an empty list.
*/
public static <T extends Annotation> List<T> findAnnotations(Class<?> clazz, Class<T> annotationClass) {
List<T> anns = new ArrayList<>();
List<Class<?>> classes = new ArrayList<>();
classes.add(clazz);
classes.addAll(ClassUtils.getAllSuperclasses(clazz));
classes.addAll(ClassUtils.getAllInterfaces(clazz));
for (Class<?> aClass : classes) {
T ann = aClass.getAnnotation(annotationClass);
if (ann != null) {
anns.add(ann);
}
ann = aClass.getPackage().getAnnotation(annotationClass);
if (ann != null) {
anns.add(ann);
}
}
return anns;
}
}
@@ -27,6 +27,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collections;
import java.util.HashMap;
import java.util.Vector;
import java.util.zip.ZipEntry;
@@ -77,11 +78,7 @@ public class ClassPathFinder {
*/
public Vector<String> findMatches() {
Vector<String> matches = new Vector<>();
URLClassLoader cl = getURLClassLoader();
if (cl == null ) {
throw new XWorkException("unable to attain an URLClassLoader") ;
}
URL[] parentUrls = cl.getURLs();
URL[] parentUrls = getClassLoaderURLs();
compiledPattern = patternMatcher.compilePattern(pattern);
for (URL url : parentUrls) {
if (!"file".equals(url.getProtocol())) {
@@ -173,20 +170,24 @@ public class ClassPathFinder {
this.patternMatcher = patternMatcher;
}
private URLClassLoader getURLClassLoader() {
URLClassLoader ucl = null;
private URL[] getClassLoaderURLs() {
URL[] urls;
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if(! (loader instanceof URLClassLoader)) {
if (!(loader instanceof URLClassLoader)) {
loader = ClassPathFinder.class.getClassLoader();
if (loader instanceof URLClassLoader) {
ucl = (URLClassLoader) loader ;
}
if (loader instanceof URLClassLoader) {
urls = ((URLClassLoader) loader).getURLs();
} else { //jdk9 or later
try {
urls = Collections.list(loader.getResources("")).toArray(new URL[0]);
} catch (IOException e) {
throw new XWorkException("unable to get ClassLoader URLs", e);
}
}
else {
ucl = (URLClassLoader) loader;
}
return ucl ;
return urls;
}
}
@@ -171,8 +171,8 @@ public class GlobalLocalizedTextProvider extends AbstractLocalizedTextProvider {
indexedTextName = aTextName;
while ((i = indexedTextName.indexOf("[", i + 1)) != -1) {
int j = indexedTextName.indexOf("]", i);
while ((i = indexedTextName.indexOf('[', i + 1)) != -1) {
int j = indexedTextName.indexOf(']', i);
String a = indexedTextName.substring(0, i);
String b = indexedTextName.substring(j);
indexedTextName = a + "[*" + b;
@@ -232,8 +232,8 @@ public class StrutsLocalizedTextProvider extends AbstractLocalizedTextProvider {
indexedTextName = aTextName;
while ((i = indexedTextName.indexOf("[", i + 1)) != -1) {
int j = indexedTextName.indexOf("]", i);
while ((i = indexedTextName.indexOf('[', i + 1)) != -1) {
int j = indexedTextName.indexOf(']', i);
String a = indexedTextName.substring(0, i);
String b = indexedTextName.substring(j);
indexedTextName = a + "[*" + b;
@@ -293,14 +293,14 @@ public class StrutsLocalizedTextProvider extends AbstractLocalizedTextProvider {
}
// see if it's a child property
int idx = aTextName.indexOf(".");
int idx = aTextName.indexOf('.');
if (idx != -1) {
String newKey = null;
String prop = null;
if (aTextName.startsWith(XWorkConverter.CONVERSION_ERROR_PROPERTY_PREFIX)) {
idx = aTextName.indexOf(".", XWorkConverter.CONVERSION_ERROR_PROPERTY_PREFIX.length());
idx = aTextName.indexOf('.', XWorkConverter.CONVERSION_ERROR_PROPERTY_PREFIX.length());
if (idx != -1) {
prop = aTextName.substring(XWorkConverter.CONVERSION_ERROR_PROPERTY_PREFIX.length(), idx);
@@ -189,7 +189,7 @@ public interface ClassFinder {
}
public String getPackageName(){
return name.indexOf(".") > 0 ? name.substring(0, name.lastIndexOf(".")) : "" ;
return name.indexOf('.') > 0 ? name.substring(0, name.lastIndexOf('.')) : "" ;
}
public List<MethodInfo> getConstructors() {
@@ -40,7 +40,8 @@ public class DefaultFileManager implements FileManager {
private static final Pattern JAR_PATTERN = Pattern.compile("^(jar:|wsjar:|zip:|vfsfile:|code-source:)?(file:)?(.*?)(\\!/|\\.jar/)(.*)");
private static final int JAR_FILE_PATH = 3;
protected static Map<String, Revision> files = Collections.synchronizedMap(new HashMap<String, Revision>());
protected static final Map<String, Revision> files = Collections.synchronizedMap(new HashMap<String, Revision>());
private static final List<URL> lazyMonitoredFilesCache = Collections.synchronizedList(new ArrayList<URL>());
protected boolean reloadingConfigs = false;
@@ -48,6 +49,16 @@ public class DefaultFileManager implements FileManager {
}
public void setReloadingConfigs(boolean reloadingConfigs) {
if (reloadingConfigs && !this.reloadingConfigs) {
//starting monitoring cached not-monitored files (lazy monitoring on demand because of performance)
this.reloadingConfigs = true;
synchronized (lazyMonitoredFilesCache) {
for (URL fileUrl : lazyMonitoredFilesCache) {
monitorFile(fileUrl);
}
lazyMonitoredFilesCache.clear();
}
}
this.reloadingConfigs = reloadingConfigs;
}
@@ -88,6 +99,12 @@ public class DefaultFileManager implements FileManager {
public void monitorFile(URL fileUrl) {
String fileName = fileUrl.toString();
if (!reloadingConfigs) {
//reserve file for monitoring on demand because of performance
files.remove(fileName);
lazyMonitoredFilesCache.add(fileUrl);
return;
}
Revision revision;
LOG.debug("Creating revision for URL: {}", fileName);
if (isJarURL(fileUrl)) {
@@ -37,11 +37,7 @@ public class JarEntryRevision extends Revision {
private long lastModified;
public static Revision build(URL fileUrl, FileManager fileManager) {
// File within a Jar
// Find separator index of jar filename and filename within jar
JarURLConnection conn = null;
try {
conn = (JarURLConnection) fileUrl.openConnection();
try (StrutsJarURLConnection conn = StrutsJarURLConnection.openConnection(fileUrl)) {
conn.setUseCaches(false);
URL url = fileManager.normalizeToFileProtocol(fileUrl);
if (url != null) {
@@ -53,14 +49,6 @@ public class JarEntryRevision extends Revision {
LOG.warn("Could not create JarEntryRevision for [{}]!", fileUrl, e);
return null;
}
finally {
if(null != conn) {
try {
conn.getInputStream().close();
} catch (IOException ignored) {
}
}
}
}
private JarEntryRevision(URL jarFileURL, long lastModified) {
@@ -72,21 +60,12 @@ public class JarEntryRevision extends Revision {
}
public boolean needsReloading() {
JarURLConnection conn = null;
long lastLastModified = lastModified;
try {
conn = (JarURLConnection) jarFileURL.openConnection();
try (StrutsJarURLConnection conn = StrutsJarURLConnection.openConnection(jarFileURL)) {
conn.setUseCaches(false);
lastLastModified = conn.getJarEntry().getTime();
} catch (IOException ignored) {
}
finally {
if(null != conn) {
try {
conn.getInputStream().close();
} catch (IOException ignored) {
}
}
} catch (Throwable e) {
LOG.warn("Could not check if needsReloading for [{}]!", jarFileURL, e);
}
return lastModified < lastLastModified;
@@ -0,0 +1,191 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.opensymphony.xwork2.util.fs;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* WW-4901 If was needed, decouples from underlying implementation of {@link URL#openConnection()}
* e.g. from IBM WebSphere com.ibm.ws.classloader.Handler$ClassLoaderURLConnection
* WW-4920 Also decouples from and fixes {@link JarURLConnection#parseSpecs(URL)} if was needed
* e.g. from Oracle WebLogic which may report jar urls like "zip:C:/web-app-lib-path/some-jar.jar"
* but {@link JarURLConnection#parseSpecs(URL)} breaks on such urls
* While {@link JarURLConnection#parseSpecs(URL)} is private, then we had to extend {@link URLConnection} instead
* @since 2.5.15
*/
class StrutsJarURLConnection extends URLConnection implements AutoCloseable {
private static final String FILE_URL_PREFIX = "file:";
private JarURLConnection jarURLConnection;
private JarFile jarFile;
private String entryName;
private URL jarFileURL;
private StrutsJarURLConnection(URL url) throws IOException {
super(url);
URLConnection conn = this.url.openConnection();
if (conn instanceof JarURLConnection) {//decoupling is not needed?
jarURLConnection = (JarURLConnection) conn;
} else {
try {
conn.getInputStream().close();
} catch (IOException ignored) {
}
parseSpecs(url);
}
}
/**
* A fixed copy of {@link JarURLConnection#parseSpecs(URL)}
*/
private void parseSpecs(URL url) throws MalformedURLException, UnsupportedEncodingException {
String spec = url.getFile();
int separator = spec.indexOf("!/");
/*
* REMIND: we don't handle nested JAR URLs
*/
if (separator == -1) {
throw new MalformedURLException("no !/ found in url spec:" + spec);
}
// start of fixing JarURLConnection#parseSpecs(URL) via handling MalformedURLException
String jarFileSpec = spec.substring(0, separator++);
try {
jarFileURL = new URL(jarFileSpec);
} catch (MalformedURLException e) {
// Probably no protocol in original jar URL, like "jar:C:/mypath/myjar.jar".
// This usually indicates that the jar file resides in the file system.
if (!jarFileSpec.startsWith("/")) {
jarFileSpec = "/" + jarFileSpec;
}
jarFileURL = new URL(FILE_URL_PREFIX + jarFileSpec);
}
// end of fix
entryName = null;
/* if ! is the last letter of the innerURL, entryName is null */
if (++separator != spec.length()) {
entryName = spec.substring(separator, spec.length());
entryName = URLDecoder.decode (entryName, "UTF-8");
}
}
@Override
public void connect() throws IOException {
if (connected) {
return;
}
if (jarURLConnection != null) {
connected = true;
return;
}
try (final InputStream in = jarFileURL.openConnection().getInputStream()) {
jarFile = AccessController.doPrivileged(
new PrivilegedExceptionAction<JarFile>() {
public JarFile run() throws IOException {
Path tmpFile = Files.createTempFile("jar_cache", null);
try {
Files.copy(in, tmpFile, StandardCopyOption.REPLACE_EXISTING);
JarFile jarFile = new JarFile(tmpFile.toFile(), true, JarFile.OPEN_READ
| JarFile.OPEN_DELETE);
return jarFile;
} catch (Throwable thr) {
try {
Files.delete(tmpFile);
} catch (IOException ioe) {
thr.addSuppressed(ioe);
}
throw thr;
} finally {
in.close();
}
}
});
connected = true;
} catch (PrivilegedActionException pae) {
throw (IOException) pae.getException();
}
}
JarEntry getJarEntry() throws IOException {
if (jarURLConnection != null) {
return jarURLConnection.getJarEntry();
} else {
connect();
return jarFile.getJarEntry(entryName);
}
}
@Override
public void setUseCaches(boolean usecaches) {
super.setUseCaches(usecaches);
if (jarURLConnection != null) {
jarURLConnection.setUseCaches(usecaches);
}
}
@Override
public InputStream getInputStream() throws IOException {
if (jarURLConnection != null) {
return jarURLConnection.getInputStream();
} else {
return jarFile.getInputStream(jarFile.getJarEntry(entryName));
}
}
@Override
public void close() throws Exception {
try {
getInputStream().close();
} catch (IOException ignored) {
}
if (jarURLConnection == null) {
try {
jarFile.close();
} catch (IOException ignored) {
}
}
}
static StrutsJarURLConnection openConnection(URL url) throws IOException {
return new StrutsJarURLConnection(url);
}
}
@@ -22,6 +22,7 @@ import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.XWorkException;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.inject.Initializable;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.ClassLoaderUtil;
import org.apache.logging.log4j.LogManager;
@@ -44,7 +45,7 @@ import java.util.zip.ZipInputStream;
* @author Jason Carreira
* @author James House
*/
public class DefaultValidatorFactory implements ValidatorFactory {
public class DefaultValidatorFactory implements ValidatorFactory, Initializable {
protected Map<String, String> validators = new HashMap<>();
private static Logger LOG = LogManager.getLogger(DefaultValidatorFactory.class);
@@ -18,8 +18,6 @@
*/
package com.opensymphony.xwork2.validator;
import com.opensymphony.xwork2.inject.Initializable;
/**
* ValidatorFactory
*
@@ -227,7 +225,7 @@ import com.opensymphony.xwork2.inject.Initializable;
* @author Jason Carreira
* @author James House
*/
public interface ValidatorFactory extends Initializable {
public interface ValidatorFactory {
/**
* Get a Validator that matches the given configuration.
@@ -41,12 +41,15 @@ public final class StrutsConstants {
/** The URL extension to use to determine if the request is meant for a Struts action */
public static final String STRUTS_ACTION_EXTENSION = "struts.action.extension";
/** Comma separated list of patterns (java.util.regex.Pattern) to be excluded from Struts2-processing */
public static final String STRUTS_ACTION_EXCLUDE_PATTERN = "struts.action.excludePattern";
/** Comma separated list of patterns (java.util.regex.Pattern) to be excluded from Struts2-processing */
public static final String STRUTS_ACTION_EXCLUDE_PATTERN = "struts.action.excludePattern";
/** Whether to use the alterative syntax for the tags or not */
/** Whether to use the alternative syntax for the tags or not */
public static final String STRUTS_TAG_ALTSYNTAX = "struts.tag.altSyntax";
/** Whether to use the response encoding (JSP page encoding) for s:include tag processing (false - use STRUTS_I18N_ENCODING - by default) */
public static final String STRUTS_TAG_INCLUDETAG_USERESPONSEENCODING = "struts.tag.includetag.useResponseEncoding";
/** The HTTP port used by Struts URLs */
public static final String STRUTS_URL_HTTP_PORT = "struts.url.http.port";
@@ -56,7 +59,7 @@ public final class StrutsConstants {
/** The default includeParams method to generate Struts URLs */
public static final String STRUTS_URL_INCLUDEPARAMS = "struts.url.includeParams";
public static final String STRUTS_URL_RENDERER = "struts.urlRenderer";
public static final String STRUTS_URL_RENDERER = "struts.urlRenderer";
/** The com.opensymphony.xwork2.ObjectFactory implementation class */
public static final String STRUTS_OBJECTFACTORY = "struts.objectFactory";
@@ -91,7 +94,7 @@ public final class StrutsConstants {
/** The org.apache.struts2.views.freemarker.FreemarkerManager implementation class */
public static final String STRUTS_FREEMARKER_MANAGER_CLASSNAME = "struts.freemarker.manager.classname";
/** Update freemarker templates cache in seconds*/
/** Update freemarker templates cache in seconds */
public static final String STRUTS_FREEMARKER_TEMPLATES_CACHE_UPDATE_DELAY = "struts.freemarker.templatesCache.updateDelay";
/** Cache model instances at BeanWrapper level */
@@ -220,12 +223,12 @@ public final class StrutsConstants {
public static final String STRUTS_LOCALE_PROVIDER_FACTORY = "struts.localeProviderFactory";
/** The name of the parameter to create when mapping an id (used by some action mappers) */
public static final String STRUTS_ID_PARAMETER_NAME = "struts.mapper.idParameterName";
/** The name of the parameter to determine whether static method access will be allowed in OGNL expressions or not */
public static final String STRUTS_ALLOW_STATIC_METHOD_ACCESS = "struts.ognl.allowStaticMethodAccess";
public static final String STRUTS_ID_PARAMETER_NAME = "struts.mapper.idParameterName";
/** The com.opensymphony.xwork2.validator.ActionValidatorManager implementation class */
/** The name of the parameter to determine whether static method access will be allowed in OGNL expressions or not */
public static final String STRUTS_ALLOW_STATIC_METHOD_ACCESS = "struts.ognl.allowStaticMethodAccess";
/** The com.opensymphony.xwork2.validator.ActionValidatorManager implementation class */
public static final String STRUTS_ACTIONVALIDATORMANAGER = "struts.actionValidatorManager";
/** The {@link com.opensymphony.xwork2.util.ValueStackFactory} implementation class */
@@ -236,7 +239,7 @@ public final class StrutsConstants {
/** The {@link com.opensymphony.xwork2.util.reflection.ReflectionContextFactory} implementation class */
public static final String STRUTS_REFLECTIONCONTEXTFACTORY = "struts.reflectionContextFactory";
/** The {@link com.opensymphony.xwork2.util.PatternMatcher} implementation class */
public static final String STRUTS_PATTERNMATCHER = "struts.patternMatcher";
@@ -246,32 +249,32 @@ public final class StrutsConstants {
/** The {@link com.opensymphony.xwork2.UnknownHandlerManager} implementation class */
public static final String STRUTS_UNKNOWN_HANDLER_MANAGER = "struts.unknownHandlerManager";
/** Throw RuntimeException when a property is not found, or the evaluation of the espression fails*/
/** Throw RuntimeException when a property is not found, or the evaluation of the expression fails */
public static final String STRUTS_EL_THROW_EXCEPTION = "struts.el.throwExceptionOnFailure";
/** Logs properties that are not found (very verbose) **/
/** Logs properties that are not found (very verbose) */
public static final String STRUTS_LOG_MISSING_PROPERTIES = "struts.ognl.logMissingProperties";
/** Enables caching of parsed OGNL expressions **/
/** Enables caching of parsed OGNL expressions */
public static final String STRUTS_ENABLE_OGNL_EXPRESSION_CACHE = "struts.ognl.enableExpressionCache";
/** Enables evaluation of OGNL expressions **/
/** Enables evaluation of OGNL expressions */
public static final String STRUTS_ENABLE_OGNL_EVAL_EXPRESSION = "struts.ognl.enableOGNLEvalExpression";
/** Disables {@link org.apache.struts2.dispatcher.StrutsRequestWrapper} request attribute value stack lookup (JSTL accessibility) **/
/** Disables {@link org.apache.struts2.dispatcher.StrutsRequestWrapper} request attribute value stack lookup (JSTL accessibility) */
public static final String STRUTS_DISABLE_REQUEST_ATTRIBUTE_VALUE_STACK_LOOKUP = "struts.disableRequestAttributeValueStackLookup";
/** The{@link org.apache.struts2.views.util.UrlHelper} implementation class **/
/** The{@link org.apache.struts2.views.util.UrlHelper} implementation class */
public static final String STRUTS_URL_HELPER = "struts.view.urlHelper";
/** {@link com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter} **/
/** {@link com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter} */
public static final String STRUTS_CONVERTER_COLLECTION = "struts.converter.collection";
public static final String STRUTS_CONVERTER_ARRAY = "struts.converter.array";
public static final String STRUTS_CONVERTER_DATE = "struts.converter.date";
public static final String STRUTS_CONVERTER_NUMBER = "struts.converter.number";
public static final String STRUTS_CONVERTER_STRING = "struts.converter.string";
/** Enable handling exceptions by Dispatcher - true by default **/
/** Enable handling exceptions by Dispatcher - true by default */
public static final String STRUTS_HANDLE_EXCEPTION = "struts.handle.exception";
public static final String STRUTS_CONVERTER_PROPERTIES_PROCESSOR = "struts.converter.properties.processor";
@@ -282,37 +285,42 @@ public final class StrutsConstants {
public static final String STRUTS_EXPRESSION_PARSER = "struts.expression.parser";
/** actions names' whitelist **/
/** Namespace names' whitelist */
public static final String STRUTS_ALLOWED_NAMESPACE_NAMES = "struts.allowed.namespace.names";
/** Default namespace name to use when namespace didn't match the whitelist */
public static final String STRUTS_DEFAULT_NAMESPACE_NAME = "struts.default.namespace.name";
/** Action names' whitelist */
public static final String STRUTS_ALLOWED_ACTION_NAMES = "struts.allowed.action.names";
/** default action name to use when action didn't match the whitelist **/
/** Default action name to use when action didn't match the whitelist */
public static final String STRUTS_DEFAULT_ACTION_NAME = "struts.default.action.name";
/** methods names' whitelist **/
/** Method names' whitelist */
public static final String STRUTS_ALLOWED_METHOD_NAMES = "struts.allowed.method.names";
/** default method name to use when method didn't match the whitelist **/
/** Default method name to use when method didn't match the whitelist */
public static final String STRUTS_DEFAULT_METHOD_NAME = "struts.default.method.name";
/** enables action: prefix **/
/** Enables action: prefix */
public static final String STRUTS_MAPPER_ACTION_PREFIX_ENABLED = "struts.mapper.action.prefix.enabled";
/** enables access to actions in other namespaces than current with action: prefix **/
/** Enables access to actions in other namespaces than current with action: prefix */
public static final String STRUTS_MAPPER_ACTION_PREFIX_CROSSNAMESPACES = "struts.mapper.action.prefix.crossNamespaces";
public static final String DEFAULT_TEMPLATE_TYPE_CONFIG_KEY = "struts.ui.templateSuffix";
/** Allows override default DispatcherErrorHandler **/
/** Allows override default DispatcherErrorHandler */
public static final String STRUTS_DISPATCHER_ERROR_HANDLER = "struts.dispatcher.errorHandler";
/** Comma delimited set of excluded classes and package names which cannot be accessed via expressions **/
/** Comma delimited set of excluded classes and package names which cannot be accessed via expressions */
public static final String STRUTS_EXCLUDED_CLASSES = "struts.excludedClasses";
public static final String STRUTS_EXCLUDED_PACKAGE_NAME_PATTERNS = "struts.excludedPackageNamePatterns";
public static final String STRUTS_EXCLUDED_PACKAGE_NAMES = "struts.excludedPackageNames";
/** Dedicated services to check if passed string is excluded/accepted **/
/** Dedicated services to check if passed string is excluded/accepted */
public static final String STRUTS_EXCLUDED_PATTERNS_CHECKER = "struts.excludedPatterns.checker";
public static final String STRUTS_ACCEPTED_PATTERNS_CHECKER = "struts.acceptedPatterns.checker";
/** Constant is used to override framework's default excluded patterns **/
/** Constant is used to override framework's default excluded patterns */
public static final String STRUTS_OVERRIDE_EXCLUDED_PATTERNS = "struts.override.excludedPatterns";
public static final String STRUTS_OVERRIDE_ACCEPTED_PATTERNS = "struts.override.acceptedPatterns";
@@ -328,4 +336,6 @@ public final class StrutsConstants {
public static final String STRUTS_LOCALIZED_TEXT_PROVIDER = "struts.localizedTextProvider";
public static final String STRUTS_DISALLOW_PROXY_MEMBER_ACCESS = "struts.disallowProxyMemberAccess";
public static final String STRUTS_OGNL_AUTO_GROWTH_COLLECTION_LIMIT = "struts.ognl.autoGrowthCollectionLimit";
}
@@ -80,14 +80,17 @@ public class Anchor extends ClosingUIBean {
urlProvider.setHttpServletResponse(response);
}
@Override
public String getDefaultOpenTemplate() {
return OPEN_TEMPLATE;
}
@Override
protected String getDefaultTemplate() {
return TEMPLATE;
}
@Override
public boolean usesBody() {
return true;
}
@@ -96,16 +99,17 @@ public class Anchor extends ClosingUIBean {
protected void evaluateExtraParams() {
super.evaluateExtraParams();
if (href != null)
if (href != null) {
addParameter("href", ensureAttributeSafelyNotEscaped(findString(href)));
else {
} else {
//no href, build it from URL attributes
StringWriter sw = new StringWriter();
urlRenderer.beforeRenderUrl(urlProvider);
urlRenderer.renderUrl(sw, urlProvider);
String builtHref = sw.toString();
if (StringUtils.isNotEmpty(builtHref))
if (StringUtils.isNotEmpty(builtHref)) {
addParameter("href", ensureAttributeSafelyNotEscaped(builtHref));
}
}
}
@@ -115,10 +119,10 @@ public class Anchor extends ClosingUIBean {
}
@Inject
public void setUrlRenderer(UrlRenderer urlRenderer) {
urlProvider.setUrlRenderer(urlRenderer);
public void setUrlRenderer(UrlRenderer urlRenderer) {
urlProvider.setUrlRenderer(urlRenderer);
this.urlRenderer = urlRenderer;
}
}
@Inject(required=false)
public void setExtraParameterProvider(ExtraParameterProvider provider) {
@@ -135,6 +139,7 @@ public class Anchor extends ClosingUIBean {
/**
* Overrides to be able to render body in a template rather than always before the template
*/
@Override
public boolean end(Writer writer, String body) {
this.processingTagBody = false;
evaluateParams();
@@ -143,15 +148,14 @@ public class Anchor extends ClosingUIBean {
mergeTemplate(writer, buildTemplateName(template, getDefaultTemplate()));
} catch (Exception e) {
LOG.error("error when rendering", e);
}
finally {
} finally {
popComponentStack();
}
return false;
}
@Override
public void addParameter(String key, Object value) {
/*
the parameters added by this method are used in the template. this method is also
@@ -160,8 +164,9 @@ public class Anchor extends ClosingUIBean {
*/
if (processingTagBody) {
this.urlParameters.put(key, value);
} else
} else {
super.addParameter(key, value);
}
}
@Override
@@ -173,8 +178,9 @@ public class Anchor extends ClosingUIBean {
*/
if (processingTagBody) {
this.urlParameters.putAll(params);
} else
} else {
super.addAllParameters(params);
}
}
public UrlProvider getUrlProvider() {
@@ -196,6 +202,7 @@ public class Anchor extends ClosingUIBean {
urlProvider.setScheme(scheme);
}
@Override
@StrutsTagAttribute(description = "The target value to use, if not using action")
public void setValue(String value) {
urlProvider.setValue(value);
@@ -30,17 +30,17 @@ import java.util.Map;
import java.util.ArrayList;
import java.util.List;
import org.apache.struts2.dispatcher.PrepareOperations;
import org.apache.struts2.views.annotations.StrutsTag;
import org.apache.struts2.StrutsException;
@StrutsTag(name="debug", tldTagClass="org.apache.struts2.views.jsp.ui.DebugTag",
description="Prints debugging information")
description="Prints debugging information (Only if 'struts.devMode' is enabled)")
public class Debug extends UIBean {
public static final String TEMPLATE = "debug";
protected ReflectionProvider reflectionProvider;
public Debug(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
super(stack, request, response);
@@ -50,7 +50,7 @@ public class Debug extends UIBean {
public void setReflectionProvider(ReflectionProvider prov) {
this.reflectionProvider = prov;
}
protected String getDefaultTemplate() {
return TEMPLATE;
}
@@ -58,25 +58,40 @@ public class Debug extends UIBean {
public boolean start(Writer writer) {
boolean result = super.start(writer);
ValueStack stack = getStack();
Iterator iter = stack.getRoot().iterator();
List stackValues = new ArrayList(stack.getRoot().size());
while (iter.hasNext()) {
Object o = iter.next();
Map values;
try {
values = reflectionProvider.getBeanMap(o);
} catch (Exception e) {
throw new StrutsException("Caught an exception while getting the property values of " + o, e);
if (showDebug()) {
ValueStack stack = getStack();
Iterator iter = stack.getRoot().iterator();
List stackValues = new ArrayList(stack.getRoot().size());
while (iter.hasNext()) {
Object o = iter.next();
Map values;
try {
values = reflectionProvider.getBeanMap(o);
} catch (Exception e) {
throw new StrutsException("Caught an exception while getting the property values of " + o, e);
}
stackValues.add(new DebugMapEntry(o.getClass().getName(), values));
}
stackValues.add(new DebugMapEntry(o.getClass().getName(), values));
addParameter("stackValues", stackValues);
}
addParameter("stackValues", stackValues);
return result;
}
@Override
public boolean end(Writer writer, String body) {
if (showDebug()) {
return super.end(writer, body);
} else {
popComponentStack();
return false;
}
}
protected boolean showDebug() {
return (devMode || Boolean.TRUE == PrepareOperations.getDevModeOverride());
}
private static class DebugMapEntry implements Map.Entry {
private Object key;
private Object value;
@@ -20,6 +20,7 @@ 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.RequestUtils;
@@ -35,6 +36,7 @@ import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;
@@ -90,17 +92,19 @@ public class Include extends Component {
private static final Logger LOG = LogManager.getLogger(Include.class);
private static String systemEncoding = System.getProperty("file.encoding");
private static final String systemEncoding = System.getProperty("file.encoding");
protected String value;
private HttpServletRequest req;
private HttpServletResponse res;
private static String defaultEncoding;
private String defaultEncoding; // Made non-static (during WW-4971 fix)
private boolean useResponseEncoding; // Added with WW-4971 fix (allows switch between usage of response or default encoding)
public Include(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
super(stack);
this.req = req;
this.res = res;
useResponseEncoding = false; // By default use defaultEncoding (vs. response/page encoding)
}
@Inject(StrutsConstants.STRUTS_I18N_ENCODING)
@@ -108,9 +112,25 @@ public class Include extends Component {
defaultEncoding = encoding;
}
@Inject(value = StrutsConstants.STRUTS_TAG_INCLUDETAG_USERESPONSEENCODING, required=false)
public void setUseResponseEncoding(String useEncoding) {
useResponseEncoding = Boolean.parseBoolean(useEncoding);
}
public boolean end(Writer writer, String body) {
String page = findString(value, "value", "You must specify the URL to include. Example: /foo.jsp");
StringBuilder urlBuf = new StringBuilder();
String encodingForInclude;
if (useResponseEncoding) {
encodingForInclude = res.getCharacterEncoding(); // Use response (page) encoding
if (encodingForInclude == null || encodingForInclude.length() == 0) {
encodingForInclude = defaultEncoding; // Revert to defaultEncoding when response (page) encoding is invalid
}
}
else {
encodingForInclude = defaultEncoding; // Use default encoding (when useResponseEncoding is false)
}
// Add URL
urlBuf.append(page);
@@ -147,7 +167,7 @@ public class Include extends Component {
// Include
try {
include(result, writer, req, res, defaultEncoding);
include(result, writer, req, res, encodingForInclude);
} catch (ServletException | IOException e) {
LOG.warn("Exception thrown during include of {}", result, e);
}
@@ -209,7 +229,7 @@ public class Include extends Component {
}
public void addParameter(String key, Object value) {
// don't use the default implementation of addParameter,
// Don't use the default implementation of addParameter,
// instead, include tag requires that each parameter be a list of objects,
// just like the HTTP servlet interfaces are (String[])
if (value != null) {
@@ -256,7 +276,7 @@ public class Include extends Component {
// Use given encoding
pageResponse.getContent().writeTo(writer, encoding);
} else {
//use the platform specific encoding
// Use the platform specific encoding
pageResponse.getContent().writeTo(writer, systemEncoding);
}
}
@@ -349,9 +369,9 @@ public class Include extends Component {
* @throws IOException
*/
public FastByteArrayOutputStream getContent() throws IOException {
//if we are using a writer, we need to flush the
//data to the underlying outputstream.
//most containers do this - but it seems Jetty 4.0.5 doesn't
// If we are using a writer, we need to flush the
// data to the underlying outputstream.
// Most containers do this - but it seems Jetty 4.0.5 doesn't
if (pagePrintWriter != null) {
pagePrintWriter.flush();
}
@@ -140,4 +140,19 @@ public class OptGroup extends Component {
public void setListValue(String listValue) {
internalUiBean.setListValue(listValue);
}
@StrutsTagAttribute(description = "Property of list objects to get css class from")
public void setListCssClass(String listCssClass) {
internalUiBean.setListCssClass(listCssClass);
}
@StrutsTagAttribute(description = "Property of list objects to get css style from")
public void setListCssStyle(String listCssStyle) {
internalUiBean.setListCssStyle(listCssStyle);
}
@StrutsTagAttribute(description = "Property of list objects to get title from")
public void setListTitle(String listTitle) {
internalUiBean.setListTitle(listTitle);
}
}
@@ -89,8 +89,8 @@ public class ServletUrlRenderer implements UrlRenderer {
// We don't include the request parameters cause they would have been
// prioritised before this [in start(Writer) method]
if (_value != null && _value.indexOf("?") > 0) {
_value = _value.substring(0, _value.indexOf("?"));
if (_value != null && _value.indexOf('?') > 0) {
_value = _value.substring(0, _value.indexOf('?'));
}
result = urlHelper.buildUrl(_value, urlComponent.getHttpServletRequest(), urlComponent.getHttpServletResponse(), urlComponent.getParameters(), scheme, urlComponent.isIncludeContext(), urlComponent.isEncode(), urlComponent.isForceAddSchemeHostAndPort(), urlComponent.isEscapeAmp());
}
@@ -150,10 +150,10 @@ public class ServletUrlRenderer implements UrlRenderer {
}
Map actionParams = null;
if (action != null && action.indexOf("?") > 0) {
String queryString = action.substring(action.indexOf("?") + 1);
if (action != null && action.indexOf('?') > 0) {
String queryString = action.substring(action.indexOf('?') + 1);
actionParams = urlHelper.parseQueryString(queryString, false);
action = action.substring(0, action.indexOf("?"));
action = action.substring(0, action.indexOf('?'));
}
ActionMapping nameMapping = actionMapper.getMappingFromActionName(action);
@@ -322,7 +322,7 @@ public class ServletUrlRenderer implements UrlRenderer {
// where the parameters specified in value attribute takes priority.
if (StringUtils.contains(value, "?")) {
String queryString = value.substring(value.indexOf("?") + 1);
String queryString = value.substring(value.indexOf('?') + 1);
mergedParams = urlHelper.parseQueryString(queryString, false);
for (Map.Entry<String, Object> entry : contextParameters.entrySet()) {
@@ -83,6 +83,7 @@ import com.opensymphony.xwork2.util.ValueStack;
public class Set extends ContextBean {
protected String scope;
protected String value;
protected boolean trimBody = true;
public Set(ValueStack stack) {
super(stack);
@@ -136,6 +137,11 @@ public class Set extends ContextBean {
this.value = value;
}
@StrutsTagAttribute(description="Set to false to prevent the default whitespace-trim of this tag's body content", type="Boolean", defaultValue="true")
public void setTrimBody(boolean trimBody) {
this.trimBody = trimBody;
}
@Override
public boolean usesBody() {
return true;
@@ -528,6 +528,7 @@ public abstract class UIBean extends Component {
this.templateEngineManager = mgr;
}
@Override
public boolean end(Writer writer, String body) {
evaluateParams();
try {
@@ -883,7 +884,7 @@ public abstract class UIBean extends Component {
evaluateExtraParams();
}
protected String escape(String name) {
protected String escape(String name) {
// escape any possible values that can make the ID painful to work with in JavaScript
if (name != null) {
return name.replaceAll("[\\/\\.\\[\\]]", "_");
@@ -930,7 +931,7 @@ public abstract class UIBean extends Component {
form.addParameter("customOnsubmitEnabled", Boolean.TRUE);
} else {
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot find an Ancestor form, custom onsubmit is NOT enabled");
LOG.warn("Cannot find an Ancestor form, custom onsubmit is NOT enabled");
}
}
}
@@ -1240,27 +1241,30 @@ public abstract class UIBean extends Component {
this.tooltipIconPath = tooltipIconPath;
}
public void setDynamicAttributes(Map<String, Object> tagDynamicAttributes) {
for (String key : tagDynamicAttributes.keySet()) {
public void setDynamicAttributes(Map<String, Object> tagDynamicAttributes) {
for (Map.Entry<String, Object> entry : tagDynamicAttributes.entrySet()) {
String key = entry.getKey();
if (!isValidTagAttribute(key)) {
dynamicAttributes.put(key, tagDynamicAttributes.get(key));
dynamicAttributes.put(key, entry.getValue());
}
}
}
@Override
/**
* supports dynamic attributes for freemarker ui tags
* @see https://issues.apache.org/jira/browse/WW-3174
@Override
/**
* supports dynamic attributes for freemarker ui tags
* @see https://issues.apache.org/jira/browse/WW-3174
* @see https://issues.apache.org/jira/browse/WW-4166
*/
*/
public void copyParams(Map params) {
super.copyParams(params);
for (Object o : params.entrySet()) {
Map.Entry entry = (Map.Entry) o;
String key = (String) entry.getKey();
if(!isValidTagAttribute(key) && !key.equals("dynamicAttributes"))
if (!isValidTagAttribute(key) && !key.equals("dynamicAttributes")) {
dynamicAttributes.put(key, entry.getValue());
}
}
}
@@ -28,26 +28,26 @@ import java.io.Writer;
*
*/
public interface UrlRenderer {
/**
* Preprocessing step
* @param provider The {@link UrlProvider} component that "owns" this renderer.
*/
void beforeRenderUrl(UrlProvider provider);
/**
* Render a URL.
* @param writer A writer that the implementation can use to write the result to.
* @param provider The {@link UrlProvider} component that "owns" this renderer.
*/
void renderUrl(Writer writer, UrlProvider provider);
/**
* Render a Form URL.
* @param formComponent The {@link Form} component that "owns" this renderer.
*/
void renderFormUrl(Form formComponent);
void setActionMapper(ActionMapper actionMapper);
/**
* Preprocessing step
* @param provider The {@link UrlProvider} component that "owns" this renderer.
*/
void beforeRenderUrl(UrlProvider provider);
/**
* Render a URL.
* @param writer A writer that the implementation can use to write the result to.
* @param provider The {@link UrlProvider} component that "owns" this renderer.
*/
void renderUrl(Writer writer, UrlProvider provider);
/**
* Render a Form URL.
* @param formComponent The {@link Form} component that "owns" this renderer.
*/
void renderFormUrl(Form formComponent);
void setActionMapper(ActionMapper actionMapper);
}
@@ -142,7 +142,7 @@ public abstract class BaseTemplateEngine implements TemplateEngine {
protected String getFinalTemplateName(Template template) {
String t = template.toString();
if (t.indexOf(".") <= 0) {
if (t.indexOf('.') <= 0) {
return t + "." + getSuffix();
}
return t;
@@ -113,5 +113,10 @@ public abstract class AbstractBeanSelectionProvider implements BeanSelectionProv
throw new ConfigurationException("Unable to load bean "+type.getName()+" ("+name+")");
}
}
@Override
public Class type() {
return type;
}
}
}
@@ -90,6 +90,9 @@ public class StrutsXmlConfigurationProvider extends XmlConfigurationProvider {
public ServletContext create(Context context) throws Exception {
return servletContext;
}
public Class<? extends ServletContext> type() {
return servletContext.getClass();
}
});
}
super.register(containerBuilder, props);
@@ -31,7 +31,6 @@ import org.apache.logging.log4j.Logger;
import org.apache.struts2.RequestUtils;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.StrutsException;
import org.apache.struts2.util.PrefixTrie;
import javax.servlet.http.HttpServletRequest;
@@ -117,6 +116,10 @@ public class DefaultActionMapper implements ActionMapper {
protected boolean allowSlashesInActionNames = false;
protected boolean alwaysSelectFullNamespace = false;
protected PrefixTrie prefixTrie = null;
protected Pattern allowedNamespaceNames = Pattern.compile("[a-zA-Z0-9._/\\-]*");
protected String defaultNamespaceName = "/";
protected Pattern allowedActionNames = Pattern.compile("[a-zA-Z0-9._!/\\-]*");
protected String defaultActionName = "index";
@@ -163,8 +166,8 @@ public class DefaultActionMapper implements ActionMapper {
}
}
if (!allowSlashesInActionNames && !allowActionCrossNamespaceAccess) {
if (actionName.lastIndexOf("/") != -1) {
actionName = actionName.substring(actionName.lastIndexOf("/") + 1);
if (actionName.lastIndexOf('/') != -1) {
actionName = actionName.substring(actionName.lastIndexOf('/') + 1);
}
}
mapping.setName(actionName);
@@ -202,6 +205,16 @@ public class DefaultActionMapper implements ActionMapper {
this.alwaysSelectFullNamespace = BooleanUtils.toBoolean(alwaysSelectFullNamespace);
}
@Inject(value = StrutsConstants.STRUTS_ALLOWED_NAMESPACE_NAMES, required = false)
public void setAllowedNamespaceNames(String allowedNamespaceNames) {
this.allowedNamespaceNames = Pattern.compile(allowedNamespaceNames);
}
@Inject(value = StrutsConstants.STRUTS_DEFAULT_NAMESPACE_NAME, required = false)
public void setDefaultNamespaceName(String defaultNamespaceName) {
this.defaultNamespaceName = defaultNamespaceName;
}
@Inject(value = StrutsConstants.STRUTS_ALLOWED_ACTION_NAMES, required = false)
public void setAllowedActionNames(String allowedActionNames) {
this.allowedActionNames = Pattern.compile(allowedActionNames);
@@ -271,7 +284,7 @@ public class DefaultActionMapper implements ActionMapper {
ActionMapping mapping = new ActionMapping();
String uri = RequestUtils.getUri(request);
int indexOfSemicolon = uri.indexOf(";");
int indexOfSemicolon = uri.indexOf(';');
uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri;
uri = dropExtension(uri, mapping);
@@ -291,7 +304,7 @@ public class DefaultActionMapper implements ActionMapper {
if (allowDynamicMethodCalls) {
// handle "name!method" convention.
String name = mapping.getName();
int exclamation = name.lastIndexOf("!");
int exclamation = name.lastIndexOf('!');
if (exclamation != -1) {
mapping.setName(name.substring(0, exclamation));
@@ -341,7 +354,7 @@ public class DefaultActionMapper implements ActionMapper {
*/
protected void parseNameAndNamespace(String uri, ActionMapping mapping, ConfigurationManager configManager) {
String namespace, name;
int lastSlash = uri.lastIndexOf("/");
int lastSlash = uri.lastIndexOf('/');
if (lastSlash == -1) {
namespace = "";
name = uri;
@@ -389,10 +402,28 @@ public class DefaultActionMapper implements ActionMapper {
}
}
mapping.setNamespace(namespace);
mapping.setNamespace(cleanupNamespaceName(namespace));
mapping.setName(cleanupActionName(name));
}
/**
* Checks namespace name against allowed pattern if not matched returns default namespace
*
* @param rawNamespace name extracted from URI
* @return safe namespace name
*/
protected String cleanupNamespaceName(final String rawNamespace) {
if (allowedNamespaceNames.matcher(rawNamespace).matches()) {
return rawNamespace;
} else {
LOG.warn(
"{} did not match allowed namespace names {} - default namespace {} will be used!",
rawNamespace, allowedNamespaceNames, defaultNamespaceName
);
return defaultNamespaceName;
}
}
/**
* Checks action name against allowed pattern if not matched returns default action name
*
@@ -131,8 +131,8 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
protected String getCanonicalName(final String originalFileName) {
String fileName = originalFileName;
int forwardSlash = fileName.lastIndexOf("/");
int backwardSlash = fileName.lastIndexOf("\\");
int forwardSlash = fileName.lastIndexOf('/');
int backwardSlash = fileName.lastIndexOf('\\');
if (forwardSlash != -1 && forwardSlash > backwardSlash) {
fileName = fileName.substring(forwardSlash + 1, fileName.length());
} else {
@@ -60,8 +60,8 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
*/
public void cleanUp() {
LOG.debug("Performing File Upload temporary storage cleanup.");
for (String fieldName : fileInfos.keySet()) {
for (FileInfo fileInfo : fileInfos.get(fieldName)) {
for (List<FileInfo> fileInfoList : fileInfos.values()) {
for (FileInfo fileInfo : fileInfoList) {
File file = fileInfo.getFile();
LOG.debug("Deleting file '{}'.", file.getName());
if (!file.delete()) {
@@ -22,13 +22,17 @@ import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.ActionProxyFactory;
import com.opensymphony.xwork2.DefaultActionProxyFactory;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Initializable;
import com.opensymphony.xwork2.inject.Inject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* <!-- START SNIPPET: description -->
@@ -55,38 +59,37 @@ import java.util.Map;
* </pre>
* <!-- END SNIPPET: description -->
*/
public class PrefixBasedActionProxyFactory extends DefaultActionProxyFactory {
public class PrefixBasedActionProxyFactory extends StrutsActionProxyFactory implements Initializable {
private static final Logger LOG = LogManager.getLogger(PrefixBasedActionProxyFactory.class);
private Map<String, ActionProxyFactory> actionProxyFactories = new HashMap<>();
private ActionProxyFactory defaultFactory;
private Set<String> prefixes = new HashSet<>();
@Inject
public void setContainer(Container container) {
this.container = container;
}
@Inject(StrutsConstants.STRUTS_ACTIONPROXYFACTORY)
public void setActionProxyFactory(ActionProxyFactory factory) {
this.defaultFactory = factory;
}
@Inject(StrutsConstants.PREFIX_BASED_MAPPER_CONFIGURATION)
public void setPrefixBasedActionProxyFactories(String list) {
if (list != null) {
String[] factories = list.split(",");
for (String factory : factories) {
String[] thisFactory = factory.split(":");
if (thisFactory.length == 2) {
String factoryPrefix = thisFactory[0].trim();
String factoryName = thisFactory[1].trim();
ActionProxyFactory obj = container.getInstance(ActionProxyFactory.class, factoryName);
if (obj != null) {
actionProxyFactories.put(factoryPrefix, obj);
} else {
LOG.warn("Invalid PrefixBasedActionProxyFactory config entry: [{}]", factory);
}
prefixes = new HashSet<>(Arrays.asList(list.split(",")));
}
}
@Override
public void init() {
for (String factory : prefixes) {
String[] thisFactory = factory.split(":");
if (thisFactory.length == 2) {
String factoryPrefix = thisFactory[0].trim();
String factoryName = thisFactory[1].trim();
ActionProxyFactory obj = container.getInstance(ActionProxyFactory.class, factoryName);
if (obj != null) {
actionProxyFactories.put(factoryPrefix, obj);
} else {
LOG.warn("Invalid PrefixBasedActionProxyFactory config entry: [{}]", factory);
}
}
}
@@ -106,8 +109,7 @@ public class PrefixBasedActionProxyFactory extends DefaultActionProxyFactory {
LOG.debug("No ActionProxyFactory defined for [{}]", key);
}
}
LOG.debug("Cannot find any matching ActionProxyFactory, falling back to [{}]", defaultFactory);
return defaultFactory.createActionProxy(namespace, actionName, methodName, extraContext, executeResult, cleanupContext);
LOG.debug("Cannot find any matching ActionProxyFactory, falling back to [{}]", super.getClass().getName());
return super.createActionProxy(namespace, actionName, methodName, extraContext, executeResult, cleanupContext);
}
}
@@ -31,10 +31,11 @@ public class BackgroundProcess implements Serializable {
private static final long serialVersionUID = 3884464776311686443L;
protected Object action;
protected ActionInvocation invocation;
//WW-4900 transient since 2.5.15
transient protected ActionInvocation invocation;
transient protected Exception exception;
protected String result;
protected Exception exception;
protected boolean done;
/**
@@ -46,7 +47,6 @@ public class BackgroundProcess implements Serializable {
*/
public BackgroundProcess(String threadName, final ActionInvocation invocation, int threadPriority) {
this.invocation = invocation;
this.action = invocation.getAction();
try {
final Thread t = new Thread(new Runnable() {
public void run() {
@@ -96,7 +96,7 @@ public class BackgroundProcess implements Serializable {
* @return the action.
*/
public Object getAction() {
return action;
return invocation.getAction();
}
/**
@@ -26,7 +26,9 @@ import org.apache.struts2.dispatcher.Parameter;
import org.apache.struts2.dispatcher.HttpParameters;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* <!-- START SNIPPET: description -->
@@ -60,14 +62,16 @@ public class CheckboxInterceptor extends AbstractInterceptor {
HttpParameters parameters = ai.getInvocationContext().getParameters();
Map<String, Parameter> extraParams = new HashMap<>();
for (String name : parameters.keySet()) {
Set<String> checkboxParameters = new HashSet<>();
for (Map.Entry<String, Parameter> parameter : parameters.entrySet()) {
String name = parameter.getKey();
if (name.startsWith("__checkbox_")) {
String checkboxName = name.substring("__checkbox_".length());
Parameter value = parameters.get(name);
parameters = parameters.remove(name);
Parameter value = parameter.getValue();
checkboxParameters.add(name);
if (value.isMultiple()) {
LOG.debug("Bypassing automatic checkbox detection due to multiple checkboxes of the same name: {}", name);
LOG.debug("Bypassing automatic checkbox detection due to multiple checkboxes of the same name: {}", name);
continue;
}
@@ -78,7 +82,7 @@ public class CheckboxInterceptor extends AbstractInterceptor {
}
}
}
parameters.remove(checkboxParameters);
ai.getInvocationContext().getParameters().appendAll(extraParams);
@@ -243,6 +243,12 @@ public class ExecuteAndWaitInterceptor extends MethodFilterInterceptor {
synchronized (httpSession) {
BackgroundProcess bp = (BackgroundProcess) session.get(KEY + name);
//WW-4900 Checks if from a de-serialized session? so background thread missed, let's start a new one.
if (bp != null && bp.getInvocation() == null) {
session.remove(KEY + name);
bp = null;
}
if ((!executeAfterValidationPass || secondTime) && bp == null) {
bp = getNewBackgroundProcess(name, actionInvocation, threadPriority);
session.put(KEY + name, bp);
@@ -261,6 +261,7 @@ public class I18nInterceptor extends AbstractInterceptor {
super(invocation);
}
@Override
public Locale find() {
Locale requestOnlyLocale = super.find();
@@ -281,7 +282,6 @@ public class I18nInterceptor extends AbstractInterceptor {
@Override
public Locale store(ActionInvocation invocation, Locale locale) {
//save it in session
Map<String, Object> session = invocation.getInvocationContext().getSession();
if (session != null) {
@@ -290,6 +290,7 @@ public class I18nInterceptor extends AbstractInterceptor {
session.put(attributeName, locale);
}
}
return locale;
}
@@ -298,19 +299,15 @@ public class I18nInterceptor extends AbstractInterceptor {
Locale locale = null;
LOG.debug("Checks session for saved locale");
Map<String, Object> session = invocation.getInvocationContext().getSession();
HttpSession session = ServletActionContext.getRequest().getSession(false);
if (session != null) {
//[WW-4741] Do not force session creation while this is a read operation
HttpSession httpSession = ServletActionContext.getRequest().getSession(false);
if(null != httpSession) {
String sessionId = httpSession.getId();
synchronized (sessionId.intern()) {
Object sessionLocale = session.get(attributeName);
if (sessionLocale != null && sessionLocale instanceof Locale) {
locale = (Locale) sessionLocale;
LOG.debug("Applied session locale: {}", locale);
}
String sessionId = session.getId();
synchronized (sessionId.intern()) {
Object sessionLocale = invocation.getInvocationContext().getSession().get(attributeName);
if (sessionLocale != null && sessionLocale instanceof Locale) {
locale = (Locale) sessionLocale;
LOG.debug("Applied session locale: {}", locale);
}
}
}
@@ -134,6 +134,7 @@ public class PostbackResult extends StrutsResultSupport {
if (actionName != null) {
actionName = conditionalParse(actionName, invocation);
parseLocation = false;
if (namespace == null) {
namespace = invocation.getProxy().getNamespace();
} else {
@@ -215,8 +216,9 @@ public class PostbackResult extends StrutsResultSupport {
private void writeFormElements(HttpServletRequest request, PrintWriter pw) throws UnsupportedEncodingException {
Map<String, String[]> params = request.getParameterMap();
for (String name : params.keySet()) {
String[] values = params.get(name);
for (Map.Entry<String, String[]> entry : params.entrySet()) {
String name = entry.getKey();
String[] values = entry.getValue();
if (isElementIncluded(name, values)) {
writeFormElement(pw, name, values);
}
@@ -159,6 +159,7 @@ public class ServletActionRedirectResult extends ServletRedirectResult implement
*/
public void execute(ActionInvocation invocation) throws Exception {
actionName = conditionalParse(actionName, invocation);
parseLocation = false;
if (namespace == null) {
namespace = invocation.getProxy().getNamespace();
} else {
@@ -137,8 +137,8 @@ public class ServletDispatcherResult extends StrutsResultSupport {
//add parameters passed on the location to #parameters
// see WW-2120
if (StringUtils.isNotEmpty(finalLocation) && finalLocation.indexOf("?") > 0) {
String queryString = finalLocation.substring(finalLocation.indexOf("?") + 1);
if (StringUtils.isNotEmpty(finalLocation) && finalLocation.indexOf('?') > 0) {
String queryString = finalLocation.substring(finalLocation.indexOf('?') + 1);
HttpParameters parameters = getParameters(invocation);
Map<String, Object> queryParams = urlHelper.parseQueryString(queryString, true);
if (queryParams != null && !queryParams.isEmpty()) {
@@ -271,7 +271,7 @@ public class ServletRedirectResult extends StrutsResultSupport implements Reflec
try {
String rawUrl = url;
if (url.contains("?")) {
rawUrl = url.substring(0, url.indexOf("?"));
rawUrl = url.substring(0, url.indexOf('?'));
}
URI uri = URI.create(rawUrl.replaceAll(" ", "%20"));
if (uri.isAbsolute()) {

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