Compare commits

..

49 Commits

Author SHA1 Message Date
Lukasz Lenart 981885fd6a [maven-release-plugin] prepare release STRUTS_6_0_0_RC4 2022-05-24 13:59:22 +02:00
Lukasz Lenart 07b88fcc35 Upgrades integration tests config to match Spring and Jetty 2022-05-24 09:51:42 +02:00
Lukasz Lenart 2cbe47297e Merge pull request #554 from gregh3269/More_localdatetime_support
Add basic LocalDateTime support WW-5175
2022-05-23 07:35:43 +02:00
Lukasz Lenart 545add9365 Merge pull request #553 from apache/WW-5179-max-length
[WW-5179] Set default value of struts.ognl.expressionMaxLength to 256
2022-05-23 07:34:17 +02:00
Lukasz Lenart ebecc7d39d Merge pull request #552 from apache/WW-5165-upgrade-spring
[WW-5165] Upgrades Spring to version 5.3.20
2022-05-23 07:34:05 +02:00
Greg Huber 226a1d49ce Add basic LocalDateTime support WW-5175 2022-05-20 11:47:08 +01:00
Greg Huber 075ef7c4e1 Add basic LocalDateTime support WW-5175 2022-05-19 10:30:36 +01:00
Lukasz Lenart 1237110652 WW-5179 Adjusts test to match new default value 2022-05-17 21:17:56 +02:00
Lukasz Lenart 3f2518afa8 WW-5179 Set default value of struts.ognl.expressionMaxLength to 256 2022-05-17 20:59:51 +02:00
Lukasz Lenart 9f9edf4705 WW-5165 Upgrades Spring to version 5.3.20 2022-05-17 07:37:39 +02:00
gregh3269 7e912742ed Basic LocalDateTime support (#532)
* Basic LocalDateTime support

* Basic LocalDateTime support

* Basic LocalDateTime support

* Basic LocalDateTime support

* Basic LocalDateTime support

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

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

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

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-04 08:52:18 +00:00
Lukasz Lenart d07a496d5c Uses common Maven Compiler plugin to set proper source and target version 2022-05-04 10:45:02 +02:00
Lukasz Lenart bef1f67d4a Upgrades Maven Jetty Plugin to work with JDK8+ 2022-05-04 10:44:54 +02:00
Lukasz Lenart 05ca1ff087 Ties cache extension points with implementation 2022-05-02 09:23:31 +02:00
JCgH4164838Gh792C124B5 199f356669 Update:
- Added some IDE-recommended annotations and cleanup to some of the
  modified files.
- Applied easier-to-read/differentiate names "ognlExpressionCacheFactory"
  and "ognlBeanInfoCacheFactory" for the cache factory configuration
   extension points.
- Reorded default configuration factory init for the cache factories (did
  not help extension override).
- Cleanup of parameterized OgnlUtil constructor.
- Added extension point aliases to StrutsBeanSelectionProvider.
- Added beaninfo for cache factories to ConstantConfig (did not help
  extension override).
- Added cache factory references to default.properties, struts-default.xml.
2022-05-01 16:25:16 -04:00
Lukasz Lenart e2718aa482 Enables branch autodeleting after PR has been merged 2022-04-07 14:43:38 +02:00
Lukasz Lenart b73fec4de0 Drops unused class 2022-04-04 17:12:33 +02:00
Lukasz Lenart c2795d2e30 Uses project specific folder 2022-03-28 13:09:21 +02:00
Lukasz Lenart a987e31a0e Upgrades OWASP Dependency Check plugin to version 7.0.1 2022-03-28 07:45:51 +02:00
Lukasz Lenart 6aff5b7faa WW-5174 Upgrades Jackson-Core to version 2.13.2 and Jackson-Databind to 2.13.2.1 2022-03-28 07:26:50 +02:00
JCgH4164838Gh792C124B5 084c66723d Update:
- Implement a no-parameter build method in OgnlCacheFactory.
- Update OgnlUtil to use no-parameter cache build method.
- Add an additional code coverage test.
2022-03-20 20:39:14 -04:00
Lukasz Lenart 5b40f9f48e WW-5172 Upgrades Freemarker to 2.3.31 version 2022-03-15 14:32:02 +01:00
Lukasz Lenart e9d0a5518c Cleans up code 2022-03-15 14:27:57 +01:00
JCgH4164838Gh792C124B5 4c37011020 Merge branch 'master' of https://github.com/JCgH4164838Gh792C124B5/struts into localS2_26_OgnlUtilOptionalCache1
# Conflicts:
#	core/src/main/java/com/opensymphony/xwork2/config/providers/StrutsDefaultConfigurationProvider.java
#	core/src/main/resources/struts-default.xml

Manually resolved conflicts.
2022-03-06 21:51:33 -05:00
JCgH4164838Gh792C124B5 fbb31ee65b Update:
- Refactored the cache design to utilize a factory pattern.
- Updated unit tests to match refactoring.
2022-03-06 21:18:21 -05:00
Lukasz Lenart c094052969 Uses Java Reflections instead BeanUtils to read property 2022-03-04 12:52:33 +01:00
Lukasz Lenart 84164c422e Drops unused dependency 2022-03-03 12:18:11 +01:00
Lukasz Lenart 8b11a3873a WW-5171 Upgrades Log4j to version 2.17.2 2022-03-01 08:10:00 +01:00
Lukasz Lenart 115fef2af7 [maven-release-plugin] prepare for next development iteration 2022-02-24 07:11:22 +01:00
JCgH4164838Gh792C124B5 4d8108e766 Update:
- Add support for an optional basic LRU cache for OGNL expressions and
  OGNL BeanInfo.
- Add support for cache limits applying to both normal and LRU caches.
  For a normal cache the entire cache will flush when the limit is reached.
- Add flags to allow switching between normal and LRU caches, and setting
  the maximum sizes.
2022-01-30 20:57:59 -05:00
108 changed files with 3171 additions and 1063 deletions
+4
View File
@@ -1,3 +1,4 @@
# Documentation https://s.apache.org/asfyaml
notifications:
commits: commits@struts.apache.org
# Send all issue emails (new, closed, comments) to issues@
@@ -8,3 +9,6 @@ notifications:
pullrequests_comment: issues@struts.apache.org
# Link opened PRs with JIRA
jira_options: link label worklog
github:
del_branch_on_merge: true
+1 -1
View File
@@ -14,5 +14,5 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.5/apache-maven-3.8.5-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
+4 -7
View File
@@ -14,17 +14,14 @@ global:
matrix:
include:
- jdk: oraclejdk8
env: STRUTS_IT=true # do integration tests and coverage reports when jdk7,9 and 11 tests prospered
env: STRUTS_IT=true # do integration tests and coverage reports when jdk 9 and 11 tests prospered
script:
- if [ "$STRUTS_IT" == "true" ]; then
./mvnw clean verify org.jacoco:jacoco-maven-plugin:report org.jacoco:jacoco-maven-plugin:report-integration org.eluder.coveralls:coveralls-maven-plugin:report -Ptravis-coveralls -DskipAssembly -B;
./mvnw clean install -DskipTests -DskipAssembly -B;
./mvnw test org.jacoco:jacoco-maven-plugin:report org.jacoco:jacoco-maven-plugin:report-integration org.eluder.coveralls:coveralls-maven-plugin:report -Ptravis-coveralls -DskipAssembly -B;
else
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
./mvnw test -DskipAssembly -B;
else
./mvnw test -DskipAssembly -Dupdate-impact -B;
fi;
./mvnw clean package test -DskipAssembly -B;
fi;
cache:
Vendored
+10 -10
View File
@@ -39,12 +39,12 @@ pipeline {
stages {
stage('Build') {
steps {
sh 'mvn -B clean install -DskipTests -DskipAssembly'
sh './mvnw -B clean install -DskipTests -DskipAssembly'
}
}
stage('Test') {
steps {
sh 'mvn -B test'
sh './mvnw -B test'
}
post {
always {
@@ -74,12 +74,12 @@ pipeline {
stages {
stage('Build') {
steps {
sh 'mvn -B clean install -DskipTests -DskipAssembly'
sh './mvnw -B clean install -DskipTests -DskipAssembly'
}
}
stage('Test') {
steps {
sh 'mvn -B test'
sh './mvnw -B test'
}
post {
always {
@@ -94,7 +94,7 @@ pipeline {
}
steps {
withCredentials([string(credentialsId: 'asf-struts-sonarcloud', variable: 'SONARCLOUD_TOKEN')]) {
sh 'mvn sonar:sonar -DskipAssembly -Dsonar.login=${SONARCLOUD_TOKEN}'
sh './mvnw sonar:sonar -DskipAssembly -Dsonar.login=${SONARCLOUD_TOKEN}'
}
}
}
@@ -119,12 +119,12 @@ pipeline {
stages {
stage('Build') {
steps {
sh 'mvn -B clean install -DskipTests -DskipAssembly'
sh './mvnw -B clean install -DskipTests -DskipAssembly'
}
}
stage('Test') {
steps {
sh 'mvn -B test'
sh './mvnw -B test'
// step([$class: 'JiraIssueUpdater', issueSelector: [$class: 'DefaultIssueSelector'], scm: scm])
}
post {
@@ -142,7 +142,7 @@ pipeline {
dir("local-snapshots-dir/") {
deleteDir()
}
sh 'mvn -B source:jar javadoc:jar -DskipAssembbly'
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly'
}
}
stage('Deploy Snapshot') {
@@ -151,7 +151,7 @@ pipeline {
}
steps {
withCredentials([file(credentialsId: 'lukaszlenart-repository-access-token', variable: 'CUSTOM_SETTINGS')]) {
sh 'mvn -s \${CUSTOM_SETTINGS} deploy'
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly'
}
}
}
@@ -165,7 +165,7 @@ pipeline {
configName: 'Nightlies',
transfers: [
sshTransfer(
remoteDirectory: '/x1/dist/struts',
remoteDirectory: '/struts/snapshot',
removePrefix: 'assembly/target/assembly/out',
sourceFiles: 'assembly/target/assembly/out/struts-*.zip'
)
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-apps</artifactId>
<packaging>pom</packaging>
+4 -4
View File
@@ -24,12 +24,12 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-apps</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-rest-showcase</artifactId>
<packaging>war</packaging>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
<name>Struts 2 Rest Showcase Webapp</name>
<description>Struts 2 Rest Showcase Example</description>
@@ -108,9 +108,9 @@
<finalName>struts2-rest-showcase</finalName>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.16.v20140903</version>
<version>9.4.46.v20220331</version>
<configuration>
<stopKey>CTRL+C</stopKey>
<stopPort>8999</stopPort>
+8 -20
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-apps</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-showcase</artifactId>
@@ -101,7 +101,7 @@
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
@@ -144,7 +144,7 @@
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.39.0</version>
<version>2.61.0</version>
<scope>test</scope>
</dependency>
@@ -155,15 +155,6 @@
<version>6.1.2.Final</version>
</dependency>
<!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
This is only necessary in tests-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
@@ -171,7 +162,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M4</version>
<version>3.0.0-M6</version>
<configuration>
<includes>
<include>it.org.apache.struts2.showcase.*Test</include>
@@ -193,16 +184,16 @@
</executions>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.16.v20140903</version>
<version>9.4.46.v20220331</version>
<configuration>
<stopKey>CTRL+C</stopKey>
<stopPort>8999</stopPort>
<systemProperties>
<systemProperty>
<name>log4j.configuration</name>
<value>file:${basedir}/src/main/resources/log4j.properties</value>
<value>file:${basedir}/src/main/resources/log4j2.xml</value>
</systemProperty>
<systemProperty>
<name>slf4j</name>
@@ -223,11 +214,8 @@
<goals>
<!-- stop any previous instance to free up the port -->
<goal>stop</goal>
<goal>run-forked</goal>
<goal>start</goal>
</goals>
<configuration>
<waitForChild>false</waitForChild>
</configuration>
</execution>
<execution>
<id>stop-jetty</id>
@@ -27,22 +27,24 @@ import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.interceptor.validation.SkipValidation;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.ScriptAssert;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import java.util.Date;
/**
* <!-- START SNIPPET: beanValidatationExample -->
*/
// <!-- START SNIPPET: beanValidationExample -->
@Namespace("/bean-validation")
@ParentPackage("bean-validation")
@Action(results = {
@Result(name = "input", location = "bean-validation.jsp"),
@Result(name = "success", location = "/WEB-INF/validation/successFieldValidatorsExample.jsp")
@Result(name = "input", location = "bean-validation.jsp"),
@Result(name = "success", location = "/WEB-INF/validation/successFieldValidatorsExample.jsp")
})
@FieldMatch(first = "fieldExpressionValidatorField", second = "requiredValidatorField", message = "requiredValidatorField and fieldExpressionValidatorField are not matching")
@ScriptAssert(lang = "javascript", script = "_this.dateValidatorField != null && _this.dateValidatorField.before(new java.util.Date())", message = "Date need to before now")
@@ -82,10 +84,10 @@ public class BeanValidationExampleAction extends ActionSupport {
private String fieldExpressionValidatorField = null;
@Action(value = "bean-validation", results = {
@Result(name = "success", location = "bean-validation.jsp")
@Result(name = "success", location = "bean-validation.jsp")
})
@SkipValidation
public String beanValidation(){
public String beanValidation() {
return SUCCESS;
}
@@ -150,7 +152,7 @@ public class BeanValidationExampleAction extends ActionSupport {
}
public void setFieldExpressionValidatorField(
String fieldExpressionValidatorField) {
String fieldExpressionValidatorField) {
this.fieldExpressionValidatorField = fieldExpressionValidatorField;
}
@@ -163,8 +165,4 @@ public class BeanValidationExampleAction extends ActionSupport {
}
}
/**
* <!-- END SNIPPET: beanValidatationExample -->
*/
// <!-- END SNIPPET: beanValidationExample -->
@@ -45,66 +45,46 @@
</bean>
<bean id="chatLoginAction" class="org.apache.struts2.showcase.chat.ChatLoginAction" scope="prototype">
<constructor-arg index="0">
<ref local="chatService"/>
</constructor-arg>
<constructor-arg index="0" ref="chatService"/>
</bean>
<bean id="chatLogoutAction" class="org.apache.struts2.showcase.chat.ChatLogoutAction" scope="prototype">
<constructor-arg index="0">
<ref local="chatService"/>
</constructor-arg>
<constructor-arg index="0" ref="chatService"/>
</bean>
<bean id="usersAvailableAction" class="org.apache.struts2.showcase.chat.UsersAvailableAction" scope="prototype">
<constructor-arg index="0">
<ref local="chatService"/>
</constructor-arg>
<constructor-arg index="0" ref="chatService"/>
</bean>
<bean id="roomsAvailableAction" class="org.apache.struts2.showcase.chat.RoomsAvailableAction" scope="prototype">
<constructor-arg index="0">
<ref local="chatService"/>
</constructor-arg>
<constructor-arg index="0" ref="chatService"/>
</bean>
<bean id="crudRoomAction" class="org.apache.struts2.showcase.chat.CrudRoomAction" scope="prototype">
<constructor-arg index="0">
<ref local="chatService"/>
</constructor-arg>
<constructor-arg index="0" ref="chatService"/>
</bean>
<bean id="enterRoomAction" class="org.apache.struts2.showcase.chat.EnterRoomAction" scope="prototype">
<constructor-arg index="0">
<ref local="chatService"/>
</constructor-arg>
<constructor-arg index="0" ref="chatService"/>
</bean>
<bean id="messagesAvailableInRoomAction" class="org.apache.struts2.showcase.chat.MessagesAvailableInRoomAction"
scope="prototype">
<constructor-arg index="0">
<ref local="chatService"/>
</constructor-arg>
<constructor-arg index="0" ref="chatService"/>
</bean>
<bean id="sendMessageToRoomAction" class="org.apache.struts2.showcase.chat.SendMessageToRoomAction"
scope="prototype">
<constructor-arg index="0">
<ref local="chatService"/>
</constructor-arg>
<constructor-arg index="0" ref="chatService"/>
</bean>
<bean id="usersAvailableInRoomAction" class="org.apache.struts2.showcase.chat.UsersAvailableInRoomAction"
scope="prototype">
<constructor-arg index="0">
<ref local="chatService"/>
</constructor-arg>
<constructor-arg index="0" ref="chatService"/>
</bean>
<bean id="exitRoomAction" class="org.apache.struts2.showcase.chat.ExitRoomAction" scope="prototype">
<constructor-arg index="0">
<ref local="chatService"/>
</constructor-arg>
<constructor-arg index="0" ref="chatService"/>
</bean>
@@ -129,9 +109,7 @@
</bean>
<bean id="startHangmanAction" class="org.apache.struts2.showcase.hangman.StartHangmanAction" scope="prototype">
<constructor-arg index="0">
<ref local="hangmanService"/>
</constructor-arg>
<constructor-arg index="0" ref="hangmanService"/>
</bean>
<bean id="guessCharacterAction" class="org.apache.struts2.showcase.hangman.GuessCharacterAction" scope="prototype"/>
@@ -32,7 +32,7 @@ public class ActionChainingTest {
try (final WebClient webClient = new WebClient()) {
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/actionchaining/actionChain1!input");
final String pageAsText = page.asText();
final String pageAsText = page.asNormalizedText();
Assert.assertTrue(pageAsText.contains("Action Chain 1 Property 1: Property Set In Action Chain 1"));
Assert.assertTrue(pageAsText.contains("Action Chain 2 Property 1: Property Set in Action Chain 2"));
Assert.assertTrue(pageAsText.contains("Action Chain 3 Property 1: Property set in Action Chain 3"));
@@ -32,7 +32,7 @@ public class ActionTagExampleTest {
try (final WebClient webClient = new WebClient()) {
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/tags/ui/actionTagExample!input.action");
final String pageAsText = page.asText();
final String pageAsText = page.asNormalizedText();
Assert.assertTrue(pageAsText.contains("This text is from the called class"));
}
}
@@ -46,7 +46,7 @@ public class AsyncTest {
final DomElement msgs = page2.getElementById("msgs");
Assert.assertEquals("hello", msgs.asText());
Assert.assertEquals("hello", msgs.asNormalizedText());
}
}
}
@@ -44,7 +44,7 @@ public class CRUDTest {
final HtmlSubmitInput button = form.getInputByValue("Save");
final HtmlPage page2 = button.click();
final String page2Text = page2.asText();
final String page2Text = page2.asNormalizedText();
Assert.assertTrue(page2Text.contains("somename1"));
Assert.assertTrue(page2Text.contains("somedescription1"));
@@ -33,7 +33,7 @@ public class ComponentTagExampleTest {
final HtmlPage page = webClient
.getPage(ParameterUtils.getBaseUrl() + "/tags/ui/componentTagExample.action");
final String pageAsText = page.asText();
final String pageAsText = page.asNormalizedText();
Assert.assertTrue(pageAsText.contains("Freemarker Custom Template - parameter 'paramName' - paramValue1"));
Assert.assertTrue(pageAsText.contains("Freemarker Custom Template - parameter 'paramName' - paramValue4"));
Assert.assertTrue(pageAsText.contains("JSP Custom Template - parameter 'paramName' - paramValue2"));
@@ -46,7 +46,7 @@ public class ConversionTest {
final HtmlSubmitInput button = form.getInputByValue("Submit");
final HtmlPage page2 = button.click();
final String page2Text = page2.asText();
final String page2Text = page2.asNormalizedText();
Assert.assertTrue(page2Text.contains("SET 0 Name: name0"));
Assert.assertTrue(page2Text.contains("SET 0 Age: 0"));
@@ -71,7 +71,7 @@ public class ConversionTest {
final HtmlSubmitInput button = form.getInputByValue("Submit");
final HtmlPage page2 = button.click();
final String page2Text = page2.asText();
final String page2Text = page2.asNormalizedText();
Assert.assertTrue(page2Text.contains("id0 -> address0"));
Assert.assertTrue(page2Text.contains("id1 -> address1"));
@@ -92,7 +92,7 @@ public class ConversionTest {
final HtmlSubmitInput button = form.getInputByValue("Submit");
final HtmlPage page2 = button.click();
final String page2Text = page2.asText();
final String page2Text = page2.asNormalizedText();
Assert.assertTrue(page2Text.contains("ADD"));
Assert.assertTrue(page2Text.contains("MINUS"));
@@ -43,12 +43,12 @@ public class ExecAndWaitTest {
final HtmlSubmitInput button = form.getInputByValue("submit");
final HtmlPage page2 = button.click();
Assert.assertTrue(page2.asText().contains("We are processing your request. Please wait."));
Assert.assertTrue(page2.asNormalizedText().contains("We are processing your request. Please wait."));
// hit it again
final HtmlPage page3 = webClient
.getPage(ParameterUtils.getBaseUrl() + "/wait/longProcess1.action?time=1000");
Assert.assertTrue(page3.asText().contains("We are processing your request. Please wait."));
Assert.assertTrue(page3.asNormalizedText().contains("We are processing your request. Please wait."));
}
}
}
@@ -43,6 +43,7 @@ public class FileDownloadTest {
}
}
@Test
public void testZip() throws Exception {
try (final WebClient webClient = new WebClient()) {
final Page page = webClient.getPage(ParameterUtils.getBaseUrl() + "/filedownload/download2.action");
@@ -36,11 +36,11 @@ public class FreeMarkerManagerTest {
final DomElement date = page.getElementById("todaysDate");
Assert.assertNotNull(date);
Assert.assertTrue(date.asText().length() > 0);
Assert.assertTrue(date.asNormalizedText().length() > 0);
final DomElement time = page.getElementById("timeNow");
Assert.assertNotNull(time);
Assert.assertTrue(time.asText().length() > 0);
Assert.assertTrue(time.asNormalizedText().length() > 0);
}
}
@@ -33,26 +33,23 @@ public class StaticContentTest {
webClient.getPage(ParameterUtils.getBaseUrl() + "/struts..");
Assert.fail("Previous request should have failed");
} catch (FailingHttpStatusCodeException e) {
Assert.assertEquals("Not Found", e.getStatusMessage());
Assert.assertEquals(404, e.getStatusCode());
}
}
}
@Test
public void testInvalidRersources2() throws Exception {
try (final WebClient webClient = new WebClient()) {
try {
webClient.getPage(ParameterUtils.getBaseUrl() + "/static/..%252f");
Assert.fail("Previous request should have failed");
} catch (FailingHttpStatusCodeException e) {
Assert.assertEquals("Not Found", e.getStatusMessage());
Assert.assertEquals(404, e.getStatusCode());
}
}
}
/*public void testInvalidRersources3() throws IOException {
try {
beginAt("/static/..%252f..%252f..%252fWEB-INF/classes/org/apache/struts2/showcase/action/EmployeeAction.class/");
fail("Previous request should have failed");
} catch (TestingEngineResponseException ex) {
// ok
}
}*/
}
@@ -65,11 +65,11 @@ public class UITagExampleTest {
final HtmlSubmitInput button = form.getInputByValue("Submit");
final HtmlPage page2 = button.click();
Assert.assertEquals("name", page2.getElementById("name").asText());
Assert.assertEquals("bio", page2.getElementById("bio").asText());
Assert.assertEquals("Red", page2.getElementById("favouriteColor").asText());
Assert.assertEquals("[Patrick, Jason]", page2.getElementById("friends").asText());
Assert.assertEquals("true", page2.getElementById("legalAge").asText());
Assert.assertEquals("name", page2.getElementById("name").asNormalizedText());
Assert.assertEquals("bio", page2.getElementById("bio").asNormalizedText());
Assert.assertEquals("Red", page2.getElementById("favouriteColor").asNormalizedText());
Assert.assertEquals("[Patrick, Jason]", page2.getElementById("friends").asNormalizedText());
Assert.assertEquals("true", page2.getElementById("legalAge").asNormalizedText());
}
}
}
@@ -47,7 +47,7 @@ public class ValidationTest {
final HtmlSubmitInput button = form.getInputByValue("Submit");
final HtmlPage page2 = button.click();
final String page2Text = page2.asText();
final String page2Text = page2.asNormalizedText();
Assert.assertTrue(page2Text.contains("Invalid field value for field \"dateValidatorField\""));
Assert.assertTrue(page2Text.contains("Invalid field value for field \"integerValidatorField\""));
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-assembly</artifactId>
+3 -3
View File
@@ -29,7 +29,7 @@
</parent>
<artifactId>struts2-bom</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
<packaging>pom</packaging>
<name>Struts 2 Bill of Materials</name>
@@ -44,7 +44,7 @@
</licenses>
<properties>
<struts-version.version>6.0.0-RC3</struts-version.version>
<struts-version.version>6.0.0-RC4</struts-version.version>
<maven.site.skip>true</maven.site.skip>
<maven.site.deploy.skip>true</maven.site.deploy.skip>
</properties>
@@ -175,7 +175,7 @@
</dependencyManagement>
<scm>
<tag>STRUTS_6_0_0_RC3</tag>
<tag>STRUTS_6_0_0_RC4</tag>
<connection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</connection>
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</developerConnection>
<url>https://github.com/apache/struts/</url>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-osgi-bundles</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-osgi-admin-bundle</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-osgi-bundles</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-osgi-demo-bundle</artifactId>
+2 -4
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-osgi-bundles</artifactId>
@@ -53,12 +53,10 @@
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<reporting>
+12 -11
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-core</artifactId>
<packaging>jar</packaging>
@@ -188,7 +188,7 @@
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
@@ -242,6 +242,16 @@
<artifactId>spring-web</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
@@ -345,15 +355,6 @@
<scope>test</scope>
</dependency>
<!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
This is only necessary in tests-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
@@ -28,6 +28,10 @@ import com.opensymphony.xwork2.conversion.*;
import com.opensymphony.xwork2.conversion.impl.*;
import com.opensymphony.xwork2.factory.*;
import com.opensymphony.xwork2.inject.*;
import com.opensymphony.xwork2.ognl.BeanInfoCacheFactory;
import com.opensymphony.xwork2.ognl.DefaultOgnlBeanInfoCacheFactory;
import com.opensymphony.xwork2.ognl.DefaultOgnlExpressionCacheFactory;
import com.opensymphony.xwork2.ognl.ExpressionCacheFactory;
import com.opensymphony.xwork2.ognl.OgnlReflectionProvider;
import com.opensymphony.xwork2.ognl.OgnlUtil;
import com.opensymphony.xwork2.ognl.OgnlValueStackFactory;
@@ -79,30 +83,37 @@ public class DefaultConfiguration implements Configuration {
}
@Override
public PackageConfig getPackageConfig(String name) {
return packageContexts.get(name);
}
@Override
public List<UnknownHandlerConfig> getUnknownHandlerStack() {
return unknownHandlerStack;
}
@Override
public void setUnknownHandlerStack(List<UnknownHandlerConfig> unknownHandlerStack) {
this.unknownHandlerStack = unknownHandlerStack;
}
@Override
public Set<String> getPackageConfigNames() {
return packageContexts.keySet();
}
@Override
public Map<String, PackageConfig> getPackageConfigs() {
return packageContexts;
}
@Override
public Set<String> getLoadedFileNames() {
return loadedFileNames;
}
@Override
public RuntimeConfiguration getRuntimeConfiguration() {
return runtimeConfiguration;
}
@@ -110,10 +121,12 @@ public class DefaultConfiguration implements Configuration {
/**
* @return the container
*/
@Override
public Container getContainer() {
return container;
}
@Override
public void addPackageConfig(String name, PackageConfig packageContext) {
PackageConfig check = packageContexts.get(name);
if (check != null) {
@@ -131,6 +144,7 @@ public class DefaultConfiguration implements Configuration {
packageContexts.put(name, packageContext);
}
@Override
public PackageConfig removePackageConfig(String packageName) {
return packageContexts.remove(packageName);
}
@@ -138,11 +152,13 @@ public class DefaultConfiguration implements Configuration {
/**
* Allows the configuration to clean up any resources used
*/
@Override
public void destroy() {
packageContexts.clear();
loadedFileNames.clear();
}
@Override
public void rebuildRuntimeConfiguration() {
runtimeConfiguration = buildRuntimeConfiguration();
}
@@ -151,10 +167,12 @@ public class DefaultConfiguration implements Configuration {
* Calls the ConfigurationProviderFactory.getConfig() to tell it to reload the configuration and then calls
* buildRuntimeConfiguration().
*
* @param providers list of ContainerProvider
* @return list of package providers
*
* @throws ConfigurationException in case of any configuration errors
*/
@Override
public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException {
packageContexts.clear();
loadedFileNames.clear();
@@ -172,6 +190,7 @@ public class DefaultConfiguration implements Configuration {
props.setConstants(builder);
builder.factory(Configuration.class, new Factory<Configuration>() {
@Override
public Configuration create(Context context) throws Exception {
return DefaultConfiguration.this;
}
@@ -279,6 +298,8 @@ public class DefaultConfiguration implements Configuration {
builder.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON);
builder.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON);
builder.factory(ExpressionCacheFactory.class, "defaultOgnlExpressionCacheFactory", DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON);
builder.factory(BeanInfoCacheFactory.class, "defaultOgnlBeanInfoCacheFactory", DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON);
builder.factory(OgnlUtil.class, Scope.SINGLETON);
builder.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON);
@@ -417,10 +438,10 @@ public class DefaultConfiguration implements Configuration {
private static class RuntimeConfigurationImpl implements RuntimeConfiguration {
private Map<String, Map<String, ActionConfig>> namespaceActionConfigs;
private Map<String, ActionConfigMatcher> namespaceActionConfigMatchers;
private NamespaceMatcher namespaceMatcher;
private Map<String, String> namespaceConfigs;
private final Map<String, Map<String, ActionConfig>> namespaceActionConfigs;
private final Map<String, ActionConfigMatcher> namespaceActionConfigMatchers;
private final NamespaceMatcher namespaceMatcher;
private final Map<String, String> namespaceConfigs;
public RuntimeConfigurationImpl(Map<String, Map<String, ActionConfig>> namespaceActionConfigs,
Map<String, String> namespaceConfigs,
@@ -448,6 +469,7 @@ public class DefaultConfiguration implements Configuration {
* @param namespace the namespace for the action or null for the empty namespace, ""
* @return the configuration information for action requested
*/
@Override
public ActionConfig getActionConfig(String namespace, String name) {
ActionConfig config = findActionConfigInNamespace(namespace, name);
@@ -503,6 +525,7 @@ public class DefaultConfiguration implements Configuration {
*
* @return a Map of namespace - > Map of ActionConfig objects, with the key being the action name
*/
@Override
public Map<String, Map<String, ActionConfig>> getActionConfigs() {
return namespaceActionConfigs;
}
@@ -26,6 +26,8 @@ import com.opensymphony.xwork2.StrutsTextProviderFactory;
import com.opensymphony.xwork2.TextProviderFactory;
import com.opensymphony.xwork2.factory.DefaultUnknownHandlerFactory;
import com.opensymphony.xwork2.factory.UnknownHandlerFactory;
import com.opensymphony.xwork2.ognl.BeanInfoCacheFactory;
import com.opensymphony.xwork2.ognl.ExpressionCacheFactory;
import com.opensymphony.xwork2.ognl.accessor.HttpParametersPropertyAccessor;
import com.opensymphony.xwork2.ognl.accessor.ParameterPropertyAccessor;
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
@@ -94,6 +96,8 @@ import com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor;
import com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor;
import com.opensymphony.xwork2.util.CompoundRoot;
import com.opensymphony.xwork2.LocalizedTextProvider;
import com.opensymphony.xwork2.ognl.DefaultOgnlBeanInfoCacheFactory;
import com.opensymphony.xwork2.ognl.DefaultOgnlExpressionCacheFactory;
import com.opensymphony.xwork2.util.StrutsLocalizedTextProvider;
import com.opensymphony.xwork2.util.OgnlTextParser;
import com.opensymphony.xwork2.util.PatternMatcher;
@@ -130,19 +134,24 @@ import java.util.Set;
public class StrutsDefaultConfigurationProvider implements ConfigurationProvider {
@Override
public void destroy() {
}
@Override
public void init(Configuration configuration) throws ConfigurationException {
}
@Override
public void loadPackages() throws ConfigurationException {
}
@Override
public boolean needsReload() {
return false;
}
@Override
public void register(ContainerBuilder builder, LocatableProperties props)
throws ConfigurationException {
@@ -208,6 +217,8 @@ public class StrutsDefaultConfigurationProvider implements ConfigurationProvider
.factory(TextProviderFactory.class, StrutsTextProviderFactory.class, Scope.SINGLETON)
.factory(LocaleProviderFactory.class, DefaultLocaleProviderFactory.class, Scope.SINGLETON)
.factory(ExpressionCacheFactory.class, "defaultOgnlExpressionCacheFactory", DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON)
.factory(BeanInfoCacheFactory.class, "defaultOgnlBeanInfoCacheFactory", DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON)
.factory(OgnlUtil.class, Scope.SINGLETON)
.factory(CollectionConverter.class, Scope.SINGLETON)
.factory(ArrayConverter.class, Scope.SINGLETON)
@@ -233,7 +244,6 @@ public class StrutsDefaultConfigurationProvider implements ConfigurationProvider
props.setProperty(StrutsConstants.STRUTS_OGNL_ENABLE_EXPRESSION_CACHE, Boolean.TRUE.toString());
props.setProperty(StrutsConstants.STRUTS_OGNL_ENABLE_EVAL_EXPRESSION, Boolean.FALSE.toString());
props.setProperty(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, Boolean.FALSE.toString());
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, Boolean.FALSE.toString());
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, Boolean.TRUE.toString());
props.setProperty(StrutsConstants.STRUTS_MATCHER_APPEND_NAMED_PARAMETERS, Boolean.TRUE.toString());
}
@@ -38,7 +38,8 @@ import java.lang.annotation.Target;
*
* <p>
* Application wide conversion:<br>
* The conversion rules will be assembled within the <code>xwork-conversion.properties</code> file within the classpath root.
* The conversion rules will be assembled within the <code>struts-conversion.properties</code> or
* <code>xwork-conversion.properties</code> (deprecated) file within the classpath root.
* Set type to: <code>type = ConversionType.APPLICATION</code>
* </p>
* <!-- END SNIPPET: description -->
@@ -18,28 +18,36 @@
*/
package com.opensymphony.xwork2.conversion.impl;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.conversion.TypeConversionException;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.TextProvider;
import com.opensymphony.xwork2.util.ValueStack;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.conversion.TypeConversionException;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.TextProvider;
import com.opensymphony.xwork2.util.ValueStack;
public class DateConverter extends DefaultTypeConverter {
private final static Logger LOG = LogManager.getLogger(DateConverter.class);
@Override
public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType) {
public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName,
Object value, Class toType) {
Date result = null;
if (value instanceof String && ((String) value).length() > 0) {
@@ -52,15 +60,12 @@ public class DateConverter extends DefaultTypeConverter {
} else if (java.sql.Timestamp.class == toType) {
Date check = null;
SimpleDateFormat dtfmt = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT,
DateFormat.MEDIUM,
locale);
SimpleDateFormat fullfmt = new SimpleDateFormat(dtfmt.toPattern() + MILLISECOND_FORMAT,
locale);
DateFormat.MEDIUM, locale);
SimpleDateFormat fullfmt = new SimpleDateFormat(dtfmt.toPattern() + MILLISECOND_FORMAT, locale);
SimpleDateFormat dfmt = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT,
locale);
SimpleDateFormat dfmt = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, locale);
SimpleDateFormat[] fmts = {fullfmt, dtfmt, dfmt};
SimpleDateFormat[] fmts = { fullfmt, dtfmt, dfmt };
for (SimpleDateFormat fmt : fmts) {
try {
check = fmt.parse(sa);
@@ -85,8 +90,39 @@ public class DateConverter extends DefaultTypeConverter {
} catch (ParseException ignore) {
}
}
} else if (java.time.LocalDateTime.class == toType || java.time.LocalDate.class == toType
|| java.time.LocalTime.class == toType) {
DateTimeFormatter dtf = null;
TemporalAccessor check = null;
DateTimeFormatter[] dfs = getDateTimeFormats(ActionContext.of(context), locale);
for (DateTimeFormatter df1 : dfs) {
try {
check = df1.parseBest(sa, LocalDateTime::from, LocalDate::from, LocalTime::from);
dtf = df1;
if (check != null) {
break;
}
} catch (DateTimeParseException ignore) {
}
}
try {
if (dtf != null && check instanceof LocalDateTime) {
return LocalDateTime.parse(sa, dtf);
} else if (dtf != null && check instanceof LocalDate) {
return LocalDate.parse(sa, dtf);
} else if (dtf != null && check instanceof LocalTime) {
return LocalTime.parse(sa, dtf);
} else {
throw new TypeConversionException("Could not parse date");
}
} catch (DateTimeParseException e) {
throw new TypeConversionException("Could not parse date", e);
}
}
//final fallback for dates without time
// final fallback for dates without time
if (df == null) {
df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
}
@@ -95,15 +131,17 @@ public class DateConverter extends DefaultTypeConverter {
result = df.parse(sa);
if (!(Date.class == toType)) {
try {
Constructor<?> constructor = toType.getConstructor(new Class[]{long.class});
return constructor.newInstance(new Object[]{Long.valueOf(result.getTime())});
Constructor<?> constructor = toType.getConstructor(new Class[] { long.class });
return constructor.newInstance(new Object[] { Long.valueOf(result.getTime()) });
} catch (Exception e) {
throw new TypeConversionException("Couldn't create class " + toType + " using default (long) constructor", e);
throw new TypeConversionException(
"Couldn't create class " + toType + " using default (long) constructor", e);
}
}
} catch (ParseException e) {
throw new TypeConversionException("Could not parse date", e);
}
} else if (Date.class.isAssignableFrom(value.getClass())) {
result = (Date) value;
}
@@ -111,16 +149,16 @@ public class DateConverter extends DefaultTypeConverter {
}
/**
* The user defined global date format,
* see {@link org.apache.struts2.components.Date#DATETAG_PROPERTY}
* The user defined global date format, see
* {@link org.apache.struts2.components.Date#DATETAG_PROPERTY}
*
* @param context current ActionContext
* @param locale current Locale to convert to
* @return defined global format
*
* @return defined global date string format
*/
protected DateFormat getGlobalDateFormat(ActionContext context, Locale locale) {
protected String getGlobalDateString(ActionContext context) {
final String dateTagProperty = org.apache.struts2.components.Date.DATETAG_PROPERTY;
SimpleDateFormat globalDateFormat = null;
String globalDateString = null;
final TextProvider tp = findProviderInStack(context.getValueStack());
@@ -130,23 +168,28 @@ public class DateConverter extends DefaultTypeConverter {
// is the same as input = DATETAG_PROPERTY
if (globalFormat != null && !dateTagProperty.equals(globalFormat)) {
LOG.debug("Found \"{}\" as \"{}\"", dateTagProperty, globalFormat);
globalDateFormat = new SimpleDateFormat(globalFormat, locale);
globalDateString = globalFormat;
} else {
LOG.debug("\"{}\" has not been defined, ignoring it", dateTagProperty);
}
}
return globalDateFormat;
return globalDateString;
}
/**
* Retrieves the list of date formats to be used when converting dates
*
* @param context the current ActionContext
* @param locale the current locale of the action
* @param locale the current locale of the action
* @return a list of DateFormat to be used for date conversion
*/
private DateFormat[] getDateFormats(ActionContext context, Locale locale) {
DateFormat globalDateFormat = getGlobalDateFormat(context, locale);
DateFormat globalDateFormat = null;
String globalFormat = getGlobalDateString(context);
if (globalFormat != null) {
globalDateFormat = new SimpleDateFormat(globalFormat, locale);
}
DateFormat dt1 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, locale);
DateFormat dt2 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale);
@@ -156,15 +199,46 @@ public class DateConverter extends DefaultTypeConverter {
DateFormat d2 = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
DateFormat d3 = DateFormat.getDateInstance(DateFormat.LONG, locale);
DateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
DateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
DateFormat rfc3339dateOnly = new SimpleDateFormat("yyyy-MM-dd");
final DateFormat[] dateFormats;
if (globalDateFormat == null) {
dateFormats = new DateFormat[]{dt1, dt2, dt3, rfc3339, d1, d2, d3, rfc3339dateOnly};
dateFormats = new DateFormat[] { dt1, dt2, dt3, rfc3339, d1, d2, d3, rfc3339dateOnly };
} else {
dateFormats = new DateFormat[]{globalDateFormat, dt1, dt2, dt3, rfc3339, d1, d2, d3, rfc3339dateOnly};
dateFormats = new DateFormat[] { globalDateFormat, dt1, dt2, dt3, rfc3339, d1, d2, d3, rfc3339dateOnly };
}
return dateFormats;
}
/**
* Retrieves the list of date time formats to be used when converting dates
*
* @param context the current ActionContext
* @param locale the current locale of the action
*
* @return a list of DateTimeFormatter to be used for date conversion
*/
protected DateTimeFormatter[] getDateTimeFormats(ActionContext context, Locale locale) {
DateTimeFormatter globalDateFormat = null;
String globalFormat = getGlobalDateString(context);
if (globalFormat != null) {
globalDateFormat = DateTimeFormatter.ofPattern(globalFormat, locale);
}
DateTimeFormatter df1 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
DateTimeFormatter df2 = DateTimeFormatter.ISO_LOCAL_DATE;
DateTimeFormatter df3 = DateTimeFormatter.ISO_LOCAL_TIME;
final DateTimeFormatter[] dateFormats;
if (globalDateFormat == null) {
dateFormats = new DateTimeFormatter[] { df1, df2, df3 };
} else {
dateFormats = new DateTimeFormatter[] { globalDateFormat, df1, df2, df3 };
}
return dateFormats;
@@ -25,6 +25,7 @@ import com.opensymphony.xwork2.inject.Inject;
import org.apache.struts2.StrutsConstants;
import java.lang.reflect.Member;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
@@ -99,6 +100,8 @@ public class XWorkBasicConverter extends DefaultTypeConverter {
result = doConvertToArray(context, o, member, propertyName, value, toType);
} else if (Date.class.isAssignableFrom(toType)) {
result = doConvertToDate(context, value, toType);
} else if (LocalDateTime.class.isAssignableFrom(toType)) {
result = doConvertToDate(context, value, toType);
} else if (Calendar.class.isAssignableFrom(toType)) {
result = doConvertToCalendar(context, value);
} else if (Collection.class.isAssignableFrom(toType)) {
@@ -201,7 +201,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
ReflectionContextState.setReportingConversionErrors(context, true);
//keep locale from original context
newStack.getActionContext().withLocale(stack.getActionContext().getLocale());
newStack.getActionContext().withLocale(stack.getActionContext().getLocale()).withValueStack(stack);
}
boolean memberAccessStack = newStack instanceof MemberAccessValueStack;
@@ -0,0 +1,23 @@
/*
* Copyright 2022 Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.ognl;
/**
* A proxy interface to be used with Struts DI mechanism
*/
public interface BeanInfoCacheFactory<Key, Value> extends OgnlCacheFactory <Key, Value> {
}
@@ -0,0 +1,44 @@
/*
* Copyright 2022 Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.ognl;
import com.opensymphony.xwork2.inject.Inject;
import org.apache.struts2.StrutsConstants;
/**
* Default OGNL Cache factory implementation.
*
* Currently used for BeanInfo cache creation.
*
* @param <Key> The type for the cache key entries
* @param <Value> The type for the cache value entries
*/
public class DefaultOgnlBeanInfoCacheFactory<Key, Value> extends DefaultOgnlCacheFactory<Key, Value>
implements BeanInfoCacheFactory<Key, Value> {
@Override
@Inject(value = StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE, required = false)
protected void setCacheMaxSize(String maxSize) {
super.setCacheMaxSize(maxSize);
}
@Override
@Inject(value = StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_LRU_MODE, required = false)
protected void setUseLRUCache(String useLRUMode) {
super.setUseLRUCache(useLRUMode);
}
}
@@ -0,0 +1,66 @@
/*
* Copyright 2022 Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.ognl;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.lang3.BooleanUtils;
/**
* Default OGNL Cache factory implementation.
*
* Currently used for Expression cache and BeanInfo cache creation.
*
* @param <Key> The type for the cache key entries
* @param <Value> The type for the cache value entries
*/
public class DefaultOgnlCacheFactory<Key, Value> implements OgnlCacheFactory<Key, Value> {
private final AtomicBoolean useLRUCache = new AtomicBoolean(false);
private final AtomicInteger cacheMaxSize = new AtomicInteger(25000);
@Override
public OgnlCache<Key, Value> buildOgnlCache() {
return buildOgnlCache(getCacheMaxSize(), 16, 0.75f, getUseLRUCache());
}
@Override
public OgnlCache<Key, Value> buildOgnlCache(int evictionLimit, int initialCapacity, float loadFactor, boolean lruCache) {
if (lruCache) {
return new OgnlLRUCache<>(evictionLimit, initialCapacity, loadFactor);
} else {
return new OgnlDefaultCache<>(evictionLimit, initialCapacity, loadFactor);
}
}
@Override
public int getCacheMaxSize() {
return cacheMaxSize.get();
}
protected void setCacheMaxSize(String maxSize) {
cacheMaxSize.set(Integer.parseInt(maxSize));
}
@Override
public boolean getUseLRUCache() {
return useLRUCache.get();
}
protected void setUseLRUCache(String useLRUMode) {
useLRUCache.set(BooleanUtils.toBoolean(useLRUMode));
}
}
@@ -0,0 +1,44 @@
/*
* Copyright 2022 Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.ognl;
import com.opensymphony.xwork2.inject.Inject;
import org.apache.struts2.StrutsConstants;
/**
* Default OGNL Expression Cache factory implementation.
*
* Currently used for Expression cache creation.
*
* @param <Key> The type for the cache key entries
* @param <Value> The type for the cache value entries
*/
public class DefaultOgnlExpressionCacheFactory<Key, Value> extends DefaultOgnlCacheFactory<Key, Value>
implements ExpressionCacheFactory<Key, Value> {
@Override
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE, required = false)
protected void setCacheMaxSize(String maxSize) {
super.setCacheMaxSize(maxSize);
}
@Override
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_LRU_MODE, required = false)
protected void setUseLRUCache(String useLRUMode) {
super.setUseLRUCache(useLRUMode);
}
}
@@ -0,0 +1,23 @@
/*
* Copyright 2022 Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.ognl;
/**
* A proxy interface to be used with Struts DI mechanism
*/
public interface ExpressionCacheFactory<Key, Value> extends OgnlCacheFactory <Key, Value> {
}
@@ -0,0 +1,41 @@
/*
* Copyright 2022 Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.ognl;
/**
* A basic cache interface for use with OGNL processing (such as Expression, BeanInfo).
* All OGNL caches will have an eviction limit, but setting an extremely high value can
* simulate an "effectively unlimited" cache.
*
* @param <Key> The type for the cache key entries
* @param <Value> The type for the cache value entries
*/
public interface OgnlCache<Key, Value> {
public Value get(Key key);
public void put(Key key, Value value);
public void putIfAbsent(Key key, Value value);
public int size();
public void clear();
public int getEvictionLimit();
public void setEvictionLimit(int cacheEvictionLimit);
}
@@ -0,0 +1,30 @@
/*
* Copyright 2022 Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.ognl;
/**
* Used by {@link com.opensymphony.xwork2.ognl.OgnlUtil} to create appropriate OGNL
* caches based on configuration.
*
* @param <Key> The type for the cache key entries
* @param <Value> The type for the cache value entries
*/
interface OgnlCacheFactory<Key, Value> {
OgnlCache<Key, Value> buildOgnlCache();
OgnlCache<Key, Value> buildOgnlCache(int evictionLimit, int initialCapacity, float loadFactor, boolean lruCache);
int getCacheMaxSize();
boolean getUseLRUCache();
}
@@ -0,0 +1,85 @@
/*
* Copyright 2022 Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.ognl;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Default OGNL cache implementation.
*
* Setting a very high eviction limit simulates an unlimited cache.
* Setting too low an eviction limit will make the cache ineffective.
*
* @param <Key> The type for the cache key entries
* @param <Value> The type for the cache value entries
*/
public class OgnlDefaultCache<Key, Value> implements OgnlCache<Key, Value> {
private final ConcurrentHashMap<Key, Value> ognlCache;
private final AtomicInteger cacheEvictionLimit = new AtomicInteger(25000);
public OgnlDefaultCache(int evictionLimit, int initialCapacity, float loadFactor) {
this.cacheEvictionLimit.set(evictionLimit);
ognlCache = new ConcurrentHashMap<>(initialCapacity, loadFactor);
}
@Override
public Value get(Key key) {
return ognlCache.get(key);
}
@Override
public void put(Key key, Value value) {
ognlCache.put(key, value);
this.clearIfEvictionLimitExceeded();
}
@Override
public void putIfAbsent(Key key, Value value) {
ognlCache.putIfAbsent(key, value);
this.clearIfEvictionLimitExceeded();
}
@Override
public int size() {
return ognlCache.size();
}
@Override
public void clear() {
ognlCache.clear();
}
@Override
public int getEvictionLimit() {
return this.cacheEvictionLimit.get();
}
@Override
public void setEvictionLimit(int cacheEvictionLimit) {
this.cacheEvictionLimit.set(cacheEvictionLimit);
}
/**
* Clear the cache if the eviction limit has been exceeded.
*/
private void clearIfEvictionLimitExceeded() {
if (ognlCache.size() > cacheEvictionLimit.get()) {
ognlCache.clear();
}
}
}
@@ -0,0 +1,87 @@
/*
* Copyright 2022 Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.ognl;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A basic OGNL LRU cache implementation.
*
* The implementation utilizes a {@link Collections#synchronizedMap(java.util.Map)}
* backed by a {@link LinkedHashMap}. May be replaced by a more efficient implementation in the future.
*
* Setting too low an eviction limit will produce more overhead than value.
* Setting too high an eviction limit may also produce more overhead than value.
* An appropriate eviction limit will need to be determined on an individual application basis.
*
* @param <Key> The type for the cache key entries
* @param <Value> The type for the cache value entries
*/
public class OgnlLRUCache<Key, Value> implements OgnlCache<Key, Value> {
private final Map<Key, Value> ognlLRUCache;
private final AtomicInteger cacheEvictionLimit = new AtomicInteger(2500);
public OgnlLRUCache(int evictionLimit, int initialCapacity, float loadFactor) {
this.cacheEvictionLimit.set(evictionLimit);
// Access-order mode selected (order mode true in LinkedHashMap constructor).
ognlLRUCache = Collections.synchronizedMap (new LinkedHashMap<Key, Value>(initialCapacity, loadFactor, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<Key,Value> eldest) {
return (this.size() > cacheEvictionLimit.get());
}
});
}
@Override
public Value get(Key key) {
return ognlLRUCache.get(key);
}
@Override
public void put(Key key, Value value) {
ognlLRUCache.put(key, value);
}
@Override
public void putIfAbsent(Key key, Value value) {
ognlLRUCache.putIfAbsent(key, value);
}
@Override
public int size() {
return ognlLRUCache.size();
}
@Override
public void clear() {
ognlLRUCache.clear();
}
@Override
public int getEvictionLimit() {
return this.cacheEvictionLimit.get();
}
@Override
public void setEvictionLimit(int cacheEvictionLimit) {
this.cacheEvictionLimit.set(cacheEvictionLimit);
}
}
@@ -38,8 +38,6 @@ import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
@@ -57,8 +55,8 @@ public class OgnlUtil {
// Flag used to reduce flooding logs with WARNs about using DevMode excluded packages
private final AtomicBoolean warnReported = new AtomicBoolean(false);
private final ConcurrentMap<String, Object> expressions = new ConcurrentHashMap<>();
private final ConcurrentMap<Class<?>, BeanInfo> beanInfoCache = new ConcurrentHashMap<>();
private final OgnlCache<String, Object> expressionCache;
private final OgnlCache<Class<?>, BeanInfo> beanInfoCache;
private TypeConverter defaultConverter;
private boolean devMode;
@@ -75,10 +73,33 @@ public class OgnlUtil {
private Container container;
private boolean allowStaticFieldAccess = true;
private boolean allowStaticMethodAccess;
private boolean disallowProxyMemberAccess;
/**
* Construct a new OgnlUtil instance for use with the framework
*
* @deprecated It is recommended to utilize the {@link OgnlUtil#OgnlUtil(com.opensymphony.xwork2.ognl.ExpressionCacheFactory, com.opensymphony.xwork2.ognl.BeanInfoCacheFactory) method instead.
*/
@Deprecated
public OgnlUtil() {
this(null, null); // Instantiate default Expression and BeanInfo caches (null factories)
}
/**
* Construct a new OgnlUtil instance for use with the framework, with optional
* cache factories for OGNL Expression and BeanInfo caches.
*
* NOTE: Although the extension points are defined for the optional cache factories, developer-defined overrides do
* do not appear to function at this time (it always appears to instantiate the default factories).
* Construction injectors do not allow the optional flag, so the definitions must be defined.
*
* @param ognlExpressionCacheFactory factory for Expression cache instance. If null, it uses a default
* @param ognlBeanInfoCacheFactory factory for BeanInfo cache instance. If null, it uses a default
*/
public OgnlUtil(
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_FACTORY, required = false) ExpressionCacheFactory<String, Object> ognlExpressionCacheFactory,
@Inject(value = StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_FACTORY, required = false) BeanInfoCacheFactory<Class<?>, BeanInfo> ognlBeanInfoCacheFactory
) {
excludedClasses = Collections.unmodifiableSet(new HashSet<>());
excludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
excludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
@@ -86,6 +107,12 @@ public class OgnlUtil {
devModeExcludedClasses = Collections.unmodifiableSet(new HashSet<>());
devModeExcludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
devModeExcludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
OgnlCacheFactory<String, Object> ognlExpressionCacheFactory1 = (ognlExpressionCacheFactory != null ? ognlExpressionCacheFactory : new DefaultOgnlExpressionCacheFactory<>());
OgnlCacheFactory<Class<?>, BeanInfo> ognlBeanInfoCacheFactory1 = (ognlBeanInfoCacheFactory != null ? ognlBeanInfoCacheFactory : new DefaultOgnlBeanInfoCacheFactory<>());
this.expressionCache = ognlExpressionCacheFactory1.buildOgnlCache();
this.beanInfoCache = ognlBeanInfoCacheFactory1.buildOgnlCache();
}
@Inject
@@ -103,6 +130,16 @@ public class OgnlUtil {
enableExpressionCache = BooleanUtils.toBoolean(cache);
}
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE, required = false)
protected void setExpressionCacheMaxSize(String maxSize) {
expressionCache.setEvictionLimit(Integer.parseInt(maxSize));
}
@Inject(value = StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE, required = false)
protected void setBeanInfoCacheMaxSize(String maxSize) {
beanInfoCache.setEvictionLimit(Integer.parseInt(maxSize));
}
@Inject(value = StrutsConstants.STRUTS_OGNL_ENABLE_EVAL_EXPRESSION, required = false)
protected void setEnableEvalExpression(String evalExpression) {
this.enableEvalExpression = BooleanUtils.toBoolean(evalExpression);
@@ -212,11 +249,6 @@ public class OgnlUtil {
this.allowStaticFieldAccess = BooleanUtils.toBoolean(allowStaticFieldAccess);
}
@Inject(value = StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, required = false)
protected void setAllowStaticMethodAccess(String allowStaticMethodAccess) {
this.allowStaticMethodAccess = BooleanUtils.toBoolean(allowStaticMethodAccess);
}
@Inject(value = StrutsConstants.STRUTS_DISALLOW_PROXY_MEMBER_ACCESS, required = false)
protected void setDisallowProxyMemberAccess(String disallowProxyMemberAccess) {
this.disallowProxyMemberAccess = BooleanUtils.toBoolean(disallowProxyMemberAccess);
@@ -273,7 +305,7 @@ public class OgnlUtil {
* @since 2.5.21
*/
public void clearExpressionCache() {
expressions.clear();
expressionCache.clear();
}
/**
@@ -284,7 +316,7 @@ public class OgnlUtil {
* @since 2.5.21
*/
public int expressionCacheSize() {
return expressions.size();
return expressionCache.size();
}
/**
@@ -532,11 +564,11 @@ public class OgnlUtil {
private <T> Object compileAndExecute(String expression, Map<String, Object> context, OgnlTask<T> task) throws OgnlException {
Object tree;
if (enableExpressionCache) {
tree = expressions.get(expression);
tree = expressionCache.get(expression);
if (tree == null) {
tree = Ognl.parseExpression(expression);
checkEnableEvalExpression(tree, context);
expressions.putIfAbsent(expression, tree);
expressionCache.putIfAbsent(expression, tree);
}
} else {
tree = Ognl.parseExpression(expression);
@@ -549,11 +581,11 @@ public class OgnlUtil {
private <T> Object compileAndExecuteMethod(String expression, Map<String, Object> context, OgnlTask<T> task) throws OgnlException {
Object tree;
if (enableExpressionCache) {
tree = expressions.get(expression);
tree = expressionCache.get(expression);
if (tree == null) {
tree = Ognl.parseExpression(expression);
checkSimpleMethod(tree, context);
expressions.putIfAbsent(expression, tree);
expressionCache.putIfAbsent(expression, tree);
}
} else {
tree = Ognl.parseExpression(expression);
@@ -798,7 +830,7 @@ public class OgnlUtil {
resolver = container.getInstance(CompoundRootAccessor.class);
}
SecurityMemberAccess memberAccess = new SecurityMemberAccess(allowStaticMethodAccess, allowStaticFieldAccess);
SecurityMemberAccess memberAccess = new SecurityMemberAccess(allowStaticFieldAccess);
memberAccess.setDisallowProxyMemberAccess(disallowProxyMemberAccess);
if (devMode) {
@@ -72,13 +72,13 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
private boolean devMode;
private boolean logMissingProperties;
protected OgnlValueStack(XWorkConverter xworkConverter, CompoundRootAccessor accessor, TextProvider prov, boolean allowStaticMethodAccess, boolean allowStaticFieldAccess) {
setRoot(xworkConverter, accessor, new CompoundRoot(), allowStaticMethodAccess, allowStaticFieldAccess);
protected OgnlValueStack(XWorkConverter xworkConverter, CompoundRootAccessor accessor, TextProvider prov, boolean allowStaticFieldAccess) {
setRoot(xworkConverter, accessor, new CompoundRoot(), allowStaticFieldAccess);
push(prov);
}
protected OgnlValueStack(ValueStack vs, XWorkConverter xworkConverter, CompoundRootAccessor accessor, boolean allowStaticMethodAccess, boolean allowStaticFieldAccess) {
setRoot(xworkConverter, accessor, new CompoundRoot(vs.getRoot()), allowStaticMethodAccess, allowStaticFieldAccess);
protected OgnlValueStack(ValueStack vs, XWorkConverter xworkConverter, CompoundRootAccessor accessor, boolean allowStaticFieldAccess) {
setRoot(xworkConverter, accessor, new CompoundRoot(vs.getRoot()), allowStaticFieldAccess);
}
@Inject
@@ -90,10 +90,9 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
securityMemberAccess.setDisallowProxyMemberAccess(ognlUtil.isDisallowProxyMemberAccess());
}
protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot,
boolean allowStaticMethodAccess, boolean allowStaticFieldAccess) {
protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot, boolean allowStaticFieldAccess) {
this.root = compoundRoot;
this.securityMemberAccess = new SecurityMemberAccess(allowStaticMethodAccess, allowStaticFieldAccess);
this.securityMemberAccess = new SecurityMemberAccess(allowStaticFieldAccess);
this.context = Ognl.createDefaultContext(this.root, securityMemberAccess, accessor, new OgnlTypeConverterWrapper(xworkConverter));
context.put(VALUE_STACK, this);
((OgnlContext) context).setTraceEvaluations(false);
@@ -219,7 +218,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
if (shouldLog) {
LOG.warn(msg, e);
}
if (throwExceptionOnFailure) {
throw new StrutsException(msg, e);
}
@@ -462,11 +461,10 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
XWorkConverter xworkConverter = cont.getInstance(XWorkConverter.class);
CompoundRootAccessor accessor = (CompoundRootAccessor) cont.getInstance(PropertyAccessor.class, CompoundRoot.class.getName());
TextProvider prov = cont.getInstance(TextProvider.class, "system");
final boolean allowStaticMethod = BooleanUtils.toBoolean(cont.getInstance(String.class, StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS));
final boolean allowStaticField = BooleanUtils.toBoolean(cont.getInstance(String.class, StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS));
OgnlValueStack aStack = new OgnlValueStack(xworkConverter, accessor, prov, allowStaticMethod, allowStaticField);
OgnlValueStack aStack = new OgnlValueStack(xworkConverter, accessor, prov, allowStaticField);
aStack.setOgnlUtil(cont.getInstance(OgnlUtil.class));
aStack.setRoot(xworkConverter, accessor, this.root, allowStaticMethod, allowStaticField);
aStack.setRoot(xworkConverter, accessor, this.root, allowStaticField);
return aStack;
}
@@ -43,8 +43,6 @@ import java.util.Set;
*/
public class OgnlValueStackFactory implements ValueStackFactory {
private static final Logger LOG = LogManager.getLogger(OgnlValueStackFactory.class);
protected XWorkConverter xworkConverter;
protected CompoundRootAccessor compoundRootAccessor;
protected TextProvider textProvider;
@@ -61,8 +59,7 @@ public class OgnlValueStackFactory implements ValueStackFactory {
}
public ValueStack createValueStack() {
ValueStack stack = new OgnlValueStack(xworkConverter, compoundRootAccessor, textProvider,
containerAllowsStaticMethodAccess(), containerAllowsStaticFieldAccess());
ValueStack stack = new OgnlValueStack(xworkConverter, compoundRootAccessor, textProvider, containerAllowsStaticFieldAccess());
container.inject(stack);
return stack.getActionContext()
.withContainer(container)
@@ -71,8 +68,7 @@ public class OgnlValueStackFactory implements ValueStackFactory {
}
public ValueStack createValueStack(ValueStack stack) {
ValueStack result = new OgnlValueStack(stack, xworkConverter, compoundRootAccessor,
containerAllowsStaticMethodAccess(), containerAllowsStaticFieldAccess());
ValueStack result = new OgnlValueStack(stack, xworkConverter, compoundRootAccessor, containerAllowsStaticFieldAccess());
container.inject(result);
return result.getActionContext()
.withContainer(container)
@@ -84,32 +80,23 @@ public class OgnlValueStackFactory implements ValueStackFactory {
protected void setContainer(Container container) throws ClassNotFoundException {
Set<String> names = container.getInstanceNames(PropertyAccessor.class);
for (String name : names) {
Class cls = Class.forName(name);
if (cls != null) {
if (Map.class.isAssignableFrom(cls)) {
PropertyAccessor acc = container.getInstance(PropertyAccessor.class, name);
}
OgnlRuntime.setPropertyAccessor(cls, container.getInstance(PropertyAccessor.class, name));
if (compoundRootAccessor == null && CompoundRoot.class.isAssignableFrom(cls)) {
compoundRootAccessor = (CompoundRootAccessor) container.getInstance(PropertyAccessor.class, name);
}
Class<?> cls = Class.forName(name);
OgnlRuntime.setPropertyAccessor(cls, container.getInstance(PropertyAccessor.class, name));
if (compoundRootAccessor == null && CompoundRoot.class.isAssignableFrom(cls)) {
compoundRootAccessor = (CompoundRootAccessor) container.getInstance(PropertyAccessor.class, name);
}
}
names = container.getInstanceNames(MethodAccessor.class);
for (String name : names) {
Class cls = Class.forName(name);
if (cls != null) {
OgnlRuntime.setMethodAccessor(cls, container.getInstance(MethodAccessor.class, name));
}
Class<?> cls = Class.forName(name);
OgnlRuntime.setMethodAccessor(cls, container.getInstance(MethodAccessor.class, name));
}
names = container.getInstanceNames(NullHandler.class);
for (String name : names) {
Class cls = Class.forName(name);
if (cls != null) {
OgnlRuntime.setNullHandler(cls, new OgnlNullHandlerWrapper(container.getInstance(NullHandler.class, name)));
}
Class<?> cls = Class.forName(name);
OgnlRuntime.setNullHandler(cls, new OgnlNullHandlerWrapper(container.getInstance(NullHandler.class, name)));
}
if (compoundRootAccessor == null) {
throw new IllegalStateException("Couldn't find the compound root accessor");
@@ -117,19 +104,8 @@ public class OgnlValueStackFactory implements ValueStackFactory {
this.container = container;
}
/**
* Retrieve allowsStaticMethodAccess state from the container (allows for lazy fetching)
*
* @return
*/
protected boolean containerAllowsStaticMethodAccess() {
return BooleanUtils.toBoolean(container.getInstance(String.class, StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS));
}
/**
* Retrieve allowStaticFieldAccess state from the container (allows for lazy fetching)
*
* @return
*/
protected boolean containerAllowsStaticFieldAccess() {
return BooleanUtils.toBoolean(container.getInstance(String.class, StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS));
@@ -42,7 +42,6 @@ public class SecurityMemberAccess implements MemberAccess {
private static final Logger LOG = LogManager.getLogger(SecurityMemberAccess.class);
private final boolean allowStaticFieldAccess;
private final boolean allowStaticMethodAccess;
private Set<Pattern> excludeProperties = Collections.emptySet();
private Set<Pattern> acceptProperties = Collections.emptySet();
private Set<Class<?>> excludedClasses = Collections.emptySet();
@@ -52,25 +51,15 @@ public class SecurityMemberAccess implements MemberAccess {
/**
* SecurityMemberAccess
* - access decisions based on whether member is static (or not)
* - block or allow access to properties (configurable-after-construction)
*
* @param allowStaticMethodAccess
* @param allowStaticFieldAccess
* - access decisions based on whether member is static (or not)
* - block or allow access to properties (configurable-after-construction)
*
* @param allowStaticFieldAccess if set to true static fields (constants) will be accessible
*/
public SecurityMemberAccess(boolean allowStaticMethodAccess, boolean allowStaticFieldAccess) {
this.allowStaticMethodAccess = allowStaticMethodAccess;
public SecurityMemberAccess(boolean allowStaticFieldAccess) {
this.allowStaticFieldAccess = allowStaticFieldAccess;
}
public final boolean getAllowStaticMethodAccess() {
return allowStaticMethodAccess;
}
public final boolean getAllowStaticFieldAccess() {
return allowStaticFieldAccess;
}
@Override
public Object setup(Map context, Object target, Member member, String propertyName) {
Object result = null;
@@ -90,13 +79,12 @@ public class SecurityMemberAccess implements MemberAccess {
public void restore(Map context, Object target, Member member, String propertyName, Object state) {
if (state != null) {
final AccessibleObject accessible = (AccessibleObject) member;
final boolean stateboolean = ((Boolean) state).booleanValue(); // Using twice (avoid unboxing)
if (!stateboolean) {
accessible.setAccessible(stateboolean);
}
else {
throw new IllegalArgumentException("Improper restore state [" + stateboolean + "] for target [" + target +
"], member [" + member + "], propertyName [" + propertyName + "]");
final boolean stateBoolean = ((Boolean) state).booleanValue(); // Using twice (avoid unboxing)
if (!stateBoolean) {
accessible.setAccessible(stateBoolean);
} else {
throw new IllegalArgumentException("Improper restore state [" + stateBoolean + "] for target [" + target +
"], member [" + member + "], propertyName [" + propertyName + "]");
}
}
}
@@ -117,6 +105,7 @@ public class SecurityMemberAccess implements MemberAccess {
return false;
}
// it needs to be before calling #checkStaticMethodAccess()
if (checkEnumAccess(target, member)) {
LOG.trace("Allowing access to enum: target [{}], member [{}]", target, member);
return true;
@@ -127,7 +116,7 @@ public class SecurityMemberAccess implements MemberAccess {
return false;
}
final Class memberClass = member.getDeclaringClass();
final Class<?> memberClass = member.getDeclaringClass();
if (isClassExcluded(memberClass)) {
LOG.warn("Declaring class of member type [{}] is excluded!", member);
@@ -135,11 +124,11 @@ public class SecurityMemberAccess implements MemberAccess {
}
// target can be null in case of accessing static fields, since OGNL 3.2.8
final Class targetClass = Modifier.isStatic(memberModifiers) ? memberClass : target.getClass();
final Class<?> targetClass = Modifier.isStatic(memberModifiers) ? memberClass : target.getClass();
if (isPackageExcluded(targetClass.getPackage(), memberClass.getPackage())) {
LOG.warn("Package [{}] of target class [{}] of target [{}] or package [{}] of member [{}] are excluded!", targetClass.getPackage(), targetClass,
target, memberClass.getPackage(), member);
target, memberClass.getPackage(), member);
return false;
}
@@ -158,33 +147,25 @@ public class SecurityMemberAccess implements MemberAccess {
/**
* Check access for static method (via modifiers).
*
*
* Note: For non-static members, the result is always true.
*
*
* @param member
* @param memberModifiers
*
*
* @return
*/
protected boolean checkStaticMethodAccess(Member member, int memberModifiers) {
if (Modifier.isStatic(memberModifiers) && !(member instanceof Field)) {
if (allowStaticMethodAccess) {
LOG.debug("Support for accessing static methods [member: {}] is deprecated!", member);
}
return allowStaticMethodAccess;
} else {
return true;
}
return !Modifier.isStatic(memberModifiers) || member instanceof Field;
}
/**
* Check access for static field (via modifiers).
*
* <p>
* Note: For non-static members, the result is always true.
*
*
* @param member
* @param memberModifiers
*
* @return
*/
protected boolean checkStaticFieldAccess(Member member, int memberModifiers) {
@@ -195,13 +176,12 @@ public class SecurityMemberAccess implements MemberAccess {
}
}
/**
/**
* Check access for public members (via modifiers)
*
* <p>
* Returns true if-and-only-if the member is public.
*
*
* @param memberModifiers
*
* @return
*/
protected boolean checkPublicMemberAccess(int memberModifiers) {
@@ -210,10 +190,8 @@ public class SecurityMemberAccess implements MemberAccess {
protected boolean checkEnumAccess(Object target, Member member) {
if (target instanceof Class) {
final Class clazz = (Class) target;
if (Enum.class.isAssignableFrom(clazz) && member.getName().equals("values")) {
return true;
}
final Class<?> clazz = (Class<?>) target;
return Enum.class.isAssignableFrom(clazz) && member.getName().equals("values");
}
return false;
}
@@ -222,7 +200,7 @@ public class SecurityMemberAccess implements MemberAccess {
if (targetPackage == null || memberPackage == null) {
LOG.warn("The use of the default (unnamed) package is discouraged!");
}
String targetPackageName = targetPackage == null ? "" : targetPackage.getName();
String memberPackageName = memberPackage == null ? "" : memberPackage.getName();
@@ -235,7 +213,7 @@ public class SecurityMemberAccess implements MemberAccess {
targetPackageName = targetPackageName + ".";
memberPackageName = memberPackageName + ".";
for (String packageName: excludedPackageNames) {
for (String packageName : excludedPackageNames) {
if (targetPackageName.startsWith(packageName) || memberPackageName.startsWith(packageName)) {
return true;
}
@@ -245,7 +223,7 @@ public class SecurityMemberAccess implements MemberAccess {
}
protected boolean isClassExcluded(Class<?> clazz) {
if (clazz == Object.class || (clazz == Class.class && !allowStaticMethodAccess)) {
if (clazz == Object.class || (clazz == Class.class && !allowStaticFieldAccess)) {
return true;
}
for (Class<?> excludedClass : excludedClasses) {
@@ -36,7 +36,7 @@ import java.util.Map;
* @author tmjee
*/
public class XWorkMethodAccessor extends ObjectMethodAccessor {
private static final Logger LOG = LogManager.getLogger(XWorkMethodAccessor.class);
@Override
@@ -58,9 +58,9 @@ public class XWorkMethodAccessor extends ObjectMethodAccessor {
//so that property strings are not cleared
//i.e. OgnlUtil should be used initially, OgnlRuntime
//thereafter
Object propVal=OgnlRuntime.getProperty(ogContext, object, string);
//use the Collection property accessor instead of the individual property accessor, because
//use the Collection property accessor instead of the individual property accessor, because
//in the case of Lists otherwise the index property could be used
PropertyAccessor accessor=OgnlRuntime.getPropertyAccessor(Collection.class);
ReflectionContextState.setGettingByKeyProperty(ogContext,true);
@@ -83,8 +83,8 @@ public class XWorkMethodAccessor extends ObjectMethodAccessor {
return callMethodWithDebugInfo(context, object, string, objects);
}
}
Boolean exec = (Boolean) context.get(ReflectionContextState.DENY_METHOD_EXECUTION);
boolean e = ((exec == null) ? false : exec.booleanValue());
Boolean exec = ReflectionContextState.isDenyMethodExecution(context);
boolean e = (exec != null && exec);
if (!e) {
return callMethodWithDebugInfo(context, object, string, objects);
@@ -110,7 +110,7 @@ public class XWorkMethodAccessor extends ObjectMethodAccessor {
@Override
public Object callStaticMethod(Map context, Class aClass, String string, Object[] objects) throws MethodFailedException {
Boolean exec = (Boolean) context.get(ReflectionContextState.DENY_METHOD_EXECUTION);
Boolean exec = ReflectionContextState.isDenyMethodExecution(context);
boolean e = ((exec == null) ? false : exec.booleanValue());
if (!e) {
@@ -226,9 +226,6 @@ public final class StrutsConstants {
/** The name of the parameter to determine whether static field access will be allowed in OGNL expressions or not */
public static final String STRUTS_ALLOW_STATIC_FIELD_ACCESS = "struts.ognl.allowStaticFieldAccess";
/** The name of the parameter to determine whether static method access will be allowed in OGNL expressions or not */
public static final String STRUTS_ALLOW_STATIC_METHOD_ACCESS = "struts.ognl.allowStaticMethodAccess";
/** The com.opensymphony.xwork2.validator.ActionValidatorManager implementation class */
public static final String STRUTS_ACTIONVALIDATORMANAGER = "struts.actionValidatorManager";
@@ -253,6 +250,47 @@ public final class StrutsConstants {
/** Throw RuntimeException when a property is not found, or the evaluation of the expression fails */
public static final String STRUTS_EL_THROW_EXCEPTION = "struts.el.throwExceptionOnFailure";
/**
* Specifies an OGNL expression cache factory implementation. A default implementation is provided, but
* could be replaced by a custom one if desired.
*
* @since 2.6
*/
public static final String STRUTS_OGNL_EXPRESSION_CACHE_FACTORY = "struts.ognl.expressionCacheFactory";
/**
* Specifies an OGNL BeanInfo cache factory implementation. A default implementation is provided, but
* could be replaced by a custom one if desired.
*
* @since 2.6
*/
public static final String STRUTS_OGNL_BEANINFO_CACHE_FACTORY = "struts.ognl.beanInfoCacheFactory";
/**
* Specifies a maximum number of cached BeanInfo used by OgnlUtility. Not specified/set by default. If
* a positive integer is specified, it will set a limit whose behaviour depends on whether the
* normal (default) cache or optional LRU cache is in place.
*
* For the normal (default) cache, exceeding the maximum will cause the entire cache to flush (clear).
* For the optional LRU cache, once the maximum is reached, the least-recently-used (LRU) entry will be
* removed when a new entry needs to be added (cache is fully-utilized).
*
* @since 2.6
*/
public static final String STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE = "struts.ognl.beanInfoCacheMaxSize";
/**
* Set the cache mode of the BeanInfo cache used by OgnlUtility. A value of true means enable
* least-recently-used (LRU) mode, a value of false (or any non-true value) means to use the
* default cache.
*
* Note: When enabling LRU cache mode you must also set a maximum size (via {@link #STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE})
* for it to be effective. Otherwise, there is no condition to evict a LRU entry (cache has no limit).
*
* @since 2.6
*/
public static final String STRUTS_OGNL_BEANINFO_CACHE_LRU_MODE = "struts.ognl.beanInfoCacheLRUMode";
/**
* Logs properties that are not found (very verbose)
* @since 2.6
@@ -278,6 +316,31 @@ public final class StrutsConstants {
*/
public static final String STRUTS_ENABLE_OGNL_EXPRESSION_CACHE = STRUTS_OGNL_ENABLE_EXPRESSION_CACHE;
/**
* Specifies a maximum number of cached parsed OGNL expressions. Not specified/set by default. If
* a positive integer is specified, it will set a limit whose behaviour depends on whether the
* normal (default) cache or optional LRU cache is in place.
*
* For the normal (default) cache, exceeding the maximum will cause the entire cache to flush (clear).
* For the optional LRU cache, once the maximum is reached, the least-recently-used (LRU) entry will be
* removed when a new entry needs to be added (cache is fully-utilized).
*
* @since 2.6
*/
public static final String STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE = "struts.ognl.expressionCacheMaxSize";
/**
* Set the cache mode of the parsed OGNL expression cache. A value of true means enable
* least-recently-used (LRU) mode, a value of false (or any non-true value) means to use the
* default cache.
*
* Note: When enabling LRU cache mode you must also set a maximum size (via {@link #STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE})
* for it to be effective. Otherwise, there is no condition to evict a LRU entry (cache has no limit).
*
* @since 2.6
*/
public static final String STRUTS_OGNL_EXPRESSION_CACHE_LRU_MODE = "struts.ognl.expressionCacheLRUMode";
/**
* Enables evaluation of OGNL expressions
* @since 2.6
@@ -25,6 +25,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.RequestUtils;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.StrutsException;
import org.apache.struts2.util.FastByteArrayOutputStream;
import org.apache.struts2.views.annotations.StrutsTag;
import org.apache.struts2.views.annotations.StrutsTagAttribute;
@@ -33,6 +34,7 @@ import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
@@ -296,6 +298,19 @@ public class Include extends Component {
buffer = new FastByteArrayOutputStream();
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setWriteListener(WriteListener writeListener) {
try {
writeListener.onWritePossible();
} catch (IOException e) {
throw new StrutsException(e);
}
}
/**
* Return all data that has been written to this OutputStream.
@@ -321,7 +321,7 @@ public class ServletUrlRenderer implements UrlRenderer {
* @param parameters component parameters
* @param contextParameters request parameters
*/
protected void mergeRequestParameters(String value, Map<String, Object> parameters, Map<String, Object> contextParameters) {
protected void mergeRequestParameters(String value, Map<String, Object> parameters, Map<String, ?> contextParameters) {
Map<String, Object> mergedParams = new LinkedHashMap<>(contextParameters);
@@ -333,7 +333,7 @@ public class ServletUrlRenderer implements UrlRenderer {
String queryString = value.substring(value.indexOf('?') + 1);
mergedParams = urlHelper.parseQueryString(queryString, false);
for (Map.Entry<String, Object> entry : contextParameters.entrySet()) {
for (Map.Entry<String, ?> entry : contextParameters.entrySet()) {
if (!mergedParams.containsKey(entry.getKey())) {
mergedParams.put(entry.getKey(), entry.getValue());
}
@@ -23,6 +23,8 @@ import com.opensymphony.xwork2.LocaleProviderFactory;
import com.opensymphony.xwork2.LocalizedTextProvider;
import com.opensymphony.xwork2.TextProviderFactory;
import com.opensymphony.xwork2.factory.UnknownHandlerFactory;
import com.opensymphony.xwork2.ognl.BeanInfoCacheFactory;
import com.opensymphony.xwork2.ognl.ExpressionCacheFactory;
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
import com.opensymphony.xwork2.FileManager;
@@ -366,6 +368,7 @@ import org.apache.struts2.views.util.UrlHelper;
*/
public class StrutsBeanSelectionProvider extends AbstractBeanSelectionProvider {
@Override
public void register(ContainerBuilder builder, LocatableProperties props) {
alias(ObjectFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY, builder, props);
alias(ActionFactory.class, StrutsConstants.STRUTS_OBJECTFACTORY_ACTIONFACTORY, builder, props);
@@ -423,6 +426,9 @@ public class StrutsBeanSelectionProvider extends AbstractBeanSelectionProvider {
alias(DateFormatter.class, StrutsConstants.STRUTS_DATE_FORMATTER, builder, props, Scope.SINGLETON);
alias(ExpressionCacheFactory.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_FACTORY, builder, props, Scope.SINGLETON);
alias(BeanInfoCacheFactory.class, StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_FACTORY, builder, props, Scope.SINGLETON);
switchDevMode(props);
}
@@ -90,7 +90,6 @@ public class ConstantConfig {
private BeanConfig localeProviderFactory;
private String mapperIdParameterName;
private Boolean ognlAllowStaticFieldAccess;
private Boolean ognlAllowStaticMethodAccess;
private BeanConfig actionValidatorManager;
private BeanConfig valueStackFactory;
private BeanConfig reflectionProvider;
@@ -144,6 +143,8 @@ public class ConstantConfig {
private Boolean disallowProxyMemberAccess;
private Integer ognlAutoGrowthCollectionLimit;
private String staticContentPath;
private BeanConfig expressionCacheFactory;
private BeanConfig beaninfoCacheFactory;
protected String beanConfToString(BeanConfig beanConf) {
return beanConf == null ? null : beanConf.getName();
@@ -220,7 +221,6 @@ public class ConstantConfig {
map.put(StrutsConstants.STRUTS_LOCALE_PROVIDER_FACTORY, beanConfToString(localeProviderFactory));
map.put(StrutsConstants.STRUTS_ID_PARAMETER_NAME, mapperIdParameterName);
map.put(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, Objects.toString(ognlAllowStaticFieldAccess, null));
map.put(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, Objects.toString(ognlAllowStaticMethodAccess, null));
map.put(StrutsConstants.STRUTS_ACTIONVALIDATORMANAGER, beanConfToString(actionValidatorManager));
map.put(StrutsConstants.STRUTS_VALUESTACKFACTORY, beanConfToString(valueStackFactory));
map.put(StrutsConstants.STRUTS_REFLECTIONPROVIDER, beanConfToString(reflectionProvider));
@@ -274,6 +274,8 @@ public class ConstantConfig {
map.put(StrutsConstants.STRUTS_DISALLOW_PROXY_MEMBER_ACCESS, Objects.toString(disallowProxyMemberAccess, null));
map.put(StrutsConstants.STRUTS_OGNL_AUTO_GROWTH_COLLECTION_LIMIT, Objects.toString(ognlAutoGrowthCollectionLimit, null));
map.put(StrutsConstants.STRUTS_UI_STATIC_CONTENT_PATH, Objects.toString(staticContentPath, StaticContentLoader.DEFAULT_STATIC_CONTENT_PATH));
map.put(StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_FACTORY, beanConfToString(expressionCacheFactory));
map.put(StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_FACTORY, beanConfToString(beaninfoCacheFactory));
return map;
}
@@ -806,14 +808,6 @@ public class ConstantConfig {
this.ognlAllowStaticFieldAccess = ognlAllowStaticFieldAccess;
}
public Boolean getOgnlAllowStaticMethodAccess() {
return ognlAllowStaticMethodAccess;
}
public void setOgnlAllowStaticMethodAccess(Boolean ognlAllowStaticMethodAccess) {
this.ognlAllowStaticMethodAccess = ognlAllowStaticMethodAccess;
}
public BeanConfig getActionValidatorManager() {
return actionValidatorManager;
}
@@ -1341,4 +1335,28 @@ public class ConstantConfig {
public void setStaticContentPath(String staticContentPath) {
this.staticContentPath = StaticContentLoader.Validator.validateStaticContentPath(staticContentPath);
}
public BeanConfig getExpressionCacheFactory() {
return expressionCacheFactory;
}
public void setExpressionCacheFactory(BeanConfig expressionCacheFactory) {
this.expressionCacheFactory = expressionCacheFactory;
}
public void setExpressionCacheFactory(Class<?> clazz) {
this.expressionCacheFactory = new BeanConfig(clazz, clazz.getName());
}
public BeanConfig getBeaninfoCacheFactory() {
return beaninfoCacheFactory;
}
public void setBeaninfoCacheFactory(BeanConfig beaninfoCacheFactory) {
this.beaninfoCacheFactory = beaninfoCacheFactory;
}
public void setBeaninfoCacheFactory(Class<?> clazz) {
this.beaninfoCacheFactory = new BeanConfig(clazz, clazz.getName());
}
}
@@ -1,91 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.util;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* A bean that can be used to format dates
*
* FIXME: remove or use to format Dates
*/
public class DateFormatter {
Date date;
DateFormat format;
// Attributes ----------------------------------------------------
DateFormat parser;
// Public --------------------------------------------------------
public DateFormatter() {
this.parser = new SimpleDateFormat();
this.format = new SimpleDateFormat();
this.date = new Date();
}
public void setDate(String date) {
try {
this.date = parser.parse(date);
} catch (ParseException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
public void setDate(Date date) {
this.date = (date == null) ? null : (Date)date.clone();
}
public void setDate(int date) {
setDate(Integer.toString(date));
}
public Date getDate() {
return this.date;
}
public void setFormat(String format) {
this.format = new SimpleDateFormat(format);
}
public void setFormat(DateFormat format) {
this.format = format;
}
public String getFormattedDate() {
return format.format(date);
}
public void setParseFormat(String format) {
this.parser = new SimpleDateFormat(format);
}
public void setParser(DateFormat parser) {
this.parser = parser;
}
public void setTime(long time) {
date.setTime(time);
}
}
@@ -24,11 +24,13 @@ import com.opensymphony.xwork2.util.TextParseUtil;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsException;
import org.apache.struts2.views.jsp.ui.OgnlTool;
import org.apache.struts2.views.util.UrlHelper;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
@@ -278,6 +280,20 @@ public class StrutsUtil {
public void write(int aByte) {
writer.write(aByte);
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setWriteListener(WriteListener writeListener) {
try {
writeListener.onWritePossible();
} catch (IOException e) {
throw new StrutsException(e);
}
}
}
}
@@ -19,7 +19,6 @@
package org.apache.struts2.util;
import com.opensymphony.xwork2.ActionContext;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.views.util.DefaultUrlHelper;
import org.apache.struts2.views.util.UrlHelper;
@@ -58,20 +57,10 @@ public class URLBean {
public String getURL() {
// all this trickier with maps is to reduce the number of objects created
Map<String, Object> fullParams = null;
if (params != null) {
fullParams = new HashMap<String, Object>();
}
Map<String, Object> fullParams = new HashMap<>();
if (page == null) {
// No particular page requested, so go to "same page"
// Add query params to parameters
if (fullParams != null) {
fullParams.putAll(request.getParameterMap());
} else {
fullParams = request.getParameterMap();
}
fullParams.putAll(request.getParameterMap());
}
// added parameters override, just like in URLTag
@@ -84,7 +73,7 @@ public class URLBean {
public URLBean addParameter(String name, Object value) {
if (params == null) {
params = new HashMap<String, String>();
params = new HashMap<>();
}
if (value == null) {
@@ -229,19 +229,49 @@ struts.ognl.logMissingProperties=false
### if the application generates a lot of different expressions
struts.ognl.enableExpressionCache=true
### Specify the OGNL expression cache factory and BeanInfo cache factory to use.
### Currently, the default implementations are used, but can be replaced with custom ones if desired.
struts.ognl.expressionCacheFactory=defaultOgnlExpressionCacheFactory
struts.ognl.beanInfoCacheFactory=defaultOgnlBeanInfoCacheFactory
### Specify a limit to the number of entries in the OGNL expressionCache.
### For the standard expressionCache mode, when the limit is exceeded the entire cache's
### content will be cleared (can help prevent memory leaks).
### For expressionCacheLRUMode true, the limit will ensure the cache does not exceed
### that size, dropping the oldest (least-recently-used) expressions to add new ones.
### NOTE: If not set, the default is 25000, which may be excessive.
# struts.ognl.expressionCacheMaxSize=1000
### Indicates if the OGNL expressionCache should use LRU mode.
### NOTE: When true, make sure to set the expressionCacheMaxSize to a reasonable value
### for your application. Otherwise the default limit will never (practically) be reached.
# struts.ognl.expressionCacheLRUMode=false
### Specify a limit to the number of entries in the OGNL beanInfoCache.
### For the standard beanInfoCache mode, when the limit is exceeded the entire cache's
### content will be cleared (can help prevent memory leaks).
### For beanInfoCacheLRUMode true, the limit will ensure the cache does not exceed
### that size, dropping the oldest (least-recently-used) expressions to add new ones.
### NOTE: If not set, the default is 25000, which may be excessive.
# struts.ognl.beanInfoCacheMaxSize=1000
### Indicates if the OGNL beanInfoCache should use LRU mode.
### NOTE: When true, make sure to set the beanInfoCacheMaxSize to a reasonable value
### for your application. Otherwise the default limit will never (practically) be reached.
# struts.ognl.beanInfoCacheLRUMode=false
### 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
### **WARNING**: If developers change this option (by configuration) they should make sure that they understand
### the implications of setting 'struts.ognl.expressionMaxLength'. They must choose a value large enough to permit
### ALL valid OGNL expressions used within the application. Values larger than the 200-400 range have diminishing
### security value (at which point it is really only a "style guard" for long OGNL expressions in an application.
### Setting a value of null or "" will also disable the feature.
struts.ognl.expressionMaxLength=256
### Defines which named instance of DateFormatter to use, there are two instances:
### - simpleDateFormatter (based on SimpleDateFormat)
@@ -231,6 +231,9 @@
<bean type="org.apache.struts2.components.date.DateFormatter" name="simpleDateFormatter" class="org.apache.struts2.components.date.SimpleDateFormatAdapter" scope="singleton"/>
<bean type="org.apache.struts2.components.date.DateFormatter" name="dateTimeFormatter" class="org.apache.struts2.components.date.DateTimeFormatterAdapter" scope="singleton"/>
<bean type="com.opensymphony.xwork2.ognl.OgnlCacheFactory" name="ognlExpressionCacheFactory" class="com.opensymphony.xwork2.ognl.DefaultOgnlExpressionCacheFactory" scope="singleton"/>
<bean type="com.opensymphony.xwork2.ognl.OgnlCacheFactory" name="ognlBeanInfoCacheFactory" class="com.opensymphony.xwork2.ognl.DefaultOgnlBeanInfoCacheFactory" scope="singleton"/>
<package name="struts-default" abstract="true">
<result-types>
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
@@ -28,6 +28,9 @@ import org.apache.struts2.conversion.TypeConversionException;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
@@ -43,14 +46,20 @@ public class DateConverterTest extends StrutsInternalTestCase {
private final static String DATE_STR = "2020-03-20";
private final static String DATE_CONVERTED = "Fri Mar 20 00:00:00";
private final static String INVALID_DATE = "99/99/2010";
private final static String LOCALDATETIME_STR = "2020-03-20T00:00:00.000000";
private final static String LOCALDATETIME1_STR = "12:00 AM Fri Mar 20, 2020";
private final static String LOCALDATETIME_CONVERTED = "2020-03-20T00:00";
private final static String LOCALDATE_STR = "2020-03-20";
private final static String LOCALTIME_STR = "01:59:10";
private final static String INVALID_LOCALDATETIME = "2010-99-99T00:00";
private final static String MESSAGE_PARSE_ERROR = "Could not parse date";
private final static String MESSAGE_DEFAULT_CONSTRUCTOR_ERROR = "Couldn't create class null using default (long) constructor";
public void testSqlTimeType() {
DateConverter converter = new DateConverter();
ActionContext context = ActionContext.of(new HashMap<>())
.withLocale(mxLocale);
ActionContext context = ActionContext.of(new HashMap<>()).withLocale(mxLocale);
Object value = converter.convertValue(context.getContextMap(), null, null, null, TIME_01_59_10, Time.class);
assertEquals("01:59:10", value.toString());
@@ -59,10 +68,10 @@ public class DateConverterTest extends StrutsInternalTestCase {
public void testSqlTimestampType() {
DateConverter converter = new DateConverter();
ActionContext context = ActionContext.of(new HashMap<>())
.withLocale(mxLocale);
ActionContext context = ActionContext.of(new HashMap<>()).withLocale(mxLocale);
Object value = converter.convertValue(context.getContextMap(), null, null, null, INPUT_TIME_STAMP_STR, Timestamp.class);
Object value = converter.convertValue(context.getContextMap(), null, null, null, INPUT_TIME_STAMP_STR,
Timestamp.class);
assertEquals(RES_TIME_STAMP_STR, value.toString());
}
@@ -74,9 +83,8 @@ public class DateConverterTest extends StrutsInternalTestCase {
ValueStack stack = new StubValueStack();
stack.push(new StubTextProvider(map));
ActionContext context = ActionContext.of(new HashMap<>())
.withLocale(new Locale("es_MX", "MX"))
.withValueStack(stack);
ActionContext context = ActionContext.of(new HashMap<>()).withLocale(new Locale("es_MX", "MX"))
.withValueStack(stack);
Object value = converter.convertValue(context.getContextMap(), null, null, null, DATE_STR, Date.class);
assertTrue(value.toString().startsWith(DATE_CONVERTED));
@@ -90,9 +98,8 @@ public class DateConverterTest extends StrutsInternalTestCase {
ValueStack stack = new StubValueStack();
stack.push(new StubTextProvider(map));
ActionContext context = ActionContext.of(new HashMap<>())
.withLocale(new Locale("es_MX", "MX"))
.withValueStack(stack);
ActionContext context = ActionContext.of(new HashMap<>()).withLocale(new Locale("es_MX", "MX"))
.withValueStack(stack);
try {
converter.convertValue(context.getContextMap(), null, null, null, INVALID_DATE, Date.class);
@@ -106,8 +113,7 @@ public class DateConverterTest extends StrutsInternalTestCase {
public void testTypeConversionExceptionWhenUsingLongConstructor() {
DateConverter converter = new DateConverter();
ActionContext context = ActionContext.of(new HashMap<>())
.withLocale(mxLocale);
ActionContext context = ActionContext.of(new HashMap<>()).withLocale(mxLocale);
try {
converter.convertValue(context.getContextMap(), null, null, null, INPUT_WHEN_LONG_CONSTRUCTOR_STR, null);
@@ -118,12 +124,73 @@ public class DateConverterTest extends StrutsInternalTestCase {
}
}
public void testLocalDateTimeType() {
DateConverter converter = new DateConverter();
ActionContext context = ActionContext.of(new HashMap<>());
Object value = converter.convertValue(context.getContextMap(), null, null, null, LOCALDATETIME_STR,
LocalDateTime.class);
assertTrue(value.toString().startsWith(LOCALDATETIME_CONVERTED));
}
public void testLocalDateTime1Type() {
DateConverter converter = new DateConverter();
Map<String, String> map = new HashMap<>();
map.put(org.apache.struts2.components.Date.DATETAG_PROPERTY, "hh:mm a EEE MMM dd, yyyy");
ValueStack stack = new StubValueStack();
stack.push(new StubTextProvider(map));
ActionContext context = ActionContext.of(new HashMap<>()).withLocale(mxLocale)
.withValueStack(stack);
Object value = converter.convertValue(context.getContextMap(), null, null, null, LOCALDATETIME1_STR,
LocalDateTime.class);
assertTrue(value.toString().startsWith(LOCALDATETIME_CONVERTED));
}
public void testLocalDateTimeTypeConversionExceptionWhenParseError() {
DateConverter converter = new DateConverter();
ActionContext context = ActionContext.of(new HashMap<>());
try {
converter.convertValue(context.getContextMap(), null, null, null, INVALID_LOCALDATETIME,
LocalDateTime.class);
fail("TypeConversionException expected - Conversion error occurred");
} catch (Exception ex) {
assertEquals(TypeConversionException.class, ex.getClass());
assertEquals(MESSAGE_PARSE_ERROR, ex.getMessage());
}
}
public void testLocalDateType() {
DateConverter converter = new DateConverter();
ActionContext context = ActionContext.of(new HashMap<>());
Object value = converter.convertValue(context.getContextMap(), null, null, null, LOCALDATE_STR,
LocalDate.class);
assertTrue(value.toString().startsWith(LOCALDATE_STR));
}
public void testLocalTimeType() {
DateConverter converter = new DateConverter();
ActionContext context = ActionContext.of(new HashMap<>());
Object value = converter.convertValue(context.getContextMap(), null, null, null, LOCALTIME_STR,
LocalTime.class);
assertTrue(value.toString().startsWith(LOCALTIME_STR));
}
@Override
protected void setUp() throws Exception {
super.setUp();
//Due to JEP 252: Use CLDR Locale Data by Default
// Due to JEP 252: Use CLDR Locale Data by Default
DateFormat dFormat = DateFormat.getDateInstance(DateFormat.SHORT, mxLocale);
if (dFormat.format(new Date()).contains("-")) { // Format when Java 9 or greater
if (dFormat.format(new Date()).contains("-")) { // Format when Java 9 or greater
INPUT_TIME_STAMP_STR = "2020-03-20 00:00:00.000";
INPUT_WHEN_LONG_CONSTRUCTOR_STR = "2020-03-20";
} else {// Format when Java 8 or lower
@@ -39,13 +39,17 @@ import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
import com.opensymphony.xwork2.util.CompoundRoot;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.ValueStackFactory;
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
import ognl.OgnlContext;
import ognl.PropertyAccessor;
import org.apache.struts2.config.StrutsXmlConfigurationProvider;
import org.apache.struts2.dispatcher.HttpParameters;
import org.junit.Assert;
import org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -335,8 +339,8 @@ public class ParametersInterceptorTest extends XWorkTestCase {
// given
Map<String, Object> params = new HashMap<>();
params.put("blah", "This is blah");
params.put("('\\u0023_memberAccess[\\'allowStaticMethodAccess\\']')(meh)", "true");
params.put("('(aaa)(('\\u0023context[\\'xwork.MethodAccessor.denyMethodExecution\\']\\u003d\\u0023foo')(\\u0023foo\\u003dnew java.lang.Boolean(\"false\")))", "");
params.put("('\\u0023_memberAccess[\\'allowStaticFieldAccess\\']')(meh)", "true");
params.put("('(aaa)(('\\u0023context[\\'xwork.MethodAccessor.denyMethodExecution\\']\\u003d\\u0023foo')(\\u0023foo\\u003dnew java.lang.Boolean(\"true\")))", "");
params.put("(asdf)(('\\u0023rt.exit(1)')(\\u0023rt\\u003d@java.lang.Runtime@getRuntime()))", "1");
HashMap<String, Object> extraContext = new HashMap<>();
@@ -351,8 +355,9 @@ public class ParametersInterceptorTest extends XWorkTestCase {
//then
assertEquals("This is blah", ((SimpleAction) proxy.getAction()).getBlah());
boolean allowMethodAccess = ((SecurityMemberAccess) ((OgnlContext) stack.getContext()).getMemberAccess()).getAllowStaticMethodAccess();
assertFalse(allowMethodAccess);
Field field = ReflectionContextState.class.getField("DENY_METHOD_EXECUTION");
boolean allowStaticFieldAccess = ((OgnlContext) stack.getContext()).getMemberAccess().isAccessible(stack.getContext(), proxy.getAction(), field, "");
assertFalse(allowStaticFieldAccess);
}
public void testParameters() throws Exception {
@@ -806,7 +811,7 @@ public class ParametersInterceptorTest extends XWorkTestCase {
ValueStack stack = new OgnlValueStack(
container.getInstance(XWorkConverter.class),
(CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()),
container.getInstance(TextProvider.class, "system"), true, true) {
container.getInstance(TextProvider.class, "system"), true) {
@Override
public void setValue(String expr, Object value) {
actual.put(expr, value);
@@ -35,6 +35,7 @@ import com.opensymphony.xwork2.util.Owner;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.location.LocatableProperties;
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
import java.beans.BeanInfo;
import ognl.InappropriateExpressionException;
import ognl.MethodFailedException;
import ognl.NoSuchPropertyException;
@@ -129,6 +130,61 @@ public class OgnlUtilTest extends XWorkTestCase {
assertSame(expr0, expr2);
}
public void testCacheEnabledMaxSize() throws OgnlException {
ognlUtil.setEnableExpressionCache("true");
ognlUtil.setExpressionCacheMaxSize("1");
Object expr0 = ognlUtil.compile("test");
Object expr2 = ognlUtil.compile("test");
assertSame(expr0, expr2);
assertEquals("Expression cache size should be at its limit", 1, ognlUtil.expressionCacheSize());
// Next epxression cached should cause the cache to clear (exceeding maximum sized).
Object expr3 = ognlUtil.compile("test1");
assertEquals("Expression cache should be empty", 0, ognlUtil.expressionCacheSize());
Object expr4 = ognlUtil.compile("test1");
Object expr5 = ognlUtil.compile("test1");
assertEquals("Expression cache size should still be at its limit", 1, ognlUtil.expressionCacheSize());
assertNotSame("2nd test expression cache attempt will exceed size and force clear, but somehow they match ?", expr3, expr4);
assertSame(expr4, expr5);
// Next epxression cached should cause the cache to clear (exceeding maximum sized).
Object expr6 = ognlUtil.compile("test");
assertEquals("Expression cache should be empty", 0, ognlUtil.expressionCacheSize());
Object expr7 = ognlUtil.compile("test");
Object expr8 = ognlUtil.compile("test");
assertNotSame("2nd test expression cache attempt will exceed size and force clear, but somehow they match ?", expr6, expr7);
assertSame(expr7, expr8);
assertEquals("Expression LRU cache size should still be at its limit", 1, ognlUtil.expressionCacheSize());
assertNotSame("1st test expression identical after ejection from LRU cache ?", expr5, expr0);
}
public void testLRUCacheEnabled() throws OgnlException {
// Force usage of LRU cache factories for the OgnlUtil instance
this.ognlUtil = generateOgnlUtilInstanceWithDefaultLRUCacheFactories();
ognlUtil.setEnableExpressionCache("true");
Object expr0 = ognlUtil.compile("test");
Object expr2 = ognlUtil.compile("test");
assertSame(expr0, expr2);
}
public void testLRUCacheEnabledMaxSize() throws OgnlException {
// Force usage of LRU cache factories for the OgnlUtil instance
this.ognlUtil = generateOgnlUtilInstanceWithDefaultLRUCacheFactories();
ognlUtil.setEnableExpressionCache("true");
ognlUtil.setExpressionCacheMaxSize("1");
Object expr0 = ognlUtil.compile("test");
Object expr2 = ognlUtil.compile("test");
assertSame(expr0, expr2);
assertEquals("Expression LRU cache size should be at its limit", 1, ognlUtil.expressionCacheSize());
Object expr3 = ognlUtil.compile("test1");
Object expr4 = ognlUtil.compile("test1");
assertSame(expr3, expr4);
assertEquals("Expression LRU cache size should still be at its limit", 1, ognlUtil.expressionCacheSize());
Object expr5 = ognlUtil.compile("test");
Object expr6 = ognlUtil.compile("test");
assertSame(expr5, expr6);
assertEquals("Expression LRU cache size should still be at its limit", 1, ognlUtil.expressionCacheSize());
assertNotSame("1st test expression identical after ejection from LRU cache ?", expr5, expr0);
}
public void testExpressionIsCachedIrrespectiveOfItsExecutionStatus() throws OgnlException {
Foo foo = new Foo();
OgnlContext context = (OgnlContext) ognlUtil.createDefaultContext(foo);
@@ -149,6 +205,30 @@ public class OgnlUtilTest extends XWorkTestCase {
}
}
public void testExpressionIsLRUCachedIrrespectiveOfItsExecutionStatus() throws OgnlException {
// Force usage of LRU cache factories for the OgnlUtil instance
this.ognlUtil = generateOgnlUtilInstanceWithDefaultLRUCacheFactories();
ognlUtil.setContainer(container); // Must be explicitly set as the generated OgnlUtil instance has no container
ognlUtil.setEnableExpressionCache("true");
Foo foo = new Foo();
OgnlContext context = (OgnlContext) ognlUtil.createDefaultContext(foo);
// Expression which executes with success
try {
ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_FINAL_PUBLIC_ATTRIBUTE", context, foo);
assertEquals("Successfully executed expression must have been cached", ognlUtil.expressionCacheSize(), 1);
} catch (Exception ex) {
fail("Expression execution should have succeeded here. Exception: " + ex);
}
// Expression which executes with failure
try {
ognlUtil.getValue("@com.opensymphony.xwork2.ognl.OgnlUtilTest@STATIC_PRIVATE_ATTRIBUTE", context, foo);
fail("Expression execution should have failed here");
} catch (Exception ex) {
assertEquals("Expression with failed execution must have been cached nevertheless", ognlUtil.expressionCacheSize(), 2);
}
}
public void testMethodExpressionIsCachedIrrespectiveOfItsExecutionStatus() throws Exception {
Foo foo = new Foo();
OgnlContext context = (OgnlContext) ognlUtil.createDefaultContext(foo);
@@ -193,6 +273,32 @@ public class OgnlUtilTest extends XWorkTestCase {
assertTrue("Expression cache empty after usage ?", ognlUtil.expressionCacheSize() > 0);
}
public void testClearExpressionLRUCache() throws OgnlException {
// Force usage of LRU cache factories for the OgnlUtil instance
this.ognlUtil = generateOgnlUtilInstanceWithDefaultLRUCacheFactories();
ognlUtil.setEnableExpressionCache("true");
// Test that the expression cache is functioning as expected.
Object expr0 = ognlUtil.compile("test");
Object expr1 = ognlUtil.compile("test");
Object expr2 = ognlUtil.compile("test");
// Cache in effect, so expr0, expr1, expr2 should be the same.
assertSame(expr0, expr1);
assertSame(expr0, expr2);
assertTrue("Expression cache empty before clear ?", ognlUtil.expressionCacheSize() > 0);
// Clear the Epxression cache and confirm subsequent requests are new.
ognlUtil.clearExpressionCache();
assertEquals("Expression cache not empty after clear ?", 0, ognlUtil.expressionCacheSize());
Object expr3 = ognlUtil.compile("test");
Object expr4 = ognlUtil.compile("test");
Object expr5 = ognlUtil.compile("test");
// Cache cleared, expr3 should be a new instance.
assertNotSame(expr0, expr3);
// Cache still in effect, so expr3, expr4, expr5 should be the same.
assertSame(expr3, expr4);
assertSame(expr3, expr5);
assertTrue("Expression cache empty after usage ?", ognlUtil.expressionCacheSize() > 0);
}
public void testClearBeanInfoCache() throws IntrospectionException {
final TestBean1 testBean1 = new TestBean1();
final TestBean2 testBean2 = new TestBean2();
@@ -242,6 +348,79 @@ public class OgnlUtilTest extends XWorkTestCase {
assertTrue("BeanInfo cache empty after usage ?", ognlUtil.beanInfoCacheSize() > 0);
}
public void testBeanInfoCache() throws IntrospectionException {
final TestBean1 testBean1 = new TestBean1();
final TestBean2 testBean2 = new TestBean2();
// Test that the BeanInfo cache is functioning as expected.
Object beanInfo1_1 = ognlUtil.getBeanInfo(testBean1);
Object beanInfo1_2 = ognlUtil.getBeanInfo(testBean1);
Object beanInfo1_3 = ognlUtil.getBeanInfo(testBean1);
// Cache in effect, so beanInfo1_1, beanInfo1_2, beanInfo1_3 should be the same.
assertSame(beanInfo1_1, beanInfo1_2);
assertSame(beanInfo1_1, beanInfo1_3);
Object beanInfo2_1 = ognlUtil.getBeanInfo(testBean2);
Object beanInfo2_2 = ognlUtil.getBeanInfo(testBean2);
Object beanInfo2_3 = ognlUtil.getBeanInfo(testBean2);
// Cache in effect, so beanInfo2_1, beanInfo2_2, beanInfo2_3 should be the same.
assertSame(beanInfo2_1, beanInfo2_2);
assertSame(beanInfo2_1, beanInfo2_3);
// BeanInfo for TestBean1 and TestBean2 should always be different.
assertNotSame(beanInfo1_1, beanInfo2_1);
assertTrue("BeanInfo cache empty after usage ?", ognlUtil.beanInfoCacheSize() > 0);
}
public void testBeanInfoLRUCache() throws IntrospectionException {
// Force usage of LRU cache factories for the OgnlUtil instance
this.ognlUtil = generateOgnlUtilInstanceWithDefaultLRUCacheFactories();
final TestBean1 testBean1 = new TestBean1();
final TestBean2 testBean2 = new TestBean2();
// Test that the BeanInfo cache is functioning as expected.
Object beanInfo1_1 = ognlUtil.getBeanInfo(testBean1);
Object beanInfo1_2 = ognlUtil.getBeanInfo(testBean1);
Object beanInfo1_3 = ognlUtil.getBeanInfo(testBean1);
// Cache in effect, so beanInfo1_1, beanInfo1_2, beanInfo1_3 should be the same.
assertSame(beanInfo1_1, beanInfo1_2);
assertSame(beanInfo1_1, beanInfo1_3);
Object beanInfo2_1 = ognlUtil.getBeanInfo(testBean2);
Object beanInfo2_2 = ognlUtil.getBeanInfo(testBean2);
Object beanInfo2_3 = ognlUtil.getBeanInfo(testBean2);
// Cache in effect, so beanInfo2_1, beanInfo2_2, beanInfo2_3 should be the same.
assertSame(beanInfo2_1, beanInfo2_2);
assertSame(beanInfo2_1, beanInfo2_3);
// BeanInfo for TestBean1 and TestBean2 should always be different.
assertNotSame(beanInfo1_1, beanInfo2_1);
assertTrue("BeanInfo cache empty after usage ?", ognlUtil.beanInfoCacheSize() > 0);
}
public void testBeanInfoLRUCacheLimits() throws IntrospectionException {
// Force usage of LRU cache factories for the OgnlUtil instance
this.ognlUtil = generateOgnlUtilInstanceWithDefaultLRUCacheFactories();
ognlUtil.setBeanInfoCacheMaxSize("1");
final TestBean1 testBean1 = new TestBean1();
final TestBean2 testBean2 = new TestBean2();
// Test that the BeanInfo cache is functioning as expected.
Object beanInfo1_1 = ognlUtil.getBeanInfo(testBean1);
Object beanInfo1_2 = ognlUtil.getBeanInfo(testBean1);
Object beanInfo1_3 = ognlUtil.getBeanInfo(testBean1);
// Cache in effect, so beanInfo1_1, beanInfo1_2, beanInfo1_3 should be the same.
assertSame(beanInfo1_1, beanInfo1_2);
assertSame(beanInfo1_1, beanInfo1_3);
Object beanInfo2_1 = ognlUtil.getBeanInfo(testBean2);
Object beanInfo2_2 = ognlUtil.getBeanInfo(testBean2);
Object beanInfo2_3 = ognlUtil.getBeanInfo(testBean2);
// Cache in effect, so beanInfo2_1, beanInfo2_2, beanInfo2_3 should be the same.
assertSame(beanInfo2_1, beanInfo2_2);
assertSame(beanInfo2_1, beanInfo2_3);
// BeanInfo for TestBean1 and TestBean2 should always be different.
assertNotSame(beanInfo1_1, beanInfo2_1);
assertTrue("BeanInfo cache empty after usage ?", ognlUtil.beanInfoCacheSize() > 0);
assertEquals("BeanInfo LRU cache size should be at its limit", 1, ognlUtil.beanInfoCacheSize());
// LRU cache should not contain TestBean1 beaninfo anymore. A new entry should exist in the cache.
Object beanInfo1_4 = ognlUtil.getBeanInfo(testBean1);
assertNotSame("BeanInfo dropped from LRU cache is the same as newly added ?", beanInfo1_1, beanInfo1_4);
ognlUtil.setBeanInfoCacheMaxSize(String.valueOf(Integer.MAX_VALUE));
}
public void testClearRuntimeCache() {
// Confirm that no exceptions or failures arise when calling the convenience global clear method.
OgnlUtil.clearRuntimeCache();
@@ -1134,6 +1313,20 @@ public class OgnlUtilTest extends XWorkTestCase {
internalTestOgnlUtilExclusionsImmutable(basicOgnlUtil);
}
public void testDefaultOgnlUtilExclusionsAlternateConstructor() {
OgnlUtil basicOgnlUtil = new OgnlUtil(null, null);
internalTestInitialEmptyOgnlUtilExclusions(basicOgnlUtil);
internalTestOgnlUtilExclusionsImmutable(basicOgnlUtil);
}
public void testDefaultOgnlUtilExclusionsAlternateConstructorPopulated() {
OgnlUtil basicOgnlUtil = new OgnlUtil(new DefaultOgnlExpressionCacheFactory<String, Object>(), new DefaultOgnlBeanInfoCacheFactory<Class<?>, BeanInfo>());
internalTestInitialEmptyOgnlUtilExclusions(basicOgnlUtil);
internalTestOgnlUtilExclusionsImmutable(basicOgnlUtil);
}
public void testOgnlUtilExcludedAdditivity() {
Set<Class<?>> excludedClasses;
Set<Pattern> excludedPackageNamePatterns;
@@ -1497,6 +1690,34 @@ public class OgnlUtilTest extends XWorkTestCase {
}
}
public void testGetExcludedPackageNamesAlternateConstructor() {
// Getter should return an immutable collection
OgnlUtil util = new OgnlUtil(null, null);
util.setExcludedPackageNames("java.lang,java.awt");
assertEquals(util.getExcludedPackageNames().size(), 2);
try {
util.getExcludedPackageNames().clear();
} catch (Exception ex) {
assertTrue(ex instanceof UnsupportedOperationException);
} finally {
assertEquals(util.getExcludedPackageNames().size(), 2);
}
}
public void testGetExcludedPackageNamesAlternateConstructorPopulated() {
// Getter should return an immutable collection
OgnlUtil util = new OgnlUtil(new DefaultOgnlExpressionCacheFactory<String, Object>(), new DefaultOgnlBeanInfoCacheFactory<Class<?>, BeanInfo>());
util.setExcludedPackageNames("java.lang,java.awt");
assertEquals(util.getExcludedPackageNames().size(), 2);
try {
util.getExcludedPackageNames().clear();
} catch (Exception ex) {
assertTrue(ex instanceof UnsupportedOperationException);
} finally {
assertEquals(util.getExcludedPackageNames().size(), 2);
}
}
public void testGetExcludedClasses() {
// Getter should return an immutable collection
OgnlUtil util = new OgnlUtil();
@@ -1511,6 +1732,34 @@ public class OgnlUtilTest extends XWorkTestCase {
}
}
public void testGetExcludedClassesAlternateConstructor() {
// Getter should return an immutable collection
OgnlUtil util = new OgnlUtil(null, null);
util.setExcludedClasses("java.lang.Runtime,java.lang.ProcessBuilder,java.net.URL");
assertEquals(util.getExcludedClasses().size(), 3);
try {
util.getExcludedClasses().clear();
} catch (Exception ex) {
assertTrue(ex instanceof UnsupportedOperationException);
} finally {
assertEquals(util.getExcludedClasses().size(), 3);
}
}
public void testGetExcludedClassesAlternateConstructorPopulated() {
// Getter should return an immutable collection
OgnlUtil util = new OgnlUtil(new DefaultOgnlExpressionCacheFactory<String, Object>(), new DefaultOgnlBeanInfoCacheFactory<Class<?>, BeanInfo>());
util.setExcludedClasses("java.lang.Runtime,java.lang.ProcessBuilder,java.net.URL");
assertEquals(util.getExcludedClasses().size(), 3);
try {
util.getExcludedClasses().clear();
} catch (Exception ex) {
assertTrue(ex instanceof UnsupportedOperationException);
} finally {
assertEquals(util.getExcludedClasses().size(), 3);
}
}
public void testGetExcludedPackageNamePatterns() {
// Getter should return an immutable collection
OgnlUtil util = new OgnlUtil();
@@ -1525,13 +1774,139 @@ public class OgnlUtilTest extends XWorkTestCase {
}
}
private void reloadTestContainerConfiguration(boolean devMode, boolean allowStaticMethod) {
public void testGetExcludedPackageNamePatternsAlternateConstructor() {
// Getter should return an immutable collection
OgnlUtil util = new OgnlUtil(null, null);
util.setExcludedPackageNamePatterns("java.lang.");
assertEquals(util.getExcludedPackageNamePatterns().size(), 1);
try {
util.getExcludedPackageNamePatterns().clear();
} catch (Exception ex) {
assertTrue(ex instanceof UnsupportedOperationException);
} finally {
assertEquals(util.getExcludedPackageNamePatterns().size(), 1);
}
}
public void testGetExcludedPackageNamePatternsAlternateConstructorPopulated() {
// Getter should return an immutable collection
OgnlUtil util = new OgnlUtil(new DefaultOgnlExpressionCacheFactory<String, Object>(), new DefaultOgnlBeanInfoCacheFactory<Class<?>, BeanInfo>());
util.setExcludedPackageNamePatterns("java.lang.");
assertEquals(util.getExcludedPackageNamePatterns().size(), 1);
try {
util.getExcludedPackageNamePatterns().clear();
} catch (Exception ex) {
assertTrue(ex instanceof UnsupportedOperationException);
} finally {
assertEquals(util.getExcludedPackageNamePatterns().size(), 1);
}
}
public void testOgnlUtilDefaultCacheClass() throws OgnlException {
OgnlDefaultCache<Integer, String> defaultCache = new OgnlDefaultCache<>(2, 16, 0.75f);
assertEquals("Initial evictionLimit did not match initial value", 2, defaultCache.getEvictionLimit());
defaultCache.setEvictionLimit(3);
assertEquals("Updated evictionLimit did not match updated value", 3, defaultCache.getEvictionLimit());
String lookupResult = defaultCache.get(Integer.valueOf(0));
assertNull("Lookup of empty cache returned non-null value ?", lookupResult);
defaultCache.put(Integer.valueOf(0), "Zero");
lookupResult = defaultCache.get(Integer.valueOf(0));
assertEquals("Retrieved value does not match put value ?", "Zero", lookupResult);
defaultCache.put(Integer.valueOf(1), "One");
defaultCache.put(Integer.valueOf(2), "Two");
assertEquals("Default cache not size evictionlimit after adding three values ?", defaultCache.getEvictionLimit(), defaultCache.size());
lookupResult = defaultCache.get(Integer.valueOf(2));
assertEquals("Retrieved value does not match put value ?", "Two", lookupResult);
defaultCache.put(Integer.valueOf(3), "Three");
assertEquals("Default cache not size zero after an add that exceeded the evection limit ?", 0, defaultCache.size());
lookupResult = defaultCache.get(Integer.valueOf(0));
assertNull("Lookup of value 0 (should have been evicted with everything) returned non-null value ?", lookupResult);
lookupResult = defaultCache.get(Integer.valueOf(3));
assertNull("Lookup of value 3 (should have been evicted with everything) returned non-null value ?", lookupResult);
defaultCache.putIfAbsent(Integer.valueOf(2), "Two");
lookupResult = defaultCache.get(Integer.valueOf(2));
assertEquals("Retrieved value does not match put value ?", "Two", lookupResult);
defaultCache.clear();
assertEquals("Default cache not empty after clear ?", 0, defaultCache.size());
}
public void testOgnlUtilLRUCacheClass() throws OgnlException {
OgnlLRUCache<Integer, String> lruCache = new OgnlLRUCache<>(2, 16, 0.75f);
assertEquals("Initial evictionLimit did not match initial value", 2, lruCache.getEvictionLimit());
lruCache.setEvictionLimit(3);
assertEquals("Updated evictionLimit did not match updated value", 3, lruCache.getEvictionLimit());
String lookupResult = lruCache.get(Integer.valueOf(0));
assertNull("Lookup of empty cache returned non-null value ?", lookupResult);
lruCache.put(Integer.valueOf(0), "Zero");
lookupResult = lruCache.get(Integer.valueOf(0));
assertEquals("Retrieved value does not match put value ?", "Zero", lookupResult);
lruCache.put(Integer.valueOf(1), "One");
lruCache.put(Integer.valueOf(2), "Two");
assertEquals("LRU cache not size evictionlimit after adding three values ?", lruCache.getEvictionLimit(), lruCache.size());
lookupResult = lruCache.get(Integer.valueOf(2));
assertEquals("Retrieved value does not match put value ?", "Two", lookupResult);
lruCache.put(Integer.valueOf(3), "Three");
assertEquals("LRU cache not size evictionlimit after adding values ?", lruCache.getEvictionLimit(), lruCache.size());
lookupResult = lruCache.get(Integer.valueOf(0));
assertNull("Lookup of value 0 (should have dropped off LRU cache) returned non-null value ?", lookupResult);
lruCache.putIfAbsent(Integer.valueOf(2), "Two");
lookupResult = lruCache.get(Integer.valueOf(2));
assertEquals("Retrieved value does not match put value ?", "Two", lookupResult);
lruCache.clear();
assertEquals("LRU cache not empty after clear ?", 0, lruCache.size());
}
/**
* Unit test primarily for code coverage
*/
public void testOgnlDefaultCacheFactoryCoverage() {
OgnlCache<String, Object> ognlCache;
DefaultOgnlCacheFactory defaultOgnlCacheFactory = new DefaultOgnlCacheFactory<String, Object>();
// Normal cache
defaultOgnlCacheFactory.setCacheMaxSize("12");
defaultOgnlCacheFactory.setUseLRUCache("false");
ognlCache = defaultOgnlCacheFactory.buildOgnlCache();
assertNotNull("No param build method result null ?", ognlCache);
assertEquals("Eviction limit for cache mismatches limit for factory ?", 12, ognlCache.getEvictionLimit() );
ognlCache = defaultOgnlCacheFactory.buildOgnlCache(6, 6, 0.75f, false);
assertNotNull("No param build method result null ?", ognlCache);
assertEquals("Eviction limit for cache mismatches limit for factory ?", 6, ognlCache.getEvictionLimit() );
// LRU cache
defaultOgnlCacheFactory.setCacheMaxSize("30");
defaultOgnlCacheFactory.setUseLRUCache("true");
ognlCache = defaultOgnlCacheFactory.buildOgnlCache();
assertNotNull("No param build method result null ?", ognlCache);
assertEquals("Eviction limit for cache mismatches limit for factory ?", 30, ognlCache.getEvictionLimit() );
ognlCache = defaultOgnlCacheFactory.buildOgnlCache(15, 15, 0.75f, false);
assertNotNull("No param build method result null ?", ognlCache);
assertEquals("Eviction limit for cache mismatches limit for factory ?", 15, ognlCache.getEvictionLimit() );
}
/**
* Generate a new OgnlUtil instance (not configured by the {@link ContainerBuilder}) that can be used for
* basic tests, with its Expression and BeanInfo factories set to LRU mode.
*
* @return OgnlUtil instance with LRU enabled Expression and BeanInfo factories
*/
private OgnlUtil generateOgnlUtilInstanceWithDefaultLRUCacheFactories() {
final OgnlUtil result;
final DefaultOgnlExpressionCacheFactory<String, Object> expressionFactory = new DefaultOgnlExpressionCacheFactory<>();
final DefaultOgnlBeanInfoCacheFactory<Class<?>, BeanInfo> beanInfoFactory = new DefaultOgnlBeanInfoCacheFactory<>();
expressionFactory.setUseLRUCache("true");
expressionFactory.setCacheMaxSize("25");
beanInfoFactory.setUseLRUCache("true");
beanInfoFactory.setCacheMaxSize("25");
result = new OgnlUtil(expressionFactory, beanInfoFactory);
return result;
}
private void reloadTestContainerConfiguration(boolean devMode, boolean allowStaticFieldAccess) {
loadConfigurationProviders(new StubConfigurationProvider() {
@Override
public void register(ContainerBuilder builder,
LocatableProperties props) throws ConfigurationException {
props.setProperty(StrutsConstants.STRUTS_DEVMODE, "" + devMode);
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, "" + allowStaticMethod);
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, "" + allowStaticFieldAccess);
}
});
ognlUtil = container.getInstance(OgnlUtil.class);
@@ -18,7 +18,10 @@
*/
package com.opensymphony.xwork2.ognl;
import com.opensymphony.xwork2.*;
import com.opensymphony.xwork2.SimpleAction;
import com.opensymphony.xwork2.TestBean;
import com.opensymphony.xwork2.TextProvider;
import com.opensymphony.xwork2.XWorkTestCase;
import com.opensymphony.xwork2.config.ConfigurationException;
import com.opensymphony.xwork2.conversion.impl.ConversionData;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
@@ -26,22 +29,17 @@ import com.opensymphony.xwork2.inject.ContainerBuilder;
import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
import com.opensymphony.xwork2.test.StubConfigurationProvider;
import com.opensymphony.xwork2.test.TestBean2;
import com.opensymphony.xwork2.util.*;
import com.opensymphony.xwork2.util.Bar;
import com.opensymphony.xwork2.util.BarJunior;
import com.opensymphony.xwork2.util.Cat;
import com.opensymphony.xwork2.util.CompoundRoot;
import com.opensymphony.xwork2.util.Dog;
import com.opensymphony.xwork2.util.Foo;
import com.opensymphony.xwork2.util.ValueStackFactory;
import com.opensymphony.xwork2.util.location.LocatableProperties;
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
import ognl.OgnlException;
import ognl.PropertyAccessor;
import java.io.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import ognl.ParseException;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LogEvent;
@@ -51,10 +49,18 @@ import org.apache.struts2.StrutsConstants;
import org.apache.struts2.StrutsException;
import org.apache.struts2.config.DefaultPropertiesProvider;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Unit test for OgnlValueStack.
*/
public class OgnlValueStackTest extends XWorkTestCase {
// Fields for static field access test
@@ -85,16 +91,15 @@ public class OgnlValueStackTest extends XWorkTestCase {
}
private OgnlValueStack createValueStack() {
return createValueStack(true, true);
return createValueStack(true);
}
private OgnlValueStack createValueStack(boolean allowStaticMethodAccess, boolean allowStaticFieldAccess) {
private OgnlValueStack createValueStack(boolean allowStaticFieldAccess) {
OgnlValueStack stack = new OgnlValueStack(
container.getInstance(XWorkConverter.class),
(CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()),
container.getInstance(TextProvider.class, "system"), allowStaticMethodAccess, allowStaticFieldAccess);
container.getInstance(XWorkConverter.class),
(CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()),
container.getInstance(TextProvider.class, "system"), allowStaticFieldAccess);
container.inject(stack);
ognlUtil.setAllowStaticMethodAccess(Boolean.toString(allowStaticMethodAccess));
ognlUtil.setAllowStaticFieldAccess(Boolean.toString(allowStaticFieldAccess));
return stack;
}
@@ -111,16 +116,14 @@ public class OgnlValueStackTest extends XWorkTestCase {
* Intended for testing OgnlValueStack instance(s) that are minimally configured.
* This should help ensure no underlying configuration/injection side-effects are responsible
* for the behaviour of fundamental access control flags).
*
* @param allowStaticMethod new allowStaticMethod configuration
*
* @param allowStaticField new allowStaticField configuration
* @return a new OgnlValueStackFactory with specified new configuration
*/
private OgnlValueStackFactory reloadValueStackFactory(Boolean allowStaticMethod, Boolean allowStaticField) {
private OgnlValueStackFactory reloadValueStackFactory(Boolean allowStaticField) {
try {
reloadTestContainerConfiguration(allowStaticMethod, allowStaticField);
}
catch (Exception ex) {
reloadTestContainerConfiguration(allowStaticField);
} catch (Exception ex) {
fail("Unable to reload container configuration and configure ognlValueStackFactory - exception: " + ex);
}
@@ -210,7 +213,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
vs.findValue("barJunior.title", true);
}
public void testSuccessFailOnErrorOnInheritedPropertiesWithMethods() {
public void testSuccessFailOnErrorOnInheritedPropertiesWithMethods() {
//this shuld not fail as the property is defined on a parent class
OgnlValueStack vs = createValueStack();
@@ -254,6 +257,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
/**
* monitors the resolution of WW-4999
*
* @since 2.5.21
*/
public void testLogMissingProperties() {
@@ -281,11 +285,11 @@ public class OgnlValueStackTest extends XWorkTestCase {
if (logMissingProperties) {
assertEquals(3, testAppender.logEvents.size());
assertEquals("Error setting value [missingProp1Value] with expression [missingProp1]",
testAppender.logEvents.get(0).getMessage().getFormattedMessage());
testAppender.logEvents.get(0).getMessage().getFormattedMessage());
assertEquals("Could not find property [missingProp2]!",
testAppender.logEvents.get(1).getMessage().getFormattedMessage());
testAppender.logEvents.get(1).getMessage().getFormattedMessage());
assertEquals("Could not find property [missingProp3]!",
testAppender.logEvents.get(2).getMessage().getFormattedMessage());
testAppender.logEvents.get(2).getMessage().getFormattedMessage());
} else {
assertEquals(0, testAppender.logEvents.size());
}
@@ -297,6 +301,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
/**
* tests the correctness of distinguishing between user exception and NoSuchMethodException
*
* @since 2.5.21
*/
public void testNotLogUserExceptionsAsMissingProperties() {
@@ -364,7 +369,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
}
});
Integer repeat = Integer.parseInt(
container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH));
container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH));
OgnlValueStack vs = createValueStack();
try {
@@ -383,65 +388,40 @@ public class OgnlValueStackTest extends XWorkTestCase {
public void testNotFailOnTooLongExpressionWithDefaultProperties() {
loadConfigurationProviders(new DefaultPropertiesProvider());
Object defaultMaxLengthFromConfiguration = container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH);
if (defaultMaxLengthFromConfiguration != null) {
assertTrue("non-null defaultMaxLengthFromConfiguration not a String ?", defaultMaxLengthFromConfiguration instanceof String);
assertTrue("non-null defaultMaxLengthFromConfiguration not empty string by default ?", ((String) defaultMaxLengthFromConfiguration).length() == 0);
} else {
assertNull("defaultMaxLengthFromConfiguration not null ?", defaultMaxLengthFromConfiguration);
}
// Original test logic was to confirm failure of exceeding the default value. Now the feature should be disabled by default,
// so this test's expectations are now changed.
Integer repeat = Integer.valueOf(256); // Since maxlength is disabled by default, just choose an arbitrary value for test
String defaultMaxLengthFromConfiguration = container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH);
assertNotNull(defaultMaxLengthFromConfiguration);
int defaultValue = 256;
OgnlValueStack vs = createValueStack();
try {
vs.findValue(StringUtils.repeat('.', repeat + 1), true);
vs.findValue(StringUtils.repeat('.', defaultValue + 1), true);
fail("findValue did not throw any exception (should either fail as invalid expression syntax or security exception) ?");
} catch (Exception ex) {
// If STRUTS_OGNL_EXPRESSION_MAX_LENGTH feature is disabled (default), the parse should fail due to a reason of invalid expression syntax
// with ParseException. Previously when it was enabled the reason for the failure would have been SecurityException.
assertTrue(ex.getCause() instanceof OgnlException);
assertTrue(((OgnlException) ex.getCause()).getReason() instanceof ParseException);
assertTrue(((OgnlException) ex.getCause()).getReason() instanceof SecurityException);
assertTrue(((OgnlException) ex.getCause()).getReason().getMessage().startsWith("This expression exceeded maximum allowed length"));
}
}
public void testNotFailOnTooLongValueWithDefaultProperties() {
try {
loadConfigurationProviders(new DefaultPropertiesProvider());
loadConfigurationProviders(new DefaultPropertiesProvider());
Object defaultMaxLengthFromConfiguration = container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH);
if (defaultMaxLengthFromConfiguration != null) {
assertTrue("non-null defaultMaxLengthFromConfiguration not a String ?", defaultMaxLengthFromConfiguration instanceof String);
assertTrue("non-null defaultMaxLengthFromConfiguration not empty string by default ?", ((String) defaultMaxLengthFromConfiguration).length() == 0);
} else {
assertNull("defaultMaxLengthFromConfiguration not null ?", defaultMaxLengthFromConfiguration);
}
// Original test logic is unchanged (testing that values can be larger than maximum expression length), but since the feature is disabled by
// default we will now have to enable it with an arbitrary value, test, and reset it to disabled.
Integer repeat = Integer.valueOf(256); // Since maxlength is disabled by default, just choose an arbitrary value for test
Object defaultMaxLengthFromConfiguration = container.getInstance(String.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_MAX_LENGTH);
assertNotNull(defaultMaxLengthFromConfiguration);
// Apply a non-default value for expressionMaxLength (as it should be disabled by default)
try {
ognlUtil.applyExpressionMaxLength(repeat.toString());
} catch (Exception ex) {
fail ("applyExpressionMaxLength did not accept maxlength string " + repeat.toString() + " ?");
}
int defaultValue = 256;
OgnlValueStack vs = createValueStack();
OgnlValueStack vs = createValueStack();
Dog dog = new Dog();
vs.push(dog);
Dog dog = new Dog();
vs.push(dog);
String value = StringUtils.repeat('.', repeat + 1);
String value = StringUtils.repeat('.', defaultValue);
vs.setValue("name", value);
vs.setValue("name", value);
assertEquals(value, dog.getName());
} finally {
// Reset expressionMaxLength value to default (disabled)
ognlUtil.applyExpressionMaxLength(null);
}
assertEquals(value, dog.getName());
}
public void testFailsOnMethodThatThrowsException() {
@@ -502,7 +482,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
Dog dog = new Dog();
dog.setDeity("fido");
vs.push(dog);
assertEquals("fido", vs.findValue("@com.opensymphony.xwork2.util.Dog@getDeity()", String.class));
assertNull(vs.findValue("@com.opensymphony.xwork2.util.Dog@getDeity()", String.class));
}
/**
@@ -517,7 +497,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
}
public void testStaticMethodDisallow() {
OgnlValueStack vs = createValueStack(false, true);
OgnlValueStack vs = createValueStack(true);
Dog dog = new Dog();
dog.setDeity("fido");
@@ -845,8 +825,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
try {
stack.setValue("bar", "3x");
fail("Attempt to set 'bar' int property to '3x' should result in RuntimeException");
}
catch (RuntimeException re) {
} catch (RuntimeException re) {
assertTrue(true);
}
@@ -1082,6 +1061,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
/**
* Fails on 2.5.20 and earlier - tested on 2.5 (5/5/2016) and failed
*
* @since 2.5.21
*/
public void testNotThrowExceptionOnTopMissingProperty() {
@@ -1104,6 +1084,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
/**
* Fails on 2.5.20 and earlier - tested on 2.5 (5/5/2016) and failed
*
* @since 2.5.21
*/
public void testNotSkipUserReturnedNullValues() {
@@ -1187,8 +1168,8 @@ public class OgnlValueStackTest extends XWorkTestCase {
stack.push("Hello World");
OgnlValueStack stack2 = new OgnlValueStack(stack,
container.getInstance(XWorkConverter.class),
(CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()), true, true);
container.getInstance(XWorkConverter.class),
(CompoundRootAccessor) container.getInstance(PropertyAccessor.class, CompoundRoot.class.getName()), true);
container.inject(stack2);
assertEquals(stack.getRoot(), stack2.getRoot());
@@ -1260,7 +1241,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
assertNull(stack.findValue("address.country.name", String.class));
}
/**
/**
* Test a default OgnlValueStackFactory and OgnlValueStack generated by it
* when a default configuration is used.
*/
@@ -1271,7 +1252,6 @@ public class OgnlValueStackTest extends XWorkTestCase {
// An OgnlValueStackFactory using a container config with default (from XWorkConfigurationProvider)
// static access flag values present should prevent staticMethodAccess but allow staticFieldAccess.
assertFalse("OgnlValueStackFactory staticMethodAccess (default flags) not false?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
assertTrue("OgnlValueStackFactory staticFieldAccess (default flags) not true?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
// An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
// but prevent non-public field access. It should also deny static method access.
@@ -1300,7 +1280,7 @@ public class OgnlValueStackTest extends XWorkTestCase {
* when no static access flags are set (not present in configuration).
*/
public void testOgnlValueStackFromOgnlValueStackFactoryNoFlagsSet() {
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(null, null);
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(null);
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
Object accessedValue;
@@ -1309,7 +1289,6 @@ public class OgnlValueStackTest extends XWorkTestCase {
// prevent staticMethodAccess AND prevent staticFieldAccess.
// Note: Under normal circumstances, explicit static access configuration flags should be present,
// but this specific check verifies what happens if those configuration flags are not present.
assertFalse("OgnlValueStackFactory staticMethodAccess (no flag present) not false?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
assertFalse("OgnlValueStackFactory staticFieldAccess (no flag present) not false?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
// An OgnlValueStack created from the above OgnlValueStackFactory should prevent public field access,
// and prevent non-public field access. It should also deny static method access.
@@ -1335,16 +1314,15 @@ public class OgnlValueStackTest extends XWorkTestCase {
/**
* Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
* when both static access flags are set to false.
* when static access flag is set to false.
*/
public void testOgnlValueStackFromOgnlValueStackFactoryNoStaticAccess() {
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(false, false);
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(false);
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
Object accessedValue;
// An OgnlValueStackFactory using a container config with both static access flags set false should
// prevent staticMethodAccess AND prevent staticFieldAccess.
assertFalse("OgnlValueStackFactory staticMethodAccess (set false) not false?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
assertFalse("OgnlValueStackFactory staticFieldAccess (set false) not false?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
// An OgnlValueStack created from the above OgnlValueStackFactory should prevent public field access,
// and prevent non-public field access. It should also deny static method access.
@@ -1370,22 +1348,20 @@ public class OgnlValueStackTest extends XWorkTestCase {
/**
* Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
* when both static access flags are set to true.
* when static access flag is set to true.
*/
public void testOgnlValueStackFromOgnlValueStackFactoryAllStaticAccess() {
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(true, true);
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(true);
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
Object accessedValue;
// An OgnlValueStackFactory using a container config with both static access flags set true should
// allow both staticMethodAccess AND staticFieldAccess.
assertTrue("OgnlValueStackFactory staticMethodAccess (set true) not true?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
assertTrue("OgnlValueStackFactory staticFieldAccess (set true) not true?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
// An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
// but prevent non-public field access. It should also allow static method access.
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
assertNotNull("unable to access static method (result null) ?", accessedValue);
assertEquals("accessed static method result not equal to expected?", accessedValue, staticInteger100Method());
assertNull("able to access static method (result non-null)!!!", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
@@ -1404,93 +1380,14 @@ public class OgnlValueStackTest extends XWorkTestCase {
assertNull("accessed private field (result not null) ?", accessedValue);
}
/**
* Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
* when static method access flag is true, static field access flag is false.
*/
public void testOgnlValueStackFromOgnlValueStackFactoryOnlyStaticMethodAccess() {
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(true, false);
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
Object accessedValue;
// An OgnlValueStackFactory using a container config with static method access flag true, static field access false should
// allow staticMethodAccess but deny staticFieldAccess.
assertTrue("OgnlValueStackFactory staticMethodAccess (set true) not true?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
assertFalse("OgnlValueStackFactory staticFieldAccess (set false) not false?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
// An OgnlValueStack created from the above OgnlValueStackFactory should deny public field access,
// and also prevent non-public field access. It should also allow static method access.
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
assertNotNull("unable to access static method (result null) ?", accessedValue);
assertEquals("accessed static method result not equal to expected?", accessedValue, staticInteger100Method());
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
assertNull("able to access static final public field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
assertNull("able to access static public field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
assertNull("accessed final package field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
assertNull("accessed package field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
assertNull("accessed final protected field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
assertNull("accessed protected field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
assertNull("accessed final private field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
assertNull("accessed private field (result not null) ?", accessedValue);
}
/**
* Test a raw OgnlValueStackFactory and OgnlValueStack generated by it
* when static method access flag is false, static field access flag is true.
*/
public void testOgnlValueStackFromOgnlValueStackFactoryOnlyStaticFieldAccess() {
OgnlValueStackFactory ognlValueStackFactory = reloadValueStackFactory(false, true);
OgnlValueStack ognlValueStack = (OgnlValueStack) ognlValueStackFactory.createValueStack();
Object accessedValue;
// An OgnlValueStackFactory using a container config with static method access flag false, static field access true should
// deny staticMethodAccess but allow staticFieldAccess.
assertFalse("OgnlValueStackFactory staticMethodAccess (set false) not false?", ognlValueStackFactory.containerAllowsStaticMethodAccess());
assertTrue("OgnlValueStackFactory staticFieldAccess (set true) not true?", ognlValueStackFactory.containerAllowsStaticFieldAccess());
// An OgnlValueStack created from the above OgnlValueStackFactory should allow public field access,
// but prevent non-public field access. It should also deny static method access.
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@staticInteger100Method()");
assertNull("able to access static method (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PUBLIC_ATTRIBUTE");
assertEquals("accessed static final public field value not equal to actual?", accessedValue, STATIC_FINAL_PUBLIC_ATTRIBUTE);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PUBLIC_ATTRIBUTE");
assertEquals("accessed static public field value not equal to actual?", accessedValue, STATIC_PUBLIC_ATTRIBUTE);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PACKAGE_ATTRIBUTE");
assertNull("accessed final package field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PACKAGE_ATTRIBUTE");
assertNull("accessed package field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PROTECTED_ATTRIBUTE");
assertNull("accessed final protected field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PROTECTED_ATTRIBUTE");
assertNull("accessed protected field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_FINAL_PRIVATE_ATTRIBUTE");
assertNull("accessed final private field (result not null) ?", accessedValue);
accessedValue = ognlValueStack.findValue("@com.opensymphony.xwork2.ognl.OgnlValueStackTest@STATIC_PRIVATE_ATTRIBUTE");
assertNull("accessed private field (result not null) ?", accessedValue);
}
private void reloadTestContainerConfiguration(Boolean allowStaticMethod, Boolean allowStaticField) throws Exception {
private void reloadTestContainerConfiguration(Boolean allowStaticField) throws Exception {
loadConfigurationProviders(new StubConfigurationProvider() {
@Override
public void register(ContainerBuilder builder,
LocatableProperties props) throws ConfigurationException {
// null values simulate undefined (by removing).
// undefined values then should be evaluated to false
if (props.containsKey(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS)) {
props.remove(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS);
}
if (props.containsKey(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS)) {
props.remove(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS);
}
if (allowStaticMethod != null) {
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_METHOD_ACCESS, "" + allowStaticMethod);
}
props.remove(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS);
if (allowStaticField != null) {
props.setProperty(StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, "" + allowStaticField);
}
@@ -23,7 +23,6 @@ import junit.framework.TestCase;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@@ -45,7 +44,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testWithoutClassExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "stringField";
Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
@@ -59,7 +58,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testClassExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "stringField";
Member member = FooBar.class.getDeclaredMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
@@ -77,7 +76,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testObjectClassExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "toString";
Member member = FooBar.class.getMethod(propertyName);
@@ -91,7 +90,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testObjectOverwrittenMethodsExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "hashCode";
Member member = FooBar.class.getMethod(propertyName);
@@ -105,7 +104,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testInterfaceInheritanceExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "barLogic";
Member member = BarInterface.class.getMethod(propertyName);
@@ -123,7 +122,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testMiddleOfInheritanceExclusion1() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "fooLogic";
Member member = FooBar.class.getMethod(propertyName);
@@ -141,7 +140,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testMiddleOfInheritanceExclusion3() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "barLogic";
Member member = BarInterface.class.getMethod(propertyName);
@@ -155,7 +154,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testMiddleOfInheritanceExclusion4() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "barLogic";
Member member = BarInterface.class.getMethod(propertyName);
@@ -173,7 +172,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testPackageExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*"));
@@ -188,10 +187,10 @@ public class SecurityMemberAccessTest extends TestCase {
// then
assertFalse("stringField is accessible!", actual);
}
public void testPackageNameExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<String> excluded = new HashSet<>();
excluded.add(FooBar.class.getPackage().getName());
@@ -209,27 +208,27 @@ public class SecurityMemberAccessTest extends TestCase {
public void testDefaultPackageExclusion() {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*"));
sma.setExcludedPackageNamePatterns(excluded);
// when
boolean actual = sma.isPackageExcluded(null, null);
// then
assertFalse("default package is excluded!", actual);
}
public void testDefaultPackageExclusion2() {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^$"));
sma.setExcludedPackageNamePatterns(excluded);
// when
boolean actual = sma.isPackageExcluded(null, null);
@@ -239,7 +238,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testAccessEnum() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
// when
Member values = MyValues.class.getMethod("values");
@@ -249,23 +248,23 @@ public class SecurityMemberAccessTest extends TestCase {
assertTrue("Access to enums is blocked!", actual);
}
public void testAccessStatic() throws Exception {
public void testAccessStaticMethod() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true, true);
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = StaticTester.class.getMethod("sayHello");
boolean actual = sma.isAccessible(context, Class.class, method, null);
// then
assertTrue("Access to static is blocked!", actual);
assertFalse("Access to static method is not blocked!", actual);
}
public void testAccessStaticField() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true, true);
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = StaticTester.class.getField("MAX_VALUE");
@@ -277,8 +276,8 @@ public class SecurityMemberAccessTest extends TestCase {
public void testBlockedStaticFieldWhenFlagIsFalse() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = StaticTester.class.getField("MAX_VALUE");
@@ -289,8 +288,8 @@ public class SecurityMemberAccessTest extends TestCase {
// public static final test
// given
sma = new SecurityMemberAccess(false, true);
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.class.getField("MIN_VALUE");
@@ -301,8 +300,8 @@ public class SecurityMemberAccessTest extends TestCase {
// package static test
// given
sma = new SecurityMemberAccess(false, true);
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("PACKAGE_STRING");
@@ -313,8 +312,8 @@ public class SecurityMemberAccessTest extends TestCase {
// package final static test
// given
sma = new SecurityMemberAccess(false, true);
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("FINAL_PACKAGE_STRING");
@@ -325,8 +324,8 @@ public class SecurityMemberAccessTest extends TestCase {
// protected static test
// given
sma = new SecurityMemberAccess(false, true);
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("PROTECTED_STRING");
@@ -337,8 +336,8 @@ public class SecurityMemberAccessTest extends TestCase {
// protected final static test
// given
sma = new SecurityMemberAccess(false, true);
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("FINAL_PROTECTED_STRING");
@@ -349,8 +348,8 @@ public class SecurityMemberAccessTest extends TestCase {
// private static test
// given
sma = new SecurityMemberAccess(false, true);
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("PRIVATE_STRING");
@@ -361,8 +360,8 @@ public class SecurityMemberAccessTest extends TestCase {
// private final static test
// given
sma = new SecurityMemberAccess(false, true);
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("FINAL_PRIVATE_STRING");
@@ -374,7 +373,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testBlockedStaticFieldWhenClassIsExcluded() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Arrays.asList(Class.class, StaticTester.class)));
// when
@@ -385,10 +384,10 @@ public class SecurityMemberAccessTest extends TestCase {
assertFalse("Access to static field isn't blocked!", actual);
}
public void testBlockStaticAccess() throws Exception {
public void testBlockStaticMethodAccess() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = StaticTester.class.getMethod("sayHello");
@@ -400,8 +399,8 @@ public class SecurityMemberAccessTest extends TestCase {
public void testBlockStaticAccessIfClassIsExcluded() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(Class.class)));
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = Class.class.getMethod("getClassLoader");
@@ -413,8 +412,8 @@ public class SecurityMemberAccessTest extends TestCase {
public void testAllowStaticAccessIfClassIsNotExcluded() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true, true);
sma.setExcludedClasses(new HashSet<Class<?>>(Collections.singletonList(ClassLoader.class)));
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(ClassLoader.class)));
// when
Member method = Class.class.getMethod("getClassLoader");
@@ -426,7 +425,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testAccessPrimitiveInt() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("java.lang.,ognl,javax"));
String propertyName = "intField";
@@ -441,7 +440,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testAccessPrimitiveDoubleWithNames() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("ognl.,javax."));
@@ -493,7 +492,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testAccessPrimitiveDoubleWithPackageRegExs() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> patterns = new HashSet<>();
patterns.add(Pattern.compile("^java\\.lang\\..*"));
sma.setExcludedPackageNamePatterns(patterns);
@@ -510,7 +509,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testAccessMemberAccessIsAccessible() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Class<?>> excluded = new HashSet<>();
excluded.add(ognl.MemberAccess.class);
sma.setExcludedClasses(excluded);
@@ -528,7 +527,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testAccessMemberAccessIsBlocked() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Class<?>> excluded = new HashSet<>();
excluded.add(SecurityMemberAccess.class);
sma.setExcludedClasses(excluded);
@@ -546,7 +545,7 @@ public class SecurityMemberAccessTest extends TestCase {
public void testPackageNameExclusionAsCommaDelimited() {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("java.lang."));
@@ -46,9 +46,9 @@ import java.util.*;
* @author tm_jee
*/
public class SetPropertiesTest extends XWorkTestCase {
private OgnlUtil ognlUtil;
@Override
public void setUp() throws Exception {
super.setUp();
@@ -57,7 +57,7 @@ public class SetPropertiesTest extends XWorkTestCase {
}
public void testOgnlUtilEmptyStringAsLong() {
Bar bar = new Bar();
Map context = Ognl.createDefaultContext(bar, new SecurityMemberAccess(false, true));
Map context = Ognl.createDefaultContext(bar, new SecurityMemberAccess(true));
context.put(XWorkConverter.REPORT_CONVERSION_ERRORS, Boolean.TRUE);
bar.setId(null);
@@ -110,7 +110,7 @@ public class SetPropertiesTest extends XWorkTestCase {
assertEquals(Cat.class, foo.getCats().get(0).getClass());
assertEquals(Cat.class, foo.getCats().get(1).getClass());
}
public void testValueStackSetValueEmptyStringAsLong() {
Bar bar = new Bar();
ValueStack vs = ActionContext.getContext().getValueStack();
@@ -193,11 +193,11 @@ public class SetPropertiesTest extends XWorkTestCase {
}
public void testAddingToMapsWithObjectsTrue() throws Exception {
doTestAddingToMapsWithObjects(true);
}
public void testAddingToMapsWithObjectsFalse() throws Exception {
doTestAddingToMapsWithObjects(false);
@@ -227,8 +227,8 @@ public class SetPropertiesTest extends XWorkTestCase {
}
public void testAddingAndModifyingCollectionWithObjectsSet() {
doTestAddingAndModifyingCollectionWithObjects(new HashSet());
}
@@ -0,0 +1,651 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.test;
import com.opensymphony.xwork2.ognl.SecurityMemberAccess;
import com.opensymphony.xwork2.util.TextParseUtil;
import junit.framework.TestCase;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
public class SecurityMemberAccessTest extends TestCase {
private Map context;
private FooBar target;
@Override
public void setUp() throws Exception {
context = new HashMap();
target = new FooBar();
}
public void testWithoutClassExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "stringField";
Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue(accessible);
}
public void testClassExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "stringField";
Member member = FooBar.class.getDeclaredMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
Set<Class<?>> excluded = new HashSet<>();
excluded.add(FooBar.class);
sma.setExcludedClasses(excluded);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse(accessible);
}
public void testObjectClassExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "toString";
Member member = FooBar.class.getMethod(propertyName);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse("toString() from Object is accessible!!!", accessible);
}
public void testObjectOverwrittenMethodsExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "hashCode";
Member member = FooBar.class.getMethod(propertyName);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue("hashCode() from FooBar isn't accessible!!!", accessible);
}
public void testInterfaceInheritanceExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "barLogic";
Member member = BarInterface.class.getMethod(propertyName);
Set<Class<?>> excluded = new HashSet<>();
excluded.add(BarInterface.class);
sma.setExcludedClasses(excluded);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse("barLogic() from BarInterface is accessible!!!", accessible);
}
public void testMiddleOfInheritanceExclusion1() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "fooLogic";
Member member = FooBar.class.getMethod(propertyName);
Set<Class<?>> excluded = new HashSet<>();
excluded.add(BarInterface.class);
sma.setExcludedClasses(excluded);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue("fooLogic() from FooInterface isn't accessible!!!", accessible);
}
public void testMiddleOfInheritanceExclusion3() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "barLogic";
Member member = BarInterface.class.getMethod(propertyName);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue("barLogic() from BarInterface isn't accessible!!!", accessible);
}
public void testMiddleOfInheritanceExclusion4() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
String propertyName = "barLogic";
Member member = BarInterface.class.getMethod(propertyName);
Set<Class<?>> excluded = new HashSet<>();
excluded.add(FooBarInterface.class);
sma.setExcludedClasses(excluded);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse("barLogic() from BarInterface is accessible!!!", accessible);
}
public void testPackageExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*"));
sma.setExcludedPackageNamePatterns(excluded);
String propertyName = "stringField";
Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
// when
boolean actual = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse("stringField is accessible!", actual);
}
public void testPackageNameExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<String> excluded = new HashSet<>();
excluded.add(FooBar.class.getPackage().getName());
sma.setExcludedPackageNames(excluded);
String propertyName = "stringField";
Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
// when
boolean actual = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse("stringField is accessible!", actual);
}
public void testDefaultPackageExclusion() {
// given
TestSecurityMemberAccess sma = new TestSecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^" + FooBar.class.getPackage().getName().replaceAll("\\.", "\\\\.") + ".*"));
sma.setExcludedPackageNamePatterns(excluded);
// when
boolean actual = sma.isPackageExcluded(null, null);
// then
assertFalse("default package is excluded!", actual);
}
public void testDefaultPackageExclusion2() {
// given
TestSecurityMemberAccess sma = new TestSecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<>();
excluded.add(Pattern.compile("^$"));
sma.setExcludedPackageNamePatterns(excluded);
// when
boolean actual = sma.isPackageExcluded(null, null);
// then
assertTrue("default package isn't excluded!", actual);
}
public void testAccessEnum() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
// when
Member values = MyValues.class.getMethod("values");
boolean actual = sma.isAccessible(context, MyValues.class, values, null);
// then
assertTrue("Access to enums is blocked!", actual);
}
public void testAccessStaticMethod() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = StaticTester.class.getMethod("sayHello");
boolean actual = sma.isAccessible(context, Class.class, method, null);
// then
assertFalse("Access to static method is not blocked!", actual);
}
public void testAccessStaticField() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = StaticTester.class.getField("MAX_VALUE");
boolean actual = sma.isAccessible(context, null, method, null);
// then
assertTrue("Access to static field is blocked!", actual);
}
public void testBlockedStaticFieldWhenFlagIsFalse() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = StaticTester.class.getField("MAX_VALUE");
boolean actual = sma.isAccessible(context, null, method, null);
// then
assertTrue("Access to public static field is blocked?", actual);
// public static final test
// given
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.class.getField("MIN_VALUE");
actual = sma.isAccessible(context, null, method, null);
// then
assertTrue("Access to public final static field is blocked?", actual);
// package static test
// given
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("PACKAGE_STRING");
actual = sma.isAccessible(context, null, method, null);
// then
assertFalse("Access to package static field is allowed?", actual);
// package final static test
// given
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("FINAL_PACKAGE_STRING");
actual = sma.isAccessible(context, null, method, null);
// then
assertFalse("Access to package final static field is allowed?", actual);
// protected static test
// given
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("PROTECTED_STRING");
actual = sma.isAccessible(context, null, method, null);
// then
assertFalse("Access to protected static field is allowed?", actual);
// protected final static test
// given
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("FINAL_PROTECTED_STRING");
actual = sma.isAccessible(context, null, method, null);
// then
assertFalse("Access to protected final static field is allowed?", actual);
// private static test
// given
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("PRIVATE_STRING");
actual = sma.isAccessible(context, null, method, null);
// then
assertFalse("Access to private static field is allowed?", actual);
// private final static test
// given
sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
method = StaticTester.getFieldByName("FINAL_PRIVATE_STRING");
actual = sma.isAccessible(context, null, method, null);
// then
assertFalse("Access to private final static field is allowed?", actual);
}
public void testBlockedStaticFieldWhenClassIsExcluded() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Arrays.asList(Class.class, StaticTester.class)));
// when
Member method = StaticTester.class.getField("MAX_VALUE");
boolean actual = sma.isAccessible(context, null, method, null);
// then
assertFalse("Access to static field isn't blocked!", actual);
}
public void testBlockStaticAccess() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = StaticTester.class.getMethod("sayHello");
boolean actual = sma.isAccessible(context, Class.class, method, null);
// then
assertFalse("Access to static isn't blocked!", actual);
}
public void testBlockStaticAccessIfClassIsExcluded() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(Class.class)));
// when
Member method = Class.class.getMethod("getClassLoader");
boolean actual = sma.isAccessible(context, Class.class, method, null);
// then
assertFalse("Access to static method of excluded class isn't blocked!", actual);
}
public void testAllowStaticAccessIfClassIsNotExcluded() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedClasses(new HashSet<>(Collections.singletonList(ClassLoader.class)));
// when
Member method = Class.class.getMethod("getClassLoader");
boolean actual = sma.isAccessible(context, Class.class, method, null);
// then
assertTrue("Invalid test! Access to static method of excluded class is blocked!", actual);
}
public void testAccessPrimitiveInt() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("java.lang.,ognl,javax"));
String propertyName = "intField";
Member member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue(accessible);
}
public void testAccessPrimitiveDoubleWithNames() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("ognl.,javax."));
Set<Class<?>> excluded = new HashSet<>();
excluded.add(Object.class);
excluded.add(Runtime.class);
excluded.add(System.class);
excluded.add(Class.class);
excluded.add(ClassLoader.class);
sma.setExcludedClasses(excluded);
String propertyName = "doubleValue";
Member member = Double.class.getMethod(propertyName);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue(accessible);
// given
propertyName = "exit";
member = System.class.getMethod(propertyName, int.class);
// when
accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse(accessible);
// given
propertyName = "intField";
member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
// when
accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue(accessible);
// given
propertyName = "doubleField";
member = FooBar.class.getMethod("get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1));
// when
accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue(accessible);
}
public void testAccessPrimitiveDoubleWithPackageRegExs() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> patterns = new HashSet<>();
patterns.add(Pattern.compile("^java\\.lang\\..*"));
sma.setExcludedPackageNamePatterns(patterns);
String propertyName = "doubleValue";
Member member = Double.class.getMethod(propertyName);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue(accessible);
}
public void testAccessMemberAccessIsAccessible() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Class<?>> excluded = new HashSet<>();
excluded.add(ognl.MemberAccess.class);
sma.setExcludedClasses(excluded);
String propertyName = "excludedClasses";
String setter = "setExcludedClasses";
Member member = SecurityMemberAccess.class.getMethod(setter, Set.class);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertTrue(accessible);
}
public void testAccessMemberAccessIsBlocked() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Class<?>> excluded = new HashSet<>();
excluded.add(SecurityMemberAccess.class);
sma.setExcludedClasses(excluded);
String propertyName = "excludedClasses";
String setter = "setExcludedClasses";
Member member = SecurityMemberAccess.class.getMethod(setter, Set.class);
// when
boolean accessible = sma.isAccessible(context, target, member, propertyName);
// then
assertFalse(accessible);
}
public void testPackageNameExclusionAsCommaDelimited() {
// given
TestSecurityMemberAccess sma = new TestSecurityMemberAccess(true);
sma.setExcludedPackageNames(TextParseUtil.commaDelimitedStringToSet("java.lang."));
// when
boolean actual = sma.isPackageExcluded(String.class.getPackage(), null);
actual &= sma.isPackageExcluded(null, String.class.getPackage());
// then
assertTrue("package java.lang. is accessible!", actual);
}
}
class FooBar implements FooBarInterface {
private String stringField;
private int intField;
private Double doubleField;
public String getStringField() {
return stringField;
}
public void setStringField(String stringField) {
this.stringField = stringField;
}
public String fooLogic() {
return "fooLogic";
}
public String barLogic() {
return "barLogic";
}
@Override
public int hashCode() {
return 1;
}
public int getIntField() {
return intField;
}
public void setIntField(int intField) {
this.intField = intField;
}
public Double getDoubleField() {
return doubleField;
}
public void setDoubleField(Double doubleField) {
this.doubleField = doubleField;
}
}
interface FooInterface {
String fooLogic();
}
interface BarInterface {
String barLogic();
}
interface FooBarInterface extends FooInterface, BarInterface {
}
enum MyValues {
ONE, TWO, THREE
}
class StaticTester {
public static int MAX_VALUE = 0;
public static final int MIN_VALUE = 0;
static String PACKAGE_STRING = "package_string";
static final String FINAL_PACKAGE_STRING = "final_package_string";
static String PROTECTED_STRING = "protected_string";
static final String FINAL_PROTECTED_STRING = "final_protected_string";
static String PRIVATE_STRING = "private_string";
static final String FINAL_PRIVATE_STRING = "final_private_string";
public static String sayHello() {
return "Hello";
}
protected static Field getFieldByName(String fieldName) throws NoSuchFieldException {
if (fieldName != null && fieldName.length() > 0) {
return StaticTester.class.getDeclaredField(fieldName);
} else {
throw new NoSuchFieldException("field: " + fieldName + " does not exist");
}
}
}
@@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.test;
import com.opensymphony.xwork2.ognl.SecurityMemberAccess;
class TestSecurityMemberAccess extends SecurityMemberAccess {
TestSecurityMemberAccess(boolean allowStaticFieldAccess) {
super(allowStaticFieldAccess);
}
@Override
public boolean isPackageExcluded(Package targetPackage, Package memberPackage) {
return super.isPackageExcluded(targetPackage, memberPackage);
}
}
@@ -18,25 +18,26 @@
*/
package org.apache.struts2.interceptor;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.Cookie;
import com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker;
import com.opensymphony.xwork2.security.DefaultExcludedPatternsChecker;
import com.opensymphony.xwork2.mock.MockActionInvocation;
import org.springframework.mock.web.MockHttpServletRequest;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsInternalTestCase;
import static org.easymock.EasyMock.*;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.mock.MockActionInvocation;
import com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker;
import com.opensymphony.xwork2.security.DefaultExcludedPatternsChecker;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsInternalTestCase;
import org.springframework.mock.web.MockHttpServletRequest;
import javax.servlet.http.Cookie;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
public class CookieInterceptorTest extends StrutsInternalTestCase {
@@ -44,9 +45,9 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
public void testIntercepDefault() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setCookies(
new Cookie("cookie1", "cookie1value"),
new Cookie("cookie2", "cookie2value"),
new Cookie("cookie3", "cookie3value")
new Cookie("cookie1", "cookie1value"),
new Cookie("cookie2", "cookie2value"),
new Cookie("cookie3", "cookie3value")
);
ServletActionContext.setRequest(request);
@@ -55,7 +56,7 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
ActionContext.getContext().getValueStack().push(action);
ActionInvocation invocation = (ActionInvocation) createMock(ActionInvocation.class);
expect(invocation.getAction()).andReturn(action);
expect(invocation.invoke()).andReturn(Action.SUCCESS);
@@ -75,16 +76,16 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
assertNull(ActionContext.getContext().getValueStack().findValue("cookie1"));
assertNull(ActionContext.getContext().getValueStack().findValue("cookie2"));
assertNull(ActionContext.getContext().getValueStack().findValue("cookie3"));
verify(invocation);
}
public void testInterceptAll1() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setCookies(
new Cookie("cookie1", "cookie1value"),
new Cookie("cookie2", "cookie2value"),
new Cookie("cookie3", "cookie3value")
new Cookie("cookie1", "cookie1value"),
new Cookie("cookie2", "cookie2value"),
new Cookie("cookie3", "cookie3value")
);
ServletActionContext.setRequest(request);
@@ -93,7 +94,7 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
ActionContext.getContext().getValueStack().push(action);
ActionInvocation invocation = (ActionInvocation) createMock(ActionInvocation.class);
expect(invocation.getAction()).andReturn(action);
expect(invocation.invoke()).andReturn(Action.SUCCESS);
@@ -117,7 +118,7 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie1"), "cookie1value");
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie2"), "cookie2value");
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie3"), "cookie3value");
verify(invocation);
}
@@ -125,9 +126,9 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
public void testInterceptAll2() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setCookies(
new Cookie("cookie1", "cookie1value"),
new Cookie("cookie2", "cookie2value"),
new Cookie("cookie3", "cookie3value")
new Cookie("cookie1", "cookie1value"),
new Cookie("cookie2", "cookie2value"),
new Cookie("cookie3", "cookie3value")
);
ServletActionContext.setRequest(request);
@@ -159,16 +160,16 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie1"), "cookie1value");
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie2"), "cookie2value");
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie3"), "cookie3value");
verify(invocation);
}
public void testInterceptSelectedCookiesNameOnly1() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setCookies(
new Cookie("cookie1", "cookie1value"),
new Cookie("cookie2", "cookie2value"),
new Cookie("cookie3", "cookie3value")
new Cookie("cookie1", "cookie1value"),
new Cookie("cookie2", "cookie2value"),
new Cookie("cookie3", "cookie3value")
);
ServletActionContext.setRequest(request);
@@ -200,16 +201,16 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie1"), "cookie1value");
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie2"), null);
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie3"), "cookie3value");
verify(invocation);
}
public void testInterceptSelectedCookiesNameOnly2() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setCookies(
new Cookie("cookie1", "cookie1value"),
new Cookie("cookie2", "cookie2value"),
new Cookie("cookie3", "cookie3value")
new Cookie("cookie1", "cookie1value"),
new Cookie("cookie2", "cookie2value"),
new Cookie("cookie3", "cookie3value")
);
ServletActionContext.setRequest(request);
@@ -218,7 +219,7 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
ActionContext.getContext().getValueStack().push(action);
ActionInvocation invocation = (ActionInvocation) createMock(ActionInvocation.class);
expect(invocation.getAction()).andReturn(action);
expect(invocation.invoke()).andReturn(Action.SUCCESS);
@@ -242,16 +243,16 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie1"), "cookie1value");
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie2"), null);
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie3"), "cookie3value");
verify(invocation);
}
public void testInterceptSelectedCookiesNameOnly3() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setCookies(
new Cookie("cookie1", "cookie1value"),
new Cookie("cookie2", "cookie2value"),
new Cookie("cookie3", "cookie3value")
new Cookie("cookie1", "cookie1value"),
new Cookie("cookie2", "cookie2value"),
new Cookie("cookie3", "cookie3value")
);
ServletActionContext.setRequest(request);
@@ -283,7 +284,7 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie1"), "cookie1value");
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie2"), null);
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie3"), "cookie3value");
verify(invocation);
}
@@ -291,9 +292,9 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
public void testInterceptSelectedCookiesNameAndValue() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setCookies(
new Cookie("cookie1", "cookie1value"),
new Cookie("cookie2", "cookie2value"),
new Cookie("cookie3", "cookie3value")
new Cookie("cookie1", "cookie1value"),
new Cookie("cookie2", "cookie2value"),
new Cookie("cookie3", "cookie3value")
);
ServletActionContext.setRequest(request);
@@ -325,7 +326,7 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie1"), "cookie1value");
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie2"), null);
assertEquals(ActionContext.getContext().getValueStack().findValue("cookie3"), null);
verify(invocation);
}
@@ -338,20 +339,44 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
String pollution5 = "model[\"class\"]['classLoader']['jarPath']";
String pollution6 = "class[\"classLoader\"]['jarPath']";
try {
new Cookie(pollution1, "pollution1");
fail("It shouldn't be possible to create cookie: " + pollution1);
} catch (IllegalArgumentException e) {
assertEquals(e.getMessage(), "Cookie name \"" + pollution1 + "\" is a reserved token");
}
try {
new Cookie(pollution4, "pollution4");
fail("It shouldn't be possible to create cookie: " + pollution4);
} catch (IllegalArgumentException e) {
assertEquals(e.getMessage(), "Cookie name \"" + pollution4 + "\" is a reserved token");
}
try {
new Cookie(pollution5, "pollution5");
fail("It shouldn't be possible to create cookie: " + pollution5);
} catch (IllegalArgumentException e) {
assertEquals(e.getMessage(), "Cookie name \"" + pollution5 + "\" is a reserved token");
}
try {
new Cookie(pollution6, "pollution6");
fail("It shouldn't be possible to create cookie: " + pollution6);
} catch (IllegalArgumentException e) {
assertEquals(e.getMessage(), "Cookie name \"" + pollution6 + "\" is a reserved token");
}
request.setCookies(
new Cookie(pollution1, "pollution1"),
new Cookie("pollution1", pollution1),
new Cookie(pollution2, "pollution2"),
new Cookie("pollution2", pollution2),
new Cookie(pollution3, "pollution3"),
new Cookie("pollution3", pollution3),
new Cookie(pollution4, "pollution4"),
new Cookie("pollution4", pollution4),
new Cookie(pollution5, "pollution5"),
new Cookie("pollution5", pollution5),
new Cookie(pollution6, "pollution6"),
new Cookie("pollution6", pollution6)
);
new Cookie("pollution1", pollution1),
new Cookie(pollution2, "pollution2"),
new Cookie("pollution2", pollution2),
new Cookie(pollution3, "pollution3"),
new Cookie("pollution3", pollution3),
new Cookie("pollution4", pollution4),
new Cookie("pollution5", pollution5),
new Cookie("pollution6", pollution6)
);
ServletActionContext.setRequest(request);
final Map<String, Boolean> excludedName = new HashMap<String, Boolean>();
@@ -375,12 +400,12 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
interceptor.intercept(invocation);
assertFalse(excludedName.get(pollution1));
//assertFalse(excludedName.get(pollution1));
assertFalse(excludedName.get(pollution2));
assertFalse(excludedName.get(pollution3));
assertFalse(excludedName.get(pollution4));
assertFalse(excludedName.get(pollution5));
assertFalse(excludedName.get(pollution6));
//assertFalse(excludedName.get(pollution4));
//assertFalse(excludedName.get(pollution5));
// assertFalse(excludedName.get(pollution6));
}
public void testCookiesWithStrutsInternalsAccess() throws Exception {
@@ -393,13 +418,13 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
String reqCookieValue = "request.userId=1";
request.setCookies(
new Cookie(sessionCookieName, "1"),
new Cookie("1", sessionCookieValue),
new Cookie(appCookieName, "1"),
new Cookie("1", appCookieValue),
new Cookie(reqCookieName, "1"),
new Cookie("1", reqCookieValue)
);
new Cookie(sessionCookieName, "1"),
new Cookie("1", sessionCookieValue),
new Cookie(appCookieName, "1"),
new Cookie("1", appCookieValue),
new Cookie(reqCookieName, "1"),
new Cookie("1", reqCookieValue)
);
ServletActionContext.setRequest(request);
final Map<String, Boolean> excludedName = new HashMap<String, Boolean>();
@@ -436,13 +461,13 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
String reqCookieValue = "request.userId=1";
request.setCookies(
new Cookie(sessionCookieName, "1"),
new Cookie("1", sessionCookieValue),
new Cookie(appCookieName, "1"),
new Cookie("1", appCookieValue),
new Cookie(reqCookieName, "1"),
new Cookie("1", reqCookieValue)
);
new Cookie(sessionCookieName, "1"),
new Cookie("1", sessionCookieValue),
new Cookie(appCookieName, "1"),
new Cookie("1", appCookieValue),
new Cookie(reqCookieName, "1"),
new Cookie("1", reqCookieValue)
);
ServletActionContext.setRequest(request);
final Map<String, Boolean> excludedName = new HashMap<>();
@@ -486,14 +511,29 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
return this.cookies;
}
public String getCookie1() { return cookie1; }
public void setCookie1(String cookie1) { this.cookie1 = cookie1; }
public String getCookie1() {
return cookie1;
}
public String getCookie2() { return cookie2; }
public void setCookie2(String cookie2) { this.cookie2 = cookie2; }
public void setCookie1(String cookie1) {
this.cookie1 = cookie1;
}
public String getCookie3() { return cookie3; }
public void setCookie3(String cookie3) { this.cookie3 = cookie3; }
public String getCookie2() {
return cookie2;
}
public void setCookie2(String cookie2) {
this.cookie2 = cookie2;
}
public String getCookie3() {
return cookie3;
}
public void setCookie3(String cookie3) {
this.cookie3 = cookie3;
}
}
public static class MockActionWithActionCookieAware extends ActionSupport implements org.apache.struts2.action.CookiesAware {
@@ -511,14 +551,29 @@ public class CookieInterceptorTest extends StrutsInternalTestCase {
return this.cookies;
}
public String getCookie1() { return cookie1; }
public void setCookie1(String cookie1) { this.cookie1 = cookie1; }
public String getCookie1() {
return cookie1;
}
public String getCookie2() { return cookie2; }
public void setCookie2(String cookie2) { this.cookie2 = cookie2; }
public void setCookie1(String cookie1) {
this.cookie1 = cookie1;
}
public String getCookie3() { return cookie3; }
public void setCookie3(String cookie3) { this.cookie3 = cookie3; }
public String getCookie2() {
return cookie2;
}
public void setCookie2(String cookie2) {
this.cookie2 = cookie2;
}
public String getCookie3() {
return cookie3;
}
public void setCookie3(String cookie3) {
this.cookie3 = cookie3;
}
}
}
@@ -58,7 +58,7 @@ public class PlainResultTest extends StrutsInternalTestCase {
result.execute(invocation);
assertEquals("{ 'value': 'test' }", response.getContentAsString());
assertEquals("application/json", response.getContentType());
assertEquals("application/json;charset=UTF-8", response.getContentType());
}
public void testWriteContentTypeCsvWithCookie() throws Exception {
@@ -72,7 +72,7 @@ public class PlainResultTest extends StrutsInternalTestCase {
result.execute(invocation);
assertEquals("name;value\nline;1\nline;2", response.getContentAsString());
assertEquals("text/csv", response.getContentType());
assertEquals("text/csv;charset=UTF-8", response.getContentType());
}
public void testHeaders() throws Exception {
@@ -146,4 +146,4 @@ public class PlainResultTest extends StrutsInternalTestCase {
ActionContext.getContext().withServletResponse(response).withActionInvocation(invocation);
}
}
}
@@ -41,7 +41,7 @@ public class SecurityMemberAccessInServletsTest extends StrutsInternalTestCase {
public void testJavaxServletPackageAccess() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<Pattern>();
excluded.add(Pattern.compile("^(?!javax\\.servlet\\..+)(javax\\..+)"));
@@ -59,7 +59,7 @@ public class SecurityMemberAccessInServletsTest extends StrutsInternalTestCase {
public void testJavaxServletPackageExclusion() throws Exception {
// given
SecurityMemberAccess sma = new SecurityMemberAccess(false, true);
SecurityMemberAccess sma = new SecurityMemberAccess(true);
Set<Pattern> excluded = new HashSet<Pattern>();
excluded.add(Pattern.compile("^javax\\..+"));
@@ -23,14 +23,21 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.SessionCookieConfig;
import javax.servlet.SessionTrackingMode;
import javax.servlet.descriptor.JspConfigDescriptor;
/**
@@ -42,12 +49,12 @@ public class StrutsMockServletContext implements ServletContext {
String realPath;
String servletInfo;
String contextPath;
Map initParams = new HashMap();
Map attributes = new HashMap();
Map<String, String> initParams = new HashMap<>();
Map<String, Object> attributes = new HashMap<>();
InputStream resourceAsStream;
public void setInitParameter(String name, String value) {
initParams.put(name, value);
public boolean setInitParameter(String name, String value) {
return initParams.put(name, value) != null;
}
public void setRealPath(String value) {
@@ -74,7 +81,7 @@ public class StrutsMockServletContext implements ServletContext {
return null;
}
public Set getResourcePaths(String s) {
public Set<String> getResourcePaths(String s) {
return null;
}
@@ -105,11 +112,11 @@ public class StrutsMockServletContext implements ServletContext {
return null;
}
public Enumeration getServlets() {
public Enumeration<Servlet> getServlets() {
return null;
}
public Enumeration getServletNames() {
public Enumeration<String> getServletNames() {
return null;
}
@@ -130,7 +137,7 @@ public class StrutsMockServletContext implements ServletContext {
return (String) initParams.get(s);
}
public Enumeration getInitParameterNames() {
public Enumeration<String> getInitParameterNames() {
return Collections.enumeration(initParams.keySet());
}
@@ -138,7 +145,7 @@ public class StrutsMockServletContext implements ServletContext {
return attributes.get(s);
}
public Enumeration getAttributeNames() {
public Enumeration<String> getAttributeNames() {
return Collections.enumeration(attributes.keySet());
}
@@ -157,12 +164,142 @@ public class StrutsMockServletContext implements ServletContext {
public void setServletInfo(String servletInfo) {
this.servletInfo = servletInfo;
}
public String getContextPath() {
return contextPath;
}
}
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
}
@Override
public int getEffectiveMajorVersion() {
return 0;
}
@Override
public int getEffectiveMinorVersion() {
return 0;
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, String className) {
return null;
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
return null;
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass) {
return null;
}
@Override
public <T extends Servlet> T createServlet(Class<T> clazz) throws ServletException {
return null;
}
@Override
public ServletRegistration getServletRegistration(String servletName) {
return null;
}
@Override
public Map<String, ? extends ServletRegistration> getServletRegistrations() {
return null;
}
@Override
public FilterRegistration.Dynamic addFilter(String filterName, String className) {
return null;
}
@Override
public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) {
return null;
}
@Override
public FilterRegistration.Dynamic addFilter(String filterName, Class<? extends Filter> filterClass) {
return null;
}
@Override
public <T extends Filter> T createFilter(Class<T> clazz) throws ServletException {
return null;
}
@Override
public FilterRegistration getFilterRegistration(String filterName) {
return null;
}
@Override
public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
return null;
}
@Override
public SessionCookieConfig getSessionCookieConfig() {
return null;
}
@Override
public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes) {
}
@Override
public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
return null;
}
@Override
public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
return null;
}
@Override
public void addListener(String className) {
}
@Override
public <T extends EventListener> void addListener(T t) {
}
@Override
public void addListener(Class<? extends EventListener> listenerClass) {
}
@Override
public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException {
return null;
}
@Override
public JspConfigDescriptor getJspConfigDescriptor() {
return null;
}
@Override
public ClassLoader getClassLoader() {
return null;
}
@Override
public void declareRoles(String... roleNames) {
}
@Override
public String getVirtualServerName() {
return null;
}
}
@@ -26,4 +26,5 @@
<constant name="struts.excludedClasses" value="java.lang.Object,java.lang.Runtime,ognl.OgnlContext,ognl.MemberAccess,ognl.ClassResolver,ognl.TypeConverter,com.opensymphony.xwork2.ognl.SecurityMemberAccess" />
<constant name="struts.ognl.allowStaticFieldAccess" value="false"/>
</struts>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-async-plugin</artifactId>
+13 -7
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -44,11 +44,6 @@
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
@@ -60,6 +55,17 @@
<artifactId>javax.el</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<!-- this library is excluded in the parent pom as it clashes with Easymock dependencies -->
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>3.2</version>
</dependency>
<!--
The Java EE API modules listed below are all marked @Deprecated(forRemoval=true), because they are scheduled
@@ -94,4 +100,4 @@
</dependencies>
</project>
</project>
@@ -20,17 +20,20 @@
*/
package org.apache.struts.beanvalidation.constraints.impl;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts.beanvalidation.constraints.FieldMatch;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
public class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object> {
private static final Logger LOG = LogManager.getLogger(FieldMatchValidator.class);
private String firstFieldName;
private String secondFieldName;
@@ -41,13 +44,23 @@ public class FieldMatchValidator implements ConstraintValidator<FieldMatch, Obje
public boolean isValid(final Object value, final ConstraintValidatorContext context) {
try {
final Object firstObj = PropertyUtils.getProperty(value, this.firstFieldName);
final Object secondObj = PropertyUtils.getProperty(value, this.secondFieldName);
final Object firstObj = readPropertyValue(value, this.firstFieldName);
final Object secondObj = readPropertyValue(value, this.secondFieldName);
return firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
} catch (final Exception ex) {
LOG.info("Error while getting values from object", ex);
return false;
}
}
private Object readPropertyValue(Object bean, String propertyName) throws Exception {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {
if (propertyName.equals(descriptor.getName())) {
return descriptor.getReadMethod().invoke(bean);
}
}
return null;
}
}
@@ -0,0 +1,84 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts.beanvalidation.constraints.impl;
import org.apache.struts.beanvalidation.constraints.FieldMatch;
import org.junit.Test;
import org.mockito.Mockito;
import javax.validation.ConstraintValidatorContext;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class FieldMatchValidatorTest {
@Test
public void matchingFields() {
// given
FieldMatchValidator validator = new FieldMatchValidator();
validator.initialize(FieldMatchTestBean.class.getAnnotation(FieldMatch.class));
ConstraintValidatorContext context = Mockito.mock(ConstraintValidatorContext.class);
// when
FieldMatchTestBean bean = new FieldMatchTestBean("12345678", "12345678");
boolean valid = validator.isValid(bean, context);
// then
assertTrue(valid);
}
@Test
public void notMatchingFields() {
// given
FieldMatchValidator validator = new FieldMatchValidator();
validator.initialize(FieldMatchTestBean.class.getAnnotation(FieldMatch.class));
ConstraintValidatorContext context = Mockito.mock(ConstraintValidatorContext.class);
// when
FieldMatchTestBean bean = new FieldMatchTestBean("12345678", "87654321");
boolean valid = validator.isValid(bean, context);
// then
assertFalse(valid);
}
@FieldMatch(first = "password", second = "repeatPassword")
public static class FieldMatchTestBean {
String password;
String repeatPassword;
public FieldMatchTestBean(String password, String repeatPassword) {
this.password = password;
this.repeatPassword = repeatPassword;
}
public String getPassword() {
return password;
}
public String getRepeatPassword() {
return repeatPassword;
}
}
}
+1 -1
View File
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-cdi-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-config-browser-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-convention-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-dwr-plugin</artifactId>
+1 -10
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-embeddedjsp-plugin</artifactId>
@@ -89,15 +89,6 @@
<artifactId>tomcat-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
This is only necessary in tests-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-gxp-plugin</artifactId>
+1 -7
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-jasperreports-plugin</artifactId>
@@ -63,12 +63,6 @@
<artifactId>jsp-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
+1 -1
View File
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-javatemplates-plugin</artifactId>
+4 -13
View File
@@ -24,8 +24,8 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
</parent>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-jfreechart-plugin</artifactId>
<packaging>jar</packaging>
@@ -71,18 +71,9 @@
<artifactId>easymock</artifactId>
<scope>test</scope>
</dependency>
<!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
This is only necessary in tests-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
+4 -12
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-json-plugin</artifactId>
@@ -105,18 +105,10 @@
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
This is only necessary in tests-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
+3 -11
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-junit-plugin</artifactId>
@@ -85,17 +85,9 @@
<artifactId>struts2-portlet-mocks-plugin</artifactId>
<optional>true</optional>
</dependency>
<!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
This is only necessary in tests-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
+1 -10
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-osgi-plugin</artifactId>
@@ -106,15 +106,6 @@
<scope>test</scope>
</dependency>
<!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
This is only necessary in tests-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-oval-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-pell-multipart-plugin</artifactId>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-plexus-plugin</artifactId>
+2 -2
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-plugins</artifactId>
@@ -76,7 +76,7 @@
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
+3 -10
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-portlet-mocks-plugin</artifactId>
@@ -47,17 +47,10 @@
<artifactId>portlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
This is only necessary in tests-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<spring.platformVersion>4.3.30.RELEASE</spring.platformVersion>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-portlet-tiles-plugin</artifactId>
+6 -16
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-portlet-plugin</artifactId>
@@ -129,27 +129,17 @@
<artifactId>spring-test</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc-portlet</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<scope>test</scope>
</dependency>
<!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
This is only necessary in tests-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.platformVersion>4.3.30.RELEASE</spring.platformVersion>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
@@ -20,14 +20,22 @@ package org.apache.struts2.portlet.servlet;
import javax.portlet.PortletContext;
import javax.portlet.PortletRequestDispatcher;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.SessionCookieConfig;
import javax.servlet.SessionTrackingMode;
import javax.servlet.descriptor.JspConfigDescriptor;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.Map;
import java.util.Set;
/**
@@ -86,6 +94,11 @@ public class PortletServletContext implements ServletContext {
return portletContext.getInitParameterNames();
}
@Override
public boolean setInitParameter(String name, String value) {
return false;
}
/* (non-Javadoc)
* @see javax.servlet.ServletContext#getMajorVersion()
*/
@@ -107,6 +120,16 @@ public class PortletServletContext implements ServletContext {
return portletContext.getMinorVersion();
}
@Override
public int getEffectiveMajorVersion() {
return 0;
}
@Override
public int getEffectiveMinorVersion() {
return 0;
}
/**
* Returns a {@link PortletServletRequestDispatcher} wrapping the {@link PortletRequestDispatcher}
* as a {@link RequestDispatcher} instance.
@@ -179,6 +202,126 @@ public class PortletServletContext implements ServletContext {
return portletContext.getPortletContextName();
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, String className) {
return null;
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
return null;
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass) {
return null;
}
@Override
public <T extends Servlet> T createServlet(Class<T> clazz) throws ServletException {
return null;
}
@Override
public ServletRegistration getServletRegistration(String servletName) {
return null;
}
@Override
public Map<String, ? extends ServletRegistration> getServletRegistrations() {
return null;
}
@Override
public FilterRegistration.Dynamic addFilter(String filterName, String className) {
return null;
}
@Override
public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) {
return null;
}
@Override
public FilterRegistration.Dynamic addFilter(String filterName, Class<? extends Filter> filterClass) {
return null;
}
@Override
public <T extends Filter> T createFilter(Class<T> clazz) throws ServletException {
return null;
}
@Override
public FilterRegistration getFilterRegistration(String filterName) {
return null;
}
@Override
public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
return null;
}
@Override
public SessionCookieConfig getSessionCookieConfig() {
return null;
}
@Override
public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes) {
}
@Override
public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
return null;
}
@Override
public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
return null;
}
@Override
public void addListener(String className) {
}
@Override
public <T extends EventListener> void addListener(T t) {
}
@Override
public void addListener(Class<? extends EventListener> listenerClass) {
}
@Override
public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException {
return null;
}
@Override
public JspConfigDescriptor getJspConfigDescriptor() {
return null;
}
@Override
public ClassLoader getClassLoader() {
return null;
}
@Override
public void declareRoles(String... roleNames) {
}
@Override
public String getVirtualServerName() {
return null;
}
/**
* @throws IllegalStateException Not supported in a portlet.
* @see javax.servlet.ServletContext#getServletNames()
@@ -21,6 +21,7 @@ package org.apache.struts2.portlet.servlet;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
/**
@@ -31,11 +32,11 @@ import javax.servlet.ServletInputStream;
public class PortletServletInputStream extends ServletInputStream {
private InputStream portletInputStream;
public PortletServletInputStream(InputStream portletInputStream) {
this.portletInputStream = portletInputStream;
}
/* (non-Javadoc)
* @see java.io.InputStream#read()
*/
@@ -107,7 +108,7 @@ public class PortletServletInputStream extends ServletInputStream {
public long skip(long n) throws IOException {
return portletInputStream.skip(n);
}
/**
* Get the wrapped {@link InputStream} instance.
* @return The wrapped {@link InputStream} instance.
@@ -116,4 +117,18 @@ public class PortletServletInputStream extends ServletInputStream {
return portletInputStream;
}
@Override
public boolean isFinished() {
return true;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readListener) {
// no-op
}
}
@@ -22,6 +22,7 @@ import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
/**
* Wrapper object exposing a {@link OutputStream} from a portlet as a {@link ServletOutputStream} instance.
@@ -31,7 +32,7 @@ import javax.servlet.ServletOutputStream;
public class PortletServletOutputStream extends ServletOutputStream {
private OutputStream portletOutputStream;
public PortletServletOutputStream(OutputStream portletOutputStream) {
this.portletOutputStream = portletOutputStream;
}
@@ -75,7 +76,7 @@ public class PortletServletOutputStream extends ServletOutputStream {
public void write(byte[] b, int off, int len) throws IOException {
portletOutputStream.write(b, off, len);
}
/**
* Get the wrapped {@link OutputStream} instance.
* @return The wrapped {@link OutputStream} instance.
@@ -83,4 +84,14 @@ public class PortletServletOutputStream extends ServletOutputStream {
public OutputStream getOutputStream() {
return portletOutputStream;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setWriteListener(WriteListener writeListener) {
// no-op
}
}
@@ -23,6 +23,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Locale;
@@ -34,12 +35,20 @@ import javax.portlet.PortletContext;
import javax.portlet.PortletRequest;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletSession;
import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpUpgradeHandler;
import javax.servlet.http.Part;
import static org.apache.struts2.portlet.PortletConstants.*;
@@ -71,7 +80,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.http.HttpServletRequest#getAuthType()
*/
public String getAuthType() {
@@ -80,7 +89,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.http.HttpServletRequest#getContextPath()
*/
public String getContextPath() {
@@ -89,7 +98,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -102,7 +111,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -113,7 +122,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Gets a property from the {@link PortletRequest}. Note that a
* {@link PortletRequest} is not guaranteed to map properties to headers.
*
*
* @see PortletRequest#getProperty(String)
* @see javax.servlet.http.HttpServletRequest#getHeader(java.lang.String)
*/
@@ -124,7 +133,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Gets the property names from the {@link PortletRequest}. Note that a
* {@link PortletRequest} is not guaranteed to map properties to headers.
*
*
* @see PortletRequest#getPropertyNames()
* @see javax.servlet.http.HttpServletRequest#getHeaderNames()
*/
@@ -136,7 +145,7 @@ public class PortletServletRequest implements HttpServletRequest {
* Gets the values for the specified property from the
* {@link PortletRequest}. Note that a {@link PortletRequest} is not
* guaranteed to map properties to headers.
*
*
* @see PortletRequest#getProperties(String)
* @see HttpServletRequest#getHeaders(String)
*/
@@ -146,7 +155,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -156,7 +165,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.http.HttpServletRequest#getMethod()
*/
public String getMethod() {
@@ -170,7 +179,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.http.HttpServletRequest#getPathInfo()
*/
public String getPathInfo() {
@@ -179,7 +188,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.http.HttpServletRequest#getPathTranslated()
*/
public String getPathTranslated() {
@@ -188,7 +197,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.http.HttpServletRequest#getQueryString()
*/
public String getQueryString() {
@@ -197,7 +206,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.http.HttpServletRequest#getRemoteUser()
*/
public String getRemoteUser() {
@@ -206,7 +215,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -216,7 +225,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -226,7 +235,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.http.HttpServletRequest#getRequestedSessionId()
*/
public String getRequestedSessionId() {
@@ -237,7 +246,7 @@ public class PortletServletRequest implements HttpServletRequest {
* A {@link PortletRequest} has no servlet path. But for compatibility with
* Struts 2 components and interceptors, the action parameter on the request
* is mapped to the servlet path.
*
*
* @see javax.servlet.http.HttpServletRequest#getServletPath()
*/
public String getServletPath() {
@@ -250,16 +259,21 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Get the {@link PortletSession} as a {@link PortletHttpSession} instance.
*
*
* @see javax.servlet.http.HttpServletRequest#getSession()
*/
public HttpSession getSession() {
return new PortletHttpSession(portletRequest.getPortletSession());
}
@Override
public String changeSessionId() {
return null;
}
/**
* Get the {@link PortletSession} as a {@link PortletHttpSession} instance.
*
*
* @see javax.servlet.http.HttpServletRequest#getSession(boolean)
*/
public HttpSession getSession(boolean create) {
@@ -268,7 +282,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.http.HttpServletRequest#getUserPrincipal()
*/
public Principal getUserPrincipal() {
@@ -277,7 +291,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -287,7 +301,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -297,7 +311,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -305,9 +319,39 @@ public class PortletServletRequest implements HttpServletRequest {
throw new IllegalStateException("Not allowed in a portlet");
}
@Override
public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
return false;
}
@Override
public void login(String username, String password) throws ServletException {
}
@Override
public void logout() throws ServletException {
}
@Override
public Collection<Part> getParts() throws IOException, ServletException {
return null;
}
@Override
public Part getPart(String name) throws IOException, ServletException {
return null;
}
@Override
public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException {
return null;
}
/*
* (non-Javadoc)
*
*
* @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid()
*/
public boolean isRequestedSessionIdValid() {
@@ -316,7 +360,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.http.HttpServletRequest#isUserInRole(java.lang.String)
*/
public boolean isUserInRole(String role) {
@@ -327,7 +371,7 @@ public class PortletServletRequest implements HttpServletRequest {
* Gets an attribute value on the {@link PortletRequest}. If the attribute
* name is <tt>javax.servlet.include.servlet_path</tt>, it returns the
* same as {@link PortletServletRequest#getServletPath()}
*
*
* @see javax.servlet.ServletRequest#getAttribute(java.lang.String)
*/
public Object getAttribute(String name) {
@@ -340,7 +384,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.ServletRequest#getAttributeNames()
*/
public Enumeration getAttributeNames() {
@@ -349,7 +393,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Can only be invoked in the event phase.
*
*
* @see ServletRequest#getCharacterEncoding()
* @throws IllegalStateException
* If the portlet is not in the event phase.
@@ -364,7 +408,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Can only be invoked in the event phase.
*
*
* @see ServletRequest#getContentLength()
* @throws IllegalStateException
* If the portlet is not in the event phase.
@@ -377,9 +421,14 @@ public class PortletServletRequest implements HttpServletRequest {
}
}
@Override
public long getContentLengthLong() {
return 0;
}
/**
* Can only be invoked in the event phase.
*
*
* @see ServletRequest#getContentType()
* @throws IllegalStateException
* If the portlet is not in the event phase.
@@ -396,7 +445,7 @@ public class PortletServletRequest implements HttpServletRequest {
* Can only be invoked in the event phase. When invoked in the event phase,
* it will wrap the portlet's {@link InputStream} as a
* {@link PortletServletInputStream}.
*
*
* @see ServletRequest#getInputStream()
* @throws IllegalStateException
* If the portlet is not in the event phase.
@@ -412,7 +461,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -425,7 +474,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -438,7 +487,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -449,9 +498,44 @@ public class PortletServletRequest implements HttpServletRequest {
throw new IllegalStateException("Not allowed in a portlet");
}
@Override
public ServletContext getServletContext() {
return null;
}
@Override
public AsyncContext startAsync() throws IllegalStateException {
return null;
}
@Override
public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException {
return null;
}
@Override
public boolean isAsyncStarted() {
return false;
}
@Override
public boolean isAsyncSupported() {
return false;
}
@Override
public AsyncContext getAsyncContext() {
return null;
}
@Override
public DispatcherType getDispatcherType() {
return null;
}
/*
* (non-Javadoc)
*
*
* @see javax.servlet.ServletRequest#getLocale()
*/
public Locale getLocale() {
@@ -460,7 +544,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.ServletRequest#getLocales()
*/
public Enumeration getLocales() {
@@ -469,7 +553,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.ServletRequest#getParameter(java.lang.String)
*/
public String getParameter(String name) {
@@ -485,7 +569,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.ServletRequest#getParameterMap()
*/
public Map getParameterMap() {
@@ -494,7 +578,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.ServletRequest#getParameterNames()
*/
public Enumeration getParameterNames() {
@@ -503,7 +587,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.ServletRequest#getParameterValues(java.lang.String)
*/
public String[] getParameterValues(String name) {
@@ -512,7 +596,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -525,7 +609,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Can only be invoked in the event phase.
*
*
* @see ServletRequest#getReader()
* @throws IllegalStateException
* If the portlet is not in the event phase.
@@ -540,7 +624,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.ServletRequest#getRealPath(java.lang.String)
*/
public String getRealPath(String path) {
@@ -549,7 +633,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -562,7 +646,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -575,7 +659,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -589,7 +673,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Get the {@link PortletRequestDispatcher} as a
* {@link PortletServletRequestDispatcher} instance.
*
*
* @see javax.servlet.ServletRequest#getRequestDispatcher(java.lang.String)
*/
public RequestDispatcher getRequestDispatcher(String path) {
@@ -599,7 +683,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.ServletRequest#getScheme()
*/
public String getScheme() {
@@ -608,7 +692,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.ServletRequest#getServerName()
*/
public String getServerName() {
@@ -617,7 +701,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Not allowed in a portlet.
*
*
* @throws IllegalStateException
* Not allowed in a portlet.
*/
@@ -630,7 +714,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.ServletRequest#isSecure()
*/
public boolean isSecure() {
@@ -639,7 +723,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.ServletRequest#removeAttribute(java.lang.String)
*/
public void removeAttribute(String name) {
@@ -648,7 +732,7 @@ public class PortletServletRequest implements HttpServletRequest {
/*
* (non-Javadoc)
*
*
* @see javax.servlet.ServletRequest#setAttribute(java.lang.String,
* java.lang.Object)
*/
@@ -658,7 +742,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Can only be invoked in the event phase.
*
*
* @see ServletRequest#setCharacterEncoding(String)
* @throws IllegalStateException
* If the portlet is not in the event phase.
@@ -674,7 +758,7 @@ public class PortletServletRequest implements HttpServletRequest {
/**
* Get the wrapped {@link PortletRequest} instance.
*
*
* @return The wrapped {@link PortletRequest} instance.
*/
public PortletRequest getPortletRequest() {
@@ -20,6 +20,7 @@ package org.apache.struts2.portlet.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Locale;
import javax.portlet.PortletResponse;
@@ -31,11 +32,11 @@ import javax.servlet.http.HttpServletResponse;
public class PortletServletResponse implements HttpServletResponse {
protected PortletResponse portletResponse;
public PortletServletResponse(PortletResponse portletResponse) {
this.portletResponse = portletResponse;
}
public void addCookie(Cookie cookie) {
throw new IllegalStateException("Not allowed in a portlet");
}
@@ -104,6 +105,26 @@ public class PortletServletResponse implements HttpServletResponse {
throw new IllegalStateException("Not allowed in a portlet");
}
@Override
public int getStatus() {
return 0;
}
@Override
public String getHeader(String name) {
return null;
}
@Override
public Collection<String> getHeaders(String name) {
return null;
}
@Override
public Collection<String> getHeaderNames() {
return null;
}
public void flushBuffer() throws IOException {
if(portletResponse instanceof RenderResponse) {
((RenderResponse)portletResponse).flushBuffer();
@@ -211,6 +232,11 @@ public class PortletServletResponse implements HttpServletResponse {
throw new IllegalStateException("Not allowed in a portlet");
}
@Override
public void setContentLengthLong(long len) {
}
public void setContentType(String type) {
if(portletResponse instanceof RenderResponse) {
((RenderResponse)portletResponse).setContentType(type);
+1 -11
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>6.0.0-RC3</version>
<version>6.0.0-RC4</version>
</parent>
<artifactId>struts2-rest-plugin</artifactId>
@@ -96,16 +96,6 @@
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<!-- The Servlet API mocks in Spring Framework 4.x only supports Servlet 3.0 and higher.
This is only necessary in tests-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
@@ -34,23 +34,22 @@ import java.io.InputStreamReader;
*/
public class ContentTypeInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 1L;
ContentTypeHandlerManager selector;
private final ContentTypeHandlerManager selector;
@Inject
public void setContentTypeHandlerSelector(ContentTypeHandlerManager sel) {
this.selector = sel;
public ContentTypeInterceptor(ContentTypeHandlerManager selector) {
this.selector = selector;
}
public String intercept(ActionInvocation invocation) throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
ContentTypeHandler handler = selector.getHandlerForRequest(request);
Object target = invocation.getAction();
if (target instanceof ModelDriven) {
target = ((ModelDriven)target).getModel();
target = ((ModelDriven<?>)target).getModel();
}
if (request.getContentLength() > 0) {
InputStream is = request.getInputStream();
InputStreamReader reader = new InputStreamReader(is);

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