mirror of
https://github.com/apache/struts.git
synced 2026-08-11 01:27:14 +00:00
Merge branch 'master' of https://github.com/apache/struts into issue/WW-5196
This commit is contained in:
@@ -12,3 +12,7 @@ notifications:
|
||||
|
||||
github:
|
||||
del_branch_on_merge: true
|
||||
protected_branches:
|
||||
master: { }
|
||||
autolink_jira:
|
||||
- WW
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# 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:
|
||||
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
security-events: write
|
||||
actions: read
|
||||
contents: read
|
||||
# Needed to access OIDC token.
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
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,59 @@
|
||||
# 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
|
||||
|
||||
permissions: read-all
|
||||
|
||||
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: trusty
|
||||
language: java
|
||||
sudo: false
|
||||
|
||||
jdk:
|
||||
- oraclejdk9
|
||||
- oraclejdk11
|
||||
|
||||
install: true
|
||||
|
||||
env:
|
||||
global:
|
||||
- secure: iI7IpfDtS+LUyS2yNuRCR3KelNyvBHuoMQ3gb1UNmR5SSL7jO/p3olQWrQROs28FJ+dpE3lHyIjoHrebKQGJHHAgTG2XWxn+G3fDsf+wSSFSLoDGj0o2SgGXooBbR2dccnNZHCyQaOyE2cIPWaOxrQZFE4No70LQB4mrP/gdkoc=
|
||||
matrix:
|
||||
include:
|
||||
- jdk: oraclejdk8
|
||||
env: STRUTS_IT=true # do integration tests and coverage reports when jdk 9 and 11 tests prospered
|
||||
|
||||
script:
|
||||
- if [ "$STRUTS_IT" == "true" ]; then
|
||||
./mvnw clean 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.1.0-SNAPSHOT</version>
|
||||
<version>6.2.0-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.1.0-SNAPSHOT</version>
|
||||
<version>6.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-rest-showcase</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>6.1.0-SNAPSHOT</version>
|
||||
<version>6.2.0-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.1.0-SNAPSHOT</version>
|
||||
<version>6.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-showcase</artifactId>
|
||||
@@ -99,6 +99,11 @@
|
||||
<artifactId>struts2-velocity-plugin</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-xslt-plugin</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
@@ -237,6 +242,7 @@
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>@{argLine}</argLine>
|
||||
<excludes>
|
||||
<exclude>it/**</exclude>
|
||||
<exclude>**/*$*</exclude>
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.showcase.servlet;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestServlet extends HttpServlet {
|
||||
@Override
|
||||
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
switch (request.getPathInfo()) {
|
||||
case "/forward":
|
||||
getServletContext().getRequestDispatcher("/dispatcher/dispatch.action").forward(request, response);
|
||||
break;
|
||||
default:
|
||||
response.sendError(404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
+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>
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="xslt" extends="struts-default" namespace="/xslt">
|
||||
<package name="xslt" extends="xslt-default" namespace="/xslt">
|
||||
<default-action-ref name="index"/>
|
||||
|
||||
<action name="index">
|
||||
@@ -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>
|
||||
@@ -44,7 +44,7 @@
|
||||
<constant name="struts.serve.static" value="true" />
|
||||
<constant name="struts.serve.static.browserCache" value="false" />
|
||||
|
||||
<constant name="struts.action.excludePattern" value=".*/images/.*\.gif,.*/img/.*\.gif,.*/styles/.*\.css,.*/js/.*\.js"/>
|
||||
<constant name="struts.action.excludePattern" value=".*/images/.*\.gif,.*/img/.*\.gif,.*/styles/.*\.css,.*/js/.*\.js,/testServlet/.*"/>
|
||||
|
||||
<include file="struts-interactive.xml" />
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -142,6 +142,11 @@
|
||||
<load-on-startup>4</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>testServlet</servlet-name>
|
||||
<servlet-class>org.apache.struts2.showcase.servlet.TestServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>dwr</servlet-name>
|
||||
<url-pattern>/dwr/*</url-pattern>
|
||||
@@ -162,6 +167,11 @@
|
||||
<url-pattern>/async/receiveNewMessages</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>testServlet</servlet-name>
|
||||
<url-pattern>/testServlet/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- END SNIPPET: dwr -->
|
||||
|
||||
<!-- SNIPPET START: example.velocity.filter.chain
|
||||
|
||||
@@ -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>
|
||||
+2
-9
@@ -32,7 +32,6 @@ public class DispatcherResultTest {
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/dispatcher/dispatch.action");
|
||||
|
||||
DomElement div = page.getElementById("dispatcher-result");
|
||||
|
||||
Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
}
|
||||
}
|
||||
@@ -40,16 +39,10 @@ public class DispatcherResultTest {
|
||||
@Test
|
||||
public void testDispatchingToAction() throws Exception {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/dispatcher/forward.action");
|
||||
|
||||
//DomElement div = page.getElementById("dispatcher-result");
|
||||
//Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
// support for forwarding to another action is broken on StrutsPrepareFilter/StrutsExecuteFilter
|
||||
// it only works in StrutsPrepareAndExecuteFilter
|
||||
// this will be fixed in Struts 6.1.x
|
||||
|
||||
Assert.assertEquals(404, page.getWebResponse().getStatusCode());
|
||||
DomElement div = page.getElementById("dispatcher-result");
|
||||
Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-31
@@ -1,4 +1,6 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
@@ -16,41 +18,24 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.dispatcher;
|
||||
package it.org.apache.struts2.showcase;
|
||||
|
||||
import com.gargoylesoftware.htmlunit.WebClient;
|
||||
import com.gargoylesoftware.htmlunit.html.DomElement;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.struts2.TestAction;
|
||||
public class ForwardTest {
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
@Test
|
||||
public void testServletForwardingToAction() throws Exception {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
// Struts excluded URL, as defined by struts.action.excludePattern
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/testServlet/forward");
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public class ServletDispatchedTestAssertInterceptor implements Interceptor {
|
||||
|
||||
private static final long serialVersionUID = 1980347231443329805L;
|
||||
|
||||
public ServletDispatchedTestAssertInterceptor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
public void init() {
|
||||
}
|
||||
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
Assert.assertTrue(invocation.getAction() instanceof TestAction);
|
||||
|
||||
TestAction testAction = (TestAction) invocation.getAction();
|
||||
|
||||
Assert.assertEquals("bar", testAction.getFoo());
|
||||
|
||||
String result = invocation.invoke();
|
||||
|
||||
return result;
|
||||
DomElement div = page.getElementById("dispatcher-result");
|
||||
Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.1.0-SNAPSHOT</version>
|
||||
<version>6.2.0-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>
|
||||
```
|
||||
+7
-2
@@ -29,7 +29,7 @@
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-bom</artifactId>
|
||||
<version>6.1.0-SNAPSHOT</version>
|
||||
<version>6.2.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Struts 2 Bill of Materials</name>
|
||||
@@ -44,7 +44,7 @@
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<struts-version.version>6.1.0-SNAPSHOT</struts-version.version>
|
||||
<struts-version.version>6.2.0-SNAPSHOT</struts-version.version>
|
||||
<maven.site.skip>true</maven.site.skip>
|
||||
<maven.site.deploy.skip>true</maven.site.deploy.skip>
|
||||
</properties>
|
||||
@@ -181,6 +181,11 @@
|
||||
<artifactId>struts2-velocity-plugin</artifactId>
|
||||
<version>${struts-version.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-xslt-plugin</artifactId>
|
||||
<version>${struts-version.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>6.1.0-SNAPSHOT</version>
|
||||
<version>6.2.0-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.1.0-SNAPSHOT</version>
|
||||
<version>6.2.0-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.1.0-SNAPSHOT</version>
|
||||
<version>6.2.0-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.1.0-SNAPSHOT</version>
|
||||
<version>6.2.0-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);
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@ import com.opensymphony.xwork2.config.impl.DefaultConfiguration;
|
||||
import com.opensymphony.xwork2.config.providers.StrutsDefaultConfigurationProvider;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.apache.struts2.StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD;
|
||||
|
||||
|
||||
/**
|
||||
@@ -42,12 +42,11 @@ public class ConfigurationManager {
|
||||
|
||||
protected static final Logger LOG = LogManager.getLogger(ConfigurationManager.class);
|
||||
protected Configuration configuration;
|
||||
protected Lock providerLock = new ReentrantLock();
|
||||
private List<ContainerProvider> containerProviders = new CopyOnWriteArrayList<>();
|
||||
private List<PackageProvider> packageProviders = new CopyOnWriteArrayList<>();
|
||||
private List<ContainerProvider> containerProviders = new ArrayList<>();
|
||||
private List<PackageProvider> packageProviders = new ArrayList<>();
|
||||
protected String defaultFrameworkBeanName;
|
||||
private boolean providersChanged = false;
|
||||
private boolean reloadConfigs = true; // for the first time
|
||||
private boolean providersChanged = true;
|
||||
private boolean alwaysReloadConfigs = false;
|
||||
|
||||
public ConfigurationManager(String name) {
|
||||
this.defaultFrameworkBeanName = name;
|
||||
@@ -59,54 +58,69 @@ public class ConfigurationManager {
|
||||
* @see com.opensymphony.xwork2.config.impl.DefaultConfiguration
|
||||
*/
|
||||
public synchronized Configuration getConfiguration() {
|
||||
if (configuration == null) {
|
||||
setConfiguration(createConfiguration(defaultFrameworkBeanName));
|
||||
try {
|
||||
configuration.reloadContainer(getContainerProviders());
|
||||
} catch (ConfigurationException e) {
|
||||
setConfiguration(null);
|
||||
throw new ConfigurationException("Unable to load configuration.", e);
|
||||
}
|
||||
} else {
|
||||
if (wasConfigInitialised()) {
|
||||
conditionalReload();
|
||||
}
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether configuration was initialised (was null)
|
||||
*/
|
||||
private boolean wasConfigInitialised() {
|
||||
if (configuration == null) {
|
||||
initialiseConfiguration();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void initialiseConfiguration() {
|
||||
if (containerProviders.isEmpty()) {
|
||||
addDefaultContainerProviders();
|
||||
}
|
||||
configuration = createConfiguration(defaultFrameworkBeanName);
|
||||
try {
|
||||
reload();
|
||||
} catch (ConfigurationException e) {
|
||||
configuration.destroy();
|
||||
configuration = null;
|
||||
providersChanged = true;
|
||||
throw new ConfigurationException("Unable to load configuration.", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addDefaultContainerProviders() {
|
||||
containerProviders.add(new StrutsDefaultConfigurationProvider());
|
||||
}
|
||||
|
||||
protected Configuration createConfiguration(String beanName) {
|
||||
return new DefaultConfiguration(beanName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all container providers and destroy managing Configuration instance
|
||||
*/
|
||||
public synchronized void destroyConfiguration() {
|
||||
clearContainerProviders();
|
||||
if (configuration != null) {
|
||||
configuration.destroy();
|
||||
configuration = null;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setConfiguration(Configuration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Get the current list of ConfigurationProviders. If no custom ConfigurationProviders have been added, this method
|
||||
* will return a list containing only a default ConfigurationProvider, {@link StrutsDefaultConfigurationProvider}.
|
||||
* If a custom ConfigurationProvider has been added, then the StrutsDefaultConfigurationProvider must be added by hand.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* TODO: The lazy instantiation of XmlConfigurationProvider should be refactored to be elsewhere. The behavior described above seems unintuitive.
|
||||
* </p>
|
||||
* Get the current list of ConfigurationProviders.
|
||||
*
|
||||
* @return the list of registered ConfigurationProvider objects
|
||||
* @see ConfigurationProvider
|
||||
*/
|
||||
public List<ContainerProvider> getContainerProviders() {
|
||||
providerLock.lock();
|
||||
try {
|
||||
if (containerProviders.size() == 0) {
|
||||
containerProviders.add(new StrutsDefaultConfigurationProvider());
|
||||
}
|
||||
|
||||
return containerProviders;
|
||||
} finally {
|
||||
providerLock.unlock();
|
||||
}
|
||||
public synchronized List<ContainerProvider> getContainerProviders() {
|
||||
return new ArrayList<>(containerProviders);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,14 +128,9 @@ public class ConfigurationManager {
|
||||
*
|
||||
* @param containerProviders list of {@link ConfigurationProvider} to be set
|
||||
*/
|
||||
public void setContainerProviders(List<ContainerProvider> containerProviders) {
|
||||
providerLock.lock();
|
||||
try {
|
||||
this.containerProviders = new CopyOnWriteArrayList<>(containerProviders);
|
||||
providersChanged = true;
|
||||
} finally {
|
||||
providerLock.unlock();
|
||||
}
|
||||
public synchronized void setContainerProviders(List<ContainerProvider> containerProviders) {
|
||||
this.containerProviders = new ArrayList<>(containerProviders);
|
||||
providersChanged = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,22 +139,32 @@ public class ConfigurationManager {
|
||||
*
|
||||
* @param provider the ConfigurationProvider to register
|
||||
*/
|
||||
public void addContainerProvider(ContainerProvider provider) {
|
||||
public synchronized void addContainerProvider(ContainerProvider provider) {
|
||||
if (!containerProviders.contains(provider)) {
|
||||
containerProviders.add(provider);
|
||||
providersChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void clearContainerProviders() {
|
||||
for (ContainerProvider containerProvider : containerProviders) {
|
||||
clearContainerProvider(containerProvider);
|
||||
public synchronized void removeContainerProvider(ContainerProvider provider) {
|
||||
if (containerProviders.remove(provider)) {
|
||||
destroyContainerProvider(provider);
|
||||
providersChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void clearContainerProviders() {
|
||||
destroyContainerProviders();
|
||||
containerProviders.clear();
|
||||
providersChanged = true;
|
||||
}
|
||||
|
||||
private void clearContainerProvider(ContainerProvider containerProvider) {
|
||||
private void destroyContainerProviders() {
|
||||
LOG.debug("Destroying all providers.");
|
||||
containerProviders.forEach(this::destroyContainerProvider);
|
||||
}
|
||||
|
||||
private void destroyContainerProvider(ContainerProvider containerProvider) {
|
||||
try {
|
||||
containerProvider.destroy();
|
||||
} catch (Exception e) {
|
||||
@@ -153,80 +172,61 @@ public class ConfigurationManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy its managing Configuration instance
|
||||
*/
|
||||
public synchronized void destroyConfiguration() {
|
||||
clearContainerProviders(); // let's destroy the ConfigurationProvider first
|
||||
containerProviders = new CopyOnWriteArrayList<>();
|
||||
if (configuration != null)
|
||||
configuration.destroy(); // let's destroy it first, before nulling it.
|
||||
configuration = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reloads the Configuration files if the configuration files indicate that they need to be reloaded.
|
||||
*/
|
||||
public synchronized void conditionalReload() {
|
||||
if (reloadConfigs || providersChanged) {
|
||||
if (alwaysReloadConfigs || providersChanged) {
|
||||
LOG.debug("Checking ConfigurationProviders for reload.");
|
||||
List<ContainerProvider> providers = getContainerProviders();
|
||||
boolean reload = needReloadContainerProviders(providers);
|
||||
if (!reload) {
|
||||
reload = needReloadPackageProviders();
|
||||
if (needReloadContainerProviders() || needReloadPackageProviders()) {
|
||||
destroyAndReload();
|
||||
}
|
||||
if (reload) {
|
||||
reloadProviders(providers);
|
||||
}
|
||||
updateReloadConfigsFlag();
|
||||
providersChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateReloadConfigsFlag() {
|
||||
reloadConfigs = Boolean.parseBoolean(configuration.getContainer().getInstance(String.class, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD));
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Updating [{}], current value is [{}], new value [{}]",
|
||||
StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, String.valueOf(reloadConfigs), String.valueOf(reloadConfigs));
|
||||
private void updateAlwaysReloadFlag() {
|
||||
boolean newValue = Boolean.parseBoolean(configuration.getContainer()
|
||||
.getInstance(String.class, STRUTS_CONFIGURATION_XML_RELOAD));
|
||||
if (alwaysReloadConfigs != newValue) {
|
||||
LOG.debug(
|
||||
"Updating [{}], current value is [{}], new value [{}]",
|
||||
STRUTS_CONFIGURATION_XML_RELOAD,
|
||||
String.valueOf(alwaysReloadConfigs),
|
||||
String.valueOf(newValue));
|
||||
alwaysReloadConfigs = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean needReloadPackageProviders() {
|
||||
if (packageProviders != null) {
|
||||
for (PackageProvider provider : packageProviders) {
|
||||
if (provider.needsReload()) {
|
||||
LOG.info("Detected package provider [{}] needs to be reloaded. Reloading all providers.", provider);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Optional<PackageProvider> provider = packageProviders.stream().filter(PackageProvider::needsReload).findAny();
|
||||
if (provider.isPresent()) {
|
||||
LOG.info("Detected package provider [{}] needs to be reloaded.", provider.get());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean needReloadContainerProviders(List<ContainerProvider> providers) {
|
||||
for (ContainerProvider provider : providers) {
|
||||
if (provider.needsReload()) {
|
||||
LOG.info("Detected container provider [{}] needs to be reloaded. Reloading all providers.", provider);
|
||||
return true;
|
||||
}
|
||||
private boolean needReloadContainerProviders() {
|
||||
Optional<ContainerProvider> provider = containerProviders.stream().filter(ContainerProvider::needsReload).findAny();
|
||||
if (provider.isPresent()) {
|
||||
LOG.info("Detected container provider [{}] needs to be reloaded.", provider.get());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void reloadProviders(List<ContainerProvider> providers) {
|
||||
for (ContainerProvider containerProvider : containerProviders) {
|
||||
try {
|
||||
containerProvider.destroy();
|
||||
} catch (Exception e) {
|
||||
LOG.warn("error while destroying configuration provider [{}]", containerProvider, e);
|
||||
}
|
||||
}
|
||||
packageProviders = this.configuration.reloadContainer(providers);
|
||||
public synchronized void destroyAndReload() {
|
||||
destroyContainerProviders();
|
||||
reload();
|
||||
}
|
||||
|
||||
public synchronized void reload() {
|
||||
packageProviders = getConfiguration().reloadContainer(getContainerProviders());
|
||||
if (wasConfigInitialised()) {
|
||||
LOG.debug("Reloading all providers.");
|
||||
packageProviders = configuration.reloadContainer(containerProviders);
|
||||
providersChanged = false;
|
||||
updateAlwaysReloadFlag();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
|
||||
/**
|
||||
* Provides beans and constants/properties for the Container
|
||||
*
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public interface ContainerProvider {
|
||||
@@ -32,29 +32,29 @@ public interface ContainerProvider {
|
||||
/**
|
||||
* Called before removed from the configuration manager
|
||||
*/
|
||||
public void destroy();
|
||||
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Initializes with the configuration
|
||||
* @param configuration The configuration
|
||||
* @throws ConfigurationException If anything goes wrong
|
||||
*/
|
||||
public void init(Configuration configuration) throws ConfigurationException;
|
||||
|
||||
void init(Configuration configuration) throws ConfigurationException;
|
||||
|
||||
/**
|
||||
* Tells whether the ContainerProvider should reload its configuration
|
||||
*
|
||||
* @return <tt>true</tt>, whether the ContainerProvider should reload its configuration, <tt>false</tt>otherwise.
|
||||
*/
|
||||
public boolean needsReload();
|
||||
|
||||
boolean needsReload();
|
||||
|
||||
/**
|
||||
* Registers beans and properties for the Container
|
||||
*
|
||||
*
|
||||
* @param builder The builder to register beans with
|
||||
* @param props The properties to register constants with
|
||||
* @throws ConfigurationException If anything goes wrong
|
||||
*/
|
||||
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException;
|
||||
|
||||
void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException;
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -298,8 +298,8 @@ public class DefaultConfiguration implements Configuration {
|
||||
|
||||
builder.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON);
|
||||
builder.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON);
|
||||
builder.factory(ExpressionCacheFactory.class, "defaultOgnlExpressionCacheFactory", DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON);
|
||||
builder.factory(BeanInfoCacheFactory.class, "defaultOgnlBeanInfoCacheFactory", DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON);
|
||||
builder.factory(ExpressionCacheFactory.class, DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON);
|
||||
builder.factory(BeanInfoCacheFactory.class, DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON);
|
||||
builder.factory(OgnlUtil.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON);
|
||||
|
||||
+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", DefaultOgnlExpressionCacheFactory.class, Scope.SINGLETON)
|
||||
.factory(BeanInfoCacheFactory.class, "defaultOgnlBeanInfoCacheFactory", DefaultOgnlBeanInfoCacheFactory.class, Scope.SINGLETON)
|
||||
.factory(OgnlUtil.class, Scope.SINGLETON)
|
||||
.factory(CollectionConverter.class, Scope.SINGLETON)
|
||||
.factory(ArrayConverter.class, Scope.SINGLETON)
|
||||
.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());
|
||||
|
||||
+484
-541
File diff suppressed because it is too large
Load Diff
@@ -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<>();
|
||||
|
||||
@@ -201,11 +201,25 @@ public enum Scope {
|
||||
|
||||
<T> Callable<? extends T> toCallable(final InternalContext context,
|
||||
final InternalFactory<? extends T> factory) {
|
||||
return new Callable<T>() {
|
||||
public T call() throws Exception {
|
||||
return InitializableFactory.wrapIfNeeded(factory).create(context);
|
||||
}
|
||||
};
|
||||
return (Callable<T>) () -> InitializableFactory.wrapIfNeeded(factory).create(context);
|
||||
}
|
||||
|
||||
public static Scope fromString(String scopeStr) {
|
||||
switch (scopeStr) {
|
||||
case "prototype":
|
||||
return Scope.PROTOTYPE;
|
||||
case "request":
|
||||
return Scope.REQUEST;
|
||||
case "session":
|
||||
return Scope.SESSION;
|
||||
case "thread":
|
||||
return Scope.THREAD;
|
||||
case "wizard":
|
||||
return Scope.WIZARD;
|
||||
case "singleton":
|
||||
default:
|
||||
return Scope.SINGLETON;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,13 @@ import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionException;
|
||||
import ognl.*;
|
||||
import ognl.ClassResolver;
|
||||
import ognl.Ognl;
|
||||
import ognl.OgnlContext;
|
||||
import ognl.OgnlException;
|
||||
import ognl.OgnlRuntime;
|
||||
import ognl.SimpleNode;
|
||||
import ognl.TypeConverter;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -37,7 +43,12 @@ import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -66,10 +77,12 @@ public class OgnlUtil {
|
||||
private Set<Class<?>> excludedClasses;
|
||||
private Set<Pattern> excludedPackageNamePatterns;
|
||||
private Set<String> excludedPackageNames;
|
||||
private Set<Class<?>> excludedPackageExemptClasses;
|
||||
|
||||
private Set<Class<?>> devModeExcludedClasses;
|
||||
private Set<Pattern> devModeExcludedPackageNamePatterns;
|
||||
private Set<String> devModeExcludedPackageNames;
|
||||
private Set<Class<?>> devModeExcludedPackageExemptClasses;
|
||||
|
||||
private Container container;
|
||||
private boolean allowStaticFieldAccess = true;
|
||||
@@ -82,7 +95,9 @@ public class OgnlUtil {
|
||||
*/
|
||||
@Deprecated
|
||||
public OgnlUtil() {
|
||||
this(null, null); // Instantiate default Expression and BeanInfo caches (null factories)
|
||||
// Instantiate default Expression and BeanInfo caches (factories must be non-null).
|
||||
this(new DefaultOgnlExpressionCacheFactory<String, Object>(),
|
||||
new DefaultOgnlBeanInfoCacheFactory<Class<?>, BeanInfo>());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,23 +111,29 @@ public class OgnlUtil {
|
||||
* @param ognlExpressionCacheFactory factory for Expression cache instance. If null, it uses a default
|
||||
* @param ognlBeanInfoCacheFactory factory for BeanInfo cache instance. If null, it uses a default
|
||||
*/
|
||||
@Inject
|
||||
public OgnlUtil(
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_EXPRESSION_CACHE_FACTORY, required = false) ExpressionCacheFactory<String, Object> ognlExpressionCacheFactory,
|
||||
@Inject(value = StrutsConstants.STRUTS_OGNL_BEANINFO_CACHE_FACTORY, required = false) BeanInfoCacheFactory<Class<?>, BeanInfo> ognlBeanInfoCacheFactory
|
||||
@Inject ExpressionCacheFactory<String, Object> ognlExpressionCacheFactory,
|
||||
@Inject BeanInfoCacheFactory<Class<?>, BeanInfo> ognlBeanInfoCacheFactory
|
||||
) {
|
||||
if (ognlExpressionCacheFactory == null) {
|
||||
throw new IllegalArgumentException("ExpressionCacheFactory parameter cannot be null");
|
||||
}
|
||||
if (ognlBeanInfoCacheFactory == null) {
|
||||
throw new IllegalArgumentException("BeanInfoCacheFactory parameter cannot be null");
|
||||
}
|
||||
excludedClasses = Collections.unmodifiableSet(new HashSet<>());
|
||||
excludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
|
||||
excludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
|
||||
excludedPackageExemptClasses = Collections.unmodifiableSet(new HashSet<>());
|
||||
|
||||
devModeExcludedClasses = Collections.unmodifiableSet(new HashSet<>());
|
||||
devModeExcludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
|
||||
devModeExcludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
|
||||
devModeExcludedPackageExemptClasses = Collections.unmodifiableSet(new HashSet<>());
|
||||
|
||||
OgnlCacheFactory<String, Object> ognlExpressionCacheFactory1 = (ognlExpressionCacheFactory != null ? ognlExpressionCacheFactory : new DefaultOgnlExpressionCacheFactory<>());
|
||||
OgnlCacheFactory<Class<?>, BeanInfo> ognlBeanInfoCacheFactory1 = (ognlBeanInfoCacheFactory != null ? ognlBeanInfoCacheFactory : new DefaultOgnlBeanInfoCacheFactory<>());
|
||||
|
||||
this.expressionCache = ognlExpressionCacheFactory1.buildOgnlCache();
|
||||
this.beanInfoCache = ognlBeanInfoCacheFactory1.buildOgnlCache();
|
||||
this.expressionCache = ognlExpressionCacheFactory.buildOgnlCache();
|
||||
this.beanInfoCache = ognlBeanInfoCacheFactory.buildOgnlCache();
|
||||
}
|
||||
|
||||
@Inject
|
||||
@@ -153,7 +174,7 @@ public class OgnlUtil {
|
||||
protected void setExcludedClasses(String commaDelimitedClasses) {
|
||||
Set<Class<?>> excludedClasses = new HashSet<>();
|
||||
excludedClasses.addAll(this.excludedClasses);
|
||||
excludedClasses.addAll(parseExcludedClasses(commaDelimitedClasses));
|
||||
excludedClasses.addAll(parseClasses(commaDelimitedClasses));
|
||||
this.excludedClasses = Collections.unmodifiableSet(excludedClasses);
|
||||
}
|
||||
|
||||
@@ -161,11 +182,11 @@ public class OgnlUtil {
|
||||
protected void setDevModeExcludedClasses(String commaDelimitedClasses) {
|
||||
Set<Class<?>> excludedClasses = new HashSet<>();
|
||||
excludedClasses.addAll(this.devModeExcludedClasses);
|
||||
excludedClasses.addAll(parseExcludedClasses(commaDelimitedClasses));
|
||||
excludedClasses.addAll(parseClasses(commaDelimitedClasses));
|
||||
this.devModeExcludedClasses = Collections.unmodifiableSet(excludedClasses);
|
||||
}
|
||||
|
||||
private Set<Class<?>> parseExcludedClasses(String commaDelimitedClasses) {
|
||||
private Set<Class<?>> parseClasses(String commaDelimitedClasses) {
|
||||
Set<String> classNames = TextParseUtil.commaDelimitedStringToSet(commaDelimitedClasses);
|
||||
Set<Class<?>> classes = new HashSet<>();
|
||||
|
||||
@@ -173,7 +194,7 @@ public class OgnlUtil {
|
||||
try {
|
||||
classes.add(Class.forName(className));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ConfigurationException("Cannot load excluded class: " + className, e);
|
||||
throw new ConfigurationException("Cannot load class for exclusion/exemption configuration: " + className, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +244,22 @@ public class OgnlUtil {
|
||||
this.devModeExcludedPackageNames = Collections.unmodifiableSet(excludedPackageNames);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_EXCLUDED_PACKAGE_EXEMPT_CLASSES, required = false)
|
||||
public void setExcludedPackageExemptClasses(String commaDelimitedClasses) {
|
||||
Set<Class<?>> excludedPackageExemptClasses = new HashSet<>();
|
||||
excludedPackageExemptClasses.addAll(this.excludedPackageExemptClasses);
|
||||
excludedPackageExemptClasses.addAll(parseClasses(commaDelimitedClasses));
|
||||
this.excludedPackageExemptClasses = Collections.unmodifiableSet(excludedPackageExemptClasses);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_EXEMPT_CLASSES, required = false)
|
||||
public void setDevModeExcludedPackageExemptClasses(String commaDelimitedClasses) {
|
||||
Set<Class<?>> excludedPackageExemptClasses = new HashSet<>();
|
||||
excludedPackageExemptClasses.addAll(this.devModeExcludedPackageExemptClasses);
|
||||
excludedPackageExemptClasses.addAll(parseClasses(commaDelimitedClasses));
|
||||
this.devModeExcludedPackageExemptClasses = Collections.unmodifiableSet(excludedPackageExemptClasses);
|
||||
}
|
||||
|
||||
private Set<String> parseExcludedPackageNames(String commaDelimitedPackageNames) {
|
||||
return TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackageNames);
|
||||
}
|
||||
@@ -239,6 +276,10 @@ public class OgnlUtil {
|
||||
return excludedPackageNames;
|
||||
}
|
||||
|
||||
public Set<Class<?>> getExcludedPackageExemptClasses() {
|
||||
return excludedPackageExemptClasses;
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected void setContainer(Container container) {
|
||||
this.container = container;
|
||||
@@ -262,10 +303,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.
|
||||
@@ -841,10 +882,12 @@ public class OgnlUtil {
|
||||
memberAccess.setExcludedClasses(devModeExcludedClasses);
|
||||
memberAccess.setExcludedPackageNamePatterns(devModeExcludedPackageNamePatterns);
|
||||
memberAccess.setExcludedPackageNames(devModeExcludedPackageNames);
|
||||
memberAccess.setExcludedPackageExemptClasses(devModeExcludedPackageExemptClasses);
|
||||
} else {
|
||||
memberAccess.setExcludedClasses(excludedClasses);
|
||||
memberAccess.setExcludedPackageNamePatterns(excludedPackageNamePatterns);
|
||||
memberAccess.setExcludedPackageNames(excludedPackageNames);
|
||||
memberAccess.setExcludedPackageExemptClasses(excludedPackageExemptClasses);
|
||||
}
|
||||
|
||||
return Ognl.createDefaultContext(root, memberAccess, resolver, defaultConverter);
|
||||
|
||||
@@ -29,7 +29,12 @@ import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.MemberAccessValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
|
||||
import ognl.*;
|
||||
import ognl.MethodFailedException;
|
||||
import ognl.NoSuchPropertyException;
|
||||
import ognl.Ognl;
|
||||
import ognl.OgnlContext;
|
||||
import ognl.OgnlException;
|
||||
import ognl.PropertyAccessor;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -87,6 +92,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
securityMemberAccess.setExcludedClasses(ognlUtil.getExcludedClasses());
|
||||
securityMemberAccess.setExcludedPackageNamePatterns(ognlUtil.getExcludedPackageNamePatterns());
|
||||
securityMemberAccess.setExcludedPackageNames(ognlUtil.getExcludedPackageNames());
|
||||
securityMemberAccess.setExcludedPackageExemptClasses(ognlUtil.getExcludedPackageExemptClasses());
|
||||
securityMemberAccess.setDisallowProxyMemberAccess(ognlUtil.isDisallowProxyMemberAccess());
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
private Set<Class<?>> excludedClasses = Collections.emptySet();
|
||||
private Set<Pattern> excludedPackageNamePatterns = Collections.emptySet();
|
||||
private Set<String> excludedPackageNames = Collections.emptySet();
|
||||
private Set<Class<?>> excludedPackageExemptClasses = Collections.emptySet();
|
||||
private boolean disallowProxyMemberAccess;
|
||||
|
||||
/**
|
||||
@@ -117,23 +118,23 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
}
|
||||
|
||||
final Class<?> memberClass = member.getDeclaringClass();
|
||||
// target can be null in case of accessing static fields, since OGNL 3.2.8
|
||||
final Class<?> targetClass = Modifier.isStatic(memberModifiers) ? memberClass : target.getClass();
|
||||
|
||||
if (isClassExcluded(memberClass)) {
|
||||
LOG.warn("Declaring class of member type [{}] is excluded!", member);
|
||||
return false;
|
||||
}
|
||||
|
||||
// target can be null in case of accessing static fields, since OGNL 3.2.8
|
||||
final Class<?> targetClass = Modifier.isStatic(memberModifiers) ? memberClass : target.getClass();
|
||||
|
||||
if (isPackageExcluded(targetClass.getPackage(), memberClass.getPackage())) {
|
||||
LOG.warn("Package [{}] of target class [{}] of target [{}] or package [{}] of member [{}] are excluded!", targetClass.getPackage(), targetClass,
|
||||
target, memberClass.getPackage(), member);
|
||||
if (isClassExcluded(targetClass)) {
|
||||
LOG.warn("Target class [{}] of target [{}] is excluded!", targetClass, target);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isClassExcluded(targetClass)) {
|
||||
LOG.warn("Target class [{}] of target [{}] is excluded!", targetClass, target);
|
||||
if (!isClassExcludedPackageExempt(targetClass) && !isClassExcludedPackageExempt(memberClass)
|
||||
&& isPackageExcluded(targetClass.getPackage(), memberClass.getPackage())) {
|
||||
LOG.warn("Package [{}] of target class [{}] of target [{}] or package [{}] of member [{}] are excluded!",
|
||||
targetClass.getPackage(), targetClass, target, memberClass.getPackage(), member);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -234,6 +235,15 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isClassExcludedPackageExempt(Class<?> clazz) {
|
||||
for (Class<?> excludedPackageExemptClass : excludedPackageExemptClasses) {
|
||||
if (clazz.isAssignableFrom(excludedPackageExemptClass)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isAcceptableProperty(String name) {
|
||||
return name == null || ((!isExcluded(name)) && isAccepted(name));
|
||||
}
|
||||
@@ -287,6 +297,10 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
this.excludedPackageNames = excludedPackageNames;
|
||||
}
|
||||
|
||||
public void setExcludedPackageExemptClasses(Set<Class<?>> excludedPackageExemptClasses) {
|
||||
this.excludedPackageExemptClasses = excludedPackageExemptClasses;
|
||||
}
|
||||
|
||||
public void setDisallowProxyMemberAccess(boolean disallowProxyMemberAccess) {
|
||||
this.disallowProxyMemberAccess = disallowProxyMemberAccess;
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.util;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
@@ -52,7 +54,7 @@ public class AnnotationUtils {
|
||||
* @param clazz The {@link Class} to inspect
|
||||
* @param allFields list of all fields
|
||||
*/
|
||||
public static void addAllFields(Class<? extends Annotation> annotationClass, Class clazz, List<Field> allFields) {
|
||||
public static void addAllFields(Class<? extends Annotation> annotationClass, Class<?> clazz, List<Field> allFields) {
|
||||
|
||||
if (clazz == null) {
|
||||
return;
|
||||
@@ -76,7 +78,7 @@ public class AnnotationUtils {
|
||||
* @param clazz The {@link Class} to inspect
|
||||
* @param allMethods list of all methods
|
||||
*/
|
||||
public static void addAllMethods(Class<? extends Annotation> annotationClass, Class clazz, List<Method> allMethods) {
|
||||
public static void addAllMethods(Class<? extends Annotation> annotationClass, Class<?> clazz, List<Method> allMethods) {
|
||||
|
||||
if (clazz == null) {
|
||||
return;
|
||||
@@ -97,12 +99,12 @@ public class AnnotationUtils {
|
||||
* @param clazz The {@link Class} to inspect
|
||||
* @param allInterfaces list of all interfaces
|
||||
*/
|
||||
public static void addAllInterfaces(Class clazz, List<Class> allInterfaces) {
|
||||
public static void addAllInterfaces(Class<?> clazz, List<Class<?>> allInterfaces) {
|
||||
if (clazz == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Class[] interfaces = clazz.getInterfaces();
|
||||
Class<?>[] interfaces = clazz.getInterfaces();
|
||||
allInterfaces.addAll(Arrays.asList(interfaces));
|
||||
addAllInterfaces(clazz.getSuperclass(), allInterfaces);
|
||||
}
|
||||
@@ -189,4 +191,21 @@ public class AnnotationUtils {
|
||||
|
||||
return anns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Varargs version of <code>AnnotatedElement.isAnnotationPresent()</code>
|
||||
*
|
||||
* @see AnnotatedElement
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static boolean isAnnotatedBy(AnnotatedElement annotatedElement, Class<? extends Annotation>... annotation) {
|
||||
if (ArrayUtils.isEmpty(annotation)) return false;
|
||||
|
||||
for (Class<? extends Annotation> c : annotation) {
|
||||
if (annotatedElement.isAnnotationPresent(c)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -29,11 +29,11 @@ import java.util.List;
|
||||
/**
|
||||
* ClassFinder searches the classpath of the specified ClassLoaderInterface for
|
||||
* packages, classes, constructors, methods, or fields with specific annotations.
|
||||
*
|
||||
* <p>
|
||||
* For security reasons ASM is used to find the annotations. Classes are not
|
||||
* loaded unless they match the requirements of a called findAnnotated* method.
|
||||
* Once loaded, these classes are cached.
|
||||
*
|
||||
* <p>
|
||||
* The getClassesNotLoaded() method can be used immediately after any find*
|
||||
* method to get a list of classes which matched the find requirements (i.e.
|
||||
* contained the annotation), but were unable to be loaded.
|
||||
@@ -67,32 +67,32 @@ public interface ClassFinder {
|
||||
|
||||
List<Package> findAnnotatedPackages(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Class> findAnnotatedClasses(Class<? extends Annotation> annotation);
|
||||
List<Class<?>> findAnnotatedClasses(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Method> findAnnotatedMethods(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Constructor> findAnnotatedConstructors(Class<? extends Annotation> annotation);
|
||||
List<Constructor<?>> findAnnotatedConstructors(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Field> findAnnotatedFields(Class<? extends Annotation> annotation);
|
||||
|
||||
List<Class> findClassesInPackage(String packageName, boolean recursive);
|
||||
List<Class<?>> findClassesInPackage(String packageName, boolean recursive);
|
||||
|
||||
List<Class> findClasses(Test<ClassInfo> test);
|
||||
List<Class<?>> findClasses(Test<ClassInfo> test);
|
||||
|
||||
List<Class> findClasses();
|
||||
List<Class<?>> findClasses();
|
||||
|
||||
ClassLoaderInterface getClassLoaderInterface();
|
||||
|
||||
public static interface Info {
|
||||
interface Info {
|
||||
String getName();
|
||||
|
||||
List<AnnotationInfo> getAnnotations();
|
||||
}
|
||||
|
||||
public class AnnotationInfo extends Annotatable implements Info {
|
||||
class AnnotationInfo extends Annotatable implements Info {
|
||||
private final String name;
|
||||
|
||||
public AnnotationInfo(Annotation annotation){
|
||||
public AnnotationInfo(Annotation annotation) {
|
||||
this(annotation.getClass().getName());
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ public interface ClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
public class Annotatable {
|
||||
class Annotatable {
|
||||
private final List<AnnotationInfo> annotations = new ArrayList<>();
|
||||
|
||||
public Annotatable(AnnotatedElement element) {
|
||||
@@ -134,12 +134,12 @@ public interface ClassFinder {
|
||||
|
||||
}
|
||||
|
||||
public class PackageInfo extends Annotatable implements Info {
|
||||
class PackageInfo extends Annotatable implements Info {
|
||||
private final String name;
|
||||
private final ClassInfo info;
|
||||
private final Package pkg;
|
||||
|
||||
public PackageInfo(Package pkg){
|
||||
public PackageInfo(Package pkg) {
|
||||
super(pkg);
|
||||
this.pkg = pkg;
|
||||
this.name = pkg.getName();
|
||||
@@ -157,11 +157,11 @@ public interface ClassFinder {
|
||||
}
|
||||
|
||||
public Package get() throws ClassNotFoundException {
|
||||
return (pkg != null)?pkg:info.get().getPackage();
|
||||
return (pkg != null) ? pkg : info.get().getPackage();
|
||||
}
|
||||
}
|
||||
|
||||
public class ClassInfo extends Annotatable implements Info {
|
||||
class ClassInfo extends Annotatable implements Info {
|
||||
private final String name;
|
||||
private final List<MethodInfo> methods = new ArrayList<>();
|
||||
private final List<MethodInfo> constructors = new ArrayList<>();
|
||||
@@ -169,17 +169,18 @@ public interface ClassFinder {
|
||||
private final List<String> interfaces = new ArrayList<>();
|
||||
private final List<String> superInterfaces = new ArrayList<>();
|
||||
private final List<FieldInfo> fields = new ArrayList<>();
|
||||
private final ClassFinder classFinder;
|
||||
|
||||
private Class<?> clazz;
|
||||
private ClassFinder classFinder;
|
||||
private ClassNotFoundException notFound;
|
||||
|
||||
public ClassInfo(Class clazz, ClassFinder classFinder) {
|
||||
public ClassInfo(Class<?> clazz, ClassFinder classFinder) {
|
||||
super(clazz);
|
||||
this.clazz = clazz;
|
||||
this.classFinder = classFinder;
|
||||
this.name = clazz.getName();
|
||||
Class superclass = clazz.getSuperclass();
|
||||
this.superType = superclass != null ? superclass.getName(): null;
|
||||
Class<?> superclass = clazz.getSuperclass();
|
||||
this.superType = superclass != null ? superclass.getName() : null;
|
||||
}
|
||||
|
||||
public ClassInfo(String name, String superType, ClassFinder classFinder) {
|
||||
@@ -188,8 +189,8 @@ public interface ClassFinder {
|
||||
this.classFinder = classFinder;
|
||||
}
|
||||
|
||||
public String getPackageName(){
|
||||
return name.indexOf('.') > 0 ? name.substring(0, name.lastIndexOf('.')) : "" ;
|
||||
public String getPackageName() {
|
||||
return name.indexOf('.') > 0 ? name.substring(0, name.lastIndexOf('.')) : "";
|
||||
}
|
||||
|
||||
public List<MethodInfo> getConstructors() {
|
||||
@@ -220,7 +221,7 @@ public interface ClassFinder {
|
||||
return superType;
|
||||
}
|
||||
|
||||
public Class get() throws ClassNotFoundException {
|
||||
public Class<?> get() throws ClassNotFoundException {
|
||||
if (clazz != null) return clazz;
|
||||
if (notFound != null) throw notFound;
|
||||
try {
|
||||
@@ -239,20 +240,20 @@ public interface ClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodInfo extends Annotatable implements Info {
|
||||
class MethodInfo extends Annotatable implements Info {
|
||||
private final ClassInfo declaringClass;
|
||||
private final String returnType;
|
||||
private final String name;
|
||||
private final List<List<AnnotationInfo>> parameterAnnotations = new ArrayList<>();
|
||||
|
||||
public MethodInfo(ClassInfo info, Constructor constructor){
|
||||
public MethodInfo(ClassInfo info, Constructor<?> constructor) {
|
||||
super(constructor);
|
||||
this.declaringClass = info;
|
||||
this.name = "<init>";
|
||||
this.returnType = Void.TYPE.getName();
|
||||
}
|
||||
|
||||
public MethodInfo(ClassInfo info, Method method){
|
||||
public MethodInfo(ClassInfo info, Method method) {
|
||||
super(method);
|
||||
this.declaringClass = info;
|
||||
this.name = method.getName();
|
||||
@@ -297,12 +298,12 @@ public interface ClassFinder {
|
||||
}
|
||||
}
|
||||
|
||||
public class FieldInfo extends Annotatable implements Info {
|
||||
class FieldInfo extends Annotatable implements Info {
|
||||
private final String name;
|
||||
private final String type;
|
||||
private final ClassInfo declaringClass;
|
||||
|
||||
public FieldInfo(ClassInfo info, Field field){
|
||||
public FieldInfo(ClassInfo info, Field field) {
|
||||
super(field);
|
||||
this.declaringClass = info;
|
||||
this.name = field.getName();
|
||||
|
||||
+15
-327
@@ -18,20 +18,14 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.validator;
|
||||
|
||||
import com.opensymphony.xwork2.*;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ActionProxy;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.ClassLoaderUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AnnotationActionValidatorManager is the entry point into XWork's annotations-based validator framework.
|
||||
@@ -40,185 +34,9 @@ import java.util.*;
|
||||
* @author Rainer Hermanns
|
||||
* @author jepjep
|
||||
*/
|
||||
public class AnnotationActionValidatorManager implements ActionValidatorManager {
|
||||
public class AnnotationActionValidatorManager extends DefaultActionValidatorManager {
|
||||
|
||||
/**
|
||||
* The file suffix for any validation file.
|
||||
*/
|
||||
protected static final String VALIDATION_CONFIG_SUFFIX = "-validation.xml";
|
||||
|
||||
private final Map<String, List<ValidatorConfig>> validatorCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
|
||||
private final Map<String, List<ValidatorConfig>> validatorFileCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
|
||||
private static final Logger LOG = LogManager.getLogger(AnnotationActionValidatorManager.class);
|
||||
|
||||
private ValidatorFactory validatorFactory;
|
||||
private ValidatorFileParser validatorFileParser;
|
||||
private FileManager fileManager;
|
||||
private boolean reloadingConfigs;
|
||||
private TextProviderFactory textProviderFactory;
|
||||
|
||||
@Inject
|
||||
public void setValidatorFactory(ValidatorFactory fac) {
|
||||
this.validatorFactory = fac;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setValidatorFileParser(ValidatorFileParser parser) {
|
||||
this.validatorFileParser = parser;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setFileManagerFactory(FileManagerFactory fileManagerFactory) {
|
||||
this.fileManager = fileManagerFactory.getFileManager();
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, required = false)
|
||||
public void setReloadingConfigs(String reloadingConfigs) {
|
||||
this.reloadingConfigs = Boolean.parseBoolean(reloadingConfigs);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setTextProviderFactory(TextProviderFactory textProviderFactory) {
|
||||
this.textProviderFactory = textProviderFactory;
|
||||
}
|
||||
|
||||
public List<Validator> getValidators(Class clazz, String context) {
|
||||
return getValidators(clazz, context, null);
|
||||
}
|
||||
|
||||
public List<Validator> getValidators(Class clazz, String context, String method) {
|
||||
final String validatorKey = buildValidatorKey(clazz, context);
|
||||
final List<ValidatorConfig> cfgs;
|
||||
|
||||
if (validatorCache.containsKey(validatorKey)) {
|
||||
if (reloadingConfigs) {
|
||||
validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, true, null));
|
||||
}
|
||||
} else {
|
||||
validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, false, null));
|
||||
}
|
||||
|
||||
// get the set of validator configs
|
||||
cfgs = new ArrayList<ValidatorConfig>(validatorCache.get(validatorKey));
|
||||
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
|
||||
// create clean instances of the validators for the caller's use
|
||||
ArrayList<Validator> validators = new ArrayList<>(cfgs.size());
|
||||
for (ValidatorConfig cfg : cfgs) {
|
||||
if (method == null || method.equals(cfg.getParams().get("methodName"))) {
|
||||
Validator validator = validatorFactory.getValidator(
|
||||
new ValidatorConfig.Builder(cfg)
|
||||
.removeParam("methodName")
|
||||
.build());
|
||||
validator.setValidatorType(cfg.getType());
|
||||
validator.setValueStack(stack);
|
||||
validators.add(validator);
|
||||
}
|
||||
}
|
||||
|
||||
return validators;
|
||||
}
|
||||
|
||||
public void validate(Object object, String context) throws ValidationException {
|
||||
validate(object, context, (String) null);
|
||||
}
|
||||
|
||||
public void validate(Object object, String context, String method) throws ValidationException {
|
||||
ValidatorContext validatorContext = new DelegatingValidatorContext(object, textProviderFactory);
|
||||
validate(object, context, validatorContext, method);
|
||||
}
|
||||
|
||||
public void validate(Object object, String context, ValidatorContext validatorContext) throws ValidationException {
|
||||
validate(object, context, validatorContext, null);
|
||||
}
|
||||
|
||||
public void validate(Object object, String context, ValidatorContext validatorContext, String method) throws ValidationException {
|
||||
List<Validator> validators = getValidators(object.getClass(), context, method);
|
||||
Set<String> shortcircuitedFields = null;
|
||||
|
||||
for (final Validator validator : validators) {
|
||||
try {
|
||||
validator.setValidatorContext(validatorContext);
|
||||
|
||||
LOG.debug("Running validator: {} for object {} and method {}", validator, object, method);
|
||||
|
||||
FieldValidator fValidator = null;
|
||||
String fullFieldName = null;
|
||||
|
||||
if (validator instanceof FieldValidator) {
|
||||
fValidator = (FieldValidator) validator;
|
||||
fullFieldName = fValidator.getValidatorContext().getFullFieldName(fValidator.getFieldName());
|
||||
|
||||
if ((shortcircuitedFields != null) && shortcircuitedFields.contains(fullFieldName)) {
|
||||
LOG.debug("Short-circuited, skipping");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (validator instanceof ShortCircuitableValidator && ((ShortCircuitableValidator) validator).isShortCircuit()) {
|
||||
// get number of existing errors
|
||||
List<String> errs = null;
|
||||
|
||||
if (fValidator != null) {
|
||||
if (validatorContext.hasFieldErrors()) {
|
||||
Collection<String> fieldErrors = validatorContext.getFieldErrors().get(fullFieldName);
|
||||
|
||||
if (fieldErrors != null) {
|
||||
errs = new ArrayList<>(fieldErrors);
|
||||
}
|
||||
}
|
||||
} else if (validatorContext.hasActionErrors()) {
|
||||
Collection<String> actionErrors = validatorContext.getActionErrors();
|
||||
|
||||
if (actionErrors != null) {
|
||||
errs = new ArrayList<>(actionErrors);
|
||||
}
|
||||
}
|
||||
|
||||
validator.validate(object);
|
||||
|
||||
if (fValidator != null) {
|
||||
if (validatorContext.hasFieldErrors()) {
|
||||
Collection<String> errCol = validatorContext.getFieldErrors().get(fullFieldName);
|
||||
|
||||
if ((errCol != null) && !errCol.equals(errs)) {
|
||||
LOG.debug("Short-circuiting on field validation");
|
||||
|
||||
if (shortcircuitedFields == null) {
|
||||
shortcircuitedFields = new TreeSet<String>();
|
||||
}
|
||||
|
||||
shortcircuitedFields.add(fullFieldName);
|
||||
}
|
||||
}
|
||||
} else if (validatorContext.hasActionErrors()) {
|
||||
Collection<String> errCol = validatorContext.getActionErrors();
|
||||
|
||||
if ((errCol != null) && !errCol.equals(errs)) {
|
||||
LOG.debug("Short-circuiting");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
validator.validate(object);
|
||||
} finally {
|
||||
validator.setValidatorContext(null);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a key for validators - used when caching validators.
|
||||
*
|
||||
* @param clazz the action.
|
||||
* @param context context
|
||||
* @return a validator key which is the class name plus context.
|
||||
*/
|
||||
@Override
|
||||
protected String buildValidatorKey(Class clazz, String context) {
|
||||
ActionInvocation invocation = ActionContext.getContext().getActionInvocation();
|
||||
ActionProxy proxy = invocation.getProxy();
|
||||
@@ -230,20 +48,11 @@ public class AnnotationActionValidatorManager implements ActionValidatorManager
|
||||
sb.append(config.getPackageName());
|
||||
sb.append("/");
|
||||
}
|
||||
|
||||
// the key needs to use the name of the action from the config file,
|
||||
// instead of the url, so wild card actions will have the same validator
|
||||
// see WW-2996
|
||||
|
||||
// UPDATE:
|
||||
// WW-3753 Using the config name instead of the context only for
|
||||
// wild card actions to keep the flexibility provided
|
||||
// by the original design (such as mapping different contexts
|
||||
// to the same action and method if desired)
|
||||
|
||||
// UPDATE:
|
||||
// WW-4536 Using NameVariablePatternMatcher allows defines actions
|
||||
// with patterns enclosed with '{}', it's similar case to WW-3753
|
||||
// WW-2996: key needs to use the name of the action from the config file, instead of the url,
|
||||
// so wildcard actions will have the same validator
|
||||
// WW-3753: Using the config name instead of the context only for wildcard actions to keep the flexibility
|
||||
// provided by the original design (such as mapping different contexts to the same action and method if desired)
|
||||
// WW-4536: Using NamedVariablePatternMatcher allows defines actions with patterns enclosed with '{}'
|
||||
String configName = config.getName();
|
||||
if (configName.contains(ActionConfig.WILDCARD) || (configName.contains("{") && configName.contains("}"))) {
|
||||
sb.append(configName);
|
||||
@@ -252,143 +61,22 @@ public class AnnotationActionValidatorManager implements ActionValidatorManager
|
||||
} else {
|
||||
sb.append(context);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private List<ValidatorConfig> buildAliasValidatorConfigs(Class aClass, String context, boolean checkFile) {
|
||||
@Override
|
||||
protected List<ValidatorConfig> buildAliasValidatorConfigs(Class aClass, String context, boolean checkFile) {
|
||||
String fileName = aClass.getName().replace('.', '/') + "-" + context.replace('/', '-') + VALIDATION_CONFIG_SUFFIX;
|
||||
|
||||
return loadFile(fileName, aClass, checkFile);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected List<ValidatorConfig> buildClassValidatorConfigs(Class aClass, boolean checkFile) {
|
||||
|
||||
String fileName = aClass.getName().replace('.', '/') + VALIDATION_CONFIG_SUFFIX;
|
||||
|
||||
List<ValidatorConfig> result = new ArrayList<>(loadFile(fileName, aClass, checkFile));
|
||||
|
||||
AnnotationValidationConfigurationBuilder builder = new AnnotationValidationConfigurationBuilder(validatorFactory);
|
||||
|
||||
List<ValidatorConfig> annotationResult = new ArrayList<>(builder.buildAnnotationClassValidatorConfigs(aClass));
|
||||
|
||||
result.addAll(annotationResult);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>This method 'collects' all the validator configurations for a given
|
||||
* action invocation.</p>
|
||||
*
|
||||
* <p>It will traverse up the class hierarchy looking for validators for every super class
|
||||
* and directly implemented interface of the current action, as well as adding validators for
|
||||
* any alias of this invocation. Nifty!</p>
|
||||
*
|
||||
* <p>Given the following class structure:</p>
|
||||
* <pre>
|
||||
* interface Thing;
|
||||
* interface Animal extends Thing;
|
||||
* interface Quadraped extends Animal;
|
||||
* class AnimalImpl implements Animal;
|
||||
* class QuadrapedImpl extends AnimalImpl implements Quadraped;
|
||||
* class Dog extends QuadrapedImpl;
|
||||
* </pre>
|
||||
*
|
||||
* <p>This method will look for the following config files for Dog:</p>
|
||||
* <pre>
|
||||
* Animal
|
||||
* Animal-context
|
||||
* AnimalImpl
|
||||
* AnimalImpl-context
|
||||
* Quadraped
|
||||
* Quadraped-context
|
||||
* QuadrapedImpl
|
||||
* QuadrapedImpl-context
|
||||
* Dog
|
||||
* Dog-context
|
||||
* </pre>
|
||||
*
|
||||
* <p>Note that the validation rules for Thing is never looked for because no class in the
|
||||
* hierarchy directly implements Thing.</p>
|
||||
*
|
||||
* @param clazz the Class to look up validators for.
|
||||
* @param context the context to use when looking up validators.
|
||||
* @param checkFile true if the validation config file should be checked to see if it has been
|
||||
* updated.
|
||||
* @param checked the set of previously checked class-contexts, null if none have been checked
|
||||
* @return a list of validator configs for the given class and context.
|
||||
*/
|
||||
private List<ValidatorConfig> buildValidatorConfigs(Class clazz, String context, boolean checkFile, Set<String> checked) {
|
||||
List<ValidatorConfig> validatorConfigs = new ArrayList<>();
|
||||
|
||||
if (checked == null) {
|
||||
checked = new TreeSet<>();
|
||||
} else if (checked.contains(clazz.getName())) {
|
||||
return validatorConfigs;
|
||||
}
|
||||
|
||||
if (clazz.isInterface()) {
|
||||
Class[] interfaces = clazz.getInterfaces();
|
||||
|
||||
for (Class anInterface : interfaces) {
|
||||
validatorConfigs.addAll(buildValidatorConfigs(anInterface, context, checkFile, checked));
|
||||
}
|
||||
} else {
|
||||
if (!clazz.equals(Object.class)) {
|
||||
validatorConfigs.addAll(buildValidatorConfigs(clazz.getSuperclass(), context, checkFile, checked));
|
||||
}
|
||||
}
|
||||
|
||||
// look for validators for implemented interfaces
|
||||
Class[] interfaces = clazz.getInterfaces();
|
||||
|
||||
for (Class anInterface1 : interfaces) {
|
||||
if (checked.contains(anInterface1.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
validatorConfigs.addAll(buildClassValidatorConfigs(anInterface1, checkFile));
|
||||
|
||||
if (context != null) {
|
||||
validatorConfigs.addAll(buildAliasValidatorConfigs(anInterface1, context, checkFile));
|
||||
}
|
||||
|
||||
checked.add(anInterface1.getName());
|
||||
}
|
||||
|
||||
validatorConfigs.addAll(buildClassValidatorConfigs(clazz, checkFile));
|
||||
|
||||
if (context != null) {
|
||||
validatorConfigs.addAll(buildAliasValidatorConfigs(clazz, context, checkFile));
|
||||
}
|
||||
|
||||
checked.add(clazz.getName());
|
||||
|
||||
return validatorConfigs;
|
||||
}
|
||||
|
||||
private List<ValidatorConfig> loadFile(String fileName, Class clazz, boolean checkFile) {
|
||||
List<ValidatorConfig> retList = Collections.emptyList();
|
||||
|
||||
URL fileUrl = ClassLoaderUtil.getResource(fileName, clazz);
|
||||
|
||||
if ((checkFile && fileManager.fileNeedsReloading(fileUrl)) || !validatorFileCache.containsKey(fileName)) {
|
||||
try (InputStream is = fileManager.loadFile(fileUrl)) {
|
||||
if (is != null) {
|
||||
retList = new ArrayList<>(validatorFileParser.parseActionValidatorConfigs(validatorFactory, is, fileName));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Caught exception while loading file {}", fileName, e);
|
||||
}
|
||||
|
||||
validatorFileCache.put(fileName, retList);
|
||||
} else {
|
||||
retList = validatorFileCache.get(fileName);
|
||||
}
|
||||
|
||||
return retList;
|
||||
}
|
||||
}
|
||||
|
||||
+154
-153
@@ -32,7 +32,16 @@ import org.apache.struts2.StrutsConstants;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static java.util.Collections.synchronizedMap;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -53,29 +62,30 @@ import java.util.*;
|
||||
*/
|
||||
public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
|
||||
private final static Logger LOG = LogManager.getLogger(DefaultActionValidatorManager.class);
|
||||
|
||||
/** The file suffix for any validation file. */
|
||||
/**
|
||||
* The file suffix for any validation file.
|
||||
*/
|
||||
protected static final String VALIDATION_CONFIG_SUFFIX = "-validation.xml";
|
||||
|
||||
private final Map<String, List<ValidatorConfig>> validatorCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
|
||||
private final Map<String, List<ValidatorConfig>> validatorFileCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
|
||||
protected final Map<String, List<ValidatorConfig>> validatorCache = synchronizedMap(new HashMap<>());
|
||||
protected final Map<String, List<ValidatorConfig>> validatorFileCache = synchronizedMap(new HashMap<>());
|
||||
private static final Logger LOG = LogManager.getLogger(DefaultActionValidatorManager.class);
|
||||
|
||||
private ValidatorFactory validatorFactory;
|
||||
private ValidatorFileParser validatorFileParser;
|
||||
private FileManager fileManager;
|
||||
private boolean reloadingConfigs;
|
||||
private TextProviderFactory textProviderFactory;
|
||||
protected ValidatorFactory validatorFactory;
|
||||
protected ValidatorFileParser validatorFileParser;
|
||||
protected FileManager fileManager;
|
||||
protected boolean reloadingConfigs;
|
||||
protected TextProviderFactory textProviderFactory;
|
||||
|
||||
@Inject
|
||||
public void setValidatorFactory(ValidatorFactory fac) {
|
||||
this.validatorFactory = fac;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setValidatorFileParser(ValidatorFileParser parser) {
|
||||
this.validatorFileParser = parser;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setValidatorFactory(ValidatorFactory fac) {
|
||||
this.validatorFactory = fac;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setFileManagerFactory(FileManagerFactory fileManagerFactory) {
|
||||
@@ -92,153 +102,137 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
this.textProviderFactory = textProviderFactory;
|
||||
}
|
||||
|
||||
public synchronized List<Validator> getValidators(Class clazz, String context) {
|
||||
return getValidators(clazz, context, null);
|
||||
}
|
||||
|
||||
public synchronized List<Validator> getValidators(Class clazz, String context, String method) {
|
||||
final String validatorKey = buildValidatorKey(clazz, context);
|
||||
|
||||
if (validatorCache.containsKey(validatorKey)) {
|
||||
if (reloadingConfigs) {
|
||||
validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, true, null));
|
||||
}
|
||||
} else {
|
||||
validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, false, null));
|
||||
}
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
|
||||
// get the set of validator configs
|
||||
List<ValidatorConfig> cfgs = validatorCache.get(validatorKey);
|
||||
|
||||
// create clean instances of the validators for the caller's use
|
||||
ArrayList<Validator> validators = new ArrayList<>(cfgs.size());
|
||||
for (ValidatorConfig cfg : cfgs) {
|
||||
if (method == null || method.equals(cfg.getParams().get("methodName"))) {
|
||||
Validator validator = validatorFactory.getValidator(cfg);
|
||||
validator.setValidatorType(cfg.getType());
|
||||
validator.setValueStack(stack);
|
||||
validators.add(validator);
|
||||
}
|
||||
}
|
||||
return validators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object object, String context) throws ValidationException {
|
||||
validate(object, context, (String) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object object, String context, String method) throws ValidationException {
|
||||
ValidatorContext validatorContext = new DelegatingValidatorContext(object, textProviderFactory);
|
||||
validate(object, context, validatorContext, method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object object, String context, ValidatorContext validatorContext) throws ValidationException {
|
||||
validate(object, context, validatorContext, null);
|
||||
}
|
||||
|
||||
public void validate(Object object, String context, ValidatorContext validatorContext, String method) throws ValidationException {
|
||||
List<Validator> validators = getValidators(object.getClass(), context, method);
|
||||
Set<String> shortcircuitedFields = null;
|
||||
|
||||
for (final Validator validator : validators) {
|
||||
try {
|
||||
validator.setValidatorContext(validatorContext);
|
||||
|
||||
LOG.debug("Running validator: {} for object {} and method {}", validator, object, method);
|
||||
|
||||
FieldValidator fValidator = null;
|
||||
String fullFieldName = null;
|
||||
|
||||
if (validator instanceof FieldValidator) {
|
||||
fValidator = (FieldValidator) validator;
|
||||
fullFieldName = fValidator.getValidatorContext().getFullFieldName(fValidator.getFieldName());
|
||||
|
||||
if ((shortcircuitedFields != null) && shortcircuitedFields.contains(fullFieldName)) {
|
||||
LOG.debug("Short-circuited, skipping");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (validator instanceof ShortCircuitableValidator && ((ShortCircuitableValidator) validator).isShortCircuit()) {
|
||||
// get number of existing errors
|
||||
List<String> errs = null;
|
||||
|
||||
if (fValidator != null) {
|
||||
if (validatorContext.hasFieldErrors()) {
|
||||
Collection<String> fieldErrors = validatorContext.getFieldErrors().get(fullFieldName);
|
||||
|
||||
if (fieldErrors != null) {
|
||||
errs = new ArrayList<>(fieldErrors);
|
||||
}
|
||||
}
|
||||
} else if (validatorContext.hasActionErrors()) {
|
||||
Collection<String> actionErrors = validatorContext.getActionErrors();
|
||||
|
||||
if (actionErrors != null) {
|
||||
errs = new ArrayList<String>(actionErrors);
|
||||
}
|
||||
}
|
||||
|
||||
validator.validate(object);
|
||||
|
||||
if (fValidator != null) {
|
||||
if (validatorContext.hasFieldErrors()) {
|
||||
Collection<String> errCol = validatorContext.getFieldErrors().get(fullFieldName);
|
||||
|
||||
if ((errCol != null) && !errCol.equals(errs)) {
|
||||
LOG.debug("Short-circuiting on field validation");
|
||||
|
||||
if (shortcircuitedFields == null) {
|
||||
shortcircuitedFields = new TreeSet<>();
|
||||
}
|
||||
|
||||
shortcircuitedFields.add(fullFieldName);
|
||||
}
|
||||
}
|
||||
} else if (validatorContext.hasActionErrors()) {
|
||||
Collection<String> errCol = validatorContext.getActionErrors();
|
||||
|
||||
if ((errCol != null) && !errCol.equals(errs)) {
|
||||
LOG.debug("Short-circuiting");
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
validator.validate(object);
|
||||
}
|
||||
finally {
|
||||
validator.setValidatorContext(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a key for validators - used when caching validators.
|
||||
*
|
||||
* @param clazz the action.
|
||||
* @param context the action's context.
|
||||
* @param context context
|
||||
* @return a validator key which is the class name plus context.
|
||||
*/
|
||||
protected static String buildValidatorKey(Class clazz, String context) {
|
||||
StringBuilder sb = new StringBuilder(clazz.getName());
|
||||
sb.append("/");
|
||||
sb.append(context);
|
||||
return sb.toString();
|
||||
protected String buildValidatorKey(Class clazz, String context) {
|
||||
return clazz.getName() + "/" + context;
|
||||
}
|
||||
|
||||
private List<ValidatorConfig> buildAliasValidatorConfigs(Class aClass, String context, boolean checkFile) {
|
||||
String fileName = aClass.getName().replace('.', '/') + "-" + context + VALIDATION_CONFIG_SUFFIX;
|
||||
|
||||
return loadFile(fileName, aClass, checkFile);
|
||||
protected Validator getValidatorFromValidatorConfig(ValidatorConfig config, ValueStack stack) {
|
||||
Validator validator = validatorFactory.getValidator(config);
|
||||
validator.setValidatorType(config.getType());
|
||||
validator.setValueStack(stack);
|
||||
return validator;
|
||||
}
|
||||
|
||||
private List<ValidatorConfig> buildClassValidatorConfigs(Class aClass, boolean checkFile) {
|
||||
String fileName = aClass.getName().replace('.', '/') + VALIDATION_CONFIG_SUFFIX;
|
||||
@Override
|
||||
public synchronized List<Validator> getValidators(Class clazz, String context, String method) {
|
||||
String validatorKey = buildValidatorKey(clazz, context);
|
||||
|
||||
return loadFile(fileName, aClass, checkFile);
|
||||
if (!validatorCache.containsKey(validatorKey)) {
|
||||
validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, false, null));
|
||||
} else if (reloadingConfigs) {
|
||||
validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, true, null));
|
||||
}
|
||||
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
List<ValidatorConfig> configs = validatorCache.get(validatorKey);
|
||||
List<Validator> validators = new ArrayList<>();
|
||||
for (ValidatorConfig config : configs) {
|
||||
if (method == null || method.equals(config.getParams().get("methodName"))) {
|
||||
validators.add(getValidatorFromValidatorConfig(config, stack));
|
||||
}
|
||||
}
|
||||
return validators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Validator> getValidators(Class clazz, String context) {
|
||||
return getValidators(clazz, context, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object object, String context, ValidatorContext validatorContext, String method) throws ValidationException {
|
||||
List<Validator> validators = getValidators(object.getClass(), context, method);
|
||||
Set<String> shortcircuitedFields = null;
|
||||
|
||||
for (Validator validator : validators) {
|
||||
validator.setValidatorContext(validatorContext);
|
||||
|
||||
LOG.debug("Running validator: {} for object {} and method {}", validator, object, method);
|
||||
|
||||
FieldValidator fValidator = null;
|
||||
String fullFieldName = null;
|
||||
|
||||
if (validator instanceof FieldValidator) {
|
||||
fValidator = (FieldValidator) validator;
|
||||
fullFieldName = validatorContext.getFullFieldName(fValidator.getFieldName());
|
||||
|
||||
if ((shortcircuitedFields != null) && shortcircuitedFields.contains(fullFieldName)) {
|
||||
LOG.debug("Short-circuited, skipping");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (validator instanceof ShortCircuitableValidator && ((ShortCircuitableValidator) validator).isShortCircuit()) {
|
||||
// get number of existing errors
|
||||
List<String> errs = null;
|
||||
|
||||
if (fValidator != null) {
|
||||
if (validatorContext.hasFieldErrors()) {
|
||||
Collection<String> fieldErrors = validatorContext.getFieldErrors().get(fullFieldName);
|
||||
|
||||
if (fieldErrors != null) {
|
||||
errs = new ArrayList<>(fieldErrors);
|
||||
}
|
||||
}
|
||||
} else if (validatorContext.hasActionErrors()) {
|
||||
Collection<String> actionErrors = validatorContext.getActionErrors();
|
||||
|
||||
if (actionErrors != null) {
|
||||
errs = new ArrayList<>(actionErrors);
|
||||
}
|
||||
}
|
||||
|
||||
validator.validate(object);
|
||||
|
||||
if (fValidator != null) {
|
||||
if (validatorContext.hasFieldErrors()) {
|
||||
Collection<String> errCol = validatorContext.getFieldErrors().get(fullFieldName);
|
||||
|
||||
if ((errCol != null) && !errCol.equals(errs)) {
|
||||
LOG.debug("Short-circuiting on field validation");
|
||||
|
||||
if (shortcircuitedFields == null) {
|
||||
shortcircuitedFields = new TreeSet<>();
|
||||
}
|
||||
|
||||
shortcircuitedFields.add(fullFieldName);
|
||||
}
|
||||
}
|
||||
} else if (validatorContext.hasActionErrors()) {
|
||||
Collection<String> errCol = validatorContext.getActionErrors();
|
||||
|
||||
if ((errCol != null) && !errCol.equals(errs)) {
|
||||
LOG.debug("Short-circuiting");
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
validator.validate(object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,18 +270,18 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
* <p>Note that the validation rules for Thing is never looked for because no class in the
|
||||
* hierarchy directly implements Thing.</p>
|
||||
*
|
||||
* @param clazz the Class to look up validators for.
|
||||
* @param context the context to use when looking up validators.
|
||||
* @param clazz the Class to look up validators for.
|
||||
* @param context the context to use when looking up validators.
|
||||
* @param checkFile true if the validation config file should be checked to see if it has been
|
||||
* updated.
|
||||
* @param checked the set of previously checked class-contexts, null if none have been checked
|
||||
* updated.
|
||||
* @param checked the set of previously checked class-contexts, null if none have been checked
|
||||
* @return a list of validator configs for the given class and context.
|
||||
*/
|
||||
private List<ValidatorConfig> buildValidatorConfigs(Class clazz, String context, boolean checkFile, Set<String> checked) {
|
||||
protected List<ValidatorConfig> buildValidatorConfigs(Class clazz, String context, boolean checkFile, Set<String> checked) {
|
||||
List<ValidatorConfig> validatorConfigs = new ArrayList<>();
|
||||
|
||||
if (checked == null) {
|
||||
checked = new TreeSet<String>();
|
||||
checked = new TreeSet<>();
|
||||
} else if (checked.contains(clazz.getName())) {
|
||||
return validatorConfigs;
|
||||
}
|
||||
@@ -295,7 +289,7 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
if (clazz.isInterface()) {
|
||||
for (Class anInterface : clazz.getInterfaces()) {
|
||||
validatorConfigs.addAll(buildValidatorConfigs(anInterface, context, checkFile, checked));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!clazz.equals(Object.class)) {
|
||||
validatorConfigs.addAll(buildValidatorConfigs(clazz.getSuperclass(), context, checkFile, checked));
|
||||
@@ -307,37 +301,44 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
if (checked.contains(anInterface1.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
validatorConfigs.addAll(buildClassValidatorConfigs(anInterface1, checkFile));
|
||||
|
||||
if (context != null) {
|
||||
validatorConfigs.addAll(buildAliasValidatorConfigs(anInterface1, context, checkFile));
|
||||
}
|
||||
|
||||
checked.add(anInterface1.getName());
|
||||
}
|
||||
|
||||
validatorConfigs.addAll(buildClassValidatorConfigs(clazz, checkFile));
|
||||
|
||||
if (context != null) {
|
||||
validatorConfigs.addAll(buildAliasValidatorConfigs(clazz, context, checkFile));
|
||||
}
|
||||
|
||||
checked.add(clazz.getName());
|
||||
|
||||
return validatorConfigs;
|
||||
}
|
||||
|
||||
private List<ValidatorConfig> loadFile(String fileName, Class clazz, boolean checkFile) {
|
||||
protected List<ValidatorConfig> buildAliasValidatorConfigs(Class aClass, String context, boolean checkFile) {
|
||||
String fileName = aClass.getName().replace('.', '/') + "-" + context + VALIDATION_CONFIG_SUFFIX;
|
||||
return loadFile(fileName, aClass, checkFile);
|
||||
}
|
||||
|
||||
protected List<ValidatorConfig> buildClassValidatorConfigs(Class aClass, boolean checkFile) {
|
||||
String fileName = aClass.getName().replace('.', '/') + VALIDATION_CONFIG_SUFFIX;
|
||||
return loadFile(fileName, aClass, checkFile);
|
||||
}
|
||||
|
||||
protected List<ValidatorConfig> loadFile(String fileName, Class clazz, boolean checkFile) {
|
||||
List<ValidatorConfig> retList = Collections.emptyList();
|
||||
|
||||
URL fileUrl = ClassLoaderUtil.getResource(fileName, clazz);
|
||||
|
||||
if ((checkFile && fileManager.fileNeedsReloading(fileUrl)) || !validatorFileCache.containsKey(fileName)) {
|
||||
try (InputStream is = fileManager.loadFile(fileUrl)) {
|
||||
if (is != null) {
|
||||
retList = new ArrayList<>(validatorFileParser.parseActionValidatorConfigs(validatorFactory, is, fileName));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Caught exception while loading file {}", fileName, e);
|
||||
LOG.error("Caught exception while closing file {}", fileName, e);
|
||||
}
|
||||
|
||||
validatorFileCache.put(fileName, retList);
|
||||
|
||||
@@ -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,9 @@ 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 directory to use for storing uploaded files */
|
||||
public static final String STRUTS_MULTIPART_SAVEDIR = "struts.multipart.saveDir";
|
||||
|
||||
@@ -174,9 +180,6 @@ public final class StrutsConstants {
|
||||
@Deprecated
|
||||
public static final String STRUTS_OBJECTFACTORY_SPRING_ENABLE_AOP_SUPPORT = "struts.objectFactory.spring.enableAopSupport";
|
||||
|
||||
/** Whether or not XSLT templates should not be cached */
|
||||
public static final String STRUTS_XSLT_NOCACHE = "struts.xslt.nocache";
|
||||
|
||||
/** Location of additional configuration properties files to load */
|
||||
public static final String STRUTS_CUSTOM_PROPERTIES = "struts.custom.properties";
|
||||
|
||||
@@ -376,7 +379,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 +401,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";
|
||||
@@ -410,11 +417,14 @@ public final class StrutsConstants {
|
||||
public static final String STRUTS_EXCLUDED_CLASSES = "struts.excludedClasses";
|
||||
public static final String STRUTS_EXCLUDED_PACKAGE_NAME_PATTERNS = "struts.excludedPackageNamePatterns";
|
||||
public static final String STRUTS_EXCLUDED_PACKAGE_NAMES = "struts.excludedPackageNames";
|
||||
public static final String STRUTS_EXCLUDED_PACKAGE_EXEMPT_CLASSES = "struts.excludedPackageExemptClasses";
|
||||
|
||||
/** Comma delimited set of excluded classes and package names which cannot be accessed via expressions in devMode */
|
||||
public static final String STRUTS_DEV_MODE_EXCLUDED_CLASSES = "struts.devMode.excludedClasses";
|
||||
public static final String STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAME_PATTERNS = "struts.devMode.excludedPackageNamePatterns";
|
||||
public static final String STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAMES = "struts.devMode.excludedPackageNames";
|
||||
public static final String STRUTS_DEV_MODE_EXCLUDED_PACKAGE_EXEMPT_CLASSES = "struts.devMode.excludedPackageExemptClasses";
|
||||
|
||||
|
||||
/** Dedicated services to check if passed string is excluded/accepted */
|
||||
public static final String STRUTS_EXCLUDED_PATTERNS_CHECKER = "struts.excludedPatterns.checker";
|
||||
@@ -450,4 +460,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";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.action;
|
||||
|
||||
import org.apache.struts2.interceptor.csp.CspSettings;
|
||||
|
||||
/**
|
||||
* Implement this interface by an action to provide a custom {@link CspSettings},
|
||||
* see {@link org.apache.struts2.interceptor.csp.CspInterceptor} for more details
|
||||
*
|
||||
* @since Struts 6.2.0
|
||||
*/
|
||||
public interface CspSettingsAware {
|
||||
|
||||
CspSettings getCspSettings();
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.io.Writer;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
@@ -294,7 +295,9 @@ public class Date extends ContextBean {
|
||||
// find the name on the valueStack
|
||||
Object dateObject = findValue(name);
|
||||
if (dateObject instanceof java.sql.Date) {
|
||||
date = ((java.sql.Date) dateObject).toLocalDate().atStartOfDay(tz);
|
||||
date = ((java.sql.Date) dateObject).toLocalDate().atTime(LocalTime.now(tz)).atZone(tz);
|
||||
} else if (dateObject instanceof java.sql.Time) {
|
||||
date = ((java.sql.Time) dateObject).toLocalTime().atDate(ZonedDateTime.now(tz).toLocalDate()).atZone(tz);
|
||||
} else if (dateObject instanceof java.util.Date) {
|
||||
date = ((java.util.Date) dateObject).toInstant().atZone(tz);
|
||||
} else if (dateObject instanceof Calendar) {
|
||||
|
||||
@@ -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());
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user