mirror of
https://github.com/apache/struts.git
synced 2026-08-07 23:57:03 +00:00
Compare commits
136 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a054e9259c | |||
| 6d8cf56977 | |||
| 7b7d3ca0e1 | |||
| 3292152f8c | |||
| 28498a807d | |||
| 2d6f1bc0a6 | |||
| 36e4e7410e | |||
| e903739624 | |||
| a85328e74e | |||
| c3deb39237 | |||
| 483a0c8d01 | |||
| f5c0aa5f3a | |||
| a77a80a803 | |||
| 4d58dd1960 | |||
| 09da11ba06 | |||
| bcfa8113ac | |||
| 65ae2b7e4f | |||
| 1af3e31548 | |||
| 18a72c3dff | |||
| 6ea50122d6 | |||
| ea7fba2846 | |||
| 4ab427f2f2 | |||
| 0a30eb44e6 | |||
| 138a8d74f0 | |||
| 341a8f20e0 | |||
| 9a431ea470 | |||
| 0fe27a673d | |||
| 35a50ea836 | |||
| 927c58b7d3 | |||
| ac168968a0 | |||
| 5a30cdbede | |||
| bfcc0b5898 | |||
| 4a51aacf40 | |||
| 728edbef56 | |||
| 6135a71335 | |||
| 6330bb1ce3 | |||
| 4a585347ed | |||
| 4bb81d5909 | |||
| 054f1f4cdb | |||
| 79a84a8f02 | |||
| 2660aaec56 | |||
| 34aeeded55 | |||
| 8d2d996056 | |||
| 6658c6360e | |||
| 9c078aef14 | |||
| eb51594ed3 | |||
| b536136191 | |||
| c74287f741 | |||
| 9e7e0b395d | |||
| 784293e46f | |||
| 58dcc830ea | |||
| 936481e7ea | |||
| a02cc6507c | |||
| 084c257d6e | |||
| 94a0c6e425 | |||
| 3e30d0c375 | |||
| 9568888700 | |||
| 943cb62953 | |||
| 79d6c07a57 | |||
| 7064c53f5c | |||
| 3fdb918127 | |||
| 1069cf8c09 | |||
| c41f05fe68 | |||
| 993c4c4cab | |||
| 01164c4d74 | |||
| 738d27952f | |||
| 984f8eff2e | |||
| 802afb0cc0 | |||
| 339c30320a | |||
| a562f8f806 | |||
| ac13c32bdb | |||
| bb71610296 | |||
| 3d7f66f428 | |||
| 50842e8d19 | |||
| cca986df35 | |||
| 511ec62105 | |||
| 2cb0d28960 | |||
| e783d18715 | |||
| 864f513365 | |||
| 9dd2560172 | |||
| 415e0fbd44 | |||
| 26effbf05d | |||
| 4c8cc361d5 | |||
| a21bd994eb | |||
| 8f0db1d22a | |||
| 58f287bf4a | |||
| e0da03c262 | |||
| 04cf1dae5f | |||
| 5338b44c23 | |||
| 2217e2c1ca | |||
| cbfd3a7ab9 | |||
| 097297affd | |||
| ddfaa1683c | |||
| ddbd02e6bb | |||
| 6887ef900b | |||
| 326de812ac | |||
| 32201b2ef2 | |||
| a4fe51f5b3 | |||
| 3774ffa7c3 | |||
| cf2078d1de | |||
| 7183d32caf | |||
| e0e7e3cb20 | |||
| eb68368280 | |||
| 296b3cc89c | |||
| 9fb86054bb | |||
| 0fc71949ca | |||
| 9faa002fa7 | |||
| 88bc5c6802 | |||
| dc1a663d69 | |||
| 36ac23acf5 | |||
| 6b2cc20b2d | |||
| ab22c7377d | |||
| 062b76718b | |||
| dc5dac7be2 | |||
| 6334a3e19e | |||
| 858f19557d | |||
| d97fa1eb38 | |||
| b9cd7d8159 | |||
| 03edeee0d8 | |||
| f04b68db03 | |||
| 7b655207ec | |||
| c9c39130f6 | |||
| 12beb20949 | |||
| a5899726a0 | |||
| 22a80f9c51 | |||
| 854572905e | |||
| b40f3efc74 | |||
| 980387e91c | |||
| 5a3d2c4eb9 | |||
| 8514406142 | |||
| bbb5b6bb37 | |||
| ce2975e2f0 | |||
| 49240c50a2 | |||
| 584634a9b5 | |||
| 5763476830 | |||
| 105b22fb9a |
@@ -12,3 +12,5 @@ notifications:
|
||||
|
||||
github:
|
||||
del_branch_on_merge: true
|
||||
protected_branches:
|
||||
master: { }
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# 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: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'java' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
@@ -0,0 +1,57 @@
|
||||
# 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: Java Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
env:
|
||||
MAVEN_OPTS: -Xmx2048m -Xms1024m
|
||||
LANG: en_US.utf8
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
java: [ '8', '11', '17' ]
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3.0.2
|
||||
- name: Set up cache
|
||||
uses: actions/cache@v3.0.8
|
||||
with:
|
||||
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 }}
|
||||
- name: Build with Maven on Java ${{ matrix.java }}
|
||||
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
|
||||
@@ -0,0 +1,69 @@
|
||||
# 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: "Scorecards supply-chain security"
|
||||
|
||||
on:
|
||||
branch_protection_rule:
|
||||
schedule:
|
||||
- cron: "30 1 * * 6" # Weekly on Saturdays
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
|
||||
analysis:
|
||||
|
||||
name: "Scorecards analysis"
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# Needed to upload the results to the code-scanning dashboard.
|
||||
security-events: write
|
||||
actions: read
|
||||
id-token: write # This is required for requesting the JWT
|
||||
contents: read # This is required for actions/checkout
|
||||
|
||||
steps:
|
||||
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # 3.1.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@99c53751e09b9529366343771cc321ec74e9bd3d # 2.0.6
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
# A read-only PAT token, which is sufficient for the action to function.
|
||||
# The relevant discussion: https://github.com/ossf/scorecard-action/issues/188
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# Publish the results for public repositories to enable scorecard badges.
|
||||
# For more details: https://github.com/ossf/scorecard-action#publishing-results
|
||||
publish_results: true
|
||||
|
||||
- name: "Upload artifact"
|
||||
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@b398f525a5587552e573b247ac661067fafa920b # 2.1.22
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
dist: jammy
|
||||
language: java
|
||||
sudo: false
|
||||
|
||||
jdk:
|
||||
- openjdk11
|
||||
- openjdk17
|
||||
|
||||
install: true
|
||||
|
||||
env:
|
||||
global:
|
||||
- secure: iI7IpfDtS+LUyS2yNuRCR3KelNyvBHuoMQ3gb1UNmR5SSL7jO/p3olQWrQROs28FJ+dpE3lHyIjoHrebKQGJHHAgTG2XWxn+G3fDsf+wSSFSLoDGj0o2SgGXooBbR2dccnNZHCyQaOyE2cIPWaOxrQZFE4No70LQB4mrP/gdkoc=
|
||||
matrix:
|
||||
include:
|
||||
- jdk: openjdk8
|
||||
env: STRUTS_IT=true # do integration tests and coverage reports when jdk 11 and 17 tests prospered
|
||||
|
||||
script:
|
||||
- if [ "$STRUTS_IT" == "true" ]; then
|
||||
./mvnw clean install -DskipTests -DskipAssembly -B;
|
||||
./mvnw test org.jacoco:jacoco-maven-plugin:report org.jacoco:jacoco-maven-plugin:report-integration org.eluder.coveralls:coveralls-maven-plugin:report -Ptravis-coveralls -DskipAssembly -B;
|
||||
else
|
||||
./mvnw clean package test -DskipAssembly -B;
|
||||
fi;
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.m2
|
||||
Vendored
+5
-3
@@ -79,7 +79,7 @@ pipeline {
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh './mvnw -B test'
|
||||
sh './mvnw -B verify -Pcoverage -DskipAssembly'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
@@ -94,7 +94,7 @@ pipeline {
|
||||
}
|
||||
steps {
|
||||
withCredentials([string(credentialsId: 'asf-struts-sonarcloud', variable: 'SONARCLOUD_TOKEN')]) {
|
||||
sh './mvnw sonar:sonar -DskipAssembly -Dsonar.login=${SONARCLOUD_TOKEN}'
|
||||
sh './mvnw -B -Pcoverage -DskipAssembly -Dsonar.login=${SONARCLOUD_TOKEN} verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,6 +160,7 @@ pipeline {
|
||||
branch 'master'
|
||||
}
|
||||
steps {
|
||||
sh './mvnw -B package -DskipTests'
|
||||
sshPublisher(publishers: [
|
||||
sshPublisherDesc(
|
||||
configName: 'Nightlies',
|
||||
@@ -167,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
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
The Apache Struts web framework
|
||||
-------------------------------
|
||||
|
||||
[](https://ci-builds.apache.org/job/Struts/job/Struts%20Core/job/master/)
|
||||
[](https://app.travis-ci.com/apache/struts)
|
||||
[](https://ci-builds.apache.org/job/Struts/job/Struts%20Core/job/master/)
|
||||
[](https://github.com/apache/struts/actions/workflows/maven.yml)
|
||||
[](https://maven-badges.herokuapp.com/maven-central/org.apache.struts/struts2-core/)
|
||||
[](https://javadoc.io/doc/org.apache.struts/struts2-core)
|
||||
[](https://coveralls.io/github/apache/struts)
|
||||
[](https://sonarcloud.io/summary/new_code?id=apache_struts)
|
||||
[](https://deps.dev/maven/org.apache.struts%3Astruts2-core)
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/6618)
|
||||
[](http://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
|
||||
The Apache Struts web framework is a free open-source solution for creating Java web applications.
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@ and what potential vulnerability it can have:
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 2.5.20 | :white_check_mark: |
|
||||
| 2.3.37 | :white_check_mark: |
|
||||
| 6.0.0 | :white_check_mark: |
|
||||
| 2.5.30 | :white_check_mark: |
|
||||
|
||||
## Reporting New Security Issues with thr Apache Struts
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# Struts 2 Apps
|
||||
These module consists of two example applications, which were built using the Apache Struts project.
|
||||
One is an old-fashioned Web application and another is a modern REST based single page app.
|
||||
|
||||
## Installation
|
||||
Enter a given folder, either `showcase/` or `rest-showcase/` and start the app using Maven:
|
||||
|
||||
```
|
||||
mvn jetty:run
|
||||
```
|
||||
|
||||
then open your browser at http://localhost:8080 and navigate to a proper context.
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.0.3</version>
|
||||
<version>6.1.2.3-SNAPSHOT</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.0.3</version>
|
||||
<version>6.1.2.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-rest-showcase</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>6.0.3</version>
|
||||
<version>6.1.2.3-SNAPSHOT</version>
|
||||
<name>Struts 2 Rest Showcase Webapp</name>
|
||||
<description>Struts 2 Rest Showcase Example</description>
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>@{argLine}</argLine>
|
||||
<excludes>
|
||||
<exclude>it/**</exclude>
|
||||
<exclude>**/*$*</exclude>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
|
||||
<struts>
|
||||
@@ -41,4 +41,4 @@
|
||||
<package name="rest-showcase" extends="rest-default">
|
||||
<global-allowed-methods>index,show,create,update,destroy,deleteConfirm,edit,editNew</global-allowed-methods>
|
||||
</package>
|
||||
</struts>
|
||||
</struts>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>6.0.3</version>
|
||||
<version>6.1.2.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-showcase</artifactId>
|
||||
@@ -237,6 +237,7 @@
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>@{argLine}</argLine>
|
||||
<excludes>
|
||||
<exclude>it/**</exclude>
|
||||
<exclude>**/*$*</exclude>
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.showcase.wait;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.interceptor.exec.ExecutorProvider;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ThreadPoolExecutorProvider implements ExecutorProvider {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ThreadPoolExecutorProvider.class);
|
||||
|
||||
private final ExecutorService executor;
|
||||
|
||||
public ThreadPoolExecutorProvider() {
|
||||
this.executor = new ThreadPoolExecutor(1, 2, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable task) {
|
||||
LOG.info("Executing task: {}", task);
|
||||
executor.execute(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShutdown() {
|
||||
return executor.isShutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
LOG.info("Shutting down executor");
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -21,31 +21,31 @@
|
||||
-->
|
||||
<!DOCTYPE validators PUBLIC
|
||||
"-//Apache Struts//XWork Validator 1.0.2//EN"
|
||||
"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
"https://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
<validators>
|
||||
<field name="description1">
|
||||
<field-validator type="requiredstring">
|
||||
<message>Description1 Is Required !!!</message>
|
||||
</field-validator>
|
||||
</field>
|
||||
|
||||
|
||||
<field name="description2">
|
||||
<field-validator type="requiredstring">
|
||||
<message>Description2 Is Required !!!</message>
|
||||
</field-validator>
|
||||
</field>
|
||||
|
||||
|
||||
<field name="description3">
|
||||
<field-validator type="requiredstring">
|
||||
<message>Description3 Is Required !!!</message>
|
||||
</field-validator>
|
||||
</field>
|
||||
|
||||
|
||||
<field name="description4">
|
||||
<field-validator type="requiredstring">
|
||||
<message>Description4 Is Required !!!</message>
|
||||
</field-validator>
|
||||
</field>
|
||||
</validators>
|
||||
|
||||
</validators>
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.dtd">
|
||||
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0//EN" "https://struts.apache.org/dtds/xwork-validator-1.0.dtd">
|
||||
<validators>
|
||||
<!-- Field-Validator Syntax -->
|
||||
<field name="currentEmployee.empId">
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.dtd">
|
||||
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0//EN" "https://struts.apache.org/dtds/xwork-validator-1.0.dtd">
|
||||
<validators>
|
||||
<!-- Field-Validator Syntax -->
|
||||
<field name="currentSkill.name">
|
||||
|
||||
+2
-3
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE validators PUBLIC
|
||||
"-//Apache Struts//XWork Validator 1.0.2//EN"
|
||||
"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
"https://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
<validators>
|
||||
<field name="upload">
|
||||
@@ -35,5 +35,4 @@
|
||||
<message>Caption cannot be empty</message>
|
||||
</field-validator>
|
||||
</field>
|
||||
</validators>
|
||||
|
||||
</validators>
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.dtd">
|
||||
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0//EN" "https://struts.apache.org/dtds/xwork-validator-1.0.dtd">
|
||||
<validators>
|
||||
<field name="person">
|
||||
<field-validator type="visitor">
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.dtd">
|
||||
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0//EN" "https://struts.apache.org/dtds/xwork-validator-1.0.dtd">
|
||||
<validators>
|
||||
<field name="name">
|
||||
<field-validator type="requiredstring">
|
||||
|
||||
+6
-6
@@ -21,8 +21,8 @@
|
||||
-->
|
||||
<!DOCTYPE validators PUBLIC
|
||||
"-//Apache Struts//XWork Validator 1.0.2//EN"
|
||||
"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
"https://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
<validators>
|
||||
<field name="value">
|
||||
<field-validator type="requiredstring">
|
||||
@@ -30,13 +30,13 @@
|
||||
<message>Value must not be empty</message>
|
||||
</field-validator>
|
||||
</field>
|
||||
|
||||
|
||||
|
||||
|
||||
<field name="count">
|
||||
<field-validator type="int">
|
||||
<message>Count must be an integer</message>
|
||||
</field-validator>
|
||||
</field-validator>
|
||||
</field>
|
||||
</validators>
|
||||
</validators>
|
||||
|
||||
|
||||
|
||||
+4
-4
@@ -21,10 +21,10 @@
|
||||
-->
|
||||
<!DOCTYPE validators PUBLIC
|
||||
"-//Apache Struts//XWork Validator 1.0//EN"
|
||||
"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
<!-- START SNIPPET: fieldValidatorsExample -->
|
||||
|
||||
"https://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
<!-- START SNIPPET: fieldValidatorsExample -->
|
||||
|
||||
<validators>
|
||||
<field name="requiredValidatorField">
|
||||
<field-validator type="required">
|
||||
|
||||
+5
-5
@@ -19,12 +19,12 @@
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE validators PUBLIC
|
||||
<!DOCTYPE validators PUBLIC
|
||||
"-//Apache Struts//XWork Validator 1.0//EN"
|
||||
"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
<!-- START SNIPPET: fieldValidatorsExample -->
|
||||
|
||||
"https://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
<!-- START SNIPPET: fieldValidatorsExample -->
|
||||
|
||||
<validators>
|
||||
<field name="requiredValidatorField">
|
||||
<field-validator type="required">
|
||||
|
||||
+6
-6
@@ -19,13 +19,13 @@
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE validators PUBLIC
|
||||
<!DOCTYPE validators PUBLIC
|
||||
"-//Apache Struts//XWork Validator 1.0//EN"
|
||||
"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
|
||||
<!-- START SNIPPET: nonFieldValidatorsExample -->
|
||||
|
||||
"https://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
|
||||
<!-- START SNIPPET: nonFieldValidatorsExample -->
|
||||
|
||||
<validators>
|
||||
<validator type="expression">
|
||||
<param name="expression"><![CDATA[ ( (someText == someTextRetype) && (someTextRetype == someTextRetypeAgain) ) ]]></param>
|
||||
|
||||
+2
-2
@@ -19,11 +19,11 @@
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" "https://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
<!-- START SNIPPET: quizValidators -->
|
||||
<!--
|
||||
Add the following DOCTYPE declaration as first line of your XXX-validation.xml file:
|
||||
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" "https://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
-->
|
||||
<validators>
|
||||
<field name="name">
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE validators PUBLIC
|
||||
"-//Apache Struts//XWork Validator 1.0//EN"
|
||||
"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
"https://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
<validators>
|
||||
<field name="name">
|
||||
|
||||
+5
-5
@@ -19,17 +19,17 @@
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE validators PUBLIC
|
||||
<!DOCTYPE validators PUBLIC
|
||||
"-//Apache Struts//XWork Validator 1.0//EN"
|
||||
"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
"https://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
<validators>
|
||||
<field name="name">
|
||||
<field-validator type="requiredstring">
|
||||
<message>Name Required</message>
|
||||
</field-validator>
|
||||
</field>
|
||||
<field name="age">
|
||||
<field name="age">
|
||||
<field-validator type="int">
|
||||
<param name="min">1</param>
|
||||
<param name="max">100</param>
|
||||
@@ -41,6 +41,6 @@
|
||||
<message>Birthday Required</message>
|
||||
</field-validator>
|
||||
</field>
|
||||
</validators>
|
||||
</validators>
|
||||
|
||||
|
||||
|
||||
+3
-3
@@ -19,10 +19,10 @@
|
||||
* under the License.
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE validators PUBLIC
|
||||
<!DOCTYPE validators PUBLIC
|
||||
"-//Apache Struts//XWork Validator 1.0//EN"
|
||||
"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
"https://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">
|
||||
|
||||
<!-- START SNIPPET: visitorValidatorsExample -->
|
||||
|
||||
<validators>
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="actionchaining" extends="struts-default" namespace="/actionchaining">
|
||||
<action name="actionChain1" class="org.apache.struts2.showcase.actionchaining.ActionChain1">
|
||||
<result type="chain">actionChain2</result>
|
||||
<result type="chain">actionChain2</result>
|
||||
</action>
|
||||
<action name="actionChain2" class="org.apache.struts2.showcase.actionchaining.ActionChain2">
|
||||
<result type="chain">actionChain3</result>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="async" extends="json-default" namespace="/async">
|
||||
|
||||
@@ -21,15 +21,15 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="conversion" namespace="/conversion" extends="struts-default">
|
||||
|
||||
|
||||
<action name="index">
|
||||
<result>/WEB-INF/conversion/index.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
<!-- Example populating a List inside an Action -->
|
||||
<action name="enterPersonsInfo" method="input"
|
||||
class="org.apache.struts2.showcase.conversion.PersonAction">
|
||||
@@ -49,8 +49,8 @@
|
||||
<action name="showPersonJavaCode">
|
||||
<result type="plainText">/WEB-INF/conversion/Person.java.txt</result>
|
||||
</action>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Example populating a Set inside an Action -->
|
||||
<action name="enterAddressesInfo" class="org.apache.struts2.showcase.conversion.AddressAction" method="input">
|
||||
<result>/WEB-INF/conversion/enterAddressInfo.jsp</result>
|
||||
@@ -68,9 +68,9 @@
|
||||
<action name="showAddressJavaCode">
|
||||
<result type="plainText">/WEB-INF/conversion/Address.java.txt</result>
|
||||
</action>
|
||||
|
||||
|
||||
<!-- Example populating a List with Tiger 5 Enum -->
|
||||
|
||||
|
||||
<!-- Example populating a List with Tiger 5 Enum -->
|
||||
<action name="enterOperationEnumInfo" class="org.apache.struts2.showcase.conversion.OperationsEnumAction" method="input">
|
||||
<result>/WEB-INF/conversion/enterOperations.jsp</result>
|
||||
</action>
|
||||
@@ -93,6 +93,6 @@
|
||||
<action name="showOperationsEnumActionConversionProperties">
|
||||
<result type="plainText">/WEB-INF/conversion/OperationsEnumActionConversion.txt</result>
|
||||
</action>
|
||||
|
||||
|
||||
</package>
|
||||
</struts>
|
||||
</struts>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="dispatcher" extends="struts-default" namespace="/dispatcher">
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="filedownload" extends="struts-default" namespace="/filedownload">
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="fileupload" extends="struts-default" namespace="/fileupload">
|
||||
|
||||
|
||||
<action name="upload" class="org.apache.struts2.showcase.fileupload.FileUploadAction" method="input">
|
||||
<result>/WEB-INF/fileupload/upload.jsp</result>
|
||||
</action>
|
||||
@@ -34,11 +34,11 @@
|
||||
<result name="input">/WEB-INF/fileupload/upload.jsp</result>
|
||||
<result>/WEB-INF/fileupload/upload-success.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
<action name="multipleUploadUsingList">
|
||||
<result>/WEB-INF/fileupload/multipleUploadUsingList.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
<action name="doMultipleUploadUsingList" class="org.apache.struts2.showcase.fileupload.MultipleFileUploadUsingListAction" method="upload">
|
||||
<result name="input">/WEB-INF/fileupload/multipleUploadUsingList.jsp</result>
|
||||
<result>/WEB-INF/fileupload/multiple-success.jsp</result>
|
||||
|
||||
@@ -21,16 +21,16 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="freemarker" namespace="/freemarker" extends="struts-default">
|
||||
<action name="customFreemarkerManagerDemo">
|
||||
<result type="freemarker">/WEB-INF/freemarker/customFreemarkerManagerUsage.ftl</result>
|
||||
</action>
|
||||
|
||||
|
||||
<action name="standardTags" class="org.apache.struts2.showcase.freemarker.StandardTagsAction">
|
||||
<result type="freemarker">/WEB-INF/freemarker/standardTags.ftl</result>
|
||||
</action>
|
||||
</package>
|
||||
</struts>
|
||||
</struts>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="hangman" extends="struts-default" namespace="/hangman">
|
||||
@@ -41,9 +41,9 @@
|
||||
<result type="freemarker">/WEB-INF/hangman/hangmanNonAjax.ftl</result>
|
||||
</action>
|
||||
</package>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<package name="hangman-ajax" extends="struts-default" namespace="/hangman/ajax">
|
||||
<action name="blank">
|
||||
<result type="freemarker">/WEB-INF/hangman/blank.ftl</result>
|
||||
@@ -61,4 +61,4 @@
|
||||
<result type="freemarker">/WEB-INF/hangman/updateGuessLeft.ftl</result>
|
||||
</action>
|
||||
</package>
|
||||
</struts>
|
||||
</struts>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="interactive" namespace="/interactive" extends="struts-default">
|
||||
@@ -38,4 +38,4 @@
|
||||
</action>
|
||||
<action name="example" class="org.apache.struts2.showcase.action.ExampleAction" />
|
||||
</package>
|
||||
</struts>
|
||||
</struts>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="modelDriven" extends="struts-default" namespace="/modelDriven">
|
||||
@@ -29,11 +29,10 @@
|
||||
<action name="modelDriven" class="org.apache.struts2.showcase.modelDriven.ModelDrivenAction" method="input">
|
||||
<result>/WEB-INF/modelDriven/modelDriven.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
<!-- Display the result page whose content is populated using the Model-Driven technique -->
|
||||
<action name="modelDrivenResult" class="org.apache.struts2.showcase.modelDriven.ModelDrivenAction">
|
||||
<result>/WEB-INF/modelDriven/modelDrivenResult.jsp</result>
|
||||
</action>
|
||||
</package>
|
||||
</struts>
|
||||
|
||||
</struts>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<!-- START SNIPPET: xworkSample -->
|
||||
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
|
||||
|
||||
<!-- ================================== -->
|
||||
<!-- === Package for ActionTag Demo === -->
|
||||
<!-- ================================== -->
|
||||
|
||||
|
||||
<package name="actionTag" extends="struts-default" namespace="/tags/non-ui/actionTag">
|
||||
<action name="showActionTagDemo" class="org.apache.struts2.showcase.tag.nonui.actiontag.ActionTagDemo" method="show">
|
||||
<result>/WEB-INF/tags/non-ui/actionTag/showActionTagDemo.jsp</result>
|
||||
@@ -46,11 +46,11 @@
|
||||
<result type="plainText">/WEB-INF/tags/non-ui/actionTag/showActionTagDemo.jsp</result>
|
||||
</action>
|
||||
</package>
|
||||
|
||||
|
||||
<!-- ==================================== -->
|
||||
<!-- === Package for IteratorGeneratorTag Demo === -->
|
||||
<!-- ==================================== -->
|
||||
|
||||
|
||||
<package name="iteratorGeneratorTag" extends="struts-default" namespace="/tags/non-ui/iteratorGeneratorTag">
|
||||
<action name="showGeneratorTagDemo" class="org.apache.struts2.showcase.tag.nonui.iteratortag.IteratorGeneratorTagDemo" method="input">
|
||||
<result>/WEB-INF/tags/non-ui/iteratorTag/showIteratorGeneratorTagDemo.jsp</result>
|
||||
@@ -60,8 +60,8 @@
|
||||
<result>/WEB-INF/tags/non-ui/iteratorTag/iteratorGeneratorTagDemoResult.jsp</result>
|
||||
</action>
|
||||
</package>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- ===================================== -->
|
||||
<!-- === Package for AppendIteratorTag Demo === -->
|
||||
<!-- ========================================== -->
|
||||
@@ -74,8 +74,8 @@
|
||||
<result>/WEB-INF/tags/non-ui/iteratorTag/appendIteratorTagDemoResult.jsp</result>
|
||||
</action>
|
||||
</package>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- ====================================== -->
|
||||
<!-- === Package for MergeIteratorTag Demo === -->
|
||||
<!-- ========================================= -->
|
||||
@@ -88,7 +88,7 @@
|
||||
<result>/WEB-INF/tags/non-ui/iteratorTag/mergeIteratorTagDemoResult.jsp</result>
|
||||
</action>
|
||||
</package>
|
||||
|
||||
|
||||
<!-- ============================================= -->
|
||||
<!-- === Package for SubsetIteratorTag Demo === -->
|
||||
<!-- =========================================== -->
|
||||
@@ -101,14 +101,14 @@
|
||||
<result>/WEB-INF/tags/non-ui/iteratorTag/subsetIteratorTagDemoResult.jsp</result>
|
||||
</action>
|
||||
</package>
|
||||
|
||||
|
||||
<!-- ========================================= -->
|
||||
<!-- === Package for Action Prefix Example === -->
|
||||
<!-- ========================================= -->
|
||||
<package name="actionPrefix" extends="struts-default" namespace="/tags/non-ui/actionPrefix">
|
||||
<action name="actionPrefixExampleUsingFreemarker">
|
||||
<result type="freemarker">/WEB-INF/tags/non-ui/actionPrefix/actionPrefixExample.ftl</result>
|
||||
</action>
|
||||
</action>
|
||||
<action name="submit" class="org.apache.struts2.showcase.tag.nonui.actionPrefix.SubmitAction">
|
||||
<result type="freemarker">/WEB-INF/tags/non-ui/actionPrefix/normalSubmit.ftl</result>
|
||||
</action>
|
||||
@@ -131,7 +131,7 @@
|
||||
<result type="plainText">/WEB-INF/tags/non-ui/actionPrefix/actionPrefixExample.ftl</result>
|
||||
</action>
|
||||
</package>
|
||||
|
||||
|
||||
<!-- ========================================== -->
|
||||
<!-- === Package for If Tag Test / Examples === -->
|
||||
<!-- ========================================== -->
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="ui-tags" extends="velocity-default" namespace="/tags/ui">
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<include file="struts-tags-ui.xml"/>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="tiles" extends="tiles-default" namespace="/tiles">
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
<struts>
|
||||
<package name="token" extends="struts-default" namespace="/token">
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
|
||||
<constant name="struts.beanValidation.providerClass" value="org.hibernate.validator.HibernateValidator"/>
|
||||
@@ -74,7 +74,7 @@
|
||||
<action name="ajaxFormSubmitSuccess" class="org.apache.struts2.showcase.validation.AjaxFormSubmitSuccessAction">
|
||||
<result>/WEB-INF/validation/ajaxFormSubmitSuccess.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
</package>
|
||||
|
||||
|
||||
@@ -83,46 +83,46 @@
|
||||
<action name="list">
|
||||
<result>index.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- ======================== -->
|
||||
<!-- === Field Validators === -->
|
||||
<!-- ======================== -->
|
||||
|
||||
|
||||
<action name="showFieldValidatorsExamples" class="org.apache.struts2.showcase.validation.FieldValidatorsExampleAction" method="input">
|
||||
<result name="input" type="dispatcher">/WEB-INF/validation/fieldValidatorsExample.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
<action name="submitFieldValidatorsExamples" class="org.apache.struts2.showcase.validation.FieldValidatorsExampleAction" method="submit">
|
||||
<result name="input" type="dispatcher">/WEB-INF/validation/fieldValidatorsExample.jsp</result>
|
||||
<result type="dispatcher">/WEB-INF/validation/successFieldValidatorsExample.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- ============================ -->
|
||||
<!-- === Non Field Validators === -->
|
||||
<!-- ============================ -->
|
||||
|
||||
|
||||
<action name="showNonFieldValidatorsExamples" class="org.apache.struts2.showcase.validation.NonFieldValidatorsExampleAction" method="input">
|
||||
<result name="input">/WEB-INF/validation/nonFieldValidatorsExample.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
<action name="submitNonFieldValidatorsExamples" class="org.apache.struts2.showcase.validation.NonFieldValidatorsExampleAction" method="submit">
|
||||
<result name="input">/WEB-INF/validation/nonFieldValidatorsExample.jsp</result>
|
||||
<result>/WEB-INF/validation/successNonFieldValidatorsExample.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- ========================== -->
|
||||
<!-- === Visitor Validators === -->
|
||||
<!-- ========================== -->
|
||||
|
||||
|
||||
<action name="showVisitorValidatorsExamples" class="org.apache.struts2.showcase.validation.VisitorValidatorsExampleAction" method="input">
|
||||
<result name="input">/WEB-INF/validation/visitorValidatorsExample.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
<action name="submitVisitorValidatorsExamples" class="org.apache.struts2.showcase.validation.VisitorValidatorsExampleAction" method="submit">
|
||||
<result name="input">/WEB-INF/validation/visitorValidatorsExample.jsp</result>
|
||||
<result>/WEB-INF/validation/successVisitorValidatorsExample.jsp</result>
|
||||
@@ -146,7 +146,7 @@
|
||||
<!-- =========================================== -->
|
||||
<!-- === Store Error Messages Across Request === -->
|
||||
<!-- =========================================== -->
|
||||
|
||||
|
||||
<action name="submitApplication" class="org.apache.struts2.showcase.validation.SubmitApplication" method="submitApplication">
|
||||
<interceptor-ref name="store">
|
||||
<param name="operationMode">STORE</param>
|
||||
@@ -173,7 +173,7 @@
|
||||
<action name="cancelApplication" class="org.apache.struts2.showcase.validation.SubmitApplication" method="cancelApplication">
|
||||
<result>/WEB-INF/validation/storeErrorsAcrossRequestCancel.jsp</result>
|
||||
</action>
|
||||
|
||||
|
||||
</package>
|
||||
</struts>
|
||||
|
||||
|
||||
|
||||
@@ -21,10 +21,17 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
|
||||
<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"/>
|
||||
<action name="index">
|
||||
<result>/WEB-INF/wait/index.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="example1">
|
||||
<result>/WEB-INF/wait/example1.jsp</result>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="xslt" extends="struts-default" namespace="/xslt">
|
||||
@@ -36,7 +36,7 @@
|
||||
<param name="exposedValue">info.classpath</param>
|
||||
</result>
|
||||
</action>
|
||||
|
||||
|
||||
<action name="jvmInfoRaw" class="org.apache.struts2.showcase.xslt.JVMAction">
|
||||
<result type="xslt">
|
||||
<param name="exposedValue">info</param>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<!-- START SNIPPET: xworkSample -->
|
||||
<struts>
|
||||
|
||||
@@ -64,14 +64,14 @@
|
||||
<title><decorator:title default="Struts2 Showcase"/></title>
|
||||
|
||||
<s:url var="bootstrapCss" value='/styles/bootstrap.css' encode='false' includeParams='none'/>
|
||||
<s:link href="%{bootstrapCss}" rel="stylesheet" type="text/css" media="all"></s:link>
|
||||
<s:link href="%{bootstrapCss}" rel="stylesheet" type="text/css" media="all"/>
|
||||
<s:url var="mainCss" value='/styles/main.css' encode='false' includeParams='none'/>
|
||||
<s:link href="%{mainCss}" rel="stylesheet" type="text/css" media="all"></s:link>
|
||||
<s:link href="%{mainCss}" rel="stylesheet" type="text/css" media="all"/>
|
||||
|
||||
<s:url var="jqueryJs" value='/js/jquery-2.1.4.min.js' encode='false' includeParams='none'/>
|
||||
<s:script src="%{jqueryJs}"></s:script>
|
||||
<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 src="%{bootstrapJs}"/>
|
||||
<s:script type="text/javascript">
|
||||
$(function () {
|
||||
var alerts = $('ul.alert').wrap('<div />');
|
||||
@@ -82,19 +82,22 @@
|
||||
|
||||
<!-- Prettify -->
|
||||
<s:url var="prettifyCss" value='/styles/prettify.css' encode='false' includeParams='none'/>
|
||||
<s:link href="%{prettifyCss}" rel="stylesheet"></s:link>
|
||||
<s:link href="%{prettifyCss}" rel="stylesheet"/>
|
||||
<s:url var="prettifyJs" value='/js/prettify.js' encode='false' includeParams='none'/>
|
||||
<s:script src="%{prettifyJs}"></s:script>
|
||||
<s:script src="%{prettifyJs}"/>
|
||||
|
||||
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
|
||||
<!--[if lt IE 9]>
|
||||
<s:script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></s:script>
|
||||
<s:script src="http://html5shim.googlecode.com/svn/trunk/html5.js"/>
|
||||
<![endif]-->
|
||||
|
||||
<s:script>
|
||||
jQuery(document).ready(function() { prettyPrint(); } );
|
||||
</s:script>
|
||||
<decorator:head/>
|
||||
</head>
|
||||
|
||||
<body id="page-home" onload="prettyPrint();">
|
||||
<body id="page-home">
|
||||
|
||||
<nav class="navbar navbar-default navbar-fixed-top">
|
||||
<div class="container-fluid">
|
||||
@@ -239,7 +242,7 @@
|
||||
</li>
|
||||
<li><s:a value="/person/index.html">Person Manager</s:a></li>
|
||||
<li><s:a value="/skill/index.html">CRUD</s:a></li>
|
||||
<li><s:a value="/wait/index.html">Execute & Wait</s:a></li>
|
||||
<li><s:a value="/wait/index">Execute & Wait</s:a></li>
|
||||
<li><s:a value="/token/index.html">Token</s:a></li>
|
||||
<li><s:url var="url" namespace="/modelDriven" action="modelDriven"/><s:a
|
||||
href="%{url}">Model Driven</s:a></li>
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<!--
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* 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
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
@@ -21,25 +21,26 @@
|
||||
<%@ taglib prefix="s" uri="/struts-tags" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>Struts2 Showcase - Execute and Wait Examples - Complete</title>
|
||||
<title>Struts2 Showcase - Execute and Wait Examples - Complete</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="page-header">
|
||||
<h1>The process is complete</h1>
|
||||
<h1>The process is complete</h1>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12" style="text-align: center;">
|
||||
<div class="row">
|
||||
<div class="col-md-12" style="text-align: center;">
|
||||
|
||||
<b>We have processed your request.</b>
|
||||
<p/>
|
||||
Click here to <s:url var="back" value="/wait/index.html"/><s:a href="%{back}" cssClass="btn btn-link">return</s:a>.
|
||||
<div class="panel">We have processed your request.</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<s:url var="back" value="/wait/index"/>
|
||||
Click here to <s:a href="%{back}" cssClass="btn btn-primary">return</s:a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<!--
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
<%@ taglib prefix="s" uri="/struts-tags" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>Struts2 Showcase - Execute and Wait Examples</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="page-header">
|
||||
<h1>Execute and Wait Examples</h1>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12" style="text-align: center;">
|
||||
|
||||
<p>
|
||||
These examples illustrate Struts build in support for execute and wait.
|
||||
<p/>
|
||||
<p>
|
||||
When you have a process that takes a long time your users can be impatient and starts to submit/click
|
||||
again.
|
||||
<br/> A good solution is to show the user a progress page (wait page) while the process takes it time.
|
||||
<p/>
|
||||
|
||||
<br/>
|
||||
<br/><a href='<s:url value="example1"/>'>Example 1 (no delay)</a>
|
||||
<br/><a href='<s:url value="example2"/>'>Example 2 (with delay)</a>
|
||||
<br/><a href='<s:url value="example3"/>'>Example 3 (with longer check delay)</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,19 +1,19 @@
|
||||
<!--
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* 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
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
@@ -21,53 +21,33 @@
|
||||
<%@ taglib prefix="s" uri="/struts-tags" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>Struts2 Showcase - Execute and Wait Examples - Wait</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="page-header">
|
||||
<h1>Execute and Wait Examples - Wait</h1>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12" style="text-align: center;">
|
||||
|
||||
<p class="well">
|
||||
We are processing your request. Please wait.
|
||||
</p>
|
||||
|
||||
<div class="progress progress-striped active">
|
||||
<div class="bar" style="width: 50%;"></div>
|
||||
</div>
|
||||
|
||||
<p/>
|
||||
You can click this link to <a href="<s:url includeParams="all"/>">refresh</a>.
|
||||
|
||||
<b>We have processed your request.</b>
|
||||
<p/>
|
||||
Click here to <s:url var="back" value="/wait/index.html"/><s:a href="%{back}" cssClass="btn btn-link">return</s:a>.
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<%@ taglib prefix="s" uri="/struts-tags" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>Struts2 Showcase - Execute and Wait Examples - Wait</title>
|
||||
<meta http-equiv="refresh" content="5;url=<s:url includeParams="all"/>"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p style="border: 1px solid silver; padding: 5px; background: #ffd; text-align: center;">
|
||||
We are processing your request. Please wait.
|
||||
</p>
|
||||
<div class="page-header">
|
||||
<h1>Execute and Wait Examples - Wait</h1>
|
||||
</div>
|
||||
|
||||
<p/>
|
||||
You can click this link to <a href="<s:url includeParams="all"/>">refresh</a>.
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12" style="text-align: center;">
|
||||
|
||||
<p class="well">
|
||||
We are processing your request. Please wait.
|
||||
</p>
|
||||
|
||||
<div class="progress progress-striped active">
|
||||
<div class="bar progress-bar progress-bar-success" style="width: 50%;"></div>
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
You can click this link to <a href="<s:url includeParams="all"/>">refresh</a>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,53 +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.
|
||||
*/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Struts2 Showcase - Execute and Wait Examples</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="page-header">
|
||||
<h1>Execute and Wait Examples</h1>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12" style="text-align: center;">
|
||||
|
||||
<p>
|
||||
These examples illustrate Struts build in support for execute and wait.
|
||||
<p/>
|
||||
<p>
|
||||
When you have a process that takes a long time your users can be impatient and starts to submit/click again.
|
||||
<br/> A good solution is to show the user a progress page (wait page) while the process takes it time.
|
||||
<p/>
|
||||
|
||||
<br/>
|
||||
<br/><a href="example1.action">Example 1 (no delay)</a>
|
||||
<br/><a href="example2.action">Example 2 (with delay)</a>
|
||||
<br/><a href="example3.action">Example 3 (with longer check delay)</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,3 @@
|
||||
# Struts 2 Assemblies
|
||||
This module is used to prepare ZIP archives with different set of JARs, like code source, Javadocs, etc.
|
||||
It's a part of the release process, it shouldn't be used directly by users.
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.0.3</version>
|
||||
<version>6.1.2.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-assembly</artifactId>
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<include>org.apache.struts:struts2-core</include>
|
||||
<include>org.freemarker:freemarker</include>
|
||||
<include>org.apache.commons:commons-lang3</include>
|
||||
<include>org.apache.commons:commons-text</include>
|
||||
<include>org.apache.logging.log4j:log4j-api</include>
|
||||
<include>ognl:ognl</include>
|
||||
<include>commons-fileupload:commons-fileupload</include>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# Struts 2 BOM
|
||||
This is a Bill-Of-Materials to be used with Maven based project. It allows to import all the Struts 2
|
||||
dependencies at once and used them in your project where needed.
|
||||
|
||||
## Installation
|
||||
You must add a proper import statement into your `pom.xml` as presented below:
|
||||
|
||||
```xml
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-bom</artifactId>
|
||||
<version>${struts2.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
```
|
||||
+3
-3
@@ -29,7 +29,7 @@
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-bom</artifactId>
|
||||
<version>6.0.3</version>
|
||||
<version>6.1.2.3-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Struts 2 Bill of Materials</name>
|
||||
@@ -44,7 +44,7 @@
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<struts-version.version>6.0.3</struts-version.version>
|
||||
<struts-version.version>6.1.2.3-SNAPSHOT</struts-version.version>
|
||||
<maven.site.skip>true</maven.site.skip>
|
||||
<maven.site.deploy.skip>true</maven.site.deploy.skip>
|
||||
</properties>
|
||||
@@ -185,7 +185,7 @@
|
||||
</dependencyManagement>
|
||||
|
||||
<scm>
|
||||
<tag>STRUTS_6_0_3</tag>
|
||||
<tag>STRUTS_6_1_2_1</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.0.3</version>
|
||||
<version>6.1.2.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-admin-bundle</artifactId>
|
||||
|
||||
@@ -22,13 +22,13 @@
|
||||
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
|
||||
<package name="bundle-admin" namespace="/osgi/admin" extends="osgi-default" strict-method-invocation="true">
|
||||
<default-action-ref name="bundles" />
|
||||
|
||||
|
||||
<action name="bundle_*!*" class="org.apache.struts2.osgi.admin.actions.BundlesAction" method="{2}">
|
||||
<param name="id">{1}</param>
|
||||
<result type="freemarker">viewBundle.ftl</result>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>6.0.3</version>
|
||||
<version>6.1.2.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-demo-bundle</artifactId>
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<!-- Set some Struts 2 constants relevant to the OSGi Plugin.
|
||||
Note: The constant definitions specified here (within the demo bundle) may also need to be
|
||||
<!-- Set some Struts 2 constants relevant to the OSGi Plugin.
|
||||
Note: The constant definitions specified here (within the demo bundle) may also need to be
|
||||
duplicated in the struts.xml configuration of the outer project that packages the demo
|
||||
bundle JAR file within it.
|
||||
-->
|
||||
@@ -52,4 +52,4 @@
|
||||
</action>
|
||||
|
||||
</package>
|
||||
</struts>
|
||||
</struts>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.0.3</version>
|
||||
<version>6.1.2.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# Struts 2 Core
|
||||
This is a core of the Apache Struts framework and all other modules depend on it.
|
||||
It requires Java 8 at minimum and a Servlet container supporting Java Servlet API 3.1 at least.
|
||||
|
||||
## Installation
|
||||
Just drop this plugin into `WEB-INF/lib` folder or add it as Maven dependency
|
||||
+3
-6
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.0.3</version>
|
||||
<version>6.1.2.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>struts2-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
@@ -41,6 +41,7 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>@{argLine}</argLine>
|
||||
<properties>
|
||||
<property>
|
||||
<name>maven.testng.output.dir</name>
|
||||
@@ -54,9 +55,6 @@
|
||||
<element>${project.build.testOutputDirectory}/xwork - jar.jar</element>
|
||||
<element>${project.build.testOutputDirectory}/xwork - zip.zip</element>
|
||||
</additionalClasspathElements>
|
||||
<includes>
|
||||
<include>**/*Test.java</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>**/XWorkTestCase.java</exclude>
|
||||
<exclude>**/TestBean.java</exclude>
|
||||
@@ -339,8 +337,7 @@
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- SLF4J support -->
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.opensymphony.xwork2.config.entities.InterceptorMapping;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.ConditionalInterceptor;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import com.opensymphony.xwork2.interceptor.PreResultListener;
|
||||
import com.opensymphony.xwork2.interceptor.WithLazyParams;
|
||||
@@ -73,7 +74,7 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
protected UnknownHandlerManager unknownHandlerManager;
|
||||
protected OgnlUtil ognlUtil;
|
||||
protected AsyncManager asyncManager;
|
||||
protected Callable asyncAction;
|
||||
protected Callable<?> asyncAction;
|
||||
protected WithLazyParams.LazyParamInjector lazyParamInjector;
|
||||
|
||||
public DefaultActionInvocation(final Map<String, Object> extraContext, final boolean pushAction) {
|
||||
@@ -101,7 +102,7 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
this.container = cont;
|
||||
}
|
||||
|
||||
@Inject(required=false)
|
||||
@Inject(required = false)
|
||||
public void setActionEventListener(ActionEventListener listener) {
|
||||
this.actionEventListener = listener;
|
||||
}
|
||||
@@ -111,7 +112,7 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
this.ognlUtil = ognlUtil;
|
||||
}
|
||||
|
||||
@Inject(required=false)
|
||||
@Inject(required = false)
|
||||
public void setAsyncManager(AsyncManager asyncManager) {
|
||||
this.asyncManager = asyncManager;
|
||||
}
|
||||
@@ -214,7 +215,7 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
} catch (NullPointerException e) {
|
||||
LOG.debug("Got NPE trying to read result configuration for resultCode [{}]", resultCode);
|
||||
}
|
||||
|
||||
|
||||
if (resultConfig == null) {
|
||||
// If no result is found for the given resultCode, try to get a wildcard '*' match.
|
||||
resultConfig = results.get("*");
|
||||
@@ -248,7 +249,12 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
if (interceptor instanceof WithLazyParams) {
|
||||
interceptor = lazyParamInjector.injectParams(interceptor, interceptorMapping.getParams(), invocationContext);
|
||||
}
|
||||
resultCode = interceptor.intercept(DefaultActionInvocation.this);
|
||||
if (interceptor instanceof ConditionalInterceptor) {
|
||||
resultCode = executeConditional((ConditionalInterceptor) interceptor);
|
||||
} else {
|
||||
LOG.debug("Executing normal interceptor: {}", interceptorMapping.getName());
|
||||
resultCode = interceptor.intercept(this);
|
||||
}
|
||||
} else {
|
||||
resultCode = invokeActionOnly();
|
||||
}
|
||||
@@ -268,9 +274,7 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
if (preResultListeners != null) {
|
||||
LOG.trace("Executing PreResultListeners for result [{}]", result);
|
||||
|
||||
for (Object preResultListener : preResultListeners) {
|
||||
PreResultListener listener = (PreResultListener) preResultListener;
|
||||
|
||||
for (PreResultListener listener : preResultListeners) {
|
||||
listener.beforeResult(this, resultCode);
|
||||
}
|
||||
}
|
||||
@@ -289,6 +293,16 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
protected String executeConditional(ConditionalInterceptor conditionalInterceptor) throws Exception {
|
||||
if (conditionalInterceptor.shouldIntercept(this)) {
|
||||
LOG.debug("Executing conditional interceptor: {}", conditionalInterceptor.getClass().getSimpleName());
|
||||
return conditionalInterceptor.intercept(this);
|
||||
} else {
|
||||
LOG.debug("Interceptor: {} is disabled, skipping to next", conditionalInterceptor.getClass().getSimpleName());
|
||||
return this.invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public String invokeActionOnly() throws Exception {
|
||||
return invokeAction(getAction(), proxy.getConfig());
|
||||
}
|
||||
@@ -314,7 +328,7 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
gripe = "Unable to instantiate Action, " + proxy.getConfig().getClassName() + ", defined for '" + proxy.getActionName() + "' in namespace '" + proxy.getNamespace() + "'";
|
||||
}
|
||||
|
||||
gripe += (((" -- " + e.getMessage()) != null) ? e.getMessage() : " [no message in exception]");
|
||||
gripe += e.getMessage();
|
||||
throw new StrutsException(gripe, e, proxy.getConfig());
|
||||
}
|
||||
|
||||
@@ -363,7 +377,7 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
result.execute(this);
|
||||
} else if (resultCode != null && !Action.NONE.equals(resultCode)) {
|
||||
throw new ConfigurationException("No result defined for action " + getAction().getClass().getName()
|
||||
+ " and result " + getResultCode(), proxy.getConfig());
|
||||
+ " and result " + getResultCode(), proxy.getConfig());
|
||||
} else {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("No result returned for action {} at {}", getAction().getClass().getName(), proxy.getConfig().getLocation());
|
||||
@@ -464,6 +478,7 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
|
||||
/**
|
||||
* Save the result to be used later.
|
||||
*
|
||||
* @param actionConfig current ActionConfig
|
||||
* @param methodResult the result of the action.
|
||||
* @return the result code to process.
|
||||
@@ -476,7 +491,7 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
container.inject(explicitResult);
|
||||
return null;
|
||||
} else if (methodResult instanceof Callable) {
|
||||
asyncAction = (Callable) methodResult;
|
||||
asyncAction = (Callable<?>) methodResult;
|
||||
return null;
|
||||
} else {
|
||||
return (String) methodResult;
|
||||
|
||||
@@ -34,22 +34,22 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base JUnit TestCase to extend for XWork specific JUnit tests. Uses
|
||||
* Base JUnit TestCase to extend for XWork specific JUnit tests. Uses
|
||||
* the generic test setup for logic.
|
||||
*
|
||||
* @author plightbo
|
||||
*/
|
||||
public abstract class XWorkTestCase extends TestCase {
|
||||
|
||||
|
||||
protected ConfigurationManager configurationManager;
|
||||
protected Configuration configuration;
|
||||
protected Container container;
|
||||
protected ActionProxyFactory actionProxyFactory;
|
||||
|
||||
|
||||
public XWorkTestCase() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
configurationManager = XWorkTestCaseHelper.setUp();
|
||||
@@ -57,7 +57,7 @@ public abstract class XWorkTestCase extends TestCase {
|
||||
container = configuration.getContainer();
|
||||
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
XWorkTestCaseHelper.tearDown(configurationManager);
|
||||
@@ -66,34 +66,33 @@ public abstract class XWorkTestCase extends TestCase {
|
||||
container = null;
|
||||
actionProxyFactory = null;
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
|
||||
protected <T> void loadButAdd(final Class<T> type, final T impl) {
|
||||
loadButAdd(type, Container.DEFAULT_NAME, impl);
|
||||
}
|
||||
|
||||
protected void loadButAdd(final Class<?> type, final String name, final Object impl) {
|
||||
|
||||
protected <T> void loadButAdd(final Class<T> type, final String name, final T impl) {
|
||||
loadConfigurationProviders(new StubConfigurationProvider() {
|
||||
@Override
|
||||
public void register(ContainerBuilder builder,
|
||||
LocatableProperties props) throws ConfigurationException {
|
||||
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
|
||||
if (impl instanceof String || ClassUtils.isPrimitiveOrWrapper(impl.getClass())) {
|
||||
props.setProperty(name, "" + impl);
|
||||
} else {
|
||||
builder.factory(type, name, new Factory() {
|
||||
public Object create(Context context) throws Exception {
|
||||
builder.factory(type, name, new Factory<T>() {
|
||||
public T create(Context context) throws Exception {
|
||||
return impl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class type() {
|
||||
return impl.getClass();
|
||||
public Class<T> type() {
|
||||
return (Class<T>) impl.getClass();
|
||||
}
|
||||
}, Scope.SINGLETON);
|
||||
}
|
||||
|
||||
@@ -20,26 +20,18 @@ package com.opensymphony.xwork2.config.entities;
|
||||
|
||||
import com.opensymphony.xwork2.util.location.Located;
|
||||
import com.opensymphony.xwork2.util.location.Location;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* Configuration for Package.
|
||||
*
|
||||
* <p>
|
||||
* In the xml configuration file this is defined as the <code>package</code> tag.
|
||||
* </p>
|
||||
*
|
||||
* @author Rainer Hermanns
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class PackageConfig extends Located implements Comparable, Serializable, InterceptorLocator {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(PackageConfig.class);
|
||||
public class PackageConfig extends Located implements Comparable<PackageConfig>, Serializable, InterceptorLocator {
|
||||
|
||||
protected Map<String, ActionConfig> actionConfigs;
|
||||
protected Map<String, ResultConfig> globalResultConfigs;
|
||||
@@ -422,8 +414,7 @@ public class PackageConfig extends Located implements Comparable, Serializable,
|
||||
return "PackageConfig: [" + name + "] for namespace [" + namespace + "] with parents [" + parents + "]";
|
||||
}
|
||||
|
||||
public int compareTo(Object o) {
|
||||
PackageConfig other = (PackageConfig) o;
|
||||
public int compareTo(PackageConfig other) {
|
||||
String full = namespace + "!" + name;
|
||||
String otherFull = other.namespace + "!" + other.name;
|
||||
|
||||
@@ -443,7 +434,6 @@ public class PackageConfig extends Located implements Comparable, Serializable,
|
||||
public static class Builder implements InterceptorLocator {
|
||||
|
||||
protected PackageConfig target;
|
||||
private boolean strictDMI = true;
|
||||
|
||||
public Builder(String name) {
|
||||
target = new PackageConfig(name);
|
||||
|
||||
+99
-92
@@ -21,26 +21,16 @@ 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.LocaleProviderFactory;
|
||||
import com.opensymphony.xwork2.StrutsTextProviderFactory;
|
||||
import com.opensymphony.xwork2.TextProviderFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultUnknownHandlerFactory;
|
||||
import com.opensymphony.xwork2.factory.UnknownHandlerFactory;
|
||||
import com.opensymphony.xwork2.ognl.BeanInfoCacheFactory;
|
||||
import com.opensymphony.xwork2.ognl.ExpressionCacheFactory;
|
||||
import com.opensymphony.xwork2.ognl.accessor.HttpParametersPropertyAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.ParameterPropertyAccessor;
|
||||
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.DefaultExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.DefaultTextProvider;
|
||||
import com.opensymphony.xwork2.DefaultUnknownHandlerManager;
|
||||
import com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
|
||||
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;
|
||||
@@ -57,14 +47,7 @@ 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.security.NotExcludedAcceptedPatternsChecker;
|
||||
import org.apache.struts2.components.date.DateFormatter;
|
||||
import org.apache.struts2.components.date.DateTimeFormatterAdapter;
|
||||
import org.apache.struts2.components.date.SimpleDateFormatAdapter;
|
||||
import org.apache.struts2.conversion.StrutsConversionPropertiesProcessor;
|
||||
import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
|
||||
import org.apache.struts2.conversion.StrutsTypeConverterCreator;
|
||||
import org.apache.struts2.conversion.StrutsTypeConverterHolder;
|
||||
import com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler;
|
||||
import com.opensymphony.xwork2.conversion.impl.NumberConverter;
|
||||
import com.opensymphony.xwork2.conversion.impl.StringConverter;
|
||||
@@ -73,34 +56,45 @@ 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.StrutsConverterFactory;
|
||||
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;
|
||||
import com.opensymphony.xwork2.ognl.accessor.ParameterPropertyAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor;
|
||||
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.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.ognl.DefaultOgnlBeanInfoCacheFactory;
|
||||
import com.opensymphony.xwork2.ognl.DefaultOgnlExpressionCacheFactory;
|
||||
import com.opensymphony.xwork2.util.StrutsLocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.util.OgnlTextParser;
|
||||
import com.opensymphony.xwork2.util.PatternMatcher;
|
||||
import com.opensymphony.xwork2.util.StrutsLocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.util.TextParser;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import com.opensymphony.xwork2.util.WildcardHelper;
|
||||
@@ -119,8 +113,19 @@ 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.url.QueryStringBuilder;
|
||||
import org.apache.struts2.url.QueryStringParser;
|
||||
import org.apache.struts2.url.StrutsQueryStringBuilder;
|
||||
import org.apache.struts2.url.StrutsQueryStringParser;
|
||||
import org.apache.struts2.url.StrutsUrlDecoder;
|
||||
import org.apache.struts2.url.StrutsUrlEncoder;
|
||||
import org.apache.struts2.url.UrlDecoder;
|
||||
import org.apache.struts2.url.UrlEncoder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -153,88 +158,90 @@ public class StrutsDefaultConfigurationProvider implements ConfigurationProvider
|
||||
|
||||
@Override
|
||||
public void register(ContainerBuilder builder, LocatableProperties props)
|
||||
throws ConfigurationException {
|
||||
throws ConfigurationException {
|
||||
|
||||
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(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(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON)
|
||||
.factory(ActionProxyFactory.class, DefaultActionProxyFactory.class, Scope.SINGLETON)
|
||||
.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.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(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(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(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, 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(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(MethodAccessor.class, Object.class.getName(), XWorkMethodAccessor.class, Scope.SINGLETON)
|
||||
.factory(MethodAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON)
|
||||
.factory(MethodAccessor.class, Object.class.getName(), XWorkMethodAccessor.class, Scope.SINGLETON)
|
||||
.factory(MethodAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON)
|
||||
|
||||
.factory(TextParser.class, OgnlTextParser.class, Scope.SINGLETON)
|
||||
.factory(TextParser.class, OgnlTextParser.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(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(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(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(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)
|
||||
.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)
|
||||
|
||||
.factory(ExcludedPatternsChecker.class, DefaultExcludedPatternsChecker.class, Scope.PROTOTYPE)
|
||||
.factory(AcceptedPatternsChecker.class, DefaultAcceptedPatternsChecker.class, Scope.PROTOTYPE)
|
||||
.factory(NotExcludedAcceptedPatternsChecker.class, DefaultNotExcludedAcceptedPatternsChecker.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(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON)
|
||||
.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON)
|
||||
|
||||
.factory(DateFormatter.class, "simpleDateFormatter", SimpleDateFormatAdapter.class, Scope.SINGLETON)
|
||||
.factory(DateFormatter.class, "dateTimeFormatter", DateTimeFormatterAdapter.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());
|
||||
|
||||
@@ -19,10 +19,26 @@ import com.opensymphony.xwork2.inject.util.ReferenceCache;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.*;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ReflectPermission;
|
||||
import java.security.AccessControlException;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Default {@link Container} implementation.
|
||||
@@ -39,11 +55,7 @@ class ContainerImpl implements Container {
|
||||
this.factories = factories;
|
||||
final Map<Class<?>, Set<String>> map = new HashMap<>();
|
||||
for (Key<?> key : factories.keySet()) {
|
||||
Set<String> names = map.get(key.getType());
|
||||
if (names == null) {
|
||||
names = new HashSet<>();
|
||||
map.put(key.getType(), names);
|
||||
}
|
||||
Set<String> names = map.computeIfAbsent(key.getType(), k -> new HashSet<>());
|
||||
names.add(key.getName());
|
||||
}
|
||||
|
||||
@@ -63,20 +75,20 @@ class ContainerImpl implements Container {
|
||||
* Field and method injectors.
|
||||
*/
|
||||
final Map<Class<?>, List<Injector>> injectors =
|
||||
new ReferenceCache<Class<?>, List<Injector>>() {
|
||||
@Override
|
||||
protected List<Injector> create(Class<?> key) {
|
||||
List<Injector> injectors = new ArrayList<>();
|
||||
addInjectors(key, injectors);
|
||||
return injectors;
|
||||
}
|
||||
};
|
||||
new ReferenceCache<Class<?>, List<Injector>>() {
|
||||
@Override
|
||||
protected List<Injector> create(Class<?> key) {
|
||||
List<Injector> injectors = new ArrayList<>();
|
||||
addInjectors(key, injectors);
|
||||
return injectors;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively adds injectors for fields and methods from the given class to the given list. Injects parent classes
|
||||
* before sub classes.
|
||||
*/
|
||||
void addInjectors(Class clazz, List<Injector> injectors) {
|
||||
void addInjectors(Class<?> clazz, List<Injector> injectors) {
|
||||
if (clazz == Object.class) {
|
||||
return;
|
||||
}
|
||||
@@ -97,38 +109,24 @@ class ContainerImpl implements Container {
|
||||
addInjectorsForMethods(clazz.getDeclaredMethods(), true, injectors);
|
||||
}
|
||||
|
||||
callInContext(new ContextualCallable<Void>() {
|
||||
public Void call(InternalContext context) {
|
||||
for (Injector injector : injectors) {
|
||||
injector.inject(context, null);
|
||||
}
|
||||
return null;
|
||||
callInContext((ContextualCallable<Void>) context -> {
|
||||
for (Injector injector : injectors) {
|
||||
injector.inject(context, null);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
void addInjectorsForMethods(Method[] methods, boolean statics, List<Injector> injectors) {
|
||||
addInjectorsForMembers(Arrays.asList(methods), statics, injectors,
|
||||
new InjectorFactory<Method>() {
|
||||
public Injector create(ContainerImpl container, Method method,
|
||||
String name) throws MissingDependencyException {
|
||||
return new MethodInjector(container, method, name);
|
||||
}
|
||||
});
|
||||
addInjectorsForMembers(Arrays.asList(methods), statics, injectors, MethodInjector::new);
|
||||
}
|
||||
|
||||
void addInjectorsForFields(Field[] fields, boolean statics, List<Injector> injectors) {
|
||||
addInjectorsForMembers(Arrays.asList(fields), statics, injectors,
|
||||
new InjectorFactory<Field>() {
|
||||
public Injector create(ContainerImpl container, Field field,
|
||||
String name) throws MissingDependencyException {
|
||||
return new FieldInjector(container, field, name);
|
||||
}
|
||||
});
|
||||
addInjectorsForMembers(Arrays.asList(fields), statics, injectors, FieldInjector::new);
|
||||
}
|
||||
|
||||
<M extends Member & AnnotatedElement> void addInjectorsForMembers(
|
||||
List<M> members, boolean statics, List<Injector> injectors, InjectorFactory<M> injectorFactory) {
|
||||
List<M> members, boolean statics, List<Injector> injectors, InjectorFactory<M> injectorFactory) {
|
||||
for (M member : members) {
|
||||
if (isStatic(member) == statics) {
|
||||
Inject inject = member.getAnnotation(Inject.class);
|
||||
@@ -148,12 +146,12 @@ class ContainerImpl implements Container {
|
||||
interface InjectorFactory<M extends Member & AnnotatedElement> {
|
||||
|
||||
Injector create(ContainerImpl container, M member, String name)
|
||||
throws MissingDependencyException;
|
||||
throws MissingDependencyException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a given {@link Member} is static or not.
|
||||
*
|
||||
*
|
||||
* @param member checked for the static modifier.
|
||||
* @return true if member is static, false otherwise.
|
||||
*/
|
||||
@@ -163,13 +161,13 @@ class ContainerImpl implements Container {
|
||||
|
||||
/**
|
||||
* Determines if a given {@link Member} is considered to be public for reflection usage or not.
|
||||
*
|
||||
*
|
||||
* @param member checked to see if it is public for reflection usage.
|
||||
* @return true if member is public for reflection usage, false otherwise.
|
||||
*/
|
||||
private static boolean isPublicForReflection(Member member) {
|
||||
return Modifier.isPublic(member.getModifiers()) &&
|
||||
Modifier.isPublic(member.getDeclaringClass().getModifiers());
|
||||
Modifier.isPublic(member.getDeclaringClass().getModifiers());
|
||||
}
|
||||
|
||||
static class FieldInjector implements Injector {
|
||||
@@ -179,7 +177,7 @@ class ContainerImpl implements Container {
|
||||
final ExternalContext<?> externalContext;
|
||||
|
||||
public FieldInjector(ContainerImpl container, Field field, String name)
|
||||
throws MissingDependencyException {
|
||||
throws MissingDependencyException {
|
||||
this.field = field;
|
||||
if (!isPublicForReflection(field) && !field.isAccessible()) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
@@ -190,7 +188,7 @@ class ContainerImpl implements Container {
|
||||
field.setAccessible(true);
|
||||
} catch (AccessControlException e) {
|
||||
throw new DependencyException("Security manager in use, could not access field: "
|
||||
+ field.getDeclaringClass().getName() + "(" + field.getName() + ")", e);
|
||||
+ field.getDeclaringClass().getName() + "(" + field.getName() + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,8 +223,12 @@ class ContainerImpl implements Container {
|
||||
* @param parameterTypes parameter types
|
||||
* @return injections
|
||||
*/
|
||||
<M extends AccessibleObject & Member> ParameterInjector<?>[]
|
||||
getParametersInjectors(M member, Annotation[][] annotations, Class[] parameterTypes, String defaultName) throws MissingDependencyException {
|
||||
<M extends AccessibleObject & Member> ParameterInjector<?>[] getParametersInjectors(
|
||||
M member,
|
||||
Annotation[][] annotations,
|
||||
Class<?>[] parameterTypes,
|
||||
String defaultName
|
||||
) throws MissingDependencyException {
|
||||
final List<ParameterInjector<?>> parameterInjectors = new ArrayList<>();
|
||||
|
||||
final Iterator<Annotation[]> annotationsIterator = Arrays.asList(annotations).iterator();
|
||||
@@ -247,12 +249,11 @@ class ContainerImpl implements Container {
|
||||
}
|
||||
|
||||
final ExternalContext<T> externalContext = ExternalContext.newInstance(member, key, this);
|
||||
return new ParameterInjector<T>(externalContext, factory);
|
||||
return new ParameterInjector<>(externalContext, factory);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private ParameterInjector<?>[] toArray(List<ParameterInjector<?>> parameterInjections) {
|
||||
return parameterInjections.toArray(new ParameterInjector[parameterInjections.size()]);
|
||||
return parameterInjections.toArray(new ParameterInjector[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,7 +262,7 @@ class ContainerImpl implements Container {
|
||||
Inject findInject(Annotation[] annotations) {
|
||||
for (Annotation annotation : annotations) {
|
||||
if (annotation.annotationType() == Inject.class) {
|
||||
return Inject.class.cast(annotation);
|
||||
return (Inject) annotation;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -283,7 +284,7 @@ class ContainerImpl implements Container {
|
||||
method.setAccessible(true);
|
||||
} catch (AccessControlException e) {
|
||||
throw new DependencyException("Security manager in use, could not access method: "
|
||||
+ name + "(" + method.getName() + ")", e);
|
||||
+ name + "(" + method.getName() + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +293,7 @@ class ContainerImpl implements Container {
|
||||
throw new DependencyException(method + " has no parameters to inject.");
|
||||
}
|
||||
parameterInjectors = container.getParametersInjectors(
|
||||
method, method.getParameterAnnotations(), parameterTypes, name);
|
||||
method, method.getParameterAnnotations(), parameterTypes, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -305,14 +306,12 @@ class ContainerImpl implements Container {
|
||||
}
|
||||
}
|
||||
|
||||
Map<Class<?>, ConstructorInjector> constructors =
|
||||
new ReferenceCache<Class<?>, ConstructorInjector>() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ConstructorInjector<?> create(Class<?> implementation) {
|
||||
return new ConstructorInjector(ContainerImpl.this, implementation);
|
||||
}
|
||||
};
|
||||
Map<Class<?>, ConstructorInjector<?>> constructors = new ReferenceCache<Class<?>, ConstructorInjector<?>>() {
|
||||
@Override
|
||||
protected ConstructorInjector<?> create(Class<?> implementation) {
|
||||
return new ConstructorInjector<>(ContainerImpl.this, implementation);
|
||||
}
|
||||
};
|
||||
|
||||
static class ConstructorInjector<T> {
|
||||
|
||||
@@ -334,7 +333,7 @@ class ContainerImpl implements Container {
|
||||
constructor.setAccessible(true);
|
||||
} catch (AccessControlException e) {
|
||||
throw new DependencyException("Security manager in use, could not access constructor: "
|
||||
+ implementation.getName() + "(" + constructor.getName() + ")", e);
|
||||
+ implementation.getName() + "(" + constructor.getName() + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,14 +358,14 @@ class ContainerImpl implements Container {
|
||||
}
|
||||
|
||||
ParameterInjector<?>[] constructParameterInjector(
|
||||
Inject inject, ContainerImpl container, Constructor<T> constructor) throws MissingDependencyException {
|
||||
Inject inject, ContainerImpl container, Constructor<T> constructor) throws MissingDependencyException {
|
||||
return constructor.getParameterTypes().length == 0
|
||||
? null // default constructor.
|
||||
: container.getParametersInjectors(
|
||||
constructor,
|
||||
constructor.getParameterAnnotations(),
|
||||
constructor.getParameterTypes(),
|
||||
inject.value()
|
||||
? null // default constructor.
|
||||
: container.getParametersInjectors(
|
||||
constructor,
|
||||
constructor.getParameterAnnotations(),
|
||||
constructor.getParameterTypes(),
|
||||
inject.value()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -378,7 +377,7 @@ class ContainerImpl implements Container {
|
||||
if (constructor.getAnnotation(Inject.class) != null) {
|
||||
if (found != null) {
|
||||
throw new DependencyException("More than one constructor annotated"
|
||||
+ " with @Inject found in " + implementation + ".");
|
||||
+ " with @Inject found in " + implementation + ".");
|
||||
}
|
||||
found = constructor;
|
||||
}
|
||||
@@ -466,7 +465,7 @@ class ContainerImpl implements Container {
|
||||
}
|
||||
}
|
||||
|
||||
private static Object[] getParameters(Member member, InternalContext context, ParameterInjector[] parameterInjectors) {
|
||||
private static Object[] getParameters(Member member, InternalContext context, ParameterInjector<?>[] parameterInjectors) {
|
||||
if (parameterInjectors == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -494,13 +493,12 @@ class ContainerImpl implements Container {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> T getInstance(Class<T> type, String name, InternalContext context) {
|
||||
final ExternalContext<?> previous = context.getExternalContext();
|
||||
final Key<T> key = Key.newInstance(type, name);
|
||||
context.setExternalContext(ExternalContext.newInstance(null, key, this));
|
||||
try {
|
||||
final InternalFactory o = getFactory(key);
|
||||
final InternalFactory<? extends T> o = getFactory(key);
|
||||
if (o != null) {
|
||||
return getFactory(key).create(context);
|
||||
} else {
|
||||
@@ -517,39 +515,25 @@ class ContainerImpl implements Container {
|
||||
|
||||
@Override
|
||||
public void inject(final Object o) {
|
||||
callInContext(new ContextualCallable<Void>() {
|
||||
public Void call(InternalContext context) {
|
||||
inject(o, context);
|
||||
return null;
|
||||
}
|
||||
callInContext((ContextualCallable<Void>) context -> {
|
||||
inject(o, context);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T inject(final Class<T> implementation) {
|
||||
return callInContext(new ContextualCallable<T>() {
|
||||
public T call(InternalContext context) {
|
||||
return inject(implementation, context);
|
||||
}
|
||||
});
|
||||
return callInContext(context -> inject(implementation, context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInstance(final Class<T> type, final String name) {
|
||||
return callInContext(new ContextualCallable<T>() {
|
||||
public T call(InternalContext context) {
|
||||
return getInstance(type, name, context);
|
||||
}
|
||||
});
|
||||
return callInContext(context -> getInstance(type, name, context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInstance(final Class<T> type) {
|
||||
return callInContext(new ContextualCallable<T>() {
|
||||
public T call(InternalContext context) {
|
||||
return getInstance(type, context);
|
||||
}
|
||||
});
|
||||
return callInContext(context -> getInstance(type, context));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -561,12 +545,7 @@ class ContainerImpl implements Container {
|
||||
return names;
|
||||
}
|
||||
|
||||
ThreadLocal<Object[]> localContext = new ThreadLocal<Object[]>() {
|
||||
@Override
|
||||
protected Object[] initialValue() {
|
||||
return new Object[1];
|
||||
}
|
||||
};
|
||||
ThreadLocal<Object[]> localContext = ThreadLocal.withInitial(() -> new Object[1]);
|
||||
|
||||
/**
|
||||
* Looks up thread local context. Creates (and removes) a new context if necessary.
|
||||
@@ -598,7 +577,7 @@ class ContainerImpl implements Container {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> ConstructorInjector<T> getConstructor(Class<T> implementation) {
|
||||
return constructors.get(implementation);
|
||||
return (ConstructorInjector<T>) constructors.get(implementation);
|
||||
}
|
||||
|
||||
final ThreadLocal<Object> localScopeStrategy = new ThreadLocal<>();
|
||||
|
||||
@@ -23,23 +23,39 @@ import com.opensymphony.xwork2.ActionInvocation;
|
||||
/**
|
||||
* Provides default implementations of optional lifecycle methods
|
||||
*/
|
||||
public abstract class AbstractInterceptor implements Interceptor {
|
||||
public abstract class AbstractInterceptor implements ConditionalInterceptor {
|
||||
|
||||
private boolean disabled;
|
||||
|
||||
/**
|
||||
* Does nothing
|
||||
*/
|
||||
public void init() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Does nothing
|
||||
*/
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Override to handle interception
|
||||
*/
|
||||
public abstract String intercept(ActionInvocation invocation) throws Exception;
|
||||
|
||||
/**
|
||||
* Allows to skip executing a given interceptor, just define {@code <param name="disabled">true</param>}
|
||||
* or use other way to override interceptor's parameters, see
|
||||
* <a href="https://struts.apache.org/core-developers/interceptors#interceptor-parameter-overriding">docs</a>.
|
||||
* @param disable if set to true, execution of a given interceptor will be skipped.
|
||||
*/
|
||||
public void setDisabled(String disable) {
|
||||
this.disabled = Boolean.parseBoolean(disable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldIntercept(ActionInvocation invocation) {
|
||||
return !this.disabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
|
||||
/**
|
||||
* A marking interface, when implemented allows to conditionally execute a given interceptor
|
||||
* within the current action invocation.
|
||||
*
|
||||
* @since Struts 6.1.1
|
||||
*/
|
||||
public interface ConditionalInterceptor extends Interceptor {
|
||||
|
||||
/**
|
||||
* Determines if a given interceptor should be executed in the current processing of action invocation.
|
||||
*
|
||||
* @param invocation current {@link ActionInvocation} to determine if the interceptor should be executed
|
||||
* @return true if the given interceptor should be included in the current action invocation
|
||||
* @since 6.1.1
|
||||
*/
|
||||
boolean shouldIntercept(ActionInvocation invocation);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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);
|
||||
|
||||
}
|
||||
+165
-11
@@ -26,6 +26,7 @@ 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;
|
||||
@@ -33,12 +34,15 @@ 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.Parameter;
|
||||
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;
|
||||
|
||||
@@ -62,6 +66,8 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
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) {
|
||||
@@ -183,8 +189,10 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
|
||||
for (Map.Entry<String, Parameter> entry : params.entrySet()) {
|
||||
String parameterName = entry.getKey();
|
||||
boolean isAcceptableParameter = isAcceptableParameter(parameterName, action);
|
||||
isAcceptableParameter &= isAcceptableParameterValue(entry.getValue(), action);
|
||||
|
||||
if (isAcceptableParameter(parameterName, action)) {
|
||||
if (isAcceptableParameter) {
|
||||
acceptableParameters.put(parameterName, entry.getValue());
|
||||
}
|
||||
}
|
||||
@@ -237,8 +245,8 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
if (action instanceof TextProvider) {
|
||||
TextProvider tp = (TextProvider) action;
|
||||
developerNotification = tp.getText("devmode.notification",
|
||||
"Developer Notification:\n{0}",
|
||||
new String[]{developerNotification}
|
||||
"Developer Notification:\n{0}",
|
||||
new String[]{developerNotification}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -264,6 +272,23 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
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
|
||||
@@ -291,6 +316,15 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
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);
|
||||
@@ -311,14 +345,37 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
"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);
|
||||
}
|
||||
@@ -332,8 +389,8 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
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());
|
||||
"https://struts.apache.org/security/#accepted--excluded-patterns",
|
||||
paramName, result.getAcceptedPattern());
|
||||
} else {
|
||||
LOG.debug("Parameter [{}] didn't match accepted pattern [{}]!", paramName, result.getAcceptedPattern());
|
||||
}
|
||||
@@ -345,8 +402,8 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
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());
|
||||
"https://struts.apache.org/security/#accepted--excluded-patterns",
|
||||
paramName, result.getExcludedPattern());
|
||||
} else {
|
||||
LOG.debug("Parameter [{}] matches excluded pattern [{}]!", paramName, result.getExcludedPattern());
|
||||
}
|
||||
@@ -355,6 +412,54 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
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
|
||||
*
|
||||
@@ -397,4 +502,53 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,10 +268,10 @@ public class OgnlUtil {
|
||||
try {
|
||||
if (maxLength == null || maxLength.isEmpty()) {
|
||||
Ognl.applyExpressionMaxLength(null);
|
||||
LOG.info("OGNL Expression Max Length disabled.");
|
||||
LOG.warn("OGNL Expression Max Length disabled.");
|
||||
} else {
|
||||
Ognl.applyExpressionMaxLength(Integer.parseInt(maxLength));
|
||||
LOG.info("OGNL Expression Max Length enabled with {}.", maxLength);
|
||||
LOG.debug("OGNL Expression Max Length enabled with {}.", maxLength);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOG.error("Unable to set OGNL Expression Max Length {}.", maxLength); // Help configuration debugging.
|
||||
|
||||
+5
@@ -109,6 +109,11 @@ public class XWorkListPropertyAccessor extends ListPropertyAccessor {
|
||||
if (listSize <= index) {
|
||||
Object result;
|
||||
|
||||
if (index > autoGrowCollectionLimit) {
|
||||
throw new OgnlException("Error auto growing collection size to " + index + " which limited to "
|
||||
+ autoGrowCollectionLimit);
|
||||
}
|
||||
|
||||
for (int i = listSize; i < index; i++) {
|
||||
list.add(null);
|
||||
}
|
||||
|
||||
@@ -28,9 +28,17 @@ import org.apache.struts2.StrutsException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.*;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.Locator;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXNotRecognizedException;
|
||||
import org.xml.sax.SAXNotSupportedException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
@@ -48,28 +56,24 @@ import java.util.Map;
|
||||
public class DomHelper {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(DomHelper.class);
|
||||
|
||||
public static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
|
||||
|
||||
public static Location getLocationObject(Element element) {
|
||||
return LocationAttributes.getLocation(element);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a W3C Document that remembers the location of each element in
|
||||
* the source file. The location of element nodes can then be retrieved
|
||||
* using the {@link #getLocationObject(Element)} method.
|
||||
*
|
||||
* @param inputSource the inputSource to read the document from
|
||||
*
|
||||
* @return the W3C Document
|
||||
*/
|
||||
public static Document parse(InputSource inputSource) {
|
||||
return parse(inputSource, null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a W3C Document that remembers the location of each element in
|
||||
* the source file. The location of element nodes can then be retrieved
|
||||
@@ -77,17 +81,16 @@ public class DomHelper {
|
||||
*
|
||||
* @param inputSource the inputSource to read the document from
|
||||
* @param dtdMappings a map of DTD names and public ids
|
||||
*
|
||||
* @return the W3C Document
|
||||
*/
|
||||
public static Document parse(InputSource inputSource, Map<String, String> dtdMappings) {
|
||||
|
||||
|
||||
SAXParserFactory factory = null;
|
||||
String parserProp = System.getProperty("xwork.saxParserFactory");
|
||||
if (parserProp != null) {
|
||||
try {
|
||||
ObjectFactory objectFactory = ActionContext.getContext().getContainer().getInstance(ObjectFactory.class);
|
||||
Class clazz = objectFactory.getClassInstance(parserProp);
|
||||
Class<?> clazz = objectFactory.getClassInstance(parserProp);
|
||||
factory = (SAXParserFactory) clazz.newInstance();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Unable to load saxParserFactory set by system property 'xwork.saxParserFactory': {}", parserProp, e);
|
||||
@@ -98,6 +101,13 @@ public class DomHelper {
|
||||
factory = SAXParserFactory.newInstance();
|
||||
}
|
||||
|
||||
try {
|
||||
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||
} catch (ParserConfigurationException | SAXNotRecognizedException | SAXNotSupportedException e) {
|
||||
throw new StrutsException("Unable to disable resolving external entities!", e);
|
||||
}
|
||||
|
||||
factory.setValidating((dtdMappings != null));
|
||||
factory.setNamespaceAware(true);
|
||||
|
||||
@@ -107,22 +117,22 @@ public class DomHelper {
|
||||
} catch (Exception ex) {
|
||||
throw new StrutsException("Unable to create SAX parser", ex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
DOMBuilder builder = new DOMBuilder();
|
||||
|
||||
// Enhance the sax stream with location information
|
||||
ContentHandler locationHandler = new LocationAttributes.Pipe(builder);
|
||||
|
||||
|
||||
try {
|
||||
parser.parse(inputSource, new StartHandler(locationHandler, dtdMappings));
|
||||
} catch (Exception ex) {
|
||||
throw new StrutsException(ex);
|
||||
}
|
||||
|
||||
|
||||
return builder.getDocument();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The <code>DOMBuilder</code> is a utility class that will generate a W3C
|
||||
* DOM Document from SAX events.
|
||||
@@ -130,27 +140,35 @@ public class DomHelper {
|
||||
* @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
|
||||
*/
|
||||
static public class DOMBuilder implements ContentHandler {
|
||||
|
||||
/** The default transformer factory shared by all instances */
|
||||
|
||||
/**
|
||||
* The default transformer factory shared by all instances
|
||||
*/
|
||||
protected static SAXTransformerFactory FACTORY;
|
||||
|
||||
/** The transformer factory */
|
||||
|
||||
/**
|
||||
* The transformer factory
|
||||
*/
|
||||
protected SAXTransformerFactory factory;
|
||||
|
||||
/** The result */
|
||||
|
||||
/**
|
||||
* The result
|
||||
*/
|
||||
protected DOMResult result;
|
||||
|
||||
/** The parentNode */
|
||||
|
||||
/**
|
||||
* The parentNode
|
||||
*/
|
||||
protected Node parentNode;
|
||||
|
||||
|
||||
protected ContentHandler nextHandler;
|
||||
|
||||
|
||||
static {
|
||||
String parserProp = System.getProperty("xwork.saxTransformerFactory");
|
||||
if (parserProp != null) {
|
||||
try {
|
||||
ObjectFactory objectFactory = ActionContext.getContext().getContainer().getInstance(ObjectFactory.class);
|
||||
Class clazz = objectFactory.getClassInstance(parserProp);
|
||||
Class<?> clazz = objectFactory.getClassInstance(parserProp);
|
||||
FACTORY = (SAXTransformerFactory) clazz.newInstance();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Unable to load SAXTransformerFactory set by system property 'xwork.saxTransformerFactory': {}", parserProp, e);
|
||||
@@ -158,7 +176,7 @@ public class DomHelper {
|
||||
}
|
||||
|
||||
if (FACTORY == null) {
|
||||
FACTORY = (SAXTransformerFactory) TransformerFactory.newInstance();
|
||||
FACTORY = (SAXTransformerFactory) TransformerFactory.newInstance();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,15 +186,16 @@ public class DomHelper {
|
||||
public DOMBuilder() {
|
||||
this((Node) null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new instance of this DOMBuilder.
|
||||
*
|
||||
* @param factory the SAX transformer factory
|
||||
*/
|
||||
public DOMBuilder(SAXTransformerFactory factory) {
|
||||
this(factory, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new instance that appends nodes to the given parent node.
|
||||
*
|
||||
@@ -185,19 +204,19 @@ public class DomHelper {
|
||||
public DOMBuilder(Node parentNode) {
|
||||
this(null, parentNode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new instance of this DOMBuilder.
|
||||
*
|
||||
* @param factory the SAX transformer factory
|
||||
* @param factory the SAX transformer factory
|
||||
* @param parentNode the parent node
|
||||
*/
|
||||
public DOMBuilder(SAXTransformerFactory factory, Node parentNode) {
|
||||
this.factory = factory == null? FACTORY: factory;
|
||||
this.factory = factory == null ? FACTORY : factory;
|
||||
this.parentNode = parentNode;
|
||||
setup();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setup this instance transformer and result objects.
|
||||
*/
|
||||
@@ -215,7 +234,7 @@ public class DomHelper {
|
||||
throw new StrutsException("Fatal-Error: Unable to get transformer handler", local);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the newly built Document.
|
||||
*
|
||||
@@ -230,60 +249,61 @@ public class DomHelper {
|
||||
return this.result.getNode().getOwnerDocument();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setDocumentLocator(Locator locator) {
|
||||
nextHandler.setDocumentLocator(locator);
|
||||
}
|
||||
|
||||
|
||||
public void startDocument() throws SAXException {
|
||||
nextHandler.startDocument();
|
||||
}
|
||||
|
||||
|
||||
public void endDocument() throws SAXException {
|
||||
nextHandler.endDocument();
|
||||
}
|
||||
|
||||
|
||||
public void startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
|
||||
nextHandler.startElement(uri, loc, raw, attrs);
|
||||
}
|
||||
|
||||
|
||||
public void endElement(String arg0, String arg1, String arg2) throws SAXException {
|
||||
nextHandler.endElement(arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
|
||||
public void startPrefixMapping(String arg0, String arg1) throws SAXException {
|
||||
nextHandler.startPrefixMapping(arg0, arg1);
|
||||
}
|
||||
|
||||
|
||||
public void endPrefixMapping(String arg0) throws SAXException {
|
||||
nextHandler.endPrefixMapping(arg0);
|
||||
}
|
||||
|
||||
|
||||
public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
|
||||
nextHandler.characters(arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
|
||||
public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
|
||||
nextHandler.ignorableWhitespace(arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
|
||||
public void processingInstruction(String arg0, String arg1) throws SAXException {
|
||||
nextHandler.processingInstruction(arg0, arg1);
|
||||
}
|
||||
|
||||
|
||||
public void skippedEntity(String arg0) throws SAXException {
|
||||
nextHandler.skippedEntity(arg0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class StartHandler extends DefaultHandler {
|
||||
|
||||
private ContentHandler nextHandler;
|
||||
private Map<String, String> dtdMappings;
|
||||
|
||||
|
||||
private final ContentHandler nextHandler;
|
||||
private final Map<String, String> dtdMappings;
|
||||
|
||||
/**
|
||||
* Create a filter that is chained to another handler.
|
||||
* @param next the next handler in the chain.
|
||||
*
|
||||
* @param next the next handler in the chain.
|
||||
* @param dtdMappings map of DTD mappings
|
||||
*/
|
||||
public StartHandler(ContentHandler next, Map<String, String> dtdMappings) {
|
||||
@@ -295,12 +315,12 @@ public class DomHelper {
|
||||
public void setDocumentLocator(Locator locator) {
|
||||
nextHandler.setDocumentLocator(locator);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void startDocument() throws SAXException {
|
||||
nextHandler.startDocument();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void endDocument() throws SAXException {
|
||||
nextHandler.endDocument();
|
||||
@@ -345,7 +365,7 @@ public class DomHelper {
|
||||
public void skippedEntity(String arg0) throws SAXException {
|
||||
nextHandler.skippedEntity(arg0);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public InputSource resolveEntity(String publicId, String systemId) {
|
||||
if (dtdMappings != null && dtdMappings.containsKey(publicId)) {
|
||||
@@ -356,7 +376,7 @@ public class DomHelper {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void warning(SAXParseException exception) {
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.util;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -57,7 +59,7 @@ import java.util.regex.Pattern;
|
||||
* </table>
|
||||
*
|
||||
* <p>
|
||||
* Excaping hasn't been implemented since the intended use of these patterns will be in matching URLs.
|
||||
* Escaping hasn't been implemented since the intended use of these patterns will be in matching URLs.
|
||||
* </p>
|
||||
*
|
||||
* @since 2.1
|
||||
@@ -75,38 +77,47 @@ public class NamedVariablePatternMatcher implements PatternMatcher<NamedVariable
|
||||
* @return The compiled pattern, null if the pattern was null or empty
|
||||
*/
|
||||
public CompiledPattern compilePattern(String data) {
|
||||
StringBuilder regex = new StringBuilder();
|
||||
if (data != null && data.length() > 0) {
|
||||
List<String> varNames = new ArrayList<>();
|
||||
StringBuilder varName = null;
|
||||
for (int x=0; x<data.length(); x++) {
|
||||
char c = data.charAt(x);
|
||||
switch (c) {
|
||||
case '{' : varName = new StringBuilder(); break;
|
||||
case '}' : if (varName == null) {
|
||||
throw new IllegalArgumentException("Mismatched braces in pattern");
|
||||
}
|
||||
varNames.add(varName.toString());
|
||||
regex.append("([^/]+)");
|
||||
varName = null;
|
||||
break;
|
||||
default : if (varName == null) {
|
||||
regex.append(c);
|
||||
} else {
|
||||
varName.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new CompiledPattern(Pattern.compile(regex.toString()), varNames);
|
||||
if (StringUtils.isEmpty(data)) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
|
||||
int len = data.length();
|
||||
StringBuilder regex = new StringBuilder();
|
||||
List<String> varNames = new ArrayList<>();
|
||||
int s = 0;
|
||||
while (s < len) {
|
||||
int e = data.indexOf('{', s);
|
||||
if (e < 0 && data.indexOf('}') > -1) {
|
||||
throw new IllegalArgumentException("Missing openning '{' in [" + data + "]!");
|
||||
}
|
||||
if (e < 0) {
|
||||
regex.append(Pattern.quote(data.substring(s)));
|
||||
break;
|
||||
}
|
||||
if (e > s) {
|
||||
regex.append(Pattern.quote(data.substring(s, e)));
|
||||
}
|
||||
s = e + 1;
|
||||
e = data.indexOf('}', s);
|
||||
if (e < 0) {
|
||||
return null;
|
||||
}
|
||||
String varName = data.substring(s, e);
|
||||
if (StringUtils.isEmpty(varName)) {
|
||||
throw new IllegalArgumentException("Missing variable name in [" + data + "]!");
|
||||
}
|
||||
varNames.add(varName);
|
||||
regex.append("([^/]+)");
|
||||
s = e + 1;
|
||||
}
|
||||
return new CompiledPattern(Pattern.compile(regex.toString()), varNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to process the data against the compiled expression. If successful, the map will contain
|
||||
* the matched data, using the specified variable names in the original pattern.
|
||||
*
|
||||
* @param map The map of variables
|
||||
* @param map The map of variables
|
||||
* @param data The data to match
|
||||
* @param expr The compiled pattern
|
||||
* @return True if matched, false if not matched, the data was null, or the data was an empty string
|
||||
@@ -116,8 +127,8 @@ public class NamedVariablePatternMatcher implements PatternMatcher<NamedVariable
|
||||
if (data != null && data.length() > 0) {
|
||||
Matcher matcher = expr.getPattern().matcher(data);
|
||||
if (matcher.matches()) {
|
||||
for (int x=0; x<expr.getVariableNames().size(); x++) {
|
||||
map.put(expr.getVariableNames().get(x), matcher.group(x+1));
|
||||
for (int x = 0; x < expr.getVariableNames().size(); x++) {
|
||||
map.put(expr.getVariableNames().get(x), matcher.group(x + 1));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -129,8 +140,8 @@ public class NamedVariablePatternMatcher implements PatternMatcher<NamedVariable
|
||||
* Stores the compiled pattern and the variable names matches will correspond to.
|
||||
*/
|
||||
public static class CompiledPattern {
|
||||
private Pattern pattern;
|
||||
private List<String> variableNames;
|
||||
private final Pattern pattern;
|
||||
private final List<String> variableNames;
|
||||
|
||||
|
||||
public CompiledPattern(Pattern pattern, List<String> variableNames) {
|
||||
|
||||
@@ -222,7 +222,7 @@ import com.opensymphony.xwork2.util.ValueStack;
|
||||
* <!-- START SNIPPET: exShortCircuitingValidators -->
|
||||
* <!DOCTYPE validators PUBLIC
|
||||
* "-//Apache Struts//XWork Validator 1.0.3//EN"
|
||||
* "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
|
||||
* "https://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
|
||||
* <validators>
|
||||
* <!-- Field Validators for email field -->
|
||||
* <field name="email">
|
||||
|
||||
@@ -115,7 +115,7 @@ package com.opensymphony.xwork2.validator;
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: exValidationRules1 -->
|
||||
* <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN"
|
||||
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
|
||||
"https://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
|
||||
* <validators>
|
||||
* <field name="bar">
|
||||
* <field-validator type="required">
|
||||
|
||||
@@ -56,6 +56,9 @@ public final class StrutsConstants {
|
||||
/** Comma separated list of patterns (java.util.regex.Pattern) to be excluded from Struts2-processing */
|
||||
public static final String STRUTS_ACTION_EXCLUDE_PATTERN = "struts.action.excludePattern";
|
||||
|
||||
/** A custom separator used to split list of patterns (java.util.regex.Pattern) to be excluded from Struts2-processing */
|
||||
public static final String STRUTS_ACTION_EXCLUDE_PATTERN_SEPARATOR = "struts.action.excludePattern.separator";
|
||||
|
||||
/** Whether to use the response encoding (JSP page encoding) for s:include tag processing (false - use STRUTS_I18N_ENCODING - by default) */
|
||||
public static final String STRUTS_TAG_INCLUDETAG_USERESPONSEENCODING = "struts.tag.includetag.useResponseEncoding";
|
||||
|
||||
@@ -139,6 +142,12 @@ public final class StrutsConstants {
|
||||
/** The maximize size of a multipart request (file upload) */
|
||||
public static final String STRUTS_MULTIPART_MAXSIZE = "struts.multipart.maxSize";
|
||||
|
||||
/** The maximized number of files allowed to upload */
|
||||
public static final String STRUTS_MULTIPART_MAXFILES = "struts.multipart.maxFiles";
|
||||
|
||||
/** The maximum length of a string parameter in a multipart request. */
|
||||
public static final String STRUTS_MULTIPART_MAX_STRING_LENGTH = "struts.multipart.maxStringLength";
|
||||
|
||||
/** The directory to use for storing uploaded files */
|
||||
public static final String STRUTS_MULTIPART_SAVEDIR = "struts.multipart.saveDir";
|
||||
|
||||
@@ -376,7 +385,7 @@ public final class StrutsConstants {
|
||||
public static final String STRUTS_CONVERTER_FILE_PROCESSOR = "struts.converter.file.processor";
|
||||
public static final String STRUTS_CONVERTER_ANNOTATION_PROCESSOR = "struts.converter.annotation.processor";
|
||||
public static final String STRUTS_CONVERTER_CREATOR = "struts.converter.creator";
|
||||
public static final String STRUTS_CONVERTER_HOLDER = "struts..converter.holder";
|
||||
public static final String STRUTS_CONVERTER_HOLDER = "struts.converter.holder";
|
||||
|
||||
public static final String STRUTS_EXPRESSION_PARSER = "struts.expression.parser";
|
||||
|
||||
@@ -398,7 +407,11 @@ public final class StrutsConstants {
|
||||
/** Enables action: prefix */
|
||||
public static final String STRUTS_MAPPER_ACTION_PREFIX_ENABLED = "struts.mapper.action.prefix.enabled";
|
||||
|
||||
/** Enables access to actions in other namespaces than current with action: prefix */
|
||||
/**
|
||||
* Enables access to actions in other namespaces than current with action: prefix
|
||||
* @deprecated it will be removed soon, please refactor your application
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String STRUTS_MAPPER_ACTION_PREFIX_CROSSNAMESPACES = "struts.mapper.action.prefix.crossNamespaces";
|
||||
|
||||
public static final String DEFAULT_TEMPLATE_TYPE_CONFIG_KEY = "struts.ui.templateSuffix";
|
||||
@@ -450,4 +463,12 @@ public final class StrutsConstants {
|
||||
|
||||
/** See {@link org.apache.struts2.components.Date#setDateFormatter(DateFormatter)} */
|
||||
public static final String STRUTS_DATE_FORMATTER = "struts.date.formatter";
|
||||
|
||||
public static final String STRUTS_URL_QUERY_STRING_BUILDER = "struts.url.queryStringBuilder";
|
||||
public static final String STRUTS_URL_QUERY_STRING_PARSER = "struts.url.queryStringParser";
|
||||
public static final String STRUTS_URL_ENCODER = "struts.url.encoder";
|
||||
public static final String STRUTS_URL_DECODER = "struts.url.decoder";
|
||||
|
||||
/** A global flag to set property {@link org.apache.struts2.components.Checkbox#setSubmitUnchecked(String)} */
|
||||
public static final String STRUTS_UI_CHECKBOX_SUBMIT_UNCHECKED = "struts.ui.checkbox.submitUnchecked";
|
||||
}
|
||||
|
||||
@@ -18,13 +18,14 @@
|
||||
*/
|
||||
package org.apache.struts2.components;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.views.annotations.StrutsTag;
|
||||
import org.apache.struts2.views.annotations.StrutsTagAttribute;
|
||||
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: javadoc -->
|
||||
@@ -46,15 +47,19 @@ import com.opensymphony.xwork2.util.ValueStack;
|
||||
*
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
@StrutsTag(
|
||||
name="checkbox",
|
||||
tldTagClass="org.apache.struts2.views.jsp.ui.CheckboxTag",
|
||||
description="Render a checkbox input field",
|
||||
allowDynamicAttributes=true)
|
||||
name = "checkbox",
|
||||
tldTagClass = "org.apache.struts2.views.jsp.ui.CheckboxTag",
|
||||
description = "Render a checkbox input field",
|
||||
allowDynamicAttributes = true)
|
||||
public class Checkbox extends UIBean {
|
||||
final public static String TEMPLATE = "checkbox";
|
||||
|
||||
private static final String ATTR_SUBMIT_UNCHECKED = "submitUnchecked";
|
||||
|
||||
public static final String TEMPLATE = "checkbox";
|
||||
|
||||
private String submitUncheckedGlobal;
|
||||
|
||||
protected String fieldValue;
|
||||
protected String submitUnchecked;
|
||||
@@ -69,46 +74,45 @@ public class Checkbox extends UIBean {
|
||||
|
||||
protected void evaluateExtraParams() {
|
||||
if (fieldValue != null) {
|
||||
addParameter("fieldValue", findString(fieldValue));
|
||||
addParameter(ATTR_FIELD_VALUE, findString(fieldValue));
|
||||
} else {
|
||||
addParameter("fieldValue", "true");
|
||||
addParameter(ATTR_FIELD_VALUE, "true");
|
||||
}
|
||||
|
||||
if (submitUnchecked != null) {
|
||||
Object parsedValue = findValue(submitUnchecked, Boolean.class);
|
||||
addParameter("submitUnchecked", parsedValue == null ? Boolean.valueOf(submitUnchecked) : parsedValue);
|
||||
addParameter(ATTR_SUBMIT_UNCHECKED, parsedValue == null ? Boolean.valueOf(submitUnchecked) : parsedValue);
|
||||
} else if (submitUncheckedGlobal != null) {
|
||||
addParameter(ATTR_SUBMIT_UNCHECKED, Boolean.parseBoolean(submitUncheckedGlobal));
|
||||
} else {
|
||||
addParameter("submitUnchecked", false);
|
||||
addParameter(ATTR_SUBMIT_UNCHECKED, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected Class getValueClassType() {
|
||||
@Override
|
||||
protected Class<?> getValueClassType() {
|
||||
return Boolean.class; // for checkboxes, everything needs to end up as a Boolean
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="The actual HTML value attribute of the checkbox.", defaultValue="true")
|
||||
@Inject(value = StrutsConstants.STRUTS_UI_CHECKBOX_SUBMIT_UNCHECKED, required = false)
|
||||
public void setSubmitUncheckedGlobal(String submitUncheckedGlobal) {
|
||||
this.submitUncheckedGlobal = submitUncheckedGlobal;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "The actual HTML value attribute of the checkbox.", defaultValue = "true")
|
||||
public void setFieldValue(String fieldValue) {
|
||||
this.fieldValue = fieldValue;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="If set to true, unchecked elements will be submitted with the form.", type="Boolean", defaultValue="false")
|
||||
@StrutsTagAttribute(description = "If set to true, unchecked elements will be submitted with the form. " +
|
||||
"Since Struts 6.1.1 you can use a constant \"" + StrutsConstants.STRUTS_UI_CHECKBOX_SUBMIT_UNCHECKED + "\" to set this attribute globally",
|
||||
type = "Boolean", defaultValue = "false")
|
||||
public void setSubmitUnchecked(String submitUnchecked) {
|
||||
this.submitUnchecked = submitUnchecked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated since 2.5.27
|
||||
* @deprecated use {@link #setLabelPosition(String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
@StrutsTagAttribute(description="(Deprecated) Define label position of form element (top/left), also 'right' is supported when using 'xhtml' theme")
|
||||
public void setLabelposition(String labelPosition) {
|
||||
super.setLabelPosition(labelPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
@StrutsTagAttribute(description="Define label position of form element (top/left), also 'right' is supported when using 'xhtml' theme")
|
||||
@StrutsTagAttribute(description = "Define label position of form element (top/left), also 'right' is supported when using 'xhtml' theme")
|
||||
public void setLabelPosition(String labelPosition) {
|
||||
super.setLabelPosition(labelPosition);
|
||||
}
|
||||
|
||||
@@ -21,5 +21,7 @@ package org.apache.struts2.components;
|
||||
import java.util.Map;
|
||||
|
||||
public interface ExtraParameterProvider {
|
||||
public Map getExtraParameters();
|
||||
|
||||
Map<String, Object> getExtraParameters();
|
||||
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapper;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
import org.apache.struts2.url.QueryStringParser;
|
||||
import org.apache.struts2.views.util.UrlHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -48,6 +49,7 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
|
||||
private ActionMapper actionMapper;
|
||||
private UrlHelper urlHelper;
|
||||
private QueryStringParser queryStringParser;
|
||||
|
||||
@Override
|
||||
@Inject
|
||||
@@ -60,6 +62,11 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
this.urlHelper = urlHelper;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setQueryStringParser(QueryStringParser queryStringParser) {
|
||||
this.queryStringParser = queryStringParser;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@@ -152,10 +159,10 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
Map actionParams = null;
|
||||
Map<String, Object> actionParams = null;
|
||||
if (action != null && action.indexOf('?') > 0) {
|
||||
String queryString = action.substring(action.indexOf('?') + 1);
|
||||
actionParams = urlHelper.parseQueryString(queryString, false);
|
||||
actionParams = queryStringParser.parse(queryString, false);
|
||||
action = action.substring(0, action.indexOf('?'));
|
||||
}
|
||||
|
||||
@@ -164,19 +171,19 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
String actionMethod = nameMapping.getMethod();
|
||||
|
||||
final ActionConfig actionConfig = formComponent.configuration.getRuntimeConfiguration().getActionConfig(
|
||||
namespace, actionName);
|
||||
namespace, actionName);
|
||||
if (actionConfig != null) {
|
||||
|
||||
ActionMapping mapping = new ActionMapping(actionName, namespace, actionMethod, formComponent.parameters);
|
||||
String result = urlHelper.buildUrl(formComponent.actionMapper.getUriFromActionMapping(mapping),
|
||||
formComponent.request, formComponent.response, actionParams, scheme, formComponent.includeContext, true, false, false);
|
||||
formComponent.request, formComponent.response, actionParams, scheme, formComponent.includeContext, true, false, false);
|
||||
formComponent.addParameter("action", result);
|
||||
|
||||
// let's try to get the actual action class and name
|
||||
// this can be used for getting the list of validators
|
||||
formComponent.addParameter("actionName", actionName);
|
||||
try {
|
||||
Class clazz = formComponent.objectFactory.getClassInstance(actionConfig.getClassName());
|
||||
Class<?> clazz = formComponent.objectFactory.getClassInstance(actionConfig.getClassName());
|
||||
formComponent.addParameter("actionClass", clazz);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// this is OK, we'll just move on
|
||||
@@ -258,7 +265,7 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
}
|
||||
|
||||
if (UrlProvider.NONE.equalsIgnoreCase(includeParams)) {
|
||||
mergeRequestParameters(urlComponent.getValue(), urlComponent.getParameters(), Collections.<String, Object>emptyMap());
|
||||
mergeRequestParameters(urlComponent.getValue(), urlComponent.getParameters(), Collections.emptyMap());
|
||||
} else if (UrlProvider.ALL.equalsIgnoreCase(includeParams)) {
|
||||
mergeRequestParameters(urlComponent.getValue(), urlComponent.getParameters(), urlComponent.getHttpServletRequest().getParameterMap());
|
||||
|
||||
@@ -284,7 +291,7 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
|
||||
private void includeGetParameters(UrlProvider urlComponent) {
|
||||
String query = extractQueryString(urlComponent);
|
||||
mergeRequestParameters(urlComponent.getValue(), urlComponent.getParameters(), urlHelper.parseQueryString(query, false));
|
||||
mergeRequestParameters(urlComponent.getValue(), urlComponent.getParameters(), queryStringParser.parse(query, false));
|
||||
}
|
||||
|
||||
private String extractQueryString(UrlProvider urlComponent) {
|
||||
@@ -309,7 +316,7 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
* Merge request parameters into current parameters. If a parameter is
|
||||
* already present, than the request parameter in the current request and value attribute
|
||||
* will not override its value.
|
||||
*
|
||||
* <p>
|
||||
* The priority is as follows:-
|
||||
* <ul>
|
||||
* <li>parameter from the current request (least priority)</li>
|
||||
@@ -317,8 +324,8 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
* <li>parameter from the param tag (most priority)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param value the value attribute (URL to be generated by this component)
|
||||
* @param parameters component parameters
|
||||
* @param value the value attribute (URL to be generated by this component)
|
||||
* @param parameters component parameters
|
||||
* @param contextParameters request parameters
|
||||
*/
|
||||
protected void mergeRequestParameters(String value, Map<String, Object> parameters, Map<String, ?> contextParameters) {
|
||||
@@ -332,7 +339,7 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
if (StringUtils.contains(value, "?")) {
|
||||
String queryString = value.substring(value.indexOf('?') + 1);
|
||||
|
||||
mergedParams = urlHelper.parseQueryString(queryString, false);
|
||||
mergedParams = queryStringParser.parse(queryString, false);
|
||||
for (Map.Entry<String, ?> entry : contextParameters.entrySet()) {
|
||||
if (!mergedParams.containsKey(entry.getKey())) {
|
||||
mergedParams.put(entry.getKey(), entry.getValue());
|
||||
|
||||
@@ -45,6 +45,7 @@ import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -435,8 +436,13 @@ import java.util.Map;
|
||||
*
|
||||
*/
|
||||
public abstract class UIBean extends Component {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(UIBean.class);
|
||||
|
||||
protected static final String ATTR_FIELD_VALUE = "fieldValue";
|
||||
protected static final String ATTR_NAME_VALUE = "nameValue";
|
||||
protected static final String ATTR_VALUE = "value";
|
||||
|
||||
protected HttpServletRequest request;
|
||||
protected HttpServletResponse response;
|
||||
|
||||
@@ -689,7 +695,6 @@ public abstract class UIBean extends Component {
|
||||
|
||||
if (labelPosition != null) {
|
||||
String labelPosition = findString(this.labelPosition);
|
||||
addParameter("labelposition", labelPosition);
|
||||
addParameter("labelPosition", labelPosition);
|
||||
}
|
||||
|
||||
@@ -795,37 +800,7 @@ public abstract class UIBean extends Component {
|
||||
addParameter("title", findString(title));
|
||||
}
|
||||
|
||||
|
||||
// see if the value was specified as a parameter already
|
||||
final String NAME_VALUE = "nameValue";
|
||||
if (parameters.containsKey("value")) {
|
||||
parameters.put(NAME_VALUE, parameters.get("value"));
|
||||
} else {
|
||||
if (evaluateNameValue()) {
|
||||
final Class<?> valueClazz = getValueClassType();
|
||||
|
||||
if (valueClazz != null) {
|
||||
if (value != null) {
|
||||
addParameter(NAME_VALUE, findValue(value, valueClazz));
|
||||
} else if (translatedName != null) {
|
||||
boolean evaluated = !translatedName.equals(this.name);
|
||||
boolean reevaluate = !evaluated || isAcceptableExpression(translatedName);
|
||||
if (!reevaluate) {
|
||||
addParameter(NAME_VALUE, translatedName);
|
||||
} else {
|
||||
String expr = completeExpression(translatedName);
|
||||
addParameter(NAME_VALUE, findValue(expr, valueClazz));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (value != null) {
|
||||
addParameter(NAME_VALUE, findValue(value));
|
||||
} else if (translatedName != null) {
|
||||
addParameter(NAME_VALUE, findValue(translatedName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
applyValueParameter(translatedName);
|
||||
|
||||
final Form form = (Form) findAncestor(Form.class);
|
||||
|
||||
@@ -909,6 +884,46 @@ public abstract class UIBean extends Component {
|
||||
evaluateExtraParams();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to calculate the "value" parameter based either on the provided {@link #value} or {@link #name}
|
||||
* @param translatedName the already evaluated {@link #name}
|
||||
*/
|
||||
protected void applyValueParameter(String translatedName) {
|
||||
// see if the value has been specified as a parameter already
|
||||
if (parameters.containsKey(ATTR_VALUE)) {
|
||||
parameters.put(ATTR_NAME_VALUE, parameters.get(ATTR_VALUE));
|
||||
} else {
|
||||
if (evaluateNameValue()) {
|
||||
final Class<?> valueClazz = getValueClassType();
|
||||
|
||||
if (valueClazz != null) {
|
||||
if (value != null) {
|
||||
addParameter(ATTR_NAME_VALUE, findValue(value, valueClazz));
|
||||
} else if (translatedName != null) {
|
||||
processTranslatedName(translatedName, (expr) -> findValue(expr, valueClazz));
|
||||
}
|
||||
} else {
|
||||
if (value != null) {
|
||||
addParameter(ATTR_NAME_VALUE, findValue(value));
|
||||
} else if (translatedName != null) {
|
||||
processTranslatedName(translatedName, this::findValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processTranslatedName(String translatedName, Function<String, Object> evaluator) {
|
||||
boolean evaluated = !translatedName.equals(this.name);
|
||||
boolean reevaluate = !evaluated || isAcceptableExpression(translatedName);
|
||||
if (!reevaluate) {
|
||||
addParameter(ATTR_NAME_VALUE, translatedName);
|
||||
} else {
|
||||
String expr = completeExpression(translatedName);
|
||||
addParameter(ATTR_NAME_VALUE, evaluator.apply(expr));
|
||||
}
|
||||
}
|
||||
|
||||
protected String escape(String name) {
|
||||
// escape any possible values that can make the ID painful to work with in JavaScript
|
||||
if (name != null) {
|
||||
@@ -1073,12 +1088,6 @@ public abstract class UIBean extends Component {
|
||||
this.cssClass = cssClass;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@StrutsTagAttribute(description="(Deprecated) The css class to use for element - it's an alias of cssClass attribute.")
|
||||
public void setClass(String cssClass) {
|
||||
this.cssClass = cssClass;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="The css style definitions for element to use")
|
||||
public void setCssStyle(String cssStyle) {
|
||||
this.cssStyle = cssStyle;
|
||||
@@ -1119,16 +1128,6 @@ public abstract class UIBean extends Component {
|
||||
this.labelSeparator = labelseparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated since 2.5.27
|
||||
* @deprecated use {@link #setLabelPosition(String)} instead
|
||||
*/
|
||||
@StrutsTagAttribute(description="(Deprecated) Define label position of form element (top/left)")
|
||||
@Deprecated
|
||||
public void setLabelposition(String labelPosition) {
|
||||
this.labelPosition = labelPosition;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="Define label position of form element (top/left)")
|
||||
public void setLabelPosition(String labelPosition) {
|
||||
this.labelPosition = labelPosition;
|
||||
|
||||
@@ -25,7 +25,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implemntations of this interface can be used to build a URL
|
||||
* Implementations of this interface can be used to build a URL
|
||||
*/
|
||||
public interface UrlProvider {
|
||||
/**
|
||||
@@ -37,9 +37,9 @@ public interface UrlProvider {
|
||||
* get - include only GET parameters in the URL (default)
|
||||
* all - include both GET and POST parameters in the URL
|
||||
*/
|
||||
public static final String NONE = "none";
|
||||
public static final String GET = "get";
|
||||
public static final String ALL = "all";
|
||||
String NONE = "none";
|
||||
String GET = "get";
|
||||
String ALL = "all";
|
||||
|
||||
boolean isPutInContext();
|
||||
|
||||
@@ -55,7 +55,7 @@ public interface UrlProvider {
|
||||
|
||||
String getIncludeParams();
|
||||
|
||||
Map getParameters();
|
||||
Map<String, Object> getParameters();
|
||||
|
||||
HttpServletRequest getHttpServletRequest();
|
||||
|
||||
@@ -78,19 +78,19 @@ public interface UrlProvider {
|
||||
boolean isForceAddSchemeHostAndPort();
|
||||
|
||||
boolean isEscapeAmp();
|
||||
|
||||
|
||||
String getPortletMode();
|
||||
|
||||
|
||||
String getWindowState();
|
||||
|
||||
String determineActionURL(String action, String namespace, String method, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Map parameters, String scheme, boolean includeContext, boolean encode, boolean forceAddSchemeHostAndPort, boolean escapeAmp);
|
||||
|
||||
String determineActionURL(String action, String namespace, String method, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Map<String, ?> parameters, String scheme, boolean includeContext, boolean encode, boolean forceAddSchemeHostAndPort, boolean escapeAmp);
|
||||
|
||||
String determineNamespace(String namespace, ValueStack stack, HttpServletRequest req);
|
||||
|
||||
String getAnchor();
|
||||
|
||||
|
||||
String getPortletUrlType();
|
||||
|
||||
|
||||
ValueStack getStack();
|
||||
|
||||
void setUrlIncludeParams(String urlIncludeParams);
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.inject.*;
|
||||
import com.opensymphony.xwork2.util.ClassLoaderUtil;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
||||
@@ -66,6 +66,10 @@ import org.apache.struts2.dispatcher.DispatcherErrorHandler;
|
||||
import org.apache.struts2.dispatcher.StaticContentLoader;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapper;
|
||||
import org.apache.struts2.dispatcher.multipart.MultiPartRequest;
|
||||
import org.apache.struts2.url.QueryStringBuilder;
|
||||
import org.apache.struts2.url.QueryStringParser;
|
||||
import org.apache.struts2.url.UrlDecoder;
|
||||
import org.apache.struts2.url.UrlEncoder;
|
||||
import org.apache.struts2.util.ContentTypeMatcher;
|
||||
import org.apache.struts2.views.freemarker.FreemarkerManager;
|
||||
import org.apache.struts2.views.util.UrlHelper;
|
||||
@@ -429,6 +433,11 @@ public class StrutsBeanSelectionProvider extends AbstractBeanSelectionProvider {
|
||||
alias(ExpressionCacheFactory.class, StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_FACTORY, builder, props, Scope.SINGLETON);
|
||||
alias(BeanInfoCacheFactory.class, StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_FACTORY, builder, props, Scope.SINGLETON);
|
||||
|
||||
alias(QueryStringBuilder.class, StrutsConstants.STRUTS_URL_QUERY_STRING_BUILDER, builder, props, Scope.SINGLETON);
|
||||
alias(QueryStringParser.class, StrutsConstants.STRUTS_URL_QUERY_STRING_PARSER, builder, props, Scope.SINGLETON);
|
||||
alias(UrlEncoder.class, StrutsConstants.STRUTS_URL_ENCODER, builder, props, Scope.SINGLETON);
|
||||
alias(UrlDecoder.class, StrutsConstants.STRUTS_URL_DECODER, builder, props, Scope.SINGLETON);
|
||||
|
||||
switchDevMode(props);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,8 @@ public class ConstantConfig {
|
||||
private String uiTheme;
|
||||
private String uiThemeExpansionToken;
|
||||
private Long multipartMaxSize;
|
||||
private Long multipartMaxFiles;
|
||||
private Long multipartMaxStringLength;
|
||||
private String multipartSaveDir;
|
||||
private Integer multipartBufferSize;
|
||||
private BeanConfig multipartParser;
|
||||
@@ -195,6 +197,8 @@ public class ConstantConfig {
|
||||
map.put(StrutsConstants.STRUTS_UI_THEME, uiTheme);
|
||||
map.put(StrutsConstants.STRUTS_UI_THEME_EXPANSION_TOKEN, uiThemeExpansionToken);
|
||||
map.put(StrutsConstants.STRUTS_MULTIPART_MAXSIZE, Objects.toString(multipartMaxSize, null));
|
||||
map.put(StrutsConstants.STRUTS_MULTIPART_MAXFILES, Objects.toString(multipartMaxFiles, null));
|
||||
map.put(StrutsConstants.STRUTS_MULTIPART_MAX_STRING_LENGTH, Objects.toString(multipartMaxStringLength, null));
|
||||
map.put(StrutsConstants.STRUTS_MULTIPART_SAVEDIR, multipartSaveDir);
|
||||
map.put(StrutsConstants.STRUTS_MULTIPART_BUFFERSIZE, Objects.toString(multipartBufferSize, null));
|
||||
map.put(StrutsConstants.STRUTS_MULTIPART_PARSER, beanConfToString(multipartParser));
|
||||
@@ -580,6 +584,22 @@ public class ConstantConfig {
|
||||
this.multipartMaxSize = multipartMaxSize;
|
||||
}
|
||||
|
||||
public Long getMultipartMaxFiles() {
|
||||
return multipartMaxFiles;
|
||||
}
|
||||
|
||||
public void setMultipartMaxFiles(Long multipartMaxFiles) {
|
||||
this.multipartMaxFiles = multipartMaxFiles;
|
||||
}
|
||||
|
||||
public Long getMultipartMaxStringLength() {
|
||||
return multipartMaxStringLength;
|
||||
}
|
||||
|
||||
public void setMultipartMaxStringLength(Long multipartMaxStringLength) {
|
||||
this.multipartMaxStringLength = multipartMaxStringLength;
|
||||
}
|
||||
|
||||
public String getMultipartSaveDir() {
|
||||
return multipartSaveDir;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,12 @@ package org.apache.struts2.dispatcher;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -36,10 +41,9 @@ public class InitOperations {
|
||||
* Creates and initializes the dispatcher
|
||||
*
|
||||
* @param filterConfig host configuration
|
||||
*
|
||||
* @return the dispatcher
|
||||
*/
|
||||
public Dispatcher initDispatcher( HostConfig filterConfig ) {
|
||||
public Dispatcher initDispatcher(HostConfig filterConfig) {
|
||||
Dispatcher dispatcher = createDispatcher(filterConfig);
|
||||
dispatcher.init();
|
||||
return dispatcher;
|
||||
@@ -49,10 +53,10 @@ public class InitOperations {
|
||||
* Initializes the static content loader with the filter configuration
|
||||
*
|
||||
* @param filterConfig host configuration
|
||||
* @param dispatcher the dispatcher
|
||||
* @param dispatcher the dispatcher
|
||||
* @return the static content loader
|
||||
*/
|
||||
public StaticContentLoader initStaticContentLoader( HostConfig filterConfig, Dispatcher dispatcher ) {
|
||||
public StaticContentLoader initStaticContentLoader(HostConfig filterConfig, Dispatcher dispatcher) {
|
||||
StaticContentLoader loader = dispatcher.getContainer().getInstance(StaticContentLoader.class);
|
||||
loader.setHostConfig(filterConfig);
|
||||
return loader;
|
||||
@@ -60,7 +64,6 @@ public class InitOperations {
|
||||
|
||||
/**
|
||||
* @return The dispatcher on the thread.
|
||||
*
|
||||
* @throws IllegalStateException If there is no dispatcher available
|
||||
*/
|
||||
public Dispatcher findDispatcherOnThread() {
|
||||
@@ -75,12 +78,11 @@ public class InitOperations {
|
||||
* Create a {@link Dispatcher}
|
||||
*
|
||||
* @param filterConfig host configuration
|
||||
*
|
||||
* @return The dispatcher on the thread.
|
||||
*/
|
||||
protected Dispatcher createDispatcher(HostConfig filterConfig) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
for ( Iterator<String> parameterNames = filterConfig.getInitParameterNames(); parameterNames.hasNext(); ) {
|
||||
for (Iterator<String> parameterNames = filterConfig.getInitParameterNames(); parameterNames.hasNext(); ) {
|
||||
String name = parameterNames.next();
|
||||
String value = filterConfig.getInitParameter(name);
|
||||
params.put(name, value);
|
||||
@@ -96,20 +98,23 @@ public class InitOperations {
|
||||
* Extract a list of patterns to exclude from request filtering
|
||||
*
|
||||
* @param dispatcher The dispatcher to check for exclude pattern configuration
|
||||
*
|
||||
* @return a List of Patterns for request to exclude if apply, or <tt>null</tt>
|
||||
*
|
||||
* @see org.apache.struts2.StrutsConstants#STRUTS_ACTION_EXCLUDE_PATTERN
|
||||
*/
|
||||
public List<Pattern> buildExcludedPatternsList( Dispatcher dispatcher ) {
|
||||
return buildExcludedPatternsList(dispatcher.getContainer().getInstance(String.class, StrutsConstants.STRUTS_ACTION_EXCLUDE_PATTERN));
|
||||
public List<Pattern> buildExcludedPatternsList(Dispatcher dispatcher) {
|
||||
String excludePatterns = dispatcher.getContainer().getInstance(String.class, StrutsConstants.STRUTS_ACTION_EXCLUDE_PATTERN);
|
||||
String separator = dispatcher.getContainer().getInstance(String.class, StrutsConstants.STRUTS_ACTION_EXCLUDE_PATTERN_SEPARATOR);
|
||||
if (separator == null) {
|
||||
separator = ",";
|
||||
}
|
||||
return buildExcludedPatternsList(excludePatterns, separator);
|
||||
}
|
||||
|
||||
private List<Pattern> buildExcludedPatternsList( String patterns ) {
|
||||
|
||||
private List<Pattern> buildExcludedPatternsList(String patterns, String separator) {
|
||||
if (null != patterns && patterns.trim().length() != 0) {
|
||||
List<Pattern> list = new ArrayList<>();
|
||||
String[] tokens = patterns.split(",");
|
||||
for ( String token : tokens ) {
|
||||
String[] tokens = patterns.split(separator);
|
||||
for (String token : tokens) {
|
||||
list.add(Pattern.compile(token.trim()));
|
||||
}
|
||||
return Collections.unmodifiableList(list);
|
||||
|
||||
@@ -34,7 +34,12 @@ import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.util.PrefixTrie;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -236,6 +241,11 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
this.allowActionPrefix = BooleanUtils.toBoolean(allowActionPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.1.0 - please refactor your application to avoid using this functionality
|
||||
* @param allowActionCrossNamespaceAccess true to enable cross namespace action access
|
||||
*/
|
||||
@Deprecated
|
||||
@Inject(value = StrutsConstants.STRUTS_MAPPER_ACTION_PREFIX_CROSSNAMESPACES)
|
||||
public void setAllowActionCrossNamespaceAccess(String allowActionCrossNamespaceAccess) {
|
||||
this.allowActionCrossNamespaceAccess = BooleanUtils.toBoolean(allowActionCrossNamespaceAccess);
|
||||
@@ -289,8 +299,8 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
}
|
||||
|
||||
parseNameAndNamespace(uri, mapping, configManager);
|
||||
extractMethodName(mapping, configManager);
|
||||
handleSpecialParameters(request, mapping);
|
||||
extractMethodName(mapping, configManager);
|
||||
return parseActionName(mapping);
|
||||
}
|
||||
|
||||
@@ -344,8 +354,8 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
/**
|
||||
* Parses the name and namespace from the uri
|
||||
*
|
||||
* @param uri The uri
|
||||
* @param mapping The action mapping to populate
|
||||
* @param uri The uri
|
||||
* @param mapping The action mapping to populate
|
||||
* @param configManager configuration manager
|
||||
*/
|
||||
protected void parseNameAndNamespace(String uri, ActionMapping mapping, ConfigurationManager configManager) {
|
||||
@@ -453,10 +463,14 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
/**
|
||||
* Reads defined method name for a given action from configuration
|
||||
*
|
||||
* @param mapping current instance of {@link ActionMapping}
|
||||
* @param mapping current instance of {@link ActionMapping}
|
||||
* @param configurationManager current instance of {@link ConfigurationManager}
|
||||
*/
|
||||
protected void extractMethodName(ActionMapping mapping, ConfigurationManager configurationManager) {
|
||||
if (mapping.getMethod() != null && allowDynamicMethodCalls) {
|
||||
LOG.debug("DMI is enabled and method has been already mapped based on bang operator");
|
||||
return;
|
||||
}
|
||||
String methodName = null;
|
||||
for (PackageConfig cfg : configurationManager.getConfiguration().getPackageConfigs().values()) {
|
||||
if (cfg.getNamespace().equals(mapping.getNamespace())) {
|
||||
@@ -507,7 +521,7 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null if no extension is specified.
|
||||
* @return null if no extension is specified.
|
||||
*/
|
||||
protected String getDefaultExtension() {
|
||||
if (extensions == null) {
|
||||
@@ -552,17 +566,19 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
}
|
||||
|
||||
protected void handleDynamicMethod(ActionMapping mapping, StringBuilder uri) {
|
||||
if (!allowDynamicMethodCalls) {
|
||||
LOG.debug("DMI is disabled, ignoring appending !method to the URI");
|
||||
return;
|
||||
}
|
||||
// See WW-3965
|
||||
if (StringUtils.isNotEmpty(mapping.getMethod())) {
|
||||
if (allowDynamicMethodCalls) {
|
||||
// handle "name!method" convention.
|
||||
String name = mapping.getName();
|
||||
if (!name.contains("!")) {
|
||||
// Append the method as no bang found
|
||||
uri.append("!").append(mapping.getMethod());
|
||||
}
|
||||
} else {
|
||||
// handle "name!method" convention.
|
||||
String name = mapping.getName();
|
||||
if (!name.contains("!")) {
|
||||
// Append the method as no bang found
|
||||
uri.append("!").append(mapping.getMethod());
|
||||
} else if (name.endsWith("!")) {
|
||||
uri.append(mapping.getMethod());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ 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.util.URLDecoderUtil;
|
||||
import org.apache.struts2.url.UrlDecoder;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
@@ -32,18 +32,26 @@ import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Extended version of {@link RestfulActionMapper}, see documentation for more details
|
||||
* https://struts.apache.org/core-developers/restful-action-mapper.html
|
||||
* <a href="https://struts.apache.org/core-developers/restful-action-mapper.html">Restful2ActionMapper</a>
|
||||
*/
|
||||
public class Restful2ActionMapper extends DefaultActionMapper {
|
||||
|
||||
protected static final Logger LOG = LogManager.getLogger(Restful2ActionMapper.class);
|
||||
private static final Logger LOG = LogManager.getLogger(Restful2ActionMapper.class);
|
||||
|
||||
public static final String HTTP_METHOD_PARAM = "__http_method";
|
||||
|
||||
private String idParameterName = null;
|
||||
|
||||
private UrlDecoder decoder;
|
||||
|
||||
public Restful2ActionMapper() {
|
||||
setSlashesInActionNames("true");
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setDecoder(UrlDecoder decoder) {
|
||||
this.decoder = decoder;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
@@ -54,7 +62,7 @@ public class Restful2ActionMapper extends DefaultActionMapper {
|
||||
throw new IllegalStateException("This action mapper requires the setting 'slashesInActionNames' to be set to 'true'");
|
||||
}
|
||||
ActionMapping mapping = super.getMapping(request, configManager);
|
||||
|
||||
|
||||
if (mapping == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -78,7 +86,7 @@ public class Restful2ActionMapper extends DefaultActionMapper {
|
||||
// Index e.g. foo/
|
||||
if (isGet(request)) {
|
||||
mapping.setMethod("index");
|
||||
|
||||
|
||||
// Creating a new entry on POST e.g. foo/
|
||||
} else if (isPost(request)) {
|
||||
mapping.setMethod("create");
|
||||
@@ -96,14 +104,14 @@ public class Restful2ActionMapper extends DefaultActionMapper {
|
||||
// Removing an item e.g. foo/1
|
||||
} else if (isDelete(request)) {
|
||||
mapping.setMethod("remove");
|
||||
|
||||
// Updating an item e.g. foo/1
|
||||
|
||||
// Updating an item e.g. foo/1
|
||||
} else if (isPut(request)) {
|
||||
mapping.setMethod("update");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (idParameterName != null && lastSlashPos > -1) {
|
||||
actionName = actionName.substring(0, lastSlashPos);
|
||||
}
|
||||
@@ -129,10 +137,10 @@ public class Restful2ActionMapper extends DefaultActionMapper {
|
||||
|
||||
while (st.hasMoreTokens()) {
|
||||
if (isNameTok) {
|
||||
paramName = URLDecoderUtil.decode(st.nextToken(), "UTF-8");
|
||||
paramName = decoder.decode(st.nextToken(), "UTF-8", false);
|
||||
isNameTok = false;
|
||||
} else {
|
||||
paramValue = URLDecoderUtil.decode(st.nextToken(), "UTF-8");
|
||||
paramValue = decoder.decode(st.nextToken(), "UTF-8", false);
|
||||
|
||||
if ((paramName != null) && (paramName.length() > 0)) {
|
||||
parameters.put(paramName, paramValue);
|
||||
@@ -143,7 +151,7 @@ public class Restful2ActionMapper extends DefaultActionMapper {
|
||||
}
|
||||
if (parameters.size() > 0) {
|
||||
if (mapping.getParams() == null) {
|
||||
mapping.setParams(new HashMap<String, Object>());
|
||||
mapping.setParams(new HashMap<>());
|
||||
}
|
||||
mapping.getParams().putAll(parameters);
|
||||
}
|
||||
|
||||
@@ -19,10 +19,11 @@
|
||||
package org.apache.struts2.dispatcher.mapper;
|
||||
|
||||
import com.opensymphony.xwork2.config.ConfigurationManager;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.RequestUtils;
|
||||
import org.apache.struts2.util.URLDecoderUtil;
|
||||
import org.apache.struts2.url.UrlDecoder;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
@@ -32,11 +33,19 @@ import java.util.StringTokenizer;
|
||||
/**
|
||||
* Simple Restfull Action Mapper to support REST application
|
||||
* See docs for more information
|
||||
* https://struts.apache.org/core-developers/restful-action-mapper.html
|
||||
* <a href="https://struts.apache.org/core-developers/restful-action-mapper.html">RestfulActionMapper</a>
|
||||
*/
|
||||
public class RestfulActionMapper implements ActionMapper {
|
||||
|
||||
protected static final Logger LOG = LogManager.getLogger(RestfulActionMapper.class);
|
||||
|
||||
private UrlDecoder decoder;
|
||||
|
||||
@Inject
|
||||
public void setDecoder(UrlDecoder decoder) {
|
||||
this.decoder = decoder;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.struts2.dispatcher.mapper.ActionMapper#getMapping(javax.servlet.http.HttpServletRequest)
|
||||
*/
|
||||
@@ -64,10 +73,10 @@ public class RestfulActionMapper implements ActionMapper {
|
||||
|
||||
while (st.hasMoreTokens()) {
|
||||
if (isNameTok) {
|
||||
paramName = URLDecoderUtil.decode(st.nextToken(), "UTF-8");
|
||||
paramName = decoder.decode(st.nextToken(), "UTF-8", false);
|
||||
isNameTok = false;
|
||||
} else {
|
||||
paramValue = URLDecoderUtil.decode(st.nextToken(), "UTF-8");
|
||||
paramValue = decoder.decode(st.nextToken(), "UTF-8", false);
|
||||
|
||||
if ((paramName != null) && (paramName.length() > 0)) {
|
||||
parameters.put(paramName, paramValue);
|
||||
@@ -98,7 +107,7 @@ public class RestfulActionMapper implements ActionMapper {
|
||||
if (value != null) {
|
||||
retVal.append("/");
|
||||
retVal.append(value);
|
||||
}
|
||||
}
|
||||
|
||||
return retVal.toString();
|
||||
}
|
||||
|
||||
+23
-5
@@ -51,8 +51,17 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
/**
|
||||
* Specifies the maximum size of the entire request.
|
||||
*/
|
||||
protected long maxSize;
|
||||
protected boolean maxSizeProvided;
|
||||
protected Long maxSize;
|
||||
|
||||
/**
|
||||
* Specifies the maximum number of files in one request.
|
||||
*/
|
||||
protected Long maxFiles;
|
||||
|
||||
/**
|
||||
* Specifies the maximum length of a string parameter in a multipart request.
|
||||
*/
|
||||
protected Long maxStringLength;
|
||||
|
||||
/**
|
||||
* Specifies the buffer size to use during streaming.
|
||||
@@ -84,10 +93,19 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
*/
|
||||
@Inject(StrutsConstants.STRUTS_MULTIPART_MAXSIZE)
|
||||
public void setMaxSize(String maxSize) {
|
||||
this.maxSizeProvided = true;
|
||||
this.maxSize = Long.parseLong(maxSize);
|
||||
}
|
||||
|
||||
@Inject(StrutsConstants.STRUTS_MULTIPART_MAXFILES)
|
||||
public void setMaxFiles(String maxFiles) {
|
||||
this.maxFiles = Long.parseLong(maxFiles);
|
||||
}
|
||||
|
||||
@Inject(StrutsConstants.STRUTS_MULTIPART_MAX_STRING_LENGTH)
|
||||
public void setMaxStringLength(String maxStringLength) {
|
||||
this.maxStringLength = Long.parseLong(maxStringLength);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setLocaleProviderFactory(LocaleProviderFactory localeProviderFactory) {
|
||||
defaultLocale = localeProviderFactory.createLocaleProvider().getLocale();
|
||||
@@ -134,9 +152,9 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
int forwardSlash = fileName.lastIndexOf('/');
|
||||
int backwardSlash = fileName.lastIndexOf('\\');
|
||||
if (forwardSlash != -1 && forwardSlash > backwardSlash) {
|
||||
fileName = fileName.substring(forwardSlash + 1, fileName.length());
|
||||
fileName = fileName.substring(forwardSlash + 1);
|
||||
} else {
|
||||
fileName = fileName.substring(backwardSlash + 1, fileName.length());
|
||||
fileName = fileName.substring(backwardSlash + 1);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
+62
-33
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.struts2.dispatcher.multipart;
|
||||
|
||||
import org.apache.commons.fileupload.FileCountLimitExceededException;
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.apache.commons.fileupload.FileUploadBase;
|
||||
import org.apache.commons.fileupload.FileUploadException;
|
||||
@@ -35,7 +36,13 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Multipart form data request adapter for Jakarta Commons Fileupload package.
|
||||
@@ -65,9 +72,12 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
} catch (FileUploadException e) {
|
||||
LOG.warn("Request exceeded size limit!", e);
|
||||
LocalizedMessage errorMessage;
|
||||
if(e instanceof FileUploadBase.SizeLimitExceededException) {
|
||||
if (e instanceof FileUploadBase.SizeLimitExceededException) {
|
||||
FileUploadBase.SizeLimitExceededException ex = (FileUploadBase.SizeLimitExceededException) e;
|
||||
errorMessage = buildErrorMessage(e, new Object[]{ex.getPermittedSize(), ex.getActualSize()});
|
||||
} else if (e instanceof FileCountLimitExceededException) {
|
||||
FileCountLimitExceededException ex = (FileCountLimitExceededException) e;
|
||||
errorMessage = buildErrorMessage(e, new Object[]{ex.getLimit()});
|
||||
} else {
|
||||
errorMessage = buildErrorMessage(e, new Object[]{});
|
||||
}
|
||||
@@ -101,7 +111,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
LOG.debug("Item is a file upload");
|
||||
|
||||
// Skip file uploads that don't have a file name - meaning that no file was selected.
|
||||
if (item.getName() == null || item.getName().trim().length() < 1) {
|
||||
if (item.getName() == null || item.getName().trim().isEmpty()) {
|
||||
LOG.debug("No file has been uploaded for the field: {}", item.getFieldName());
|
||||
return;
|
||||
}
|
||||
@@ -118,28 +128,42 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
}
|
||||
|
||||
protected void processNormalFormField(FileItem item, String charset) throws UnsupportedEncodingException {
|
||||
LOG.debug("Item is a normal form field");
|
||||
try {
|
||||
LOG.debug("Item is a normal form field");
|
||||
|
||||
List<String> values;
|
||||
if (params.get(item.getFieldName()) != null) {
|
||||
values = params.get(item.getFieldName());
|
||||
} else {
|
||||
values = new ArrayList<>();
|
||||
}
|
||||
List<String> values;
|
||||
if (params.get(item.getFieldName()) != null) {
|
||||
values = params.get(item.getFieldName());
|
||||
} else {
|
||||
values = new ArrayList<>();
|
||||
}
|
||||
|
||||
if (item.getSize() == 0) {
|
||||
values.add(StringUtils.EMPTY);
|
||||
} else if (charset != null) {
|
||||
values.add(item.getString(charset));
|
||||
} else {
|
||||
// note: see https://issues.apache.org/jira/browse/WW-633
|
||||
// basically, in some cases the charset may be null, so
|
||||
// we're just going to try to "other" method (no idea if this
|
||||
// will work)
|
||||
values.add(item.getString());
|
||||
long size = item.getSize();
|
||||
if (size == 0) {
|
||||
values.add(StringUtils.EMPTY);
|
||||
} else if (size > maxStringLength) {
|
||||
String errorKey = "struts.messages.upload.error.parameter.too.long";
|
||||
LocalizedMessage localizedMessage = new LocalizedMessage(this.getClass(), errorKey, null,
|
||||
new Object[]{item.getFieldName(), maxStringLength, size});
|
||||
|
||||
if (!errors.contains(localizedMessage)) {
|
||||
errors.add(localizedMessage);
|
||||
}
|
||||
return;
|
||||
|
||||
} else if (charset != null) {
|
||||
values.add(item.getString(charset));
|
||||
} else {
|
||||
// note: see https://issues.apache.org/jira/browse/WW-633
|
||||
// basically, in some cases the charset may be null, so
|
||||
// we're just going to try to "other" method (no idea if this
|
||||
// will work)
|
||||
values.add(item.getString());
|
||||
}
|
||||
params.put(item.getFieldName(), values);
|
||||
} finally {
|
||||
item.delete();
|
||||
}
|
||||
params.put(item.getFieldName(), values);
|
||||
item.delete();
|
||||
}
|
||||
|
||||
protected List<FileItem> parseRequest(HttpServletRequest servletRequest, String saveDir) throws FileUploadException {
|
||||
@@ -150,7 +174,12 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
|
||||
protected ServletFileUpload createServletFileUpload(DiskFileItemFactory fac) {
|
||||
ServletFileUpload upload = new ServletFileUpload(fac);
|
||||
upload.setSizeMax(maxSize);
|
||||
if (maxSize != null) {
|
||||
upload.setSizeMax(maxSize);
|
||||
}
|
||||
if (maxFiles != null) {
|
||||
upload.setFileCountMax(maxFiles);
|
||||
}
|
||||
return upload;
|
||||
}
|
||||
|
||||
@@ -186,7 +215,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
contentTypes.add(fileItem.getContentType());
|
||||
}
|
||||
|
||||
return contentTypes.toArray(new String[contentTypes.size()]);
|
||||
return contentTypes.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -215,7 +244,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
fileList.add(new StrutsUploadedFile(storeLocation));
|
||||
}
|
||||
|
||||
return fileList.toArray(new UploadedFile[fileList.size()]);
|
||||
return fileList.toArray(new UploadedFile[0]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -233,7 +262,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
fileNames.add(getCanonicalName(fileItem.getName()));
|
||||
}
|
||||
|
||||
return fileNames.toArray(new String[fileNames.size()]);
|
||||
return fileNames.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -251,7 +280,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
fileNames.add(((DiskFileItem) fileItem).getStoreLocation().getName());
|
||||
}
|
||||
|
||||
return fileNames.toArray(new String[fileNames.size()]);
|
||||
return fileNames.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -259,7 +288,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
*/
|
||||
public String getParameter(String name) {
|
||||
List<String> v = params.get(name);
|
||||
if (v != null && v.size() > 0) {
|
||||
if (v != null && !v.isEmpty()) {
|
||||
return v.get(0);
|
||||
}
|
||||
|
||||
@@ -278,8 +307,8 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
*/
|
||||
public String[] getParameterValues(String name) {
|
||||
List<String> v = params.get(name);
|
||||
if (v != null && v.size() > 0) {
|
||||
return v.toArray(new String[v.size()]);
|
||||
if (v != null && !v.isEmpty()) {
|
||||
return v.toArray(new String[0]);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -316,14 +345,14 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#cleanUp()
|
||||
*/
|
||||
* @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#cleanUp()
|
||||
*/
|
||||
public void cleanUp() {
|
||||
Set<String> names = files.keySet();
|
||||
for (String name : names) {
|
||||
List<FileItem> items = files.get(name);
|
||||
for (FileItem item : items) {
|
||||
LOG.debug("Removing file {} {}", name, item );
|
||||
LOG.debug("Removing file {} {}", name, item);
|
||||
if (!item.isInMemory()) {
|
||||
item.delete();
|
||||
}
|
||||
|
||||
+21
-17
@@ -30,15 +30,15 @@ import org.apache.struts2.dispatcher.LocalizedMessage;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Multi-part form data request adapter for Jakarta Commons FileUpload package that
|
||||
* leverages the streaming API rather than the traditional non-streaming API.
|
||||
*
|
||||
* <p>
|
||||
* For more details see WW-3025
|
||||
*
|
||||
* @author Chris Cranford
|
||||
* @since 2.3.18
|
||||
*/
|
||||
public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
@@ -85,7 +85,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
types.add(fileInfo.getContentType());
|
||||
}
|
||||
|
||||
return types.toArray(new String[types.size()]);
|
||||
return types.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -102,7 +102,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
files.add(new StrutsUploadedFile(fileInfo.getFile()));
|
||||
}
|
||||
|
||||
return files.toArray(new UploadedFile[files.size()]);
|
||||
return files.toArray(new UploadedFile[0]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -119,7 +119,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
names.add(getCanonicalName(fileInfo.getOriginalName()));
|
||||
}
|
||||
|
||||
return names.toArray(new String[names.size()]);
|
||||
return names.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -143,7 +143,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
names.add(fileInfo.getFile().getName());
|
||||
}
|
||||
|
||||
return names.toArray(new String[names.size()]);
|
||||
return names.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -170,7 +170,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
public String[] getParameterValues(String name) {
|
||||
List<String> values = parameters.get(name);
|
||||
if (values != null && values.size() > 0) {
|
||||
return values.toArray(new String[values.size()]);
|
||||
return values.toArray(new String[0]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -209,9 +209,12 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
// Interface with Commons FileUpload API
|
||||
// Using the Streaming API
|
||||
ServletFileUpload servletFileUpload = new ServletFileUpload();
|
||||
if (maxSizeProvided) {
|
||||
if (maxSize != null) {
|
||||
servletFileUpload.setSizeMax(maxSize);
|
||||
}
|
||||
if (maxFiles != null) {
|
||||
servletFileUpload.setFileCountMax(maxFiles);
|
||||
}
|
||||
FileItemIterator i = servletFileUpload.getItemIterator(request);
|
||||
|
||||
// Iterate the file items
|
||||
@@ -258,7 +261,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
// if maxSize is specified as -1, there is no sanity check and it's
|
||||
// safe to return true for any request, delegating the failure
|
||||
// checks later in the upload process.
|
||||
if (maxSize == -1 || request == null) {
|
||||
if ((maxSize != null && maxSize == -1) || request == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -286,8 +289,9 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
*/
|
||||
protected void addFileSkippedError(String fileName, HttpServletRequest request) {
|
||||
String exceptionMessage = "Skipped file " + fileName + "; request size limit exceeded.";
|
||||
FileSizeLimitExceededException exception = new FileUploadBase.FileSizeLimitExceededException(exceptionMessage, getRequestSize(request), maxSize);
|
||||
LocalizedMessage message = buildErrorMessage(exception, new Object[]{fileName, getRequestSize(request), maxSize});
|
||||
long allowedMaxSize = maxSize != null ? maxSize : -1;
|
||||
FileSizeLimitExceededException exception = new FileUploadBase.FileSizeLimitExceededException(exceptionMessage, getRequestSize(request), allowedMaxSize);
|
||||
LocalizedMessage message = buildErrorMessage(exception, new Object[]{fileName, getRequestSize(request), allowedMaxSize});
|
||||
if (!errors.contains(message)) {
|
||||
errors.add(message);
|
||||
}
|
||||
@@ -386,12 +390,12 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
* @throws IOException in case of IO errors
|
||||
*/
|
||||
protected boolean streamFileToDisk(FileItemStream itemStream, File file) throws IOException {
|
||||
boolean result = false;
|
||||
boolean result;
|
||||
try (InputStream input = itemStream.openStream();
|
||||
OutputStream output = new BufferedOutputStream(new FileOutputStream(file), bufferSize)) {
|
||||
OutputStream output = new BufferedOutputStream(Files.newOutputStream(file.toPath()), bufferSize)) {
|
||||
byte[] buffer = new byte[bufferSize];
|
||||
LOG.debug("Streaming file using buffer size {}.", bufferSize);
|
||||
for (int length = 0; ((length = input.read(buffer)) > 0); ) {
|
||||
for (int length; ((length = input.read(buffer)) > 0); ) {
|
||||
output.write(buffer, 0, length);
|
||||
}
|
||||
result = true;
|
||||
@@ -433,9 +437,9 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
|
||||
private static final long serialVersionUID = 1083158552766906037L;
|
||||
|
||||
private File file;
|
||||
private String contentType;
|
||||
private String originalName;
|
||||
private final File file;
|
||||
private final String contentType;
|
||||
private final String originalName;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
|
||||
@@ -47,25 +47,16 @@ public class CoepInterceptor extends AbstractInterceptor implements PreResultLis
|
||||
private static final String COEP_REPORT_HEADER = "Cross-Origin-Embedder-Policy-Report-Only";
|
||||
|
||||
private final Set<String> exemptedPaths = new HashSet<>();
|
||||
private boolean disabled = false;
|
||||
private String header = COEP_ENFORCING_HEADER;
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
if (disabled) {
|
||||
LOG.trace("COEP interceptor has been disabled");
|
||||
} else {
|
||||
invocation.addPreResultListener(this);
|
||||
}
|
||||
invocation.addPreResultListener(this);
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeResult(ActionInvocation invocation, String resultCode) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
HttpServletRequest req = invocation.getInvocationContext().getServletRequest();
|
||||
final String path = req.getContextPath();
|
||||
|
||||
@@ -92,8 +83,4 @@ public class CoepInterceptor extends AbstractInterceptor implements PreResultLis
|
||||
}
|
||||
}
|
||||
|
||||
public void setDisabled(String value) {
|
||||
disabled = Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -49,24 +49,16 @@ public class CoopInterceptor extends AbstractInterceptor implements PreResultLis
|
||||
private static final String COOP_HEADER = "Cross-Origin-Opener-Policy";
|
||||
|
||||
private final Set<String> exemptedPaths = new HashSet<>();
|
||||
private boolean disabled = false;
|
||||
private String mode = SAME_ORIGIN;
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
if (disabled) {
|
||||
LOG.trace("COOP interceptor has been disabled");
|
||||
} else {
|
||||
invocation.addPreResultListener(this);
|
||||
}
|
||||
invocation.addPreResultListener(this);
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeResult(ActionInvocation invocation, String resultCode) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
HttpServletRequest request = invocation.getInvocationContext().getServletRequest();
|
||||
String path = request.getContextPath();
|
||||
|
||||
@@ -95,7 +87,4 @@ public class CoopInterceptor extends AbstractInterceptor implements PreResultLis
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public void setDisabled(String value) {
|
||||
this.disabled = Boolean.parseBoolean(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +22,17 @@ import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ActionProxy;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.interceptor.exec.BackgroundProcess;
|
||||
import org.apache.struts2.interceptor.exec.ExecutorProvider;
|
||||
import org.apache.struts2.interceptor.exec.StrutsBackgroundProcess;
|
||||
import org.apache.struts2.interceptor.exec.StrutsExecutorProvider;
|
||||
import org.apache.struts2.util.TokenHelper;
|
||||
import org.apache.struts2.views.freemarker.FreemarkerResult;
|
||||
|
||||
@@ -84,7 +89,7 @@ import java.util.Map;
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <p><u>Interceptor parameters:</u></p>
|
||||
*
|
||||
* <p>
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
*
|
||||
* <ul>
|
||||
@@ -94,11 +99,11 @@ import java.util.Map;
|
||||
* <li>delaySleepInterval (optional) - only used with delay. Used for waking up at certain intervals to check if the background process is already done. Default is 100 millis.</li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
*
|
||||
* <p><u>Extending the interceptor:</u></p>
|
||||
*
|
||||
* <p>
|
||||
* <!-- START SNIPPET: extending -->
|
||||
* <p>
|
||||
* If you wish to make special preparations before and/or after the invocation of the background thread, you can extend
|
||||
@@ -167,9 +172,8 @@ import java.util.Map;
|
||||
* <result name="success">longRunningAction-success.jsp</result>
|
||||
* </action>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* <!-- END SNIPPET: example -->
|
||||
*
|
||||
*/
|
||||
public class ExecuteAndWaitInterceptor extends MethodFilterInterceptor {
|
||||
|
||||
@@ -186,22 +190,28 @@ public class ExecuteAndWaitInterceptor extends MethodFilterInterceptor {
|
||||
private int threadPriority = Thread.NORM_PRIORITY;
|
||||
|
||||
private Container container;
|
||||
private ExecutorProvider executor;
|
||||
|
||||
@Inject
|
||||
public void setContainer(Container container) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
@Inject(required = false)
|
||||
public void setExecutorProvider(ExecutorProvider executorProvider) {
|
||||
this.executor = executorProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new background process
|
||||
*
|
||||
* @param name The process name
|
||||
* @param name The process name
|
||||
* @param actionInvocation The action invocation
|
||||
* @param threadPriority The thread priority
|
||||
* @param threadPriority The thread priority
|
||||
* @return The new process
|
||||
*/
|
||||
protected BackgroundProcess getNewBackgroundProcess(String name, ActionInvocation actionInvocation, int threadPriority) {
|
||||
return new BackgroundProcess(name + "BackgroundThread", actionInvocation, threadPriority);
|
||||
return new StrutsBackgroundProcess(actionInvocation, name + "_background-process", threadPriority);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,7 +219,6 @@ public class ExecuteAndWaitInterceptor extends MethodFilterInterceptor {
|
||||
* are mapped to requests.
|
||||
*
|
||||
* @param proxy action proxy
|
||||
*
|
||||
* @return the name of the background thread
|
||||
*/
|
||||
protected String getBackgroundProcessName(ActionProxy proxy) {
|
||||
@@ -223,10 +232,10 @@ public class ExecuteAndWaitInterceptor extends MethodFilterInterceptor {
|
||||
ActionProxy proxy = actionInvocation.getProxy();
|
||||
String name = getBackgroundProcessName(proxy);
|
||||
ActionContext context = actionInvocation.getInvocationContext();
|
||||
Map session = context.getSession();
|
||||
Map<String, Object> session = context.getSession();
|
||||
HttpSession httpSession = ServletActionContext.getRequest().getSession(true);
|
||||
|
||||
Boolean secondTime = true;
|
||||
Boolean secondTime = true;
|
||||
if (executeAfterValidationPass) {
|
||||
secondTime = (Boolean) context.get(KEY);
|
||||
if (secondTime == null) {
|
||||
@@ -250,8 +259,13 @@ public class ExecuteAndWaitInterceptor extends MethodFilterInterceptor {
|
||||
}
|
||||
|
||||
if ((!executeAfterValidationPass || secondTime) && bp == null) {
|
||||
bp = getNewBackgroundProcess(name, actionInvocation, threadPriority);
|
||||
bp = getNewBackgroundProcess(name, actionInvocation, threadPriority).prepare();
|
||||
session.put(KEY + name, bp);
|
||||
if (executor.isShutdown()) {
|
||||
LOG.warn("Executor is shutting down, cannot execute a new process");
|
||||
return actionInvocation.invoke();
|
||||
}
|
||||
executor.execute(bp);
|
||||
performInitialDelay(bp); // first time let some time pass before showing wait page
|
||||
secondTime = false;
|
||||
}
|
||||
@@ -259,16 +273,16 @@ public class ExecuteAndWaitInterceptor extends MethodFilterInterceptor {
|
||||
if ((!executeAfterValidationPass || !secondTime) && bp != null && !bp.isDone()) {
|
||||
actionInvocation.getStack().push(bp.getAction());
|
||||
|
||||
final String token = TokenHelper.getToken();
|
||||
if (token != null) {
|
||||
TokenHelper.setSessionToken(TokenHelper.getTokenName(), token);
|
||||
final String token = TokenHelper.getToken();
|
||||
if (token != null) {
|
||||
TokenHelper.setSessionToken(TokenHelper.getTokenName(), token);
|
||||
}
|
||||
|
||||
Map results = proxy.getConfig().getResults();
|
||||
Map<String, ResultConfig> results = proxy.getConfig().getResults();
|
||||
if (!results.containsKey(WAIT)) {
|
||||
LOG.warn("ExecuteAndWait interceptor has detected that no result named 'wait' is available. " +
|
||||
"Defaulting to a plain built-in wait page. It is highly recommend you " +
|
||||
"provide an action-specific or global result named '{}'.", WAIT);
|
||||
LOG.warn("ExecuteAndWait interceptor has detected that no result named 'wait' is available. " +
|
||||
"Defaulting to a plain built-in wait page. It is highly recommend you " +
|
||||
"provide an action-specific or global result named '{}'.", WAIT);
|
||||
// no wait result? hmm -- let's try to do dynamically put it in for you!
|
||||
|
||||
//we used to add a fake "wait" result here, since the configuration is unmodifiable, that is no longer
|
||||
@@ -286,7 +300,7 @@ public class ExecuteAndWaitInterceptor extends MethodFilterInterceptor {
|
||||
session.remove(KEY + name);
|
||||
actionInvocation.getStack().push(bp.getAction());
|
||||
|
||||
// if an exception occured during action execution, throw it here
|
||||
// if an exception occurred during action execution, throw it here
|
||||
if (bp.getException() != null) {
|
||||
throw bp.getException();
|
||||
}
|
||||
@@ -369,5 +383,17 @@ public class ExecuteAndWaitInterceptor extends MethodFilterInterceptor {
|
||||
this.executeAfterValidationPass = executeAfterValidationPass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
super.init();
|
||||
if (executor == null) {
|
||||
executor = new StrutsExecutorProvider();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
super.destroy();
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +55,6 @@ public class FetchMetadataInterceptor extends AbstractInterceptor {
|
||||
private final Set<String> exemptedPaths = new HashSet<>();
|
||||
private final ResourceIsolationPolicy resourceIsolationPolicy = new StrutsResourceIsolationPolicy();
|
||||
|
||||
private boolean disabled = false;
|
||||
|
||||
@Inject(required = false)
|
||||
public void setExemptedPaths(String paths) {
|
||||
this.exemptedPaths.addAll(TextParseUtil.commaDelimitedStringToSet(paths));
|
||||
@@ -64,10 +62,6 @@ public class FetchMetadataInterceptor extends AbstractInterceptor {
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
if (disabled) {
|
||||
LOG.trace("Fetch Metadata interceptor has been disabled");
|
||||
return invocation.invoke();
|
||||
}
|
||||
ActionContext context = invocation.getInvocationContext();
|
||||
HttpServletRequest request = context.getServletRequest();
|
||||
|
||||
@@ -111,7 +105,4 @@ public class FetchMetadataInterceptor extends AbstractInterceptor {
|
||||
response.setHeader(VARY_HEADER, VARY_HEADER_VALUE);
|
||||
}
|
||||
|
||||
public void setDisabled(String value) {
|
||||
this.disabled = Boolean.parseBoolean(value);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user