mirror of
https://github.com/apache/struts.git
synced 2026-08-31 19:35:40 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d8cf56977 | |||
| 7b7d3ca0e1 | |||
| 3292152f8c | |||
| 28498a807d | |||
| 2d6f1bc0a6 | |||
| 36e4e7410e | |||
| e903739624 | |||
| a85328e74e | |||
| c3deb39237 | |||
| 483a0c8d01 |
@@ -3,10 +3,10 @@ notifications:
|
||||
commits: commits@struts.apache.org
|
||||
# Send all issue emails (new, closed, comments) to issues@
|
||||
issues: issues@struts.apache.org
|
||||
# Send new/closed PR notifications to commits@
|
||||
pullrequests_status: notifications@struts.apache.org
|
||||
# Send new/closed PR notifications to dev@
|
||||
pullrequests_status: dev@struts.apache.org
|
||||
# Send individual PR comments/reviews to issues@
|
||||
pullrequests_comment: notifications@struts.apache.org
|
||||
pullrequests_comment: issues@struts.apache.org
|
||||
# Link opened PRs with JIRA
|
||||
jira_options: link label worklog
|
||||
|
||||
@@ -14,7 +14,3 @@ github:
|
||||
del_branch_on_merge: true
|
||||
protected_branches:
|
||||
master: { }
|
||||
autolink_jira:
|
||||
- WW
|
||||
dependabot_alerts: true
|
||||
dependabot_updates: true
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "maven"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
@@ -20,14 +20,6 @@ on:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
security-events: write
|
||||
actions: read
|
||||
contents: read
|
||||
# Needed to access OIDC token.
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
@@ -42,14 +34,14 @@ jobs:
|
||||
language: [ 'java' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
+21
-10
@@ -13,7 +13,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
name: Java Maven
|
||||
name: Java Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -21,26 +21,37 @@ on:
|
||||
branches:
|
||||
- master
|
||||
|
||||
permissions: read-all
|
||||
|
||||
env:
|
||||
MAVEN_OPTS: -Xmx2048m -Xms1024m
|
||||
LANG: en_US.utf8
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and Test
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
java: [ '8', '11', '17', '21' ]
|
||||
java: [ '8', '11', '17' ]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
uses: actions/checkout@v3.0.2
|
||||
- name: Set up cache
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
distribution: temurin
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maven-
|
||||
- name: Set up JDK ${{ matrix.java }}
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: adopt
|
||||
java-version: ${{ matrix.java }}
|
||||
cache: 'maven'
|
||||
- name: Build with Maven on Java ${{ matrix.java }}
|
||||
run: mvn -B -V -DskipAssembly verify --no-transfer-progress
|
||||
if: matrix.java != '11'
|
||||
run: mvn -B -V -DskipAssembly test --no-transfer-progress
|
||||
- name: Code coverage on Java ${{ matrix.java }}
|
||||
if: matrix.java == '11'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONARCLOUD_TOKEN }}
|
||||
run: mvn -B -V -Pcoverage -DskipAssembly verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar --no-transfer-progress
|
||||
|
||||
@@ -40,12 +40,12 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@v4 # 3.1.0
|
||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # 3.1.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # 2.3.1
|
||||
uses: ossf/scorecard-action@99c53751e09b9529366343771cc321ec74e9bd3d # 2.0.6
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
@@ -57,13 +57,13 @@ jobs:
|
||||
publish_results: true
|
||||
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # 4.0.0
|
||||
uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # 3.1.0
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@03e7845b7bfcd5e7fb63d1ae8c61b0e791134fab # 2.22.11
|
||||
uses: github/codeql-action/upload-sarif@b398f525a5587552e573b247ac661067fafa920b # 2.1.22
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -1,46 +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.
|
||||
|
||||
name: SonarCloud
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
permissions: read-all
|
||||
|
||||
env:
|
||||
MAVEN_OPTS: -Xmx2048m -Xms1024m
|
||||
LANG: en_US.utf8
|
||||
|
||||
jobs:
|
||||
sonarcloud:
|
||||
name: Scan
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: temurin
|
||||
java-version: 17
|
||||
cache: 'maven'
|
||||
- env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONARCLOUD_TOKEN }}
|
||||
run: mvn -B -V -Pcoverage -DskipAssembly verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar --no-transfer-progress
|
||||
@@ -1,2 +0,0 @@
|
||||
# Request PR review from any Apache Struts committer
|
||||
* @apache/struts-committers
|
||||
Vendored
+20
-93
@@ -25,36 +25,6 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('JDK 21') {
|
||||
agent {
|
||||
label 'ubuntu'
|
||||
}
|
||||
tools {
|
||||
jdk 'jdk_21_latest'
|
||||
maven 'maven_3_latest'
|
||||
}
|
||||
environment {
|
||||
MAVEN_OPTS = "-Xmx1024m"
|
||||
}
|
||||
stages {
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh './mvnw -B -DskipAssembly verify --no-transfer-progress'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
junit(testResults: '**/surefire-reports/*.xml', allowEmptyResults: true)
|
||||
junit(testResults: '**/failsafe-reports/*.xml', allowEmptyResults: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
cleanWs deleteDirs: true, patterns: [[pattern: '**/target/**', type: 'INCLUDE']]
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('JDK 17') {
|
||||
agent {
|
||||
label 'ubuntu'
|
||||
@@ -69,12 +39,12 @@ pipeline {
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh './mvnw -B -DskipAssembly verify --no-transfer-progress'
|
||||
sh './mvnw -B clean install -DskipTests -DskipAssembly'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh './mvnw -B verify -Pcoverage -DskipAssembly'
|
||||
sh './mvnw -B test'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
@@ -83,61 +53,6 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Code Quality') {
|
||||
when {
|
||||
anyOf {
|
||||
branch 'master'; branch 'release/struts-7-0-x'
|
||||
}
|
||||
}
|
||||
steps {
|
||||
withCredentials([string(credentialsId: 'asf-struts-sonarcloud', variable: 'SONARCLOUD_TOKEN')]) {
|
||||
sh './mvnw -B -Pcoverage -DskipAssembly -Dsonar.login=${SONARCLOUD_TOKEN} verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Build Source & JavaDoc') {
|
||||
when {
|
||||
branch 'release/struts-7-0-x'
|
||||
}
|
||||
steps {
|
||||
dir("local-snapshots-dir/") {
|
||||
deleteDir()
|
||||
}
|
||||
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly'
|
||||
}
|
||||
}
|
||||
stage('Deploy Snapshot') {
|
||||
when {
|
||||
branch 'release/struts-7-0-x'
|
||||
}
|
||||
steps {
|
||||
withCredentials([file(credentialsId: 'lukaszlenart-repository-access-token', variable: 'CUSTOM_SETTINGS')]) {
|
||||
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Upload nightlies') {
|
||||
when {
|
||||
branch 'release/struts-7-0-x'
|
||||
}
|
||||
steps {
|
||||
sh './mvnw -B package -DskipTests'
|
||||
sshPublisher(publishers: [
|
||||
sshPublisherDesc(
|
||||
configName: 'Nightlies',
|
||||
transfers: [
|
||||
sshTransfer(
|
||||
remoteDirectory: '/struts/snapshot',
|
||||
removePrefix: 'assembly/target/assembly/out',
|
||||
sourceFiles: 'assembly/target/assembly/out/struts-*.zip',
|
||||
cleanRemote: true
|
||||
)
|
||||
],
|
||||
verbose: true
|
||||
)
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
@@ -159,12 +74,12 @@ pipeline {
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh './mvnw -B -DskipAssembly verify --no-transfer-progress'
|
||||
sh './mvnw -B clean install -DskipTests -DskipAssembly'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh './mvnw -B test'
|
||||
sh './mvnw -B verify -Pcoverage -DskipAssembly'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
@@ -173,6 +88,16 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Code Quality') {
|
||||
when {
|
||||
branch 'master'
|
||||
}
|
||||
steps {
|
||||
withCredentials([string(credentialsId: 'asf-struts-sonarcloud', variable: 'SONARCLOUD_TOKEN')]) {
|
||||
sh './mvnw -B -Pcoverage -DskipAssembly -Dsonar.login=${SONARCLOUD_TOKEN} verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
@@ -200,6 +125,7 @@ pipeline {
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh './mvnw -B test'
|
||||
// step([$class: 'JiraIssueUpdater', issueSelector: [$class: 'DefaultIssueSelector'], scm: scm])
|
||||
}
|
||||
post {
|
||||
always {
|
||||
@@ -242,7 +168,8 @@ pipeline {
|
||||
sshTransfer(
|
||||
remoteDirectory: '/struts/snapshot',
|
||||
removePrefix: 'assembly/target/assembly/out',
|
||||
sourceFiles: 'assembly/target/assembly/out/struts-*.zip'
|
||||
sourceFiles: 'assembly/target/assembly/out/struts-*.zip',
|
||||
cleanRemote: true
|
||||
)
|
||||
],
|
||||
verbose: true
|
||||
@@ -263,7 +190,7 @@ pipeline {
|
||||
failure {
|
||||
script {
|
||||
emailext(
|
||||
to: "notifications@struts.apache.org",
|
||||
to: "dev@struts.apache.org",
|
||||
recipientProviders: [[$class: 'DevelopersRecipientProvider']],
|
||||
from: "Mr. Jenkins <jenkins@builds.apache.org>",
|
||||
subject: "Jenkins job ${env.JOB_NAME}#${env.BUILD_NUMBER} failed",
|
||||
@@ -286,7 +213,7 @@ Director of Continuous Integration
|
||||
unstable {
|
||||
script {
|
||||
emailext(
|
||||
to: "notifications@struts.apache.org",
|
||||
to: "dev@struts.apache.org",
|
||||
recipientProviders: [[$class: 'DevelopersRecipientProvider']],
|
||||
from: "Mr. Jenkins <jenkins@builds.apache.org>",
|
||||
subject: "Jenkins job ${env.JOB_NAME}#${env.BUILD_NUMBER} unstable",
|
||||
@@ -309,7 +236,7 @@ Director of Continuous Integration
|
||||
fixed {
|
||||
script {
|
||||
emailext(
|
||||
to: "notifications@struts.apache.org",
|
||||
to: "dev@struts.apache.org",
|
||||
recipientProviders: [[$class: 'DevelopersRecipientProvider']],
|
||||
from: 'Mr. Jenkins <jenkins@builds.apache.org>',
|
||||
subject: "Jenkins job ${env.JOB_NAME}#${env.BUILD_NUMBER} back to normal",
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.1.2.2</version>
|
||||
</parent>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.1.2.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-rest-showcase</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.1.2.2</version>
|
||||
<name>Struts 2 Rest Showcase Webapp</name>
|
||||
<description>Struts 2 Rest Showcase Example</description>
|
||||
|
||||
@@ -56,10 +56,12 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -78,6 +80,7 @@
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.htmlunit</groupId>
|
||||
<artifactId>htmlunit</artifactId>
|
||||
<version>2.39.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
|
||||
<struts>
|
||||
|
||||
+16
-6
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.1.2.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-showcase</artifactId>
|
||||
@@ -68,6 +68,12 @@
|
||||
<artifactId>struts2-json-plugin</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.tiles</groupId>
|
||||
<artifactId>tiles-jsp</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-convention-plugin</artifactId>
|
||||
@@ -93,11 +99,6 @@
|
||||
<artifactId>struts2-velocity-plugin</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-xslt-plugin</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
@@ -108,18 +109,22 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-jcl</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -130,6 +135,10 @@
|
||||
<groupId>org.directwebremoting</groupId>
|
||||
<artifactId>dwr</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-fileupload</groupId>
|
||||
<artifactId>commons-fileupload</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
@@ -140,6 +149,7 @@
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.htmlunit</groupId>
|
||||
<artifactId>htmlunit</artifactId>
|
||||
<version>2.61.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -21,17 +21,16 @@
|
||||
package org.apache.struts2.showcase.chat;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
public class ChatLoginAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private ChatService chatService;
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
|
||||
private String name;
|
||||
|
||||
@@ -61,8 +60,8 @@ public class ChatLoginAction extends ActionSupport implements SessionAware {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
// === SessionAware ===
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,18 +21,17 @@
|
||||
package org.apache.struts2.showcase.chat;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
public class ChatLogoutAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private ChatService chatService;
|
||||
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
|
||||
|
||||
public ChatLogoutAction(ChatService chatService) {
|
||||
@@ -51,8 +50,8 @@ public class ChatLogoutAction extends ActionSupport implements SessionAware {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
// === SessionAware ===
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,17 +21,16 @@
|
||||
package org.apache.struts2.showcase.chat;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
public class EnterRoomAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private ChatService chatService;
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
private String roomName;
|
||||
|
||||
public String getRoomName() {
|
||||
@@ -57,9 +56,10 @@ public class EnterRoomAction extends ActionSupport implements SessionAware {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
// === SessionAware ===
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,18 +21,17 @@
|
||||
package org.apache.struts2.showcase.chat;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
public class ExitRoomAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String roomName;
|
||||
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
|
||||
public String getRoomName() {
|
||||
return roomName;
|
||||
@@ -55,9 +54,9 @@ public class ExitRoomAction extends ActionSupport implements SessionAware {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
// === SessionAware ===
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-7
@@ -21,11 +21,10 @@
|
||||
package org.apache.struts2.showcase.chat;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
public class SendMessageToRoomAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -34,7 +33,7 @@ public class SendMessageToRoomAction extends ActionSupport implements SessionAwa
|
||||
|
||||
private String roomName;
|
||||
private String message;
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
|
||||
|
||||
public SendMessageToRoomAction(ChatService chatService) {
|
||||
@@ -68,10 +67,9 @@ public class SendMessageToRoomAction extends ActionSupport implements SessionAwa
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+55
-47
@@ -21,67 +21,75 @@
|
||||
package org.apache.struts2.showcase.fileupload;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.action.UploadedFilesAware;
|
||||
import org.apache.struts2.dispatcher.multipart.UploadedFile;
|
||||
|
||||
import java.util.List;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Show case File Upload example's action. <code>FileUploadAction</code>
|
||||
*/
|
||||
public class FileUploadAction extends ActionSupport implements UploadedFilesAware {
|
||||
public class FileUploadAction extends ActionSupport {
|
||||
|
||||
private String contentType;
|
||||
private UploadedFile uploadedFile;
|
||||
private String fileName;
|
||||
private String caption;
|
||||
private String originalName;
|
||||
private static final long serialVersionUID = 5156288255337069381L;
|
||||
|
||||
public String input() throws Exception {
|
||||
return SUCCESS;
|
||||
}
|
||||
private String contentType;
|
||||
private File upload;
|
||||
private String fileName;
|
||||
private String caption;
|
||||
|
||||
public String upload() throws Exception {
|
||||
return SUCCESS;
|
||||
}
|
||||
public String input() throws Exception {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
public String upload() throws Exception {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
// since we are using <s:file name="upload" .../> the file name will be
|
||||
// obtained through getter/setter of <file-tag-name>FileName
|
||||
public String getUploadFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public String getOriginalName() {
|
||||
return originalName;
|
||||
}
|
||||
public void setUploadFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public Object getUploadedFile() {
|
||||
return uploadedFile.getContent();
|
||||
}
|
||||
|
||||
public String getCaption() {
|
||||
return caption;
|
||||
}
|
||||
// since we are using <s:file name="upload" ... /> the content type will be
|
||||
// obtained through getter/setter of <file-tag-name>ContentType
|
||||
public String getUploadContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public void setCaption(String caption) {
|
||||
this.caption = caption;
|
||||
}
|
||||
public void setUploadContentType(String contentType) {
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public long getUploadSize() {
|
||||
if (uploadedFile != null) {
|
||||
return uploadedFile.length();
|
||||
} else {
|
||||
return 0;
|
||||
|
||||
// since we are using <s:file name="upload" ... /> the File itself will be
|
||||
// obtained through getter/setter of <file-tag-name>
|
||||
public File getUpload() {
|
||||
return upload;
|
||||
}
|
||||
|
||||
public void setUpload(File upload) {
|
||||
this.upload = upload;
|
||||
}
|
||||
|
||||
|
||||
public String getCaption() {
|
||||
return caption;
|
||||
}
|
||||
|
||||
public void setCaption(String caption) {
|
||||
this.caption = caption;
|
||||
}
|
||||
|
||||
public long getUploadSize() {
|
||||
if (upload != null) {
|
||||
return upload.length();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withUploadedFiles(List<UploadedFile> uploadedFiles) {
|
||||
this.uploadedFile = uploadedFiles.get(0);
|
||||
this.fileName = uploadedFile.getName();
|
||||
this.contentType = uploadedFile.getContentType();
|
||||
this.originalName = uploadedFile.getOriginalName();
|
||||
}
|
||||
}
|
||||
|
||||
+6
-8
@@ -21,16 +21,15 @@
|
||||
package org.apache.struts2.showcase.hangman;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
public class GetUpdatedHangmanAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private static final long serialVersionUID = 5506025785406043027L;
|
||||
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
private Hangman hangman;
|
||||
|
||||
|
||||
@@ -46,6 +45,10 @@ public class GetUpdatedHangmanAction extends ActionSupport implements SessionAwa
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public Hangman getHangman() {
|
||||
return hangman;
|
||||
}
|
||||
@@ -53,9 +56,4 @@ public class GetUpdatedHangmanAction extends ActionSupport implements SessionAwa
|
||||
public void setHangman(Hangman hangman) {
|
||||
this.hangman = hangman;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-8
@@ -21,16 +21,15 @@
|
||||
package org.apache.struts2.showcase.hangman;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
public class GuessCharacterAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private static final long serialVersionUID = 9050915577007590674L;
|
||||
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
private Character character;
|
||||
private Hangman hangman;
|
||||
|
||||
@@ -45,6 +44,10 @@ public class GuessCharacterAction extends ActionSupport implements SessionAware
|
||||
return hangman;
|
||||
}
|
||||
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public void setCharacter(Character character) {
|
||||
this.character = character;
|
||||
}
|
||||
@@ -52,9 +55,4 @@ public class GuessCharacterAction extends ActionSupport implements SessionAware
|
||||
public Character getCharacter() {
|
||||
return this.character;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-7
@@ -21,11 +21,10 @@
|
||||
package org.apache.struts2.showcase.hangman;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
import static org.apache.struts2.showcase.hangman.HangmanConstants.HANGMAN_SESSION_KEY;
|
||||
|
||||
public class StartHangmanAction extends ActionSupport implements SessionAware {
|
||||
@@ -34,7 +33,7 @@ public class StartHangmanAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private HangmanService service;
|
||||
private Hangman hangman;
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
|
||||
|
||||
public StartHangmanAction(HangmanService service) {
|
||||
@@ -54,8 +53,8 @@ public class StartHangmanAction extends ActionSupport implements SessionAware {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
// === SessionAware ===
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.showcase.servlet;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestServlet extends HttpServlet {
|
||||
@Override
|
||||
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
switch (request.getPathInfo()) {
|
||||
case "/forward":
|
||||
getServletContext().getRequestDispatcher("/dispatcher/dispatch.action").forward(request, response);
|
||||
break;
|
||||
default:
|
||||
response.sendError(404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,11 +21,9 @@
|
||||
package org.apache.struts2.showcase.xslt;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.ServletRequestAware;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.struts2.action.ServletRequestAware;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -55,6 +53,10 @@ public class JVMAction implements ServletRequestAware {
|
||||
return servletRequest;
|
||||
}
|
||||
|
||||
public void setServletRequest(HttpServletRequest servletRequest) {
|
||||
this.servletRequest = servletRequest;
|
||||
}
|
||||
|
||||
public Map<String, String> getEnvironment() {
|
||||
return environment;
|
||||
}
|
||||
@@ -98,9 +100,4 @@ public class JVMAction implements ServletRequestAware {
|
||||
this.systemProperties = systemProperties;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withServletRequest(HttpServletRequest request) {
|
||||
this.servletRequest = request;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="actionchaining" extends="struts-default" namespace="/actionchaining">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="async" extends="json-default" namespace="/async">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="conversion" namespace="/conversion" extends="struts-default">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="dispatcher" extends="struts-default" namespace="/dispatcher">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="filedownload" extends="struts-default" namespace="/filedownload">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="fileupload" extends="struts-default" namespace="/fileupload">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="freemarker" namespace="/freemarker" extends="struts-default">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="hangman" extends="struts-default" namespace="/hangman">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="interactive" namespace="/interactive" extends="struts-default">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="modelDriven" extends="struts-default" namespace="/modelDriven">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<!-- START SNIPPET: xworkSample -->
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="ui-tags" extends="velocity-default" namespace="/tags/ui">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<include file="struts-tags-ui.xml"/>
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="tiles" extends="tiles-default" namespace="/tiles">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
<struts>
|
||||
<package name="token" extends="struts-default" namespace="/token">
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
|
||||
|
||||
@@ -20,15 +20,12 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
|
||||
<bean type="org.apache.struts2.interceptor.exec.ExecutorProvider" name="threadPool"
|
||||
class="org.apache.struts2.showcase.wait.ThreadPoolExecutorProvider"/>
|
||||
|
||||
<constant name="struts.executor.provider" value="threadPool"/>
|
||||
<bean type="org.apache.struts2.interceptor.exec.ExecutorProvider" class="org.apache.struts2.showcase.wait.ThreadPoolExecutorProvider"/>
|
||||
|
||||
<package name="wait" extends="struts-default" namespace="/wait">
|
||||
<default-action-ref name="index"/>
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="xslt" extends="xslt-default" namespace="/xslt">
|
||||
<package name="xslt" extends="struts-default" namespace="/xslt">
|
||||
<default-action-ref name="index"/>
|
||||
|
||||
<action name="index">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<!-- START SNIPPET: xworkSample -->
|
||||
<struts>
|
||||
@@ -34,19 +34,6 @@
|
||||
<constant name="struts.custom.i18n.resources" value="globalMessages" />
|
||||
<constant name="struts.action.extension" value="action,," />
|
||||
|
||||
<constant name="struts.allowlist.enable" value="true" />
|
||||
<constant name="struts.allowlist.packageNames"
|
||||
value="
|
||||
org.apache.struts2.showcase.model,
|
||||
org.apache.struts2.showcase.conversion
|
||||
"/>
|
||||
<constant name="struts.allowlist.classes"
|
||||
value="
|
||||
org.apache.struts2.showcase.UITagExample$Language,
|
||||
org.apache.struts2.showcase.UITagExample$VehicalType,
|
||||
org.apache.struts2.showcase.UITagExample$VehicalSpecific
|
||||
"/>
|
||||
|
||||
<constant name="struts.convention.package.locators.basePackage" value="org.apache.struts2.showcase" />
|
||||
<constant name="struts.convention.result.path" value="/WEB-INF" />
|
||||
|
||||
@@ -57,7 +44,7 @@
|
||||
<constant name="struts.serve.static" value="true" />
|
||||
<constant name="struts.serve.static.browserCache" value="false" />
|
||||
|
||||
<constant name="struts.action.excludePattern" value=".*/images/.*\.gif,.*/img/.*\.gif,.*/styles/.*\.css,.*/js/.*\.js,/testServlet/.*"/>
|
||||
<constant name="struts.action.excludePattern" value=".*/images/.*\.gif,.*/img/.*\.gif,.*/styles/.*\.css,.*/js/.*\.js"/>
|
||||
|
||||
<include file="struts-interactive.xml" />
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
<s:script src="%{jqueryJs}"/>
|
||||
<s:url var="bootstrapJs" value='/js/bootstrap.min.js' encode='false' includeParams='none'/>
|
||||
<s:script src="%{bootstrapJs}"/>
|
||||
<s:script>
|
||||
<s:script type="text/javascript">
|
||||
$(function () {
|
||||
var alerts = $('ul.alert').wrap('<div />');
|
||||
alerts.prepend('<a class="close" data-dismiss="alert" href="#">×</a>');
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
-->
|
||||
<%@ page
|
||||
language="java"
|
||||
language="java"
|
||||
contentType="text/html; charset=UTF-8"
|
||||
pageEncoding="UTF-8"%>
|
||||
<%@ taglib prefix="s" uri="/struts-tags" %>
|
||||
@@ -37,10 +37,9 @@
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<ul>
|
||||
<li>ContentType: <s:property value="contentType" /></li>
|
||||
<li>FileName: <s:property value="fileName" /></li>
|
||||
<li>Original FileName: <s:property value="originalName" /></li>
|
||||
<li>File: <s:property value="uploadedFile" /></li>
|
||||
<li>ContentType: <s:property value="uploadContentType" /></li>
|
||||
<li>FileName: <s:property value="uploadFileName" /></li>
|
||||
<li>File: <s:property value="upload" /></li>
|
||||
<li>Caption:<s:property value="caption" /></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<s:script>
|
||||
<s:script type="text/javascript">
|
||||
/********************************************************************
|
||||
* JS just used on this page.
|
||||
* Usually this would be placed in a JS file
|
||||
|
||||
@@ -142,11 +142,6 @@
|
||||
<load-on-startup>4</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>testServlet</servlet-name>
|
||||
<servlet-class>org.apache.struts2.showcase.servlet.TestServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>dwr</servlet-name>
|
||||
<url-pattern>/dwr/*</url-pattern>
|
||||
@@ -167,11 +162,6 @@
|
||||
<url-pattern>/async/receiveNewMessages</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>testServlet</servlet-name>
|
||||
<url-pattern>/testServlet/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- END SNIPPET: dwr -->
|
||||
|
||||
<!-- SNIPPET START: example.velocity.filter.chain
|
||||
|
||||
+9
-2
@@ -32,6 +32,7 @@ public class DispatcherResultTest {
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/dispatcher/dispatch.action");
|
||||
|
||||
DomElement div = page.getElementById("dispatcher-result");
|
||||
|
||||
Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
}
|
||||
}
|
||||
@@ -39,10 +40,16 @@ public class DispatcherResultTest {
|
||||
@Test
|
||||
public void testDispatchingToAction() throws Exception {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/dispatcher/forward.action");
|
||||
|
||||
DomElement div = page.getElementById("dispatcher-result");
|
||||
Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
//DomElement div = page.getElementById("dispatcher-result");
|
||||
//Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
// support for forwarding to another action is broken on StrutsPrepareFilter/StrutsExecuteFilter
|
||||
// it only works in StrutsPrepareAndExecuteFilter
|
||||
// this will be fixed in Struts 6.1.x
|
||||
|
||||
Assert.assertEquals(404, page.getWebResponse().getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package it.org.apache.struts2.showcase;
|
||||
|
||||
import com.gargoylesoftware.htmlunit.WebClient;
|
||||
import com.gargoylesoftware.htmlunit.html.DomElement;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ForwardTest {
|
||||
|
||||
@Test
|
||||
public void testServletForwardingToAction() throws Exception {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
// Struts excluded URL, as defined by struts.action.excludePattern
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/testServlet/forward");
|
||||
|
||||
DomElement div = page.getElementById("dispatcher-result");
|
||||
Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.1.2.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-assembly</artifactId>
|
||||
@@ -41,8 +41,9 @@
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>dependency-maven-plugin</artifactId>
|
||||
<version>1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-war</id>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#set ($stylebase = "https://struts.apache.org/css")
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<!--
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
@@ -16,7 +16,7 @@ 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.
|
||||
under the License.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
@@ -43,12 +43,12 @@ under the License.
|
||||
<script src='http://struts.apache.org/highlighter/js/$hscript' type='text/javascript'></script>
|
||||
#end
|
||||
|
||||
<script>
|
||||
<script type="text/javascript">
|
||||
SyntaxHighlighter.defaults['toolbar'] = false;
|
||||
SyntaxHighlighter.all();
|
||||
</script>
|
||||
#end
|
||||
<script>
|
||||
<script type="text/javascript" language="javascript">
|
||||
var hide = null;
|
||||
var show = null;
|
||||
var children = null;
|
||||
|
||||
+5
-10
@@ -24,12 +24,12 @@
|
||||
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<artifactId>struts-master</artifactId>
|
||||
<version>14</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-bom</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.1.2.2</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Struts 2 Bill of Materials</name>
|
||||
@@ -44,7 +44,7 @@
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<struts-version.version>6.4.0-SNAPSHOT</struts-version.version>
|
||||
<struts-version.version>6.1.2.2</struts-version.version>
|
||||
<maven.site.skip>true</maven.site.skip>
|
||||
<maven.site.deploy.skip>true</maven.site.deploy.skip>
|
||||
</properties>
|
||||
@@ -181,16 +181,11 @@
|
||||
<artifactId>struts2-velocity-plugin</artifactId>
|
||||
<version>${struts-version.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-xslt-plugin</artifactId>
|
||||
<version>${struts-version.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<scm>
|
||||
<tag>STRUTS_6_3_0_1</tag>
|
||||
<tag>STRUTS_6_1_2_2</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>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.1.2.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-admin-bundle</artifactId>
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
<head>
|
||||
<title>OSGi Console</title>
|
||||
|
||||
<@s.link rel="stylesheet" type="text/css" href="${base}${parameters.staticContentPath}/css/shell.css" />
|
||||
<@s.link rel="stylesheet" type="text/css" href="${base}${parameters.staticContentPath}/css/main.css" />
|
||||
<@s.link rel="stylesheet" type="text/css" href="${base}${parameters.staticContentPath}/css/redmond/jquery-ui-1.12.1.redmond.css" />
|
||||
<link rel="stylesheet" type="text/css" href="<@s.url value="${parameters.staticContentPath}/css/shell.css" />" />
|
||||
<link rel="stylesheet" type="text/css" href="<@s.url value="${parameters.staticContentPath}/css/main.css" />" />
|
||||
<link rel="stylesheet" type="text/css" href="<@s.url value="${parameters.staticContentPath}/css/redmond/jquery-ui-1.12.1.redmond.css" />" />
|
||||
|
||||
<@s.script src="${base}${parameters.staticContentPath}/js/shell.js" />
|
||||
<@s.script src="${base}${parameters.staticContentPath}/js/jquery-1.12.4.min.js" />
|
||||
<@s.script src="${base}${parameters.staticContentPath}/js/jquery-ui-1.12.1.min.js" />
|
||||
<script src="<@s.url value="${parameters.staticContentPath}/js/shell.js" />"></script>
|
||||
<script src="<@s.url value="${parameters.staticContentPath}/js/jquery-1.12.4.min.js" />"></script>
|
||||
<script src="<@s.url value="${parameters.staticContentPath}/js/jquery-ui-1.12.1.min.js" />"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="menu">
|
||||
|
||||
@@ -22,17 +22,17 @@
|
||||
<head>
|
||||
<title>${bundle.symbolicName!}</title>
|
||||
|
||||
<@s.link rel="stylesheet" type="text/css" href="${base}${parameters.staticContentPath}/css/main.css" />
|
||||
<@s.link rel="stylesheet" type="text/css" href="${base}${parameters.staticContentPath}/css/redmond/jquery-ui-1.12.1.redmond.css" />
|
||||
<link rel="stylesheet" type="text/css" href="<@s.url value="${parameters.staticContentPath}/css/main.css" />" />
|
||||
<link rel="stylesheet" type="text/css" href="<@s.url value="${parameters.staticContentPath}/css/redmond/jquery-ui-1.12.1.redmond.css" />" />
|
||||
|
||||
<@s.script src="${base}${parameters.staticContentPath}/js/jquery-1.12.4.min.js"/>
|
||||
<@s.script src="${base}${parameters.staticContentPath}/js/jquery-ui-1.12.1.min.js" />
|
||||
<script src="<@s.url value="${parameters.staticContentPath}/js/jquery-1.12.4.min.js" />"></script>
|
||||
<script src="<@s.url value="${parameters.staticContentPath}/js/jquery-ui-1.12.1.min.js" />"></script>
|
||||
|
||||
<@s.script>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
$("#tabs").tabs();
|
||||
});
|
||||
</@s.script>
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
@@ -72,7 +72,7 @@
|
||||
<span class="ui-icon ui-icon-transferthick-e-w"></span>
|
||||
OSGi Shell
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<@s.actionerror />
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
<head>
|
||||
<title>OSGi Bundles</title>
|
||||
|
||||
<@s.link rel="stylesheet" type="text/css" href="${base}${parameters.staticContentPath}/css/main.css" />
|
||||
<@s.link rel="stylesheet" type="text/css" href="${base}${parameters.staticContentPath}/css/redmond/jquery-ui-1.12.1.redmond.css" />
|
||||
<link rel="stylesheet" type="text/css" href="<@s.url value="${parameters.staticContentPath}/css/main.css" />" />
|
||||
<link rel="stylesheet" type="text/css" href="<@s.url value="${parameters.staticContentPath}/css/redmond/jquery-ui-1.12.1.redmond.css" />" />
|
||||
|
||||
<@s.script src="${base}${parameters.staticContentPath}/js/jquery-1.12.4.min.js" />
|
||||
<@s.script src="${base}${parameters.staticContentPath}/js/jquery-ui-1.12.1.min.js" />
|
||||
<script src="<@s.url value="${parameters.staticContentPath}/js/jquery-1.12.4.min.js" />"></script>
|
||||
<script src="<@s.url value="${parameters.staticContentPath}/js/jquery-ui-1.12.1.min.js" />"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<span class="ui-icon ui-icon-transferthick-e-w"></span>
|
||||
OSGi Shell
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<@s.actionerror />
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
-->
|
||||
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.1.2.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-demo-bundle</artifactId>
|
||||
@@ -39,8 +39,8 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-digester3</artifactId>
|
||||
<groupId>commons-digester</groupId>
|
||||
<artifactId>commons-digester</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<!-- Set some Struts 2 constants relevant to the OSGi Plugin.
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.1.2.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
|
||||
+7
-6
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.4.0-SNAPSHOT</version>
|
||||
<version>6.1.2.2</version>
|
||||
</parent>
|
||||
<artifactId>struts2-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
@@ -184,11 +184,6 @@
|
||||
<artifactId>freemarker</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
@@ -222,6 +217,11 @@
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
@@ -260,6 +260,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -20,17 +20,12 @@ package com.opensymphony.xwork2;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
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 java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
@@ -101,9 +96,15 @@ public class ActionChainResult implements Result {
|
||||
*/
|
||||
private static final String CHAIN_HISTORY = "CHAIN_HISTORY";
|
||||
|
||||
/**
|
||||
* The result parameter name to set the name of the action to chain to.
|
||||
*/
|
||||
public static final String SKIP_ACTIONS_PARAM = "skipActions";
|
||||
|
||||
|
||||
private ActionProxy proxy;
|
||||
private String actionName;
|
||||
|
||||
|
||||
private String namespace;
|
||||
|
||||
private String methodName;
|
||||
@@ -132,6 +133,7 @@ public class ActionChainResult implements Result {
|
||||
this.skipActions = skipActions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param actionProxyFactory the actionProxyFactory to set
|
||||
*/
|
||||
@@ -170,6 +172,7 @@ public class ActionChainResult implements Result {
|
||||
this.skipActions = actions;
|
||||
}
|
||||
|
||||
|
||||
public void setMethod(String method) {
|
||||
this.methodName = method;
|
||||
}
|
||||
@@ -203,14 +206,18 @@ public class ActionChainResult implements Result {
|
||||
throw new IllegalArgumentException("Invocation cannot be null!");
|
||||
}
|
||||
|
||||
String finalNamespace = namespace != null ? translateVariables(namespace) : invocation.getProxy()
|
||||
.getNamespace();
|
||||
String finalActionName = translateVariables(actionName);
|
||||
String finalMethodName = methodName != null ? translateVariables(methodName) : null;
|
||||
ValueStack stack = invocation.getInvocationContext().getValueStack();
|
||||
String finalNamespace = this.namespace != null
|
||||
? TextParseUtil.translateVariables(namespace, stack)
|
||||
: invocation.getProxy().getNamespace();
|
||||
String finalActionName = TextParseUtil.translateVariables(actionName, stack);
|
||||
String finalMethodName = this.methodName != null
|
||||
? TextParseUtil.translateVariables(this.methodName, stack)
|
||||
: null;
|
||||
|
||||
if (isInChainHistory(finalNamespace, finalActionName, finalMethodName)) {
|
||||
addToHistory(finalNamespace, finalActionName, finalMethodName);
|
||||
throw new StrutsException("Infinite recursion detected: " + ActionChainResult.getChainHistory());
|
||||
throw new StrutsException("Infinite recursion detected: " + ActionChainResult.getChainHistory().toString());
|
||||
}
|
||||
|
||||
if (ActionChainResult.getChainHistory().isEmpty() && invocation.getProxy() != null) {
|
||||
@@ -218,7 +225,7 @@ public class ActionChainResult implements Result {
|
||||
}
|
||||
addToHistory(finalNamespace, finalActionName, finalMethodName);
|
||||
|
||||
Map<String, Object> extraContext = ActionContext.of()
|
||||
Map<String, Object> extraContext = ActionContext.of(new HashMap<>())
|
||||
.withValueStack(invocation.getInvocationContext().getValueStack())
|
||||
.withParameters(invocation.getInvocationContext().getParameters())
|
||||
.with(CHAIN_HISTORY, ActionChainResult.getChainHistory())
|
||||
@@ -230,25 +237,20 @@ public class ActionChainResult implements Result {
|
||||
proxy.execute();
|
||||
}
|
||||
|
||||
protected String translateVariables(String text) {
|
||||
return TextParseUtil.translateVariables(text, ActionContext.getContext().getValueStack());
|
||||
@Override public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final ActionChainResult that = (ActionChainResult) o;
|
||||
|
||||
if (actionName != null ? !actionName.equals(that.actionName) : that.actionName != null) return false;
|
||||
if (methodName != null ? !methodName.equals(that.methodName) : that.methodName != null) return false;
|
||||
if (namespace != null ? !namespace.equals(that.namespace) : that.namespace != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ActionChainResult that = (ActionChainResult) o;
|
||||
return Objects.equals(actionName, that.actionName) && Objects.equals(methodName,
|
||||
that.methodName) && Objects.equals(namespace, that.namespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
@Override public int hashCode() {
|
||||
int result;
|
||||
result = (actionName != null ? actionName.hashCode() : 0);
|
||||
result = 31 * result + (namespace != null ? namespace.hashCode() : 0);
|
||||
@@ -258,15 +260,24 @@ public class ActionChainResult implements Result {
|
||||
|
||||
private boolean isInChainHistory(String namespace, String actionName, String methodName) {
|
||||
LinkedList<? extends String> chainHistory = ActionChainResult.getChainHistory();
|
||||
Set<String> skipActionsList = new HashSet<>();
|
||||
if (skipActions != null && skipActions.length() > 0) {
|
||||
String finalSkipActions = translateVariables(skipActions);
|
||||
skipActionsList.addAll(TextParseUtil.commaDelimitedStringToSet(finalSkipActions));
|
||||
|
||||
if (chainHistory == null) {
|
||||
return false;
|
||||
} else {
|
||||
// Actions to skip
|
||||
Set<String> skipActionsList = new HashSet<>();
|
||||
if (skipActions != null && skipActions.length() > 0) {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
String finalSkipActions = TextParseUtil.translateVariables(this.skipActions, stack);
|
||||
skipActionsList.addAll(TextParseUtil.commaDelimitedStringToSet(finalSkipActions));
|
||||
}
|
||||
if (!skipActionsList.contains(actionName)) {
|
||||
// Get if key is in the chain history
|
||||
return chainHistory.contains(makeKey(namespace, actionName, methodName));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
if (!skipActionsList.contains(actionName)) {
|
||||
return chainHistory.contains(makeKey(namespace, actionName, methodName));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void addToHistory(String namespace, String actionName, String methodName) {
|
||||
@@ -275,6 +286,10 @@ public class ActionChainResult implements Result {
|
||||
}
|
||||
|
||||
private String makeKey(String namespace, String actionName, String methodName) {
|
||||
return namespace + "/" + actionName + (methodName != null ? "!" + methodName : "");
|
||||
if (null == methodName) {
|
||||
return namespace + "/" + actionName;
|
||||
}
|
||||
|
||||
return namespace + "/" + actionName + "!" + methodName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,52 +58,79 @@ import java.util.Map;
|
||||
*/
|
||||
public class ActionContext implements Serializable {
|
||||
|
||||
private static final ThreadLocal<ActionContext> actionContext = new ThreadLocal<>();
|
||||
static ThreadLocal<ActionContext> actionContext = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Constant for the name of the action being executed.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String ACTION_NAME = "org.apache.struts2.ActionContext.name";
|
||||
@Deprecated
|
||||
public static final String ACTION_NAME = "com.opensymphony.xwork2.ActionContext.name";
|
||||
|
||||
/**
|
||||
* Constant for the {@link com.opensymphony.xwork2.util.ValueStack OGNL value stack}.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String VALUE_STACK = ValueStack.VALUE_STACK;
|
||||
@Deprecated
|
||||
public static final String VALUE_STACK = ValueStack.VALUE_STACK;
|
||||
|
||||
/**
|
||||
* Constant for the action's session.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String SESSION = "org.apache.struts2.ActionContext.session";
|
||||
@Deprecated
|
||||
public static final String SESSION = "com.opensymphony.xwork2.ActionContext.session";
|
||||
|
||||
/**
|
||||
* Constant for the action's application context.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String APPLICATION = "org.apache.struts2.ActionContext.application";
|
||||
@Deprecated
|
||||
public static final String APPLICATION = "com.opensymphony.xwork2.ActionContext.application";
|
||||
|
||||
/**
|
||||
* Constant for the action's parameters.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String PARAMETERS = "org.apache.struts2.ActionContext.parameters";
|
||||
@Deprecated
|
||||
public static final String PARAMETERS = "com.opensymphony.xwork2.ActionContext.parameters";
|
||||
|
||||
/**
|
||||
* Constant for the action's locale.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String LOCALE = "org.apache.struts2.ActionContext.locale";
|
||||
@Deprecated
|
||||
public static final String LOCALE = "com.opensymphony.xwork2.ActionContext.locale";
|
||||
|
||||
/**
|
||||
* Constant for the action's {@link com.opensymphony.xwork2.ActionInvocation invocation} context.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String ACTION_INVOCATION = "org.apache.struts2.ActionContext.actionInvocation";
|
||||
@Deprecated
|
||||
public static final String ACTION_INVOCATION = "com.opensymphony.xwork2.ActionContext.actionInvocation";
|
||||
|
||||
/**
|
||||
* Constant for the map of type conversion errors.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String CONVERSION_ERRORS = "org.apache.struts2.ActionContext.conversionErrors";
|
||||
@Deprecated
|
||||
public static final String CONVERSION_ERRORS = "com.opensymphony.xwork2.ActionContext.conversionErrors";
|
||||
|
||||
/**
|
||||
* Constant for the container
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String CONTAINER = "org.apache.struts2.ActionContext.container";
|
||||
@Deprecated
|
||||
public static final String CONTAINER = "com.opensymphony.xwork2.ActionContext.container";
|
||||
|
||||
private final Map<String, Object> context;
|
||||
|
||||
@@ -118,6 +145,7 @@ public class ActionContext implements Serializable {
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext based on passed in Map
|
||||
* and assign this instance to the current thread
|
||||
*
|
||||
* @param context a map with context values
|
||||
* @return new ActionContext
|
||||
@@ -129,15 +157,6 @@ public class ActionContext implements Serializable {
|
||||
return new ActionContext(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext based on empty Map
|
||||
*
|
||||
* @return new ActionContext
|
||||
*/
|
||||
public static ActionContext of() {
|
||||
return of(new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the provided context with the current thread
|
||||
*
|
||||
@@ -192,7 +211,13 @@ public class ActionContext implements Serializable {
|
||||
* Sets the action invocation (the execution state).
|
||||
*
|
||||
* @param actionInvocation the action execution state.
|
||||
* @deprecated use {@link #withActionInvocation(ActionInvocation)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setActionInvocation(ActionInvocation actionInvocation) {
|
||||
put(ACTION_INVOCATION, actionInvocation);
|
||||
}
|
||||
|
||||
public ActionContext withActionInvocation(ActionInvocation actionInvocation) {
|
||||
put(ACTION_INVOCATION, actionInvocation);
|
||||
return this;
|
||||
@@ -211,7 +236,13 @@ public class ActionContext implements Serializable {
|
||||
* Sets the action's application context.
|
||||
*
|
||||
* @param application the action's application context.
|
||||
* @deprecated use {@link #withApplication(Map)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setApplication(Map<String, Object> application) {
|
||||
put(APPLICATION, application);
|
||||
}
|
||||
|
||||
public ActionContext withApplication(Map<String, Object> application) {
|
||||
put(APPLICATION, application);
|
||||
return this;
|
||||
@@ -240,7 +271,13 @@ public class ActionContext implements Serializable {
|
||||
* Sets conversion errors which occurred when executing the action.
|
||||
*
|
||||
* @param conversionErrors a Map of errors which occurred when executing the action.
|
||||
* @deprecated use {@link #withConversionErrors(Map)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setConversionErrors(Map<String, ConversionData> conversionErrors) {
|
||||
put(CONVERSION_ERRORS, conversionErrors);
|
||||
}
|
||||
|
||||
public ActionContext withConversionErrors(Map<String, ConversionData> conversionErrors) {
|
||||
put(CONVERSION_ERRORS, conversionErrors);
|
||||
return this;
|
||||
@@ -267,7 +304,13 @@ public class ActionContext implements Serializable {
|
||||
* Sets the Locale for the current action.
|
||||
*
|
||||
* @param locale the Locale for the current action.
|
||||
* @deprecated use {@link #withLocale(Locale)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setLocale(Locale locale) {
|
||||
put(LOCALE, locale);
|
||||
}
|
||||
|
||||
public ActionContext withLocale(Locale locale) {
|
||||
put(LOCALE, locale);
|
||||
return this;
|
||||
@@ -284,7 +327,7 @@ public class ActionContext implements Serializable {
|
||||
|
||||
if (locale == null) {
|
||||
locale = Locale.getDefault();
|
||||
withLocale(locale);
|
||||
setLocale(locale);
|
||||
}
|
||||
|
||||
return locale;
|
||||
@@ -293,13 +336,28 @@ public class ActionContext implements Serializable {
|
||||
/**
|
||||
* Sets the name of the current Action in the ActionContext.
|
||||
*
|
||||
* @param actionName the name of the current action.
|
||||
* @param name the name of the current action.
|
||||
* @deprecated use {@link #withActionName(String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setName(String name) {
|
||||
put(ACTION_NAME, name);
|
||||
}
|
||||
|
||||
public ActionContext withActionName(String actionName) {
|
||||
put(ACTION_NAME, actionName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the current Action.
|
||||
*
|
||||
* @return the name of the current action.
|
||||
*/
|
||||
public String getName() {
|
||||
return (String) get(ACTION_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the current Action.
|
||||
*
|
||||
@@ -314,6 +372,10 @@ public class ActionContext implements Serializable {
|
||||
*
|
||||
* @param parameters the parameters for the current action.
|
||||
*/
|
||||
public void setParameters(HttpParameters parameters) {
|
||||
put(PARAMETERS, parameters);
|
||||
}
|
||||
|
||||
public ActionContext withParameters(HttpParameters parameters) {
|
||||
put(PARAMETERS, parameters);
|
||||
return this;
|
||||
@@ -334,7 +396,13 @@ public class ActionContext implements Serializable {
|
||||
* Sets a map of action session values.
|
||||
*
|
||||
* @param session the session values.
|
||||
* @deprecated use {@link #withSession(Map)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSession(Map<String, Object> session) {
|
||||
put(SESSION, session);
|
||||
}
|
||||
|
||||
public ActionContext withSession(Map<String, Object> session) {
|
||||
put(SESSION, session);
|
||||
return this;
|
||||
@@ -353,8 +421,14 @@ public class ActionContext implements Serializable {
|
||||
/**
|
||||
* Sets the OGNL value stack.
|
||||
*
|
||||
* @param valueStack the OGNL value stack.
|
||||
* @param stack the OGNL value stack.
|
||||
* @deprecated Use {@link #withValueStack(ValueStack)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setValueStack(ValueStack stack) {
|
||||
put(VALUE_STACK, stack);
|
||||
}
|
||||
|
||||
public ActionContext withValueStack(ValueStack valueStack) {
|
||||
put(VALUE_STACK, valueStack);
|
||||
return this;
|
||||
@@ -372,8 +446,14 @@ public class ActionContext implements Serializable {
|
||||
/**
|
||||
* Gets the container for this request
|
||||
*
|
||||
* @param container The container
|
||||
* @param cont The container
|
||||
* @deprecated use {@link #withContainer(Container)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setContainer(Container cont) {
|
||||
put(CONTAINER, cont);
|
||||
}
|
||||
|
||||
public ActionContext withContainer(Container container) {
|
||||
put(CONTAINER, container);
|
||||
return this;
|
||||
|
||||
@@ -1,86 +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 com.opensymphony.xwork2;
|
||||
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.ConfigurationManager;
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.inject.Context;
|
||||
import com.opensymphony.xwork2.inject.Factory;
|
||||
import com.opensymphony.xwork2.inject.Scope;
|
||||
import com.opensymphony.xwork2.test.StubConfigurationProvider;
|
||||
import com.opensymphony.xwork2.util.XWorkTestCaseHelper;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
public abstract class XWorkJUnit4TestCase {
|
||||
|
||||
protected ConfigurationManager configurationManager;
|
||||
protected Configuration configuration;
|
||||
protected Container container;
|
||||
protected ActionProxyFactory actionProxyFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
configurationManager = XWorkTestCaseHelper.setUp();
|
||||
configuration = configurationManager.getConfiguration();
|
||||
container = configuration.getContainer();
|
||||
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
XWorkTestCaseHelper.tearDown(configurationManager);
|
||||
}
|
||||
|
||||
protected void loadConfigurationProviders(ConfigurationProvider... providers) {
|
||||
configurationManager = XWorkTestCaseHelper.loadConfigurationProviders(configurationManager, providers);
|
||||
configuration = configurationManager.getConfiguration();
|
||||
container = configuration.getContainer();
|
||||
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
|
||||
}
|
||||
|
||||
protected void loadButAdd(final Class<?> type, final Object impl) {
|
||||
loadButAdd(type, Container.DEFAULT_NAME, impl);
|
||||
}
|
||||
|
||||
protected void loadButAdd(final Class<?> type, final String name, final Object impl) {
|
||||
loadConfigurationProviders(new StubConfigurationProvider() {
|
||||
@Override
|
||||
public void register(ContainerBuilder builder,
|
||||
LocatableProperties props) throws ConfigurationException {
|
||||
builder.factory(type, name, new Factory() {
|
||||
public Object create(Context context) throws Exception {
|
||||
return impl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class type() {
|
||||
return impl.getClass();
|
||||
}
|
||||
}, Scope.SINGLETON);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,17 +22,14 @@ import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.ConfigurationManager;
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.inject.Context;
|
||||
import com.opensymphony.xwork2.inject.Factory;
|
||||
import com.opensymphony.xwork2.inject.Scope;
|
||||
import com.opensymphony.xwork2.inject.*;
|
||||
import com.opensymphony.xwork2.test.StubConfigurationProvider;
|
||||
import com.opensymphony.xwork2.util.XWorkTestCaseHelper;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -64,6 +61,10 @@ public abstract class XWorkTestCase extends TestCase {
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
XWorkTestCaseHelper.tearDown(configurationManager);
|
||||
configurationManager = null;
|
||||
configuration = null;
|
||||
container = null;
|
||||
actionProxyFactory = null;
|
||||
}
|
||||
|
||||
protected void loadConfigurationProviders(ConfigurationProvider... providers) {
|
||||
@@ -100,7 +101,7 @@ public abstract class XWorkTestCase extends TestCase {
|
||||
}
|
||||
|
||||
protected Map<String, Object> createContextWithLocale(Locale locale) {
|
||||
return ActionContext.of()
|
||||
return ActionContext.of(new HashMap<>())
|
||||
.withLocale(locale)
|
||||
.getContextMap();
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@ import com.opensymphony.xwork2.config.impl.DefaultConfiguration;
|
||||
import com.opensymphony.xwork2.config.providers.StrutsDefaultConfigurationProvider;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.apache.struts2.StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
|
||||
/**
|
||||
@@ -42,11 +42,12 @@ public class ConfigurationManager {
|
||||
|
||||
protected static final Logger LOG = LogManager.getLogger(ConfigurationManager.class);
|
||||
protected Configuration configuration;
|
||||
private List<ContainerProvider> containerProviders = new ArrayList<>();
|
||||
private List<PackageProvider> packageProviders = new ArrayList<>();
|
||||
protected Lock providerLock = new ReentrantLock();
|
||||
private List<ContainerProvider> containerProviders = new CopyOnWriteArrayList<>();
|
||||
private List<PackageProvider> packageProviders = new CopyOnWriteArrayList<>();
|
||||
protected String defaultFrameworkBeanName;
|
||||
private boolean providersChanged = true;
|
||||
private boolean alwaysReloadConfigs = false;
|
||||
private boolean providersChanged = false;
|
||||
private boolean reloadConfigs = true; // for the first time
|
||||
|
||||
public ConfigurationManager(String name) {
|
||||
this.defaultFrameworkBeanName = name;
|
||||
@@ -58,69 +59,54 @@ public class ConfigurationManager {
|
||||
* @see com.opensymphony.xwork2.config.impl.DefaultConfiguration
|
||||
*/
|
||||
public synchronized Configuration getConfiguration() {
|
||||
if (wasConfigInitialised()) {
|
||||
if (configuration == null) {
|
||||
setConfiguration(createConfiguration(defaultFrameworkBeanName));
|
||||
try {
|
||||
configuration.reloadContainer(getContainerProviders());
|
||||
} catch (ConfigurationException e) {
|
||||
setConfiguration(null);
|
||||
throw new ConfigurationException("Unable to load configuration.", e);
|
||||
}
|
||||
} else {
|
||||
conditionalReload();
|
||||
}
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether configuration was initialised (was null)
|
||||
*/
|
||||
private boolean wasConfigInitialised() {
|
||||
if (configuration == null) {
|
||||
initialiseConfiguration();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void initialiseConfiguration() {
|
||||
if (containerProviders.isEmpty()) {
|
||||
addDefaultContainerProviders();
|
||||
}
|
||||
configuration = createConfiguration(defaultFrameworkBeanName);
|
||||
try {
|
||||
reload();
|
||||
} catch (ConfigurationException e) {
|
||||
configuration.destroy();
|
||||
configuration = null;
|
||||
providersChanged = true;
|
||||
throw new ConfigurationException("Unable to load configuration.", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addDefaultContainerProviders() {
|
||||
containerProviders.add(new StrutsDefaultConfigurationProvider());
|
||||
}
|
||||
|
||||
protected Configuration createConfiguration(String beanName) {
|
||||
return new DefaultConfiguration(beanName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all container providers and destroy managing Configuration instance
|
||||
*/
|
||||
public synchronized void destroyConfiguration() {
|
||||
clearContainerProviders();
|
||||
if (configuration != null) {
|
||||
configuration.destroy();
|
||||
configuration = null;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setConfiguration(Configuration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current list of ConfigurationProviders.
|
||||
* <p>
|
||||
* Get the current list of ConfigurationProviders. If no custom ConfigurationProviders have been added, this method
|
||||
* will return a list containing only a default ConfigurationProvider, {@link StrutsDefaultConfigurationProvider}.
|
||||
* If a custom ConfigurationProvider has been added, then the StrutsDefaultConfigurationProvider must be added by hand.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* TODO: The lazy instantiation of XmlConfigurationProvider should be refactored to be elsewhere. The behavior described above seems unintuitive.
|
||||
* </p>
|
||||
*
|
||||
* @return the list of registered ConfigurationProvider objects
|
||||
* @see ConfigurationProvider
|
||||
*/
|
||||
public synchronized List<ContainerProvider> getContainerProviders() {
|
||||
return new ArrayList<>(containerProviders);
|
||||
public List<ContainerProvider> getContainerProviders() {
|
||||
providerLock.lock();
|
||||
try {
|
||||
if (containerProviders.size() == 0) {
|
||||
containerProviders.add(new StrutsDefaultConfigurationProvider());
|
||||
}
|
||||
|
||||
return containerProviders;
|
||||
} finally {
|
||||
providerLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,9 +114,14 @@ public class ConfigurationManager {
|
||||
*
|
||||
* @param containerProviders list of {@link ConfigurationProvider} to be set
|
||||
*/
|
||||
public synchronized void setContainerProviders(List<ContainerProvider> containerProviders) {
|
||||
this.containerProviders = new ArrayList<>(containerProviders);
|
||||
providersChanged = true;
|
||||
public void setContainerProviders(List<ContainerProvider> containerProviders) {
|
||||
providerLock.lock();
|
||||
try {
|
||||
this.containerProviders = new CopyOnWriteArrayList<>(containerProviders);
|
||||
providersChanged = true;
|
||||
} finally {
|
||||
providerLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,32 +130,22 @@ public class ConfigurationManager {
|
||||
*
|
||||
* @param provider the ConfigurationProvider to register
|
||||
*/
|
||||
public synchronized void addContainerProvider(ContainerProvider provider) {
|
||||
public void addContainerProvider(ContainerProvider provider) {
|
||||
if (!containerProviders.contains(provider)) {
|
||||
containerProviders.add(provider);
|
||||
providersChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void removeContainerProvider(ContainerProvider provider) {
|
||||
if (containerProviders.remove(provider)) {
|
||||
destroyContainerProvider(provider);
|
||||
providersChanged = true;
|
||||
public void clearContainerProviders() {
|
||||
for (ContainerProvider containerProvider : containerProviders) {
|
||||
clearContainerProvider(containerProvider);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void clearContainerProviders() {
|
||||
destroyContainerProviders();
|
||||
containerProviders.clear();
|
||||
providersChanged = true;
|
||||
}
|
||||
|
||||
private void destroyContainerProviders() {
|
||||
LOG.debug("Destroying all providers.");
|
||||
containerProviders.forEach(this::destroyContainerProvider);
|
||||
}
|
||||
|
||||
private void destroyContainerProvider(ContainerProvider containerProvider) {
|
||||
private void clearContainerProvider(ContainerProvider containerProvider) {
|
||||
try {
|
||||
containerProvider.destroy();
|
||||
} catch (Exception e) {
|
||||
@@ -172,61 +153,80 @@ public class ConfigurationManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy its managing Configuration instance
|
||||
*/
|
||||
public synchronized void destroyConfiguration() {
|
||||
clearContainerProviders(); // let's destroy the ConfigurationProvider first
|
||||
containerProviders = new CopyOnWriteArrayList<>();
|
||||
if (configuration != null)
|
||||
configuration.destroy(); // let's destroy it first, before nulling it.
|
||||
configuration = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reloads the Configuration files if the configuration files indicate that they need to be reloaded.
|
||||
*/
|
||||
public synchronized void conditionalReload() {
|
||||
if (alwaysReloadConfigs || providersChanged) {
|
||||
if (reloadConfigs || providersChanged) {
|
||||
LOG.debug("Checking ConfigurationProviders for reload.");
|
||||
if (needReloadContainerProviders() || needReloadPackageProviders()) {
|
||||
destroyAndReload();
|
||||
List<ContainerProvider> providers = getContainerProviders();
|
||||
boolean reload = needReloadContainerProviders(providers);
|
||||
if (!reload) {
|
||||
reload = needReloadPackageProviders();
|
||||
}
|
||||
if (reload) {
|
||||
reloadProviders(providers);
|
||||
}
|
||||
updateReloadConfigsFlag();
|
||||
providersChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAlwaysReloadFlag() {
|
||||
boolean newValue = Boolean.parseBoolean(configuration.getContainer()
|
||||
.getInstance(String.class, STRUTS_CONFIGURATION_XML_RELOAD));
|
||||
if (alwaysReloadConfigs != newValue) {
|
||||
LOG.debug(
|
||||
"Updating [{}], current value is [{}], new value [{}]",
|
||||
STRUTS_CONFIGURATION_XML_RELOAD,
|
||||
String.valueOf(alwaysReloadConfigs),
|
||||
String.valueOf(newValue));
|
||||
alwaysReloadConfigs = newValue;
|
||||
private void updateReloadConfigsFlag() {
|
||||
reloadConfigs = Boolean.parseBoolean(configuration.getContainer().getInstance(String.class, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD));
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Updating [{}], current value is [{}], new value [{}]",
|
||||
StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, String.valueOf(reloadConfigs), String.valueOf(reloadConfigs));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean needReloadPackageProviders() {
|
||||
Optional<PackageProvider> provider = packageProviders.stream().filter(PackageProvider::needsReload).findAny();
|
||||
if (provider.isPresent()) {
|
||||
LOG.info("Detected package provider [{}] needs to be reloaded.", provider.get());
|
||||
return true;
|
||||
if (packageProviders != null) {
|
||||
for (PackageProvider provider : packageProviders) {
|
||||
if (provider.needsReload()) {
|
||||
LOG.info("Detected package provider [{}] needs to be reloaded. Reloading all providers.", provider);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean needReloadContainerProviders() {
|
||||
Optional<ContainerProvider> provider = containerProviders.stream().filter(ContainerProvider::needsReload).findAny();
|
||||
if (provider.isPresent()) {
|
||||
LOG.info("Detected container provider [{}] needs to be reloaded.", provider.get());
|
||||
return true;
|
||||
private boolean needReloadContainerProviders(List<ContainerProvider> providers) {
|
||||
for (ContainerProvider provider : providers) {
|
||||
if (provider.needsReload()) {
|
||||
LOG.info("Detected container provider [{}] needs to be reloaded. Reloading all providers.", provider);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public synchronized void destroyAndReload() {
|
||||
destroyContainerProviders();
|
||||
reload();
|
||||
private void reloadProviders(List<ContainerProvider> providers) {
|
||||
for (ContainerProvider containerProvider : containerProviders) {
|
||||
try {
|
||||
containerProvider.destroy();
|
||||
} catch (Exception e) {
|
||||
LOG.warn("error while destroying configuration provider [{}]", containerProvider, e);
|
||||
}
|
||||
}
|
||||
packageProviders = this.configuration.reloadContainer(providers);
|
||||
}
|
||||
|
||||
public synchronized void reload() {
|
||||
if (wasConfigInitialised()) {
|
||||
LOG.debug("Reloading all providers.");
|
||||
packageProviders = configuration.reloadContainer(containerProviders);
|
||||
providersChanged = false;
|
||||
updateAlwaysReloadFlag();
|
||||
}
|
||||
packageProviders = getConfiguration().reloadContainer(getContainerProviders());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
|
||||
/**
|
||||
* Provides beans and constants/properties for the Container
|
||||
*
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public interface ContainerProvider {
|
||||
@@ -32,29 +32,29 @@ public interface ContainerProvider {
|
||||
/**
|
||||
* Called before removed from the configuration manager
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
public void destroy();
|
||||
|
||||
/**
|
||||
* Initializes with the configuration
|
||||
* @param configuration The configuration
|
||||
* @throws ConfigurationException If anything goes wrong
|
||||
*/
|
||||
void init(Configuration configuration) throws ConfigurationException;
|
||||
|
||||
public void init(Configuration configuration) throws ConfigurationException;
|
||||
|
||||
/**
|
||||
* Tells whether the ContainerProvider should reload its configuration
|
||||
*
|
||||
* @return <tt>true</tt>, whether the ContainerProvider should reload its configuration, <tt>false</tt>otherwise.
|
||||
*/
|
||||
boolean needsReload();
|
||||
|
||||
public boolean needsReload();
|
||||
|
||||
/**
|
||||
* Registers beans and properties for the Container
|
||||
*
|
||||
*
|
||||
* @param builder The builder to register beans with
|
||||
* @param props The properties to register constants with
|
||||
* @throws ConfigurationException If anything goes wrong
|
||||
*/
|
||||
void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException;
|
||||
|
||||
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException;
|
||||
|
||||
}
|
||||
|
||||
@@ -18,110 +18,39 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.config.impl;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.DefaultLocaleProviderFactory;
|
||||
import com.opensymphony.xwork2.DefaultTextProvider;
|
||||
import com.opensymphony.xwork2.FileManager;
|
||||
import com.opensymphony.xwork2.FileManagerFactory;
|
||||
import com.opensymphony.xwork2.LocaleProviderFactory;
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.StrutsTextProviderFactory;
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.TextProviderFactory;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.ContainerProvider;
|
||||
import com.opensymphony.xwork2.config.FileManagerFactoryProvider;
|
||||
import com.opensymphony.xwork2.config.FileManagerProvider;
|
||||
import com.opensymphony.xwork2.config.PackageProvider;
|
||||
import com.opensymphony.xwork2.config.RuntimeConfiguration;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorMapping;
|
||||
import com.opensymphony.xwork2.config.entities.PackageConfig;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.config.entities.ResultTypeConfig;
|
||||
import com.opensymphony.xwork2.config.entities.UnknownHandlerConfig;
|
||||
import com.opensymphony.xwork2.*;
|
||||
import com.opensymphony.xwork2.config.*;
|
||||
import com.opensymphony.xwork2.config.entities.*;
|
||||
import com.opensymphony.xwork2.config.providers.EnvsValueSubstitutor;
|
||||
import com.opensymphony.xwork2.config.providers.InterceptorBuilder;
|
||||
import com.opensymphony.xwork2.config.providers.ValueSubstitutor;
|
||||
import com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor;
|
||||
import com.opensymphony.xwork2.conversion.ConversionFileProcessor;
|
||||
import com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor;
|
||||
import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
|
||||
import com.opensymphony.xwork2.conversion.TypeConverter;
|
||||
import com.opensymphony.xwork2.conversion.TypeConverterCreator;
|
||||
import com.opensymphony.xwork2.conversion.TypeConverterHolder;
|
||||
import com.opensymphony.xwork2.conversion.impl.ArrayConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.CollectionConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.DateConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.DefaultConversionAnnotationProcessor;
|
||||
import com.opensymphony.xwork2.conversion.impl.DefaultConversionFileProcessor;
|
||||
import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
|
||||
import com.opensymphony.xwork2.conversion.impl.NumberConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.StringConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
import com.opensymphony.xwork2.factory.ActionFactory;
|
||||
import com.opensymphony.xwork2.factory.ConverterFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultActionFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultInterceptorFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultResultFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultUnknownHandlerFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultValidatorFactory;
|
||||
import com.opensymphony.xwork2.factory.InterceptorFactory;
|
||||
import com.opensymphony.xwork2.factory.ResultFactory;
|
||||
import com.opensymphony.xwork2.factory.StrutsConverterFactory;
|
||||
import com.opensymphony.xwork2.factory.UnknownHandlerFactory;
|
||||
import com.opensymphony.xwork2.factory.ValidatorFactory;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.inject.Context;
|
||||
import com.opensymphony.xwork2.inject.Factory;
|
||||
import com.opensymphony.xwork2.inject.Scope;
|
||||
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.OgnlCacheFactory;
|
||||
import com.opensymphony.xwork2.ognl.OgnlReflectionProvider;
|
||||
import com.opensymphony.xwork2.ognl.OgnlUtil;
|
||||
import com.opensymphony.xwork2.ognl.OgnlValueStackFactory;
|
||||
import com.opensymphony.xwork2.ognl.SecurityMemberAccess;
|
||||
import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.RootAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor;
|
||||
import com.opensymphony.xwork2.util.OgnlTextParser;
|
||||
import com.opensymphony.xwork2.util.PatternMatcher;
|
||||
import com.opensymphony.xwork2.util.StrutsLocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.util.TextParser;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import com.opensymphony.xwork2.util.*;
|
||||
import com.opensymphony.xwork2.util.fs.DefaultFileManager;
|
||||
import com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
import ognl.MethodAccessor;
|
||||
import ognl.PropertyAccessor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.conversion.StrutsConversionPropertiesProcessor;
|
||||
import org.apache.struts2.conversion.StrutsTypeConverterCreator;
|
||||
import org.apache.struts2.conversion.StrutsTypeConverterHolder;
|
||||
import org.apache.struts2.ognl.OgnlGuard;
|
||||
import org.apache.struts2.ognl.ProviderAllowlist;
|
||||
import org.apache.struts2.ognl.StrutsOgnlGuard;
|
||||
import org.apache.struts2.conversion.StrutsTypeConverterCreator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
@@ -132,21 +61,6 @@ import java.util.TreeSet;
|
||||
*/
|
||||
public class DefaultConfiguration implements Configuration {
|
||||
|
||||
public static final Map<String, Object> BOOTSTRAP_CONSTANTS;
|
||||
|
||||
static {
|
||||
Map<String, Object> constants = new HashMap<>();
|
||||
constants.put(StrutsConstants.STRUTS_DEVMODE, Boolean.FALSE);
|
||||
constants.put(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, Boolean.FALSE);
|
||||
constants.put(StrutsConstants.STRUTS_MATCHER_APPEND_NAMED_PARAMETERS, Boolean.TRUE);
|
||||
constants.put(StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_TYPE, OgnlCacheFactory.CacheType.BASIC);
|
||||
constants.put(StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE, 10000);
|
||||
constants.put(StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_TYPE, OgnlCacheFactory.CacheType.BASIC);
|
||||
constants.put(StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE, 10000);
|
||||
constants.put(StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION, Boolean.FALSE);
|
||||
BOOTSTRAP_CONSTANTS = Collections.unmodifiableMap(constants);
|
||||
}
|
||||
|
||||
protected static final Logger LOG = LogManager.getLogger(DefaultConfiguration.class);
|
||||
|
||||
// Programmatic Action Configurations
|
||||
@@ -325,8 +239,12 @@ public class DefaultConfiguration implements Configuration {
|
||||
}
|
||||
|
||||
protected ActionContext setContext(Container cont) {
|
||||
ValueStack vs = cont.getInstance(ValueStackFactory.class).createValueStack();
|
||||
return ActionContext.of(vs.getContext()).bind();
|
||||
ActionContext context = ActionContext.getContext();
|
||||
if (context == null) {
|
||||
ValueStack vs = cont.getInstance(ValueStackFactory.class).createValueStack();
|
||||
context = ActionContext.of(vs.getContext()).bind();
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
protected Container createBootstrapContainer(List<ContainerProvider> providers) {
|
||||
@@ -341,73 +259,63 @@ public class DefaultConfiguration implements Configuration {
|
||||
fmFactoryRegistered = true;
|
||||
}
|
||||
}
|
||||
builder.factory(ObjectFactory.class, Scope.SINGLETON);
|
||||
builder.factory(ActionFactory.class, DefaultActionFactory.class, Scope.SINGLETON);
|
||||
builder.factory(ResultFactory.class, DefaultResultFactory.class, Scope.SINGLETON);
|
||||
builder.factory(InterceptorFactory.class, DefaultInterceptorFactory.class, Scope.SINGLETON);
|
||||
builder.factory(com.opensymphony.xwork2.factory.ValidatorFactory.class, com.opensymphony.xwork2.factory.DefaultValidatorFactory.class, Scope.SINGLETON);
|
||||
builder.factory(ConverterFactory.class, StrutsConverterFactory.class, Scope.SINGLETON);
|
||||
builder.factory(UnknownHandlerFactory.class, DefaultUnknownHandlerFactory.class, Scope.SINGLETON);
|
||||
|
||||
bootstrapFactories(builder);
|
||||
bootstrapTypeConverters(builder);
|
||||
|
||||
builder.factory(FileManager.class, "system", DefaultFileManager.class, Scope.SINGLETON);
|
||||
if (!fmFactoryRegistered) {
|
||||
builder.factory(FileManagerFactory.class, DefaultFileManagerFactory.class, Scope.SINGLETON);
|
||||
}
|
||||
builder.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON);
|
||||
builder.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON);
|
||||
|
||||
for (Map.Entry<String, Object> entry : BOOTSTRAP_CONSTANTS.entrySet()) {
|
||||
builder.constant(entry.getKey(), String.valueOf(entry.getValue()));
|
||||
}
|
||||
builder.factory(XWorkConverter.class, Scope.SINGLETON);
|
||||
builder.factory(ConversionPropertiesProcessor.class, StrutsConversionPropertiesProcessor.class, Scope.SINGLETON);
|
||||
builder.factory(ConversionFileProcessor.class, DefaultConversionFileProcessor.class, Scope.SINGLETON);
|
||||
builder.factory(ConversionAnnotationProcessor.class, DefaultConversionAnnotationProcessor.class, Scope.SINGLETON);
|
||||
builder.factory(TypeConverterCreator.class, StrutsTypeConverterCreator.class, Scope.SINGLETON);
|
||||
builder.factory(TypeConverterHolder.class, StrutsTypeConverterHolder.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(XWorkBasicConverter.class, Scope.SINGLETON);
|
||||
builder.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_COLLECTION, CollectionConverter.class, Scope.SINGLETON);
|
||||
builder.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_ARRAY, ArrayConverter.class, Scope.SINGLETON);
|
||||
builder.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_DATE, DateConverter.class, Scope.SINGLETON);
|
||||
builder.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_NUMBER, NumberConverter.class, Scope.SINGLETON);
|
||||
builder.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_STRING, StringConverter.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(LocalizedTextProvider.class, StrutsLocalizedTextProvider.class, Scope.SINGLETON);
|
||||
builder.factory(TextProviderFactory.class, StrutsTextProviderFactory.class, Scope.SINGLETON);
|
||||
builder.factory(LocaleProviderFactory.class, DefaultLocaleProviderFactory.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(TextParser.class, OgnlTextParser.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON);
|
||||
builder.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON);
|
||||
builder.factory(ExpressionCacheFactory.class, DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON);
|
||||
builder.factory(BeanInfoCacheFactory.class, DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON);
|
||||
builder.factory(OgnlUtil.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON);
|
||||
|
||||
builder.constant(StrutsConstants.STRUTS_DEVMODE, "false");
|
||||
builder.constant(StrutsConstants.STRUTS_OGNL_LOG_MISSING_PROPERTIES, "false");
|
||||
builder.constant(StrutsConstants.STRUTS_OGNL_ENABLE_EVAL_EXPRESSION, "false");
|
||||
builder.constant(StrutsConstants.STRUTS_OGNL_ENABLE_EXPRESSION_CACHE, "true");
|
||||
builder.constant(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, "false");
|
||||
builder.constant(StrutsConstants.STRUTS_I18N_RELOAD, "false");
|
||||
|
||||
builder.constant(StrutsConstants.STRUTS_MATCHER_APPEND_NAMED_PARAMETERS, "true");
|
||||
|
||||
return builder.create(true);
|
||||
}
|
||||
|
||||
public static ContainerBuilder bootstrapFactories(ContainerBuilder builder) {
|
||||
return builder
|
||||
// TODO: SpringObjectFactoryTest fails when these are SINGLETON
|
||||
.factory(ObjectFactory.class, Scope.PROTOTYPE)
|
||||
.factory(ActionFactory.class, DefaultActionFactory.class, Scope.PROTOTYPE)
|
||||
.factory(ResultFactory.class, DefaultResultFactory.class, Scope.PROTOTYPE)
|
||||
.factory(InterceptorFactory.class, DefaultInterceptorFactory.class, Scope.PROTOTYPE)
|
||||
.factory(ValidatorFactory.class, DefaultValidatorFactory.class, Scope.PROTOTYPE)
|
||||
.factory(ConverterFactory.class, StrutsConverterFactory.class, Scope.PROTOTYPE)
|
||||
.factory(UnknownHandlerFactory.class, DefaultUnknownHandlerFactory.class, Scope.PROTOTYPE)
|
||||
|
||||
.factory(FileManager.class, "system", DefaultFileManager.class, Scope.SINGLETON)
|
||||
.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON)
|
||||
.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON)
|
||||
|
||||
.factory(XWorkConverter.class, Scope.SINGLETON)
|
||||
.factory(XWorkBasicConverter.class, Scope.SINGLETON)
|
||||
.factory(ConversionPropertiesProcessor.class, StrutsConversionPropertiesProcessor.class, Scope.SINGLETON)
|
||||
.factory(ConversionFileProcessor.class, DefaultConversionFileProcessor.class, Scope.SINGLETON)
|
||||
.factory(ConversionAnnotationProcessor.class, DefaultConversionAnnotationProcessor.class, Scope.SINGLETON)
|
||||
.factory(TypeConverterCreator.class, StrutsTypeConverterCreator.class, Scope.SINGLETON)
|
||||
.factory(TypeConverterHolder.class, StrutsTypeConverterHolder.class, Scope.SINGLETON)
|
||||
|
||||
.factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON)
|
||||
.factory(LocalizedTextProvider.class, StrutsLocalizedTextProvider.class, Scope.SINGLETON)
|
||||
.factory(TextProviderFactory.class, StrutsTextProviderFactory.class, Scope.SINGLETON)
|
||||
.factory(LocaleProviderFactory.class, DefaultLocaleProviderFactory.class, Scope.SINGLETON)
|
||||
.factory(TextParser.class, OgnlTextParser.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON)
|
||||
.factory(RootAccessor.class, CompoundRootAccessor.class, Scope.SINGLETON)
|
||||
.factory(MethodAccessor.class, XWorkMethodAccessor.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ExpressionCacheFactory.class, DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON)
|
||||
.factory(BeanInfoCacheFactory.class, DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON)
|
||||
.factory(OgnlUtil.class, Scope.SINGLETON)
|
||||
.factory(SecurityMemberAccess.class, Scope.PROTOTYPE)
|
||||
.factory(OgnlGuard.class, StrutsOgnlGuard.class, Scope.SINGLETON)
|
||||
.factory(ProviderAllowlist.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON);
|
||||
}
|
||||
|
||||
public static ContainerBuilder bootstrapTypeConverters(ContainerBuilder builder) {
|
||||
return builder
|
||||
.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_COLLECTION, CollectionConverter.class, Scope.SINGLETON)
|
||||
.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_ARRAY, ArrayConverter.class, Scope.SINGLETON)
|
||||
.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_DATE, DateConverter.class, Scope.SINGLETON)
|
||||
.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_NUMBER, NumberConverter.class, Scope.SINGLETON)
|
||||
.factory(TypeConverter.class, StrutsConstants.STRUTS_CONVERTER_STRING, StringConverter.class, Scope.SINGLETON);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This builds the internal runtime configuration used by Xwork for finding and configuring Actions from the
|
||||
|
||||
@@ -18,11 +18,7 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.config.impl;
|
||||
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.ContainerProvider;
|
||||
import com.opensymphony.xwork2.config.PackageProvider;
|
||||
import com.opensymphony.xwork2.config.RuntimeConfiguration;
|
||||
import com.opensymphony.xwork2.config.*;
|
||||
import com.opensymphony.xwork2.config.entities.PackageConfig;
|
||||
import com.opensymphony.xwork2.config.entities.UnknownHandlerConfig;
|
||||
import com.opensymphony.xwork2.config.providers.StrutsDefaultConfigurationProvider;
|
||||
@@ -30,12 +26,9 @@ import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.inject.Scope;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
@@ -58,9 +51,10 @@ public class MockConfiguration implements Configuration {
|
||||
builder.factory(Configuration.class, MockConfiguration.class, Scope.SINGLETON);
|
||||
LocatableProperties props = new LocatableProperties();
|
||||
new StrutsDefaultConfigurationProvider().register(builder, props);
|
||||
for (Map.Entry<String, Object> entry : DefaultConfiguration.BOOTSTRAP_CONSTANTS.entrySet()) {
|
||||
builder.constant(entry.getKey(), String.valueOf(entry.getValue()));
|
||||
}
|
||||
builder.constant(StrutsConstants.STRUTS_DEVMODE, "false");
|
||||
builder.constant(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, "true");
|
||||
builder.constant(StrutsConstants.STRUTS_OGNL_ENABLE_EXPRESSION_CACHE, "true");
|
||||
builder.constant(StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION, "false");
|
||||
container = builder.create(true);
|
||||
}
|
||||
|
||||
|
||||
+135
-45
@@ -20,24 +20,61 @@ package com.opensymphony.xwork2.config.providers;
|
||||
|
||||
import com.opensymphony.xwork2.ActionProxyFactory;
|
||||
import com.opensymphony.xwork2.DefaultActionProxyFactory;
|
||||
import com.opensymphony.xwork2.DefaultLocaleProviderFactory;
|
||||
import com.opensymphony.xwork2.DefaultTextProvider;
|
||||
import com.opensymphony.xwork2.DefaultUnknownHandlerManager;
|
||||
import com.opensymphony.xwork2.FileManager;
|
||||
import com.opensymphony.xwork2.FileManagerFactory;
|
||||
import com.opensymphony.xwork2.LocaleProviderFactory;
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.StrutsTextProviderFactory;
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.TextProviderFactory;
|
||||
import com.opensymphony.xwork2.UnknownHandlerManager;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
import com.opensymphony.xwork2.config.impl.DefaultConfiguration;
|
||||
import com.opensymphony.xwork2.conversion.ConversionAnnotationProcessor;
|
||||
import com.opensymphony.xwork2.conversion.ConversionFileProcessor;
|
||||
import com.opensymphony.xwork2.conversion.ConversionPropertiesProcessor;
|
||||
import com.opensymphony.xwork2.conversion.NullHandler;
|
||||
import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
|
||||
import com.opensymphony.xwork2.conversion.TypeConverterCreator;
|
||||
import com.opensymphony.xwork2.conversion.TypeConverterHolder;
|
||||
import com.opensymphony.xwork2.conversion.impl.ArrayConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.CollectionConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.DateConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.DefaultConversionAnnotationProcessor;
|
||||
import com.opensymphony.xwork2.conversion.impl.DefaultConversionFileProcessor;
|
||||
import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
|
||||
import com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler;
|
||||
import com.opensymphony.xwork2.conversion.impl.NumberConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.StringConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
import com.opensymphony.xwork2.factory.ActionFactory;
|
||||
import com.opensymphony.xwork2.factory.ConverterFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultActionFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultInterceptorFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultResultFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultUnknownHandlerFactory;
|
||||
import com.opensymphony.xwork2.factory.InterceptorFactory;
|
||||
import com.opensymphony.xwork2.factory.ResultFactory;
|
||||
import com.opensymphony.xwork2.factory.StrutsConverterFactory;
|
||||
import com.opensymphony.xwork2.factory.UnknownHandlerFactory;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.inject.Scope;
|
||||
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.ObjectProxy;
|
||||
import com.opensymphony.xwork2.ognl.OgnlReflectionContextFactory;
|
||||
import com.opensymphony.xwork2.ognl.OgnlReflectionProvider;
|
||||
import com.opensymphony.xwork2.ognl.OgnlUtil;
|
||||
import com.opensymphony.xwork2.ognl.OgnlValueStackFactory;
|
||||
import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.HttpParametersPropertyAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.ObjectAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.ObjectProxyPropertyAccessor;
|
||||
@@ -47,17 +84,25 @@ import com.opensymphony.xwork2.ognl.accessor.XWorkEnumerationAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.XWorkIteratorPropertyAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor;
|
||||
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.DefaultExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.OgnlTextParser;
|
||||
import com.opensymphony.xwork2.util.PatternMatcher;
|
||||
import com.opensymphony.xwork2.util.StrutsLocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.util.TextParser;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import com.opensymphony.xwork2.util.WildcardHelper;
|
||||
import com.opensymphony.xwork2.util.fs.DefaultFileManager;
|
||||
import com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextFactory;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
import com.opensymphony.xwork2.validator.ActionValidatorManager;
|
||||
import com.opensymphony.xwork2.validator.AnnotationActionValidatorManager;
|
||||
import com.opensymphony.xwork2.validator.DefaultActionValidatorManager;
|
||||
@@ -65,11 +110,14 @@ import com.opensymphony.xwork2.validator.DefaultValidatorFactory;
|
||||
import com.opensymphony.xwork2.validator.DefaultValidatorFileParser;
|
||||
import com.opensymphony.xwork2.validator.ValidatorFactory;
|
||||
import com.opensymphony.xwork2.validator.ValidatorFileParser;
|
||||
import ognl.MethodAccessor;
|
||||
import ognl.PropertyAccessor;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.conversion.StrutsConversionPropertiesProcessor;
|
||||
import org.apache.struts2.conversion.StrutsTypeConverterCreator;
|
||||
import org.apache.struts2.conversion.StrutsTypeConverterHolder;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.interceptor.exec.ExecutorProvider;
|
||||
import org.apache.struts2.interceptor.exec.StrutsExecutorProvider;
|
||||
import org.apache.struts2.url.QueryStringBuilder;
|
||||
import org.apache.struts2.url.QueryStringParser;
|
||||
import org.apache.struts2.url.StrutsQueryStringBuilder;
|
||||
@@ -109,60 +157,102 @@ public class StrutsDefaultConfigurationProvider implements ConfigurationProvider
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
|
||||
public void register(ContainerBuilder builder, LocatableProperties props)
|
||||
throws ConfigurationException {
|
||||
|
||||
DefaultConfiguration.bootstrapFactories(builder)
|
||||
.factory(FileManagerFactory.class, DefaultFileManagerFactory.class, Scope.SINGLETON)
|
||||
builder
|
||||
.factory(ObjectFactory.class)
|
||||
.factory(ActionFactory.class, DefaultActionFactory.class)
|
||||
.factory(ResultFactory.class, DefaultResultFactory.class)
|
||||
.factory(InterceptorFactory.class, DefaultInterceptorFactory.class)
|
||||
.factory(com.opensymphony.xwork2.factory.ValidatorFactory.class, com.opensymphony.xwork2.factory.DefaultValidatorFactory.class)
|
||||
.factory(ConverterFactory.class, StrutsConverterFactory.class)
|
||||
.factory(UnknownHandlerFactory.class, DefaultUnknownHandlerFactory.class)
|
||||
|
||||
.factory(ActionProxyFactory.class, DefaultActionProxyFactory.class, Scope.SINGLETON)
|
||||
.factory(ActionProxyFactory.class, DefaultActionProxyFactory.class, Scope.SINGLETON)
|
||||
.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ValidatorFactory.class, DefaultValidatorFactory.class, Scope.SINGLETON)
|
||||
.factory(ValidatorFileParser.class, DefaultValidatorFileParser.class, Scope.SINGLETON)
|
||||
.factory(PatternMatcher.class, WildcardHelper.class, Scope.SINGLETON)
|
||||
.factory(XWorkConverter.class, Scope.SINGLETON)
|
||||
.factory(XWorkBasicConverter.class, Scope.SINGLETON)
|
||||
.factory(ConversionPropertiesProcessor.class, StrutsConversionPropertiesProcessor.class, Scope.SINGLETON)
|
||||
.factory(ConversionFileProcessor.class, DefaultConversionFileProcessor.class, Scope.SINGLETON)
|
||||
.factory(ConversionAnnotationProcessor.class, DefaultConversionAnnotationProcessor.class, Scope.SINGLETON)
|
||||
.factory(TypeConverterCreator.class, StrutsTypeConverterCreator.class, Scope.SINGLETON)
|
||||
.factory(TypeConverterHolder.class, StrutsTypeConverterHolder.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ReflectionContextFactory.class, OgnlReflectionContextFactory.class, Scope.SINGLETON)
|
||||
.factory(FileManager.class, "system", DefaultFileManager.class, Scope.SINGLETON)
|
||||
.factory(FileManagerFactory.class, DefaultFileManagerFactory.class, Scope.SINGLETON)
|
||||
.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON)
|
||||
.factory(ValidatorFactory.class, DefaultValidatorFactory.class, Scope.SINGLETON)
|
||||
.factory(ValidatorFileParser.class, DefaultValidatorFileParser.class, Scope.SINGLETON)
|
||||
.factory(PatternMatcher.class, WildcardHelper.class, Scope.SINGLETON)
|
||||
.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON)
|
||||
.factory(ReflectionContextFactory.class, OgnlReflectionContextFactory.class, Scope.SINGLETON)
|
||||
|
||||
.factory(PropertyAccessor.class, Object.class.getName(), ObjectAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Iterator.class.getName(), XWorkIteratorPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Enumeration.class.getName(), XWorkEnumerationAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Object.class.getName(), ObjectAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Iterator.class.getName(), XWorkIteratorPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Enumeration.class.getName(), XWorkEnumerationAccessor.class, Scope.SINGLETON)
|
||||
|
||||
.factory(UnknownHandlerManager.class, DefaultUnknownHandlerManager.class, Scope.SINGLETON)
|
||||
.factory(UnknownHandlerManager.class, DefaultUnknownHandlerManager.class, Scope.SINGLETON)
|
||||
|
||||
// silly workarounds for ognl since there is no way to flush its caches
|
||||
.factory(PropertyAccessor.class, List.class.getName(), XWorkListPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, ArrayList.class.getName(), XWorkListPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, HashSet.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Set.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, HashMap.class.getName(), XWorkMapPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Map.class.getName(), XWorkMapPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Collection.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, ObjectProxy.class.getName(), ObjectProxyPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, HttpParameters.class.getName(), HttpParametersPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Parameter.class.getName(), ParameterPropertyAccessor.class, Scope.SINGLETON)
|
||||
// silly workarounds for ognl since there is no way to flush its caches
|
||||
.factory(PropertyAccessor.class, List.class.getName(), XWorkListPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, ArrayList.class.getName(), XWorkListPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, HashSet.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Set.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, HashMap.class.getName(), XWorkMapPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Map.class.getName(), XWorkMapPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Collection.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, ObjectProxy.class.getName(), ObjectProxyPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, HttpParameters.class.getName(), HttpParametersPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Parameter.class.getName(), ParameterPropertyAccessor.class, Scope.SINGLETON)
|
||||
|
||||
.factory(NullHandler.class, Object.class.getName(), InstantiatingNullHandler.class, Scope.SINGLETON)
|
||||
.factory(ActionValidatorManager.class, AnnotationActionValidatorManager.class, Scope.SINGLETON)
|
||||
.factory(ActionValidatorManager.class, "no-annotations", DefaultActionValidatorManager.class, Scope.SINGLETON)
|
||||
.factory(MethodAccessor.class, Object.class.getName(), XWorkMethodAccessor.class, Scope.SINGLETON)
|
||||
.factory(MethodAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON)
|
||||
|
||||
.factory(CollectionConverter.class, Scope.SINGLETON)
|
||||
.factory(ArrayConverter.class, Scope.SINGLETON)
|
||||
.factory(DateConverter.class, Scope.SINGLETON)
|
||||
.factory(NumberConverter.class, Scope.SINGLETON)
|
||||
.factory(StringConverter.class, Scope.SINGLETON)
|
||||
.factory(TextParser.class, OgnlTextParser.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ExcludedPatternsChecker.class, DefaultExcludedPatternsChecker.class, Scope.PROTOTYPE)
|
||||
.factory(AcceptedPatternsChecker.class, DefaultAcceptedPatternsChecker.class, Scope.PROTOTYPE)
|
||||
.factory(NotExcludedAcceptedPatternsChecker.class, DefaultNotExcludedAcceptedPatternsChecker.class, Scope.SINGLETON)
|
||||
.factory(NullHandler.class, Object.class.getName(), InstantiatingNullHandler.class, Scope.SINGLETON)
|
||||
.factory(ActionValidatorManager.class, AnnotationActionValidatorManager.class, Scope.SINGLETON)
|
||||
.factory(ActionValidatorManager.class, "no-annotations", DefaultActionValidatorManager.class, Scope.SINGLETON)
|
||||
|
||||
.factory(QueryStringBuilder.class, StrutsQueryStringBuilder.class, Scope.SINGLETON)
|
||||
.factory(QueryStringParser.class, StrutsQueryStringParser.class, Scope.SINGLETON)
|
||||
.factory(UrlEncoder.class, StrutsUrlEncoder.class, Scope.SINGLETON)
|
||||
.factory(UrlDecoder.class, StrutsUrlDecoder.class, Scope.SINGLETON)
|
||||
.factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON)
|
||||
.factory(LocalizedTextProvider.class, StrutsLocalizedTextProvider.class, Scope.SINGLETON)
|
||||
.factory(TextProviderFactory.class, StrutsTextProviderFactory.class, Scope.SINGLETON)
|
||||
.factory(LocaleProviderFactory.class, DefaultLocaleProviderFactory.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ExecutorProvider.class, StrutsExecutorProvider.class, Scope.SINGLETON);
|
||||
.factory(ExpressionCacheFactory.class, DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON)
|
||||
.factory(BeanInfoCacheFactory.class, DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON)
|
||||
.factory(OgnlUtil.class, Scope.SINGLETON)
|
||||
.factory(CollectionConverter.class, Scope.SINGLETON)
|
||||
.factory(ArrayConverter.class, Scope.SINGLETON)
|
||||
.factory(DateConverter.class, Scope.SINGLETON)
|
||||
.factory(NumberConverter.class, Scope.SINGLETON)
|
||||
.factory(StringConverter.class, Scope.SINGLETON)
|
||||
|
||||
for (Map.Entry<String, Object> entry : DefaultConfiguration.BOOTSTRAP_CONSTANTS.entrySet()) {
|
||||
props.setProperty(entry.getKey(), String.valueOf(entry.getValue()));
|
||||
}
|
||||
.factory(ExcludedPatternsChecker.class, DefaultExcludedPatternsChecker.class, Scope.PROTOTYPE)
|
||||
.factory(AcceptedPatternsChecker.class, DefaultAcceptedPatternsChecker.class, Scope.PROTOTYPE)
|
||||
.factory(NotExcludedAcceptedPatternsChecker.class, DefaultNotExcludedAcceptedPatternsChecker.class
|
||||
, Scope.SINGLETON)
|
||||
|
||||
.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON)
|
||||
|
||||
.factory(QueryStringBuilder.class, StrutsQueryStringBuilder.class, Scope.SINGLETON)
|
||||
.factory(QueryStringParser.class, StrutsQueryStringParser.class, Scope.SINGLETON)
|
||||
.factory(UrlEncoder.class, StrutsUrlEncoder.class, Scope.SINGLETON)
|
||||
.factory(UrlDecoder.class, StrutsUrlDecoder.class, Scope.SINGLETON)
|
||||
;
|
||||
|
||||
props.setProperty(StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION, Boolean.FALSE.toString());
|
||||
props.setProperty(StrutsConstants.STRUTS_I18N_RELOAD, Boolean.FALSE.toString());
|
||||
props.setProperty(StrutsConstants.STRUTS_DEVMODE, Boolean.FALSE.toString());
|
||||
props.setProperty(StrutsConstants.STRUTS_OGNL_LOG_MISSING_PROPERTIES, Boolean.FALSE.toString());
|
||||
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_FIELD_ACCESS, Boolean.TRUE.toString());
|
||||
props.setProperty(StrutsConstants.STRUTS_MATCHER_APPEND_NAMED_PARAMETERS, Boolean.TRUE.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1067
-133
File diff suppressed because it is too large
Load Diff
-1024
File diff suppressed because it is too large
Load Diff
@@ -201,25 +201,11 @@ public enum Scope {
|
||||
|
||||
<T> Callable<? extends T> toCallable(final InternalContext context,
|
||||
final InternalFactory<? extends T> factory) {
|
||||
return (Callable<T>) () -> InitializableFactory.wrapIfNeeded(factory).create(context);
|
||||
}
|
||||
|
||||
public static Scope fromString(String scopeStr) {
|
||||
switch (scopeStr) {
|
||||
case "prototype":
|
||||
return Scope.PROTOTYPE;
|
||||
case "request":
|
||||
return Scope.REQUEST;
|
||||
case "session":
|
||||
return Scope.SESSION;
|
||||
case "thread":
|
||||
return Scope.THREAD;
|
||||
case "wizard":
|
||||
return Scope.WIZARD;
|
||||
case "singleton":
|
||||
default:
|
||||
return Scope.SINGLETON;
|
||||
}
|
||||
return new Callable<T>() {
|
||||
public T call() throws Exception {
|
||||
return InitializableFactory.wrapIfNeeded(factory).create(context);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+16
-16
@@ -52,9 +52,9 @@ import java.util.Map;
|
||||
* <ul>
|
||||
*
|
||||
* <li>logEnabled (optional) - Should exceptions also be logged? (boolean true|false)</li>
|
||||
*
|
||||
*
|
||||
* <li>logLevel (optional) - what log level should we use (<code>trace, debug, info, warn, error, fatal</code>)? - defaut is <code>debug</code></li>
|
||||
*
|
||||
*
|
||||
* <li>logCategory (optional) - If provided we would use this category (eg. <code>com.mycompany.app</code>).
|
||||
* Default is to use <code>com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor</code>.</li>
|
||||
*
|
||||
@@ -102,7 +102,7 @@ import java.util.Map;
|
||||
* </xwork>
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* This second example will also log the exceptions using our own category
|
||||
* <code>com.mycompany.app.unhandled</code> at WARN level.
|
||||
@@ -117,8 +117,8 @@ import java.util.Map;
|
||||
* <interceptor-ref name="exception">
|
||||
* <param name="logEnabled">true</param>
|
||||
* <param name="logCategory">com.mycompany.app.unhandled</param>
|
||||
* <param name="logLevel">WARN</param>
|
||||
* </interceptor-ref>
|
||||
* <param name="logLevel">WARN</param>
|
||||
* </interceptor-ref>
|
||||
* <interceptor-ref name="i18n"/>
|
||||
* <interceptor-ref name="staticParams"/>
|
||||
* <interceptor-ref name="params"/>
|
||||
@@ -129,7 +129,7 @@ import java.util.Map;
|
||||
* </interceptors>
|
||||
*
|
||||
* <default-interceptor-ref name="exceptionmappingStack"/>
|
||||
*
|
||||
*
|
||||
* <global-results>
|
||||
* <result name="unhandledException">/unhandled-exception.jsp</result>
|
||||
* </global-results>
|
||||
@@ -137,12 +137,12 @@ import java.util.Map;
|
||||
* <global-exception-mappings>
|
||||
* <exception-mapping exception="java.lang.Exception" result="unhandledException"/>
|
||||
* </global-exception-mappings>
|
||||
*
|
||||
*
|
||||
* <action name="exceptionDemo" class="org.apache.struts2.showcase.exceptionmapping.ExceptionMappingAction">
|
||||
* <exception-mapping exception="org.apache.struts2.showcase.exceptionmapping.ExceptionMappingException"
|
||||
* result="damm"/>
|
||||
* <result name="input">index.jsp</result>
|
||||
* <result name="success">success.jsp</result>
|
||||
* <result name="success">success.jsp</result>
|
||||
* <result name="damm">damm.jsp</result>
|
||||
* </action>
|
||||
*
|
||||
@@ -151,18 +151,18 @@ import java.util.Map;
|
||||
* <!-- END SNIPPET: example2 -->
|
||||
* </pre>
|
||||
*
|
||||
* @author Matthew E. Porter (matthew dot porter at metissian dot com)
|
||||
* @author Matthew E. Porter (matthew dot porter at metissian dot com)
|
||||
* @author Claus Ibsen
|
||||
*/
|
||||
public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ExceptionMappingInterceptor.class);
|
||||
|
||||
protected Logger categoryLogger;
|
||||
protected boolean logEnabled = false;
|
||||
protected String logCategory;
|
||||
protected String logLevel;
|
||||
|
||||
|
||||
|
||||
public boolean isLogEnabled() {
|
||||
return logEnabled;
|
||||
@@ -204,7 +204,7 @@ public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
Map<String, String> mappingParams = mappingConfig.getParams();
|
||||
// create a mutable HashMap since some interceptors will remove parameters, and parameterMap is immutable
|
||||
HttpParameters parameters = HttpParameters.create(mappingParams).build();
|
||||
invocation.getInvocationContext().withParameters(parameters);
|
||||
invocation.getInvocationContext().setParameters(parameters);
|
||||
result = mappingConfig.getResult();
|
||||
publishException(invocation, new ExceptionHolder(e));
|
||||
} else {
|
||||
@@ -217,7 +217,7 @@ public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
|
||||
/**
|
||||
* Handles the logging of the exception.
|
||||
*
|
||||
*
|
||||
* @param e the exception to log.
|
||||
*/
|
||||
protected void handleLogging(Exception e) {
|
||||
@@ -231,10 +231,10 @@ public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
doLog(LOG, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs the actual logging.
|
||||
*
|
||||
*
|
||||
* @param logger the provided logger to use.
|
||||
* @param e the exception to log.
|
||||
*/
|
||||
@@ -243,7 +243,7 @@ public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
logger.debug(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ("trace".equalsIgnoreCase(logLevel)) {
|
||||
logger.trace(e.getMessage(), e);
|
||||
} else if ("debug".equalsIgnoreCase(logLevel)) {
|
||||
|
||||
@@ -30,8 +30,7 @@ package com.opensymphony.xwork2.interceptor;
|
||||
* parameters cannot be set by malicious users.
|
||||
* </p>
|
||||
*
|
||||
* @deprecated since Struts 6.2.0, use {@link org.apache.struts2.action.NoParameters}
|
||||
* @author Dick Zetterberg (dick@transitor.se)
|
||||
*/
|
||||
@Deprecated
|
||||
public interface NoParameters extends org.apache.struts2.action.NoParameters {
|
||||
public interface NoParameters {
|
||||
}
|
||||
|
||||
+15
-17
@@ -26,6 +26,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
@@ -33,33 +34,33 @@ import java.util.TreeMap;
|
||||
* <!-- START SNIPPET: description -->
|
||||
*
|
||||
* The Parameter Filter Interceptor blocks parameters from getting
|
||||
* to the rest of the stack or your action. You can use multiple
|
||||
* to the rest of the stack or your action. You can use multiple
|
||||
* parameter filter interceptors for a given action, so, for example,
|
||||
* you could use one in your default stack that filtered parameters
|
||||
* you wanted blocked from every action and those you wanted blocked
|
||||
* you wanted blocked from every action and those you wanted blocked
|
||||
* from an individual action you could add an additional interceptor
|
||||
* for each action.
|
||||
*
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
*
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
*
|
||||
* <ul>
|
||||
* <li>allowed - a comma delimited list of parameter prefixes
|
||||
* that are allowed to pass to the action</li>
|
||||
* <li>blocked - a comma delimited list of parameter prefixes
|
||||
* <li>blocked - a comma delimited list of parameter prefixes
|
||||
* that are not allowed to pass to the action</li>
|
||||
* <li>defaultBlock - boolean (default to false) whether by
|
||||
* default a given parameter is blocked. If true, then a parameter
|
||||
* must have a prefix in the allowed list in order to be able
|
||||
* must have a prefix in the allowed list in order to be able
|
||||
* to pass to the action
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* <p>The way parameters are filtered for the least configuration is that
|
||||
* if a string is in the allowed or blocked lists, then any parameter
|
||||
* that is a member of the object represented by the parameter is allowed
|
||||
* or blocked respectively.</p>
|
||||
*
|
||||
*
|
||||
* <p>For example, if the parameters are:
|
||||
* <ul>
|
||||
* <li>blocked: person,person.address.createDate,personDao</li>
|
||||
@@ -68,16 +69,16 @@ import java.util.TreeMap;
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* The parameters person.name, person.phoneNum etc would be blocked
|
||||
* The parameters person.name, person.phoneNum etc would be blocked
|
||||
* because 'person' is in the blocked list. However, person.address.street
|
||||
* and person.address.city would be allowed because person.address is
|
||||
* in the allowed list (the longer string determines permissions).</p>
|
||||
* in the allowed list (the longer string determines permissions).</p>
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
*
|
||||
* <!-- START SNIPPET: extending -->
|
||||
* There are no known extension points to this interceptor.
|
||||
* <!-- END SNIPPET: extending -->
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
* <interceptors>
|
||||
@@ -85,7 +86,7 @@ import java.util.TreeMap;
|
||||
* <interceptor name="parameterFilter" class="com.opensymphony.xwork2.interceptor.ParameterFilterInterceptor"/>
|
||||
* ...
|
||||
* </interceptors>
|
||||
*
|
||||
*
|
||||
* <action ....>
|
||||
* ...
|
||||
* <interceptor-ref name="parameterFilter">
|
||||
@@ -95,12 +96,9 @@ import java.util.TreeMap;
|
||||
* </action>
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @author Gabe
|
||||
*
|
||||
* @deprecated since 6.4.0, use {@link org.apache.struts2.interceptor.parameter.ParametersInterceptor}.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ParameterFilterInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ParameterFilterInterceptor.class);
|
||||
@@ -135,7 +133,7 @@ public class ParameterFilterInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
}
|
||||
|
||||
invocation.getInvocationContext().withParameters(parameters);
|
||||
invocation.getInvocationContext().setParameters(parameters);
|
||||
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
@@ -19,8 +19,19 @@
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, use {@link org.apache.struts2.action.ParameterNameAware}.
|
||||
* This interface is implemented by actions that want to declare acceptable parameters. Works in conjunction with {@link
|
||||
* ParametersInterceptor}. For example, actions may want to create a white list of parameters they will accept or a
|
||||
* blacklist of parameters they will reject to prevent clients from setting other unexpected (and possibly dangerous)
|
||||
* parameters.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ParameterNameAware extends org.apache.struts2.action.ParameterNameAware {
|
||||
public interface ParameterNameAware {
|
||||
|
||||
/**
|
||||
* Tests if the the action will accept the parameter with the given name.
|
||||
*
|
||||
* @param parameterName the parameter name
|
||||
* @return <tt>true</tt> if accepted, <tt>false</tt> otherwise
|
||||
*/
|
||||
boolean acceptableParameterName(String parameterName);
|
||||
|
||||
}
|
||||
|
||||
+85
-67
@@ -23,102 +23,120 @@ import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.action.NoParameters;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
* This is a simple XWork interceptor that allows parameters (matching
|
||||
* one of the paramNames attribute csv value) to be
|
||||
* one of the paramNames attribute csv value) to be
|
||||
* removed from the parameter map if they match a certain value
|
||||
* (matching one of the paramValues attribute csv value), before they
|
||||
* are set on the action. A typical usage would be to want a dropdown/select
|
||||
* to map onto a boolean value on an action. The select had the options
|
||||
* none, yes and no with values -1, true and false. The true and false would
|
||||
* map across correctly. However the -1 would be set to false.
|
||||
* This was not desired as one might needed the value on the action to stay null.
|
||||
* This interceptor fixes this by preventing the parameter from ever reaching
|
||||
* (matching one of the paramValues attribute csv value), before they
|
||||
* are set on the action. A typical usage would be to want a dropdown/select
|
||||
* to map onto a boolean value on an action. The select had the options
|
||||
* none, yes and no with values -1, true and false. The true and false would
|
||||
* map across correctly. However the -1 would be set to false.
|
||||
* This was not desired as one might needed the value on the action to stay null.
|
||||
* This interceptor fixes this by preventing the parameter from ever reaching
|
||||
* the action.
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
*
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
* <ul>
|
||||
* <li>paramNames - A comma separated value (csv) indicating the parameter name
|
||||
* whose param value should be considered that if they match any of the
|
||||
* comma separated value (csv) from paramValues attribute, shall be
|
||||
* removed from the parameter map such that they will not be applied
|
||||
* to the action</li>
|
||||
* <li>paramValues - A comma separated value (csv) indicating the parameter value that if
|
||||
* matched shall have its parameter be removed from the parameter map
|
||||
* such that they will not be applied to the action</li>
|
||||
* <li>paramNames - A comma separated value (csv) indicating the parameter name
|
||||
* whose param value should be considered that if they match any of the
|
||||
* comma separated value (csv) from paramValues attribute, shall be
|
||||
* removed from the parameter map such that they will not be applied
|
||||
* to the action</li>
|
||||
* <li>paramValues - A comma separated value (csv) indicating the parameter value that if
|
||||
* matched shall have its parameter be removed from the parameter map
|
||||
* such that they will not be applied to the action</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
*
|
||||
*
|
||||
* <!-- START SNIPPET: extending -->
|
||||
* No intended extension point
|
||||
*
|
||||
* <!-- END SNIPPET: extending -->
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
*
|
||||
* <action name="sample" class="org.martingilday.Sample">
|
||||
* <interceptor-ref name="paramRemover">
|
||||
* <param name="paramNames">aParam,anotherParam</param>
|
||||
* <param name="paramValues">--,-1</param>
|
||||
* <param name="paramNames">aParam,anotherParam</param>
|
||||
* <param name="paramValues">--,-1</param>
|
||||
* </interceptor-ref>
|
||||
* <interceptor-ref name="defaultStack" />
|
||||
* ...
|
||||
* </action>
|
||||
*
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @author martin.gilday
|
||||
*/
|
||||
public class ParameterRemoverInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ParameterRemoverInterceptor.class);
|
||||
private static final Logger LOG = LogManager.getLogger(ParameterRemoverInterceptor.class);
|
||||
|
||||
private Set<String> paramNames = Collections.emptySet();
|
||||
private Set<String> paramValues = Collections.emptySet();
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
/**
|
||||
* Decide if the parameter should be removed from the parameter map based on
|
||||
* <code>paramNames</code> and <code>paramValues</code>.
|
||||
*
|
||||
* @see com.opensymphony.xwork2.interceptor.AbstractInterceptor
|
||||
*/
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
if (!(invocation.getAction() instanceof NoParameters)
|
||||
&& (null != this.paramNames)) {
|
||||
ActionContext ac = invocation.getInvocationContext();
|
||||
HttpParameters parameters = ac.getParameters();
|
||||
private Set<String> paramNames = Collections.emptySet();
|
||||
private Set<String> paramValues = Collections.emptySet();
|
||||
|
||||
if (parameters != null) {
|
||||
|
||||
/**
|
||||
* Decide if the parameter should be removed from the parameter map based on
|
||||
* <code>paramNames</code> and <code>paramValues</code>.
|
||||
*
|
||||
* @see com.opensymphony.xwork2.interceptor.AbstractInterceptor
|
||||
*/
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
if (!(invocation.getAction() instanceof NoParameters)
|
||||
&& (null != this.paramNames)) {
|
||||
ActionContext ac = invocation.getInvocationContext();
|
||||
HttpParameters parameters = ac.getParameters();
|
||||
|
||||
if (parameters != null) {
|
||||
for (String removeName : paramNames) {
|
||||
try {
|
||||
Parameter parameter = parameters.get(removeName);
|
||||
if (parameter.isDefined() && this.paramValues.contains(parameter.getValue())) {
|
||||
parameters.remove(removeName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to convert parameter to string", e);
|
||||
}
|
||||
try {
|
||||
Parameter parameter = parameters.get(removeName);
|
||||
if (parameter.isDefined() && this.paramValues.contains(parameter.getValue())) {
|
||||
parameters.remove(removeName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to convert parameter to string", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows <code>paramNames</code> attribute to be set as comma-separated-values (csv).
|
||||
*
|
||||
* @param paramNames the paramNames to set
|
||||
*/
|
||||
public void setParamNames(String paramNames) {
|
||||
this.paramNames = TextParseUtil.commaDelimitedStringToSet(paramNames);
|
||||
}
|
||||
/**
|
||||
* Allows <code>paramNames</code> attribute to be set as comma-separated-values (csv).
|
||||
*
|
||||
* @param paramNames the paramNames to set
|
||||
*/
|
||||
public void setParamNames(String paramNames) {
|
||||
this.paramNames = TextParseUtil.commaDelimitedStringToSet(paramNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows <code>paramValues</code> attribute to be set as a comma-separated-values (csv).
|
||||
*
|
||||
* @param paramValues the paramValues to set
|
||||
*/
|
||||
public void setParamValues(String paramValues) {
|
||||
this.paramValues = TextParseUtil.commaDelimitedStringToSet(paramValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows <code>paramValues</code> attribute to be set as a comma-separated-values (csv).
|
||||
*
|
||||
* @param paramValues the paramValues to set
|
||||
*/
|
||||
public void setParamValues(String paramValues) {
|
||||
this.paramValues = TextParseUtil.commaDelimitedStringToSet(paramValues);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,19 @@
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, use {@link org.apache.struts2.action.ParameterValueAware}.
|
||||
* This interface is implemented by actions that want to declare acceptable parameter value. Works in conjunction with {@link
|
||||
* ParametersInterceptor}. For example, actions may want to create a white list of parameter values they will accept or a
|
||||
* blacklist of parameter values they will reject to prevent clients from setting other unexpected (and possibly dangerous)
|
||||
* parameter values.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ParameterValueAware extends org.apache.struts2.action.ParameterValueAware {
|
||||
public interface ParameterValueAware {
|
||||
|
||||
/**
|
||||
* Tests if the the action will accept the parameter with the given value.
|
||||
*
|
||||
* @param parameterValue the parameter value
|
||||
* @return <tt>true</tt> if accepted, <tt>false</tt> otherwise
|
||||
*/
|
||||
boolean acceptableParameterValue(String parameterValue);
|
||||
|
||||
}
|
||||
|
||||
@@ -18,8 +18,537 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.ClearableValueStack;
|
||||
import com.opensymphony.xwork2.util.MemberAccessValueStack;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, use {@link org.apache.struts2.interceptor.parameter.ParametersInterceptor}.
|
||||
* This interceptor sets all parameters on the value stack.
|
||||
*/
|
||||
public class ParametersInterceptor extends org.apache.struts2.interceptor.parameter.ParametersInterceptor {
|
||||
public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ParametersInterceptor.class);
|
||||
|
||||
protected static final int PARAM_NAME_MAX_LENGTH = 100;
|
||||
|
||||
private static final Pattern DMI_IGNORED_PATTERN = Pattern.compile("^(action|method):.*", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private int paramNameMaxLength = PARAM_NAME_MAX_LENGTH;
|
||||
private boolean devMode = false;
|
||||
private boolean dmiEnabled = false;
|
||||
|
||||
protected boolean ordered = false;
|
||||
|
||||
private ValueStackFactory valueStackFactory;
|
||||
private ExcludedPatternsChecker excludedPatterns;
|
||||
private AcceptedPatternsChecker acceptedPatterns;
|
||||
private Set<Pattern> excludedValuePatterns = null;
|
||||
private Set<Pattern> acceptedValuePatterns = null;
|
||||
|
||||
@Inject
|
||||
public void setValueStackFactory(ValueStackFactory valueStackFactory) {
|
||||
this.valueStackFactory = valueStackFactory;
|
||||
}
|
||||
|
||||
@Inject(StrutsConstants.STRUTS_DEVMODE)
|
||||
public void setDevMode(String mode) {
|
||||
this.devMode = BooleanUtils.toBoolean(mode);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setExcludedPatterns(ExcludedPatternsChecker excludedPatterns) {
|
||||
this.excludedPatterns = excludedPatterns;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setAcceptedPatterns(AcceptedPatternsChecker acceptedPatterns) {
|
||||
this.acceptedPatterns = acceptedPatterns;
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION, required = false)
|
||||
protected void setDynamicMethodInvocation(String dmiEnabled) {
|
||||
this.dmiEnabled = Boolean.parseBoolean(dmiEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the param name exceeds the configured maximum length it will not be
|
||||
* accepted.
|
||||
*
|
||||
* @param paramNameMaxLength Maximum length of param names
|
||||
*/
|
||||
public void setParamNameMaxLength(int paramNameMaxLength) {
|
||||
this.paramNameMaxLength = paramNameMaxLength;
|
||||
}
|
||||
|
||||
static private int countOGNLCharacters(String s) {
|
||||
int count = 0;
|
||||
for (int i = s.length() - 1; i >= 0; i--) {
|
||||
char c = s.charAt(i);
|
||||
if (c == '.' || c == '[') count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares based on number of '.' and '[' characters (fewer is higher)
|
||||
*/
|
||||
static final Comparator<String> rbCollator = (s1, s2) -> {
|
||||
int l1 = countOGNLCharacters(s1);
|
||||
int l2 = countOGNLCharacters(s2);
|
||||
return l1 < l2 ? -1 : (l2 < l1 ? 1 : s1.compareTo(s2));
|
||||
};
|
||||
|
||||
@Override
|
||||
public String doIntercept(ActionInvocation invocation) throws Exception {
|
||||
Object action = invocation.getAction();
|
||||
if (!(action instanceof NoParameters)) {
|
||||
ActionContext ac = invocation.getInvocationContext();
|
||||
HttpParameters parameters = retrieveParameters(ac);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Setting params {}", getParameterLogMap(parameters));
|
||||
}
|
||||
|
||||
if (parameters != null) {
|
||||
Map<String, Object> contextMap = ac.getContextMap();
|
||||
try {
|
||||
ReflectionContextState.setCreatingNullObjects(contextMap, true);
|
||||
ReflectionContextState.setDenyMethodExecution(contextMap, true);
|
||||
ReflectionContextState.setReportingConversionErrors(contextMap, true);
|
||||
|
||||
ValueStack stack = ac.getValueStack();
|
||||
setParameters(action, stack, parameters);
|
||||
} finally {
|
||||
ReflectionContextState.setCreatingNullObjects(contextMap, false);
|
||||
ReflectionContextState.setDenyMethodExecution(contextMap, false);
|
||||
ReflectionContextState.setReportingConversionErrors(contextMap, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parameter map to apply from wherever appropriate
|
||||
*
|
||||
* @param ac The action context
|
||||
* @return The parameter map to apply
|
||||
*/
|
||||
protected HttpParameters retrieveParameters(ActionContext ac) {
|
||||
return ac.getParameters();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the parameters into context's ParameterMap
|
||||
*
|
||||
* @param ac The action context
|
||||
* @param newParams The parameter map to apply
|
||||
* <p>
|
||||
* In this class this is a no-op, since the parameters were fetched from the same location.
|
||||
* In subclasses both retrieveParameters() and addParametersToContext() should be overridden.
|
||||
* </p>
|
||||
*/
|
||||
protected void addParametersToContext(ActionContext ac, Map<String, ?> newParams) {
|
||||
}
|
||||
|
||||
protected void setParameters(final Object action, ValueStack stack, HttpParameters parameters) {
|
||||
HttpParameters params;
|
||||
Map<String, Parameter> acceptableParameters;
|
||||
if (ordered) {
|
||||
params = HttpParameters.create().withComparator(getOrderedComparator()).withParent(parameters).build();
|
||||
acceptableParameters = new TreeMap<>(getOrderedComparator());
|
||||
} else {
|
||||
params = HttpParameters.create().withParent(parameters).build();
|
||||
acceptableParameters = new TreeMap<>();
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Parameter> entry : params.entrySet()) {
|
||||
String parameterName = entry.getKey();
|
||||
boolean isAcceptableParameter = isAcceptableParameter(parameterName, action);
|
||||
isAcceptableParameter &= isAcceptableParameterValue(entry.getValue(), action);
|
||||
|
||||
if (isAcceptableParameter) {
|
||||
acceptableParameters.put(parameterName, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
ValueStack newStack = valueStackFactory.createValueStack(stack);
|
||||
boolean clearableStack = newStack instanceof ClearableValueStack;
|
||||
if (clearableStack) {
|
||||
//if the stack's context can be cleared, do that to prevent OGNL
|
||||
//from having access to objects in the stack, see XW-641
|
||||
((ClearableValueStack) newStack).clearContextValues();
|
||||
Map<String, Object> context = newStack.getContext();
|
||||
ReflectionContextState.setCreatingNullObjects(context, true);
|
||||
ReflectionContextState.setDenyMethodExecution(context, true);
|
||||
ReflectionContextState.setReportingConversionErrors(context, true);
|
||||
|
||||
//keep locale from original context
|
||||
newStack.getActionContext().withLocale(stack.getActionContext().getLocale()).withValueStack(stack);
|
||||
}
|
||||
|
||||
boolean memberAccessStack = newStack instanceof MemberAccessValueStack;
|
||||
if (memberAccessStack) {
|
||||
//block or allow access to properties
|
||||
//see WW-2761 for more details
|
||||
MemberAccessValueStack accessValueStack = (MemberAccessValueStack) newStack;
|
||||
accessValueStack.setAcceptProperties(acceptedPatterns.getAcceptedPatterns());
|
||||
accessValueStack.setExcludeProperties(excludedPatterns.getExcludedPatterns());
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Parameter> entry : acceptableParameters.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
Parameter value = entry.getValue();
|
||||
try {
|
||||
newStack.setParameter(name, value.getObject());
|
||||
} catch (RuntimeException e) {
|
||||
if (devMode) {
|
||||
notifyDeveloperParameterException(action, name, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clearableStack) {
|
||||
stack.getActionContext().withConversionErrors(newStack.getActionContext().getConversionErrors());
|
||||
}
|
||||
|
||||
addParametersToContext(ActionContext.getContext(), acceptableParameters);
|
||||
}
|
||||
|
||||
protected void notifyDeveloperParameterException(Object action, String property, String message) {
|
||||
String developerNotification = "Unexpected Exception caught setting '" + property + "' on '" + action.getClass() + ": " + message;
|
||||
if (action instanceof TextProvider) {
|
||||
TextProvider tp = (TextProvider) action;
|
||||
developerNotification = tp.getText("devmode.notification",
|
||||
"Developer Notification:\n{0}",
|
||||
new String[]{developerNotification}
|
||||
);
|
||||
}
|
||||
|
||||
LOG.error(developerNotification);
|
||||
|
||||
if (action instanceof ValidationAware) {
|
||||
// see https://issues.apache.org/jira/browse/WW-4066
|
||||
Collection<String> messages = ((ValidationAware) action).getActionMessages();
|
||||
messages.add(message);
|
||||
((ValidationAware) action).setActionMessages(messages);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if name of parameter can be accepted or thrown away
|
||||
*
|
||||
* @param name parameter name
|
||||
* @param action current action
|
||||
* @return true if parameter is accepted
|
||||
*/
|
||||
protected boolean isAcceptableParameter(String name, Object action) {
|
||||
ParameterNameAware parameterNameAware = (action instanceof ParameterNameAware) ? (ParameterNameAware) action : null;
|
||||
return acceptableName(name) && (parameterNameAware == null || parameterNameAware.acceptableParameterName(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if parameter value can be accepted or thrown away
|
||||
*
|
||||
* @param param the parameter
|
||||
* @param action current action
|
||||
* @return true if parameter is accepted
|
||||
*/
|
||||
protected boolean isAcceptableParameterValue(Parameter param, Object action) {
|
||||
ParameterValueAware parameterValueAware = (action instanceof ParameterValueAware) ? (ParameterValueAware) action : null;
|
||||
boolean acceptableParamValue = (parameterValueAware == null || parameterValueAware.acceptableParameterValue(param.getValue()));
|
||||
if (hasParamValuesToExclude() || hasParamValuesToAccept()) {
|
||||
// Additional validations to process
|
||||
acceptableParamValue &= acceptableValue(param.getName(), param.getValue());
|
||||
}
|
||||
return acceptableParamValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance of the comparator to use for the ordered sorting. Override this
|
||||
* method to customize the ordering of the parameters as they are set to the
|
||||
* action.
|
||||
*
|
||||
* @return A comparator to sort the parameters
|
||||
*/
|
||||
protected Comparator<String> getOrderedComparator() {
|
||||
return rbCollator;
|
||||
}
|
||||
|
||||
protected String getParameterLogMap(HttpParameters parameters) {
|
||||
if (parameters == null) {
|
||||
return "NONE";
|
||||
}
|
||||
|
||||
StringBuilder logEntry = new StringBuilder();
|
||||
for (Map.Entry<String, Parameter> entry : parameters.entrySet()) {
|
||||
logEntry.append(entry.getKey());
|
||||
logEntry.append(" => ");
|
||||
logEntry.append(entry.getValue().getValue());
|
||||
logEntry.append(" ");
|
||||
}
|
||||
|
||||
return logEntry.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the name passed is:
|
||||
* * Within the max length of a parameter name
|
||||
* * Is not excluded
|
||||
* * Is accepted
|
||||
*
|
||||
* @param name - Name to check
|
||||
* @return true if accepted
|
||||
*/
|
||||
protected boolean acceptableName(String name) {
|
||||
if (isIgnoredDMI(name)) {
|
||||
LOG.trace("DMI is enabled, ignoring DMI method: {}", name);
|
||||
return false;
|
||||
}
|
||||
boolean accepted = isWithinLengthLimit(name) && !isExcluded(name) && isAccepted(name);
|
||||
if (devMode && accepted) { // notify only when in devMode
|
||||
LOG.debug("Parameter [{}] was accepted and will be appended to action!", name);
|
||||
}
|
||||
return accepted;
|
||||
}
|
||||
|
||||
private boolean isIgnoredDMI(String name) {
|
||||
if (dmiEnabled) {
|
||||
return DMI_IGNORED_PATTERN.matcher(name).matches();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates:
|
||||
* * Value is null/blank
|
||||
* * Value is not excluded
|
||||
* * Value is accepted
|
||||
*
|
||||
* @param name - Param name (for logging)
|
||||
* @param value - value to check
|
||||
* @return true if accepted
|
||||
*/
|
||||
protected boolean acceptableValue(String name, String value) {
|
||||
boolean accepted = (value == null || value.isEmpty() || (!isParamValueExcluded(value) && isParamValueAccepted(value)));
|
||||
if (!accepted) {
|
||||
String message = "Value [{}] of parameter [{}] was not accepted and will be dropped!";
|
||||
if (devMode) {
|
||||
LOG.warn(message, value, name);
|
||||
} else {
|
||||
LOG.debug(message, value, name);
|
||||
}
|
||||
}
|
||||
return accepted;
|
||||
}
|
||||
|
||||
protected boolean isWithinLengthLimit(String name) {
|
||||
boolean matchLength = name.length() <= paramNameMaxLength;
|
||||
if (!matchLength) {
|
||||
if (devMode) { // warn only when in devMode
|
||||
LOG.warn("Parameter [{}] is too long, allowed length is [{}]. Use Interceptor Parameter Overriding " +
|
||||
"to override the limit, see more at\n" +
|
||||
"https://struts.apache.org/core-developers/interceptors.html#interceptor-parameter-overriding",
|
||||
name, paramNameMaxLength);
|
||||
} else {
|
||||
LOG.warn("Parameter [{}] is too long, allowed length is [{}]", name, paramNameMaxLength);
|
||||
}
|
||||
}
|
||||
return matchLength;
|
||||
}
|
||||
|
||||
protected boolean isAccepted(String paramName) {
|
||||
AcceptedPatternsChecker.IsAccepted result = acceptedPatterns.isAccepted(paramName);
|
||||
if (result.isAccepted()) {
|
||||
return true;
|
||||
} else if (devMode) { // warn only when in devMode
|
||||
LOG.warn("Parameter [{}] didn't match accepted pattern [{}]! See Accepted / Excluded patterns at\n" +
|
||||
"https://struts.apache.org/security/#accepted--excluded-patterns",
|
||||
paramName, result.getAcceptedPattern());
|
||||
} else {
|
||||
LOG.debug("Parameter [{}] didn't match accepted pattern [{}]!", paramName, result.getAcceptedPattern());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isExcluded(String paramName) {
|
||||
ExcludedPatternsChecker.IsExcluded result = excludedPatterns.isExcluded(paramName);
|
||||
if (result.isExcluded()) {
|
||||
if (devMode) { // warn only when in devMode
|
||||
LOG.warn("Parameter [{}] matches excluded pattern [{}]! See Accepted / Excluded patterns at\n" +
|
||||
"https://struts.apache.org/security/#accepted--excluded-patterns",
|
||||
paramName, result.getExcludedPattern());
|
||||
} else {
|
||||
LOG.debug("Parameter [{}] matches excluded pattern [{}]!", paramName, result.getExcludedPattern());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isParamValueExcluded(String value) {
|
||||
if (!hasParamValuesToExclude()) {
|
||||
LOG.debug("'excludedValuePatterns' not defined so anything is allowed");
|
||||
return false;
|
||||
}
|
||||
for (Pattern excludedValuePattern : excludedValuePatterns) {
|
||||
if (excludedValuePattern.matcher(value).matches()) {
|
||||
if (devMode) {
|
||||
LOG.warn("Parameter value [{}] matches excluded pattern [{}]! See Accepting/Excluding parameter values at\n" +
|
||||
"https://struts.apache.org/core-developers/parameters-interceptor#excluding-parameter-values",
|
||||
value, excludedValuePatterns);
|
||||
} else {
|
||||
LOG.debug("Parameter value [{}] matches excluded pattern [{}]", value, excludedValuePattern);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isParamValueAccepted(String value) {
|
||||
if (!hasParamValuesToAccept()) {
|
||||
LOG.debug("'acceptedValuePatterns' not defined so anything is allowed");
|
||||
return true;
|
||||
}
|
||||
for (Pattern acceptedValuePattern : acceptedValuePatterns) {
|
||||
if (acceptedValuePattern.matcher(value).matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (devMode) {
|
||||
LOG.warn("Parameter value [{}] didn't match accepted pattern [{}]! See Accepting/Excluding parameter values at\n" +
|
||||
"https://struts.apache.org/core-developers/parameters-interceptor#excluding-parameter-values",
|
||||
value, acceptedValuePatterns);
|
||||
} else {
|
||||
LOG.debug("Parameter value [{}] was not accepted!", value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasParamValuesToExclude() {
|
||||
return excludedValuePatterns != null && excludedValuePatterns.size() > 0;
|
||||
}
|
||||
|
||||
private boolean hasParamValuesToAccept() {
|
||||
return acceptedValuePatterns != null && acceptedValuePatterns.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to order the parameters or not
|
||||
*
|
||||
* @return True to order
|
||||
*/
|
||||
public boolean isOrdered() {
|
||||
return ordered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to order the parameters by object depth or not
|
||||
*
|
||||
* @param ordered True to order them
|
||||
*/
|
||||
public void setOrdered(boolean ordered) {
|
||||
this.ordered = ordered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a comma-delimited list of regular expressions to match
|
||||
* parameters that are allowed in the parameter map (aka whitelist).
|
||||
* <p>
|
||||
* Don't change the default unless you know what you are doing in terms
|
||||
* of security implications.
|
||||
* </p>
|
||||
*
|
||||
* @param commaDelim A comma-delimited list of regular expressions
|
||||
*/
|
||||
public void setAcceptParamNames(String commaDelim) {
|
||||
acceptedPatterns.setAcceptedPatterns(commaDelim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a comma-delimited list of regular expressions to match
|
||||
* parameters that should be removed from the parameter map.
|
||||
*
|
||||
* @param commaDelim A comma-delimited list of regular expressions
|
||||
*/
|
||||
public void setExcludeParams(String commaDelim) {
|
||||
excludedPatterns.setExcludedPatterns(commaDelim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a comma-delimited list of regular expressions to match
|
||||
* values of parameters that should be accepted and included in the parameter map.
|
||||
*
|
||||
* @param commaDelimitedPatterns A comma-delimited set of regular expressions
|
||||
*/
|
||||
public void setAcceptedValuePatterns(String commaDelimitedPatterns) {
|
||||
Set<String> patterns = TextParseUtil.commaDelimitedStringToSet(commaDelimitedPatterns);
|
||||
if (acceptedValuePatterns == null) {
|
||||
// Limit unwanted log entries (for 1st call, acceptedValuePatterns null)
|
||||
LOG.debug("Sets accepted value patterns to [{}], note this may impact the safety of your application!", patterns);
|
||||
} else {
|
||||
LOG.warn("Replacing accepted patterns [{}] with [{}], be aware that this may impact safety of your application!",
|
||||
acceptedValuePatterns, patterns);
|
||||
}
|
||||
acceptedValuePatterns = new HashSet<>(patterns.size());
|
||||
try {
|
||||
for (String pattern : patterns) {
|
||||
acceptedValuePatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
acceptedValuePatterns = Collections.unmodifiableSet(acceptedValuePatterns);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a comma-delimited list of regular expressions to match
|
||||
* values of parameters that should be removed from the parameter map.
|
||||
*
|
||||
* @param commaDelimitedPatterns A comma-delimited set of regular expressions
|
||||
*/
|
||||
public void setExcludedValuePatterns(String commaDelimitedPatterns) {
|
||||
Set<String> patterns = TextParseUtil.commaDelimitedStringToSet(commaDelimitedPatterns);
|
||||
if (excludedValuePatterns == null) {
|
||||
// Limit unwanted log entries (for 1st call, excludedValuePatterns null)
|
||||
LOG.debug("Setting excluded value patterns to [{}]", patterns);
|
||||
} else {
|
||||
LOG.warn("Replacing excluded value patterns [{}] with [{}], be aware that this may impact safety of your application!",
|
||||
excludedValuePatterns, patterns);
|
||||
}
|
||||
excludedValuePatterns = new HashSet<>(patterns.size());
|
||||
try {
|
||||
for (String pattern : patterns) {
|
||||
excludedValuePatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
excludedValuePatterns = Collections.unmodifiableSet(excludedValuePatterns);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -236,6 +236,6 @@ public class StaticParametersInterceptor extends AbstractInterceptor {
|
||||
combinedParams = HttpParameters.create(newParams);
|
||||
combinedParams = combinedParams.withExtraParams(previousParams);
|
||||
}
|
||||
ac.withParameters(combinedParams.build());
|
||||
ac.setParameters(combinedParams.build());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ public class AnnotationParameterFilterInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
}
|
||||
|
||||
invocation.getInvocationContext().withParameters(parameters);
|
||||
invocation.getInvocationContext().setParameters(parameters);
|
||||
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
+9
-10
@@ -16,7 +16,6 @@
|
||||
package com.opensymphony.xwork2.ognl;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import org.apache.commons.lang3.EnumUtils;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
/**
|
||||
@@ -30,16 +29,16 @@ import org.apache.struts2.StrutsConstants;
|
||||
public class DefaultOgnlBeanInfoCacheFactory<Key, Value> extends DefaultOgnlCacheFactory<Key, Value>
|
||||
implements BeanInfoCacheFactory<Key, Value> {
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, use {@link #DefaultOgnlBeanInfoCacheFactory(String, String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public DefaultOgnlBeanInfoCacheFactory() {
|
||||
@Override
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE, required = false)
|
||||
protected void setCacheMaxSize(String maxSize) {
|
||||
super.setCacheMaxSize(maxSize);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public DefaultOgnlBeanInfoCacheFactory(@Inject(value = StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE) String cacheMaxSize,
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_TYPE) String defaultCacheType) {
|
||||
super(Integer.parseInt(cacheMaxSize), EnumUtils.getEnumIgnoreCase(CacheType.class, defaultCacheType));
|
||||
@Override
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_LRU_MODE, required = false)
|
||||
protected void setUseLRUCache(String useLRUMode) {
|
||||
super.setUseLRUCache(useLRUMode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,86 +15,52 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.ognl;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
|
||||
/**
|
||||
* <p>Default OGNL Cache factory implementation.</p>
|
||||
* Default OGNL Cache factory implementation.
|
||||
*
|
||||
* <p>Currently used for Expression cache and BeanInfo cache creation.</p>
|
||||
* Currently used for Expression cache and BeanInfo cache creation.
|
||||
*
|
||||
* @param <Key> The type for the cache key entries
|
||||
* @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 static final int DEFAULT_INIT_CAPACITY = 16;
|
||||
private static final float DEFAULT_LOAD_FACTOR = 0.75f;
|
||||
|
||||
private CacheType defaultCacheType;
|
||||
private int cacheMaxSize;
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, use {@link #DefaultOgnlCacheFactory(int, CacheType)}
|
||||
*/
|
||||
@Deprecated
|
||||
public DefaultOgnlCacheFactory() {
|
||||
this(10000, CacheType.BASIC);
|
||||
}
|
||||
|
||||
public DefaultOgnlCacheFactory(int cacheMaxSize, CacheType defaultCacheType) {
|
||||
this.cacheMaxSize = cacheMaxSize;
|
||||
this.defaultCacheType = defaultCacheType;
|
||||
}
|
||||
private final AtomicBoolean useLRUCache = new AtomicBoolean(false);
|
||||
private final AtomicInteger cacheMaxSize = new AtomicInteger(25000);
|
||||
|
||||
@Override
|
||||
public OgnlCache<Key, Value> buildOgnlCache() {
|
||||
return buildOgnlCache(getCacheMaxSize(), DEFAULT_INIT_CAPACITY, DEFAULT_LOAD_FACTOR, defaultCacheType);
|
||||
return buildOgnlCache(getCacheMaxSize(), 16, 0.75f, getUseLRUCache());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OgnlCache<Key, Value> buildOgnlCache(int evictionLimit,
|
||||
int initialCapacity,
|
||||
float loadFactor,
|
||||
CacheType cacheType) {
|
||||
switch (cacheType) {
|
||||
case BASIC:
|
||||
return new OgnlDefaultCache<>(evictionLimit, initialCapacity, loadFactor);
|
||||
case LRU:
|
||||
return new OgnlLRUCache<>(evictionLimit, initialCapacity, loadFactor);
|
||||
case WTLFU:
|
||||
return new OgnlCaffeineCache<>(evictionLimit, initialCapacity);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown cache type: " + cacheType);
|
||||
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;
|
||||
return cacheMaxSize.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0
|
||||
*/
|
||||
@Deprecated
|
||||
protected void setCacheMaxSize(String maxSize) {
|
||||
cacheMaxSize = Integer.parseInt(maxSize);
|
||||
cacheMaxSize.set(Integer.parseInt(maxSize));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheType getDefaultCacheType() {
|
||||
return defaultCacheType;
|
||||
public boolean getUseLRUCache() {
|
||||
return useLRUCache.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* No effect when {@code useLRUMode} is {@code false}
|
||||
*
|
||||
* @deprecated since 6.4.0
|
||||
*/
|
||||
@Deprecated
|
||||
protected void setUseLRUCache(String useLRUMode) {
|
||||
if (BooleanUtils.toBoolean(useLRUMode)) {
|
||||
defaultCacheType = CacheType.LRU;
|
||||
}
|
||||
useLRUCache.set(BooleanUtils.toBoolean(useLRUMode));
|
||||
}
|
||||
}
|
||||
|
||||
+12
-13
@@ -16,30 +16,29 @@
|
||||
package com.opensymphony.xwork2.ognl;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import org.apache.commons.lang3.EnumUtils;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
/**
|
||||
* Default OGNL Expression Cache factory implementation.
|
||||
* <p>
|
||||
*
|
||||
* Currently used for Expression cache creation.
|
||||
*
|
||||
* @param <Key> The type for the cache key entries
|
||||
* @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> {
|
||||
implements ExpressionCacheFactory<Key, Value> {
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, use {@link #DefaultOgnlExpressionCacheFactory(String, String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public DefaultOgnlExpressionCacheFactory() {
|
||||
@Override
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE, required = false)
|
||||
protected void setCacheMaxSize(String maxSize) {
|
||||
super.setCacheMaxSize(maxSize);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public DefaultOgnlExpressionCacheFactory(@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE) String cacheMaxSize,
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_TYPE) String defaultCacheType) {
|
||||
super(Integer.parseInt(cacheMaxSize), EnumUtils.getEnumIgnoreCase(CacheType.class, defaultCacheType));
|
||||
@Override
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_LRU_MODE, required = false)
|
||||
protected void setUseLRUCache(String useLRUMode) {
|
||||
super.setUseLRUCache(useLRUMode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,23 +19,23 @@ 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> {
|
||||
|
||||
Value get(Key key);
|
||||
public Value get(Key key);
|
||||
|
||||
void put(Key key, Value value);
|
||||
public void put(Key key, Value value);
|
||||
|
||||
void putIfAbsent(Key key, Value value);
|
||||
public void putIfAbsent(Key key, Value value);
|
||||
|
||||
int size();
|
||||
public int size();
|
||||
|
||||
void clear();
|
||||
public void clear();
|
||||
|
||||
int getEvictionLimit();
|
||||
public int getEvictionLimit();
|
||||
|
||||
void setEvictionLimit(int cacheEvictionLimit);
|
||||
public void setEvictionLimit(int cacheEvictionLimit);
|
||||
}
|
||||
|
||||
@@ -19,52 +19,12 @@ 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 <Key> The type for the cache key entries
|
||||
* @param <Value> The type for the cache value entries
|
||||
*/
|
||||
public interface OgnlCacheFactory<Key, Value> {
|
||||
interface OgnlCacheFactory<Key, Value> {
|
||||
OgnlCache<Key, Value> buildOgnlCache();
|
||||
|
||||
/**
|
||||
* Note that if {@code lruCache} is {@code false}, the cache type could still be LRU if the default cache type is
|
||||
* configured as such.
|
||||
* @deprecated since 6.4.0, use {@link #buildOgnlCache(int, int, float, CacheType)}
|
||||
*/
|
||||
@Deprecated
|
||||
default OgnlCache<Key, Value> buildOgnlCache(int evictionLimit,
|
||||
int initialCapacity,
|
||||
float loadFactor,
|
||||
boolean lruCache) {
|
||||
return buildOgnlCache(evictionLimit,
|
||||
initialCapacity,
|
||||
loadFactor,
|
||||
lruCache ? CacheType.LRU : getDefaultCacheType());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param evictionLimit maximum capacity of the cache where applicable for cache type chosen
|
||||
* @param initialCapacity initial capacity of the cache where applicable for cache type chosen
|
||||
* @param loadFactor load factor of the cache where applicable for cache type chosen
|
||||
* @param cacheType type of cache to build
|
||||
* @return a new cache instance
|
||||
*/
|
||||
OgnlCache<Key, Value> buildOgnlCache(int evictionLimit, int initialCapacity, float loadFactor, CacheType cacheType);
|
||||
|
||||
OgnlCache<Key, Value> buildOgnlCache(int evictionLimit, int initialCapacity, float loadFactor, boolean lruCache);
|
||||
int getCacheMaxSize();
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0
|
||||
*/
|
||||
@Deprecated
|
||||
default boolean getUseLRUCache() {
|
||||
return CacheType.LRU.equals(getDefaultCacheType());
|
||||
}
|
||||
|
||||
CacheType getDefaultCacheType();
|
||||
|
||||
enum CacheType {
|
||||
BASIC,
|
||||
LRU,
|
||||
WTLFU
|
||||
}
|
||||
boolean getUseLRUCache();
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* 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.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
|
||||
/**
|
||||
* <p>This OGNL Cache implementation is backed by {@link Caffeine} which uses the Window TinyLfu algorithm.</p>
|
||||
*
|
||||
* <p>An appropriate eviction limit should be chosen for your specific application based on factors and requirements
|
||||
* such as:</p>
|
||||
* <ul>
|
||||
* <li>Quantity and complexity of actions</li>
|
||||
* <li>Volume of requests</li>
|
||||
* <li>Rate limits and attack potential/patterns</li>
|
||||
* <li>Memory constraints</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <K> The type for the cache key entries
|
||||
* @param <V> The type for the cache value entries
|
||||
*/
|
||||
public class OgnlCaffeineCache<K, V> implements OgnlCache<K, V> {
|
||||
|
||||
private final Cache<K, V> cache;
|
||||
|
||||
public OgnlCaffeineCache(int evictionLimit, int initialCapacity) {
|
||||
this.cache = Caffeine.newBuilder().initialCapacity(initialCapacity).maximumSize(evictionLimit).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(K key) {
|
||||
return cache.getIfPresent(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
cache.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putIfAbsent(K key, V value) {
|
||||
cache.asMap().putIfAbsent(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return cache.asMap().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
cache.invalidateAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEvictionLimit() {
|
||||
return Math.toIntExact(cache.policy().eviction().orElseThrow(IllegalStateException::new).getMaximum());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEvictionLimit(int cacheEvictionLimit) {
|
||||
cache.policy().eviction().orElseThrow(IllegalStateException::new).setMaximum(cacheEvictionLimit);
|
||||
}
|
||||
}
|
||||
@@ -19,40 +19,37 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* <p>Basic OGNL cache implementation.</p>
|
||||
*
|
||||
* <p>This implementation is backed by a {@link ConcurrentHashMap} that is cleared whenever the eviction limit is
|
||||
* surpassed.</p>
|
||||
*
|
||||
* <p>Setting a very high eviction limit simulates an unlimited cache.</p>
|
||||
* <p>Setting too low an eviction limit will make the cache ineffective.</p>
|
||||
*
|
||||
* @param <K> The type for the cache key entries
|
||||
* @param <V> The type for the cache value entries
|
||||
* 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<K, V> implements OgnlCache<K, V> {
|
||||
public class OgnlDefaultCache<Key, Value> implements OgnlCache<Key, Value> {
|
||||
|
||||
private final ConcurrentHashMap<K, V> ognlCache;
|
||||
private final AtomicInteger cacheEvictionLimit;
|
||||
private final ConcurrentHashMap<Key, Value> ognlCache;
|
||||
private final AtomicInteger cacheEvictionLimit = new AtomicInteger(25000);
|
||||
|
||||
public OgnlDefaultCache(int evictionLimit, int initialCapacity, float loadFactor) {
|
||||
cacheEvictionLimit = new AtomicInteger(evictionLimit);
|
||||
this.cacheEvictionLimit.set(evictionLimit);
|
||||
ognlCache = new ConcurrentHashMap<>(initialCapacity, loadFactor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(K key) {
|
||||
public Value get(Key key) {
|
||||
return ognlCache.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
public void put(Key key, Value value) {
|
||||
ognlCache.put(key, value);
|
||||
this.clearIfEvictionLimitExceeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putIfAbsent(K key, V value) {
|
||||
public void putIfAbsent(Key key, Value value) {
|
||||
ognlCache.putIfAbsent(key, value);
|
||||
this.clearIfEvictionLimitExceeded();
|
||||
}
|
||||
|
||||
@@ -21,46 +21,46 @@ import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* <p>A basic OGNL LRU cache implementation.</p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>Setting too low an eviction limit will produce more overhead than value.</p>
|
||||
* <p>Setting too high an eviction limit may also produce more overhead than value.</p>
|
||||
* <p>An appropriate eviction limit will need to be determined on an individual application basis.</p>
|
||||
*
|
||||
* @param <K> The type for the cache key entries
|
||||
* @param <V> The type for the cache value entries
|
||||
* 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<K, V> implements OgnlCache<K, V> {
|
||||
public class OgnlLRUCache<Key, Value> implements OgnlCache<Key, Value> {
|
||||
|
||||
private final Map<K, V> ognlLRUCache;
|
||||
private final AtomicInteger cacheEvictionLimit;
|
||||
private final Map<Key, Value> ognlLRUCache;
|
||||
private final AtomicInteger cacheEvictionLimit = new AtomicInteger(2500);
|
||||
|
||||
public OgnlLRUCache(int evictionLimit, int initialCapacity, float loadFactor) {
|
||||
cacheEvictionLimit = new AtomicInteger(evictionLimit);
|
||||
this.cacheEvictionLimit.set(evictionLimit);
|
||||
// Access-order mode selected (order mode true in LinkedHashMap constructor).
|
||||
ognlLRUCache = Collections.synchronizedMap(new LinkedHashMap<K, V>(initialCapacity, loadFactor, true) {
|
||||
ognlLRUCache = Collections.synchronizedMap (new LinkedHashMap<Key, Value>(initialCapacity, loadFactor, true) {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
|
||||
return size() > cacheEvictionLimit.get();
|
||||
protected boolean removeEldestEntry(Map.Entry<Key,Value> eldest) {
|
||||
return (this.size() > cacheEvictionLimit.get());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(K key) {
|
||||
public Value get(Key key) {
|
||||
return ognlLRUCache.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V value) {
|
||||
public void put(Key key, Value value) {
|
||||
ognlLRUCache.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putIfAbsent(K key, V value) {
|
||||
public void putIfAbsent(Key key, Value value) {
|
||||
ognlLRUCache.putIfAbsent(key, value);
|
||||
}
|
||||
|
||||
@@ -81,9 +81,7 @@ public class OgnlLRUCache<K, V> implements OgnlCache<K, V> {
|
||||
|
||||
@Override
|
||||
public void setEvictionLimit(int cacheEvictionLimit) {
|
||||
if (cacheEvictionLimit < size()) {
|
||||
clear();
|
||||
}
|
||||
this.cacheEvictionLimit.set(cacheEvictionLimit);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ package com.opensymphony.xwork2.ognl;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionException;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
import ognl.Ognl;
|
||||
import ognl.OgnlException;
|
||||
import ognl.OgnlRuntime;
|
||||
|
||||
@@ -32,9 +33,9 @@ import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
public class OgnlReflectionProvider implements ReflectionProvider {
|
||||
|
||||
|
||||
private OgnlUtil ognlUtil;
|
||||
|
||||
|
||||
@Inject
|
||||
public void setOgnlUtil(OgnlUtil ognlUtil) {
|
||||
this.ognlUtil = ognlUtil;
|
||||
@@ -68,6 +69,7 @@ public class OgnlReflectionProvider implements ReflectionProvider {
|
||||
|
||||
public void setProperties(Map<String, ?> props, Object o, Map<String, Object> context, boolean throwPropertyExceptions) throws ReflectionException{
|
||||
ognlUtil.setProperties(props, o, context, throwPropertyExceptions);
|
||||
|
||||
}
|
||||
|
||||
public void setProperties(Map<String, ?> properties, Object o) {
|
||||
@@ -132,7 +134,7 @@ public class OgnlReflectionProvider implements ReflectionProvider {
|
||||
public void setValue(String expression, Map<String, Object> context, Object root,
|
||||
Object value) throws ReflectionException {
|
||||
try {
|
||||
ognlUtil.setValue(expression, context, root, value);
|
||||
Ognl.setValue(expression, context, root, value);
|
||||
} catch (OgnlException e) {
|
||||
throw new ReflectionException(e);
|
||||
}
|
||||
|
||||
@@ -18,45 +18,29 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.ognl;
|
||||
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.ognl.accessor.RootAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionException;
|
||||
import ognl.ClassResolver;
|
||||
import ognl.Ognl;
|
||||
import ognl.OgnlContext;
|
||||
import ognl.OgnlException;
|
||||
import ognl.OgnlRuntime;
|
||||
import ognl.SimpleNode;
|
||||
import ognl.TypeConverter;
|
||||
import ognl.*;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.ognl.OgnlGuard;
|
||||
import org.apache.struts2.ognl.StrutsOgnlGuard;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.opensymphony.xwork2.util.ConfigParseUtil.toClassesSet;
|
||||
import static com.opensymphony.xwork2.util.ConfigParseUtil.toNewPatternsSet;
|
||||
import static com.opensymphony.xwork2.util.ConfigParseUtil.toPackageNamesSet;
|
||||
import static java.util.Collections.emptySet;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static org.apache.struts2.ognl.OgnlGuard.EXPR_BLOCKED;
|
||||
|
||||
|
||||
/**
|
||||
* Utility class that provides common access to the Ognl APIs for
|
||||
@@ -74,46 +58,67 @@ public class OgnlUtil {
|
||||
private final OgnlCache<String, Object> expressionCache;
|
||||
private final OgnlCache<Class<?>, BeanInfo> beanInfoCache;
|
||||
private TypeConverter defaultConverter;
|
||||
private final OgnlGuard ognlGuard;
|
||||
|
||||
private boolean devMode;
|
||||
private boolean enableExpressionCache = true;
|
||||
private boolean enableEvalExpression;
|
||||
|
||||
private String devModeExcludedClasses = "";
|
||||
private String devModeExcludedPackageNamePatterns = "";
|
||||
private String devModeExcludedPackageNames = "";
|
||||
private String devModeExcludedPackageExemptClasses = "";
|
||||
private Set<Class<?>> excludedClasses;
|
||||
private Set<Pattern> excludedPackageNamePatterns;
|
||||
private Set<String> excludedPackageNames;
|
||||
|
||||
private Set<Class<?>> devModeExcludedClasses;
|
||||
private Set<Pattern> devModeExcludedPackageNamePatterns;
|
||||
private Set<String> devModeExcludedPackageNames;
|
||||
|
||||
private Container container;
|
||||
private boolean allowStaticFieldAccess = true;
|
||||
private boolean disallowProxyMemberAccess;
|
||||
|
||||
/**
|
||||
* Construct a new OgnlUtil instance for use with the framework
|
||||
*
|
||||
* @deprecated since 6.0.0. Use {@link #OgnlUtil(ExpressionCacheFactory, BeanInfoCacheFactory, OgnlGuard) instead.
|
||||
* @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(new DefaultOgnlExpressionCacheFactory<>(),
|
||||
new DefaultOgnlBeanInfoCacheFactory<>(),
|
||||
new StrutsOgnlGuard());
|
||||
// Instantiate default Expression and BeanInfo caches (factories must be non-null).
|
||||
this(new DefaultOgnlExpressionCacheFactory<String, Object>(),
|
||||
new DefaultOgnlBeanInfoCacheFactory<Class<?>, BeanInfo>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new OgnlUtil instance for use with the framework, with optional cache factories for OGNL Expression
|
||||
* and BeanInfo caches.
|
||||
* Construct a new OgnlUtil instance for use with the framework, with optional
|
||||
* cache factories for OGNL Expression and BeanInfo caches.
|
||||
*
|
||||
* @param ognlExpressionCacheFactory factory for Expression cache instance
|
||||
* @param ognlBeanInfoCacheFactory factory for BeanInfo cache instance
|
||||
* @param ognlGuard OGNL Guard instance
|
||||
* 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
|
||||
*/
|
||||
@Inject
|
||||
public OgnlUtil(@Inject ExpressionCacheFactory<String, Object> ognlExpressionCacheFactory,
|
||||
@Inject BeanInfoCacheFactory<Class<?>, BeanInfo> ognlBeanInfoCacheFactory,
|
||||
@Inject OgnlGuard ognlGuard) {
|
||||
this.expressionCache = requireNonNull(ognlExpressionCacheFactory).buildOgnlCache();
|
||||
this.beanInfoCache = requireNonNull(ognlBeanInfoCacheFactory).buildOgnlCache();
|
||||
this.ognlGuard = requireNonNull(ognlGuard);
|
||||
public OgnlUtil(
|
||||
@Inject ExpressionCacheFactory<String, Object> ognlExpressionCacheFactory,
|
||||
@Inject BeanInfoCacheFactory<Class<?>, BeanInfo> ognlBeanInfoCacheFactory
|
||||
) {
|
||||
if (ognlExpressionCacheFactory == null) {
|
||||
throw new IllegalArgumentException("ExpressionCacheFactory parameter cannot be null");
|
||||
}
|
||||
if (ognlBeanInfoCacheFactory == null) {
|
||||
throw new IllegalArgumentException("BeanInfoCacheFactory parameter cannot be null");
|
||||
}
|
||||
excludedClasses = Collections.unmodifiableSet(new HashSet<>());
|
||||
excludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
|
||||
excludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
|
||||
|
||||
devModeExcludedClasses = Collections.unmodifiableSet(new HashSet<>());
|
||||
devModeExcludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
|
||||
devModeExcludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
|
||||
|
||||
this.expressionCache = ognlExpressionCacheFactory.buildOgnlCache();
|
||||
this.beanInfoCache = ognlBeanInfoCacheFactory.buildOgnlCache();
|
||||
}
|
||||
|
||||
@Inject
|
||||
@@ -126,23 +131,17 @@ public class OgnlUtil {
|
||||
this.devMode = BooleanUtils.toBoolean(mode);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_ENABLE_EXPRESSION_CACHE, required = false)
|
||||
@Inject(StrutsConstants.STRUTS_OGNL_ENABLE_EXPRESSION_CACHE)
|
||||
protected void setEnableExpressionCache(String cache) {
|
||||
enableExpressionCache = BooleanUtils.toBoolean(cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, changing maximum cache size after initialisation is not necessary.
|
||||
*/
|
||||
@Deprecated
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_MAXSIZE, required = false)
|
||||
protected void setExpressionCacheMaxSize(String maxSize) {
|
||||
expressionCache.setEvictionLimit(Integer.parseInt(maxSize));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, changing maximum cache size after initialisation is not necessary.
|
||||
*/
|
||||
@Deprecated
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_MAXSIZE, required = false)
|
||||
protected void setBeanInfoCacheMaxSize(String maxSize) {
|
||||
beanInfoCache.setEvictionLimit(Integer.parseInt(maxSize));
|
||||
}
|
||||
@@ -156,88 +155,94 @@ public class OgnlUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
*/
|
||||
@Deprecated
|
||||
@Inject(value = StrutsConstants.STRUTS_EXCLUDED_CLASSES, required = false)
|
||||
protected void setExcludedClasses(String commaDelimitedClasses) {
|
||||
// Must be set directly on SecurityMemberAccess
|
||||
Set<Class<?>> excludedClasses = new HashSet<>();
|
||||
excludedClasses.addAll(this.excludedClasses);
|
||||
excludedClasses.addAll(parseExcludedClasses(commaDelimitedClasses));
|
||||
this.excludedClasses = Collections.unmodifiableSet(excludedClasses);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_CLASSES, required = false)
|
||||
protected void setDevModeExcludedClasses(String commaDelimitedClasses) {
|
||||
this.devModeExcludedClasses = commaDelimitedClasses;
|
||||
Set<Class<?>> excludedClasses = new HashSet<>();
|
||||
excludedClasses.addAll(this.devModeExcludedClasses);
|
||||
excludedClasses.addAll(parseExcludedClasses(commaDelimitedClasses));
|
||||
this.devModeExcludedClasses = Collections.unmodifiableSet(excludedClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
*/
|
||||
@Deprecated
|
||||
private Set<Class<?>> parseExcludedClasses(String commaDelimitedClasses) {
|
||||
Set<String> classNames = TextParseUtil.commaDelimitedStringToSet(commaDelimitedClasses);
|
||||
Set<Class<?>> classes = new HashSet<>();
|
||||
|
||||
for (String className : classNames) {
|
||||
try {
|
||||
classes.add(Class.forName(className));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ConfigurationException("Cannot load excluded class: " + className, e);
|
||||
}
|
||||
}
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAME_PATTERNS, required = false)
|
||||
protected void setExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) {
|
||||
// Must be set directly on SecurityMemberAccess
|
||||
Set<Pattern> excludedPackageNamePatterns = new HashSet<>();
|
||||
excludedPackageNamePatterns.addAll(this.excludedPackageNamePatterns);
|
||||
excludedPackageNamePatterns.addAll(parseExcludedPackageNamePatterns(commaDelimitedPackagePatterns));
|
||||
this.excludedPackageNamePatterns = Collections.unmodifiableSet(excludedPackageNamePatterns);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAME_PATTERNS, required = false)
|
||||
protected void setDevModeExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) {
|
||||
this.devModeExcludedPackageNamePatterns = commaDelimitedPackagePatterns;
|
||||
Set<Pattern> excludedPackageNamePatterns = new HashSet<>();
|
||||
excludedPackageNamePatterns.addAll(this.devModeExcludedPackageNamePatterns);
|
||||
excludedPackageNamePatterns.addAll(parseExcludedPackageNamePatterns(commaDelimitedPackagePatterns));
|
||||
this.devModeExcludedPackageNamePatterns = Collections.unmodifiableSet(excludedPackageNamePatterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
*/
|
||||
@Deprecated
|
||||
private Set<Pattern> parseExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) {
|
||||
Set<String> packagePatterns = TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackagePatterns);
|
||||
Set<Pattern> packageNamePatterns = new HashSet<>();
|
||||
|
||||
for (String pattern : packagePatterns) {
|
||||
packageNamePatterns.add(Pattern.compile(pattern));
|
||||
}
|
||||
|
||||
return packageNamePatterns;
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAMES, required = false)
|
||||
protected void setExcludedPackageNames(String commaDelimitedPackageNames) {
|
||||
// Must be set directly on SecurityMemberAccess
|
||||
Set<String> excludedPackageNames = new HashSet<>();
|
||||
excludedPackageNames.addAll(this.excludedPackageNames);
|
||||
excludedPackageNames.addAll(parseExcludedPackageNames(commaDelimitedPackageNames));
|
||||
this.excludedPackageNames = Collections.unmodifiableSet(excludedPackageNames);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAMES, required = false)
|
||||
protected void setDevModeExcludedPackageNames(String commaDelimitedPackageNames) {
|
||||
this.devModeExcludedPackageNames = commaDelimitedPackageNames;
|
||||
Set<String> excludedPackageNames = new HashSet<>();
|
||||
excludedPackageNames.addAll(this.devModeExcludedPackageNames);
|
||||
excludedPackageNames.addAll(parseExcludedPackageNames(commaDelimitedPackageNames));
|
||||
this.devModeExcludedPackageNames = Collections.unmodifiableSet(excludedPackageNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setExcludedPackageExemptClasses(String commaDelimitedClasses) {
|
||||
// Must be set directly on SecurityMemberAccess
|
||||
private Set<String> parseExcludedPackageNames(String commaDelimitedPackageNames) {
|
||||
return TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackageNames);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_EXEMPT_CLASSES, required = false)
|
||||
public void setDevModeExcludedPackageExemptClasses(String commaDelimitedClasses) {
|
||||
this.devModeExcludedPackageExemptClasses = commaDelimitedClasses;
|
||||
public Set<Class<?>> getExcludedClasses() {
|
||||
return excludedClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
*/
|
||||
@Deprecated
|
||||
public Set<String> getExcludedClasses() {
|
||||
return toClassesSet(container.getInstance(String.class, StrutsConstants.STRUTS_EXCLUDED_CLASSES));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
*/
|
||||
@Deprecated
|
||||
public Set<Pattern> getExcludedPackageNamePatterns() {
|
||||
return toNewPatternsSet(emptySet(), container.getInstance(String.class, StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAME_PATTERNS));
|
||||
return excludedPackageNamePatterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
*/
|
||||
@Deprecated
|
||||
public Set<String> getExcludedPackageNames() {
|
||||
return toPackageNamesSet(container.getInstance(String.class, StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAMES));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
*/
|
||||
@Deprecated
|
||||
public Set<String> getExcludedPackageExemptClasses() {
|
||||
return toClassesSet(container.getInstance(String.class, StrutsConstants.STRUTS_EXCLUDED_PACKAGE_EXEMPT_CLASSES));
|
||||
return excludedPackageNames;
|
||||
}
|
||||
|
||||
@Inject
|
||||
@@ -245,28 +250,14 @@ public class OgnlUtil {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
*/
|
||||
@Deprecated
|
||||
@Inject(value = StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, required = false)
|
||||
protected void setAllowStaticFieldAccess(String allowStaticFieldAccess) {
|
||||
// Must be set directly on SecurityMemberAccess
|
||||
this.allowStaticFieldAccess = BooleanUtils.toBoolean(allowStaticFieldAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
*/
|
||||
@Deprecated
|
||||
@Inject(value = StrutsConstants.STRUTS_DISALLOW_PROXY_MEMBER_ACCESS, required = false)
|
||||
protected void setDisallowProxyMemberAccess(String disallowProxyMemberAccess) {
|
||||
// Must be set directly on SecurityMemberAccess
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
*/
|
||||
@Deprecated
|
||||
protected void setDisallowDefaultPackageAccess(String disallowDefaultPackageAccess) {
|
||||
// Must be set directly on SecurityMemberAccess
|
||||
this.disallowProxyMemberAccess = BooleanUtils.toBoolean(disallowProxyMemberAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -288,20 +279,8 @@ public class OgnlUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isDisallowProxyMemberAccess() {
|
||||
return BooleanUtils.toBoolean(container.getInstance(String.class, StrutsConstants.STRUTS_DISALLOW_PROXY_MEMBER_ACCESS));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isDisallowDefaultPackageAccess() {
|
||||
return BooleanUtils.toBoolean(container.getInstance(String.class, StrutsConstants.STRUTS_DISALLOW_DEFAULT_PACKAGE_ACCESS));
|
||||
return disallowProxyMemberAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -509,7 +488,8 @@ public class OgnlUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around Ognl#setValue
|
||||
* Wrapper around Ognl.setValue() to handle type conversion for collection elements.
|
||||
* Ideally, this should be handled by OGNL directly.
|
||||
*
|
||||
* @param name the name
|
||||
* @param context context map
|
||||
@@ -519,7 +499,16 @@ public class OgnlUtil {
|
||||
* @throws OgnlException in case of ognl errors
|
||||
*/
|
||||
public void setValue(final String name, final Map<String, Object> context, final Object root, final Object value) throws OgnlException {
|
||||
ognlSet(name, context, root, value, context, this::checkEvalExpression, this::checkArithmeticExpression);
|
||||
compileAndExecute(name, context, (OgnlTask<Void>) tree -> {
|
||||
if (isEvalExpression(tree, context)) {
|
||||
throw new OgnlException("Eval expression/chained expressions cannot be used as parameter name");
|
||||
}
|
||||
if (isArithmeticExpression(tree, context)) {
|
||||
throw new OgnlException("Arithmetic expressions cannot be used as parameter name");
|
||||
}
|
||||
Ognl.setValue(tree, context, root, value);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isEvalExpression(Object tree, Map<String, Object> context) throws OgnlException {
|
||||
@@ -562,58 +551,58 @@ public class OgnlUtil {
|
||||
}
|
||||
|
||||
public Object getValue(final String name, final Map<String, Object> context, final Object root) throws OgnlException {
|
||||
return getValue(name, context, root, null);
|
||||
return compileAndExecute(name, context, tree -> Ognl.getValue(tree, context, root));
|
||||
}
|
||||
|
||||
public Object callMethod(final String name, final Map<String, Object> context, final Object root) throws OgnlException {
|
||||
return ognlGet(name, context, root, null, context, this::checkSimpleMethod);
|
||||
return compileAndExecuteMethod(name, context, tree -> Ognl.getValue(tree, context, root));
|
||||
}
|
||||
|
||||
public Object getValue(final String name, final Map<String, Object> context, final Object root, final Class<?> resultType) throws OgnlException {
|
||||
return ognlGet(name, context, root, resultType, context, this::checkEnableEvalExpression);
|
||||
return compileAndExecute(name, context, tree -> Ognl.getValue(tree, context, root, resultType));
|
||||
}
|
||||
|
||||
|
||||
public Object compile(String expression) throws OgnlException {
|
||||
return compile(expression, null);
|
||||
}
|
||||
|
||||
private void ognlSet(String expr, Map<String, Object> context, Object root, Object value, Map<String, Object> checkContext, TreeValidator... treeValidators) throws OgnlException {
|
||||
Object tree = toTree(expr);
|
||||
for (TreeValidator validator : treeValidators) {
|
||||
validator.validate(tree, checkContext);
|
||||
}
|
||||
Ognl.setValue(tree, context, root, value);
|
||||
}
|
||||
|
||||
private <T> T ognlGet(String expr, Map<String, Object> context, Object root, Class<T> resultType, Map<String, Object> checkContext, TreeValidator... treeValidators) throws OgnlException {
|
||||
Object tree = toTree(expr);
|
||||
for (TreeValidator validator : treeValidators) {
|
||||
validator.validate(tree, checkContext);
|
||||
}
|
||||
return (T) Ognl.getValue(tree, context, root, resultType);
|
||||
}
|
||||
|
||||
private Object toTree(String expr) throws OgnlException {
|
||||
Object tree = null;
|
||||
private <T> Object compileAndExecute(String expression, Map<String, Object> context, OgnlTask<T> task) throws OgnlException {
|
||||
Object tree;
|
||||
if (enableExpressionCache) {
|
||||
tree = expressionCache.get(expr);
|
||||
}
|
||||
if (tree == null) {
|
||||
tree = ognlGuard.parseExpression(expr);
|
||||
if (enableExpressionCache) {
|
||||
expressionCache.put(expr, tree);
|
||||
tree = expressionCache.get(expression);
|
||||
if (tree == null) {
|
||||
tree = Ognl.parseExpression(expression);
|
||||
checkEnableEvalExpression(tree, context);
|
||||
expressionCache.putIfAbsent(expression, tree);
|
||||
}
|
||||
} else {
|
||||
tree = Ognl.parseExpression(expression);
|
||||
checkEnableEvalExpression(tree, context);
|
||||
}
|
||||
if (EXPR_BLOCKED.equals(tree)) {
|
||||
throw new OgnlException("Expression blocked by OgnlGuard: " + expr);
|
||||
|
||||
return task.execute(tree);
|
||||
}
|
||||
|
||||
private <T> Object compileAndExecuteMethod(String expression, Map<String, Object> context, OgnlTask<T> task) throws OgnlException {
|
||||
Object tree;
|
||||
if (enableExpressionCache) {
|
||||
tree = expressionCache.get(expression);
|
||||
if (tree == null) {
|
||||
tree = Ognl.parseExpression(expression);
|
||||
checkSimpleMethod(tree, context);
|
||||
expressionCache.putIfAbsent(expression, tree);
|
||||
}
|
||||
} else {
|
||||
tree = Ognl.parseExpression(expression);
|
||||
checkSimpleMethod(tree, context);
|
||||
}
|
||||
return tree;
|
||||
|
||||
return task.execute(tree);
|
||||
}
|
||||
|
||||
public Object compile(String expression, Map<String, Object> context) throws OgnlException {
|
||||
Object tree = toTree(expression);
|
||||
checkEnableEvalExpression(tree, context);
|
||||
return tree;
|
||||
return compileAndExecute(expression, context, tree -> tree);
|
||||
}
|
||||
|
||||
private void checkEnableEvalExpression(Object tree, Map<String, Object> context) throws OgnlException {
|
||||
@@ -628,18 +617,6 @@ public class OgnlUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkEvalExpression(Object tree, Map<String, Object> context) throws OgnlException {
|
||||
if (isEvalExpression(tree, context)) {
|
||||
throw new OgnlException("Eval expression/chained expressions cannot be used as parameter name");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkArithmeticExpression(Object tree, Map<String, Object> context) throws OgnlException {
|
||||
if (isArithmeticExpression(tree, context)) {
|
||||
throw new OgnlException("Arithmetic expressions cannot be used as parameter name");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the properties in the object "from" and sets them in the object "to"
|
||||
* using specified type converter, or {@link com.opensymphony.xwork2.conversion.impl.XWorkConverter} if none
|
||||
@@ -670,15 +647,9 @@ public class OgnlUtil {
|
||||
* note if exclusions AND inclusions are supplied and not null nothing will get copied.
|
||||
* @param editable the class (or interface) to restrict property setting to
|
||||
*/
|
||||
public void copy(final Object from,
|
||||
final Object to,
|
||||
final Map<String, Object> context,
|
||||
Collection<String> exclusions,
|
||||
Collection<String> inclusions,
|
||||
Class<?> editable) {
|
||||
public void copy(final Object from, final Object to, final Map<String, Object> context, Collection<String> exclusions, Collection<String> inclusions, Class<?> editable) {
|
||||
if (from == null || to == null) {
|
||||
LOG.warn(
|
||||
"Skipping attempt to copy from, or to, a null source.", new RuntimeException());
|
||||
LOG.warn("Attempting to copy from or to a null source. This is illegal and is bein skipped. This may be due to an error in an OGNL expression, action chaining, or some other event.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -692,7 +663,8 @@ public class OgnlUtil {
|
||||
fromPds = getPropertyDescriptors(from);
|
||||
if (editable != null) {
|
||||
toPds = getPropertyDescriptors(editable);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
toPds = getPropertyDescriptors(to);
|
||||
}
|
||||
} catch (IntrospectionException e) {
|
||||
@@ -707,31 +679,33 @@ public class OgnlUtil {
|
||||
}
|
||||
|
||||
for (PropertyDescriptor fromPd : fromPds) {
|
||||
if (fromPd.getReadMethod() == null) {
|
||||
continue;
|
||||
if (fromPd.getReadMethod() != null) {
|
||||
boolean copy = true;
|
||||
if (exclusions != null && exclusions.contains(fromPd.getName())) {
|
||||
copy = false;
|
||||
} else if (inclusions != null && !inclusions.contains(fromPd.getName())) {
|
||||
copy = false;
|
||||
}
|
||||
|
||||
if (copy) {
|
||||
PropertyDescriptor toPd = toPdHash.get(fromPd.getName());
|
||||
if ((toPd != null) && (toPd.getWriteMethod() != null)) {
|
||||
try {
|
||||
compileAndExecute(fromPd.getName(), context, expr -> {
|
||||
Object value = Ognl.getValue(expr, contextFrom, from);
|
||||
Ognl.setValue(expr, contextTo, to, value);
|
||||
return null;
|
||||
});
|
||||
|
||||
} catch (OgnlException e) {
|
||||
LOG.debug("Got OGNL exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (exclusions != null && exclusions.contains(fromPd.getName()) ||
|
||||
inclusions != null && !inclusions.contains(fromPd.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PropertyDescriptor toPd = toPdHash.get(fromPd.getName());
|
||||
if (toPd == null || toPd.getWriteMethod() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
Object value = ognlGet(fromPd.getName(),
|
||||
contextFrom,
|
||||
from,
|
||||
null,
|
||||
context,
|
||||
this::checkEnableEvalExpression);
|
||||
ognlSet(fromPd.getName(), contextTo, to, value, context);
|
||||
} catch (OgnlException e) {
|
||||
LOG.debug("Got OGNL exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -750,7 +724,7 @@ public class OgnlUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the java beans property descriptors for the given source.
|
||||
* Get's the java beans property descriptors for the given source.
|
||||
*
|
||||
* @param source the source object.
|
||||
* @return property descriptors.
|
||||
@@ -794,7 +768,7 @@ public class OgnlUtil {
|
||||
final String propertyName = propertyDescriptor.getDisplayName();
|
||||
Method readMethod = propertyDescriptor.getReadMethod();
|
||||
if (readMethod != null) {
|
||||
final Object value = ognlGet(propertyName, sourceMap, source, null, null, this::checkEnableEvalExpression);
|
||||
final Object value = compileAndExecute(propertyName, null, expr -> Ognl.getValue(expr, sourceMap, source));
|
||||
beanMap.put(propertyName, value);
|
||||
} else {
|
||||
beanMap.put(propertyName, "There is no read method for " + propertyName);
|
||||
@@ -856,33 +830,34 @@ public class OgnlUtil {
|
||||
return createDefaultContext(root, null);
|
||||
}
|
||||
|
||||
protected Map<String, Object> createDefaultContext(Object root, ClassResolver resolver) {
|
||||
protected Map<String, Object> createDefaultContext(Object root, ClassResolver classResolver) {
|
||||
ClassResolver resolver = classResolver;
|
||||
if (resolver == null) {
|
||||
resolver = container.getInstance(RootAccessor.class);
|
||||
if (resolver == null) {
|
||||
throw new IllegalStateException("Cannot find ClassResolver");
|
||||
}
|
||||
resolver = container.getInstance(CompoundRootAccessor.class);
|
||||
}
|
||||
|
||||
SecurityMemberAccess memberAccess = container.getInstance(SecurityMemberAccess.class);
|
||||
memberAccess.useEnforceAllowlistEnabled(Boolean.FALSE.toString());
|
||||
SecurityMemberAccess memberAccess = new SecurityMemberAccess(allowStaticFieldAccess);
|
||||
memberAccess.setDisallowProxyMemberAccess(disallowProxyMemberAccess);
|
||||
|
||||
if (devMode) {
|
||||
if (!warnReported.get()) {
|
||||
warnReported.set(true);
|
||||
LOG.warn("Working in devMode, using devMode excluded classes and packages!");
|
||||
}
|
||||
memberAccess.useExcludedClasses(devModeExcludedClasses);
|
||||
memberAccess.useExcludedPackageNamePatterns(devModeExcludedPackageNamePatterns);
|
||||
memberAccess.useExcludedPackageNames(devModeExcludedPackageNames);
|
||||
memberAccess.useExcludedPackageExemptClasses(devModeExcludedPackageExemptClasses);
|
||||
memberAccess.setExcludedClasses(devModeExcludedClasses);
|
||||
memberAccess.setExcludedPackageNamePatterns(devModeExcludedPackageNamePatterns);
|
||||
memberAccess.setExcludedPackageNames(devModeExcludedPackageNames);
|
||||
} else {
|
||||
memberAccess.setExcludedClasses(excludedClasses);
|
||||
memberAccess.setExcludedPackageNamePatterns(excludedPackageNamePatterns);
|
||||
memberAccess.setExcludedPackageNames(excludedPackageNames);
|
||||
}
|
||||
|
||||
return Ognl.createDefaultContext(root, memberAccess, resolver, defaultConverter);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface TreeValidator {
|
||||
void validate(Object tree, Map<String, Object> context) throws OgnlException;
|
||||
private interface OgnlTask<T> {
|
||||
T execute(Object tree) throws OgnlException;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,17 +24,12 @@ import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.RootAccessor;
|
||||
import com.opensymphony.xwork2.util.ClearableValueStack;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.MemberAccessValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
|
||||
import ognl.MethodFailedException;
|
||||
import ognl.NoSuchPropertyException;
|
||||
import ognl.Ognl;
|
||||
import ognl.OgnlContext;
|
||||
import ognl.OgnlException;
|
||||
import ognl.*;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -76,93 +71,34 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
private transient XWorkConverter converter;
|
||||
private boolean devMode;
|
||||
private boolean logMissingProperties;
|
||||
private boolean shouldFallbackToContext = true;
|
||||
|
||||
/**
|
||||
* @since 6.4.0
|
||||
*/
|
||||
protected OgnlValueStack(ValueStack vs,
|
||||
XWorkConverter xworkConverter,
|
||||
RootAccessor accessor,
|
||||
TextProvider prov,
|
||||
SecurityMemberAccess securityMemberAccess) {
|
||||
setRoot(xworkConverter,
|
||||
accessor,
|
||||
vs != null ? new CompoundRoot(vs.getRoot()) : new CompoundRoot(),
|
||||
securityMemberAccess);
|
||||
if (prov != null) {
|
||||
push(prov);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 6.4.0
|
||||
*/
|
||||
protected OgnlValueStack(XWorkConverter xworkConverter, RootAccessor accessor, TextProvider prov, SecurityMemberAccess securityMemberAccess) {
|
||||
this(null, xworkConverter, accessor, prov, securityMemberAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 6.4.0
|
||||
*/
|
||||
protected OgnlValueStack(ValueStack vs, XWorkConverter xworkConverter, RootAccessor accessor, SecurityMemberAccess securityMemberAccess) {
|
||||
this(vs, xworkConverter, accessor, null, securityMemberAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, use {@link #OgnlValueStack(ValueStack, XWorkConverter, RootAccessor, TextProvider, SecurityMemberAccess)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
protected OgnlValueStack(ValueStack vs,
|
||||
XWorkConverter xworkConverter,
|
||||
CompoundRootAccessor accessor,
|
||||
TextProvider prov,
|
||||
boolean allowStaticFieldAccess) {
|
||||
this(vs, xworkConverter, accessor, prov, new SecurityMemberAccess(allowStaticFieldAccess));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, use {@link #OgnlValueStack(XWorkConverter, RootAccessor, TextProvider, SecurityMemberAccess)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
protected OgnlValueStack(XWorkConverter xworkConverter, CompoundRootAccessor accessor, TextProvider prov, boolean allowStaticFieldAccess) {
|
||||
this(xworkConverter, accessor, prov, new SecurityMemberAccess(allowStaticFieldAccess));
|
||||
setRoot(xworkConverter, accessor, new CompoundRoot(), allowStaticFieldAccess);
|
||||
push(prov);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, use {@link #OgnlValueStack(ValueStack, XWorkConverter, RootAccessor, SecurityMemberAccess)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
protected OgnlValueStack(ValueStack vs, XWorkConverter xworkConverter, CompoundRootAccessor accessor, boolean allowStaticFieldAccess) {
|
||||
this(vs, xworkConverter, accessor, new SecurityMemberAccess(allowStaticFieldAccess));
|
||||
setRoot(xworkConverter, accessor, new CompoundRoot(vs.getRoot()), allowStaticFieldAccess);
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected void setOgnlUtil(OgnlUtil ognlUtil) {
|
||||
this.ognlUtil = ognlUtil;
|
||||
securityMemberAccess.setExcludedClasses(ognlUtil.getExcludedClasses());
|
||||
securityMemberAccess.setExcludedPackageNamePatterns(ognlUtil.getExcludedPackageNamePatterns());
|
||||
securityMemberAccess.setExcludedPackageNames(ognlUtil.getExcludedPackageNames());
|
||||
securityMemberAccess.setDisallowProxyMemberAccess(ognlUtil.isDisallowProxyMemberAccess());
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 6.4.0
|
||||
*/
|
||||
protected void setRoot(XWorkConverter xworkConverter, RootAccessor accessor, CompoundRoot compoundRoot, SecurityMemberAccess securityMemberAccess) {
|
||||
protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot, boolean allowStaticFieldAccess) {
|
||||
this.root = compoundRoot;
|
||||
this.securityMemberAccess = securityMemberAccess;
|
||||
this.securityMemberAccess = new SecurityMemberAccess(allowStaticFieldAccess);
|
||||
this.context = Ognl.createDefaultContext(this.root, securityMemberAccess, accessor, new OgnlTypeConverterWrapper(xworkConverter));
|
||||
this.converter = xworkConverter;
|
||||
context.put(VALUE_STACK, this);
|
||||
((OgnlContext) context).setTraceEvaluations(false);
|
||||
((OgnlContext) context).setKeepLastEvaluation(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, use {@link #setRoot(XWorkConverter, RootAccessor, CompoundRoot, SecurityMemberAccess)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot, boolean allowStaticFieldAccess) {
|
||||
setRoot(xworkConverter, accessor, compoundRoot, new SecurityMemberAccess(allowStaticFieldAccess));
|
||||
}
|
||||
|
||||
@Inject(StrutsConstants.STRUTS_DEVMODE)
|
||||
protected void setDevMode(String mode) {
|
||||
this.devMode = BooleanUtils.toBoolean(mode);
|
||||
@@ -173,11 +109,6 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
this.logMissingProperties = BooleanUtils.toBoolean(logMissingProperties);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_VALUE_STACK_FALLBACK_TO_CONTEXT, required = false)
|
||||
protected void setShouldFallbackToContext(String shouldFallbackToContext) {
|
||||
this.shouldFallbackToContext = BooleanUtils.toBoolean(shouldFallbackToContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see com.opensymphony.xwork2.util.ValueStack#getContext()
|
||||
*/
|
||||
@@ -343,16 +274,34 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
}
|
||||
|
||||
private Object tryFindValue(String expr) throws OgnlException {
|
||||
return tryFindValue(expr, defaultType);
|
||||
Object value;
|
||||
expr = lookupForOverrides(expr);
|
||||
if (defaultType != null) {
|
||||
value = findValue(expr, defaultType);
|
||||
} else {
|
||||
value = getValueUsingOgnl(expr);
|
||||
if (value == null) {
|
||||
value = findInContext(expr);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private String lookupForOverrides(String expr) {
|
||||
if (overrides != null && overrides.containsKey(expr)) {
|
||||
if ((overrides != null) && overrides.containsKey(expr)) {
|
||||
expr = (String) overrides.get(expr);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
private Object getValueUsingOgnl(String expr) throws OgnlException {
|
||||
try {
|
||||
return ognlUtil.getValue(expr, context, root);
|
||||
} finally {
|
||||
context.remove(THROW_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
public Object findValue(String expr) {
|
||||
return findValue(expr, false);
|
||||
}
|
||||
@@ -407,25 +356,25 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
}
|
||||
|
||||
private Object tryFindValue(String expr, Class asType) throws OgnlException {
|
||||
Object value = null;
|
||||
try {
|
||||
expr = lookupForOverrides(expr);
|
||||
Object value = ognlUtil.getValue(expr, context, root, asType);
|
||||
value = getValue(expr, asType);
|
||||
if (value == null) {
|
||||
value = findInContext(expr);
|
||||
if (value != null && asType != null) {
|
||||
value = converter.convertValue(getContext(), value, asType);
|
||||
}
|
||||
return converter.convertValue(getContext(), value, asType);
|
||||
}
|
||||
return value;
|
||||
} finally {
|
||||
context.remove(THROW_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private Object getValue(String expr, Class asType) throws OgnlException {
|
||||
return ognlUtil.getValue(expr, context, root, asType);
|
||||
}
|
||||
|
||||
protected Object findInContext(String name) {
|
||||
if (!shouldFallbackToContext) {
|
||||
return null;
|
||||
}
|
||||
return getContext().get(name);
|
||||
}
|
||||
|
||||
@@ -505,42 +454,38 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
return root.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retained for serializability - see {@link com.opensymphony.xwork2.ognl.OgnlValueStackTest#testSerializable}
|
||||
*/
|
||||
private Object readResolve() {
|
||||
// TODO: this should be done better
|
||||
ActionContext ac = ActionContext.getContext();
|
||||
Container cont = ac.getContainer();
|
||||
XWorkConverter xworkConverter = cont.getInstance(XWorkConverter.class);
|
||||
RootAccessor accessor = cont.getInstance(RootAccessor.class);
|
||||
CompoundRootAccessor accessor = (CompoundRootAccessor) cont.getInstance(PropertyAccessor.class, CompoundRoot.class.getName());
|
||||
TextProvider prov = cont.getInstance(TextProvider.class, "system");
|
||||
SecurityMemberAccess sma = cont.getInstance(SecurityMemberAccess.class);
|
||||
OgnlValueStack aStack = new OgnlValueStack(xworkConverter, accessor, prov, sma);
|
||||
final boolean allowStaticField = BooleanUtils.toBoolean(cont.getInstance(String.class, StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS));
|
||||
OgnlValueStack aStack = new OgnlValueStack(xworkConverter, accessor, prov, allowStaticField);
|
||||
aStack.setOgnlUtil(cont.getInstance(OgnlUtil.class));
|
||||
aStack.setRoot(xworkConverter, accessor, this.root, sma);
|
||||
aStack.setRoot(xworkConverter, accessor, this.root, allowStaticField);
|
||||
|
||||
return aStack;
|
||||
}
|
||||
|
||||
|
||||
public void clearContextValues() {
|
||||
//this is an OGNL ValueStack so the context will be an OgnlContext
|
||||
//it would be better to make context of type OgnlContext
|
||||
((OgnlContext) context).getValues().clear();
|
||||
}
|
||||
|
||||
public void useAcceptProperties(Set<Pattern> acceptedProperties) {
|
||||
securityMemberAccess.useAcceptProperties(acceptedProperties);
|
||||
public void setAcceptProperties(Set<Pattern> acceptedProperties) {
|
||||
securityMemberAccess.setAcceptProperties(acceptedProperties);
|
||||
}
|
||||
|
||||
public void useExcludeProperties(Set<Pattern> excludeProperties) {
|
||||
securityMemberAccess.useExcludeProperties(excludeProperties);
|
||||
public void setExcludeProperties(Set<Pattern> excludeProperties) {
|
||||
securityMemberAccess.setExcludeProperties(excludeProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
*/
|
||||
@Deprecated
|
||||
@Inject
|
||||
protected void setXWorkConverter(final XWorkConverter converter) {
|
||||
// no-op
|
||||
this.converter = converter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import com.opensymphony.xwork2.conversion.NullHandler;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.ognl.accessor.RootAccessor;
|
||||
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;
|
||||
@@ -35,6 +35,7 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -42,10 +43,8 @@ import java.util.Set;
|
||||
*/
|
||||
public class OgnlValueStackFactory implements ValueStackFactory {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(OgnlValueStackFactory.class);
|
||||
|
||||
protected XWorkConverter xworkConverter;
|
||||
protected RootAccessor compoundRootAccessor;
|
||||
protected CompoundRootAccessor compoundRootAccessor;
|
||||
protected TextProvider textProvider;
|
||||
protected Container container;
|
||||
|
||||
@@ -54,117 +53,62 @@ public class OgnlValueStackFactory implements ValueStackFactory {
|
||||
this.xworkConverter = converter;
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected void setCompoundRootAccessor(RootAccessor compoundRootAccessor) {
|
||||
this.compoundRootAccessor = compoundRootAccessor;
|
||||
OgnlRuntime.setPropertyAccessor(CompoundRoot.class, compoundRootAccessor);
|
||||
OgnlRuntime.setMethodAccessor(CompoundRoot.class, compoundRootAccessor);
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected void setMethodAccessor(MethodAccessor methodAccessor) {
|
||||
OgnlRuntime.setMethodAccessor(Object.class, methodAccessor);
|
||||
}
|
||||
|
||||
@Inject("system")
|
||||
protected void setTextProvider(TextProvider textProvider) {
|
||||
this.textProvider = textProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueStack createValueStack() {
|
||||
return createValueStack(null, true);
|
||||
ValueStack stack = new OgnlValueStack(xworkConverter, compoundRootAccessor, textProvider, containerAllowsStaticFieldAccess());
|
||||
container.inject(stack);
|
||||
return stack.getActionContext()
|
||||
.withContainer(container)
|
||||
.withValueStack(stack)
|
||||
.getValueStack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueStack createValueStack(ValueStack stack) {
|
||||
return createValueStack(stack, false);
|
||||
ValueStack result = new OgnlValueStack(stack, xworkConverter, compoundRootAccessor, containerAllowsStaticFieldAccess());
|
||||
container.inject(result);
|
||||
return result.getActionContext()
|
||||
.withContainer(container)
|
||||
.withValueStack(result)
|
||||
.getValueStack();
|
||||
}
|
||||
|
||||
protected ValueStack createValueStack(ValueStack stack, boolean useTextProvider) {
|
||||
ValueStack newStack = new OgnlValueStack(
|
||||
stack, xworkConverter, compoundRootAccessor, useTextProvider ? textProvider : null, container.getInstance(SecurityMemberAccess.class));
|
||||
container.inject(newStack);
|
||||
return newStack.getActionContext().withContainer(container).withValueStack(newStack).getValueStack();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link PropertyAccessor}'s, {@link MethodAccessor}'s and {@link NullHandler}'s are registered on a per-class
|
||||
* basis by defining a bean adhering to the corresponding interface with a name corresponding to the class it is
|
||||
* intended to handle.
|
||||
* <p>
|
||||
* The only exception is the {@link MethodAccessor} for the {@link Object} type which has its own extension point.
|
||||
*
|
||||
* @see #setMethodAccessor(MethodAccessor)
|
||||
* @see #registerAdditionalMethodAccessors()
|
||||
*/
|
||||
@Inject
|
||||
protected void setContainer(Container container) throws ClassNotFoundException {
|
||||
this.container = container;
|
||||
registerPropertyAccessors();
|
||||
registerNullHandlers();
|
||||
registerAdditionalMethodAccessors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that the default {@link MethodAccessor} for handling {@link Object} methods is registered in
|
||||
* {@link #setMethodAccessor} and can be configured using the extension point
|
||||
* {@link StrutsConstants#STRUTS_METHOD_ACCESSOR}.
|
||||
*/
|
||||
protected void registerAdditionalMethodAccessors() {
|
||||
Set<String> names = container.getInstanceNames(MethodAccessor.class);
|
||||
for (String name : names) {
|
||||
Class<?> cls;
|
||||
try {
|
||||
cls = Class.forName(name);
|
||||
if (cls.equals(Object.class)) {
|
||||
// The Object method accessor can only be configured using the struts.methodAccessor extension point
|
||||
continue;
|
||||
}
|
||||
if (cls.equals(CompoundRoot.class)) {
|
||||
// TODO: This bean is deprecated, please remove this if statement when removing the struts-beans.xml entry
|
||||
continue;
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Since this interface is also used as an extension point for the Object MethodAccessor, we expect
|
||||
// there to be beans with names that don't correspond to classes. We can safely ignore these.
|
||||
continue;
|
||||
}
|
||||
MethodAccessor methodAccessor = container.getInstance(MethodAccessor.class, name);
|
||||
OgnlRuntime.setMethodAccessor(cls, methodAccessor);
|
||||
LOG.debug("Registered custom OGNL MethodAccessor [{}] for class [{}]", methodAccessor.getClass().getName(), cls.getName());
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerNullHandlers() throws ClassNotFoundException {
|
||||
Set<String> names = container.getInstanceNames(NullHandler.class);
|
||||
for (String name : names) {
|
||||
Class<?> cls = Class.forName(name);
|
||||
NullHandler nullHandler = container.getInstance(NullHandler.class, name);
|
||||
OgnlRuntime.setNullHandler(cls, new OgnlNullHandlerWrapper(nullHandler));
|
||||
LOG.debug("Registered custom OGNL NullHandler [{}] for class [{}]", nullHandler.getClass().getName(), cls.getName());
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerPropertyAccessors() throws ClassNotFoundException {
|
||||
Set<String> names = container.getInstanceNames(PropertyAccessor.class);
|
||||
for (String name : names) {
|
||||
Class<?> cls = Class.forName(name);
|
||||
if (cls.equals(CompoundRoot.class)) {
|
||||
// TODO: This bean is deprecated, please remove this if statement when removing the struts-beans.xml entry
|
||||
continue;
|
||||
OgnlRuntime.setPropertyAccessor(cls, container.getInstance(PropertyAccessor.class, name));
|
||||
if (compoundRootAccessor == null && CompoundRoot.class.isAssignableFrom(cls)) {
|
||||
compoundRootAccessor = (CompoundRootAccessor) container.getInstance(PropertyAccessor.class, name);
|
||||
}
|
||||
PropertyAccessor propertyAccessor = container.getInstance(PropertyAccessor.class, name);
|
||||
OgnlRuntime.setPropertyAccessor(cls, propertyAccessor);
|
||||
LOG.debug("Registered custom OGNL PropertyAccessor [{}] for class [{}]", propertyAccessor.getClass().getName(), cls.getName());
|
||||
}
|
||||
|
||||
names = container.getInstanceNames(MethodAccessor.class);
|
||||
for (String name : names) {
|
||||
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);
|
||||
OgnlRuntime.setNullHandler(cls, new OgnlNullHandlerWrapper(container.getInstance(NullHandler.class, name)));
|
||||
}
|
||||
if (compoundRootAccessor == null) {
|
||||
throw new IllegalStateException("Couldn't find the compound root accessor");
|
||||
}
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.4.0, no replacement.
|
||||
* Retrieve allowStaticFieldAccess state from the container (allows for lazy fetching)
|
||||
*/
|
||||
@Deprecated
|
||||
protected boolean containerAllowsStaticFieldAccess() {
|
||||
return BooleanUtils.toBoolean(container.getInstance(String.class, StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,39 +18,21 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.ognl;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.ProxyUtil;
|
||||
import ognl.MemberAccess;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.ognl.ProviderAllowlist;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.opensymphony.xwork2.util.ConfigParseUtil.toClassObjectsSet;
|
||||
import static com.opensymphony.xwork2.util.ConfigParseUtil.toClassesSet;
|
||||
import static com.opensymphony.xwork2.util.ConfigParseUtil.toNewClassesSet;
|
||||
import static com.opensymphony.xwork2.util.ConfigParseUtil.toNewPackageNamesSet;
|
||||
import static com.opensymphony.xwork2.util.ConfigParseUtil.toNewPatternsSet;
|
||||
import static com.opensymphony.xwork2.util.ConfigParseUtil.toPackageNamesSet;
|
||||
import static java.text.MessageFormat.format;
|
||||
import static java.util.Collections.emptySet;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
|
||||
/**
|
||||
* Allows access decisions to be made on the basis of whether a member is static or not.
|
||||
* Also blocks or allows access to properties.
|
||||
@@ -59,39 +41,13 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(SecurityMemberAccess.class);
|
||||
|
||||
private static final Set<String> ALLOWLIST_REQUIRED_PACKAGES = unmodifiableSet(new HashSet<>(Arrays.asList(
|
||||
"com.opensymphony.xwork2.validator.validators",
|
||||
"org.apache.struts2.components",
|
||||
"org.apache.struts2.views.jsp"
|
||||
)));
|
||||
|
||||
private static final Set<Class<?>> ALLOWLIST_REQUIRED_CLASSES = unmodifiableSet(new HashSet<>(Arrays.asList(
|
||||
java.lang.Enum.class,
|
||||
java.lang.String.class,
|
||||
java.util.Date.class,
|
||||
java.util.HashMap.class,
|
||||
java.util.Map.class,
|
||||
java.util.Map.Entry.class
|
||||
)));
|
||||
|
||||
private final ProviderAllowlist providerAllowlist;
|
||||
private boolean allowStaticFieldAccess = true;
|
||||
private Set<Pattern> excludeProperties = emptySet();
|
||||
private Set<Pattern> acceptProperties = emptySet();
|
||||
private Set<String> excludedClasses = unmodifiableSet(new HashSet<>(singletonList(Object.class.getName())));
|
||||
private Set<Pattern> excludedPackageNamePatterns = emptySet();
|
||||
private Set<String> excludedPackageNames = emptySet();
|
||||
private Set<String> excludedPackageExemptClasses = emptySet();
|
||||
private boolean enforceAllowlistEnabled = false;
|
||||
private Set<Class<?>> allowlistClasses = emptySet();
|
||||
private Set<String> allowlistPackageNames = emptySet();
|
||||
private boolean disallowProxyMemberAccess = false;
|
||||
private boolean disallowDefaultPackageAccess = false;
|
||||
|
||||
@Inject
|
||||
public SecurityMemberAccess(@Inject ProviderAllowlist providerAllowlist) {
|
||||
this.providerAllowlist = providerAllowlist;
|
||||
}
|
||||
private final boolean allowStaticFieldAccess;
|
||||
private Set<Pattern> excludeProperties = Collections.emptySet();
|
||||
private Set<Pattern> acceptProperties = Collections.emptySet();
|
||||
private Set<Class<?>> excludedClasses = Collections.emptySet();
|
||||
private Set<Pattern> excludedPackageNamePatterns = Collections.emptySet();
|
||||
private Set<String> excludedPackageNames = Collections.emptySet();
|
||||
private boolean disallowProxyMemberAccess;
|
||||
|
||||
/**
|
||||
* SecurityMemberAccess
|
||||
@@ -99,12 +55,9 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
* - block or allow access to properties (configurable-after-construction)
|
||||
*
|
||||
* @param allowStaticFieldAccess if set to true static fields (constants) will be accessible
|
||||
* @deprecated since 6.4.0, use {@link #SecurityMemberAccess(ProviderAllowlist)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public SecurityMemberAccess(boolean allowStaticFieldAccess) {
|
||||
this(null);
|
||||
useAllowStaticFieldAccess(String.valueOf(allowStaticFieldAccess));
|
||||
this.allowStaticFieldAccess = allowStaticFieldAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,187 +77,86 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
|
||||
@Override
|
||||
public void restore(Map context, Object target, Member member, String propertyName, Object state) {
|
||||
if (state == null) {
|
||||
return;
|
||||
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 + "]");
|
||||
}
|
||||
}
|
||||
if ((Boolean) state) {
|
||||
throw new IllegalArgumentException(format(
|
||||
"Improper restore state [true] for target [{0}], member [{1}], propertyName [{2}]",
|
||||
target,
|
||||
member,
|
||||
propertyName));
|
||||
}
|
||||
((AccessibleObject) member).setAccessible(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccessible(Map context, Object target, Member member, String propertyName) {
|
||||
LOG.debug("Checking access for [target: {}, member: {}, property: {}]", target, member, propertyName);
|
||||
|
||||
if (target != null) {
|
||||
// Special case: Target is a Class object but not Class.class
|
||||
if (Class.class.equals(target.getClass()) && !Class.class.equals(target)) {
|
||||
if (!isStatic(member)) {
|
||||
throw new IllegalArgumentException("Member expected to be static!");
|
||||
}
|
||||
if (!member.getDeclaringClass().equals(target)) {
|
||||
throw new IllegalArgumentException("Target class does not match static member!");
|
||||
}
|
||||
target = null; // This information is not useful to us and conflicts with following logic which expects target to be null or an instance containing the member
|
||||
// Standard case: Member should exist on target
|
||||
} else if (!member.getDeclaringClass().isAssignableFrom(target.getClass())) {
|
||||
throw new IllegalArgumentException("Member does not exist on target!");
|
||||
}
|
||||
}
|
||||
final int memberModifiers = member.getModifiers();
|
||||
|
||||
if (!checkProxyMemberAccess(target, member)) {
|
||||
LOG.warn("Access to proxy is blocked! Member class [{}] of target [{}], member [{}]", member.getDeclaringClass(), target, member);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!checkPublicMemberAccess(member)) {
|
||||
if (!checkPublicMemberAccess(memberModifiers)) {
|
||||
LOG.warn("Access to non-public [{}] is blocked!", member);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!checkStaticFieldAccess(member)) {
|
||||
if (!checkStaticFieldAccess(member, memberModifiers)) {
|
||||
LOG.warn("Access to static field [{}] is blocked!", member);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!checkStaticMethodAccess(member)) {
|
||||
// it needs to be before calling #checkStaticMethodAccess()
|
||||
if (checkEnumAccess(target, member)) {
|
||||
LOG.trace("Allowing access to enum: target [{}], member [{}]", target, member);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!checkStaticMethodAccess(member, memberModifiers)) {
|
||||
LOG.warn("Access to static method [{}] is blocked!", member);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!checkDefaultPackageAccess(target, member)) {
|
||||
return false;
|
||||
}
|
||||
final Class<?> memberClass = member.getDeclaringClass();
|
||||
|
||||
if (!checkExclusionList(target, member)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!checkAllowlist(target, member)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isAcceptableProperty(propertyName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if member access is allowed
|
||||
*/
|
||||
protected boolean checkAllowlist(Object target, Member member) {
|
||||
Class<?> memberClass = member.getDeclaringClass();
|
||||
if (!enforceAllowlistEnabled) {
|
||||
return true;
|
||||
}
|
||||
if (!isClassAllowlisted(memberClass)) {
|
||||
LOG.warn(format("Declaring class [{0}] of member type [{1}] is not allowlisted!", memberClass, member));
|
||||
return false;
|
||||
}
|
||||
if (target == null || target.getClass() == memberClass) {
|
||||
return true;
|
||||
}
|
||||
Class<?> targetClass = target.getClass();
|
||||
if (!isClassAllowlisted(targetClass)) {
|
||||
LOG.warn(format("Target class [{0}] of target [{1}] is not allowlisted!", targetClass, target));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isClassAllowlisted(Class<?> clazz) {
|
||||
return allowlistClasses.contains(clazz)
|
||||
|| ALLOWLIST_REQUIRED_CLASSES.contains(clazz)
|
||||
|| (providerAllowlist != null && providerAllowlist.getProviderAllowlist().contains(clazz))
|
||||
|| isClassBelongsToPackages(clazz, ALLOWLIST_REQUIRED_PACKAGES)
|
||||
|| isClassBelongsToPackages(clazz, allowlistPackageNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if member access is allowed
|
||||
*/
|
||||
protected boolean checkExclusionList(Object target, Member member) {
|
||||
Class<?> memberClass = member.getDeclaringClass();
|
||||
if (isClassExcluded(memberClass)) {
|
||||
LOG.warn("Declaring class of member type [{}] is excluded!", memberClass);
|
||||
LOG.warn("Declaring class of member type [{}] is excluded!", member);
|
||||
return false;
|
||||
}
|
||||
if (isPackageExcluded(memberClass)) {
|
||||
LOG.warn("Package [{}] of member class [{}] of member [{}] is excluded!",
|
||||
memberClass.getPackage(),
|
||||
memberClass,
|
||||
target);
|
||||
|
||||
// target can be null in case of accessing static fields, since OGNL 3.2.8
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
if (target == null || target.getClass() == memberClass) {
|
||||
return true;
|
||||
}
|
||||
Class<?> targetClass = target.getClass();
|
||||
|
||||
if (isClassExcluded(targetClass)) {
|
||||
LOG.warn("Target class [{}] of target [{}] is excluded!", targetClass, target);
|
||||
return false;
|
||||
}
|
||||
if (isPackageExcluded(targetClass)) {
|
||||
LOG.warn("Package [{}] of target [{}] is excluded!", targetClass.getPackage(), member);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if member access is allowed
|
||||
*/
|
||||
protected boolean checkDefaultPackageAccess(Object target, Member member) {
|
||||
if (!disallowDefaultPackageAccess) {
|
||||
return true;
|
||||
}
|
||||
Class<?> memberClass = member.getDeclaringClass();
|
||||
if (memberClass.getPackage() == null || memberClass.getPackage().getName().isEmpty()) {
|
||||
LOG.warn("Class [{}] from the default package is excluded!", memberClass);
|
||||
if (disallowProxyMemberAccess && ProxyUtil.isProxyMember(member, target)) {
|
||||
LOG.warn("Access to proxy is blocked! Target class [{}] of target [{}], member [{}]", targetClass, target, member);
|
||||
return false;
|
||||
}
|
||||
if (target == null || target.getClass() == memberClass) {
|
||||
return true;
|
||||
}
|
||||
Class<?> targetClass = target.getClass();
|
||||
if (targetClass.getPackage() == null || targetClass.getPackage().getName().isEmpty()) {
|
||||
LOG.warn("Class [{}] from the default package is excluded!", targetClass);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if member access is allowed
|
||||
*/
|
||||
protected boolean checkProxyMemberAccess(Object target, Member member) {
|
||||
return !(disallowProxyMemberAccess && ProxyUtil.isProxyMember(member, target));
|
||||
return isAcceptableProperty(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check access for static method (via modifiers).
|
||||
* <p>
|
||||
*
|
||||
* Note: For non-static members, the result is always true.
|
||||
*
|
||||
* @return {@code true} if member access is allowed
|
||||
* @param member
|
||||
* @param memberModifiers
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected boolean checkStaticMethodAccess(Member member) {
|
||||
if (checkEnumAccess(member)) {
|
||||
LOG.trace("Exempting Enum#values from static method check: class [{}]", member.getDeclaringClass());
|
||||
return true;
|
||||
}
|
||||
return member instanceof Field || !isStatic(member);
|
||||
}
|
||||
|
||||
private static boolean isStatic(Member member) {
|
||||
return Modifier.isStatic(member.getModifiers());
|
||||
protected boolean checkStaticMethodAccess(Member member, int memberModifiers) {
|
||||
return !Modifier.isStatic(memberModifiers) || member instanceof Field;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,145 +164,130 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
* <p>
|
||||
* Note: For non-static members, the result is always true.
|
||||
*
|
||||
* @return {@code true} if member access is allowed
|
||||
* @param member
|
||||
* @param memberModifiers
|
||||
* @return
|
||||
*/
|
||||
protected boolean checkStaticFieldAccess(Member member) {
|
||||
if (allowStaticFieldAccess) {
|
||||
protected boolean checkStaticFieldAccess(Member member, int memberModifiers) {
|
||||
if (Modifier.isStatic(memberModifiers) && member instanceof Field) {
|
||||
return allowStaticFieldAccess;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return !(member instanceof Field) || !isStatic(member);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check access for public members (via modifiers)
|
||||
* <p>
|
||||
* Returns true if-and-only-if the member is public.
|
||||
*
|
||||
* @return {@code true} if member access is allowed
|
||||
* @param memberModifiers
|
||||
* @return
|
||||
*/
|
||||
protected boolean checkPublicMemberAccess(Member member) {
|
||||
return Modifier.isPublic(member.getModifiers());
|
||||
protected boolean checkPublicMemberAccess(int memberModifiers) {
|
||||
return Modifier.isPublic(memberModifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if member access is allowed
|
||||
*/
|
||||
protected boolean checkEnumAccess(Member member) {
|
||||
return member.getDeclaringClass().isEnum()
|
||||
&& isStatic(member)
|
||||
&& member instanceof Method
|
||||
&& member.getName().equals("values")
|
||||
&& ((Method) member).getParameterCount() == 0;
|
||||
}
|
||||
|
||||
protected boolean isPackageExcluded(Class<?> clazz) {
|
||||
return !excludedPackageExemptClasses.contains(clazz.getName()) && (isExcludedPackageNames(clazz) || isExcludedPackageNamePatterns(clazz));
|
||||
}
|
||||
|
||||
public static String toPackageName(Class<?> clazz) {
|
||||
if (clazz.getPackage() == null) {
|
||||
return "";
|
||||
protected boolean checkEnumAccess(Object target, Member member) {
|
||||
if (target instanceof Class) {
|
||||
final Class<?> clazz = (Class<?>) target;
|
||||
return Enum.class.isAssignableFrom(clazz) && member.getName().equals("values");
|
||||
}
|
||||
return clazz.getPackage().getName();
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isExcludedPackageNamePatterns(Class<?> clazz) {
|
||||
return excludedPackageNamePatterns.stream().anyMatch(pattern -> pattern.matcher(toPackageName(clazz)).matches());
|
||||
protected boolean isPackageExcluded(Package targetPackage, Package memberPackage) {
|
||||
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();
|
||||
|
||||
for (Pattern pattern : excludedPackageNamePatterns) {
|
||||
if (pattern.matcher(targetPackageName).matches() || pattern.matcher(memberPackageName).matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
targetPackageName = targetPackageName + ".";
|
||||
memberPackageName = memberPackageName + ".";
|
||||
|
||||
for (String packageName : excludedPackageNames) {
|
||||
if (targetPackageName.startsWith(packageName) || memberPackageName.startsWith(packageName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isExcludedPackageNames(Class<?> clazz) {
|
||||
return isClassBelongsToPackages(clazz, excludedPackageNames);
|
||||
}
|
||||
|
||||
public static boolean isClassBelongsToPackages(Class<?> clazz, Set<String> matchingPackages) {
|
||||
List<String> packageParts = Arrays.asList(toPackageName(clazz).split("\\."));
|
||||
for (int i = 0; i < packageParts.size(); i++) {
|
||||
String parentPackage = String.join(".", packageParts.subList(0, i + 1));
|
||||
if (matchingPackages.contains(parentPackage)) {
|
||||
protected boolean isClassExcluded(Class<?> clazz) {
|
||||
if (clazz == Object.class || (clazz == Class.class && !allowStaticFieldAccess)) {
|
||||
return true;
|
||||
}
|
||||
for (Class<?> excludedClass : excludedClasses) {
|
||||
if (clazz.isAssignableFrom(excludedClass)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isClassExcluded(Class<?> clazz) {
|
||||
return excludedClasses.contains(clazz.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if member access is allowed
|
||||
*/
|
||||
protected boolean isAcceptableProperty(String name) {
|
||||
return name == null || !isExcluded(name) && isAccepted(name);
|
||||
return name == null || ((!isExcluded(name)) && isAccepted(name));
|
||||
}
|
||||
|
||||
protected boolean isAccepted(String paramName) {
|
||||
if (acceptProperties.isEmpty()) {
|
||||
return true;
|
||||
if (!this.acceptProperties.isEmpty()) {
|
||||
for (Pattern pattern : acceptProperties) {
|
||||
Matcher matcher = pattern.matcher(paramName);
|
||||
if (matcher.matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//no match, but acceptedParams is not empty
|
||||
return false;
|
||||
}
|
||||
return acceptProperties.stream().map(pattern -> pattern.matcher(paramName)).anyMatch(Matcher::matches);
|
||||
|
||||
//empty acceptedParams
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isExcluded(String paramName) {
|
||||
return excludeProperties.stream().map(pattern -> pattern.matcher(paramName)).anyMatch(Matcher::matches);
|
||||
if (!this.excludeProperties.isEmpty()) {
|
||||
for (Pattern pattern : excludeProperties) {
|
||||
Matcher matcher = pattern.matcher(paramName);
|
||||
if (matcher.matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void useExcludeProperties(Set<Pattern> excludeProperties) {
|
||||
public void setExcludeProperties(Set<Pattern> excludeProperties) {
|
||||
this.excludeProperties = excludeProperties;
|
||||
}
|
||||
|
||||
public void useAcceptProperties(Set<Pattern> acceptedProperties) {
|
||||
public void setAcceptProperties(Set<Pattern> acceptedProperties) {
|
||||
this.acceptProperties = acceptedProperties;
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_ALLOW_STATIC_FIELD_ACCESS, required = false)
|
||||
public void useAllowStaticFieldAccess(String allowStaticFieldAccess) {
|
||||
this.allowStaticFieldAccess = BooleanUtils.toBoolean(allowStaticFieldAccess);
|
||||
if (!this.allowStaticFieldAccess) {
|
||||
useExcludedClasses(Class.class.getName());
|
||||
}
|
||||
public void setExcludedClasses(Set<Class<?>> excludedClasses) {
|
||||
this.excludedClasses = excludedClasses;
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_EXCLUDED_CLASSES, required = false)
|
||||
public void useExcludedClasses(String commaDelimitedClasses) {
|
||||
this.excludedClasses = toNewClassesSet(excludedClasses, commaDelimitedClasses);
|
||||
public void setExcludedPackageNamePatterns(Set<Pattern> excludedPackageNamePatterns) {
|
||||
this.excludedPackageNamePatterns = excludedPackageNamePatterns;
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAME_PATTERNS, required = false)
|
||||
public void useExcludedPackageNamePatterns(String commaDelimitedPackagePatterns) {
|
||||
this.excludedPackageNamePatterns = toNewPatternsSet(excludedPackageNamePatterns, commaDelimitedPackagePatterns);
|
||||
public void setExcludedPackageNames(Set<String> excludedPackageNames) {
|
||||
this.excludedPackageNames = excludedPackageNames;
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAMES, required = false)
|
||||
public void useExcludedPackageNames(String commaDelimitedPackageNames) {
|
||||
this.excludedPackageNames = toNewPackageNamesSet(excludedPackageNames, commaDelimitedPackageNames);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_EXCLUDED_PACKAGE_EXEMPT_CLASSES, required = false)
|
||||
public void useExcludedPackageExemptClasses(String commaDelimitedClasses) {
|
||||
this.excludedPackageExemptClasses = toClassesSet(commaDelimitedClasses);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_ALLOWLIST_ENABLE, required = false)
|
||||
public void useEnforceAllowlistEnabled(String enforceAllowlistEnabled) {
|
||||
this.enforceAllowlistEnabled = BooleanUtils.toBoolean(enforceAllowlistEnabled);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_ALLOWLIST_CLASSES, required = false)
|
||||
public void useAllowlistClasses(String commaDelimitedClasses) {
|
||||
this.allowlistClasses = toClassObjectsSet(commaDelimitedClasses);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_ALLOWLIST_PACKAGE_NAMES, required = false)
|
||||
public void useAllowlistPackageNames(String commaDelimitedPackageNames) {
|
||||
this.allowlistPackageNames = toPackageNamesSet(commaDelimitedPackageNames);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_DISALLOW_PROXY_MEMBER_ACCESS, required = false)
|
||||
public void useDisallowProxyMemberAccess(String disallowProxyMemberAccess) {
|
||||
this.disallowProxyMemberAccess = BooleanUtils.toBoolean(disallowProxyMemberAccess);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_DISALLOW_DEFAULT_PACKAGE_ACCESS, required = false)
|
||||
public void useDisallowDefaultPackageAccess(String disallowDefaultPackageAccess) {
|
||||
this.disallowDefaultPackageAccess = BooleanUtils.toBoolean(disallowDefaultPackageAccess);
|
||||
public void setDisallowProxyMemberAccess(boolean disallowProxyMemberAccess) {
|
||||
this.disallowProxyMemberAccess = disallowProxyMemberAccess;
|
||||
}
|
||||
}
|
||||
|
||||
+17
-49
@@ -22,12 +22,7 @@ import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.ognl.OgnlValueStack;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import ognl.MethodFailedException;
|
||||
import ognl.NoSuchPropertyException;
|
||||
import ognl.Ognl;
|
||||
import ognl.OgnlContext;
|
||||
import ognl.OgnlException;
|
||||
import ognl.OgnlRuntime;
|
||||
import ognl.*;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -36,11 +31,7 @@ import org.apache.struts2.StrutsException;
|
||||
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static java.lang.String.format;
|
||||
@@ -53,12 +44,11 @@ import static org.apache.commons.lang3.BooleanUtils.toBoolean;
|
||||
* @author Rainer Hermanns
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class CompoundRootAccessor implements RootAccessor {
|
||||
public class CompoundRootAccessor implements PropertyAccessor, MethodAccessor, ClassResolver {
|
||||
|
||||
/**
|
||||
* Used by OGNl to generate bytecode
|
||||
*/
|
||||
@Override
|
||||
public String getSourceAccessor(OgnlContext context, Object target, Object index) {
|
||||
return null;
|
||||
}
|
||||
@@ -66,28 +56,20 @@ public class CompoundRootAccessor implements RootAccessor {
|
||||
/**
|
||||
* Used by OGNl to generate bytecode
|
||||
*/
|
||||
@Override
|
||||
public String getSourceSetter(OgnlContext context, Object target, Object index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private final static Logger LOG = LogManager.getLogger(CompoundRootAccessor.class);
|
||||
private final static Class[] EMPTY_CLASS_ARRAY = new Class[0];
|
||||
private static final Map<MethodCall, Boolean> invalidMethods = new ConcurrentHashMap<>();
|
||||
private static Map<MethodCall, Boolean> invalidMethods = new ConcurrentHashMap<>();
|
||||
private boolean devMode;
|
||||
private boolean disallowCustomOgnlMap;
|
||||
|
||||
@Inject(StrutsConstants.STRUTS_DEVMODE)
|
||||
protected void setDevMode(String mode) {
|
||||
this.devMode = BooleanUtils.toBoolean(mode);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_DISALLOW_CUSTOM_OGNL_MAP, required = false)
|
||||
public void useDisallowCustomOgnlMap(String disallowCustomOgnlMap) {
|
||||
this.disallowCustomOgnlMap = BooleanUtils.toBoolean(disallowCustomOgnlMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException {
|
||||
CompoundRoot root = (CompoundRoot) target;
|
||||
OgnlContext ognlContext = (OgnlContext) context;
|
||||
@@ -136,7 +118,6 @@ public class CompoundRootAccessor implements RootAccessor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(Map context, Object target, Object name) throws OgnlException {
|
||||
CompoundRoot root = (CompoundRoot) target;
|
||||
OgnlContext ognlContext = (OgnlContext) context;
|
||||
@@ -146,7 +127,7 @@ public class CompoundRootAccessor implements RootAccessor {
|
||||
return root.cutStack(index);
|
||||
} else if (name instanceof String) {
|
||||
if ("top".equals(name)) {
|
||||
if (!root.isEmpty()) {
|
||||
if (root.size() > 0) {
|
||||
return root.get(0);
|
||||
} else {
|
||||
return null;
|
||||
@@ -182,7 +163,6 @@ public class CompoundRootAccessor implements RootAccessor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object callMethod(Map context, Object target, String name, Object[] objects) throws MethodFailedException {
|
||||
CompoundRoot root = (CompoundRoot) target;
|
||||
|
||||
@@ -210,23 +190,26 @@ public class CompoundRootAccessor implements RootAccessor {
|
||||
}
|
||||
|
||||
SortedSet<String> set = new TreeSet<>();
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (PropertyDescriptor pd : descriptors.values()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(pd.getName()).append(": ");
|
||||
|
||||
sb.append(pd.getName()).append(": ");
|
||||
int padding = maxSize - pd.getName().length();
|
||||
for (int i = 0; i < padding; i++) {
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append(pd.getPropertyType().getName());
|
||||
set.add(sb.toString());
|
||||
|
||||
sb = new StringBuffer();
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String aSet : set) {
|
||||
sb.append(aSet).append("\n");
|
||||
sb = new StringBuffer();
|
||||
for (Object aSet : set) {
|
||||
String s = (String) aSet;
|
||||
sb.append(s).append("\n");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
} catch (IntrospectionException | OgnlException e) {
|
||||
LOG.debug("Got exception in callMethod", e);
|
||||
@@ -275,23 +258,13 @@ public class CompoundRootAccessor implements RootAccessor {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object callStaticMethod(Map transientVars, Class aClass, String s, Object[] objects) throws MethodFailedException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class classForName(String className, Map context) throws ClassNotFoundException {
|
||||
Object root = Ognl.getRoot(context);
|
||||
|
||||
if (disallowCustomOgnlMap) {
|
||||
String nodeClassName = ((OgnlContext) context).getCurrentNode().getClass().getName();
|
||||
if ("ognl.ASTMap".equals(nodeClassName)) {
|
||||
LOG.error("Constructing OGNL ASTMap's from custom classes is forbidden. Attempted class: {}", className);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (root instanceof CompoundRoot) {
|
||||
if (className.startsWith("vs")) {
|
||||
@@ -348,14 +321,9 @@ public class CompoundRootAccessor implements RootAccessor {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof MethodCall)) {
|
||||
return false;
|
||||
}
|
||||
MethodCall mc = (MethodCall) obj;
|
||||
return mc.clazz.equals(clazz) && mc.name.equals(name) && Arrays.equals(mc.args, args);
|
||||
MethodCall mc = (CompoundRootAccessor.MethodCall) obj;
|
||||
|
||||
return (mc.clazz.equals(clazz) && mc.name.equals(name) && Arrays.equals(mc.args, args));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,29 +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 com.opensymphony.xwork2.ognl.accessor;
|
||||
|
||||
import ognl.ClassResolver;
|
||||
import ognl.MethodAccessor;
|
||||
import ognl.PropertyAccessor;
|
||||
|
||||
/**
|
||||
* @since 6.4.0
|
||||
*/
|
||||
public interface RootAccessor extends PropertyAccessor, MethodAccessor, ClassResolver {
|
||||
}
|
||||
@@ -32,37 +32,37 @@ public interface AcceptedPatternsChecker {
|
||||
* @param value to check
|
||||
* @return object containing result of matched pattern and pattern itself
|
||||
*/
|
||||
IsAccepted isAccepted(String value);
|
||||
public IsAccepted isAccepted(String value);
|
||||
|
||||
/**
|
||||
* Sets excluded patterns during runtime
|
||||
*
|
||||
* @param commaDelimitedPatterns comma delimited string with patterns
|
||||
*/
|
||||
void setAcceptedPatterns(String commaDelimitedPatterns);
|
||||
public void setAcceptedPatterns(String commaDelimitedPatterns);
|
||||
|
||||
/**
|
||||
* Set excluded patterns during runtime
|
||||
*
|
||||
* @param patterns array of additional excluded patterns
|
||||
*/
|
||||
void setAcceptedPatterns(String[] patterns);
|
||||
public void setAcceptedPatterns(String[] patterns);
|
||||
|
||||
/**
|
||||
* Sets excluded patterns during runtime
|
||||
*
|
||||
* @param patterns set of additional patterns
|
||||
*/
|
||||
void setAcceptedPatterns(Set<String> patterns);
|
||||
public void setAcceptedPatterns(Set<String> patterns);
|
||||
|
||||
/**
|
||||
* Allow access list of all defined excluded patterns
|
||||
*
|
||||
* @return set of excluded patterns
|
||||
*/
|
||||
Set<Pattern> getAcceptedPatterns();
|
||||
public Set<Pattern> getAcceptedPatterns();
|
||||
|
||||
final class IsAccepted {
|
||||
public final static class IsAccepted {
|
||||
|
||||
private final boolean accepted;
|
||||
private final String acceptedPattern;
|
||||
|
||||
+25
-20
@@ -43,7 +43,7 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
|
||||
"\\w+([:]?\\w+)?((\\.\\w+)|(\\[\\d+])|(\\(\\d+\\))|(\\['(\\w-?|[\\u4e00-\\u9fa5]-?)+'])|(\\('(\\w-?|[\\u4e00-\\u9fa5]-?)+'\\)))*([!]?\\w+)?"
|
||||
};
|
||||
|
||||
protected Set<Pattern> acceptedPatterns;
|
||||
private Set<Pattern> acceptedPatterns;
|
||||
|
||||
public DefaultAcceptedPatternsChecker() {
|
||||
setAcceptedPatterns(ACCEPTED_PATTERNS);
|
||||
@@ -62,19 +62,28 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_OVERRIDE_ACCEPTED_PATTERNS, required = false)
|
||||
protected void setOverrideAcceptedPatterns(String acceptablePatterns) {
|
||||
setAcceptedPatterns(acceptablePatterns);
|
||||
LOG.warn("Overriding accepted patterns [{}] with [{}], be aware that this affects all instances and safety of your application!",
|
||||
acceptedPatterns, acceptablePatterns);
|
||||
acceptedPatterns = new HashSet<>();
|
||||
try {
|
||||
for (String pattern : TextParseUtil.commaDelimitedStringToSet(acceptablePatterns)) {
|
||||
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
acceptedPatterns = Collections.unmodifiableSet(acceptedPatterns);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_ADDITIONAL_ACCEPTED_PATTERNS, required = false)
|
||||
protected void setAdditionalAcceptedPatterns(String acceptablePatterns) {
|
||||
LOG.warn("Adding additional global patterns [{}] to accepted patterns!", acceptablePatterns);
|
||||
Set<Pattern> newAcceptedPatterns = new HashSet<>(acceptedPatterns);
|
||||
acceptedPatterns = new HashSet<>(acceptedPatterns); // Make mutable before adding
|
||||
try {
|
||||
for (String pattern : TextParseUtil.commaDelimitedStringToSet(acceptablePatterns)) {
|
||||
newAcceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
acceptedPatterns = Collections.unmodifiableSet(newAcceptedPatterns);
|
||||
acceptedPatterns = Collections.unmodifiableSet(acceptedPatterns);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,24 +99,20 @@ public class DefaultAcceptedPatternsChecker implements AcceptedPatternsChecker {
|
||||
|
||||
@Override
|
||||
public void setAcceptedPatterns(Set<String> patterns) {
|
||||
logPatternChange(patterns);
|
||||
Set<Pattern> newAcceptedPatterns = new HashSet<>(patterns.size());
|
||||
try {
|
||||
for (String pattern : patterns) {
|
||||
newAcceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
acceptedPatterns = Collections.unmodifiableSet(newAcceptedPatterns);
|
||||
}
|
||||
}
|
||||
|
||||
protected void logPatternChange(Set<String> newPatterns) {
|
||||
if (acceptedPatterns == null) {
|
||||
// No need to warn on class initialisation
|
||||
LOG.debug("Sets accepted patterns to [{}], note this impacts the safety of your application!", newPatterns);
|
||||
// Limit unwanted log entries (for 1st call, acceptedPatterns null)
|
||||
LOG.debug("Sets accepted patterns to [{}], note this impacts the safety of your application!", patterns);
|
||||
} else {
|
||||
LOG.warn("Replacing accepted patterns [{}] with [{}], be aware that this affects all instances and safety of your application!",
|
||||
acceptedPatterns, newPatterns);
|
||||
acceptedPatterns, patterns);
|
||||
}
|
||||
acceptedPatterns = new HashSet<>(patterns.size());
|
||||
try {
|
||||
for (String pattern : patterns) {
|
||||
acceptedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
acceptedPatterns = Collections.unmodifiableSet(acceptedPatterns);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-5
@@ -36,9 +36,8 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
|
||||
private static final Logger LOG = LogManager.getLogger(DefaultExcludedPatternsChecker.class);
|
||||
|
||||
public static final String[] EXCLUDED_PATTERNS = {
|
||||
"(^|\\%\\{)((#?)(top(\\.|\\['|\\[\")|\\[\\d\\]\\.)?)(dojo|struts|session|request|response|application|servlet(Request|Response|Context)|parameters|context|_memberAccess)(\\.|\\[).*",
|
||||
".*(^|\\.|\\[|\\'|\"|get)class(\\(\\.|\\[|\\'|\").*",
|
||||
"actionErrors|actionMessages|fieldErrors"
|
||||
"(^|\\%\\{)((#?)(top(\\.|\\['|\\[\")|\\[\\d\\]\\.)?)(dojo|struts|session|request|response|application|servlet(Request|Response|Context)|parameters|context|_memberAccess)(\\.|\\[).*",
|
||||
".*(^|\\.|\\[|\\'|\"|get)class(\\(\\.|\\[|\\'|\").*"
|
||||
};
|
||||
|
||||
private Set<Pattern> excludedPatterns;
|
||||
@@ -49,7 +48,21 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_OVERRIDE_EXCLUDED_PATTERNS, required = false)
|
||||
protected void setOverrideExcludePatterns(String excludePatterns) {
|
||||
setExcludedPatterns(excludePatterns);
|
||||
if (excludedPatterns != null && excludedPatterns.size() > 0) {
|
||||
LOG.warn("Overriding excluded patterns [{}] with [{}], be aware that this affects all instances and safety of your application!",
|
||||
excludedPatterns, excludePatterns);
|
||||
} else {
|
||||
// Limit unwanted log entries (when excludedPatterns null/empty - usually 1st call)
|
||||
LOG.debug("Overriding excluded patterns with [{}]", excludePatterns);
|
||||
}
|
||||
excludedPatterns = new HashSet<>();
|
||||
try {
|
||||
for (String pattern : TextParseUtil.commaDelimitedStringToSet(excludePatterns)) {
|
||||
excludedPatterns.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
|
||||
}
|
||||
} finally {
|
||||
excludedPatterns = Collections.unmodifiableSet(excludedPatterns);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_ADDITIONAL_EXCLUDED_PATTERNS, required = false)
|
||||
@@ -85,7 +98,7 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
|
||||
|
||||
@Override
|
||||
public void setExcludedPatterns(Set<String> patterns) {
|
||||
if (excludedPatterns != null && !excludedPatterns.isEmpty()) {
|
||||
if (excludedPatterns != null && excludedPatterns.size() > 0) {
|
||||
LOG.warn("Replacing excluded patterns [{}] with [{}], be aware that this affects all instances and safety of your application!",
|
||||
excludedPatterns, patterns);
|
||||
} else {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user