Compare commits

..

162 Commits

Author SHA1 Message Date
Lukasz Lenart 26e1535b58 [maven-release-plugin] prepare release STRUTS_2_5_27 2021-10-19 09:54:17 +02:00
Yasser Zamani a96dd31be6 Merge pull request #493 from apache/WW-5136-class-deprecated
[WW-5136] Makes class attribute deprecated
2021-07-01 11:43:46 +04:30
Lukasz Lenart fe45511712 WW-5136 Makes class attribute deprecated 2021-06-27 09:48:43 +02:00
Lukasz Lenart 90ea4d8aa1 Merge pull request #490 from apache/WW-5132-labelposition
[WW-5132] [WW-5123] labelposition
2021-06-27 09:17:10 +02:00
Lukasz Lenart d04ed76f1b WW-5135 Upgrades Xstream to version 1.4.17 2021-06-20 20:52:21 +02:00
Lukasz Lenart f1824b5393 WW-5132 Marks old labelposition as Deprecated 2021-06-18 07:02:20 +02:00
Lukasz Lenart 675deff599 WW-5123 Adds right option to TLD for Checkbox tag 2021-06-14 20:28:24 +02:00
Lukasz Lenart 256cd14bf0 WW-5123 Makes labelpostion deprecated 2021-06-14 20:27:48 +02:00
Lukasz Lenart 620b8c3a0c Merge pull request #484 from apache/ww_5125_2_5
[WW-5125] use .get(...) instead of [...] for fieldErrors
2021-05-02 12:05:10 +02:00
Yasser Zamani 20e4529e35 [WW-5125] use .get(...) instead of [...] for fieldErrors
All [ occurrences in all ftl files reviewed. Only fieldErrors had used [...] which replaced by .get(...) to fix WW-5125 as well as aligning with other ftl files conduct.
2021-04-25 14:56:47 +04:30
Lukasz Lenart 8a26c0d753 WW-5118 Upgrades OGNL to ver 3.1.29 to fix Long conversion 2021-04-06 07:20:24 +02:00
Lukasz Lenart b2580e1d76 WW-5122 Upgrades Xstream to version 1.4.16 2021-03-28 10:11:49 +02:00
Lukasz Lenart a65b8d5d51 [WW-5117] Reorders stack (#475)
* Moves action on top just before the tag
* Moves pushes out of try-finally block
2021-03-25 17:26:13 +04:30
Yasser Zamani 7e912a2985 Merge pull request #479 from davoustp/contention-in-singleton-injection-2.5.x
[WW-5121] Fix: remove contention during Scope.SINGLETON injection
2021-03-23 20:31:28 +04:30
Lukasz Lenart 1b9563d366 Merge pull request #477 from davoustp/contention-in-localized-resources-2.5.x
[WW-5119] Fix: remove contention during localized text lookup (JDK 1.7+)
2021-03-22 10:40:43 +01:00
Pascal Davoust ce8b75de58 [WW-5121] Fix: remove contention during Scope.SINGLETON injection 2021-03-22 09:40:02 +01:00
Pascal Davoust 280f25d2fe Update AbstractLocalizedTextProvider.java
Applied code review comments from JCgH4164838Gh792C124B5 into account
2021-03-22 08:50:59 +01:00
Pascal Davoust 69669d6cf7 Fix: remove contention during localized text lookup (JDK 1.7+) 2021-03-15 11:56:41 +01:00
Lukasz Lenart 39d70e3944 Merge pull request #472 from Marcono1234/struts-2-5-x
2.5.x backport: WW-5116 Fix wrong regex range
2021-02-08 20:06:27 +01:00
Marcono1234 cb5e55b06c WW-5116 Fix wrong regex range 2021-02-08 17:10:49 +01:00
Lukasz Lenart ea23ce295a [maven-release-plugin] prepare for next development iteration 2020-11-25 17:32:09 +01:00
Lukasz Lenart 4cf9093cc5 [maven-release-plugin] prepare release STRUTS_2_5_26 2020-11-25 17:31:54 +01:00
Lukasz Lenart 46bae3ce68 Reverts version to 2.5.26-SNAPSHOT 2020-11-25 17:13:51 +01:00
Lukasz Lenart dfa8fb3e4c Fixes translating id in Form tag 2020-11-25 17:12:57 +01:00
Lukasz Lenart a2df8f9890 [maven-release-plugin] prepare for next development iteration 2020-11-24 08:22:00 +01:00
Lukasz Lenart 7253edeada [maven-release-plugin] prepare release STRUTS_2_5_26 2020-11-24 08:16:43 +01:00
Lukasz Lenart 2efe3cec7a Adds additional excludes packages and uses strict SMI declaration 2020-11-24 07:51:43 +01:00
Lukasz Lenart 4506d5716d Reverts version to 2.5.26-SNAPSHOT 2020-11-24 07:49:59 +01:00
Lukasz Lenart 83aff6e470 [maven-release-plugin] prepare for next development iteration 2020-11-21 08:40:22 +01:00
Lukasz Lenart 3138dc7fbd [maven-release-plugin] prepare release STRUTS_2_5_26 2020-11-21 08:40:09 +01:00
Lukasz Lenart 4566734662 Merge pull request #446 from apache/WW-5096-fix-static
[WW-5096] Fix StaticParametersInterceptor param overwrite
2020-11-20 07:47:20 +01:00
Lukasz Lenart d591b7e3b9 WW-5096 Adds tests to cover overwrite 2020-11-18 09:34:49 +01:00
Lukasz Lenart 9c45d6b025 WW-5096 Fixes params overwriting 2020-11-14 21:50:14 +01:00
Lukasz Lenart 482af41673 Adds some additional excluded packages 2020-11-13 19:37:02 +01:00
Lukasz Lenart 0a75d8e8fa Avoids recursion in tags 2020-11-11 07:31:36 +01:00
Lukasz Lenart 1d18e8f9a8 WW-5095 Sets ActionMapping when preparing a test nv 2020-11-11 07:27:40 +01:00
Lukasz Lenart f6365e7363 Uses proper tools labels 2020-11-05 08:08:44 +01:00
Lukasz Lenart 84aeb77011 [maven-release-plugin] prepare for next development iteration 2020-09-17 13:37:00 +02:00
Lukasz Lenart b3a9d82d58 [maven-release-plugin] prepare release STRUTS_2_5_25 2020-09-17 13:36:38 +02:00
Lukasz Lenart 828d02fcbd Merge pull request #438 from yasserzamani/WW-5087
WW-5087 handle Parameter.Empty properly
2020-09-15 07:48:19 +02:00
Yasser Zamani 88b05cdaed WW-5087 handle Parameter.Empty properly
There was a bug with AliasInterceptor not handling the Parameter.Empty that is returned from HttpParameters.get(). Since HttpParameters.get() always returns a non-null value, the Evaluated object is treated as always being defined, which results in the empty value being set incorrectly on the stack.
2020-09-14 18:00:54 +04:30
Lukasz Lenart e60df05c27 Merge pull request #437 from gregh3269/struts-2-5-x
Empty file upload, storeLocation null gives wrong error message.
2020-09-09 12:57:59 +02:00
Greg Huber 1efcc938cf Empty file upload, storeLocation null gives wrong error message. 2020-09-09 11:02:55 +01:00
Lukasz Lenart 7b1c3b0fca Merge pull request #436 from JCgH4164838Gh792C124B5/WW-5075_S2_5_OSGiPluginBackportfix
Backport a few PR#433 OSGi plugin-related changes from 2.6 to 2.5.
2020-09-09 07:52:57 +02:00
JCgH4164838Gh792C124B5 10a834a54c Backport a few PR#433 OSGi plugin-related changes from 2.6 to 2.5.
- Fix to allow the OSGi plugin to initialize with no internet connection.
- Fix an unintended JS change for the admin bundle.
- Fix the OSGi Demo bundle so it works under 2.5.x as well.
2020-09-08 15:25:02 -04:00
Lukasz Lenart abb1ac3c99 [maven-release-plugin] prepare for next development iteration 2020-08-18 07:38:38 +02:00
Lukasz Lenart dcc59937a8 [maven-release-plugin] prepare release STRUTS_2_5_24 2020-08-18 07:38:25 +02:00
Lukasz Lenart 22c88faf38 WW-5086 Fixes s:set tag to persists empty body 2020-08-17 09:46:27 +02:00
Lukasz Lenart 1191ca3ed0 WW-5086 Fixes s:set tag with empty body 2020-08-17 08:30:56 +02:00
Yasser Zamani bcfb769005 Merge pull request #427 from JCgH4164838Gh792C124B5/WW-5075_S2_5_OSGiPluginUpdate
WW-5075 Fixes for OSGi plugin in 2.5.x
2020-07-29 08:08:57 +04:30
JCgH4164838Gh792C124B5 d61be3e4ce Updated with suggested changes from review.
- BundlePackageLoader changes suggested by L. Lenart.
- FelixOsgiHost changes to better handle Felix bundle cache location
  processing (Windows and Linux).
- FelixOsgIHost test modified to not fail if felix-cache directory cannot
  be created (warn only) to avoid failing the whole build.
2020-07-25 16:11:02 -04:00
JCgH4164838Gh792C124B5 c7149ab1bc Initial attempt to fix OSGi Plugin issues discovered during examination of
WW-5075.
- Indication is that the OSGi Plugin has been failing since Struts 2.3.4.
- Applied fix to ResourceFinder to restore 2.3.x logic that was broken in
  2.5.x.
- Implemented changes to restore OSGi Plugin functionality for 2.5.x.
- Applied changes to the OSGi Admin Bundle to function under 2.5.x.
- Updated the OSGi Admin Bundle JS libraries and related CSS to newer
  versions.
- Added new unit tests for the OSGi plugin.
- The OSGi plugin will only function properly with exploded/expanded WAR
  files.
2020-07-20 01:12:12 -04:00
Yasser Zamani 4504e610f1 Merge pull request #425 from apache/WW-5077-dmi-aware
[WW-5077] DMI aware pattern
2020-07-17 14:16:36 +04:30
Lukasz Lenart 9b3a23eb28 WW-5077 Adjusts DMI aware Regex to be more narrowed 2020-07-17 08:08:57 +02:00
Lukasz Lenart 3220d832d2 WW-5077 Restores escaped brackets 2020-07-16 07:30:06 +02:00
Lukasz Lenart bd007953ea Sets a proper timestamp as maven-jar-plugin doesn't support "now" 2020-07-11 20:39:55 +02:00
Lukasz Lenart 1b0c743e85 WW-5077 Uses a different pattern if DMI is enabled 2020-07-11 20:31:30 +02:00
Lukasz Lenart 89e02a4fb4 Adds outputTimestamp property to support reproducible build
See the link for more details
https://lists.apache.org/thread.html/r27ebcfec6431dc5f4830744e3567f082d8f140dc579f2a35408ea25c%40%3Cusers.maven.apache.org%3E
2020-07-11 19:45:33 +02:00
Lukasz Lenart 8cb93ad39a [maven-release-plugin] prepare for next development iteration 2020-07-02 07:53:53 +02:00
Lukasz Lenart e8656d5737 [maven-release-plugin] prepare release STRUTS_2_5_23 2020-07-02 07:53:39 +02:00
Lukasz Lenart 7f10ed505f Merge pull request #419 from apache/WW-5077-better-logs
[WW-5077] Better logs
2020-05-24 09:32:56 +02:00
Lukasz Lenart 043814b774 WW-5077 Uses better logging to inform user about excluded params 2020-05-24 08:59:40 +02:00
Lukasz Lenart 0fabde9f97 Merge pull request #417 from JCgH4164838Gh792C124B5/LL_tiny-improvements_unittest
Provide unit test for partial backport PR#416 for 2.5.x
2020-05-18 07:49:51 +02:00
JCgH4164838Gh792C124B5 4457f03c70 Provide unit test for partial backport of L. Lenart's PR#414 to 2.5.x:
- DispatcherTest provides code coverage tests of all getLocale() paths.
2020-05-17 14:20:41 -04:00
Lukasz Lenart 3d3512a399 Merge pull request #416 from JCgH4164838Gh792C124B5/Partial_Backport_LL_tiny-improvements
Partial backport of Tiny improvements PR#414 to 2.5.x:
2020-05-17 08:58:49 +02:00
JCgH4164838Gh792C124B5 59a6cbf6ca Partial backport of L. Lenart's PR#414 to 2.5.x:
- Improve Dispatcher getLocale() handling if running in AppEngine.
- Implemented the same improvement to the defaultLocale logic path within
  getLocale().
2020-05-16 18:48:35 -04:00
Lukasz Lenart 19802b0614 Bumps struts-master and maven-site-plugin 2020-05-14 07:21:48 +02:00
Lukasz Lenart e46e662a7a Merge pull request #411 from JCgH4164838Gh792C124B5/WW-5072_fix
Minor change to fix WW-5072
2020-05-03 12:00:20 +02:00
JCgH4164838Gh792C124B5 4786fba0d7 Minor change to fix WW-5072 (single file upload failure):
- Add action-local method to get upload file size.
- Change file upload validation to use new method.
2020-05-02 17:51:45 -04:00
Lukasz Lenart e32bd7dba9 Merge pull request #405 from apache/WW-5065-append-or-not
[WW-5065] Defines a new flag to control appending params
2020-04-26 19:51:29 +02:00
Lukasz Lenart 6e1d2add07 WW-5065 Adds missing flag value 2020-04-24 09:33:06 +02:00
Lukasz Lenart 2eeac367fe WW-5065 Cleans up code and marks old constructor as deprecated 2020-04-24 09:32:50 +02:00
Lukasz Lenart 30b43044a3 WW-5065 Defines a new flag to control appending params 2020-04-23 07:13:14 +02:00
Lukasz Lenart 5c82f0246e Merge pull request #400 from atkaiser/WW5065-FixAbstractMatcherReplaceParams
[WW-5065] Removing unnecessary part of AbstractMatcher#replaceParameters
2020-04-22 06:59:21 +02:00
Lukasz Lenart fff35cfd9d Merge pull request #402 from JCgH4164838Gh792C124B5/WW-5067-25x-Fix1
WW-5067-Fix1 (correct accidental artifactId change)
2020-04-20 07:45:58 +02:00
Lukasz Lenart 1526b36dd6 Merge pull request #404 from JCgH4164838Gh792C124B5/WW-5069
Initial fix for WW-5069 (improve build behaviour JDK9+)
2020-04-20 07:23:57 +02:00
JCgH4164838Gh792C124B5 6d6a422db7 Initial fix for WW-5069:
- Force US Locale for two tests that use date strings of the form
MM/DD/CCYY.
- When the tests/build are run in an environment with a non-US Locale
and newer JDKs the tests may fail due to inability to parse the US date
format.

Note: Was noticed on Windows 10 with JDK11, but could affect other
environments when run in a non-US Locale.
2020-04-19 21:50:09 -04:00
JCgH4164838Gh792C124B5 5cf57b9132 WW-5067-Fix1
- Accidental change of artifactId when groupId was changed for weld-se in
original PR.  This commit restores the originally intended artifactId.
2020-04-18 15:49:44 -04:00
Lukasz Lenart f4c0135878 Merge pull request #401 from JCgH4164838Gh792C124B5/WW-5067-25x
Proposed WW-5067 change
2020-04-13 09:08:26 +02:00
JCgH4164838Gh792C124B5 77cfae3084 Proposed WW-5067 change.
------
Proposed list of library version updates:
---
- cdi-api 1.0-SP4 -> 1.2
- weld-core 1.0.1-SP4 -> 2.2.16.SP1
- weld-se 1.0.1-Final -> weld-se-core 2.2.16.SP1
- slf4j-api 1.7.28 -> 1.7.30
- slf4j-simple 1.7.28 -> 1.7.30
- jackson 2.10.0 -> 2.10.3
- ognl 3.1.26 -> 3.1.28
- asm 7.1 -> 7.3.1
- spring 4.3.25.RELEASE -> 4.3.26.RELEASE
- freemarker 2.3.28 -> 2.3.30
- org.apache.felix.main 4.6.1 -> 6.0.3
---
Proposed list of Maven plugin version updates:
---
- doxia-core 1.8 -> 1.9.1
- doxia-module-markdown 1.7 -> 1.9.1
- maven-project-info-reports-plugin 2.7 -> 3.0.0
- updateimpact-maven-plugin 1.0.10 -> 1.0.12
- maven-surefire-plugin 2.22.1 -> 3.0.0-M4
- maven-war-plugin 2.1 -> 3.2.3
- maven-dependency-plugin 2.10 -> 3.1.2
- dependency-check-maven 3.3.4 -> 5.3.2
Note: Unable to upgrade maven-bundle-plugin past 2.1.0 as it introduced
      OOM during JDK7 builds with default heap settings.
---
2020-04-12 23:38:43 -04:00
Alex Kaiser ec56290056 Removing unnecessary part of AbstractMatcher#replaceParameters method and adding a test to make sure it is working correctly 2020-04-08 11:23:02 -07:00
Lukasz Lenart 47c87bc62c Merge pull request #385 from JCgH4164838Gh792C124B5/local_25x_TstFix1
Fix incorrect encoding strings in FileUploadInterceptorTest
2019-12-01 12:34:54 +01:00
JCgH4164838Gh792C124B5 ce467b7fa5 Fix incorrect encoding strings provided in FileUPloadInterceptorTest
- Tests were using "text/html" which is not a valid character encoding.
No impact currently, but the tests could fail in the future if this is not
corrected.  If the code is re-used elsewhere for a test of an action a
valid encoding will be needed.
- Switch to a predefined constant CharSet to get the string instead.
2019-11-30 16:06:05 -05:00
Lukasz Lenart 73eb6ed189 Adds a link to Struts Examples pages 2019-11-25 09:39:50 +01:00
Lukasz Lenart 80a91dc75f [maven-release-plugin] prepare for next development iteration 2019-11-17 20:17:42 +01:00
Lukasz Lenart a6edb0d5df [maven-release-plugin] prepare release STRUTS_2_5_22 2019-11-17 20:17:20 +01:00
JCgH4164838Gh792C124B5 3dfc5a4074 Disable expressionMaxLength by default for Struts 2.5.x. (#380)
* Disable struts.ognl.expressionMaxLength by default for Struts 2.5.x.
- Commented out struts.ognl.expressionMaxLength line in default.properties
and provided in-place comments about its usage.
- Changed OgnlValueStack.handleOgnlException() methods to output error
instead of warn for failures to evaluate expressions due to security
constraints.
- Updated existing unit tests to compensate for change in default
behaviour.
- Added a unit test to confirm default behaviour for
struts.ognl.expressionMaxLength is disabled.

* Updated commit for disable struts.ognl.expressionMaxLength by default for
Struts 2.5.x
- Additional unit test requested by Y. Zamani for code coverage.
- Corrected accidental use of wrong (static) toString method in one test.
- Addition of a minimum struts.ognl.expressionMaxLength value permitted
by Struts 2 (128).  Any value smaller than that is likely to be a
configuration error and if a user really wishes to force it they may go to
OGNL directly to do so.

* Updated commit for disable struts.ognl.expressionMaxLength by default for
Struts 2.5.x
- Removed minimum struts.ognl.expressionMaxLength (restored to previous
behaviour) as requested by Y. Zamani and L. Lenart.
- Updated unit tests to compensate for the above change.
- Changed log output from warn to error in applyExpressionMaxLength() on
exception since it will likely be considered a fatal condition.
2019-11-16 20:09:19 +03:30
Lukasz Lenart fdfeb3233a Uses the latest struts-master 2019-11-07 20:41:58 +01:00
Lukasz Lenart ae3ae2be76 [maven-release-plugin] prepare for next development iteration 2019-11-07 20:18:06 +01:00
Lukasz Lenart 8dface4fcb [maven-release-plugin] prepare release STRUTS_2_5_21 2019-11-07 20:17:01 +01:00
Lukasz Lenart 1348971d40 Merge pull request #378 from JCgH4164838Gh792C124B5/local_25x_CfgChg1
Minor follow-up changes to PR #371
2019-11-04 08:32:03 +01:00
JCgH4164838Gh792C124B5 dd6d206d78 Additional change
- added unit test (hoping to make coveralls happy).
2019-11-02 14:11:21 -04:00
JCgH4164838Gh792C124B5 e2b644a4fb Minor follow-up changes to PR #371
- added some additional exclusions in struts-default.xml.
- added log warning that specifies the value of maxLength involved if
  applyExpressionMaxLength(maxLength) fails.
- added null guards to two handleOgnlException() methods that could
  result in an NPE with #371 changes (a null OgnlException parameter
  was permissible previously, correct or not).
2019-11-02 13:31:09 -04:00
Lukasz Lenart 13cfba86f8 Merge pull request #371 from yasserzamani/WW-5041
WW-5041 Upgrade to OGNL 3.1.26 and adapt to its new features
2019-10-30 08:18:01 +01:00
Lukasz Lenart d84d59f53c Merge branch 'struts-2-5-x' into WW-5041 2019-10-30 07:50:01 +01:00
Lukasz Lenart 3651f55869 Merge pull request #376 from sepe81/update-jackson-to-210
WW-5042 Upgrade jackson-databind to version 2.10.0
2019-10-16 13:39:13 +02:00
Sebastian Peters 7ffa750c68 WW-5042 Upgrade jackson-databind to version 2.10.0
(cherry picked from commit 4556f404bd)
2019-10-15 18:40:33 +02:00
Lukasz Lenart 313876aa3c Merge pull request #372 from JCgH4164838Gh792C124B5/local_25x_LibUpd4
Update multiple Struts 2.5.x libraries to more recent versions.
2019-10-09 07:24:42 +02:00
JCgH4164838Gh792C124B5 9d7a9f81db Remove jackson-databind 2.9.9.x comment from pom.xml as requested by
S. Peters and L. Lenart.
2019-10-08 21:01:14 -04:00
JCgH4164838Gh792C124B5 fe98223724 Update multiple Struts 2.5.x libraries to more recent versions.
Relates to WW-5033 and PRs: #356, #362.  Updated libraries:

Spring Platform 4.3.24 -> 4.3.25
Log4j2 2.11.2 -> 2.12.1
Jackson 2.9.9 -> 2.9.10 (allows removal of jackson 2.9.9.3 "micro patch"
entry, taking care of pom.xml FIXME).
stax2-api 4.1 -> 4.2 (noted during Jackson update)
Fluido Skin 1.7 -> 1.8
SLF4J 1.7.26 -> 1.7.28
2019-10-06 18:29:57 -04:00
Yasser Zamani 1de94b2092 WW-5041 Upgrade to OGNL 3.1.26 and adapt to its new features 2019-10-01 14:57:46 +03:30
Lukasz Lenart 706bb560e4 Merge pull request #367 from JCgH4164838Gh792C124B5/local_25x_SendRedirectEnh
Minor improvement proposed for ServletRedirectResult sendRedirect()
2019-09-23 08:54:14 +02:00
Lukasz Lenart 12d4feaf8f Merge pull request #366 from JCgH4164838Gh792C124B5/local_25x_SendErrorEnh
Improved logging for DefaultDispatcherErrorHandler, DefaultStaticContentLoader
2019-09-23 08:54:02 +02:00
JCgH4164838Gh792C124B5 d88a8382d4 Changed the styling of log outputs (as suggested by A. Mashchenko and
L. Lenart).
Added comment to explain why the log output avoids a stacktrace (due to
exceptions being re-thrown).
Updated existing ServletRedirectResultTest to supply tests that exercise
the new code paths and demonstrate expected logging.
2019-09-22 21:45:44 -04:00
JCgH4164838Gh792C124B5 73809eae54 Changed the styling of log outputs (as suggested by A. Mashchenko).
Changed the log outputs to output full stacktraces (as suggested by
A. Mashchenko and L. Lenart).
Updated existing DefaultStaticContentLoaderTest and created a new
DefaultDispatcherErrorHandlerTest to supply tests that exercise the new
code paths and demonstrate expected logging.
2019-09-21 23:29:24 -04:00
JCgH4164838Gh792C124B5 5b4b554d11 Minor improvement proposed for ServletRedirectResult sendRedirect()
Supply log warning when an IOException or IllegalStateException occurs to
better allow developers to track the failed redirect location and status
details.  The exceptions are re-thrown to ensure existing flow-control
behaviour is preserved.

When getWriter() is called, utilize a finally block to ensure close is
called.
2019-09-17 22:22:41 -04:00
JCgH4164838Gh792C124B5 fcbd29b7f9 Changed the log outputs in this PR to utilize log4j2 {} notation (as per
suggestion by A. Mashchenko and L. Lenart)
Changed the log outputs in this PR from info level to warn level (as per
 suggestion by L. Lenart).
Note: The info level was originally chosen to make it easier to filter out
in the very unlikely case of log flood.
2019-09-17 21:10:34 -04:00
JCgH4164838Gh792C124B5 220896a0cf Improved logging for DefaultDispatcherErrorHandler and
DefaultStaticContentLoader.

Provide informational logging for the processing of the two dispatcher
classes when an http sendError fails for the two known failure types
(IOException, IllegalStateException).

In both circumstances it is beneficial to have the developer aware of the
failures via the logs.  These are not events that should be happening on a
regular basis, so there is little risk of a log flood.

DefaultStaticContentLoader didn't catch either exception type previously,
so changing it to make handling the same as DefaultDispatcherErrorHandler.

For DefaultDispatcherErrorHandler the IOException was caught with no
notice of failure previously.  Now there will be an info level log output.
Previously the IllegalStateException was not caught, which resulted in the
unrecoverable exception being thrown up to the calling thread, usually
resulting in an ugly stacktrace to stdout/stderr.  Now there will be an
info level log output instead.

If devMode is true, the info log outputs will include the exception
parameter to the log, so a stacktrace can be viewed for more details.  If
devMode is false (production mode), then only the exception's tostring()
output will be produced.
2019-09-15 20:48:15 -04:00
Lukasz Lenart 632f19eab3 WW-5038 Upgrades jackson-databind to version 2.9.9.3
plus upgrades jackson-core to 2.9.9

(cherry picked from commit 8187006)
2019-09-07 16:39:12 +04:30
Sebastian Haas 50a145152d Fix typo in MultiselectInterceptor javadoc
(cherry picked from commit dca0dd2)
2019-09-07 15:31:38 +04:30
JCgH4164838Gh792C124B5 f7b191f782 WW-5033 - Update to latest versions for some Struts 2.5.x dependencies: (#362)
* WW-5033 - Update to latests versions for some Struts 2.5.x dependencies:
- ASM 7 -> 7.1
- Spring 4.3.20.RELEASE -> 4.3.24.RELEASE

* fix Travis build
2019-09-07 14:33:34 +04:30
Yasser Zamani 4ae1a6a26d Merge pull request #361 from JCgH4164838Gh792C124B5/localS2_25x_OgnlCachecontrol
Proposed WW-5035 enhancement:
2019-09-07 14:32:03 +04:30
Lukasz Lenart 79e598f360 WW-5037 Upgrades commons-beanutils to version 1.9.4 2019-09-02 12:20:23 +02:00
JCgH4164838Gh792C124B5 9216e8e22c Proposed WW-5035 enhancement:
- Provide cache clearing methods for OgnlUtil (expression cache, BeanInfo
cache).
- Provide methods to check the cache sizes (entry number for expression
cache, BeanInfo cache).
- Provide static method to clear the OgnlRuntime cache (convenience
method).
2019-06-15 11:44:28 -04:00
Lukasz Lenart 651eac2c57 Merge pull request #358 from yasserzamani/WW-4999
fix logMissingProperties (WW-4999)
2019-06-03 08:25:32 +02:00
Yasser Zamani a50af87644 test false for logMissingProperties (WW-4999) 2019-06-02 17:22:28 +04:30
Yasser Zamani 9e01fbd2dd decouple logMissingProperties from devMode (WW-4999) 2019-06-01 12:52:22 +04:30
Yasser Zamani d4dd3386cc test not throw exception on top missing property (WW-4999)
instead continue to next objects in stack

Also tests not skip returned null values by user method
2019-06-01 09:37:19 +04:30
Yasser Zamani 0999fba8c4 not log user exceptions as missing properties (WW-4999)
Also reaks loop on user method exceptions - but continue to next objects in stack on NoSuchMethodException.
2019-05-31 17:57:25 +04:30
Yasser Zamani 3ac6835c5c fix logMissingProperties (WW-4999)
Moves checking OgnlValueStack.THROW_EXCEPTION_ON_FAILURE outside loop because it shouldn't throw exception on first failure while is trying all root objects.

Returns on first successful call because it's not rational and is confusing user to skip when user method successfully returns null as an actual result.

Fixes WW-4999 via honoring (devMode && logMissingProperties) for OgnlValueStack.THROW_EXCEPTION_ON_FAILURE and REPORT_ERRORS_ON_NO_PROP.
2019-05-30 16:36:54 +04:30
Yasser Zamani b0dd7c1c0d include ref in path as WW-5011 workaround (#353)
* include ref in path for StrutsApplicationResource as WW-5011 workaround

* add license to newly added xml files in previous commit

* WW-5011 include ref in path via .toURI().getPath()

* WW-5011 check protocol and not throw exception due to lazy file existence

* decrease log file size to pass travis build
2019-05-28 09:53:27 +04:30
Lukasz Lenart a63beef1f8 Merge pull request #355 from JCgH4164838Gh792C124B5/localS2_25x_TextProviderFix
Minor enhancement/fix to AbstractLocalizedTextProvider:
2019-05-27 09:45:50 +02:00
Aleksandr Mashchenko e74e5539dd Merge pull request #356 from JCgH4164838Gh792C124B5/local_25x_LibUpd3
Update Three Struts 2.5.x dependencies to latest versions
2019-05-26 20:16:49 +03:00
JCgH4164838Gh792C124B5 2226fcc168 Update Three Struts 2.5.x dependencies to latest versions:
- Jackson 2.9.8 -> 2.9.9
- Log4j2 2.11.1 -> 2.11.2
- OGNL 3.1.22 -> 3.1.23
Struts 2.5.21-SNAPSHOT builds successfully with these versions.
2019-05-25 17:09:33 -04:00
JCgH4164838Gh792C124B5 865b8a20df Update PR with unit test:
- Add a unit test to include test coverage and confirm no failures
in the new methods.
2019-05-11 16:28:34 -04:00
JCgH4164838Gh792C124B5 3c6956116e Minor enhancement/fix to AbstractLocalizedTextProvider:
- Made "constant" RELOADED static to save an initialization every time.
- Updated clearBundle(final String bundleName) method comment as it
  seemed inaccurate, added debug log output when called.
- Introduced protected clearBundle(final String bundleName, Locale locale)
  method for use by descendants, with debug log output when called.
- Introduced protected clearMissingBundlesCache() method for use by
  descendants, with debug log when called.
2019-05-11 13:19:35 -04:00
Lukasz Lenart bb9ce7582b Merge pull request #354 from JCgH4164838Gh792C124B5/localS2_25x_B10
Minor consistency update correction for WW-5029 fix to the 2.5.x branch
2019-04-29 07:42:13 +02:00
JCgH4164838Gh792C124B5 11d373f8b4 Minor consistency update correction for WW-5029 fix to the 2.5.x branch:
- Correct missing verification in buildAllowedMethods()/loadGlobalAllowedMethods() that the nodes are
  of type Node.TEXT_NODE (as buildResults() does).
- Made two class fields final, as suggested by IDE.
2019-04-27 12:35:40 -04:00
Lukasz Lenart b23bfd42d2 Merge pull request #350 from yasserzamani/WW-4958
fix multipart request RegEx (relates to WW-4958)
2019-04-23 08:25:40 +02:00
Yasser Zamani f94b681050 fix multipart request RegEx
Note: Unlike some similar constructs in other header fields, media
type parameters do not allow whitespace (even "bad" whitespace)
around the "=" character.

Reference: https://tools.ietf.org/html/rfc7231#section-3.1.1.1
See also: WW-4958
2019-04-23 09:32:43 +04:30
JCgH4164838Gh792C124B5 fb38a919c9 Proposed fix for WW-5029 for the 2.5.x branch (#347)
* Proposed fix for WW-5029 for the 2.5.x branch:
- NOTE: If the PR is accepted please credit Maxime Clement for this change as they found
        the issue, identified the probable cause/related details and opened the JIRA.
- Updated XWorkConfigurationProvider buildAllowedMethods(), loadGlobalAllowedMethods() so that
  they now handle situations when a SAX parser produces multiple elements to represent the tag
  body value.
- No changes to unit tests.

* Update commit to fix weakness identified by Maxime Clement:
- Implementation should now properly concatenate the node children values together (as a single unified string)
  in both buildAllowedMethods(), loadGlobalAllowedMethods() - before generating the method Set to be added.
- Made some eligible variables final.

* Update commit to provide new unit tests:
- Added unit tests to confirm the fixes for buildAllowedMethods(), loadGlobalAllowedMethods()
- Added Mock DOM classes sufficient for these tests.
- Added unit tests to cover buildResults() and loadGlobalResults().
2019-04-20 09:54:36 +04:30
Yasser Zamani e25c826167 Merge pull request #349 from JCgH4164838Gh792C124B5/localS2_25x_B9
Proposed fix for WW-5028 for the 2.5.x branch:
2019-04-20 08:58:07 +04:30
JCgH4164838Gh792C124B5 4815744eaf (Amended commit based on feedback)
Proposed fix for WW-5028 for the 2.5.x branch:
- Disable printing stacktrace on exceptions by the Dispatcher by default.
- Printing stacktrace on exception is only enabled with devMode set to true, as suggested by L. Lenart.
- Now prints stacktrace on exception using LOG, as suggested by A. Mashchenko and the the JIRA reporter.
  Log level set to debug as recommended by Y. Zamani.
- Added two additional unit tests for Dispatcher devMode and handleException states.
2019-04-16 22:26:46 -04:00
Yasser Zamani f5a7776854 Merge pull request #344 from lukaszlenart/WW-4958
[WW-4958] Uses less restrictive RegEx to check if it's a multipart request
2019-04-14 14:06:35 +04:30
Lukasz Lenart f45d2752bb WW-4958 Uses less restrictive Regex to check if it's a multipart request 2019-03-30 09:23:50 +01:00
JCgH4164838Gh792C124B5 0262574095 Proposed fix for WW-5024 in the 2.5.x branch: (#343)
- NOTE: If the PR is accepted please credit Robert Hollencamp (Github @rhollencamp) for this change
        as he found the issue, proposed a solution for 2.6 (master), and opened the JIRA.
- Updated HttpParameters, ActionMappingParametersInterceptor to prevent multi-level Parameter wrapping from occuring.
- Added a new ActionMappingParametersInterceptorTest to verify the fix.
2019-03-29 07:20:56 +01:00
Aleksandr Mashchenko 30cb56a414 Merge pull request #342 from JCgH4164838Gh792C124B5/localS2_25x_B5
WW-5026 TokenSessionStoreInterceptor double-submit failure
2019-03-26 22:55:42 +02:00
JCgH4164838Gh792C124B5 63dc85fd7a Updated commit with changes suggested by reviewers:
- Replace TokenSessionStoreInterceptor inline comment previously added with method comment blocks (better locatioh for explanation)
- Eliminate duplicate savedActionContext.setValueStack call in InvocationSessionStore (typo)
- Improve InvocationSessionStore.loadInvocation() by reording assignment statements to allow single-line assignments
2019-03-25 23:36:07 -04:00
JCgH4164838Gh792C124B5 5b0ec3400d Fix issue introduced with earlier WW-4873 fix:
- Fixes error 500 processing failures for double-submit results with TokenSessionStoreInterceptor processing
- Fix to InvocationSessionStore, new unit test confirming fix in InvocationSessionStoreTest
- Minor whitespace fix to TokenSessionStoreInterceptor
2019-03-25 01:00:10 -04:00
Yasser Zamani d460d71498 Merge pull request #341 from JCgH4164838Gh792C124B5/localS2_25x_Testfix
Backport OgnlValueStackTest test fix and unit test additions from master
2019-03-18 09:55:17 +03:30
JCgH4164838Gh792C124B5 53f64cdecf Backport applicable OgnlValueStackTest test fix and unit test additions from 2.6:
- This backport resulted from a review inspired/suggested by Y. Zamani in discussions for PR#334.
- Backports fix of error in testNullMethod().
- Backports applicable static access tests (static method access only), cleanup of unused imports.
- As with 2.6, it uses Y. Zamani's improved/enhanced reload mechanism.
2019-03-16 17:50:18 -04:00
Lukasz Lenart aff4d46835 Merge pull request #336 from JCgH4164838Gh792C124B5/local_25x_LibUpd2
Upgrade SLF4J to 1.7.26 (WW-5023)
2019-02-25 08:40:42 +01:00
Yasser Zamani a15c12a051 add properties support to XWorkTestCase.loadButAdd
also includes cleanups for PRs #292 and #320
2019-02-24 17:53:45 +03:30
JCgH4164838Gh792C124B5 e62155c460 Upgrade SLF4J to 1.7.26 (WW-5023) 2019-02-21 12:25:23 -05:00
Lukasz Lenart f7f4fbd47f Merge pull request #333 from JCgH4164838Gh792C124B5/localS2_25x_Appfix
Minor config fixes for the Showcase Application in 2.5.x:
2019-02-12 09:33:18 +01:00
JCgH4164838Gh792C124B5 2d81439553 Minor config fixes for the Showcase Application in 2.5.x:
1) Token examples. Examples 2 and 3 previously resulted in 403's upon submit (config issue).
2) Token examples. Example 4 resulted in error 500 when selected from the menu (FTL param type issue).
3) Validation examples.  Examples quizBasic, quizClient and quizClientCss resulted in 404's when selected from menu (config issue).
4) File upload examples.  Multiple file upload missing result page (list and array), added missing JSP.  Added missing input results in configuration.
5) Add manual test for public constant access via expression (to If tag JSP).
Similar to PR#255 for 2.6.x.
2019-02-11 19:37:11 -05:00
Lukasz Lenart 7afe35cb96 Adds a Jenkinsfile to allow build this branch as well 2019-02-11 09:32:49 +01:00
Yasser Zamani fdd1054070 Merge pull request #328 from aleksandr-m/feature/WW-5009
WW-5009 EmptyStackException in JSON plugin due to concurrency
2019-02-05 14:37:57 +03:30
Aleksandr Mashchenko 32e88d1a2e Merge pull request #322 from aleksandr-m/feature/WW-4991
WW-4991 Not existing property in listValueKey throws exception
2019-02-04 21:52:26 +02:00
Lukasz Lenart 6403de4516 Merge pull request #315 from yasserzamani/WW-5005
WW-5005 upgrade to ASM 7
2019-02-04 10:57:33 +01:00
Yasser Zamani 13c517fc3c Merge branch 'struts-2-5-x' into WW-5005 2019-02-04 12:47:23 +03:30
Aleksandr Mashchenko 7242a87165 WW-5009 Fix tests 2019-02-03 12:58:43 +02:00
Aleksandr Mashchenko 0323795d67 WW-5009 EmptyStackException in JSON plugin due to concurrency 2019-02-03 12:41:18 +02:00
Aleksandr Mashchenko 71267a9b4b Revert some changes to be more consistent with 2.6 version 2019-01-31 17:32:36 +02:00
JCgH4164838Gh792C124B5 5524c579d2 Fix for NPE issue discovered in WW-5004. (#316)
* Fix for NPE issue discovered in WW-5004.
- Guard fix for a NPE that can arise under certain conditions, identified by A. Mashchenko.

* Fix for NPE issue discovered in WW-5004 (amended commit).
- Guard fix for a NPE that can arise under certain conditions, identified by A. Mashchenko.
- Requires the following elements to implement a fuller fix:
  - Back-port relevant guard logic in ProxyUtil from master into 2.5.x to deal with the NPE.
  - Update SecurityMemberAccess to block access to static fields.
  - Upgrade to OGNL 3.1.22 (re-enables access to public static fields w/out access checks).
  - Add unit test to confirm proper functionality of the fix.
  - Correct missing entry in 4 test configuration XML files (needed for new unit test).
- Replaced literal injection parameter name for setStaticFieldAccessLevel in OgnlValueStackFactory with the appropriate constant.
  Note: Even though a constant was defined in StrutsConstants, the value for the injection name in all places is the XWorkConstants.
        It has to remain the same to avoid breaking anything.
2019-01-31 18:01:41 +03:30
Aleksandr Mashchenko 873ca8fa20 WW-4991 Not existing property in listValueKey throws exception 2019-01-30 23:10:06 +02:00
Yasser Zamani 8988d57644 Merge pull request #318 from lukaszlenart/WW-5007-jackson-ugrade-s25
[WW-5007] Upgrades Jackson libraries to version 2.9.8
2019-01-25 15:23:18 +03:30
Lukasz Lenart 2e7cf63964 WW-5007 Upgrades Jackson libraries to version 2.9.8 2019-01-25 12:29:48 +01:00
Yasser Zamani 3eb68be674 upgrade to ASM 7
fixes WW-5005
2019-01-23 16:24:40 +03:30
Yasser Zamani c9f279ec2e Merge pull request #314 from JCgH4164838Gh792C124B5/localS2_25x_B2
Minor cleanup/consistency changes for 3 modules.
2019-01-23 11:51:58 +03:30
JCgH4164838Gh792C124B5 881e1b2580 Minor cleanup/consistency changes for 3 modules.
- Made a private ConcurrentMap reference final, made initial sets immutable (consistency).
- Made sets for Accepted and Excluded patterns checkers immutable in 2 modules (consistency).
- Added @Override annotations missing from a few methods in 2 modules.
- Updated the 3 relevant unit tests to verify immutable states of various sets.
2019-01-18 00:09:29 -05:00
Lukasz Lenart cb0ac7c440 [maven-release-plugin] prepare for next development iteration 2019-01-09 09:00:04 +01:00
227 changed files with 8611 additions and 1570 deletions
+4 -3
View File
@@ -1,3 +1,4 @@
dist: trusty
language: java
sudo: false
@@ -8,12 +9,12 @@ jdk:
- oraclejdk11
install: true
script: mvn test -DskipAssembly
script: mvn test -DskipAssembly -B
after_success:
# TODO delete following if statement after fix of https://github.com/cobertura/cobertura/issues/271
- if [ "$TRAVIS_JDK_VERSION" == "openjdk8" ] || [ "$TRAVIS_JDK_VERSION" == "oraclejdk8" ]; then
mvn cobertura:cobertura org.eluder.coveralls:coveralls-maven-plugin:report com.updateimpact:updateimpact-maven-plugin:submit -Ptravis-coveralls,update-impact -DskipAssembly;
mvn cobertura:cobertura org.eluder.coveralls:coveralls-maven-plugin:report com.updateimpact:updateimpact-maven-plugin:submit -Ptravis-coveralls,update-impact -DskipAssembly -B;
else
echo "Not reporting coverage for $TRAVIS_JDK_VERSION due to incompatibility or to save performance";
fi;
@@ -25,4 +26,4 @@ env:
cache:
directories:
- $HOME/.m2
Vendored
+29
View File
@@ -0,0 +1,29 @@
#!groovy
pipeline {
agent {
label 'ubuntu'
}
options {
buildDiscarder logRotator(daysToKeepStr: '14', numToKeepStr: '10')
timeout(80)
disableConcurrentBuilds()
}
tools {
jdk 'jdk_1.7_latest'
maven 'maven_3_latest'
}
triggers {
pollSCM 'H/15 * * * *'
}
environment {
MAVEN_OPTS = '-Xmx1024m -XX:MaxPermSize=256m'
}
stages {
stage('Build') {
steps {
sh 'mvn --version'
sh 'mvn clean source:jar javadoc:jar install deploy -DskipWiki -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2'
}
}
}
}
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.5.20</version>
<version>2.5.27</version>
</parent>
<artifactId>struts2-apps</artifactId>
<packaging>pom</packaging>
+2 -2
View File
@@ -24,12 +24,12 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-apps</artifactId>
<version>2.5.20</version>
<version>2.5.27</version>
</parent>
<artifactId>struts2-rest-showcase</artifactId>
<packaging>war</packaging>
<version>2.5.20</version>
<version>2.5.27</version>
<name>Struts 2 Rest Showcase Webapp</name>
<description>Struts 2 Rest Showcase Example</description>
+2 -2
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-apps</artifactId>
<version>2.5.20</version>
<version>2.5.27</version>
</parent>
<artifactId>struts2-showcase</artifactId>
@@ -167,7 +167,7 @@
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.3.Final</version>
<version>5.4.3.Final</version>
</dependency>
<!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
@@ -84,4 +84,12 @@ public class FileUploadAction extends ActionSupport {
public void setCaption(String caption) {
this.caption = caption;
}
public long getUploadSize() {
if (upload != null) {
return upload.length();
} else {
return 0;
}
}
}
@@ -26,7 +26,7 @@
<validators>
<field name="upload">
<field-validator type="fieldexpression">
<param name="expression"><![CDATA[upload.length() > 0]]></param>
<param name="expression"><![CDATA[getUploadSize() > 0]]></param>
<message>File cannot be empty</message>
</field-validator>
</field>
@@ -40,6 +40,7 @@
</action>
<action name="doMultipleUploadUsingList" class="org.apache.struts2.showcase.fileupload.MultipleFileUploadUsingListAction" method="upload">
<result name="input">/WEB-INF/fileupload/multipleUploadUsingList.jsp</result>
<result>/WEB-INF/fileupload/multiple-success.jsp</result>
</action>
@@ -49,6 +50,7 @@
</action>
<action name="doMultipleUploadUsingArray" class="org.apache.struts2.showcase.fileupload.MultipleFileUploadUsingArrayAction" method="upload">
<result name="input">/WEB-INF/fileupload/multipleUploadUsingArray.jsp</result>
<result>/WEB-INF/fileupload/multiple-success.jsp</result>
</action>
@@ -48,7 +48,7 @@
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="token"/>
<result name="invalid.token">/WEB-INF/token/doublePost.jsp</result>
<result name="success" type="redirect">/WEB-INF/token/transferDone.jsp</result>
<result name="success">/WEB-INF/token/transferDone.jsp</result>
</action>
@@ -62,7 +62,7 @@
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="tokenSession"/>
<result name="invalid.token">/WEB-INF/token/doublePost.jsp</result>
<result name="success" type="redirect">/WEB-INF/token/transferDone.jsp</result>
<result name="success">/WEB-INF/token/transferDone.jsp</result>
</action>
@@ -34,28 +34,28 @@
<package name="validation" extends="json-default" namespace="/validation">
<action name="index">
<result>/WEB-INF/validation/index.jsp</result>
<result>index.jsp</result>
</action>
<action name="quizBasic" class="org.apache.struts2.showcase.validation.QuizAction">
<result name="input">quiz-basic.jsp</result>
<result>quiz-success.jsp</result>
<result name="input">/WEB-INF/validation/quiz-basic.jsp</result>
<result>/WEB-INF/validation/quiz-success.jsp</result>
</action>
<action name="quizClient" class="org.apache.struts2.showcase.validation.QuizAction">
<result name="input">quiz-client.jsp</result>
<result>quiz-success.jsp</result>
<result name="input">/WEB-INF/validation/quiz-client.jsp</result>
<result>/WEB-INF/validation/quiz-success.jsp</result>
</action>
<action name="quizClientCss" class="org.apache.struts2.showcase.validation.QuizAction">
<result name="input">quiz-client-css.jsp</result>
<result>quiz-success.jsp</result>
<result name="input">/WEB-INF/validation/quiz-client-css.jsp</result>
<result>/WEB-INF/validation/quiz-success.jsp</result>
</action>
<action name="quizAjax" class="org.apache.struts2.showcase.validation.QuizAction">
<interceptor-ref name="jsonValidationWorkflowStack"/>
<result name="input">quiz-ajax.jsp</result>
<result>quiz-success.jsp</result>
<result name="input">/WEB-INF/validation/quiz-ajax.jsp</result>
<result>/WEB-INF/validation/quiz-success.jsp</result>
</action>
<!-- =========================================== -->
@@ -22,12 +22,12 @@ ${parameters.after!}<#t/>
</td><#lt/>
</tr>
<#if (parameters.errorposition!"top") == 'bottom'>
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/>
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors.get(parameters.name)??/>
<#if hasFieldErrors>
<tr errorFor="${parameters.id}">
<td class="tdErrorMessage" colspan="2"><#rt/>
<#if hasFieldErrors>
<#list fieldErrors[parameters.name] as error>
<#list fieldErrors.get(parameters.name) as error>
<div class="errorMessage">${error?html}</div><#t/>
</#list>
</#if>
@@ -21,29 +21,29 @@
<#--
Always include elements to show errors. They may be filled later via AJAX.
-->
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/>
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors.get(parameters.name)??/>
<#if (parameters.errorposition!"top") == 'top'>
<tr errorFor="${parameters.id}">
<td class="tdErrorMessage" colspan="2" data-error-for-fieldname="${parameters.name}"><#rt/>
<#if hasFieldErrors>
<#list fieldErrors[parameters.name] as error>
<#list fieldErrors.get(parameters.name) as error>
<div class="errorMessage">${error?html}</div><#t/>
</#list>
</#if>
</td><#lt/>
</tr>
</#if>
<#if !parameters.labelposition?? && (parameters.form.labelposition)??>
<#assign labelpos = parameters.form.labelposition/>
<#elseif parameters.labelposition??>
<#assign labelpos = parameters.labelposition/>
<#if !parameters.labelPosition?? && (parameters.form.labelPosition)??>
<#assign labelPos = parameters.form.labelPosition/>
<#elseif parameters.labelPosition??>
<#assign labelpos = parameters.labelPosition/>
</#if>
<#--
if the label position is top,
then give the label it's own row in the table
-->
<tr>
<#if (labelpos!"") == 'top'>
<#if (labelPos!"") == 'top'>
<td class="tdLabelTop" colspan="2"><#rt/>
<#else>
<td class="tdLabel"><#rt/>
@@ -72,7 +72,7 @@ ${parameters.labelseparator!":"?html}<#t/>
</#if>
</td><#lt/>
<#-- add the extra row -->
<#if (labelpos!"") == 'top'>
<#if (labelPos!"") == 'top'>
</tr>
<tr>
</#if>
@@ -0,0 +1,65 @@
<!--
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
-->
<%@ page
language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Struts2 Showcase - Fileupload sample - Multiple fileupload</title>
</head>
<body>
<div class="page-header">
<h1>Fileupload sample - Multiple fileupload</h1>
</div>
<div class="container-fluid">
<s:iterator var="counter" begin="1" end="3">
<!-- Mechanism for display to work with upload both as an array and list in a single JSP (a bit ugly).
Note: Output "index" doesn't always match if the input is "sparse". -->
<s:if test="%{#counter <= upload.length}">
<s:set var="displayContent" value="true" />
</s:if>
<s:elseif test="%{#counter <= upload.size}">
<s:set var="displayContent" value="true" />
</s:elseif>
<s:else>
<s:set var="displayContent" value="false" />
</s:else>
<s:if test="%{#displayContent == true}">
<div class="row">
<div class="col-md-12">
<b>File (<s:property value="#counter" />):</b>
<ul>
<li>ContentType: <s:property value="uploadContentType[#counter - 1]" /></li>
<li>FileName: <s:property value="uploadFileName[#counter -1]" /></li>
<li>File: <s:property value="upload[#counter - 1]" /></li>
</ul>
</div>
</div>
</s:if>
</s:iterator>
</div>
</body>
</html>
@@ -39,7 +39,7 @@
<div class="hero-unit">
<h1>Welcome!</h1>
<p>The Struts Showcase demonstrates a variety of use cases and tag usages. Essentially, the application exercises various framework features in isolation. The Showcase is not meant as a "best practices" example.</p>
<p>For more "by example" solutions, see the <a class="btn btn-primary btn-large">Struts Cookbook &raquo;</a> pages.</p>
<p>For more "by example" solutions, see the <a href="https://github.com/apache/struts-examples" class="btn btn-primary btn-large">Struts Examples &raquo;</a> pages.</p>
</div>
</div>
@@ -18,6 +18,7 @@
* under the License.
*/
-->
<%@page import="org.apache.struts2.showcase.hangman.HangmanConstants" %>
<%@taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
@@ -635,5 +636,18 @@
</div>
</div>
</div>
<br>
<br>
<p>
A secondary test for this JSP visually verifies expression access to a public constant.
A direct access to the same public constant via scriptlet provides secondary verification.
</p>
<br>
<div>
Test public static (constant) access (expression). Value: <s:property default="unavailable" value="@org.apache.struts2.showcase.hangman.HangmanConstants@HANGMAN_SESSION_KEY" />
</div>
<div>
Test public static (constant) access (scriptlet). Value: <%=org.apache.struts2.showcase.hangman.HangmanConstants.HANGMAN_SESSION_KEY%>
</div>
</body>
</html>
@@ -50,7 +50,7 @@
<@s.form action="transfer4">
<@s.token/>
<@s.textfield label="Amount" name="amount" required="true" value="400"/>
<@s.textfield label="Amount" name="amount" required=true value="400"/>
<@s.submit value="Transfer money" cssClass="btn btn-primary"/>
</@s.form>
</div>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.5.20</version>
<version>2.5.27</version>
</parent>
<artifactId>struts2-assembly</artifactId>
+6 -3
View File
@@ -30,7 +30,7 @@
</parent>
<artifactId>struts2-bom</artifactId>
<version>2.5.20</version>
<version>2.5.27</version>
<packaging>pom</packaging>
<name>Struts 2 Bill of Materials</name>
@@ -45,7 +45,7 @@
</licenses>
<properties>
<struts-version.version>2.5.20</struts-version.version>
<struts-version.version>2.5.27</struts-version.version>
<maven.site.skip>true</maven.site.skip>
<maven.site.deploy.skip>true</maven.site.deploy.skip>
</properties>
@@ -181,6 +181,9 @@
</dependencyManagement>
<scm>
<tag>STRUTS_2_5_20</tag>
<tag>STRUTS_2_5_27</tag>
<connection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</connection>
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</developerConnection>
<url>https://github.com/apache/struts/</url>
</scm>
</project>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-osgi-bundles</artifactId>
<version>2.5.20</version>
<version>2.5.27</version>
</parent>
<artifactId>struts2-osgi-admin-bundle</artifactId>
@@ -60,6 +60,9 @@ public class BundlesAction extends ActionSupport implements ServletContextAware
}
public String start() throws BundleException {
clearErrorsAndMessages();
addActionMessage("Start - OSGi Host: " + osgiHost + ", ID: " + id);
Bundle bundle = osgiHost.getBundles().get(id);
try {
bundle.start();
@@ -69,29 +72,35 @@ public class BundlesAction extends ActionSupport implements ServletContextAware
//there no easy way/elegant way to know if the bundle was processed already
Thread.sleep(1000);
} catch (Exception e) {
addActionError(e.toString());
addActionError("Exception: " + e.toString() + " (" + e.getMessage() + ")");
}
return view();
}
public String stop() throws BundleException {
clearErrorsAndMessages();
addActionMessage("Stop - OSGi Host: " + osgiHost + ", ID: " + id);
Bundle bundle = osgiHost.getBundles().get(id);
try {
bundle.stop();
} catch (Exception e) {
addActionError(e.toString());
addActionError("Exception: " + e.toString() + " (" + e.getMessage() + ")");
}
return view();
}
public String update() throws BundleException {
clearErrorsAndMessages();
addActionMessage("Update - OSGi Host: " + osgiHost + ", ID: " + id);
Bundle bundle = osgiHost.getBundles().get(id);
try {
bundle.update();
} catch (Exception e) {
addActionError(e.toString());
addActionError("Exception: " + e.toString() + " (" + e.getMessage() + ")");
}
return view();
@@ -114,13 +123,14 @@ public class BundlesAction extends ActionSupport implements ServletContextAware
}
public List<PackageConfig> getPackages() {
List<PackageConfig> pkgs = new ArrayList<PackageConfig>();
List<PackageConfig> pkgs = new ArrayList<>();
Bundle bundle = getBundle();
if (bundle.getState() == Bundle.ACTIVE) {
for (String name : bundleAccessor.getPackagesByBundle(bundle)) {
PackageConfig packageConfig = configuration.getPackageConfig(name);
if (packageConfig != null)
if (packageConfig != null) {
pkgs.add(packageConfig);
}
}
}
return pkgs;
@@ -133,13 +143,14 @@ public class BundlesAction extends ActionSupport implements ServletContextAware
public Collection<Bundle> getBundles() {
List<Bundle> bundles = new ArrayList(osgiHost.getBundles().values());
Collections.sort(bundles, new Comparator<Bundle>() {
@Override
public int compare(Bundle bundle1, Bundle bundle2) {
boolean bundle1StrutsEnabled = isStrutsEnabled(bundle1);
boolean bundle2StrutsEnabled = isStrutsEnabled(bundle2);
if ((bundle1StrutsEnabled && bundle2StrutsEnabled) || (!bundle1StrutsEnabled && !bundle2StrutsEnabled))
if ((bundle1StrutsEnabled && bundle2StrutsEnabled) || (!bundle1StrutsEnabled && !bundle2StrutsEnabled)) {
return bundle1.getSymbolicName().compareTo(bundle2.getSymbolicName());
else {
} else {
return bundle1StrutsEnabled ? -1 : 1;
}
}
@@ -172,7 +183,7 @@ public class BundlesAction extends ActionSupport implements ServletContextAware
try {
state = bundle.getState();
} catch (Exception e) {
addActionError("Unable to determine bundle state: " + e.getMessage());
addActionError("Unable to determine bundle state. Exception: " + e.toString() + " (" + e.getMessage() + ")");
return false;
}
@@ -181,8 +192,7 @@ public class BundlesAction extends ActionSupport implements ServletContextAware
} else if ("stop".equals(val)) {
return state == Bundle.ACTIVE;
} else if ("update".equals(val)) {
return state == Bundle.ACTIVE || state == Bundle.INSTALLED
|| state == Bundle.RESOLVED;
return state == Bundle.ACTIVE || state == Bundle.INSTALLED || state == Bundle.RESOLVED;
}
throw new IllegalArgumentException("Invalid state");
}
@@ -197,6 +207,7 @@ public class BundlesAction extends ActionSupport implements ServletContextAware
this.bundleAccessor = bundleAccessor;
}
@Override
public void setServletContext(ServletContext servletContext) {
osgiHost = (OsgiHost) servletContext.getAttribute(StrutsOsgiListener.OSGI_HOST);
}
@@ -24,20 +24,29 @@ package org.apache.struts2.osgi.admin.actions;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import org.apache.struts2.osgi.DefaultBundleAccessor;
import org.apache.felix.shell.ShellService;
import org.apache.struts2.osgi.DefaultBundleAccessor;
import org.apache.struts2.osgi.interceptor.BundleContextAware;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionSupport;
/**
* This action executes commands on the Felix Shell
* This action executes commands on the Felix Shell.
*
* The action is BundleContextAware so that if the OSGi interceptor is used the BundleContext
* can be provided for configurations where the DefaultBundleAccessor is insufficient.
*
*/
public class ShellAction extends ActionSupport {
public class ShellAction extends ActionSupport implements BundleContextAware {
private String command;
private String output;
private BundleContext bundleContext;
@Override
public String execute() {
// get service
ByteArrayOutputStream outByteStream = new ByteArrayOutputStream();
@@ -52,7 +61,9 @@ public class ShellAction extends ActionSupport {
outString = outByteStream.toString().trim();
errString = errByteStream.toString().trim();
} catch (Exception e) {
errString = e.getMessage();
outString = outByteStream.toString().trim();
errString = "Exception: " + e.toString() + " (" + e.getMessage() + "). Output:" + outString +
". Error: " + errByteStream.toString().trim(); // Full details for troubleshooting.
} finally {
outStream.close();
errStream.close();
@@ -75,17 +86,58 @@ public class ShellAction extends ActionSupport {
}
public void executeCommand(String commandLine, PrintStream out, PrintStream err) throws Exception {
ShellService shellService = getShellService();
if (shellService != null)
ShellService shellService = getShellService(out);
if (shellService != null) {
out.println("Attempting to execute command: " + commandLine);
shellService.executeCommand(commandLine, out, err);
}
else
err.println("Apache Felix Shell service is not installed");
}
private ShellService getShellService() {
private ShellService getShellService(PrintStream out) {
//bundle can be de-activated, so keeping a reference aorund is not a good idea
DefaultBundleAccessor bundleAcessor = DefaultBundleAccessor.getInstance();
ServiceReference ref = bundleAcessor.getServiceReference(ShellService.class.getName());
return (ShellService) bundleAcessor.getService(ref);
final DefaultBundleAccessor bundleAccessor = DefaultBundleAccessor.getInstance();
ServiceReference ref = (bundleAccessor != null ? bundleAccessor.getServiceReference(ShellService.class.getName()) : null);
//out.println("DefaultBundleAccessor: " + bundleAcessor + ", ServiceReference [" + ShellService.class.getName() + "]: " + ref); // No logger, for debugging only.
if (ref == null && this.bundleContext != null) {
// Depending on OSGi and Felix bundle configurations, the DefaultBundleAccessor may not be able to locate the ShellService.
// In such cases, use the bundleContext (if available) to locate the ShellService in a "brute-force" manner.
final Bundle[] bundles = this.bundleContext.getBundles();
if (bundles != null && bundles.length > 0) {
for (Bundle currentBundle : bundles) {
if (currentBundle != null) {
//out.println("Bundle [" + index + "], SymbolicName: " + currentBundle.getSymbolicName() + ", Location: " + currentBundle.getLocation() + ", BundleID: " + currentBundle.getBundleId()); // No logger, for debugging only.
if (currentBundle.getSymbolicName().startsWith("org.apache.felix.shell")) {
BundleContext currentBundleContext = currentBundle.getBundleContext();
Object directShellServiceByClass = (currentBundleContext != null ? currentBundleContext.getServiceReference(org.apache.felix.shell.ShellService.class) : null);
Object directShellServiceByName = (currentBundleContext != null ? currentBundleContext.getServiceReference("org.apache.felix.shell.ShellService") : null);
//out.println(" ShellService reference (via bundle's context) by class: " + directShellServiceByClass); // No logger, for debugging only.
//out.println(" ShellService reference (via bundle's context) by name: " + directShellServiceByName); // No logger, for debugging only.
if (ref == null) {
ref = (directShellServiceByClass != null ? (ServiceReference) directShellServiceByClass : (ServiceReference) directShellServiceByName);
}
}
} else {
//out.println("Bundle [" + index + "] is null"); // No logger, for debugging only.
}
}
} else {
//out.println("OSGi Interceptor-provided BundleContext bundle array is null or empty"); // No logger, for debugging only.
}
}
if (ref == null) {
out.println("ShellService reference cannot be found (null), service lookup will fail.");
}
return (ShellService) (bundleAccessor != null ? bundleAccessor.getService(ref) : null);
}
@Override
public void setBundleContext(BundleContext bundleContext) {
//System.out.println("ShellAction - setBundleContext called. BundleContext: " + bundleContext); // No logger, for debugging only.
this.bundleContext = bundleContext;
}
}
@@ -1,9 +1,13 @@
Copyright (c) 2009 Paul Bakaus, http://jqueryui.com/
Copyright jQuery Foundation and other contributors, https://jquery.org/
This software consists of voluntary contributions made by many
individuals (AUTHORS.txt, http://jqueryui.com/about) For exact
contribution history, see the revision history and logs, available
at http://jquery-ui.googlecode.com/svn/
individuals. For exact contribution history, see the revision history
available at https://github.com/jquery/jquery-ui
The following license applies to all parts of this software except as
documented below:
====
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@@ -23,3 +27,17 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
====
Copyright and related rights for sample code are waived via CC0. Sample
code is defined as all source code contained within the demos directory.
CC0: http://creativecommons.org/publicdomain/zero/1.0/
====
All files located in the node_modules and external directories are
externally maintained libraries used by this software which have their
own licenses; we recommend you read them, as their terms may differ from
the terms above.
+3 -2
View File
@@ -2,7 +2,8 @@ Apache Struts
Copyright 2000-2011 The Apache Software Foundation
This product includes software developed by
The Apache Software Foundation (http://www.apache.org/).
The Apache Software Foundation (https://www.apache.org/).
The binary distributions includes the following third party software:
JQuery (http://jquery.com/).
jQuery (https://jquery.com/).
jQuery UI (https://jqueryui.com/).
@@ -24,11 +24,11 @@
<link rel="stylesheet" type="text/css" href="<@s.url value="/static/css/shell.css" />" />
<link rel="stylesheet" type="text/css" href="<@s.url value="/static/css/main.css" />" />
<link rel="stylesheet" type="text/css" href="<@s.url value="/static/css/redmond/jquery-ui-1.7.1.custom.css" />" />
<link rel="stylesheet" type="text/css" href="<@s.url value="/static/css/redmond/jquery-ui-1.12.1.redmond.css" />" />
<script src="<@s.url value="/static/js/shell.js" />"></script>
<script src="<@s.url value="/static/js/jquery-1.3.2.min.js" />"></script>
<script src="<@s.url value="/static/js/jquery-ui-1.7.1.custom.min.js" />"></script>
<script src="<@s.url value="/static/js/jquery-1.12.4.min.js" />"></script>
<script src="<@s.url value="/static/js/jquery-ui-1.12.1.min.js" />"></script>
</head>
<body>
<div class="menu">
@@ -23,10 +23,10 @@
<title>${bundle.symbolicName!}</title>
<link rel="stylesheet" type="text/css" href="<@s.url value="/static/css/main.css" />" />
<link rel="stylesheet" type="text/css" href="<@s.url value="/static/css/redmond/jquery-ui-1.7.1.custom.css" />" />
<link rel="stylesheet" type="text/css" href="<@s.url value="/static/css/redmond/jquery-ui-1.12.1.redmond.css" />" />
<script src="<@s.url value="/static/js/jquery-1.3.2.min.js" />"></script>
<script src="<@s.url value="/static/js/jquery-ui-1.7.1.custom.min.js" />"></script>
<script src="<@s.url value="/static/js/jquery-1.12.4.min.js" />"></script>
<script src="<@s.url value="/static/js/jquery-ui-1.12.1.min.js" />"></script>
<script type="text/javascript">
$(function() {
@@ -163,5 +163,8 @@
</table>
</div>
</div>
<@s.actionmessage />
</body>
</html>
@@ -23,10 +23,10 @@
<title>OSGi Bundles</title>
<link rel="stylesheet" type="text/css" href="<@s.url value="/static/css/main.css" />" />
<link rel="stylesheet" type="text/css" href="<@s.url value="/static/css/redmond/jquery-ui-1.7.1.custom.css" />" />
<link rel="stylesheet" type="text/css" href="<@s.url value="/static/css/redmond/jquery-ui-1.12.1.redmond.css" />" />
<script src="<@s.url value="/static/js/jquery-1.3.2.min.js" />"></script>
<script src="<@s.url value="/static/js/jquery-ui-1.7.1.custom.min.js" />"></script>
<script src="<@s.url value="/static/js/jquery-1.12.4.min.js" />"></script>
<script src="<@s.url value="/static/js/jquery-ui-1.12.1.min.js" />"></script>
</head>
<body>
@@ -44,6 +44,9 @@
</a>
</div>
</div>
<@s.actionerror />
<table class="properties" style="clear:both; width:700px">
<thead>
<tr>
@@ -87,5 +90,8 @@
</#list>
</tbody>
</table>
<@s.actionmessage />
</body>
</html>
File diff suppressed because it is too large Load Diff
@@ -1,404 +0,0 @@
/*
* jQuery UI CSS Framework
* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
*/
/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
.ui-helper-clearfix { display: inline-block; }
/* required comment for clearfix to work in Opera \*/
* html .ui-helper-clearfix { height:1%; }
.ui-helper-clearfix { display:block; }
/* end clearfix */
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/*
* jQuery UI CSS Framework
* Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande,%20Lucida%20Sans,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=5px&bgColorHeader=5c9ccc&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=55&borderColorHeader=4297d7&fcHeader=ffffff&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=469bdd&bgColorDefault=dfeffc&bgTextureDefault=02_glass.png&bgImgOpacityDefault=85&borderColorDefault=c5dbec&fcDefault=2e6e9e&iconColorDefault=6da8d5&bgColorHover=d0e5f5&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=79b7e7&fcHover=1d5987&iconColorHover=217bc0&bgColorActive=f5f8f9&bgTextureActive=06_inset_hard.png&bgImgOpacityActive=100&borderColorActive=79b7e7&fcActive=e17009&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=fad42e&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
*/
/* Component containers
----------------------------------*/
.ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1em; }
.ui-widget-content { border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; }
.ui-widget-content a { color: #222222; }
.ui-widget-header { border: 1px solid #4297d7; background: #5c9ccc url(images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
.ui-widget-header a { color: #ffffff; }
/* Interaction states
----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default { border: 1px solid #c5dbec; background: #dfeffc url(images/ui-bg_glass_85_dfeffc_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #2e6e9e; outline: none; }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2e6e9e; text-decoration: none; outline: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #79b7e7; background: #d0e5f5 url(images/ui-bg_glass_75_d0e5f5_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1d5987; outline: none; }
.ui-state-hover a, .ui-state-hover a:hover { color: #1d5987; text-decoration: none; outline: none; }
.ui-state-active, .ui-widget-content .ui-state-active { border: 1px solid #79b7e7; background: #f5f8f9 url(images/ui-bg_inset-hard_100_f5f8f9_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #e17009; outline: none; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e17009; outline: none; text-decoration: none; }
/* Interaction Cues
----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight {border: 1px solid #fad42e; background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #363636; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a { color: #363636; }
.ui-state-error, .ui-widget-content .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
.ui-state-error a, .ui-widget-content .ui-state-error a { color: #cd0a0a; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text { color: #cd0a0a; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_d8e7f3_256x240.png); }
.ui-state-default .ui-icon { background-image: url(images/ui-icons_6da8d5_256x240.png); }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_217bc0_256x240.png); }
.ui-state-active .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); }
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-off { background-position: -96px -144px; }
.ui-icon-radio-on { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
.ui-corner-tl { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; }
.ui-corner-tr { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; }
.ui-corner-bl { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; }
.ui-corner-br { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
.ui-corner-top { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; }
.ui-corner-bottom { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
.ui-corner-right { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; }
.ui-corner-left { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; }
.ui-corner-all { -moz-border-radius: 5px; -webkit-border-radius: 5px; }
/* Overlays */
.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; }/* Accordion
----------------------------------*/
.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
.ui-accordion .ui-accordion-li-fix { display: inline; }
.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em 2.2em; }
.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; }
.ui-accordion .ui-accordion-content-active { display: block; }/* Datepicker
----------------------------------*/
.ui-datepicker { width: 17em; padding: .2em .2em 0; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; }
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
.ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; }
/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
display: none; /*sorry for IE5*/
display/**/: block; /*sorry for IE5*/
position: absolute; /*must have*/
z-index: -1; /*must have*/
filter: mask(); /*must have*/
top: -4px; /*must have*/
left: -4px; /*must have*/
width: 200px; /*must have*/
height: 200px; /*must have*/
}/* Dialog
----------------------------------*/
.ui-dialog { position: relative; padding: .2em; width: 300px; }
.ui-dialog .ui-dialog-titlebar { padding: .5em .3em .3em 1em; position: relative; }
.ui-dialog .ui-dialog-title { float: left; margin: .1em 0 .2em; }
.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; }
.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
.ui-draggable .ui-dialog-titlebar { cursor: move; }
/* Progressbar
----------------------------------*/
.ui-progressbar { height:2em; text-align: left; }
.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/* Resizable
----------------------------------*/
.ui-resizable { position: relative;}
.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0px; }
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0px; }
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0px; height: 100%; }
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0px; height: 100%; }
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Slider
----------------------------------*/
.ui-slider { position: relative; text-align: left; }
.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; }
.ui-slider-horizontal { height: .8em; }
.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
.ui-slider-horizontal .ui-slider-range-min { left: 0; }
.ui-slider-horizontal .ui-slider-range-max { right: 0; }
.ui-slider-vertical { width: .8em; height: 100px; }
.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs
----------------------------------*/
.ui-tabs { padding: .2em; zoom: 1; }
.ui-tabs .ui-tabs-nav { list-style: none; position: relative; padding: .2em .2em 0; }
.ui-tabs .ui-tabs-nav li { position: relative; float: left; border-bottom-width: 0 !important; margin: 0 .2em -1px 0; padding: 0; }
.ui-tabs .ui-tabs-nav li a { float: left; text-decoration: none; padding: .5em 1em; }
.ui-tabs .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 1px; border-bottom-width: 0; }
.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
.ui-tabs .ui-tabs-panel { padding: 1em 1.4em; display: block; border-width: 0; background: none; }
.ui-tabs .ui-tabs-hide { display: none !important; }
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -29,8 +29,8 @@
result_div.appendChild(document.createElement('br'));
for (var line_index in result_array) {
var result_wrap = document.createElement('pre')
line = document.createTextNode(result_array[line_index]);
var result_wrap = document.createElement('pre');
var line = document.createTextNode(result_array[line_index]);
result_wrap.appendChild(line);
result_div.appendChild(result_wrap);
result_div.appendChild(document.createElement('br'));
+6 -5
View File
@@ -21,28 +21,29 @@
-->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<package name="bundle-admin" namespace="/osgi/admin" extends="struts-default">
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<package name="bundle-admin" namespace="/osgi/admin" extends="osgi-default" strict-method-invocation="true">
<default-action-ref name="bundles" />
<action name="bundle_*!*" class="org.apache.struts2.osgi.admin.actions.BundlesAction" method="{2}">
<param name="id">{1}</param>
<result type="freemarker">viewBundle.ftl</result>
<allowed-methods>index,view,start,stop,update</allowed-methods>
</action>
<action name="bundles" class="org.apache.struts2.osgi.admin.actions.BundlesAction" method="index">
<result type="freemarker">viewBundles.ftl</result>
</action>
<action name="execCommand" class="org.apache.struts2.osgi.admin.actions.ShellAction">
<result type="freemarker">commandResult.ftl</result>
</action>
<action name="shell">
<action name="shell" class="org.apache.struts2.osgi.admin.actions.ShellAction">
<result type="freemarker">shell.ftl</result>
</action>
</package>
+1 -2
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-osgi-bundles</artifactId>
<version>2.5.20</version>
<version>2.5.27</version>
</parent>
<artifactId>struts2-osgi-demo-bundle</artifactId>
@@ -67,7 +67,6 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<version>2.1.0</version>
<configuration>
<instructions>
<manifestLocation>META-INF</manifestLocation>
@@ -22,13 +22,21 @@ package actions.osgi;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Actions;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.ResultPath;
@ResultPath("/content")
@Namespace("/osgi")
@ResultPath("/content/osgi")
public class HelloWorldAction extends ActionSupport {
private Message message;
private Message message = new Message("Default non-null message");
@Action("hello-convention")
@Override
@Actions({
@Action(value="hello-convention", results={@Result(name="success", type="freemarker", location="/content/osgi/hello-convention.ftl")}),
@Action(value="/osgi/hello-convention", results={@Result(name="success", type="freemarker", location="/content/osgi/hello-convention.ftl")})
})
public String execute() {
return SUCCESS;
}
@@ -45,6 +53,7 @@ public class HelloWorldAction extends ActionSupport {
return "Hello!!!";
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("{message:");
sb.append(message != null ? message.getText() : "null");
@@ -20,7 +20,7 @@
-->
<html>
<head>
<title>Action mapped by the XML configurationn</title>
<title>Action mapped by the XML configuration</title>
</head>
<body>
This is an action mapped by XML configuration, using a <b>FreeMarker</b> result.
@@ -18,7 +18,7 @@
*#
<html>
<head>
<title>Action mapped by the XML configurationn</title>
<title>Action mapped by the XML configuration</title>
</head>
<body>
This is an action mapped by XML configuration, using a <b>Velocity</b> result.
+21 -6
View File
@@ -20,21 +20,36 @@
*/
-->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<package name="bundle-demo" namespace="/osgi" extends="osgi-default">
<!-- Set some Struts 2 constants relevant to the OSGi Plugin.
Note: The constant definitions specified here (within the demo bundle) may also need to be
duplicated in the struts.xml configuration of the outer project that packages the demo
bundle JAR file within it.
-->
<constant name="struts.objectFactory" value="osgi" />
<constant name="struts.objectFactory.delegate" value="struts" />
<constant name="struts.freemarker.manager.classname" value="org.apache.struts2.osgi.BundleFreemarkerManager" />
<constant name="struts.velocity.manager.classname" value="org.apache.struts2.osgi.VelocityBundleResourceLoader" />
<constant name="struts.staticContentLoader" value="org.apache.struts2.osgi.loaders.StaticContentBundleResourceLoader" />
<package name="bundle-demo" namespace="/osgi" extends="osgi-default" strict-method-invocation="true">
<default-action-ref name="home" />
<action name="hello-velocity" class="helloWorldAction">
<action name="hello-velocity" class="actions.osgi.HelloWorldAction">
<result type="velocity">/content/osgi/hello.vm</result>
</action>
<action name="hello-freemarker" class="helloWorldAction">
<action name="hello-freemarker" class="actions.osgi.HelloWorldAction">
<result type="freemarker">/content/osgi/hello.ftl</result>
</action>
<action name="home">
<action name="home" class="actions.osgi.HelloWorldAction">
<result type="freemarker">/content/osgi/home.ftl</result>
</action>
</package>
</struts>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.5.20</version>
<version>2.5.27</version>
</parent>
<artifactId>struts2-osgi-bundles</artifactId>
+3 -2
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.5.20</version>
<version>2.5.27</version>
</parent>
<artifactId>struts2-core</artifactId>
<packaging>jar</packaging>
@@ -190,7 +190,8 @@
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.5.0</version>
<version>1.7.0</version>
<!-- Match version of minimum compatible version -->
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
@@ -27,6 +27,7 @@ import com.opensymphony.xwork2.test.StubConfigurationProvider;
import com.opensymphony.xwork2.util.XWorkTestCaseHelper;
import com.opensymphony.xwork2.util.location.LocatableProperties;
import junit.framework.TestCase;
import org.apache.commons.lang3.ClassUtils;
/**
* Base JUnit TestCase to extend for XWork specific JUnit tests. Uses
@@ -78,16 +79,20 @@ public abstract class XWorkTestCase extends TestCase {
@Override
public void register(ContainerBuilder builder,
LocatableProperties props) throws ConfigurationException {
builder.factory(type, name, new Factory() {
public Object create(Context context) throws Exception {
return impl;
}
if (impl instanceof String || ClassUtils.isPrimitiveOrWrapper(impl.getClass())) {
props.setProperty(name, "" + impl);
} else {
builder.factory(type, name, new Factory() {
public Object create(Context context) throws Exception {
return impl;
}
@Override
public Class type() {
return impl.getClass();
}
}, Scope.SINGLETON);
@Override
public Class type() {
return impl.getClass();
}
}, Scope.SINGLETON);
}
}
});
}
@@ -36,10 +36,8 @@ import java.util.*;
* @since 2.1
*/
public abstract class AbstractMatcher<E> implements Serializable {
/**
* <p> The logging instance </p>
*/
private static final Logger log = LogManager.getLogger(AbstractMatcher.class);
private static final Logger LOG = LogManager.getLogger(AbstractMatcher.class);
/**
* <p> Handles all wildcard pattern matching. </p>
@@ -50,10 +48,34 @@ public abstract class AbstractMatcher<E> implements Serializable {
* <p> The compiled patterns and their associated target objects </p>
*/
List<Mapping<E>> compiledPatterns = new ArrayList<>();
;
/**
* This flag controls if passed named params should be appended
* to the map in {@link #replaceParameters(Map, Map)}
* and will be accessible in {@link com.opensymphony.xwork2.config.entities.ResultConfig}.
* If set to false, the named parameters won't be appended.
*
* This behaviour is controlled by {@link org.apache.struts2.StrutsConstants#STRUTS_MATCHER_APPEND_NAMED_PARAMETERS}
*
* @since 2.5.23
* See WW-5065
*/
private final boolean appendNamedParameters;
public AbstractMatcher(PatternMatcher<?> helper) {
public AbstractMatcher(PatternMatcher<?> helper, boolean appendNamedParameters) {
this.wildcard = (PatternMatcher<Object>) helper;
this.appendNamedParameters = appendNamedParameters;
}
/**
* Creates a matcher with {@link #appendNamedParameters} set to true to keep backward compatibility
*
* @param helper an instance of {@link PatternMatcher}
* @deprecated use @{link {@link AbstractMatcher(PatternMatcher, boolean)} instead
*/
@Deprecated
public AbstractMatcher(PatternMatcher<?> helper) {
this(helper, true);
}
/**
@@ -84,17 +106,17 @@ public abstract class AbstractMatcher<E> implements Serializable {
name = name.substring(1);
}
log.debug("Compiling pattern '{}'", name);
LOG.debug("Compiling pattern '{}'", name);
pattern = wildcard.compilePattern(name);
compiledPatterns.add(new Mapping<E>(name, pattern, target));
compiledPatterns.add(new Mapping<>(name, pattern, target));
if (looseMatch) {
int lastStar = name.lastIndexOf('*');
if (lastStar > 1 && lastStar == name.length() - 1) {
if (name.charAt(lastStar - 1) != '*') {
pattern = wildcard.compilePattern(name.substring(0, lastStar - 1));
compiledPatterns.add(new Mapping<E>(name, pattern, target));
compiledPatterns.add(new Mapping<>(name, pattern, target));
}
}
}
@@ -115,12 +137,12 @@ public abstract class AbstractMatcher<E> implements Serializable {
E config = null;
if (compiledPatterns.size() > 0) {
log.debug("Attempting to match '{}' to a wildcard pattern, {} available", potentialMatch, compiledPatterns.size());
LOG.debug("Attempting to match '{}' to a wildcard pattern, {} available", potentialMatch, compiledPatterns.size());
Map<String,String> vars = new LinkedHashMap<String,String>();
Map<String,String> vars = new LinkedHashMap<>();
for (Mapping<E> m : compiledPatterns) {
if (wildcard.match(vars, potentialMatch, m.getPattern())) {
log.debug("Value matches pattern '{}'", m.getOriginalPattern());
LOG.debug("Value matches pattern '{}'", m.getOriginalPattern());
config = convert(potentialMatch, m.getTarget(), vars);
break;
}
@@ -152,20 +174,23 @@ public abstract class AbstractMatcher<E> implements Serializable {
*/
protected Map<String,String> replaceParameters(Map<String, String> orig, Map<String,String> vars) {
Map<String, String> map = new LinkedHashMap<>();
//this will set the group index references, like {1}
for (Map.Entry<String,String> entry : orig.entrySet()) {
map.put(entry.getKey(), convertParam(entry.getValue(), vars));
}
//the values map will contain entries like name->"Lex Luthor" and 1->"Lex Luthor"
//now add the non-numeric values
for (Map.Entry<String,String> entry: vars.entrySet()) {
if (!NumberUtils.isCreatable(entry.getKey())) {
map.put(entry.getKey(), entry.getValue());
if (appendNamedParameters) {
LOG.debug("Appending named parameters to the result map");
//the values map will contain entries like name->"Lex Luthor" and 1->"Lex Luthor"
//now add the non-numeric values
for (Map.Entry<String,String> entry: vars.entrySet()) {
if (!NumberUtils.isCreatable(entry.getKey())) {
map.put(entry.getKey(), entry.getValue());
}
}
}
return map;
}
@@ -192,7 +217,7 @@ public abstract class AbstractMatcher<E> implements Serializable {
c = val.charAt(x);
if (x < len - 2 &&
c == '{' && '}' == val.charAt(x+2)) {
varVal = (String)vars.get(String.valueOf(val.charAt(x + 1)));
varVal = vars.get(String.valueOf(val.charAt(x + 1)));
if (varVal != null) {
ret.append(varVal);
}
@@ -213,18 +238,18 @@ public abstract class AbstractMatcher<E> implements Serializable {
/**
* <p> The original pattern. </p>
*/
private String original;
private final String original;
/**
* <p> The compiled pattern. </p>
*/
private Object pattern;
private final Object pattern;
/**
* <p> The original object. </p>
*/
private E config;
private final E config;
/**
* <p> Contructs a read-only Mapping instance. </p>
@@ -58,7 +58,33 @@ public class ActionConfigMatcher extends AbstractMatcher<ActionConfig> implement
public ActionConfigMatcher(PatternMatcher<?> patternMatcher,
Map<String, ActionConfig> configs,
boolean looseMatch) {
super(patternMatcher);
this(patternMatcher, configs, looseMatch, true);
}
/**
* <p> Finds and precompiles the wildcard patterns from the ActionConfig
* "path" attributes. ActionConfig's will be evaluated in the order they
* exist in the config file. Only paths that actually contain a
* wildcard will be compiled. </p>
*
* <p>Patterns can optionally be matched "loosely". When
* the end of the pattern matches \*[^*]\*$ (wildcard, no wildcard,
* wildcard), if the pattern fails, it is also matched as if the
* last two characters didn't exist. The goal is to support the
* legacy "*!*" syntax, where the "!*" is optional.</p>
*
* @param patternMatcher pattern matcher
* @param configs An array of ActionConfig's to process
* @param looseMatch To loosely match wildcards or not
* @param appendNamedParameters To append named parameters or not
*
* @since 2.5.23
* See WW-5065
*/
public ActionConfigMatcher(PatternMatcher<?> patternMatcher,
Map<String, ActionConfig> configs,
boolean looseMatch, boolean appendNamedParameters) {
super(patternMatcher, appendNamedParameters);
for (Map.Entry<String, ActionConfig> entry : configs.entrySet()) {
addPattern(entry.getKey(), entry.getValue(), looseMatch);
}
@@ -289,6 +289,8 @@ public class DefaultConfiguration implements Configuration {
builder.constant(XWorkConstants.RELOAD_XML_CONFIGURATION, "false");
builder.constant(StrutsConstants.STRUTS_I18N_RELOAD, "false");
builder.constant(StrutsConstants.STRUTS_MATCHER_APPEND_NAMED_PARAMETERS, "true");
return builder.create(true);
}
@@ -338,8 +340,12 @@ public class DefaultConfiguration implements Configuration {
}
PatternMatcher<int[]> matcher = container.getInstance(PatternMatcher.class);
boolean appendNamedParameters = Boolean.parseBoolean(
container.getInstance(String.class, StrutsConstants.STRUTS_MATCHER_APPEND_NAMED_PARAMETERS)
);
return new RuntimeConfigurationImpl(Collections.unmodifiableMap(namespaceActionConfigs),
Collections.unmodifiableMap(namespaceConfigs), matcher);
Collections.unmodifiableMap(namespaceConfigs), matcher, appendNamedParameters);
}
private void setDefaultResults(Map<String, ResultConfig> results, PackageConfig packageContext) {
@@ -417,15 +423,18 @@ public class DefaultConfiguration implements Configuration {
public RuntimeConfigurationImpl(Map<String, Map<String, ActionConfig>> namespaceActionConfigs,
Map<String, String> namespaceConfigs,
PatternMatcher<int[]> matcher) {
PatternMatcher<int[]> matcher,
boolean appendNamedParameters)
{
this.namespaceActionConfigs = namespaceActionConfigs;
this.namespaceConfigs = namespaceConfigs;
this.namespaceActionConfigMatchers = new LinkedHashMap<>();
this.namespaceMatcher = new NamespaceMatcher(matcher, namespaceActionConfigs.keySet());
this.namespaceMatcher = new NamespaceMatcher(matcher, namespaceActionConfigs.keySet(), appendNamedParameters);
for (Map.Entry<String, Map<String, ActionConfig>> entry : namespaceActionConfigs.entrySet()) {
namespaceActionConfigMatchers.put(entry.getKey(), new ActionConfigMatcher(matcher, entry.getValue(), true));
ActionConfigMatcher configMatcher = new ActionConfigMatcher(matcher, entry.getValue(), true, appendNamedParameters);
namespaceActionConfigMatchers.put(entry.getKey(), configMatcher);
}
}
@@ -29,9 +29,23 @@ import java.util.Set;
* @since 2.1
*/
public class NamespaceMatcher extends AbstractMatcher<NamespaceMatch> {
public NamespaceMatcher(PatternMatcher<?> patternMatcher,
Set<String> namespaces) {
super(patternMatcher);
public NamespaceMatcher(PatternMatcher<?> patternMatcher, Set<String> namespaces) {
this(patternMatcher, namespaces, true);
}
/**
* Matches namespace strings against a wildcard pattern matcher
*
* @param patternMatcher pattern matcher
* @param namespaces A set of namespaces to process
* @param appendNamedParameters To append named parameters or not
*
* @since 2.5.23
* See WW-5065
*/
public NamespaceMatcher(PatternMatcher<?> patternMatcher, Set<String> namespaces, boolean appendNamedParameters) {
super(patternMatcher, appendNamedParameters);
for (String name : namespaces) {
if (!patternMatcher.isLiteral(name)) {
addPattern(name, new NamespaceMatch(name, null), false);
@@ -108,6 +108,7 @@ import com.opensymphony.xwork2.validator.DefaultValidatorFactory;
import com.opensymphony.xwork2.validator.DefaultValidatorFileParser;
import com.opensymphony.xwork2.validator.ValidatorFactory;
import com.opensymphony.xwork2.validator.ValidatorFileParser;
import com.sun.org.apache.xpath.internal.operations.Bool;
import ognl.MethodAccessor;
import ognl.PropertyAccessor;
import org.apache.struts2.StrutsConstants;
@@ -227,6 +228,7 @@ public class XWorkConfigurationProvider implements ConfigurationProvider {
props.setProperty(XWorkConstants.ENABLE_OGNL_EVAL_EXPRESSION, Boolean.FALSE.toString());
props.setProperty(XWorkConstants.RELOAD_XML_CONFIGURATION, Boolean.FALSE.toString());
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, Boolean.FALSE.toString());
props.setProperty(StrutsConstants.STRUTS_MATCHER_APPEND_NAMED_PARAMETERS, Boolean.TRUE.toString());
}
}
@@ -93,12 +93,12 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
private String configFileName;
private ObjectFactory objectFactory;
private Set<String> loadedFileUrls = new HashSet<>();
private final Set<String> loadedFileUrls = new HashSet<>();
private boolean errorIfMissing;
private Map<String, String> dtdMappings;
private Configuration configuration;
private boolean throwExceptionOnDuplicateBeans = true;
private Map<String, Element> declaredPackages = new HashMap<>();
private final Map<String, Element> declaredPackages = new HashMap<>();
private FileManager fileManager;
private ValueSubstitutor valueSubstitutor;
@@ -874,15 +874,24 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
if (allowedMethodsEls.getLength() > 0) {
// user defined 'allowed-methods' so used them whatever Strict DMI was enabled or not
allowedMethods = new HashSet<>(packageContext.getGlobalAllowedMethods());
if (allowedMethodsEls.getLength() > 0) {
Node n = allowedMethodsEls.item(0).getFirstChild();
if (n != null) {
String s = n.getNodeValue().trim();
if (s.length() > 0) {
allowedMethods.addAll(TextParseUtil.commaDelimitedStringToSet(s));
// Fix for WW-5029 (concatenate all possible text node children)
final Node allowedMethodsNode = allowedMethodsEls.item(0);
if (allowedMethodsNode != null) {
final NodeList allowedMethodsChildren = allowedMethodsNode.getChildNodes();
final StringBuilder allowedMethodsSB = new StringBuilder();
for (int i = 0; i < allowedMethodsChildren.getLength(); i++) {
Node allowedMethodsChildNode = allowedMethodsChildren.item(i);
if (allowedMethodsChildNode != null && allowedMethodsChildNode.getNodeType() == Node.TEXT_NODE) {
String childNodeValue = allowedMethodsChildNode.getNodeValue();
childNodeValue = (childNodeValue != null ? childNodeValue.trim() : "");
if (childNodeValue.length() > 0) {
allowedMethodsSB.append(childNodeValue);
}
}
}
if (allowedMethodsSB.length() > 0) {
allowedMethods.addAll(TextParseUtil.commaDelimitedStringToSet(allowedMethodsSB.toString()));
}
}
} else if (packageContext.isStrictMethodInvocation()) {
// user enabled Strict DMI but didn't defined action specific 'allowed-methods' so we use 'global-allowed-methods' only
@@ -937,11 +946,23 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
if (globalAllowedMethodsElms.getLength() > 0) {
Set<String> globalAllowedMethods = new HashSet<>();
Node n = globalAllowedMethodsElms.item(0).getFirstChild();
if (n != null) {
String s = n.getNodeValue().trim();
if (s.length() > 0) {
globalAllowedMethods = TextParseUtil.commaDelimitedStringToSet(s);
// Fix for WW-5029 (concatenate all possible text node children)
Node globaAllowedMethodsNode = globalAllowedMethodsElms.item(0);
if (globaAllowedMethodsNode != null) {
NodeList globaAllowedMethodsChildren = globaAllowedMethodsNode.getChildNodes();
final StringBuilder globalAllowedMethodsSB = new StringBuilder();
for (int i = 0; i < globaAllowedMethodsChildren.getLength(); i++) {
Node globalAllowedMethodsChildNode = globaAllowedMethodsChildren.item(i);
if (globalAllowedMethodsChildNode != null && globalAllowedMethodsChildNode.getNodeType() == Node.TEXT_NODE) {
String childNodeValue = globalAllowedMethodsChildNode.getNodeValue();
childNodeValue = (childNodeValue != null ? childNodeValue.trim() : "");
if (childNodeValue.length() > 0) {
globalAllowedMethodsSB.append(childNodeValue);
}
}
}
if (globalAllowedMethodsSB.length() > 0) {
globalAllowedMethods.addAll(TextParseUtil.commaDelimitedStringToSet(globalAllowedMethodsSB.toString()));
}
}
packageContext.addGlobalAllowedMethods(globalAllowedMethods);
@@ -164,7 +164,8 @@ class ContainerImpl implements Container {
public FieldInjector(ContainerImpl container, Field field, String name)
throws MissingDependencyException {
this.field = field;
if (!field.isAccessible()) {
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()))
&& !field.isAccessible()) {
SecurityManager sm = System.getSecurityManager();
try {
if (sm != null) {
@@ -256,7 +257,8 @@ class ContainerImpl implements Container {
public MethodInjector(ContainerImpl container, Method method, String name) throws MissingDependencyException {
this.method = method;
if (!method.isAccessible()) {
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible()) {
SecurityManager sm = System.getSecurityManager();
try {
if (sm != null) {
@@ -306,7 +308,8 @@ class ContainerImpl implements Container {
this.implementation = implementation;
constructor = findConstructorIn(implementation);
if (!constructor.isAccessible()) {
if ((!Modifier.isPublic(constructor.getModifiers()) || !Modifier.isPublic(constructor.getDeclaringClass().getModifiers()))
&& !constructor.isAccessible()) {
SecurityManager sm = System.getSecurityManager();
try {
if (sm != null) {
@@ -44,15 +44,17 @@ public enum Scope {
@Override
<T> InternalFactory<? extends T> scopeFactory(Class<T> type, String name, final InternalFactory<? extends T> factory) {
return new InternalFactory<T>() {
T instance;
volatile T instance;
public T create(InternalContext context) {
synchronized (context.getContainer()) {
if (instance == null) {
instance = InitializableFactory.wrapIfNeeded(factory).create(context);
if (instance == null) {
synchronized (context.getContainer()) {
if (instance == null) {
instance = InitializableFactory.wrapIfNeeded(factory).create(context);
}
}
return instance;
}
return instance;
}
@Override
@@ -32,6 +32,7 @@ import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.dispatcher.HttpParameters;
import org.apache.struts2.dispatcher.Parameter;
import java.util.Map;
@@ -173,7 +174,10 @@ public class AliasInterceptor extends AbstractInterceptor {
HttpParameters contextParameters = ActionContext.getContext().getParameters();
if (null != contextParameters) {
value = new Evaluated(contextParameters.get(name));
Parameter param = contextParameters.get(name);
if (param.isDefined()) {
value = new Evaluated(param.getValue());
}
}
}
if (value.isDefined()) {
@@ -25,13 +25,16 @@ import com.opensymphony.xwork2.XWorkConstants;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
import com.opensymphony.xwork2.util.*;
import com.opensymphony.xwork2.util.ClearableValueStack;
import com.opensymphony.xwork2.util.MemberAccessValueStack;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.ValueStackFactory;
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.dispatcher.Parameter;
import org.apache.struts2.dispatcher.HttpParameters;
import org.apache.struts2.dispatcher.Parameter;
import java.util.Collection;
import java.util.Comparator;
@@ -100,8 +103,8 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
*/
static final Comparator<String> rbCollator = new Comparator<String>() {
public int compare(String s1, String s2) {
int l1 = countOGNLCharacters(s1),
l2 = countOGNLCharacters(s2);
int l1 = countOGNLCharacters(s1);
int l2 = countOGNLCharacters(s2);
return l1 < l2 ? -1 : (l2 < l1 ? 1 : s1.compareTo(s2));
}
@@ -185,7 +188,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
if (clearableStack) {
//if the stack's context can be cleared, do that to prevent OGNL
//from having access to objects in the stack, see XW-641
((ClearableValueStack)newStack).clearContextValues();
((ClearableValueStack) newStack).clearContextValues();
Map<String, Object> context = newStack.getContext();
ReflectionContextState.setCreatingNullObjects(context, true);
ReflectionContextState.setDenyMethodExecution(context, true);
@@ -228,7 +231,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
TextProvider tp = (TextProvider) action;
developerNotification = tp.getText("devmode.notification",
"Developer Notification:\n{0}",
new String[]{ developerNotification }
new String[]{developerNotification}
);
}
@@ -245,7 +248,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
/**
* Checks if name of parameter can be accepted or thrown away
*
* @param name parameter name
* @param name parameter name
* @param action current action
* @return true if parameter is accepted
*/
@@ -289,27 +292,45 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
return accepted;
}
protected boolean isWithinLengthLimit( String name ) {
protected boolean isWithinLengthLimit(String name) {
boolean matchLength = name.length() <= paramNameMaxLength;
if (!matchLength) {
LOG.debug("Parameter [{}] is too long, allowed length is [{}]", name, String.valueOf(paramNameMaxLength));
if (devMode) { // warn only when in devMode
LOG.warn("Parameter [{}] is too long, allowed length is [{}]. Use Interceptor Parameter Overriding " +
"to override the limit, see more at\n" +
"https://struts.apache.org/core-developers/interceptors.html#interceptor-parameter-overriding",
name, paramNameMaxLength);
} else {
LOG.warn("Parameter [{}] is too long, allowed length is [{}]", name, paramNameMaxLength);
}
}
return matchLength;
}
}
protected boolean isAccepted(String paramName) {
AcceptedPatternsChecker.IsAccepted result = acceptedPatterns.isAccepted(paramName);
if (result.isAccepted()) {
return true;
} else if (devMode) { // warn only when in devMode
LOG.warn("Parameter [{}] didn't match accepted pattern [{}]! See Accepted / Excluded patterns at\n" +
"https://struts.apache.org/security/#accepted--excluded-patterns",
paramName, result.getAcceptedPattern());
} else {
LOG.debug("Parameter [{}] didn't match accepted pattern [{}]!", paramName, result.getAcceptedPattern());
}
LOG.debug("Parameter [{}] didn't match accepted pattern [{}]!", paramName, result.getAcceptedPattern());
return false;
}
protected boolean isExcluded(String paramName) {
ExcludedPatternsChecker.IsExcluded result = excludedPatterns.isExcluded(paramName);
if (result.isExcluded()) {
LOG.debug("Parameter [{}] matches excluded pattern [{}]!", paramName, result.getExcludedPattern());
if (devMode) { // warn only when in devMode
LOG.warn("Parameter [{}] matches excluded pattern [{}]! See Accepted / Excluded patterns at\n" +
"https://struts.apache.org/security/#accepted--excluded-patterns",
paramName, result.getExcludedPattern());
} else {
LOG.debug("Parameter [{}] matches excluded pattern [{}]!", paramName, result.getExcludedPattern());
}
return true;
}
return false;
@@ -227,21 +227,13 @@ public class StaticParametersInterceptor extends AbstractInterceptor {
protected void addParametersToContext(ActionContext ac, Map<String, ?> newParams) {
HttpParameters previousParams = ac.getParameters();
HttpParameters.Builder combinedParams = HttpParameters.create();
HttpParameters.Builder combinedParams;
if (overwrite) {
if (previousParams != null) {
combinedParams = combinedParams.withParent(previousParams);
}
if (newParams != null) {
combinedParams = combinedParams.withExtraParams(newParams);
}
combinedParams = HttpParameters.create().withParent( previousParams);
combinedParams = combinedParams.withExtraParams(newParams);
} else {
if (newParams != null) {
combinedParams = combinedParams.withExtraParams(newParams);
}
if (previousParams != null) {
combinedParams = combinedParams.withParent(previousParams);
}
combinedParams = HttpParameters.create(newParams);
combinedParams = combinedParams.withExtraParams(previousParams);
}
ac.setParameters(combinedParams.build());
}
@@ -54,7 +54,7 @@ public class OgnlUtil {
private static final Logger LOG = LogManager.getLogger(OgnlUtil.class);
private ConcurrentMap<String, Object> expressions = new ConcurrentHashMap<>();
private final ConcurrentMap<String, Object> expressions = new ConcurrentHashMap<>();
private final ConcurrentMap<Class, BeanInfo> beanInfoCache = new ConcurrentHashMap<>();
private TypeConverter defaultConverter;
@@ -74,6 +74,9 @@ public class OgnlUtil {
excludedClasses = new HashSet<>();
excludedPackageNamePatterns = new HashSet<>();
excludedPackageNames = new HashSet<>();
excludedClasses = Collections.unmodifiableSet(excludedClasses);
excludedPackageNamePatterns = Collections.unmodifiableSet(excludedPackageNamePatterns);
excludedPackageNames = Collections.unmodifiableSet(excludedPackageNames);
}
@Inject
@@ -181,10 +184,98 @@ public class OgnlUtil {
this.disallowProxyMemberAccess = Boolean.parseBoolean(disallowProxyMemberAccess);
}
/**
* @param maxLength Injects the Struts OGNL maximum expression length.
*/
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH, required = false)
protected void applyExpressionMaxLength(String maxLength) {
try {
if (maxLength == null || maxLength.isEmpty()) {
// user is going to disable this functionality
Ognl.applyExpressionMaxLength(null);
} else {
Ognl.applyExpressionMaxLength(Integer.parseInt(maxLength));
}
} catch (Exception ex) {
LOG.error("Unable to set OGNL Expression Max Length {}.", maxLength); // Help configuration debugging.
throw ex;
}
}
public boolean isDisallowProxyMemberAccess() {
return disallowProxyMemberAccess;
}
/**
* Convenience mechanism to clear the OGNL Runtime Cache via OgnlUtil. May be utilized
* by applications that generate many unique OGNL expressions over time.
*
* Note: This call affects the global OGNL cache, see ({@link ognl.OgnlRuntime#clearCache()} for details.
*
* Warning: Frequent calling if this method may negatively impact performance, but may be required
* to avoid memory exhaustion (resource leak) with too many OGNL expressions being cached.
*
* @since 2.5.21
*/
public static void clearRuntimeCache() {
OgnlRuntime.clearCache();
}
/**
* Provide a mechanism to clear the OGNL expression cache. May be utilized by applications
* that generate many unique OGNL expressions over time.
*
* Note: This call affects the current OgnlUtil instance. For Struts this is often a Singleton
* instance so it can be "effectively global".
*
* Warning: Frequent calling if this method may negatively impact performance, but may be required
* to avoid memory exhaustion (resource leak) with too many OGNL expressions being cached.
*
* @since 2.5.21
*/
public void clearExpressionCache() {
expressions.clear();
}
/**
* Check the size of the expression cache (current number of elements).
*
* @return current number of elements in the expression cache.
*
* @since 2.5.21
*/
public int expressionCacheSize() {
return expressions.size();
}
/**
* Provide a mechanism to clear the BeanInfo cache. May be utilized by applications
* that request BeanInfo and/or PropertyDescriptors for many unique classes or objects over time
* (especially dynamic objects).
*
* Note: This call affects the current OgnlUtil instance. For Struts this is often a Singleton
* instance so it can be "effectively global".
*
* Warning: Frequent calling if this method may negatively impact performance, but may be required
* to avoid memory exhaustion (resource leak) with too many BeanInfo elements being cached.
*
* @since 2.5.21
*/
public void clearBeanInfoCache() {
beanInfoCache.clear();
}
/**
* Check the size of the BeanInfo cache (current number of elements).
*
* @return current number of elements in the BeanInfo cache.
*
* @since 2.5.21
*/
public int beanInfoCacheSize() {
return beanInfoCache.size();
}
/**
* Sets the object's properties using the default type converter, defaulting to not throw
* exceptions for problems setting the properties.
@@ -682,6 +773,9 @@ public class OgnlUtil {
setValue(name, context, o, value);
} catch (OgnlException e) {
Throwable reason = e.getReason();
if (reason instanceof SecurityException) {
LOG.warn("Could not evaluate this expression due to security constraints: [{}]", name, e);
}
String msg = "Caught OgnlException while setting property '" + name + "' on type '" + o.getClass().getName() + "'.";
Throwable exception = (reason == null) ? e : reason;
@@ -182,7 +182,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
private void trySetValue(String expr, Object value, boolean throwExceptionOnFailure, Map<String, Object> context) throws OgnlException {
context.put(XWorkConverter.CONVERSION_PROPERTY_FULLNAME, expr);
context.put(REPORT_ERRORS_ON_NO_PROP, (throwExceptionOnFailure) ? Boolean.TRUE : Boolean.FALSE);
context.put(REPORT_ERRORS_ON_NO_PROP, throwExceptionOnFailure || logMissingProperties ? Boolean.TRUE : Boolean.FALSE);
ognlUtil.setValue(expr, context, root, value);
}
@@ -204,6 +204,9 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
}
protected void handleOgnlException(String expr, Object value, boolean throwExceptionOnFailure, OgnlException e) {
if (e != null && e.getReason() instanceof SecurityException) {
LOG.error("Could not evaluate this expression due to security constraints: [{}]", expr, e);
}
boolean shouldLog = shouldLogMissingPropertyWarning(e);
String msg = null;
if (throwExceptionOnFailure || shouldLog) {
@@ -246,7 +249,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
}
protected void setupExceptionOnFailure(boolean throwExceptionOnFailure) {
if (throwExceptionOnFailure) {
if (throwExceptionOnFailure || logMissingProperties) {
context.put(THROW_EXCEPTION_ON_FAILURE, true);
}
}
@@ -326,7 +329,12 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
}
protected Object handleOgnlException(String expr, boolean throwExceptionOnFailure, OgnlException e) {
Object ret = findInContext(expr);
Object ret = null;
if (e != null && e.getReason() instanceof SecurityException) {
LOG.error("Could not evaluate this expression due to security constraints: [{}]", expr, e);
} else {
ret = findInContext(expr);
}
if (ret == null) {
if (shouldLogMissingPropertyWarning(e)) {
LOG.warn("Could not find property [{}]!", expr, e);
@@ -339,8 +347,9 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
}
protected boolean shouldLogMissingPropertyWarning(OgnlException e) {
return (e instanceof NoSuchPropertyException || e instanceof MethodFailedException)
&& devMode && logMissingProperties;
return (e instanceof NoSuchPropertyException ||
(e instanceof MethodFailedException && e.getReason() instanceof NoSuchMethodException))
&& logMissingProperties;
}
private Object tryFindValue(String expr, Class asType) throws OgnlException {
@@ -19,6 +19,7 @@
package com.opensymphony.xwork2.ognl;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.XWorkConstants;
import com.opensymphony.xwork2.TextProvider;
import com.opensymphony.xwork2.conversion.NullHandler;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
@@ -61,7 +62,7 @@ public class OgnlValueStackFactory implements ValueStackFactory {
this.textProvider = textProvider;
}
@Inject(value="allowStaticMethodAccess", required=false)
@Inject(value = XWorkConstants.ALLOW_STATIC_METHOD_ACCESS, required = false)
protected void setAllowStaticMethodAccess(String allowStaticMethodAccess) {
this.allowStaticMethodAccess = BooleanUtils.toBoolean(allowStaticMethodAccess);
}
@@ -49,7 +49,7 @@ public class SecurityMemberAccess extends DefaultMemberAccess {
/**
* SecurityMemberAccess
* - access decisions based on whether member is static (or not)
* - block or allow access to properties (configureable-after-construction)
* - block or allow access to properties (configurable-after-construction)
*
* @param allowStaticMethodAccess
*/
@@ -217,13 +217,14 @@ public class CompoundRootAccessor implements PropertyAccessor, MethodAccessor, C
return null;
}
Throwable reason = null;
Class[] argTypes = getArgTypes(objects);
for (Object o : root) {
if (o == null) {
continue;
}
Class clazz = o.getClass();
Class[] argTypes = getArgTypes(objects);
MethodCall mc = null;
@@ -233,24 +234,27 @@ public class CompoundRootAccessor implements PropertyAccessor, MethodAccessor, C
if ((argTypes == null) || !invalidMethods.containsKey(mc)) {
try {
Object value = OgnlRuntime.callMethod((OgnlContext) context, o, name, objects);
if (value != null) {
return value;
}
return OgnlRuntime.callMethod((OgnlContext) context, o, name, objects);
} catch (OgnlException e) {
// try the next one
Throwable reason = e.getReason();
reason = e.getReason();
if (!context.containsKey(OgnlValueStack.THROW_EXCEPTION_ON_FAILURE) && (mc != null) && (reason != null) && (reason.getClass() == NoSuchMethodException.class)) {
invalidMethods.put(mc, Boolean.TRUE);
} else if (reason != null) {
throw new MethodFailedException(o, name, e.getReason());
if (reason != null && !(reason instanceof NoSuchMethodException)) {
// method has found but thrown an exception
break;
}
if ((mc != null) && (reason != null)) {
invalidMethods.put(mc, Boolean.TRUE);
}
// continue and try the next one
}
}
}
if (context.containsKey(OgnlValueStack.THROW_EXCEPTION_ON_FAILURE)) {
throw new MethodFailedException(target, name, reason);
}
return null;
}
@@ -21,10 +21,13 @@ package com.opensymphony.xwork2.security;
import com.opensymphony.xwork2.XWorkConstants;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.TextParseUtil;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
@@ -34,7 +37,11 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
private static final Logger LOG = LogManager.getLogger(DefaultAcceptedPatternsChecker.class);
public static final String[] ACCEPTED_PATTERNS = {
"\\w+((\\.\\w+)|(\\[\\d+\\])|(\\(\\d+\\))|(\\['(\\w|[\\u4e00-\\u9fa5])+'\\])|(\\('(\\w|[\\u4e00-\\u9fa5])+'\\)))*"
"\\w+((\\.\\w+)|(\\[\\d+])|(\\(\\d+\\))|(\\['(\\w|[\\u4e00-\\u9fa5])+'])|(\\('(\\w|[\\u4e00-\\u9fa5])+'\\)))*"
};
public static final String[] DMI_AWARE_ACCEPTED_PATTERNS = {
"\\w+([:]?\\w+)?((\\.\\w+)|(\\[\\d+])|(\\(\\d+\\))|(\\['(\\w|[\\u4e00-\\u9fa5])+'])|(\\('(\\w|[\\u4e00-\\u9fa5])+'\\)))*([!]?\\w+)?"
};
private Set<Pattern> acceptedPatterns;
@@ -43,46 +50,74 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
setAcceptedPatterns(ACCEPTED_PATTERNS);
}
public DefaultAcceptedPatternsChecker(
@Inject(value = StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION, required = false) String dmiValue
) {
if (BooleanUtils.toBoolean(dmiValue)) {
LOG.debug("DMI is enabled, adding DMI related accepted patterns");
setAcceptedPatterns(DMI_AWARE_ACCEPTED_PATTERNS);
} else {
setAcceptedPatterns(ACCEPTED_PATTERNS);
}
}
@Inject(value = XWorkConstants.OVERRIDE_ACCEPTED_PATTERNS, required = false)
protected void setOverrideAcceptedPatterns(String acceptablePatterns) {
LOG.warn("Overriding accepted patterns [{}] with [{}], be aware that this affects all instances and safety of your application!",
acceptedPatterns, acceptablePatterns);
acceptedPatterns, acceptablePatterns);
acceptedPatterns = new HashSet<>();
for (String pattern : TextParseUtil.commaDelimitedStringToSet(acceptablePatterns)) {
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
try {
for (String pattern : TextParseUtil.commaDelimitedStringToSet(acceptablePatterns)) {
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
}
} finally {
acceptedPatterns = Collections.unmodifiableSet(acceptedPatterns);
}
}
@Inject(value = XWorkConstants.ADDITIONAL_ACCEPTED_PATTERNS, required = false)
protected void setAdditionalAcceptedPatterns(String acceptablePatterns) {
LOG.warn("Adding additional global patterns [{}] to accepted patterns!", acceptablePatterns);
for (String pattern : TextParseUtil.commaDelimitedStringToSet(acceptablePatterns)) {
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
acceptedPatterns = new HashSet<>(acceptedPatterns); // Make mutable before adding
try {
for (String pattern : TextParseUtil.commaDelimitedStringToSet(acceptablePatterns)) {
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
}
} finally {
acceptedPatterns = Collections.unmodifiableSet(acceptedPatterns);
}
}
@Override
public void setAcceptedPatterns(String commaDelimitedPatterns) {
setAcceptedPatterns(TextParseUtil.commaDelimitedStringToSet(commaDelimitedPatterns));
}
@Override
public void setAcceptedPatterns(String[] additionalPatterns) {
setAcceptedPatterns(new HashSet<>(Arrays.asList(additionalPatterns)));
}
@Override
public void setAcceptedPatterns(Set<String> patterns) {
if (acceptedPatterns == null) {
// Limit unwanted log entries (for 1st call, acceptedPatterns null)
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, patterns);
}
acceptedPatterns = new HashSet<>(patterns.size());
for (String pattern : patterns) {
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
try {
for (String pattern : patterns) {
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
}
} finally {
acceptedPatterns = Collections.unmodifiableSet(acceptedPatterns);
}
}
@Override
public IsAccepted isAccepted(String value) {
for (Pattern acceptedPattern : acceptedPatterns) {
if (acceptedPattern.matcher(value).matches()) {
@@ -93,6 +128,7 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
return IsAccepted.no(acceptedPatterns.toString());
}
@Override
public Set<Pattern> getAcceptedPatterns() {
return acceptedPatterns;
}
@@ -27,6 +27,7 @@ import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
@@ -55,36 +56,48 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
// Limit unwanted log entries (when excludedPatterns null/empty - usually 1st call)
LOG.debug("Overriding excluded patterns with [{}]", excludePatterns);
}
excludedPatterns = new HashSet<Pattern>();
for (String pattern : TextParseUtil.commaDelimitedStringToSet(excludePatterns)) {
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
excludedPatterns = new HashSet<>();
try {
for (String pattern : TextParseUtil.commaDelimitedStringToSet(excludePatterns)) {
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
}
} finally {
excludedPatterns = Collections.unmodifiableSet(excludedPatterns);
}
}
@Inject(value = XWorkConstants.ADDITIONAL_EXCLUDED_PATTERNS, required = false)
public void setAdditionalExcludePatterns(String excludePatterns) {
LOG.debug("Adding additional global patterns [{}] to excluded patterns!", excludePatterns);
for (String pattern : TextParseUtil.commaDelimitedStringToSet(excludePatterns)) {
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
excludedPatterns = new HashSet<>(excludedPatterns); // Make mutable before adding
try {
for (String pattern : TextParseUtil.commaDelimitedStringToSet(excludePatterns)) {
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
}
} finally {
excludedPatterns = Collections.unmodifiableSet(excludedPatterns);
}
}
@Inject(StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION)
protected void setDynamicMethodInvocation(String dmiValue) {
if (BooleanUtils.toBoolean(dmiValue) == false) {
if (!BooleanUtils.toBoolean(dmiValue)) {
LOG.debug("DMI is disabled, adding DMI related excluded patterns");
setAdditionalExcludePatterns("^(action|method):.*");
}
}
@Override
public void setExcludedPatterns(String commaDelimitedPatterns) {
setExcludedPatterns(TextParseUtil.commaDelimitedStringToSet(commaDelimitedPatterns));
}
@Override
public void setExcludedPatterns(String[] patterns) {
setExcludedPatterns(new HashSet<>(Arrays.asList(patterns)));
}
@Override
public void setExcludedPatterns(Set<String> patterns) {
if (excludedPatterns != null && excludedPatterns.size() > 0) {
LOG.warn("Replacing excluded patterns [{}] with [{}], be aware that this affects all instances and safety of your application!",
@@ -94,11 +107,16 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
LOG.debug("Sets excluded patterns to [{}]", patterns);
}
excludedPatterns = new HashSet<>(patterns.size());
for (String pattern : patterns) {
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
try {
for (String pattern : patterns) {
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
}
} finally {
excludedPatterns = Collections.unmodifiableSet(excludedPatterns);
}
}
@Override
public IsExcluded isExcluded(String value) {
for (Pattern excludedPattern : excludedPatterns) {
if (excludedPattern.matcher(value).matches()) {
@@ -109,6 +127,7 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
return IsExcluded.no(excludedPatterns);
}
@Override
public Set<Pattern> getExcludedPatterns() {
return excludedPatterns;
}
@@ -31,8 +31,6 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -53,7 +51,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
public static final String STRUTS_MESSAGES_BUNDLE = "org/apache/struts2/struts-messages";
private static final String TOMCAT_RESOURCE_ENTRIES_FIELD = "resourceEntries";
private final String RELOADED = "com.opensymphony.xwork2.util.LocalizedTextProvider.reloaded";
private static final String RELOADED = "com.opensymphony.xwork2.util.LocalizedTextProvider.reloaded";
protected final ConcurrentMap<String, ResourceBundle> bundlesMap = new ConcurrentHashMap<>();
protected boolean devMode = false;
@@ -61,7 +59,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
private final ConcurrentMap<MessageFormatKey, MessageFormat> messageFormats = new ConcurrentHashMap<>();
private final ConcurrentMap<Integer, List<String>> classLoaderMap = new ConcurrentHashMap<>();
private final Set<String> missingBundles = Collections.synchronizedSet(new HashSet<String>());
private final ConcurrentMap<String, Boolean> missingBundles = new ConcurrentHashMap<>();
private final ConcurrentMap<Integer, ClassLoader> delegatedClassLoaderMap = new ConcurrentHashMap<>();
/**
@@ -225,10 +223,45 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
}
/**
* @param bundleName Removes the bundle from any cached "misses"
* Clear a specific bundle from the <code>bundlesMap</code>
*
* Warning: This method <b>may be ineffective</b> due to the way the <code>bundlesMap</code>
* is used in combination with locale. Descendants should use the method
* {@link #clearBundle(java.lang.String, java.util.Locale)} instead.
*
* @param bundleName The bundle to remove from the bundle map
*/
public void clearBundle(final String bundleName) {
bundlesMap.remove(getCurrentThreadContextClassLoader().hashCode() + bundleName);
final ResourceBundle removedBundle = bundlesMap.remove(getCurrentThreadContextClassLoader().hashCode() + bundleName);
LOG.debug("Clearing resource bundle [{}], result: [{}].", bundleName, Boolean.valueOf(removedBundle != null));
}
/**
* Clear a specific bundle + locale combination from the <code>bundlesMap</code>.
* Intended for descendants to use clear a bundle + locale combination.
*
* @param bundleName The bundle (combined with locale) to remove from the bundle map
* @param locale Provides the locale to combine with the bundle to get the key
*/
protected void clearBundle(final String bundleName, Locale locale) {
final String key = createMissesKey(String.valueOf(getCurrentThreadContextClassLoader().hashCode()), bundleName, locale);
final ResourceBundle removedBundle = bundlesMap.remove(key);
LOG.debug("Clearing resource bundle [{}], locale [{}], result: [{}].", bundleName, locale, Boolean.valueOf(removedBundle != null));
}
/**
* Clears the <code>missingBundles</code> contents. This allows descendants to
* clear the <b>"missing bundles cache"</b> when desired (or needed).
*
* Note: This method may be used when the <code>bundlesMap</code> state has changed
* in such a way that bundles that were previously "missing" may now be available
* (e.g. after calling {@link #addDefaultResourceBundle(java.lang.String)} when the
* {@link AbstractLocalizedTextProvider} has already been used for failed bundle
* lookups of a given key, or some transitory state made a bundle lookup fail.
*/
protected void clearMissingBundlesCache() {
missingBundles.clear();
LOG.debug("Cleared the missing bundles cache.");
}
protected void reloadBundles() {
@@ -355,7 +388,7 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
ClassLoader classLoader = getCurrentThreadContextClassLoader();
String key = createMissesKey(String.valueOf(classLoader.hashCode()), aBundleName, locale);
if (missingBundles.contains(key)) {
if (missingBundles.containsKey(key)) {
return null;
}
@@ -378,11 +411,11 @@ abstract class AbstractLocalizedTextProvider implements LocalizedTextProvider {
}
} catch (MissingResourceException e) {
LOG.debug("Missing resource bundle [{}]!", aBundleName, e);
missingBundles.add(key);
missingBundles.putIfAbsent(key, Boolean.TRUE);
}
} else {
LOG.debug("Missing resource bundle [{}]!", aBundleName);
missingBundles.add(key);
missingBundles.putIfAbsent(key, Boolean.TRUE);
}
}
return bundle;
@@ -82,13 +82,14 @@ public class ProxyUtil {
}
/**
* Check whether the given member is a proxy member of a proxy object.
* Check whether the given member is a proxy member of a proxy object or is a static proxy member.
* @param member the member to check
* @param object the object to check
*/
public static boolean isProxyMember(Member member, Object object) {
if (!isProxy(object))
if (!Modifier.isStatic(member.getModifiers()) && !isProxy(object)) {
return false;
}
Boolean flag = isProxyMemberCache.get(member);
if (flag != null) {
@@ -58,10 +58,25 @@ public class ResourceFinder {
this(path, classLoaderInterface, null);
}
/**
* Create a ResourceFinder instance for looking up resources (via ClassLoader or via specific URLs
* specifying resource locations).
*
* This class was functional in Struts 2.3.x, but broken for Struts 2.5.x (before 2.5.24), when dealing with
* JAR resources in certain circumstances. The current logic permits the base path to be "" (empty string),
* which is required to also match JAR entries rooted at "" and not just file entries rooted at "/".
*
* @param path Base path from which to look for resources (typically "xyz/abc/klm" form for file or
* jar contents).
* @param classLoaderInterface ClassLoader to perform the resource lookup. If null, a default Thread
* ClassLoader will be used.
* @param urls URLs (typically file: or jar:) within which to search for resources, instead of the
* ClassLoader. If null, fallback to a ClassLoader instead.
*/
public ResourceFinder(String path, ClassLoaderInterface classLoaderInterface, URL... urls) {
path = StringUtils.trimToEmpty(path);
if (!StringUtils.endsWith(path, "/")) {
path += "/";
if (!path.isEmpty() && !StringUtils.endsWith(path, "/")) {
path += "/"; // Only append terminator to nonempty paths, otherwise JAR entry lookups break.
}
this.path = path;
@@ -1015,15 +1030,26 @@ public class ResourceFinder {
public Map<URL, Set<String>> findPackagesMap(String uri) throws IOException {
String basePath = path + uri;
LOG.trace(" basePath(initial): " + basePath);
if (!basePath.endsWith("/")) {
basePath += "/";
}
LOG.trace(" basePath(final): " + basePath);
Enumeration<URL> urls = getResources(basePath);
Map<URL, Set<String>> result = new HashMap<>();
if (! urls.hasMoreElements()) {
LOG.debug(" urls enumeration for basePath is empty ?");
}
while (urls.hasMoreElements()) {
URL location = urls.nextElement();
LOG.debug(" url (location): " + location);
try {
if ("jar".equals(location.getProtocol())) {
Set<String> resources = new HashSet<>();
@@ -1114,12 +1140,20 @@ public class ResourceFinder {
jarfile = conn.getJarFile();
Enumeration<JarEntry> entries = jarfile.entries();
if (entries == null || ! entries.hasMoreElements()) {
LOG.debug(" JAR entries null or empty");
}
LOG.debug(" Looking for entries matching basePath: " + basePath);
while (entries != null && entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String name = entry.getName();
if (entry.isDirectory() && StringUtils.startsWith(name, basePath)) {
resources.add(name);
} else if (entry.isDirectory()) {
LOG.trace(" entry: " + name + " , isDirectory: " + entry.isDirectory() + " but does not start with basepath");
}
}
}
@@ -1156,13 +1190,22 @@ public class ResourceFinder {
private Enumeration<URL> getResources(String fulluri) throws IOException {
if (urls == null) {
LOG.debug(" urls (member) null, using classLoaderInterface to get resources");
return classLoaderInterface.getResources(fulluri);
}
LOG.debug(" urls (member) non-null, using findResource to get resources");
Vector<URL> resources = new Vector<>();
for (URL url : urls) {
URL resource = findResource(fulluri, url);
if (resource != null){
if (resource != null) {
LOG.trace(" resource lookup non-null");
resources.add(resource);
} else {
LOG.trace(" resource lookup is null");
}
}
return resources.elements();
@@ -261,6 +261,9 @@ public final class StrutsConstants {
/** Enables evaluation of OGNL expressions */
public static final String STRUTS_ENABLE_OGNL_EVAL_EXPRESSION = "struts.ognl.enableOGNLEvalExpression";
/** The maximum length of an expression (OGNL) */
public static final String STRUTS_OGNL_EXPRESSION_MAX_LENGTH = "struts.ognl.expressionMaxLength";
/** Disables {@link org.apache.struts2.dispatcher.StrutsRequestWrapper} request attribute value stack lookup (JSTL accessibility) */
public static final String STRUTS_DISABLE_REQUEST_ATTRIBUTE_VALUE_STACK_LOOKUP = "struts.disableRequestAttributeValueStackLookup";
@@ -338,4 +341,7 @@ public final class StrutsConstants {
public static final String STRUTS_DISALLOW_PROXY_MEMBER_ACCESS = "struts.disallowProxyMemberAccess";
public static final String STRUTS_OGNL_AUTO_GROWTH_COLLECTION_LIMIT = "struts.ognl.autoGrowthCollectionLimit";
/** See {@link com.opensymphony.xwork2.config.impl.AbstractMatcher#appendNamedParameters */
public static final String STRUTS_MATCHER_APPEND_NAMED_PARAMETERS = "struts.matcher.appendNamedParameters";
}
@@ -83,4 +83,21 @@ public class Checkbox extends UIBean {
this.fieldValue = fieldValue;
}
/**
* Deprecated since 2.5.27
* @deprecated use {@link #setLabelPosition(String)} instead
*/
@Deprecated
@Override
@StrutsTagAttribute(description="(Deprecated) Define label position of form element (top/left), also 'right' is supported when using 'xhtml' theme")
public void setLabelposition(String labelPosition) {
super.setLabelPosition(labelPosition);
}
@Override
@StrutsTagAttribute(description="Define label position of form element (top/left), also 'right' is supported when using 'xhtml' theme")
public void setLabelPosition(String labelPosition) {
super.setLabelPosition(labelPosition);
}
}
@@ -300,7 +300,7 @@ public class Component {
* expression otherwise.
*/
protected String completeExpressionIfAltSyntax(String expr) {
if (altSyntax()) {
if (altSyntax() && !ComponentUtils.containsExpression(expr)) {
return "%{" + expr + "}";
}
return expr;
@@ -382,6 +382,15 @@ public class Component {
}
}
/**
* Detects if altSyntax is enabled and then checks if expression contains %{...}
* @param expr a string to examined
* @return true if altSyntax is enabled and expr contains %{...}
*/
protected boolean recursion(String expr) {
return ComponentUtils.altSyntax(stack) && ComponentUtils.containsExpression(expr);
}
/**
* Renders an action URL by consulting the {@link org.apache.struts2.dispatcher.mapper.ActionMapper}.
* @param action the action
@@ -221,7 +221,7 @@ public class Form extends ClosingUIBean {
@Override
protected void populateComponentHtmlId(Form form) {
if (id != null) {
addParameter("id", escape(id));
super.populateComponentHtmlId(null);
}
// if no id given, it will be tried to generate it from the action attribute
@@ -31,8 +31,7 @@ import com.opensymphony.xwork2.util.ValueStack;
* complex expression and then simply reference that variable each time rather than the complex expression. This is
* useful in both cases: when the complex expression takes time (performance improvement) or is hard to read (code
* readability improvement).</p>
* <p>If the tag is used with body content, the evaluation of the value parameter is omitted. Instead, the String to
* which the body evaluates is set as value for the scoped variable.</p>
* <p>If the value parameter is omitted, the String to which the body evaluates is set as value for the scoped variable.</p>
*
* <p>The scopes available are as follows:</p>
* <ul>
@@ -94,10 +93,10 @@ public class Set extends ContextBean {
Object o;
if (value == null) {
if (body != null && !body.equals("")) {
o = body;
} else {
if (body == null) {
o = findValue("top");
} else {
o = body;
}
} else {
o = findValue(value);
@@ -637,7 +637,7 @@ public abstract class UIBean extends Component {
public void evaluateParams() {
String templateDir = getTemplateDir();
String theme = getTheme();
addParameter("templateDir", templateDir);
addParameter("theme", theme);
addParameter("template", template != null ? findString(template) : getDefaultTemplate());
@@ -679,7 +679,9 @@ public abstract class UIBean extends Component {
}
if (labelPosition != null) {
addParameter("labelposition", findString(labelPosition));
String labelPosition = findString(this.labelPosition);
addParameter("labelposition", labelPosition);
addParameter("labelPosition", labelPosition);
}
if (requiredPosition != null) {
@@ -689,7 +691,7 @@ public abstract class UIBean extends Component {
if (errorPosition != null) {
addParameter("errorposition", findString(errorPosition));
}
if (requiredLabel != null) {
addParameter("required", findValue(requiredLabel, Boolean.class));
}
@@ -795,8 +797,11 @@ public abstract class UIBean extends Component {
addParameter("nameValue", findValue(value, valueClazz));
} else if (name != null) {
String expr = completeExpressionIfAltSyntax(name);
addParameter("nameValue", findValue(expr, valueClazz));
if (recursion(name)) {
addParameter("nameValue", expr);
} else {
addParameter("nameValue", findValue(expr, valueClazz));
}
}
} else {
if (value != null) {
@@ -1002,7 +1007,7 @@ public abstract class UIBean extends Component {
} else {
tryId = generatedId;
}
//fix for https://issues.apache.org/jira/browse/WW-4299
//do not assign value to id if tryId is null
if (tryId != null) {
@@ -1021,9 +1026,7 @@ public abstract class UIBean extends Component {
@StrutsTagAttribute(description="HTML id attribute")
public void setId(String id) {
if (id != null) {
this.id = findString(id);
}
this.id = id;
}
@StrutsTagAttribute(description="The template directory.")
@@ -1050,7 +1053,8 @@ public abstract class UIBean extends Component {
this.cssClass = cssClass;
}
@StrutsTagAttribute(description="The css class to use for element - it's an alias of cssClass attribute.")
@Deprecated
@StrutsTagAttribute(description="(Deprecated) The css class to use for element - it's an alias of cssClass attribute.")
public void setClass(String cssClass) {
this.cssClass = cssClass;
}
@@ -1095,11 +1099,21 @@ public abstract class UIBean extends Component {
this.labelSeparator = labelseparator;
}
@StrutsTagAttribute(description="Define label position of form element (top/left)")
/**
* Deprecated since 2.5.27
* @deprecated use {@link #setLabelPosition(String)} instead
*/
@StrutsTagAttribute(description="(Deprecated) Define label position of form element (top/left)")
@Deprecated
public void setLabelposition(String labelPosition) {
this.labelPosition = labelPosition;
}
@StrutsTagAttribute(description="Define label position of form element (top/left)")
public void setLabelPosition(String labelPosition) {
this.labelPosition = labelPosition;
}
@StrutsTagAttribute(description="Define required position of required form element (left|right)")
public void setRequiredPosition(String requiredPosition) {
this.requiredPosition = requiredPosition;
@@ -1109,7 +1123,7 @@ public abstract class UIBean extends Component {
public void setErrorPosition(String errorPosition) {
this.errorPosition = errorPosition;
}
@StrutsTagAttribute(description="The name to set for element")
public void setName(String name) {
this.name = name;
@@ -1241,8 +1255,8 @@ public abstract class UIBean extends Component {
this.tooltipIconPath = tooltipIconPath;
}
public void setDynamicAttributes(Map<String, Object> tagDynamicAttributes) {
for (Map.Entry<String, Object> entry : tagDynamicAttributes.entrySet()) {
public void setDynamicAttributes(Map<String, String> tagDynamicAttributes) {
for (Map.Entry<String, String> entry : tagDynamicAttributes.entrySet()) {
String key = entry.getKey();
if (!isValidTagAttribute(key)) {
@@ -64,7 +64,7 @@ public class FreemarkerTemplateEngine extends BaseTemplateEngine {
public void setFreemarkerManager(FreemarkerManager mgr) {
this.freemarkerManager = mgr;
}
public void renderTemplate(TemplateRenderingContext templateContext) throws Exception {
// get the various items required from the stack
ValueStack stack = templateContext.getStack();
@@ -121,6 +121,10 @@ public class FreemarkerTemplateEngine extends BaseTemplateEngine {
ActionInvocation ai = ActionContext.getContext().getActionInvocation();
Object action = (ai == null) ? null : ai.getAction();
if (action == null) {
LOG.warn("Rendering tag {} out of Action scope, accessing directly JSPs is not recommended! " +
"Please read https://struts.apache.org/security/#never-expose-jsp-files-directly", templateName);
}
SimpleHash model = freemarkerManager.buildTemplateModel(stack, action, servletContext, req, res, config.getObjectWrapper());
model.put("tag", templateContext.getTag());
@@ -144,15 +148,20 @@ public class FreemarkerTemplateEngine extends BaseTemplateEngine {
}
};
LOG.debug("Puts action on the top of ValueStack, just before the tag");
action = stack.pop();
stack.push(templateContext.getTag());
stack.push(action);
try {
stack.push(templateContext.getTag());
template.process(model, writer);
} finally {
stack.pop();
stack.pop(); // removes action
stack.pop(); // removes tag
stack.push(action); // puts back action
}
}
protected String getSuffix() {
return "ftl";
}
}
}
@@ -97,6 +97,10 @@ public class DefaultDispatcherErrorHandler implements DispatcherErrorHandler {
response.sendError(code, e.getMessage());
} catch (IOException e1) {
// we're already sending an error, not much else we can do if more stuff breaks
LOG.warn("Unable to send error response, code: {};", code, e1);
} catch (IllegalStateException ise) {
// Log illegalstate instead of passing unrecoverable exception to calling thread
LOG.warn("Unable to send error response, code: {}; isCommited: {};", code, response.isCommitted(), ise);
}
}
@@ -122,6 +126,10 @@ public class DefaultDispatcherErrorHandler implements DispatcherErrorHandler {
response.sendError(code, "Unable to show problem report:\n" + exp + "\n\n" + LocationUtils.getLocation(exp));
} catch (IOException ex) {
// we're already sending an error, not much else we can do if more stuff breaks
LOG.warn("Unable to send error response, code: {};", code, ex);
} catch (IllegalStateException ise) {
// Log illegalstate instead of passing unrecoverable exception to calling thread
LOG.warn("Unable to send error response, code: {}; isCommited: {};", code, response.isCommitted(), ise);
}
}
}
@@ -218,7 +218,15 @@ public class DefaultStaticContentLoader implements StaticContentLoader {
}
}
response.sendError(HttpServletResponse.SC_NOT_FOUND);
try {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
} catch (IOException e1) {
// we're already sending an error, not much else we can do if more stuff breaks
LOG.warn("Unable to send error response, code: {};", HttpServletResponse.SC_NOT_FOUND, e1);
} catch (IllegalStateException ise) {
// Log illegalstate instead of passing unrecoverable exception to calling thread
LOG.warn("Unable to send error response, code: {}; isCommited: {};", HttpServletResponse.SC_NOT_FOUND, response.isCommitted(), ise);
}
}
protected void process(InputStream is, String path, HttpServletRequest request, HttpServletResponse response) throws IOException {
@@ -85,7 +85,7 @@ public class Dispatcher {
*/
public static final String REQUEST_POST_METHOD = "POST";
public static final String MULTIPART_FORM_DATA_REGEX = "^multipart/form-data(; boundary=[0-9a-zA-Z'()+_,\\-./:=?]{1,70})?(;charset=[a-zA-Z\\-0-9]{3,14})?";
public static final String MULTIPART_FORM_DATA_REGEX = "^multipart/form-data(?:\\s*;\\s*boundary=[0-9a-zA-Z'()+_,\\-./:=?]{1,70})?(?:\\s*;\\s*charset=[a-zA-Z\\-0-9]{3,14})?";
/**
* Provide a thread local instance.
@@ -582,8 +582,10 @@ public class Dispatcher {
logConfigurationException(request, e);
sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e);
} catch (Exception e) {
e.printStackTrace();
if (handleException || devMode) {
if (devMode) {
LOG.debug("Dispatcher serviceAction failed", e);
}
sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
} else {
throw new ServletException(e);
@@ -694,12 +696,23 @@ public class Dispatcher {
try {
locale = LocaleUtils.toLocale(defaultLocale);
} catch (IllegalArgumentException e) {
LOG.warn(new ParameterizedMessage("Cannot convert 'struts.locale' = [{}] to proper locale, defaulting to request locale [{}]",
defaultLocale, request.getLocale()), e);
locale = request.getLocale();
try {
locale = request.getLocale();
LOG.warn(new ParameterizedMessage("Cannot convert 'struts.locale' = [{}] to proper locale, defaulting to request locale [{}]",
defaultLocale, locale), e);
} catch (RuntimeException rex) {
LOG.warn(new ParameterizedMessage("Cannot convert 'struts.locale' = [{}] to proper locale, and cannot get locale from HTTP Request, falling back to system default locale",
defaultLocale), rex);
locale = Locale.getDefault();
}
}
} else {
locale = request.getLocale();
try {
locale = request.getLocale();
} catch (RuntimeException rex) {
LOG.warn("Cannot get locale from HTTP Request, falling back to system default locale", rex);
locale = Locale.getDefault();
}
}
return locale;
}
@@ -192,7 +192,34 @@ public class HttpParameters implements Map<String, Parameter>, Cloneable {
for (Map.Entry<String, Object> entry : requestParameterMap.entrySet()) {
String name = entry.getKey();
Object value = entry.getValue();
parameters.put(name, new Parameter.Request(name, value));
if (value instanceof Parameter) {
parameters.put(name, (Parameter) value);
} else {
parameters.put(name, new Parameter.Request(name, value));
}
}
return new HttpParameters(parameters);
}
/**
* Alternate Builder method which avoids wrapping any parameters that are already
* a {@link Parameter} element within another {@link Parameter} wrapper.
*
* @return
*/
public HttpParameters buildNoNestedWrapping() {
Map<String, Parameter> parameters = (parent == null)
? new HashMap<String, Parameter>()
: new HashMap<>(parent.parameters);
for (Map.Entry<String, Object> entry : requestParameterMap.entrySet()) {
String name = entry.getKey();
Object value = entry.getValue();
Parameter parameterValue = (value instanceof Parameter)
? (Parameter) value
: new Parameter.Request(name, value);
parameters.put(name, parameterValue);
}
return new HttpParameters(parameters);
@@ -74,6 +74,8 @@ import java.util.Map;
public class ActionMappingParametersInterceptor extends ParametersInterceptor {
/**
* Get the parameter map from ActionMapping associated with the provided ActionContext.
*
* @param ac The action context
* @return the parameters from the action mapping in the context. If none found, returns an empty map.
*/
@@ -81,27 +83,25 @@ public class ActionMappingParametersInterceptor extends ParametersInterceptor {
protected HttpParameters retrieveParameters(ActionContext ac) {
ActionMapping mapping = (ActionMapping) ac.get(ServletActionContext.ACTION_MAPPING);
if (mapping != null) {
return HttpParameters.create(mapping.getParams()).build();
return HttpParameters.create(mapping.getParams()).buildNoNestedWrapping();
} else {
return HttpParameters.create().build();
return HttpParameters.create().buildNoNestedWrapping();
}
}
/**
* Adds the parameters into context's ParameterMap
* Adds the parameters into the current ActionContext's parameter map.
*
* Note: The method should avoid re-wrapping values which are already of type Parameter.
*
* @param ac The action context
* @param newParams The parameter map to apply
* <p>
* In this class this is a no-op, since the parameters were fetched from the same location.
* In subclasses both retrieveParameters() and addParametersToContext() should be overridden.
* </p>
*/
@Override
protected void addParametersToContext(ActionContext ac, Map<String, ?> newParams) {
HttpParameters previousParams = ac.getParameters();
HttpParameters.Builder combinedParams = HttpParameters.create().withParent(previousParams).withExtraParams(newParams);
ac.setParameters(combinedParams.build());
ac.setParameters(combinedParams.buildNoNestedWrapping());
}
}
@@ -343,6 +343,14 @@ public class FileUploadInterceptor extends AbstractInterceptor {
validation.addFieldError(inputName, errMsg);
}
if (LOG.isWarnEnabled()) {
LOG.warn(errMsg);
}
} else if (file.getContent() == null) {
String errMsg = getTextMessage(action, "struts.messages.error.uploading", new String[]{filename});
if (validation != null) {
validation.addFieldError(inputName, errMsg);
}
if (LOG.isWarnEnabled()) {
LOG.warn(errMsg);
}
@@ -29,7 +29,7 @@ import java.util.Map;
/**
* Just as the CheckboxInterceptor checks that if only the hidden field is present, so too does this interceptor. If
* the "__multiselect_" request parameter is present and its visible counterpart is not, set a new request parameter to an
* empty Sting.
* empty String.
*/
public class MultiselectInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 1L;
@@ -37,7 +37,7 @@ public class MultiselectInterceptor extends AbstractInterceptor {
/**
* Just as the CheckboxInterceptor checks that if only the hidden field is present, so too does this interceptor.
* If the "__multiselect_" request parameter is present and its visible counterpart is not, set a new request parameter
* to an empty Sting.
* to an empty String.
*
* @param ai ActionInvocation
* @return the result of the action
@@ -112,6 +112,20 @@ public class TokenSessionStoreInterceptor extends TokenInterceptor {
}
}
/**
* Handles processing of invalid tokens. If a previously stored invocation is
* available, the method will attempt to return and render its result. Otherwise
* it will return INVALID_TOKEN_CODE.
*
* Note: Because a stored (previously completed) invocation's PageContext will be closed,
* this method must replace the stored PageContext with the current invocation's one (or a null).
* See {@link org.apache.struts2.util.InvocationSessionStore#loadInvocation(String key, String token)} for details.
*
* @param invocation
*
* @return
* @throws Exception
*/
@Override
protected String handleInvalidToken(ActionInvocation invocation) throws Exception {
ActionContext ac = invocation.getInvocationContext();
@@ -126,11 +140,11 @@ public class TokenSessionStoreInterceptor extends TokenInterceptor {
params.remove(tokenName);
params.remove(TokenHelper.TOKEN_NAME_FIELD);
String sessionTokenName = TokenHelper.buildTokenSessionAttributeName(tokenName);
String sessionTokenName = TokenHelper.buildTokenSessionAttributeName(tokenName);
ActionInvocation savedInvocation = InvocationSessionStore.loadInvocation(sessionTokenName, token);
if (savedInvocation != null) {
// set the valuestack to the request scope
// set the savedInvocation's valuestack to the request scope
ValueStack stack = savedInvocation.getStack();
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
@@ -153,13 +167,23 @@ public class TokenSessionStoreInterceptor extends TokenInterceptor {
return INVALID_TOKEN_CODE;
}
/**
* Handles processing of valid tokens. Stores the current invocation for
* later use by {@link handleInvalidToken}.
* See {@link org.apache.struts2.util.InvocationSessionStore#storeInvocation(String key, String token, ActionInvocation invocation)} for details.
*
* @param invocation
*
* @return
* @throws Exception
*/
@Override
protected String handleValidToken(ActionInvocation invocation) throws Exception {
// we know the token name and token must be there
String key = TokenHelper.getTokenName();
String token = TokenHelper.getToken(key);
String sessionTokenName = TokenHelper.buildTokenSessionAttributeName(key);
InvocationSessionStore.storeInvocation(sessionTokenName, token, invocation);
String sessionTokenName = TokenHelper.buildTokenSessionAttributeName(key);
InvocationSessionStore.storeInvocation(sessionTokenName, token, invocation);
return invocation.invoke();
}
@@ -149,7 +149,7 @@ public class PostbackResult extends StrutsResultSupport {
} else {
String location = getLocation();
// Do not prepend if the URL is a FQN
if (!location.matches("^([a-zA-z]+:)?//.*")) {
if (!location.matches("^([a-zA-Z]+:)?//.*")) {
// If the URL is relative to the servlet context, prepend the servlet context path
if (prependServletContext && (request.getContextPath() != null) && (request.getContextPath().length() > 0)) {
location = request.getContextPath() + location;
@@ -250,13 +250,24 @@ public class ServletRedirectResult extends StrutsResultSupport implements Reflec
* @throws IOException in case of IO errors
*/
protected void sendRedirect(HttpServletResponse response, String finalLocation) throws IOException {
if (SC_FOUND == statusCode) {
response.sendRedirect(finalLocation);
} else {
response.setStatus(statusCode);
response.setHeader("Location", finalLocation);
response.getWriter().write(finalLocation);
response.getWriter().close();
try {
if (SC_FOUND == statusCode) {
response.sendRedirect(finalLocation);
} else {
response.setStatus(statusCode);
response.setHeader("Location", finalLocation);
try {
response.getWriter().write(finalLocation);
} finally {
response.getWriter().close();
}
}
} catch (IOException ioe) {
LOG.warn("Unable to redirect to: {}, code: {}; {}", finalLocation, statusCode, ioe);
throw ioe; // Re-throw required to preserve existing default behaviour (no stacktrace in above warn for this reason)
} catch (IllegalStateException ise) {
LOG.warn("Unable to redirect to: {}, code: {}; isCommited: {}; {}", finalLocation, statusCode, response.isCommitted(), ise);
throw ise; // Re-throw required to preserve existing default behaviour (no stacktrace in above warn for this reason)
}
}
@@ -20,6 +20,7 @@ package org.apache.struts2.util;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import org.apache.struts2.ServletActionContext;
import java.io.Serializable;
import java.util.HashMap;
@@ -55,11 +56,20 @@ public class InvocationSessionStore {
return null;
}
ActionInvocation savedInvocation = null;
if (invocationContext.invocation != null) {
savedInvocation = invocationContext.invocation;
ActionContext.setContext(savedInvocation.getInvocationContext());
ActionContext.getContext().setValueStack(savedInvocation.getStack());
final ActionInvocation savedInvocation = invocationContext.invocation;
if (savedInvocation != null) {
// WW-5026 - Preserve the previous PageContext (even if null) and restore it to the
// ActionContext after loading the savedInvocation context. The saved context's PageContext
// would already be closed at this point (causing failures if used for output).
final ActionContext savedActionContext = savedInvocation.getInvocationContext();
final ActionContext previousActionContext = ActionContext.getContext();
ActionContext.setContext(savedActionContext);
savedActionContext.setValueStack(savedInvocation.getStack());
if (previousActionContext != null) {
savedActionContext.put(ServletActionContext.PAGE_CONTEXT, previousActionContext.get(ServletActionContext.PAGE_CONTEXT));
} else {
savedActionContext.put(ServletActionContext.PAGE_CONTEXT, null);
}
}
return savedInvocation;
@@ -68,9 +68,13 @@ public class SetTag extends ContextBeanTag {
@Override
protected String getBody() {
if (trimBody) {
return super.getBody();
if (bodyContent == null) {
return null;
} else {
return bodyContent.getString().trim();
}
} else {
return (bodyContent == null ? "" : bodyContent.getString());
return (bodyContent == null ? null : bodyContent.getString());
}
}
}
@@ -18,9 +18,7 @@
*/
package org.apache.struts2.views.jsp.ui;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.struts2.components.UIBean;
import org.apache.struts2.util.ComponentUtils;
import org.apache.struts2.views.jsp.ComponentTagSupport;
import javax.servlet.jsp.JspException;
@@ -40,7 +38,7 @@ public abstract class AbstractUITag extends ComponentTagSupport implements Dynam
protected String disabled;
protected String label;
protected String labelSeparator;
protected String labelposition;
protected String labelPosition;
protected String requiredPosition;
protected String errorPosition;
protected String name;
@@ -78,7 +76,7 @@ public abstract class AbstractUITag extends ComponentTagSupport implements Dynam
protected String tooltipIconPath;
// dynamic attributes.
protected Map<String, Object> dynamicAttributes = new HashMap<>();
protected Map<String, String> dynamicAttributes = new HashMap<>();
protected void populateParams() {
super.populateParams();
@@ -92,7 +90,7 @@ public abstract class AbstractUITag extends ComponentTagSupport implements Dynam
uiBean.setDisabled(disabled);
uiBean.setLabel(label);
uiBean.setLabelSeparator(labelSeparator);
uiBean.setLabelposition(labelposition);
uiBean.setLabelPosition(labelPosition);
uiBean.setRequiredPosition(requiredPosition);
uiBean.setErrorPosition(errorPosition);
uiBean.setName(name);
@@ -137,6 +135,10 @@ public abstract class AbstractUITag extends ComponentTagSupport implements Dynam
this.cssClass = cssClass;
}
/**
* @deprecated Use {@link #setCssClass(String)} instead
*/
@Deprecated
public void setClass(String cssClass) {
this.cssClass = cssClass;
}
@@ -169,8 +171,17 @@ public abstract class AbstractUITag extends ComponentTagSupport implements Dynam
this.label = label;
}
/**
* Deprecated since 2.5.27
* @deprecated use {@link #setLabelPosition(String)} instead
*/
@Deprecated
public void setLabelposition(String labelPosition) {
this.labelposition = labelPosition;
this.labelPosition = labelPosition;
}
public void setLabelPosition(String labelPosition) {
this.labelPosition = labelPosition;
}
public void setRequiredPosition(String requiredPosition) {
@@ -302,11 +313,7 @@ public abstract class AbstractUITag extends ComponentTagSupport implements Dynam
}
public void setDynamicAttribute(String uri, String localName, Object value) throws JspException {
if (ComponentUtils.altSyntax(getStack()) && ComponentUtils.isExpression(value.toString())) {
dynamicAttributes.put(localName, String.valueOf(ObjectUtils.defaultIfNull(findValue(value.toString()), value)));
} else {
dynamicAttributes.put(localName, value);
}
dynamicAttributes.put(localName, String.valueOf(value));
}
}
@@ -18,13 +18,12 @@
*/
package org.apache.struts2.views.jsp.ui;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.struts2.components.Checkbox;
import org.apache.struts2.components.Component;
import com.opensymphony.xwork2.util.ValueStack;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @see Checkbox
@@ -23,12 +23,16 @@ import ognl.OgnlException;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.ognl.OgnlUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* FIXME: remove?
*/
public class OgnlTool {
private static final Logger LOG = LogManager.getLogger(OgnlTool.class);
private OgnlUtil ognlUtil;
public OgnlTool() {
@@ -43,6 +47,9 @@ public class OgnlTool {
try {
return Ognl.getValue(ognlUtil.compile(expr), context);
} catch (OgnlException e) {
if (e.getReason() instanceof SecurityException) {
LOG.warn("Could not evaluate this expression due to security constraints: [{}]", expr, e);
}
return null;
}
}
@@ -219,4 +219,15 @@ struts.ognl.enableExpressionCache=true
### Indicates if Dispatcher should handle unexpected exceptions by calling sendError()
### or simply rethrow it as a ServletException to allow future processing by other frameworks like Spring Security
struts.handle.exception=true
### Applies maximum length allowed on OGNL expressions for security enhancement (optional)
###
### **WARNING**: If developers enable this option (by configuration) they should make sure that they understand the implications of setting
### struts.ognl.expressionMaxLength. They must choose a value large enough to permit ALL valid OGNL expressions used within the application.
### Values larger than the 200-400 range have diminishing security value (at which point it is really only a "style guard" for long OGNL
### expressions in an application. Setting a value of null or "" will also disable the feature.
###
### NOTE: The sample line below is *INTENTIONALLY* commented out, as this feature is disabled by default.
# struts.ognl.expressionMaxLength=256
### END SNIPPET: complete_file
+22 -1
View File
@@ -45,6 +45,7 @@
java.lang.ClassLoader,
java.lang.Shutdown,
java.lang.ProcessBuilder,
sun.misc.Unsafe,
com.opensymphony.xwork2.ActionContext" />
<!-- this must be valid regex, each '.' in package name must be escaped! -->
@@ -55,16 +56,36 @@
<constant name="struts.excludedPackageNames"
value="
ognl.,
java.io.,
java.net.,
java.nio.,
javax.,
freemarker.core.,
freemarker.template.,
freemarker.ext.jsp.,
freemarker.ext.rhino.,
sun.misc.,
sun.reflect.,
javassist.,
org.apache.velocity.,
org.objectweb.asm.,
org.springframework.context.,
com.opensymphony.xwork2.inject.,
com.opensymphony.xwork2.ognl.,
com.opensymphony.xwork2.security.,
com.opensymphony.xwork2.util." />
com.opensymphony.xwork2.util.,
org.apache.tomcat.,
org.apache.catalina.core.,
com.ibm.websphere.,
org.apache.geronimo.,
org.apache.openejb.,
org.apache.tomee.,
org.eclipse.jetty.,
org.mortbay.jetty.,
org.glassfish.,
org.jboss.as.,
org.wildfly.,
weblogic.," />
<bean class="com.opensymphony.xwork2.ObjectFactory" name="struts"/>
<bean type="com.opensymphony.xwork2.factory.ResultFactory" name="struts" class="org.apache.struts2.factory.StrutsResultFactory" />
@@ -24,16 +24,16 @@
#set ($hasFieldErrors = $fieldErrors.get($parameters.name))
#foreach ($error in $fieldErrors.get($parameters.name))
<tr errorFor="$parameters.id">
#if ($parameters.labelposition == 'top')<td align="left" valign="top" colspan="2">#else<td align="center" valign="top" colspan="2">#end<span class="errorMessage">$!struts.htmlEncode($error)</span></td>
#if ($parameters.labelPosition == 'top')<td align="left" valign="top" colspan="2">#else<td align="center" valign="top" colspan="2">#end<span class="errorMessage">$!struts.htmlEncode($error)</span></td>
</tr>
#end
#end
## if the label position is top,
## then give the label it's own row in the table
<tr>
#if ($parameters.labelposition && $parameters.labelposition == 'top')<td align="left" valign="top" colspan="2">#else<td align="right" valign="top">#end#if ($parameters.label)<label #if ($parameters.id) for="$!struts.htmlEncode($parameters.id)"#end#if ($hasFieldErrors) class="errorLabel"#else class="label"#end>#if ($parameters.required)<span class="required">*</span>#end$!struts.htmlEncode($parameters.label):</label>#end</td>
#if ($parameters.labelPosition && $parameters.labelPosition == 'top')<td align="left" valign="top" colspan="2">#else<td align="right" valign="top">#end#if ($parameters.label)<label #if ($parameters.id) for="$!struts.htmlEncode($parameters.id)"#end#if ($hasFieldErrors) class="errorLabel"#else class="label"#end>#if ($parameters.required)<span class="required">*</span>#end$!struts.htmlEncode($parameters.label):</label>#end</td>
## add the extra row
#if ($parameters.labelposition && $parameters.labelposition == 'top')
#if ($parameters.labelPosition && $parameters.labelPosition == 'top')
</tr>
<tr>
#end
@@ -23,12 +23,12 @@ NOTE: The 'header' stuff that follows is in this one file for checkbox due to th
that for checkboxes we do not want the label field to show up as checkboxes handle their own
lables
-->
<#assign hasFieldErrors = fieldErrors?? && fieldErrors[parameters.name]??/>
<#assign hasFieldErrors = fieldErrors?? && fieldErrors.get(parameters.name)??/>
<div <#rt/><#if parameters.id??>id="wwgrp_${parameters.id}"<#rt/></#if> class="wwgrp">
<#if hasFieldErrors>
<div <#rt/><#if parameters.id??>id="wwerr_${parameters.id}"<#rt/></#if> class="wwerr">
<#list fieldErrors[parameters.name] as error>
<#list fieldErrors.get(parameters.name) as error>
<div<#rt/>
<#if parameters.id??>
errorFor="${parameters.id}"<#rt/>
@@ -39,12 +39,12 @@ lables
</#list>
</div><#t/>
</#if>
<#if !parameters.labelposition?? && (parameters.form.labelposition)??>
<#assign labelpos = parameters.form.labelposition/>
<#elseif parameters.labelposition??>
<#assign labelpos = parameters.labelposition/>
<#if !parameters.labelPosition?? && (parameters.form.labelPosition)??>
<#assign labelPos = parameters.form.labelPosition/>
<#elseif parameters.labelPosition??>
<#assign labelPos = parameters.labelPosition/>
</#if>
<#if (labelpos!"") == 'left'>
<#if (labelPos!"") == 'left'>
<span <#rt/>
<#if parameters.id??>id="wwlbl_${parameters.id}"<#rt/></#if> class="wwlbl">
<label<#t/>
@@ -60,7 +60,7 @@ lables
</span>
</#if>
<#if (labelpos!"top") == 'top'>
<#if (labelPos!"top") == 'top'>
<div <#rt/>
<#else>
<span <#rt/>
@@ -72,14 +72,14 @@ lables
</#if>
<#include "/${parameters.templateDir}/simple/checkbox.ftl" />
<#if (labelpos!"") != 'left'>
<#if (labelpos!"top") == 'top'>
<#if (labelPos!"") != 'left'>
<#if (labelPos!"top") == 'top'>
</div> <#rt/>
<#else>
</span> <#rt/>
</#if>
<#if parameters.label??>
<#if (labelpos!"top") == 'top'>
<#if (labelPos!"top") == 'top'>
<div <#rt/>
<#else>
<span <#rt/>
@@ -98,7 +98,7 @@ lables
</#if>
</#if>
<#if parameters.label??>
<#if (labelpos!"top") == 'top'>
<#if (labelPos!"top") == 'top'>
</div> <#rt/>
<#else>
</span> <#rt/>
@@ -20,21 +20,21 @@
-->
${parameters.after!}<#t/>
<#lt/>
<#if !parameters.labelposition?? && (parameters.form.labelposition)??>
<#assign labelpos = parameters.form.labelposition/>
<#elseif parameters.labelposition??>
<#assign labelpos = parameters.labelposition/>
<#if !parameters.labelPosition?? && (parameters.form.labelPosition)??>
<#assign labelPos = parameters.form.labelPosition/>
<#elseif parameters.labelPosition??>
<#assign labelPos = parameters.labelPosition/>
</#if>
<#if (labelpos!"top") == 'top'>
<#if (labelPos!"top") == 'top'>
</div> <#rt/>
<#else>
</span> <#rt/>
</#if>
<#if (parameters.errorposition!"top") == 'bottom'>
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/>
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors.get(parameters.name)??/>
<#if hasFieldErrors>
<div <#rt/><#if parameters.id??>id="wwerr_${parameters.id}"<#rt/></#if> class="wwerr">
<#list fieldErrors[parameters.name] as error>
<#list fieldErrors.get(parameters.name) as error>
<div<#rt/>
<#if parameters.id??>
errorFor="${parameters.id}"<#rt/>
@@ -46,4 +46,4 @@ ${parameters.after!}<#t/>
</div><#t/>
</#if>
</#if>
</div>
</div>
@@ -22,13 +22,13 @@
Only show message if errors are available.
This will be done if ActionSupport is used.
-->
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/>
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors.get(parameters.name)??/>
<div <#rt/><#if parameters.id??>id="wwgrp_${parameters.id}"<#rt/></#if> class="wwgrp">
<#if (parameters.errorposition!"top") == 'top'>
<#if hasFieldErrors>
<div <#rt/><#if parameters.id??>id="wwerr_${parameters.id}"<#rt/></#if> class="wwerr">
<#list fieldErrors[parameters.name] as error>
<#list fieldErrors.get(parameters.name) as error>
<div<#rt/>
<#if parameters.id??>
errorFor="${parameters.id}"<#rt/>
@@ -41,13 +41,13 @@
</#if>
</#if>
<#if !parameters.labelposition?? && (parameters.form.labelposition)??>
<#assign labelpos = parameters.form.labelposition/>
<#elseif parameters.labelposition??>
<#assign labelpos = parameters.labelposition/>
<#if !parameters.labelPosition?? && (parameters.form.labelPosition)??>
<#assign labelPos = parameters.form.labelPosition/>
<#elseif parameters.labelPosition??>
<#assign labelPos = parameters.labelPosition/>
</#if>
<#if parameters.label??>
<#if (labelpos!"top") == 'top'>
<#if (labelPos!"top") == 'top'>
<div <#rt/>
<#else>
<span <#rt/>
@@ -69,7 +69,7 @@
${parameters.label?html}${parameters.labelseparator!":"?html}
<#include "/${parameters.templateDir}/xhtml/tooltip.ftl" />
</label><#t/>
<#if (labelpos!"top") == 'top'>
<#if (labelPos!"top") == 'top'>
</div> <br /><#rt/>
<#else>
</span> <#rt/>
@@ -19,15 +19,14 @@
*/
-->
<#include "/${parameters.templateDir}/${parameters.expandTheme}/controlheader-core.ftl">
<#if !parameters.labelposition?? && (parameters.form.labelposition)??>
<#assign labelpos = parameters.form.labelposition/>
<#elseif parameters.labelposition??>
<#assign labelpos = parameters.labelposition/>
<#if !parameters.labelPosition?? && (parameters.form.labelPosition)??>
<#assign labelPos = parameters.form.labelPosition/>
<#elseif parameters.labelPosition??>
<#assign labelPos = parameters.labelPosition/>
</#if>
<#if (labelpos!"top") == 'top'>
<#if (labelPos!"top") == 'top'>
<div <#rt/>
<#else>
<span <#rt/>
</#if>
<#if parameters.id??>id="wwctrl_${parameters.id}"<#rt/></#if> class="wwctrl">
@@ -18,12 +18,12 @@
* under the License.
*/
-->
<#if !parameters.labelposition?? && (parameters.form.labelposition)??>
<#assign labelpos = parameters.form.labelposition/>
<#elseif parameters.labelposition??>
<#assign labelpos = parameters.labelposition/>
<#if !parameters.labelPosition?? && (parameters.form.labelPosition)??>
<#assign labelPos = parameters.form.labelPosition/>
<#elseif parameters.labelPosition??>
<#assign labelPos = parameters.labelPosition/>
</#if>
<#if (labelpos!"top") == 'top'>
<#if (labelPos!"top") == 'top'>
<div <#rt/>
<#else>
<span <#rt/>
@@ -34,7 +34,7 @@
</#if>
><#t/>
<#include "/${parameters.templateDir}/simple/reset.ftl" />
<#if (labelpos!"top") == 'top'>
<#if (labelPos!"top") == 'top'>
</div> <#t/>
<#else>
</span> <#t/>
@@ -19,12 +19,12 @@
*/
-->
<#include "/${parameters.templateDir}/simple/submit-close.ftl" />
<#if !parameters.labelposition?? && (parameters.form.labelposition)??>
<#assign labelpos = parameters.form.labelposition/>
<#elseif parameters.labelposition??>
<#assign labelpos = parameters.labelposition/>
<#if !parameters.labelPosition?? && (parameters.form.labelPosition)??>
<#assign labelPos = parameters.form.labelPosition/>
<#elseif parameters.labelPosition??>
<#assign labelPos = parameters.labelPosition/>
</#if>
<#if (labelpos!"top") == 'top'>
<#if (labelPos!"top") == 'top'>
</div> <#t/>
<#else>
</span> <#t/>
@@ -18,12 +18,12 @@
* under the License.
*/
-->
<#if !parameters.labelposition?? && (parameters.form.labelposition)??>
<#assign labelpos = parameters.form.labelposition/>
<#elseif parameters.labelposition??>
<#assign labelpos = parameters.labelposition/>
<#if !parameters.labelPosition?? && (parameters.form.labelPosition)??>
<#assign labelPos = parameters.form.labelPosition/>
<#elseif parameters.labelPosition??>
<#assign labelPos = parameters.labelPosition/>
</#if>
<#if (labelpos!"top") == 'top'>
<#if (labelPos!"top") == 'top'>
<div <#rt/>
<#else>
<span <#rt/>
@@ -18,7 +18,7 @@
* under the License.
*/
-->
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors[parameters.name]??/>
<#assign hasFieldErrors = parameters.name?? && fieldErrors?? && fieldErrors.get(parameters.name)??/>
<#if parameters.cssClass?has_content && !(hasFieldErrors && parameters.cssErrorClass??)>
class="${parameters.cssClass?html}"<#rt/>
<#elseif parameters.cssClass?has_content && (hasFieldErrors && parameters.cssErrorClass??)>
@@ -29,4 +29,4 @@
</#if>
${aKey}="${value?html}"<#rt/>
</#list><#rt/>
</#if><#rt/>
</#if><#rt/>
@@ -29,7 +29,7 @@
<#list eKeys as eKey><#t/>
<#if (eKey = fieldErrorFieldName)><#t/>
<#assign haveMatchedErrorField=true><#t/>
<#assign eValue = fieldErrors[fieldErrorFieldName]><#t/>
<#assign eValue = fieldErrors.get(fieldErrorFieldName)><#t/>
<#if (haveMatchedErrorField && (!doneStartUlTag))><#t/>
<ul<#rt/>
<#if parameters.id?has_content>
@@ -69,7 +69,7 @@
</#if>
>
<#list eKeys as eKey><#t/>
<#assign eValue = fieldErrors[eKey]><#t/>
<#assign eValue = fieldErrors.get(eKey)><#t/>
<#list eValue as eEachValue><#t/>
<li><span><#if parameters.escape>${eEachValue!?html}<#else>${eEachValue!}</#if></span></li>
</#list><#t/>
@@ -29,9 +29,12 @@
<#if parameters.listValueKey??>
<#-- checks the valueStack for the 'valueKey.' The valueKey is then looked-up in the locale
file for it's localized value. This is then used as a label -->
<#assign itemValue = stack.findString(parameters.listValueKey)/>
<#-- FIXME: find a better way to get the value than a call to @s.text -->
<#assign itemValue><@s.text name="${itemValue}"/></#assign>
<#assign valueKey = stack.findString(parameters.listValueKey)!''/>
<#if valueKey?has_content>
<#assign itemValue = struts.getText(valueKey) />
<#else>
<#assign itemValue = parameters.listValueKey />
</#if>
<#elseif parameters.listValue??>
<#assign itemValue = stack.findString(parameters.listValue)/>
<#else>
@@ -70,8 +70,8 @@
<#if parameters.listValueKey??>
<#-- checks the valueStack for the 'valueKey.' The valueKey is then looked-up in the locale file for it's
localized value. This is then used as a label -->
<#assign valueKey = stack.findString(parameters.listValueKey) />
<#if valueKey??>
<#assign valueKey = stack.findString(parameters.listValueKey)!'' />
<#if valueKey?has_content>
<#assign itemValue = struts.getText(valueKey) />
<#else>
<#assign itemValue = parameters.listValueKey />

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