mirror of
https://github.com/apache/struts.git
synced 2026-08-08 16:16:58 +00:00
Compare commits
115 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3227d5929a | |||
| 4a8ddbb274 | |||
| 67ba458d03 | |||
| 959b2182b2 | |||
| 6de93e77db | |||
| 59dc9301e0 | |||
| 2fc4a822a4 | |||
| 6a6270f62a | |||
| 9153228b6a | |||
| 5713a74edc | |||
| 32071c71ad | |||
| 7e4791985b | |||
| 3c1e44ca2d | |||
| 2ba8d97ad0 | |||
| cba0db0b07 | |||
| 688162cae2 | |||
| a33c162f53 | |||
| c7a6daf5ce | |||
| 370c7ce17a | |||
| 55989befce | |||
| 2e4a4b5e36 | |||
| 9d07c3b4c3 | |||
| 575e4e8c9b | |||
| 74388dfba7 | |||
| 4ee8b02262 | |||
| c8febc2050 | |||
| 3ea126388c | |||
| 09993e3476 | |||
| f5688e680b | |||
| 60a3db0a63 | |||
| 4714d27678 | |||
| 4feceee5f1 | |||
| 1f5305c249 | |||
| 1903e0ef33 | |||
| 8a2f494c12 | |||
| 6b2e5ecd9b | |||
| cb08d18b5a | |||
| 1e2517b59e | |||
| 8d6ecee849 | |||
| 570bf46a7f | |||
| be82a72403 | |||
| 6fbd9e5321 | |||
| b0a4c4f417 | |||
| b001c61f89 | |||
| 2beac8eba4 | |||
| d351843ecd | |||
| 22036174c7 | |||
| ced44650ec | |||
| 1908cbab8f | |||
| c176390926 | |||
| fe46ad9f4a | |||
| a0dc19c4be | |||
| 7cdcd84b83 | |||
| 8566c14648 | |||
| c75ddbbf3e | |||
| b15dc458cf | |||
| 3f74923099 | |||
| 5b2f63fa7e | |||
| d9d580ae3d | |||
| 67e0477993 | |||
| 89bcbecc70 | |||
| 67ee1b2d67 | |||
| 5b81ec0852 | |||
| 266cd1333c | |||
| 323267fa88 | |||
| 2432449975 | |||
| 45a1f5efc6 | |||
| b488c80aa2 | |||
| 144010c3b7 | |||
| 9b87e88bb0 | |||
| 117e84f246 | |||
| a28f22605c | |||
| deb6c09bce | |||
| f95f9a7cd3 | |||
| 9e23fbe665 | |||
| a623842bce | |||
| 2757c23572 | |||
| ebedd7391f | |||
| 7ce8f484e0 | |||
| dfd07190bd | |||
| 111bc25650 | |||
| 8ba8ee5fe6 | |||
| 14bd4b80cf | |||
| bbca2717f9 | |||
| b622e5d725 | |||
| efa447af21 | |||
| cf6cbf3816 | |||
| 48ee44bbc2 | |||
| b18fbda1f7 | |||
| 28c8f1503d | |||
| d1695f7a4d | |||
| b359da5517 | |||
| 36a890ba69 | |||
| e3fbe88355 | |||
| 272c2e7bba | |||
| 60095a6934 | |||
| ae9dc42da7 | |||
| 8da6a79926 | |||
| 7deb481298 | |||
| 9f2770b2c3 | |||
| 78451db87e | |||
| 49ddf6130a | |||
| 1bcadd4682 | |||
| b115a510a6 | |||
| fbab5d4df9 | |||
| cd7f1097e2 | |||
| 2eff2da4fd | |||
| b3629460e6 | |||
| 3528b88327 | |||
| 3e04197ba7 | |||
| 09eb286020 | |||
| d33be1d43c | |||
| 9d903ddf96 | |||
| 4ccde0087e | |||
| 7473b4cef9 |
@@ -11,9 +11,19 @@ notifications:
|
||||
jira_options: link label worklog
|
||||
|
||||
github:
|
||||
description: "Apache Struts is a free, open-source, MVC framework for creating elegant, modern Java web applications"
|
||||
homepage: https://struts.apache.org/
|
||||
del_branch_on_merge: true
|
||||
protected_branches:
|
||||
master:
|
||||
main:
|
||||
# contexts are the names of checks that must pass.
|
||||
contexts:
|
||||
- build
|
||||
required_pull_request_reviews:
|
||||
# it does not work because our github teams are private/secret, see INFRA-25666
|
||||
require_code_owner_reviews: false
|
||||
required_approving_review_count: 0
|
||||
release/*:
|
||||
# contexts are the names of checks that must pass.
|
||||
contexts:
|
||||
- build
|
||||
|
||||
@@ -44,12 +44,12 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3.26.8
|
||||
uses: github/codeql-action/init@v3.27.1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3.26.8
|
||||
uses: github/codeql-action/autobuild@v3.27.1
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3.26.8
|
||||
uses: github/codeql-action/analyze@v3.27.1
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
@@ -57,13 +57,13 @@ jobs:
|
||||
publish_results: true
|
||||
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # 4.4.0
|
||||
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # 4.4.3
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@323f5ef653b88011bf10e9a0a56d70d742463c9a # 2.22.11
|
||||
uses: github/codeql-action/upload-sarif@acb9cb18eec7e3a113ef83cff0be91e75cfd9526 # 2.22.11
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
Vendored
+11
-54
@@ -69,7 +69,7 @@ pipeline {
|
||||
stages {
|
||||
stage('Test & Coverage') {
|
||||
steps {
|
||||
sh './mvnw -B verify -Pcoverage -DskipAssembly --no-transfer-progress'
|
||||
sh './mvnw -B verify -Pcoverage -DskipAssembly'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
@@ -81,58 +81,15 @@ pipeline {
|
||||
stage('Code Quality') {
|
||||
when {
|
||||
anyOf {
|
||||
branch 'master'; branch 'release/struts-7-0-x'
|
||||
branch 'release/struts-6-7-x'
|
||||
}
|
||||
}
|
||||
steps {
|
||||
withCredentials([string(credentialsId: 'asf-struts-sonarcloud', variable: 'SONARCLOUD_TOKEN')]) {
|
||||
sh './mvnw -B -Pcoverage -DskipAssembly -Dsonar.login=${SONARCLOUD_TOKEN} verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar --no-transfer-progress'
|
||||
sh './mvnw -B -Pcoverage -DskipAssembly -Dsonar.login=${SONARCLOUD_TOKEN} verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Build Source & JavaDoc') {
|
||||
when {
|
||||
branch 'release/struts-7-0-x'
|
||||
}
|
||||
steps {
|
||||
dir("local-snapshots-dir/") {
|
||||
deleteDir()
|
||||
}
|
||||
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly --no-transfer-progress'
|
||||
}
|
||||
}
|
||||
stage('Deploy Snapshot') {
|
||||
when {
|
||||
branch 'release/struts-7-0-x'
|
||||
}
|
||||
steps {
|
||||
withCredentials([file(credentialsId: 'lukaszlenart-repository-access-token', variable: 'CUSTOM_SETTINGS')]) {
|
||||
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly --no-transfer-progress'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Upload nightlies') {
|
||||
when {
|
||||
branch 'release/struts-7-0-x'
|
||||
}
|
||||
steps {
|
||||
sh './mvnw -B package -DskipTests --no-transfer-progress'
|
||||
sshPublisher(publishers: [
|
||||
sshPublisherDesc(
|
||||
configName: 'Nightlies',
|
||||
transfers: [
|
||||
sshTransfer(
|
||||
remoteDirectory: '/struts/snapshot',
|
||||
removePrefix: 'assembly/target/assembly/out',
|
||||
sourceFiles: 'assembly/target/assembly/out/struts-*.zip',
|
||||
cleanRemote: true
|
||||
)
|
||||
],
|
||||
verbose: true
|
||||
)
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
@@ -154,12 +111,12 @@ pipeline {
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh './mvnw -B clean install -DskipTests -DskipAssembly --no-transfer-progress'
|
||||
sh './mvnw -B clean install -DskipTests -DskipAssembly'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh './mvnw -B verify --no-transfer-progress'
|
||||
sh './mvnw -B verify -DskipAssembly'
|
||||
}
|
||||
post {
|
||||
always {
|
||||
@@ -170,31 +127,31 @@ pipeline {
|
||||
}
|
||||
stage('Build Source & JavaDoc') {
|
||||
when {
|
||||
branch 'master'
|
||||
branch 'release/struts-6-7-x'
|
||||
}
|
||||
steps {
|
||||
dir("local-snapshots-dir/") {
|
||||
deleteDir()
|
||||
}
|
||||
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly --no-transfer-progress'
|
||||
sh './mvnw -B source:jar javadoc:jar -DskipTests -DskipAssembly'
|
||||
}
|
||||
}
|
||||
stage('Deploy Snapshot') {
|
||||
when {
|
||||
branch 'master'
|
||||
branch 'release/struts-6-7-x'
|
||||
}
|
||||
steps {
|
||||
withCredentials([file(credentialsId: 'lukaszlenart-repository-access-token', variable: 'CUSTOM_SETTINGS')]) {
|
||||
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly --no-transfer-progress'
|
||||
sh './mvnw -s \${CUSTOM_SETTINGS} deploy -DskipTests -DskipAssembly'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Upload nightlies') {
|
||||
when {
|
||||
branch 'master'
|
||||
branch 'release/struts-6-7-x'
|
||||
}
|
||||
steps {
|
||||
sh './mvnw -B package -DskipTests --no-transfer-progress'
|
||||
sh './mvnw -B package -DskipTests'
|
||||
sshPublisher(publishers: [
|
||||
sshPublisherDesc(
|
||||
configName: 'Nightlies',
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.6.1</version>
|
||||
<version>6.7.1</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.6.1</version>
|
||||
<version>6.7.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-rest-showcase</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>6.6.1</version>
|
||||
<version>6.7.1</version>
|
||||
<name>Struts 2 Rest Showcase Webapp</name>
|
||||
<description>Struts 2 Rest Showcase Example</description>
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>6.6.1</version>
|
||||
<version>6.7.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-showcase</artifactId>
|
||||
@@ -163,7 +163,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<version>3.5.1</version>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>it.org.apache.struts2.showcase.*Test</include>
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ public class ModelDrivenAction extends ActionSupport implements ModelDriven {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getModel() {
|
||||
public Gangster getModel() {
|
||||
return new Gangster();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.6.1</version>
|
||||
<version>6.7.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-assembly</artifactId>
|
||||
|
||||
+4
-4
@@ -25,11 +25,11 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.6.1</version>
|
||||
<version>6.7.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-bom</artifactId>
|
||||
<version>6.6.1</version>
|
||||
<version>6.7.1</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Struts 2 Bill of Materials</name>
|
||||
@@ -44,7 +44,7 @@
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<struts-version.version>6.6.1</struts-version.version>
|
||||
<struts-version.version>6.7.1</struts-version.version>
|
||||
<maven.site.skip>true</maven.site.skip>
|
||||
<maven.site.deploy.skip>true</maven.site.deploy.skip>
|
||||
</properties>
|
||||
@@ -190,7 +190,7 @@
|
||||
</dependencyManagement>
|
||||
|
||||
<scm>
|
||||
<tag>STRUTS_6_6_1</tag>
|
||||
<tag>STRUTS_6_7_1</tag>
|
||||
<connection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</connection>
|
||||
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</developerConnection>
|
||||
<url>https://github.com/apache/struts/</url>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>6.6.1</version>
|
||||
<version>6.7.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-admin-bundle</artifactId>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>6.6.1</version>
|
||||
<version>6.7.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-demo-bundle</artifactId>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.6.1</version>
|
||||
<version>6.7.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.6.1</version>
|
||||
<version>6.7.1</version>
|
||||
</parent>
|
||||
<artifactId>struts2-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -19,70 +19,10 @@
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
/**
|
||||
* All actions <b>may</b> implement this interface, which exposes the <code>execute()</code> method.
|
||||
* <p>
|
||||
* However, as of XWork 1.1, this is <b>not</b> required and is only here to assist users. You are free to create POJOs
|
||||
* that honor the same contract defined by this interface without actually implementing the interface.
|
||||
* </p>
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.action.Action} instead.
|
||||
*/
|
||||
public interface Action {
|
||||
|
||||
/**
|
||||
* The action execution was successful. Show result
|
||||
* view to the end user.
|
||||
*/
|
||||
public static final String SUCCESS = "success";
|
||||
|
||||
/**
|
||||
* The action execution was successful but do not
|
||||
* show a view. This is useful for actions that are
|
||||
* handling the view in another fashion like redirect.
|
||||
*/
|
||||
public static final String NONE = "none";
|
||||
|
||||
/**
|
||||
* The action execution was a failure.
|
||||
* Show an error view, possibly asking the
|
||||
* user to retry entering data.
|
||||
*/
|
||||
public static final String ERROR = "error";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The action execution require more input
|
||||
* in order to succeed.
|
||||
* This result is typically used if a form
|
||||
* handling action has been executed so as
|
||||
* to provide defaults for a form. The
|
||||
* form associated with the handler should be
|
||||
* shown to the end user.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This result is also used if the given input
|
||||
* params are invalid, meaning the user
|
||||
* should try providing input again.
|
||||
* </p>
|
||||
*/
|
||||
public static final String INPUT = "input";
|
||||
|
||||
/**
|
||||
* The action could not execute, since the
|
||||
* user most was not logged in. The login view
|
||||
* should be shown.
|
||||
*/
|
||||
public static final String LOGIN = "login";
|
||||
|
||||
|
||||
/**
|
||||
* Where the logic of the action is executed.
|
||||
*
|
||||
* @return a string representing the logical result of the execution.
|
||||
* See constants in this interface for a list of standard result values.
|
||||
* @throws Exception thrown if a system level exception occurs.
|
||||
* <b>Note:</b> Application level exceptions should be handled by returning
|
||||
* an error value, such as <code>Action.ERROR</code>.
|
||||
*/
|
||||
public String execute() throws Exception;
|
||||
|
||||
@Deprecated
|
||||
public interface Action extends org.apache.struts2.action.Action {
|
||||
}
|
||||
|
||||
@@ -18,263 +18,21 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
*
|
||||
* This result invokes an entire other action, complete with it's own interceptor stack and result.
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <b>This result type takes the following parameters:</b>
|
||||
*
|
||||
* <!-- START SNIPPET: params -->
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li><b>actionName (default)</b> - the name of the action that will be chained to</li>
|
||||
*
|
||||
* <li><b>namespace</b> - used to determine which namespace the Action is in that we're chaining. If namespace is null,
|
||||
* this defaults to the current namespace</li>
|
||||
*
|
||||
* <li><b>method</b> - used to specify another method on target action to be invoked.
|
||||
* If null, this defaults to execute method</li>
|
||||
*
|
||||
* <li><b>skipActions</b> - (optional) the list of comma separated action names for the
|
||||
* actions that could be chained to</li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <!-- END SNIPPET: params -->
|
||||
*
|
||||
* <b>Example:</b>
|
||||
*
|
||||
* <pre><!-- START SNIPPET: example -->
|
||||
* <package name="public" extends="struts-default">
|
||||
* <!-- Chain creatAccount to login, using the default parameter -->
|
||||
* <action name="createAccount" class="...">
|
||||
* <result type="chain">login</result>
|
||||
* </action>
|
||||
*
|
||||
* <action name="login" class="...">
|
||||
* <!-- Chain to another namespace -->
|
||||
* <result type="chain">
|
||||
* <param name="actionName">dashboard</param>
|
||||
* <param name="namespace">/secure</param>
|
||||
* </result>
|
||||
* </action>
|
||||
* </package>
|
||||
*
|
||||
* <package name="secure" extends="struts-default" namespace="/secure">
|
||||
* <action name="dashboard" class="...">
|
||||
* <result>dashboard.jsp</result>
|
||||
* </action>
|
||||
* </package>
|
||||
* <!-- END SNIPPET: example --></pre>
|
||||
*
|
||||
* @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
|
||||
*/
|
||||
public class ActionChainResult implements Result {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ActionChainResult.class);
|
||||
|
||||
/**
|
||||
* The result parameter name to set the name of the action to chain to.
|
||||
*/
|
||||
public static final String DEFAULT_PARAM = "actionName";
|
||||
|
||||
/**
|
||||
* The action context key to save the chain history.
|
||||
*/
|
||||
private static final String CHAIN_HISTORY = "CHAIN_HISTORY";
|
||||
|
||||
private ActionProxy proxy;
|
||||
private String actionName;
|
||||
|
||||
private String namespace;
|
||||
|
||||
private String methodName;
|
||||
|
||||
/**
|
||||
* The list of actions to skip.
|
||||
*/
|
||||
private String skipActions;
|
||||
|
||||
private ActionProxyFactory actionProxyFactory;
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.result.ActionChainResult} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ActionChainResult extends org.apache.struts2.result.ActionChainResult {
|
||||
|
||||
public ActionChainResult() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ActionChainResult(String namespace, String actionName, String methodName) {
|
||||
this.namespace = namespace;
|
||||
this.actionName = actionName;
|
||||
this.methodName = methodName;
|
||||
super(namespace, actionName, methodName);
|
||||
}
|
||||
|
||||
public ActionChainResult(String namespace, String actionName, String methodName, String skipActions) {
|
||||
this.namespace = namespace;
|
||||
this.actionName = actionName;
|
||||
this.methodName = methodName;
|
||||
this.skipActions = skipActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param actionProxyFactory the actionProxyFactory to set
|
||||
*/
|
||||
@Inject
|
||||
public void setActionProxyFactory(ActionProxyFactory actionProxyFactory) {
|
||||
this.actionProxyFactory = actionProxyFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the action name.
|
||||
*
|
||||
* @param actionName The action name.
|
||||
*/
|
||||
public void setActionName(String actionName) {
|
||||
this.actionName = actionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the namespace of the Action that we're chaining to. if namespace
|
||||
* is null, this defaults to the current namespace.
|
||||
*
|
||||
* @param namespace the name of the namespace we're chaining to
|
||||
*/
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of actions to skip.
|
||||
* To test if an action should not throe an infinite recursion,
|
||||
* only the action name is used, not the namespace.
|
||||
*
|
||||
* @param actions The list of action name separated by a white space.
|
||||
*/
|
||||
public void setSkipActions(String actions) {
|
||||
this.skipActions = actions;
|
||||
}
|
||||
|
||||
public void setMethod(String method) {
|
||||
this.methodName = method;
|
||||
}
|
||||
|
||||
public ActionProxy getProxy() {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the XWork chain history.
|
||||
* The stack is a list of <code>namespace/action!method</code> keys.
|
||||
*
|
||||
* @return the chain history as string list
|
||||
*/
|
||||
public static LinkedList<String> getChainHistory() {
|
||||
LinkedList<String> chainHistory = (LinkedList<String>) ActionContext.getContext().get(CHAIN_HISTORY);
|
||||
// Add if not exists
|
||||
if (chainHistory == null) {
|
||||
chainHistory = new LinkedList<>();
|
||||
ActionContext.getContext().put(CHAIN_HISTORY, chainHistory);
|
||||
}
|
||||
|
||||
return chainHistory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param invocation the DefaultActionInvocation calling the action call stack
|
||||
*/
|
||||
public void execute(ActionInvocation invocation) throws Exception {
|
||||
if (invocation == null) {
|
||||
throw new IllegalArgumentException("Invocation cannot be null!");
|
||||
}
|
||||
|
||||
String finalNamespace = namespace != null ? translateVariables(namespace) : invocation.getProxy()
|
||||
.getNamespace();
|
||||
String finalActionName = translateVariables(actionName);
|
||||
String finalMethodName = methodName != null ? translateVariables(methodName) : null;
|
||||
|
||||
if (isInChainHistory(finalNamespace, finalActionName, finalMethodName)) {
|
||||
addToHistory(finalNamespace, finalActionName, finalMethodName);
|
||||
throw new StrutsException("Infinite recursion detected: " + ActionChainResult.getChainHistory());
|
||||
}
|
||||
|
||||
if (ActionChainResult.getChainHistory().isEmpty() && invocation.getProxy() != null) {
|
||||
addToHistory(finalNamespace, invocation.getProxy().getActionName(), invocation.getProxy().getMethod());
|
||||
}
|
||||
addToHistory(finalNamespace, finalActionName, finalMethodName);
|
||||
|
||||
Map<String, Object> extraContext = ActionContext.of()
|
||||
.withValueStack(invocation.getInvocationContext().getValueStack())
|
||||
.withParameters(invocation.getInvocationContext().getParameters())
|
||||
.with(CHAIN_HISTORY, ActionChainResult.getChainHistory())
|
||||
.getContextMap();
|
||||
|
||||
LOG.debug("Chaining to action {}", finalActionName);
|
||||
|
||||
proxy = actionProxyFactory.createActionProxy(finalNamespace, finalActionName, finalMethodName, extraContext);
|
||||
proxy.execute();
|
||||
}
|
||||
|
||||
protected String translateVariables(String text) {
|
||||
return TextParseUtil.translateVariables(text, ActionContext.getContext().getValueStack());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ActionChainResult that = (ActionChainResult) o;
|
||||
return Objects.equals(actionName, that.actionName) && Objects.equals(methodName,
|
||||
that.methodName) && Objects.equals(namespace, that.namespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
result = (actionName != null ? actionName.hashCode() : 0);
|
||||
result = 31 * result + (namespace != null ? namespace.hashCode() : 0);
|
||||
result = 31 * result + (methodName != null ? methodName.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isInChainHistory(String namespace, String actionName, String methodName) {
|
||||
LinkedList<? extends String> chainHistory = ActionChainResult.getChainHistory();
|
||||
Set<String> skipActionsList = new HashSet<>();
|
||||
if (skipActions != null && skipActions.length() > 0) {
|
||||
String finalSkipActions = translateVariables(skipActions);
|
||||
skipActionsList.addAll(TextParseUtil.commaDelimitedStringToSet(finalSkipActions));
|
||||
}
|
||||
if (!skipActionsList.contains(actionName)) {
|
||||
return chainHistory.contains(makeKey(namespace, actionName, methodName));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void addToHistory(String namespace, String actionName, String methodName) {
|
||||
List<String> chainHistory = ActionChainResult.getChainHistory();
|
||||
chainHistory.add(makeKey(namespace, actionName, methodName));
|
||||
}
|
||||
|
||||
private String makeKey(String namespace, String actionName, String methodName) {
|
||||
return namespace + "/" + actionName + (methodName != null ? "!" + methodName : "");
|
||||
super(namespace, actionName, methodName, skipActions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ package com.opensymphony.xwork2;
|
||||
import com.opensymphony.xwork2.conversion.impl.ConversionData;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.StrutsStatics;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
|
||||
@@ -30,515 +28,249 @@ import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The ActionContext is the context in which an {@link Action} is executed. Each context is basically a
|
||||
* container of objects an action needs for execution like the session, parameters, locale, etc.
|
||||
* </p>
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* The ActionContext is thread local which means that values stored in the ActionContext are
|
||||
* unique per thread. See the {@link ThreadLocal} class for more information. The benefit of
|
||||
* this is you don't need to worry about a user specific action context, you just get it:
|
||||
* </p>
|
||||
*
|
||||
* <code>ActionContext context = ActionContext.getContext();</code>
|
||||
*
|
||||
* <p>
|
||||
* Finally, because of the thread local usage you don't need to worry about making your actions thread safe.
|
||||
* </p>
|
||||
*
|
||||
* @author Patrick Lightbody
|
||||
* @author Bill Lynch (docs)
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.ActionContext} instead.
|
||||
*/
|
||||
public class ActionContext implements Serializable {
|
||||
@Deprecated
|
||||
public class ActionContext extends org.apache.struts2.ActionContext {
|
||||
|
||||
private static final ThreadLocal<ActionContext> actionContext = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Constant for the name of the action being executed.
|
||||
*/
|
||||
private static final String ACTION_NAME = "org.apache.struts2.ActionContext.name";
|
||||
|
||||
/**
|
||||
* Constant for the {@link com.opensymphony.xwork2.util.ValueStack OGNL value stack}.
|
||||
*/
|
||||
private static final String VALUE_STACK = ValueStack.VALUE_STACK;
|
||||
|
||||
/**
|
||||
* Constant for the action's session.
|
||||
*/
|
||||
private static final String SESSION = "org.apache.struts2.ActionContext.session";
|
||||
|
||||
/**
|
||||
* Constant for the action's application context.
|
||||
*/
|
||||
private static final String APPLICATION = "org.apache.struts2.ActionContext.application";
|
||||
|
||||
/**
|
||||
* Constant for the action's parameters.
|
||||
*/
|
||||
private static final String PARAMETERS = "org.apache.struts2.ActionContext.parameters";
|
||||
|
||||
/**
|
||||
* Constant for the action's locale.
|
||||
*/
|
||||
private static final String LOCALE = "org.apache.struts2.ActionContext.locale";
|
||||
|
||||
/**
|
||||
* Constant for the action's {@link com.opensymphony.xwork2.ActionInvocation invocation} context.
|
||||
*/
|
||||
private static final String ACTION_INVOCATION = "org.apache.struts2.ActionContext.actionInvocation";
|
||||
|
||||
/**
|
||||
* Constant for the map of type conversion errors.
|
||||
*/
|
||||
private static final String CONVERSION_ERRORS = "org.apache.struts2.ActionContext.conversionErrors";
|
||||
|
||||
/**
|
||||
* Constant for the container
|
||||
*/
|
||||
private static final String CONTAINER = "org.apache.struts2.ActionContext.container";
|
||||
|
||||
private final Map<String, Object> context;
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext initialized with another context.
|
||||
*
|
||||
* @param context a context map.
|
||||
*/
|
||||
protected ActionContext(Map<String, Object> context) {
|
||||
this.context = context;
|
||||
private ActionContext(org.apache.struts2.ActionContext actualContext) {
|
||||
super(actualContext.getContextMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext based on passed in Map
|
||||
*
|
||||
* @param context a map with context values
|
||||
* @return new ActionContext
|
||||
*/
|
||||
public static ActionContext of(Map<String, Object> context) {
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException("Context cannot be null!");
|
||||
public static ActionContext adapt(org.apache.struts2.ActionContext actualContext) {
|
||||
if (actualContext instanceof ActionContext) {
|
||||
return (ActionContext) actualContext;
|
||||
}
|
||||
return new ActionContext(context);
|
||||
return actualContext != null ? new ActionContext(actualContext) : null;
|
||||
}
|
||||
|
||||
public static ActionContext of(Map<String, Object> context) {
|
||||
return adapt(org.apache.struts2.ActionContext.of(context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext based on empty Map
|
||||
*
|
||||
* @return new ActionContext
|
||||
*/
|
||||
public static ActionContext of() {
|
||||
return of(new HashMap<>());
|
||||
return adapt(org.apache.struts2.ActionContext.of());
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the provided context with the current thread
|
||||
*
|
||||
* @param actionContext context to bind to the thread
|
||||
* @return context which was bound to the thread
|
||||
*/
|
||||
public static ActionContext bind(ActionContext actionContext) {
|
||||
ActionContext.setContext(actionContext);
|
||||
return ActionContext.getContext();
|
||||
return adapt(org.apache.struts2.ActionContext.bind(actionContext));
|
||||
}
|
||||
|
||||
public static boolean containsValueStack(Map<String, Object> context) {
|
||||
return context != null && context.containsKey(VALUE_STACK);
|
||||
return org.apache.struts2.ActionContext.containsValueStack(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds this context with the current thread
|
||||
*
|
||||
* @return this context which was bound to the thread
|
||||
*/
|
||||
public ActionContext bind() {
|
||||
ActionContext.setContext(this);
|
||||
return ActionContext.getContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wipes out current ActionContext, use wisely!
|
||||
*/
|
||||
public static void clear() {
|
||||
actionContext.remove();
|
||||
org.apache.struts2.ActionContext.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action context for the current thread.
|
||||
*
|
||||
* @param context the action context.
|
||||
*/
|
||||
private static void setContext(ActionContext context) {
|
||||
actionContext.set(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ActionContext specific to the current thread.
|
||||
*
|
||||
* @return the ActionContext for the current thread, is never <tt>null</tt>.
|
||||
*/
|
||||
public static ActionContext getContext() {
|
||||
return actionContext.get();
|
||||
return adapt(org.apache.struts2.ActionContext.getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext bind() {
|
||||
super.bind();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action invocation (the execution state).
|
||||
*
|
||||
* @param actionInvocation the action execution state.
|
||||
*/
|
||||
public ActionContext withActionInvocation(ActionInvocation actionInvocation) {
|
||||
put(ACTION_INVOCATION, actionInvocation);
|
||||
return withActionInvocation((org.apache.struts2.ActionInvocation) actionInvocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext withActionInvocation(org.apache.struts2.ActionInvocation actionInvocation) {
|
||||
super.withActionInvocation(actionInvocation);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the action invocation (the execution state).
|
||||
*
|
||||
* @return the action invocation (the execution state).
|
||||
*/
|
||||
@Override
|
||||
public ActionInvocation getActionInvocation() {
|
||||
return (ActionInvocation) get(ACTION_INVOCATION);
|
||||
return ActionInvocation.adapt(super.getActionInvocation());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action's application context.
|
||||
*
|
||||
* @param application the action's application context.
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withApplication(Map<String, Object> application) {
|
||||
put(APPLICATION, application);
|
||||
super.withApplication(application);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Map of the ServletContext when in a servlet environment or a generic application level Map otherwise.
|
||||
*
|
||||
* @return a Map of ServletContext or generic application level Map
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Map<String, Object> getApplication() {
|
||||
return (Map<String, Object>) get(APPLICATION);
|
||||
return super.getApplication();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the context map.
|
||||
*
|
||||
* @return the context map.
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getContextMap() {
|
||||
return context;
|
||||
return super.getContextMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets conversion errors which occurred when executing the action.
|
||||
*
|
||||
* @param conversionErrors a Map of errors which occurred when executing the action.
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withConversionErrors(Map<String, ConversionData> conversionErrors) {
|
||||
put(CONVERSION_ERRORS, conversionErrors);
|
||||
super.withConversionErrors(conversionErrors);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the map of conversion errors which occurred when executing the action.
|
||||
*
|
||||
* @return the map of conversion errors which occurred when executing the action or an empty map if
|
||||
* there were no errors.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Map<String, ConversionData> getConversionErrors() {
|
||||
Map<String, ConversionData> errors = (Map<String, ConversionData>) get(CONVERSION_ERRORS);
|
||||
|
||||
if (errors == null) {
|
||||
errors = withConversionErrors(new HashMap<>()).getConversionErrors();
|
||||
}
|
||||
|
||||
return errors;
|
||||
return super.getConversionErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Locale for the current action.
|
||||
*
|
||||
* @param locale the Locale for the current action.
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withLocale(Locale locale) {
|
||||
put(LOCALE, locale);
|
||||
super.withLocale(locale);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Locale of the current action. If no locale was ever specified the platform's
|
||||
* {@link java.util.Locale#getDefault() default locale} is used.
|
||||
*
|
||||
* @return the Locale of the current action.
|
||||
*/
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
Locale locale = (Locale) get(LOCALE);
|
||||
|
||||
if (locale == null) {
|
||||
locale = Locale.getDefault();
|
||||
withLocale(locale);
|
||||
}
|
||||
|
||||
return locale;
|
||||
return super.getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the current Action in the ActionContext.
|
||||
*
|
||||
* @param actionName the name of the current action.
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withActionName(String actionName) {
|
||||
put(ACTION_NAME, actionName);
|
||||
super.withActionName(actionName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the current Action.
|
||||
*
|
||||
* @return the name of the current action.
|
||||
*/
|
||||
@Override
|
||||
public String getActionName() {
|
||||
return (String) get(ACTION_NAME);
|
||||
return super.getActionName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action parameters.
|
||||
*
|
||||
* @param parameters the parameters for the current action.
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withParameters(HttpParameters parameters) {
|
||||
put(PARAMETERS, parameters);
|
||||
super.withParameters(parameters);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Map of the HttpServletRequest parameters when in a servlet environment or a generic Map of
|
||||
* parameters otherwise.
|
||||
*
|
||||
* @return a Map of HttpServletRequest parameters or a multipart map when in a servlet environment, or a
|
||||
* generic Map of parameters otherwise.
|
||||
*/
|
||||
@Override
|
||||
public HttpParameters getParameters() {
|
||||
return (HttpParameters) get(PARAMETERS);
|
||||
return super.getParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a map of action session values.
|
||||
*
|
||||
* @param session the session values.
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withSession(Map<String, Object> session) {
|
||||
put(SESSION, session);
|
||||
super.withSession(session);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Map of HttpSession values when in a servlet environment or a generic session map otherwise.
|
||||
*
|
||||
* @return the Map of HttpSession values when in a servlet environment or a generic session map otherwise.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Map<String, Object> getSession() {
|
||||
return (Map<String, Object>) get(SESSION);
|
||||
return super.getSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the OGNL value stack.
|
||||
*
|
||||
* @param valueStack the OGNL value stack.
|
||||
*/
|
||||
public ActionContext withValueStack(ValueStack valueStack) {
|
||||
put(VALUE_STACK, valueStack);
|
||||
return withValueStack((org.apache.struts2.util.ValueStack) valueStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext withValueStack(org.apache.struts2.util.ValueStack valueStack) {
|
||||
super.withValueStack(valueStack);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OGNL value stack.
|
||||
*
|
||||
* @return the OGNL value stack.
|
||||
*/
|
||||
@Override
|
||||
public ValueStack getValueStack() {
|
||||
return (ValueStack) get(VALUE_STACK);
|
||||
return ValueStack.adapt(super.getValueStack());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the container for this request
|
||||
*
|
||||
* @param container The container
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withContainer(Container container) {
|
||||
put(CONTAINER, container);
|
||||
super.withContainer(container);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the container for this request
|
||||
*
|
||||
* @return The container
|
||||
*/
|
||||
@Override
|
||||
public Container getContainer() {
|
||||
return (Container) get(CONTAINER);
|
||||
return super.getContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInstance(Class<T> type) {
|
||||
Container cont = getContainer();
|
||||
if (cont != null) {
|
||||
return cont.getInstance(type);
|
||||
} else {
|
||||
throw new StrutsException("Cannot find an initialized container for this request.");
|
||||
}
|
||||
return super.getInstance(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value that is stored in the current ActionContext by doing a lookup using the value's key.
|
||||
*
|
||||
* @param key the key used to find the value.
|
||||
* @return the value that was found using the key or <tt>null</tt> if the key was not found.
|
||||
*/
|
||||
@Override
|
||||
public Object get(String key) {
|
||||
return context.get(key);
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value in the current ActionContext. The value can be looked up using the key.
|
||||
*
|
||||
* @param key the key of the value.
|
||||
* @param value the value to be stored.
|
||||
*/
|
||||
@Override
|
||||
public void put(String key, Object value) {
|
||||
context.put(key, value);
|
||||
super.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ServletContext associated with current action
|
||||
*
|
||||
* @return current ServletContext
|
||||
*/
|
||||
@Override
|
||||
public ServletContext getServletContext() {
|
||||
return (ServletContext) get(StrutsStatics.SERVLET_CONTEXT);
|
||||
return super.getServletContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ServletContext to action context
|
||||
*
|
||||
* @param servletContext associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withServletContext(ServletContext servletContext) {
|
||||
put(StrutsStatics.SERVLET_CONTEXT, servletContext);
|
||||
super.withServletContext(servletContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ServletRequest associated with current action
|
||||
*
|
||||
* @return current ServletRequest
|
||||
*/
|
||||
@Override
|
||||
public HttpServletRequest getServletRequest() {
|
||||
return (HttpServletRequest) get(StrutsStatics.HTTP_REQUEST);
|
||||
return super.getServletRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ServletRequest to action context
|
||||
*
|
||||
* @param request associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withServletRequest(HttpServletRequest request) {
|
||||
put(StrutsStatics.HTTP_REQUEST, request);
|
||||
super.withServletRequest(request);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ServletResponse associated with current action
|
||||
*
|
||||
* @return current ServletResponse
|
||||
*/
|
||||
@Override
|
||||
public HttpServletResponse getServletResponse() {
|
||||
return (HttpServletResponse) get(StrutsStatics.HTTP_RESPONSE);
|
||||
return super.getServletResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ServletResponse to action context
|
||||
*
|
||||
* @param response associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withServletResponse(HttpServletResponse response) {
|
||||
put(StrutsStatics.HTTP_RESPONSE, response);
|
||||
super.withServletResponse(response);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets PageContext associated with current action
|
||||
*
|
||||
* @return current PageContext
|
||||
*/
|
||||
@Override
|
||||
public PageContext getPageContext() {
|
||||
return (PageContext) get(StrutsStatics.PAGE_CONTEXT);
|
||||
return super.getPageContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns PageContext to action context
|
||||
*
|
||||
* @param pageContext associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withPageContext(PageContext pageContext) {
|
||||
put(StrutsStatics.PAGE_CONTEXT, pageContext);
|
||||
super.withPageContext(pageContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ActionMapping associated with current action
|
||||
*
|
||||
* @return current ActionMapping
|
||||
*/
|
||||
@Override
|
||||
public ActionMapping getActionMapping() {
|
||||
return (ActionMapping) get(StrutsStatics.ACTION_MAPPING);
|
||||
return super.getActionMapping();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ActionMapping to action context
|
||||
*
|
||||
* @param actionMapping associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withActionMapping(ActionMapping actionMapping) {
|
||||
put(StrutsStatics.ACTION_MAPPING, actionMapping);
|
||||
super.withActionMapping(actionMapping);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns an extra context map to action context
|
||||
*
|
||||
* @param extraContext to add to the current action context
|
||||
* @return ActionContext
|
||||
*/
|
||||
@Override
|
||||
public ActionContext withExtraContext(Map<String, Object> extraContext) {
|
||||
if (extraContext != null) {
|
||||
context.putAll(extraContext);
|
||||
}
|
||||
super.withExtraContext(extraContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds arbitrary key to action context
|
||||
*
|
||||
* @param key a string
|
||||
* @param value an object
|
||||
* @return ActionContext
|
||||
*/
|
||||
@Override
|
||||
public ActionContext with(String key, Object value) {
|
||||
put(key, value);
|
||||
super.with(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,24 +21,50 @@ package com.opensymphony.xwork2;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
|
||||
/**
|
||||
* Provides hooks for handling key action events
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.ActionEventListener} instead.
|
||||
*/
|
||||
public interface ActionEventListener {
|
||||
/**
|
||||
* Called after an action has been created.
|
||||
*
|
||||
* @param action The action
|
||||
* @param stack The current value stack
|
||||
* @return The action to use
|
||||
*/
|
||||
public Object prepare(Object action, ValueStack stack);
|
||||
|
||||
/**
|
||||
* Called when an exception is thrown by the action
|
||||
*
|
||||
* @param t The exception/error that was thrown
|
||||
* @param stack The current value stack
|
||||
* @return A result code to execute, can be null
|
||||
*/
|
||||
public String handleException(Throwable t, ValueStack stack);
|
||||
@Deprecated
|
||||
public interface ActionEventListener extends org.apache.struts2.ActionEventListener {
|
||||
|
||||
@Override
|
||||
default Object prepare(Object action, org.apache.struts2.util.ValueStack stack) {
|
||||
return prepare(action, ValueStack.adapt(stack));
|
||||
}
|
||||
|
||||
@Override
|
||||
default String handleException(Throwable t, org.apache.struts2.util.ValueStack stack) {
|
||||
return handleException(t, ValueStack.adapt(stack));
|
||||
}
|
||||
|
||||
Object prepare(Object action, ValueStack stack);
|
||||
|
||||
String handleException(Throwable t, ValueStack stack);
|
||||
|
||||
static ActionEventListener adapt(org.apache.struts2.ActionEventListener actualListener) {
|
||||
if (actualListener instanceof ActionEventListener) {
|
||||
return (ActionEventListener) actualListener;
|
||||
}
|
||||
return actualListener != null ? new LegacyAdapter(actualListener) : null;
|
||||
}
|
||||
|
||||
class LegacyAdapter implements ActionEventListener {
|
||||
|
||||
private final org.apache.struts2.ActionEventListener adaptee;
|
||||
|
||||
private LegacyAdapter(org.apache.struts2.ActionEventListener adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object prepare(Object action, ValueStack stack) {
|
||||
return adaptee.prepare(action, stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handleException(Throwable t, ValueStack stack) {
|
||||
return adaptee.handleException(t, stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,158 +22,125 @@ import com.opensymphony.xwork2.interceptor.PreResultListener;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
|
||||
/**
|
||||
* An {@link ActionInvocation} represents the execution state of an {@link Action}. It holds the Interceptors and the Action instance.
|
||||
* By repeated re-entrant execution of the <code>invoke()</code> method, initially by the {@link ActionProxy}, then by the Interceptors, the
|
||||
* Interceptors are all executed, and then the {@link Action} and the {@link Result}.
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @see com.opensymphony.xwork2.ActionProxy
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.ActionInvocation} instead.
|
||||
*/
|
||||
public interface ActionInvocation {
|
||||
@Deprecated
|
||||
public interface ActionInvocation extends org.apache.struts2.ActionInvocation {
|
||||
|
||||
/**
|
||||
* Get the Action associated with this ActionInvocation.
|
||||
*
|
||||
* @return the Action
|
||||
*/
|
||||
Object getAction();
|
||||
|
||||
/**
|
||||
* Gets whether this ActionInvocation has executed before.
|
||||
* This will be set after the Action and the Result have executed.
|
||||
*
|
||||
* @return <tt>true</tt> if this ActionInvocation has executed before.
|
||||
*/
|
||||
boolean isExecuted();
|
||||
|
||||
/**
|
||||
* Gets the ActionContext associated with this ActionInvocation. The ActionProxy is
|
||||
* responsible for setting this ActionContext onto the ThreadLocal before invoking
|
||||
* the ActionInvocation and resetting the old ActionContext afterwards.
|
||||
*
|
||||
* @return the ActionContext.
|
||||
*/
|
||||
@Override
|
||||
ActionContext getInvocationContext();
|
||||
|
||||
/**
|
||||
* Get the ActionProxy holding this ActionInvocation.
|
||||
*
|
||||
* @return the ActionProxy.
|
||||
*/
|
||||
ActionProxy getProxy();
|
||||
|
||||
/**
|
||||
* If the ActionInvocation has been executed before and the Result is an instance of {@link ActionChainResult}, this method
|
||||
* will walk down the chain of <code>ActionChainResult</code>s until it finds a non-chain result, which will be returned. If the
|
||||
* ActionInvocation's result has not been executed before, the Result instance will be created and populated with
|
||||
* the result params.
|
||||
*
|
||||
* @return the result.
|
||||
* @throws Exception can be thrown.
|
||||
*/
|
||||
@Override
|
||||
Result getResult() throws Exception;
|
||||
|
||||
/**
|
||||
* Gets the result code returned from this ActionInvocation.
|
||||
*
|
||||
* @return the result code
|
||||
*/
|
||||
String getResultCode();
|
||||
@Override
|
||||
ActionProxy getProxy();
|
||||
|
||||
/**
|
||||
* Sets the result code, possibly overriding the one returned by the
|
||||
* action.
|
||||
*
|
||||
* <p>
|
||||
* The "intended" purpose of this method is to allow PreResultListeners to
|
||||
* override the result code returned by the Action.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If this method is used before the Action executes, the Action's returned
|
||||
* result code will override what was set. However the Action could (if
|
||||
* specifically coded to do so) inspect the ActionInvocation to see that
|
||||
* someone "upstream" (e.g. an Interceptor) had suggested a value as the
|
||||
* result, and it could therefore return the same value itself.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If this method is called between the Action execution and the Result
|
||||
* execution, then the value set here will override the result code the
|
||||
* action had returned. Creating an Interceptor that implements
|
||||
* {@link PreResultListener} will give you this opportunity.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If this method is called after the Result has been executed, it will
|
||||
* have the effect of raising an IllegalStateException.
|
||||
* </p>
|
||||
*
|
||||
* @param resultCode the result code.
|
||||
* @throws IllegalStateException if called after the Result has been executed.
|
||||
* @see #isExecuted()
|
||||
*/
|
||||
void setResultCode(String resultCode);
|
||||
|
||||
/**
|
||||
* Gets the ValueStack associated with this ActionInvocation.
|
||||
*
|
||||
* @return the ValueStack
|
||||
*/
|
||||
@Override
|
||||
ValueStack getStack();
|
||||
|
||||
/**
|
||||
* Register a {@link PreResultListener} to be notified after the Action is executed and
|
||||
* before the Result is executed.
|
||||
*
|
||||
* <p>
|
||||
* The ActionInvocation implementation must guarantee that listeners will be called in
|
||||
* the order in which they are registered.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Listener registration and execution does not need to be thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @param listener the listener to add.
|
||||
*/
|
||||
@Override
|
||||
default void addPreResultListener(org.apache.struts2.interceptor.PreResultListener listener) {
|
||||
addPreResultListener(PreResultListener.adapt(listener));
|
||||
}
|
||||
|
||||
void addPreResultListener(PreResultListener listener);
|
||||
|
||||
/**
|
||||
* Invokes the next step in processing this ActionInvocation.
|
||||
*
|
||||
* <p>
|
||||
* If there are more Interceptors, this will call the next one. If Interceptors choose not to short-circuit
|
||||
* ActionInvocation processing and return their own return code, they will call invoke() to allow the next Interceptor
|
||||
* to execute. If there are no more Interceptors to be applied, the Action is executed.
|
||||
* If the {@link ActionProxy#getExecuteResult()} method returns <tt>true</tt>, the Result is also executed.
|
||||
* </p>
|
||||
*
|
||||
* @throws Exception can be thrown.
|
||||
* @return the return code.
|
||||
*/
|
||||
String invoke() throws Exception;
|
||||
@Override
|
||||
default void setActionEventListener(org.apache.struts2.ActionEventListener listener) {
|
||||
setActionEventListener(ActionEventListener.adapt(listener));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes only the Action (not Interceptors or Results).
|
||||
*
|
||||
* <p>
|
||||
* This is useful in rare situations where advanced usage with the interceptor/action/result workflow is
|
||||
* being manipulated for certain functionality.
|
||||
* </p>
|
||||
*
|
||||
* @return the return code.
|
||||
* @throws Exception can be thrown.
|
||||
*/
|
||||
String invokeActionOnly() throws Exception;
|
||||
|
||||
/**
|
||||
* Sets the action event listener to respond to key action events.
|
||||
*
|
||||
* @param listener the listener.
|
||||
*/
|
||||
void setActionEventListener(ActionEventListener listener);
|
||||
|
||||
void init(ActionProxy proxy) ;
|
||||
@Override
|
||||
default void init(org.apache.struts2.ActionProxy proxy) {
|
||||
init(ActionProxy.adapt(proxy));
|
||||
}
|
||||
|
||||
void init(ActionProxy proxy);
|
||||
|
||||
static ActionInvocation adapt(org.apache.struts2.ActionInvocation actualInvocation) {
|
||||
if (actualInvocation instanceof ActionInvocation) {
|
||||
return (ActionInvocation) actualInvocation;
|
||||
}
|
||||
return actualInvocation != null ? new LegacyAdapter(actualInvocation) : null;
|
||||
}
|
||||
|
||||
class LegacyAdapter implements ActionInvocation {
|
||||
|
||||
private final org.apache.struts2.ActionInvocation adaptee;
|
||||
|
||||
private LegacyAdapter(org.apache.struts2.ActionInvocation adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAction() {
|
||||
return adaptee.getAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExecuted() {
|
||||
return adaptee.isExecuted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionContext getInvocationContext() {
|
||||
return ActionContext.adapt(adaptee.getInvocationContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionProxy getProxy() {
|
||||
return ActionProxy.adapt(adaptee.getProxy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result getResult() throws Exception {
|
||||
return Result.adapt(adaptee.getResult());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResultCode() {
|
||||
return adaptee.getResultCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResultCode(String resultCode) {
|
||||
adaptee.setResultCode(resultCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueStack getStack() {
|
||||
return ValueStack.adapt(adaptee.getStack());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPreResultListener(PreResultListener listener) {
|
||||
adaptee.addPreResultListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String invoke() throws Exception {
|
||||
return adaptee.invoke();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String invokeActionOnly() throws Exception {
|
||||
return adaptee.invokeActionOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionEventListener(ActionEventListener listener) {
|
||||
adaptee.setActionEventListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(ActionProxy proxy) {
|
||||
adaptee.init(proxy);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,88 +20,75 @@ package com.opensymphony.xwork2;
|
||||
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
|
||||
/**
|
||||
* ActionProxy is an extra layer between XWork and the action so that different proxies are possible.
|
||||
*
|
||||
* <p>
|
||||
* An example of this would be a remote proxy, where the layer between XWork and the action might be RMI or SOAP.
|
||||
* </p>
|
||||
*
|
||||
* @author Jason Carreira
|
||||
*/
|
||||
public interface ActionProxy {
|
||||
@Deprecated
|
||||
public interface ActionProxy extends org.apache.struts2.ActionProxy {
|
||||
|
||||
/**
|
||||
* Gets the Action instance for this Proxy.
|
||||
*
|
||||
* @return the Action instance
|
||||
*/
|
||||
Object getAction();
|
||||
|
||||
/**
|
||||
* Gets the alias name this ActionProxy is mapped to.
|
||||
*
|
||||
* @return the alias name
|
||||
*/
|
||||
String getActionName();
|
||||
|
||||
/**
|
||||
* Gets the ActionConfig this ActionProxy is built from.
|
||||
*
|
||||
* @return the ActionConfig
|
||||
*/
|
||||
ActionConfig getConfig();
|
||||
|
||||
/**
|
||||
* Sets whether this ActionProxy should also execute the Result after executing the Action.
|
||||
*
|
||||
* @param executeResult <tt>true</tt> to also execute the Result.
|
||||
*/
|
||||
void setExecuteResult(boolean executeResult);
|
||||
|
||||
/**
|
||||
* Gets the status of whether the ActionProxy is set to execute the Result after the Action is executed.
|
||||
*
|
||||
* @return the status
|
||||
*/
|
||||
boolean getExecuteResult();
|
||||
|
||||
/**
|
||||
* Gets the ActionInvocation associated with this ActionProxy.
|
||||
*
|
||||
* @return the ActionInvocation
|
||||
*/
|
||||
@Override
|
||||
ActionInvocation getInvocation();
|
||||
|
||||
/**
|
||||
* Gets the namespace the ActionConfig for this ActionProxy is mapped to.
|
||||
*
|
||||
* @return the namespace
|
||||
*/
|
||||
String getNamespace();
|
||||
static ActionProxy adapt(org.apache.struts2.ActionProxy actualProxy) {
|
||||
if (actualProxy instanceof ActionProxy) {
|
||||
return (ActionProxy) actualProxy;
|
||||
}
|
||||
return actualProxy != null ? new LegacyAdapter(actualProxy) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute this ActionProxy. This will set the ActionContext from the ActionInvocation into the ActionContext
|
||||
* ThreadLocal before invoking the ActionInvocation, then set the old ActionContext back into the ThreadLocal.
|
||||
*
|
||||
* @return the result code returned from executing the ActionInvocation
|
||||
* @throws Exception can be thrown.
|
||||
* @see ActionInvocation
|
||||
*/
|
||||
String execute() throws Exception;
|
||||
class LegacyAdapter implements ActionProxy {
|
||||
|
||||
/**
|
||||
* Gets the method name to execute, or <tt>null</tt> if no method has been specified (meaning <code>execute</code> will be invoked).
|
||||
*
|
||||
* @return the method to execute
|
||||
*/
|
||||
String getMethod();
|
||||
private final org.apache.struts2.ActionProxy adaptee;
|
||||
|
||||
/**
|
||||
* Gets status of the method value's initialization.
|
||||
*
|
||||
* @return true if the method returned by getMethod() is not a default initializer value.
|
||||
*/
|
||||
boolean isMethodSpecified();
|
||||
|
||||
private LegacyAdapter(org.apache.struts2.ActionProxy adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAction() {
|
||||
return adaptee.getAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActionName() {
|
||||
return adaptee.getActionName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionConfig getConfig() {
|
||||
return adaptee.getConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExecuteResult(boolean executeResult) {
|
||||
adaptee.setExecuteResult(executeResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getExecuteResult() {
|
||||
return adaptee.getExecuteResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionInvocation getInvocation() {
|
||||
return ActionInvocation.adapt(adaptee.getInvocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
return adaptee.getNamespace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String execute() throws Exception {
|
||||
return adaptee.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod() {
|
||||
return adaptee.getMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMethodSpecified() {
|
||||
return adaptee.isMethodSpecified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,342 +18,11 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
import com.opensymphony.xwork2.conversion.impl.ConversionData;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Provides a default implementation for the most common actions.
|
||||
* See the documentation for all the interfaces this class implements for more detailed information.
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.ActionSupport} instead.
|
||||
*/
|
||||
public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ActionSupport.class);
|
||||
|
||||
private final ValidationAwareSupport validationAware = new ValidationAwareSupport();
|
||||
|
||||
private transient TextProvider textProvider;
|
||||
private transient LocaleProvider localeProvider;
|
||||
|
||||
protected Container container;
|
||||
|
||||
@Override
|
||||
public void setActionErrors(Collection<String> errorMessages) {
|
||||
validationAware.setActionErrors(errorMessages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getActionErrors() {
|
||||
return validationAware.getActionErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionMessages(Collection<String> messages) {
|
||||
validationAware.setActionMessages(messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getActionMessages() {
|
||||
return validationAware.getActionMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFieldErrors(Map<String, List<String>> errorMap) {
|
||||
validationAware.setFieldErrors(errorMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getFieldErrors() {
|
||||
return validationAware.getFieldErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return getLocaleProvider().getLocale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidLocaleString(String localeStr) {
|
||||
return getLocaleProvider().isValidLocaleString(localeStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidLocale(Locale locale) {
|
||||
return getLocaleProvider().isValidLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale toLocale(String localeStr) {
|
||||
return getLocaleProvider().toLocale(localeStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasKey(String key) {
|
||||
return getTextProvider().hasKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName) {
|
||||
return getTextProvider().getText(aTextName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, String defaultValue) {
|
||||
return getTextProvider().getText(aTextName, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, String defaultValue, String obj) {
|
||||
return getTextProvider().getText(aTextName, defaultValue, obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, List<?> args) {
|
||||
return getTextProvider().getText(aTextName, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String[] args) {
|
||||
return getTextProvider().getText(key, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, String defaultValue, List<?> args) {
|
||||
return getTextProvider().getText(aTextName, defaultValue, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String defaultValue, String[] args) {
|
||||
return getTextProvider().getText(key, defaultValue, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String defaultValue, List<?> args, ValueStack stack) {
|
||||
return getTextProvider().getText(key, defaultValue, args, stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String defaultValue, String[] args, ValueStack stack) {
|
||||
return getTextProvider().getText(key, defaultValue, args, stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dedicated method to support I10N and conversion errors
|
||||
*
|
||||
* @param key message which contains formatting string
|
||||
* @param expr that should be formatted
|
||||
* @return formatted expr with format specified by key
|
||||
*/
|
||||
public String getFormatted(String key, String expr) {
|
||||
Map<String, ConversionData> conversionErrors = ActionContext.getContext().getConversionErrors();
|
||||
if (conversionErrors.containsKey(expr)) {
|
||||
String[] vals = (String[]) conversionErrors.get(expr).getValue();
|
||||
return vals[0];
|
||||
} else {
|
||||
final ValueStack valueStack = ActionContext.getContext().getValueStack();
|
||||
final Object val = valueStack.findValue(expr);
|
||||
return getText(key, Arrays.asList(val));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceBundle getTexts() {
|
||||
return getTextProvider().getTexts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceBundle getTexts(String aBundleName) {
|
||||
return getTextProvider().getTexts(aBundleName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addActionError(String anErrorMessage) {
|
||||
validationAware.addActionError(anErrorMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addActionMessage(String aMessage) {
|
||||
validationAware.addActionMessage(aMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFieldError(String fieldName, String errorMessage) {
|
||||
validationAware.addFieldError(fieldName, errorMessage);
|
||||
}
|
||||
|
||||
public String input() throws Exception {
|
||||
return INPUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* A default implementation that does nothing an returns "success".
|
||||
*
|
||||
* <p>
|
||||
* Subclasses should override this method to provide their business logic.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* See also {@link com.opensymphony.xwork2.Action#execute()}.
|
||||
* </p>
|
||||
*
|
||||
* @return returns {@link #SUCCESS}
|
||||
* @throws Exception can be thrown by subclasses.
|
||||
*/
|
||||
@Override
|
||||
public String execute() throws Exception {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActionErrors() {
|
||||
return validationAware.hasActionErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActionMessages() {
|
||||
return validationAware.hasActionMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasErrors() {
|
||||
return validationAware.hasErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFieldErrors() {
|
||||
return validationAware.hasFieldErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears field errors. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearFieldErrors() {
|
||||
validationAware.clearFieldErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears action errors. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearActionErrors() {
|
||||
validationAware.clearActionErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears messages. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearMessages() {
|
||||
validationAware.clearMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all errors. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearErrors() {
|
||||
validationAware.clearErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all errors and messages. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearErrorsAndMessages() {
|
||||
validationAware.clearErrorsAndMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* A default implementation that validates nothing.
|
||||
* Subclasses should override this method to provide validations.
|
||||
*/
|
||||
@Override
|
||||
public void validate() {
|
||||
// A default implementation that validates nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: pause-method -->
|
||||
* Stops the action invocation immediately (by throwing a PauseException) and causes the action invocation to return
|
||||
* the specified result, such as {@link #SUCCESS}, {@link #INPUT}, etc.
|
||||
*
|
||||
* <p>
|
||||
* The next time this action is invoked (and using the same continuation ID), the method will resume immediately
|
||||
* after where this method was called, with the entire call stack in the execute method restored.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Note: this method can <b>only</b> be called within the {@link #execute()} method.
|
||||
* </p>
|
||||
*
|
||||
* <!-- END SNIPPET: pause-method -->
|
||||
*
|
||||
* @param result the result to return - the same type of return value in the {@link #execute()} method.
|
||||
*/
|
||||
public void pause(String result) {
|
||||
}
|
||||
|
||||
/**
|
||||
* If called first time it will create {@link com.opensymphony.xwork2.TextProviderFactory},
|
||||
* inject dependency (if {@link com.opensymphony.xwork2.inject.Container} is accesible) into in,
|
||||
* then will create new {@link com.opensymphony.xwork2.TextProvider} and store it in a field
|
||||
* for future references and at the returns reference to that field
|
||||
*
|
||||
* @return reference to field with TextProvider
|
||||
*/
|
||||
protected TextProvider getTextProvider() {
|
||||
if (textProvider == null) {
|
||||
final TextProviderFactory tpf = getContainer().getInstance(TextProviderFactory.class);
|
||||
textProvider = tpf.createInstance(getClass());
|
||||
}
|
||||
return textProvider;
|
||||
}
|
||||
|
||||
protected LocaleProvider getLocaleProvider() {
|
||||
if (localeProvider == null) {
|
||||
final LocaleProviderFactory localeProviderFactory = getContainer().getInstance(LocaleProviderFactory.class);
|
||||
localeProvider = localeProviderFactory.createLocaleProvider();
|
||||
}
|
||||
return localeProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: This a temporary solution, maybe we should consider stop injecting container into beans
|
||||
*/
|
||||
protected Container getContainer() {
|
||||
if (container == null) {
|
||||
container = ActionContext.getContext().getContainer();
|
||||
if (container != null) {
|
||||
boolean devMode = Boolean.parseBoolean(container.getInstance(String.class, StrutsConstants.STRUTS_DEVMODE));
|
||||
if (devMode) {
|
||||
LOG.warn("Container is null, action was created manually? Fallback to ActionContext");
|
||||
} else {
|
||||
LOG.debug("Container is null, action was created manually? Fallback to ActionContext");
|
||||
}
|
||||
} else {
|
||||
LOG.warn("Container is null, action was created out of ActionContext scope?!?");
|
||||
}
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setContainer(Container container) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public class ActionSupport extends org.apache.struts2.ActionSupport implements Action, Validateable, ValidationAware {
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import ognl.NoSuchPropertyException;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.result.ActionChainResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
@@ -248,12 +249,15 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
Interceptor interceptor = interceptorMapping.getInterceptor();
|
||||
if (interceptor instanceof WithLazyParams) {
|
||||
interceptor = lazyParamInjector.injectParams(interceptor, interceptorMapping.getParams(), invocationContext);
|
||||
} else if (interceptor instanceof Interceptor.LegacyAdapter && ((Interceptor.LegacyAdapter) interceptor).getAdaptee() instanceof WithLazyParams) {
|
||||
org.apache.struts2.interceptor.Interceptor adaptee = ((Interceptor.LegacyAdapter) interceptor).getAdaptee();
|
||||
lazyParamInjector.injectParams(adaptee, interceptorMapping.getParams(), invocationContext);
|
||||
}
|
||||
if (interceptor instanceof ConditionalInterceptor) {
|
||||
resultCode = executeConditional((ConditionalInterceptor) interceptor);
|
||||
} else {
|
||||
LOG.debug("Executing normal interceptor: {}", interceptorMapping.getName());
|
||||
resultCode = interceptor.intercept(this);
|
||||
resultCode = interceptor.intercept((org.apache.struts2.ActionInvocation) this);
|
||||
}
|
||||
} else {
|
||||
resultCode = invokeActionOnly();
|
||||
@@ -294,9 +298,9 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
}
|
||||
|
||||
protected String executeConditional(ConditionalInterceptor conditionalInterceptor) throws Exception {
|
||||
if (conditionalInterceptor.shouldIntercept(this)) {
|
||||
if (conditionalInterceptor.shouldIntercept((org.apache.struts2.ActionInvocation) this)) {
|
||||
LOG.debug("Executing conditional interceptor: {}", conditionalInterceptor.getClass().getSimpleName());
|
||||
return conditionalInterceptor.intercept(this);
|
||||
return conditionalInterceptor.intercept((org.apache.struts2.ActionInvocation) this);
|
||||
} else {
|
||||
LOG.debug("Interceptor: {} is disabled, skipping to next", conditionalInterceptor.getClass().getSimpleName());
|
||||
return this.invoke();
|
||||
@@ -374,7 +378,7 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
result = createResult();
|
||||
|
||||
if (result != null) {
|
||||
result.execute(this);
|
||||
result.execute((org.apache.struts2.ActionInvocation) 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());
|
||||
|
||||
@@ -19,18 +19,8 @@
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
/**
|
||||
* ModelDriven Actions provide a model object to be pushed onto the ValueStack
|
||||
* in addition to the Action itself, allowing a FormBean type approach like Struts.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.ModelDriven} instead.
|
||||
*/
|
||||
public interface ModelDriven<T> {
|
||||
|
||||
/**
|
||||
* Gets the model to be pushed onto the ValueStack instead of the Action itself.
|
||||
*
|
||||
* @return the model
|
||||
*/
|
||||
T getModel();
|
||||
|
||||
@Deprecated
|
||||
public interface ModelDriven<T> extends org.apache.struts2.ModelDriven<T> {
|
||||
}
|
||||
|
||||
@@ -19,19 +19,8 @@
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
/**
|
||||
* Preparable Actions will have their <code>prepare()</code> method called if the {@link com.opensymphony.xwork2.interceptor.PrepareInterceptor}
|
||||
* is applied to the ActionConfig.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @see com.opensymphony.xwork2.interceptor.PrepareInterceptor
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.Preparable} instead.
|
||||
*/
|
||||
public interface Preparable {
|
||||
|
||||
/**
|
||||
* This method is called to allow the action to prepare itself.
|
||||
*
|
||||
* @throws Exception thrown if a system level exception occurs.
|
||||
*/
|
||||
void prepare() throws Exception;
|
||||
|
||||
@Deprecated
|
||||
public interface Preparable extends org.apache.struts2.Preparable {
|
||||
}
|
||||
|
||||
@@ -18,33 +18,39 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* All results (except for <code>Action.NONE</code>) of an {@link Action} are mapped to a View implementation.
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* Examples of Views might be:
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>SwingPanelView - pops up a new Swing panel</li>
|
||||
* <li>ActionChainView - executes another action</li>
|
||||
* <li>SerlvetRedirectView - redirects the HTTP response to a URL</li>
|
||||
* <li>ServletDispatcherView - dispatches the HTTP response to a URL</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author plightbo
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.result.Result} instead.
|
||||
*/
|
||||
public interface Result extends Serializable {
|
||||
@Deprecated
|
||||
public interface Result extends org.apache.struts2.result.Result {
|
||||
|
||||
@Override
|
||||
default void execute(org.apache.struts2.ActionInvocation invocation) throws Exception {
|
||||
execute(ActionInvocation.adapt(invocation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a generic interface for all action execution results.
|
||||
* Whether that be displaying a webpage, generating an email, sending a JMS message, etc.
|
||||
*
|
||||
* @param invocation the invocation context.
|
||||
* @throws Exception can be thrown.
|
||||
*/
|
||||
void execute(ActionInvocation invocation) throws Exception;
|
||||
|
||||
static Result adapt(org.apache.struts2.result.Result actualResult) {
|
||||
if (actualResult instanceof Result) {
|
||||
return (Result) actualResult;
|
||||
}
|
||||
return actualResult != null ? new LegacyAdapter(actualResult) : null;
|
||||
}
|
||||
|
||||
class LegacyAdapter implements Result {
|
||||
|
||||
private final org.apache.struts2.result.Result adaptee;
|
||||
|
||||
private LegacyAdapter(org.apache.struts2.result.Result adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(ActionInvocation invocation) throws Exception {
|
||||
adaptee.execute(ActionInvocation.adapt(invocation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,8 @@
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
/**
|
||||
* Simple marker interface to indicate an object should <b>not</b> have its properties copied during chaining.
|
||||
*
|
||||
* @see com.opensymphony.xwork2.interceptor.ChainingInterceptor
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.Unchainable} instead.
|
||||
*/
|
||||
public interface Unchainable {
|
||||
@Deprecated
|
||||
public interface Unchainable extends org.apache.struts2.Unchainable {
|
||||
}
|
||||
|
||||
@@ -19,17 +19,8 @@
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
/**
|
||||
* Provides an interface in which a call for a validation check can be done.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @see ActionSupport
|
||||
* @see com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.Validateable} instead.
|
||||
*/
|
||||
public interface Validateable {
|
||||
|
||||
/**
|
||||
* Performs validation.
|
||||
*/
|
||||
void validate();
|
||||
|
||||
@Deprecated
|
||||
public interface Validateable extends org.apache.struts2.Validateable {
|
||||
}
|
||||
|
||||
@@ -36,8 +36,16 @@ public class InterceptorMapping implements Serializable {
|
||||
private Interceptor interceptor;
|
||||
private final Map<String, String> params;
|
||||
|
||||
public InterceptorMapping(String name, org.apache.struts2.interceptor.Interceptor interceptor) {
|
||||
this(name, Interceptor.adapt(interceptor));
|
||||
}
|
||||
|
||||
public InterceptorMapping(String name, org.apache.struts2.interceptor.Interceptor interceptor, Map<String, String> params) {
|
||||
this(name, Interceptor.adapt(interceptor), params);
|
||||
}
|
||||
|
||||
public InterceptorMapping(String name, Interceptor interceptor) {
|
||||
this(name, interceptor, new HashMap<String, String>());
|
||||
this(name, interceptor, new HashMap<>());
|
||||
}
|
||||
|
||||
public InterceptorMapping(String name, Interceptor interceptor, Map<String, String> params) {
|
||||
|
||||
@@ -38,7 +38,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class ResultConfig extends Located implements Serializable {
|
||||
|
||||
protected Map<String,String> params;
|
||||
protected Map<String, String> params;
|
||||
protected String className;
|
||||
protected String name;
|
||||
|
||||
@@ -63,7 +63,7 @@ public class ResultConfig extends Located implements Serializable {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Map<String,String> getParams() {
|
||||
public Map<String, String> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ public class ResultConfig extends Located implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addParams(Map<String,String> params) {
|
||||
public Builder addParams(Map<String, String> params) {
|
||||
target.params.putAll(params);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ import com.opensymphony.xwork2.factory.ActionFactory;
|
||||
import com.opensymphony.xwork2.factory.ConverterFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultActionFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultInterceptorFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultResultFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultUnknownHandlerFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultValidatorFactory;
|
||||
import com.opensymphony.xwork2.factory.InterceptorFactory;
|
||||
@@ -109,6 +108,7 @@ 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.factory.StrutsResultFactory;
|
||||
import org.apache.struts2.ognl.OgnlGuard;
|
||||
import org.apache.struts2.ognl.ProviderAllowlist;
|
||||
import org.apache.struts2.ognl.StrutsOgnlGuard;
|
||||
@@ -363,7 +363,7 @@ public class DefaultConfiguration implements Configuration {
|
||||
// TODO: SpringObjectFactoryTest fails when these are SINGLETON
|
||||
.factory(ObjectFactory.class, Scope.PROTOTYPE)
|
||||
.factory(ActionFactory.class, DefaultActionFactory.class, Scope.PROTOTYPE)
|
||||
.factory(ResultFactory.class, DefaultResultFactory.class, Scope.PROTOTYPE)
|
||||
.factory(ResultFactory.class, StrutsResultFactory.class, Scope.PROTOTYPE)
|
||||
.factory(InterceptorFactory.class, DefaultInterceptorFactory.class, Scope.PROTOTYPE)
|
||||
.factory(ValidatorFactory.class, DefaultValidatorFactory.class, Scope.PROTOTYPE)
|
||||
.factory(ConverterFactory.class, StrutsConverterFactory.class, Scope.PROTOTYPE)
|
||||
|
||||
@@ -70,13 +70,18 @@ public class DefaultInterceptorFactory implements InterceptorFactory {
|
||||
reflectionProvider.setProperties(params, o);
|
||||
}
|
||||
|
||||
Interceptor interceptor = null;
|
||||
if (o instanceof Interceptor) {
|
||||
Interceptor interceptor = (Interceptor) o;
|
||||
interceptor.init();
|
||||
return interceptor;
|
||||
interceptor = (Interceptor) o;
|
||||
} else if (o instanceof org.apache.struts2.interceptor.Interceptor) {
|
||||
interceptor = Interceptor.adapt((org.apache.struts2.interceptor.Interceptor) o);
|
||||
}
|
||||
|
||||
throw new ConfigurationException("Class [" + interceptorClassName + "] does not implement Interceptor", interceptorConfig);
|
||||
if (interceptor == null) {
|
||||
throw new ConfigurationException("Class [" + interceptorClassName + "] does not implement Interceptor", interceptorConfig);
|
||||
}
|
||||
interceptor.init();
|
||||
return interceptor;
|
||||
} catch (InstantiationException e) {
|
||||
cause = e;
|
||||
message = "Unable to instantiate an instance of Interceptor class [" + interceptorClassName + "].";
|
||||
|
||||
@@ -20,17 +20,22 @@ package com.opensymphony.xwork2.factory;
|
||||
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.Result;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionException;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionExceptionHandler;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
import org.apache.struts2.factory.StrutsResultFactory;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Default implementation
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link StrutsResultFactory} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class DefaultResultFactory implements ResultFactory {
|
||||
|
||||
private ObjectFactory objectFactory;
|
||||
@@ -51,19 +56,29 @@ public class DefaultResultFactory implements ResultFactory {
|
||||
Result result = null;
|
||||
|
||||
if (resultClassName != null) {
|
||||
result = (Result) objectFactory.buildBean(resultClassName, extraContext);
|
||||
Object o = objectFactory.buildBean(resultClassName, extraContext);
|
||||
|
||||
Map<String, String> params = resultConfig.getParams();
|
||||
if (params != null) {
|
||||
for (Map.Entry<String, String> paramEntry : params.entrySet()) {
|
||||
try {
|
||||
reflectionProvider.setProperty(paramEntry.getKey(), paramEntry.getValue(), result, extraContext, true);
|
||||
reflectionProvider.setProperty(paramEntry.getKey(), paramEntry.getValue(), o, extraContext, true);
|
||||
} catch (ReflectionException ex) {
|
||||
if (result instanceof ReflectionExceptionHandler) {
|
||||
((ReflectionExceptionHandler) result).handle(ex);
|
||||
if (o instanceof ReflectionExceptionHandler) {
|
||||
((ReflectionExceptionHandler) o).handle(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (o instanceof Result) {
|
||||
result = (Result) o;
|
||||
} else if (o instanceof org.apache.struts2.result.Result) {
|
||||
result = Result.adapt((org.apache.struts2.result.Result) o);
|
||||
}
|
||||
if (result == null) {
|
||||
throw new ConfigurationException("Class [" + resultClassName + "] does not implement Result", resultConfig);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -242,6 +242,41 @@ class ContainerImpl implements Container {
|
||||
return toArray(parameterInjectors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets parameter injectors with nulls for optional dependencies.
|
||||
*
|
||||
* @param member to which the parameters belong
|
||||
* @param annotations on the parameters
|
||||
* @param parameterTypes parameter types
|
||||
* @return injections
|
||||
*/
|
||||
<M extends AccessibleObject & Member> ParameterInjector<?>[] getParametersInjectorsWithNulls(
|
||||
M member,
|
||||
Annotation[][] annotations,
|
||||
Class<?>[] parameterTypes,
|
||||
String defaultName
|
||||
) throws MissingDependencyException {
|
||||
final List<ParameterInjector<?>> parameterInjectors = new ArrayList<>();
|
||||
|
||||
final Iterator<Annotation[]> annotationsIterator = Arrays.asList(annotations).iterator();
|
||||
for (Class<?> parameterType : parameterTypes) {
|
||||
Inject annotation = findInject(annotationsIterator.next());
|
||||
String name = annotation == null ? defaultName : annotation.value();
|
||||
Key<?> key = Key.newInstance(parameterType, name);
|
||||
try {
|
||||
parameterInjectors.add(createParameterInjector(key, member));
|
||||
} catch (MissingDependencyException e) {
|
||||
if (annotation != null && annotation.required()) {
|
||||
throw e;
|
||||
} else {
|
||||
parameterInjectors.add(createNullParameterInjector(key, member));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return toArray(parameterInjectors);
|
||||
}
|
||||
|
||||
<T> ParameterInjector<T> createParameterInjector(Key<T> key, Member member) throws MissingDependencyException {
|
||||
final InternalFactory<? extends T> factory = getFactory(key);
|
||||
if (factory == null) {
|
||||
@@ -252,6 +287,23 @@ class ContainerImpl implements Container {
|
||||
return new ParameterInjector<>(externalContext, factory);
|
||||
}
|
||||
|
||||
<T> ParameterInjector<T> createNullParameterInjector(Key<T> key, Member member) throws MissingDependencyException {
|
||||
final InternalFactory<? extends T> factory = new InternalFactory<T>() {
|
||||
@Override
|
||||
public T create(InternalContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends T> type() {
|
||||
return key.getType();
|
||||
}
|
||||
};
|
||||
|
||||
final ExternalContext<T> externalContext = ExternalContext.newInstance(member, key, this);
|
||||
return new ParameterInjector<>(externalContext, factory);
|
||||
}
|
||||
|
||||
private ParameterInjector<?>[] toArray(List<ParameterInjector<?>> parameterInjections) {
|
||||
return parameterInjections.toArray(new ParameterInjector[0]);
|
||||
}
|
||||
@@ -361,7 +413,7 @@ class ContainerImpl implements Container {
|
||||
Inject inject, ContainerImpl container, Constructor<T> constructor) throws MissingDependencyException {
|
||||
return constructor.getParameterTypes().length == 0
|
||||
? null // default constructor.
|
||||
: container.getParametersInjectors(
|
||||
: container.getParametersInjectorsWithNulls(
|
||||
constructor,
|
||||
constructor.getParameterAnnotations(),
|
||||
constructor.getParameterTypes(),
|
||||
|
||||
@@ -21,41 +21,28 @@ package com.opensymphony.xwork2.interceptor;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
|
||||
/**
|
||||
* Provides default implementations of optional lifecycle methods
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.AbstractInterceptor} instead.
|
||||
*/
|
||||
public abstract class AbstractInterceptor implements ConditionalInterceptor {
|
||||
|
||||
private boolean disabled;
|
||||
|
||||
/**
|
||||
* Does nothing
|
||||
*/
|
||||
public void init() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing
|
||||
*/
|
||||
public void destroy() {
|
||||
}
|
||||
@Deprecated
|
||||
public abstract class AbstractInterceptor extends org.apache.struts2.interceptor.AbstractInterceptor implements ConditionalInterceptor {
|
||||
|
||||
/**
|
||||
* 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 String intercept(org.apache.struts2.ActionInvocation invocation) throws Exception {
|
||||
return intercept(ActionInvocation.adapt(invocation));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldIntercept(ActionInvocation invocation) {
|
||||
return !this.disabled;
|
||||
return super.shouldIntercept(invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldIntercept(org.apache.struts2.ActionInvocation invocation) {
|
||||
return shouldIntercept(ActionInvocation.adapt(invocation));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,21 +20,22 @@ package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.ClearableValueStack;
|
||||
import com.opensymphony.xwork2.util.Evaluated;
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -90,7 +91,10 @@ import java.util.Map;
|
||||
* </pre>
|
||||
*
|
||||
* @author Matthew Payne
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.AliasInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class AliasInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(AliasInterceptor.class);
|
||||
@@ -108,7 +112,7 @@ public class AliasInterceptor extends AbstractInterceptor {
|
||||
@Inject(StrutsConstants.STRUTS_DEVMODE)
|
||||
public void setDevMode(String mode) {
|
||||
this.devMode = Boolean.parseBoolean(mode);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setValueStackFactory(ValueStackFactory valueStackFactory) {
|
||||
@@ -225,7 +229,7 @@ public class AliasInterceptor extends AbstractInterceptor {
|
||||
LOG.debug("invalid alias expression: {}", aliasesKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,21 +18,26 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionChainResult;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.Result;
|
||||
import com.opensymphony.xwork2.Unchainable;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.ProxyUtil;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.ProxyUtil;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.Unchainable;
|
||||
import org.apache.struts2.result.ActionChainResult;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
@@ -112,8 +117,11 @@ import java.util.*;
|
||||
*
|
||||
* @author mrdon
|
||||
* @author tm_jee ( tm_jee(at)yahoo.co.uk )
|
||||
* @see com.opensymphony.xwork2.ActionChainResult
|
||||
* @see ActionChainResult
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ChainingInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ChainingInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ChainingInterceptor.class);
|
||||
|
||||
+31
-11
@@ -21,19 +21,39 @@ 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.
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @since Struts 6.1.1
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.Interceptor} instead.
|
||||
*/
|
||||
public interface ConditionalInterceptor extends Interceptor {
|
||||
@Deprecated
|
||||
public interface ConditionalInterceptor extends org.apache.struts2.interceptor.ConditionalInterceptor, Interceptor {
|
||||
|
||||
@Override
|
||||
default boolean shouldIntercept(org.apache.struts2.ActionInvocation invocation) {
|
||||
return shouldIntercept(ActionInvocation.adapt(invocation));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
static ConditionalInterceptor adapt(org.apache.struts2.interceptor.ConditionalInterceptor actualInterceptor) {
|
||||
if (actualInterceptor instanceof ConditionalInterceptor) {
|
||||
return (ConditionalInterceptor) actualInterceptor;
|
||||
}
|
||||
return actualInterceptor != null ? new LegacyAdapter(actualInterceptor) : null;
|
||||
}
|
||||
|
||||
class LegacyAdapter extends Interceptor.LegacyAdapter implements ConditionalInterceptor {
|
||||
|
||||
private final org.apache.struts2.interceptor.ConditionalInterceptor adaptee;
|
||||
|
||||
private LegacyAdapter(org.apache.struts2.interceptor.ConditionalInterceptor adaptee) {
|
||||
super(adaptee);
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldIntercept(ActionInvocation invocation) {
|
||||
return adaptee.shouldIntercept(invocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -24,6 +24,7 @@ import com.opensymphony.xwork2.conversion.impl.ConversionData;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -41,13 +42,13 @@ import java.util.Map;
|
||||
* display the original string ("abc") again rather than the int value (likely 0, which would make very little sense to
|
||||
* the user).
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> Since 2.5.2, this interceptor extends {@link MethodFilterInterceptor}, therefore being
|
||||
* able to deal with excludeMethods / includeMethods parameters. See [Workflow Interceptor]
|
||||
* (class {@link DefaultWorkflowInterceptor}) for documentation and examples on how to use this feature.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <p><u>Interceptor parameters:</u></p>
|
||||
@@ -84,7 +85,10 @@ import java.util.Map;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jason Carreira
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ConversionErrorInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ConversionErrorInterceptor extends MethodFilterInterceptor {
|
||||
|
||||
public static final String ORIGINAL_PROPERTY_OVERRIDE = "original.property.override";
|
||||
|
||||
+7
-1
@@ -25,11 +25,14 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.reflect.MethodUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
import org.apache.struts2.interceptor.ValidationErrorAware;
|
||||
import org.apache.struts2.interceptor.ValidationWorkflowAware;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
* <p>
|
||||
* An interceptor that makes sure there are not validation, conversion or action errors before allowing the interceptor chain to continue.
|
||||
* An interceptor that makes sure there are not validation, conversion or action errors before allowing the interceptor chain to continue.
|
||||
* If a single FieldError or ActionError (including the ones replicated by the Message Store Interceptor in a redirection) is found, the INPUT result will be triggered.
|
||||
* <b>This interceptor does not perform any validation</b>.
|
||||
* </p>
|
||||
@@ -129,7 +132,10 @@ import org.apache.logging.log4j.Logger;
|
||||
* @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
|
||||
* @author Philip Luppens
|
||||
* @author tm_jee
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.DefaultWorkflowInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class DefaultWorkflowInterceptor extends MethodFilterInterceptor {
|
||||
|
||||
private static final long serialVersionUID = 7563014655616490865L;
|
||||
|
||||
+4
-1
@@ -20,8 +20,8 @@ package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.config.entities.ExceptionMappingConfig;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
|
||||
import java.util.List;
|
||||
@@ -153,7 +153,10 @@ import java.util.Map;
|
||||
*
|
||||
* @author Matthew E. Porter (matthew dot porter at metissian dot com)
|
||||
* @author Claus Ibsen
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ExceptionMappingInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ExceptionMappingInterceptor.class);
|
||||
|
||||
@@ -20,203 +20,56 @@ package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: introduction -->
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>
|
||||
* An interceptor is a stateless class that follows the interceptor pattern, as
|
||||
* found in {@link javax.servlet.Filter} and in AOP languages.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Interceptors are objects that dynamically intercept Action invocations.
|
||||
* They provide the developer with the opportunity to define code that can be executed
|
||||
* before and/or after the execution of an action. They also have the ability
|
||||
* to prevent an action from executing. Interceptors provide developers a way to
|
||||
* encapsulate common functionality in a re-usable form that can be applied to
|
||||
* one or more Actions.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Interceptors <b>must</b> be stateless and not assume that a new instance will be created for each request or Action.
|
||||
* Interceptors may choose to either short-circuit the {@link ActionInvocation} execution and return a return code
|
||||
* (such as {@link com.opensymphony.xwork2.Action#SUCCESS}), or it may choose to do some processing before
|
||||
* and/or after delegating the rest of the procesing using {@link ActionInvocation#invoke()}.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: introduction -->
|
||||
*
|
||||
* <!-- START SNIPPET: parameterOverriding -->
|
||||
* <p>
|
||||
* Interceptor's parameter could be overridden through the following ways :-
|
||||
* </p>
|
||||
|
||||
* <b>Method 1:</b>
|
||||
* <pre>
|
||||
* <action name="myAction" class="myActionClass">
|
||||
* <interceptor-ref name="exception"/>
|
||||
* <interceptor-ref name="alias"/>
|
||||
* <interceptor-ref name="params"/>
|
||||
* <interceptor-ref name="servletConfig"/>
|
||||
* <interceptor-ref name="prepare"/>
|
||||
* <interceptor-ref name="i18n"/>
|
||||
* <interceptor-ref name="chain"/>
|
||||
* <interceptor-ref name="modelDriven"/>
|
||||
* <interceptor-ref name="fileUpload"/>
|
||||
* <interceptor-ref name="staticParams"/>
|
||||
* <interceptor-ref name="params"/>
|
||||
* <interceptor-ref name="conversionError"/>
|
||||
* <interceptor-ref name="validation">
|
||||
* <param name="excludeMethods">myValidationExcudeMethod</param>
|
||||
* </interceptor-ref>
|
||||
* <interceptor-ref name="workflow">
|
||||
* <param name="excludeMethods">myWorkflowExcludeMethod</param>
|
||||
* </interceptor-ref>
|
||||
* </action>
|
||||
* </pre>
|
||||
*
|
||||
* <b>Method 2:</b>
|
||||
* <pre>
|
||||
* <action name="myAction" class="myActionClass">
|
||||
* <interceptor-ref name="defaultStack">
|
||||
* <param name="validation.excludeMethods">myValidationExcludeMethod</param>
|
||||
* <param name="workflow.excludeMethods">myWorkflowExcludeMethod</param>
|
||||
* </interceptor-ref>
|
||||
* </action>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* In the first method, the whole default stack is copied and the parameter then
|
||||
* changed accordingly.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* In the second method, the 'interceptor-ref' refer to an existing
|
||||
* interceptor-stack, namely defaultStack in this example, and override the validator
|
||||
* and workflow interceptor excludeMethods typically in this case. Note that in the
|
||||
* 'param' tag, the name attribute contains a dot (.) the word before the dot(.)
|
||||
* specifies the interceptor name whose parameter is to be overridden and the word after
|
||||
* the dot (.) specifies the parameter itself. Essetially it is as follows :-
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <interceptor-name>.<parameter-name>
|
||||
* </pre>
|
||||
* <p>
|
||||
* <b>Note</b> also that in this case the 'interceptor-ref' name attribute
|
||||
* is used to indicate an interceptor stack which makes sense as if it is referring
|
||||
* to the interceptor itself it would be just using Method 1 describe above.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: parameterOverriding -->
|
||||
*
|
||||
* <p>
|
||||
* <b>Nested Interceptor param overriding</b>
|
||||
* </p>
|
||||
*
|
||||
* <!-- START SNIPPET: nestedParameterOverriding -->
|
||||
* <p>
|
||||
* Interceptor stack parameter overriding could be nested into as many level as possible, though it would
|
||||
* be advisable not to nest it too deep as to avoid confusion, For example,
|
||||
* </p>
|
||||
* <pre>
|
||||
* <interceptor name="interceptor1" class="foo.bar.Interceptor1" />
|
||||
* <interceptor name="interceptor2" class="foo.bar.Interceptor2" />
|
||||
* <interceptor name="interceptor3" class="foo.bar.Interceptor3" />
|
||||
* <interceptor name="interceptor4" class="foo.bar.Interceptor4" />
|
||||
* <interceptor-stack name="stack1">
|
||||
* <interceptor-ref name="interceptor1" />
|
||||
* </interceptor-stack>
|
||||
* <interceptor-stack name="stack2">
|
||||
* <interceptor-ref name="intercetor2" />
|
||||
* <interceptor-ref name="stack1" />
|
||||
* </interceptor-stack>
|
||||
* <interceptor-stack name="stack3">
|
||||
* <interceptor-ref name="interceptor3" />
|
||||
* <interceptor-ref name="stack2" />
|
||||
* </interceptor-stack>
|
||||
* <interceptor-stack name="stack4">
|
||||
* <interceptor-ref name="interceptor4" />
|
||||
* <interceptor-ref name="stack3" />
|
||||
* </interceptor-stack>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Assuming the interceptor has the following properties
|
||||
* </p>
|
||||
*
|
||||
* <table border="1" summary="">
|
||||
* <tr>
|
||||
* <td>Interceptor</td>
|
||||
* <td>property</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Interceptor1</td>
|
||||
* <td>param1</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Interceptor2</td>
|
||||
* <td>param2</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Interceptor3</td>
|
||||
* <td>param3</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Interceptor4</td>
|
||||
* <td>param4</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* <p>
|
||||
* We could override them as follows :
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <action ... >
|
||||
* <!-- to override parameters of interceptor located directly in the stack -->
|
||||
* <interceptor-ref name="stack4">
|
||||
* <param name="interceptor4.param4"> ... </param>
|
||||
* </interceptor-ref>
|
||||
* </action>
|
||||
*
|
||||
* <action ... >
|
||||
* <!-- to override parameters of interceptor located under nested stack -->
|
||||
* <interceptor-ref name="stack4">
|
||||
* <param name="stack3.interceptor3.param3"> ... </param>
|
||||
* <param name="stack3.stack2.interceptor2.param2"> ... </param>
|
||||
* <param name="stack3.stack2.stack1.interceptor1.param1"> ... </param>
|
||||
* </interceptor-ref>
|
||||
* </action>
|
||||
* </pre>
|
||||
*
|
||||
* <!-- END SNIPPET: nestedParameterOverriding -->
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @author tmjee
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.Interceptor} instead.
|
||||
*/
|
||||
public interface Interceptor extends Serializable {
|
||||
@Deprecated
|
||||
public interface Interceptor extends org.apache.struts2.interceptor.Interceptor {
|
||||
|
||||
/**
|
||||
* Called to let an interceptor clean up any resources it has allocated.
|
||||
*/
|
||||
void destroy();
|
||||
@Override
|
||||
default String intercept(org.apache.struts2.ActionInvocation invocation) throws Exception {
|
||||
return intercept(ActionInvocation.adapt(invocation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after an interceptor is created, but before any requests are processed using
|
||||
* {@link #intercept(com.opensymphony.xwork2.ActionInvocation) intercept} , giving
|
||||
* the Interceptor a chance to initialize any needed resources.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the
|
||||
* request by the {@link ActionInvocation} or to short-circuit the processing and just return a String return code.
|
||||
*
|
||||
* @param invocation the action invocation
|
||||
* @return the return code, either returned from {@link ActionInvocation#invoke()}, or from the interceptor itself.
|
||||
* @throws Exception any system-level error, as defined in {@link com.opensymphony.xwork2.Action#execute()}.
|
||||
*/
|
||||
String intercept(ActionInvocation invocation) throws Exception;
|
||||
|
||||
static Interceptor adapt(org.apache.struts2.interceptor.Interceptor actualInterceptor) {
|
||||
if (actualInterceptor instanceof org.apache.struts2.interceptor.ConditionalInterceptor) {
|
||||
return ConditionalInterceptor.adapt((org.apache.struts2.interceptor.ConditionalInterceptor) actualInterceptor);
|
||||
}
|
||||
if (actualInterceptor instanceof Interceptor) {
|
||||
return (Interceptor) actualInterceptor;
|
||||
}
|
||||
return actualInterceptor != null ? new LegacyAdapter(actualInterceptor) : null;
|
||||
}
|
||||
|
||||
class LegacyAdapter implements Interceptor {
|
||||
|
||||
private final org.apache.struts2.interceptor.Interceptor adaptee;
|
||||
|
||||
protected LegacyAdapter(org.apache.struts2.interceptor.Interceptor adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
public org.apache.struts2.interceptor.Interceptor getAdaptee() {
|
||||
return adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
return adaptee.intercept(invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
adaptee.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
adaptee.init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,10 @@ import org.apache.logging.log4j.Logger;
|
||||
* </pre>
|
||||
*
|
||||
* @author Jason Carreira
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.LoggingInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class LoggingInterceptor extends AbstractInterceptor {
|
||||
private static final Logger LOG = LogManager.getLogger(LoggingInterceptor.class);
|
||||
private static final String FINISH_MESSAGE = "Finishing execution stack for action ";
|
||||
|
||||
+24
-21
@@ -31,56 +31,59 @@ import java.util.Set;
|
||||
*
|
||||
* <p>
|
||||
* MethodFilterInterceptor is an abstract <code>Interceptor</code> used as
|
||||
* a base class for interceptors that will filter execution based on method
|
||||
* a base class for interceptors that will filter execution based on method
|
||||
* names according to specified included/excluded method lists.
|
||||
*
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* Settable parameters are as follows:
|
||||
*
|
||||
*
|
||||
* <ul>
|
||||
* <li>excludeMethods - method names to be excluded from interceptor processing</li>
|
||||
* <li>includeMethods - method names to be included in interceptor processing</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* <b>NOTE:</b> If method name are available in both includeMethods and
|
||||
* excludeMethods, it will be considered as an included method:
|
||||
*
|
||||
* <b>NOTE:</b> If method name are available in both includeMethods and
|
||||
* excludeMethods, it will be considered as an included method:
|
||||
* includeMethods takes precedence over excludeMethods.
|
||||
*
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* Interceptors that extends this capability include:
|
||||
*
|
||||
*
|
||||
* <ul>
|
||||
* <li>TokenInterceptor</li>
|
||||
* <li>TokenSessionStoreInterceptor</li>
|
||||
* <li>DefaultWorkflowInterceptor</li>
|
||||
* <li>ValidationInterceptor</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* <!-- END SNIPPET: javadoc -->
|
||||
*
|
||||
*
|
||||
* @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
|
||||
* @author Rainer Hermanns
|
||||
*
|
||||
*
|
||||
* @see org.apache.struts2.interceptor.TokenInterceptor
|
||||
* @see org.apache.struts2.interceptor.TokenSessionStoreInterceptor
|
||||
* @see com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor
|
||||
* @see com.opensymphony.xwork2.validator.ValidationInterceptor
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.MethodFilterInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class MethodFilterInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(MethodFilterInterceptor.class);
|
||||
|
||||
|
||||
protected Set<String> excludeMethods = Collections.emptySet();
|
||||
protected Set<String> includeMethods = Collections.emptySet();
|
||||
|
||||
public void setExcludeMethods(String excludeMethods) {
|
||||
this.excludeMethods = TextParseUtil.commaDelimitedStringToSet(excludeMethods);
|
||||
}
|
||||
|
||||
|
||||
public Set<String> getExcludeMethodsSet() {
|
||||
return excludeMethods;
|
||||
}
|
||||
@@ -88,7 +91,7 @@ public abstract class MethodFilterInterceptor extends AbstractInterceptor {
|
||||
public void setIncludeMethods(String includeMethods) {
|
||||
this.includeMethods = TextParseUtil.commaDelimitedStringToSet(includeMethods);
|
||||
}
|
||||
|
||||
|
||||
public Set<String> getIncludeMethodsSet() {
|
||||
return includeMethods;
|
||||
}
|
||||
@@ -97,7 +100,7 @@ public abstract class MethodFilterInterceptor extends AbstractInterceptor {
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
if (applyInterceptor(invocation)) {
|
||||
return doIntercept(invocation);
|
||||
}
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
@@ -110,14 +113,14 @@ public abstract class MethodFilterInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
return applyMethod;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subclasses must override to implement the interceptor logic.
|
||||
*
|
||||
*
|
||||
* @param invocation the action invocation
|
||||
* @return the result of invocation
|
||||
* @throws Exception in case of any errors
|
||||
*/
|
||||
protected abstract String doIntercept(ActionInvocation invocation) throws Exception;
|
||||
|
||||
|
||||
}
|
||||
|
||||
+3
-125
@@ -18,131 +18,9 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.WildcardHelper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utility class contains common methods used by
|
||||
* {@link com.opensymphony.xwork2.interceptor.MethodFilterInterceptor}.
|
||||
*
|
||||
* @author tm_jee
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.MethodFilterInterceptorUtil} instead.
|
||||
*/
|
||||
public class MethodFilterInterceptorUtil {
|
||||
|
||||
/**
|
||||
* Static method to decide if the specified <code>method</code> should be
|
||||
* apply (not filtered) depending on the set of <code>excludeMethods</code> and
|
||||
* <code>includeMethods</code>.
|
||||
*
|
||||
* <ul>
|
||||
* <li>
|
||||
* <code>includeMethods</code> takes precedence over <code>excludeMethods</code>
|
||||
* </li>
|
||||
* </ul>
|
||||
* <b>Note:</b> Supports wildcard listings in includeMethods/excludeMethods
|
||||
*
|
||||
* @param excludeMethods list of methods to exclude.
|
||||
* @param includeMethods list of methods to include.
|
||||
* @param method the specified method to check
|
||||
* @return <tt>true</tt> if the method should be applied.
|
||||
*/
|
||||
public static boolean applyMethod(Set<String> excludeMethods, Set<String> includeMethods, String method) {
|
||||
|
||||
// quick check to see if any actual pattern matching is needed
|
||||
boolean needsPatternMatch = false;
|
||||
for (String includeMethod : includeMethods) {
|
||||
if (!"*".equals(includeMethod) && includeMethod.contains("*")) {
|
||||
needsPatternMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (String excludeMethod : excludeMethods) {
|
||||
if (!"*".equals(excludeMethod) && excludeMethod.contains("*")) {
|
||||
needsPatternMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// this section will try to honor the original logic, while
|
||||
// still allowing for wildcards later
|
||||
if (!needsPatternMatch && (includeMethods.contains("*") || includeMethods.size() == 0) ) {
|
||||
if (excludeMethods != null
|
||||
&& excludeMethods.contains(method)
|
||||
&& !includeMethods.contains(method) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// test the methods using pattern matching
|
||||
WildcardHelper wildcard = new WildcardHelper();
|
||||
String methodCopy ;
|
||||
if (method == null ) { // no method specified
|
||||
methodCopy = "";
|
||||
}
|
||||
else {
|
||||
methodCopy = new String(method);
|
||||
}
|
||||
for (String pattern : includeMethods) {
|
||||
if (pattern.contains("*")) {
|
||||
int[] compiledPattern = wildcard.compilePattern(pattern);
|
||||
HashMap<String, String> matchedPatterns = new HashMap<>();
|
||||
boolean matches = wildcard.match(matchedPatterns, methodCopy, compiledPattern);
|
||||
if (matches) {
|
||||
return true; // run it, includeMethods takes precedence
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (pattern.equals(methodCopy)) {
|
||||
return true; // run it, includeMethods takes precedence
|
||||
}
|
||||
}
|
||||
}
|
||||
if (excludeMethods.contains("*") ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// CHECK ME: Previous implementation used include method
|
||||
for ( String pattern : excludeMethods) {
|
||||
if (pattern.contains("*")) {
|
||||
int[] compiledPattern = wildcard.compilePattern(pattern);
|
||||
HashMap<String, String> matchedPatterns = new HashMap<>();
|
||||
boolean matches = wildcard.match(matchedPatterns, methodCopy, compiledPattern);
|
||||
if (matches) {
|
||||
// if found, and wasn't included earlier, don't run it
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (pattern.equals(methodCopy)) {
|
||||
// if found, and wasn't included earlier, don't run it
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// default fall-back from before changes
|
||||
return includeMethods.size() == 0 || includeMethods.contains(method) || includeMethods.contains("*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #applyMethod(Set, Set, String)}, except that <code>excludeMethods</code>
|
||||
* and <code>includeMethods</code> are supplied as comma separated string.
|
||||
*
|
||||
* @param excludeMethods comma seperated string of methods to exclude.
|
||||
* @param includeMethods comma seperated string of methods to include.
|
||||
* @param method the specified method to check
|
||||
* @return <tt>true</tt> if the method should be applied.
|
||||
*/
|
||||
public static boolean applyMethod(String excludeMethods, String includeMethods, String method) {
|
||||
Set<String> includeMethodsSet = TextParseUtil.commaDelimitedStringToSet(includeMethods == null? "" : includeMethods);
|
||||
Set<String> excludeMethodsSet = TextParseUtil.commaDelimitedStringToSet(excludeMethods == null? "" : excludeMethods);
|
||||
|
||||
return applyMethod(excludeMethodsSet, includeMethodsSet, method);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public class MethodFilterInterceptorUtil extends org.apache.struts2.interceptor.MethodFilterInterceptorUtil {
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ModelDriven;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.struts2.ModelDriven;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
@@ -71,10 +71,13 @@ import com.opensymphony.xwork2.util.ValueStack;
|
||||
* </action>
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @author tm_jee
|
||||
* @version $Date$ $Id$
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ModelDrivenInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ModelDrivenInterceptor extends AbstractInterceptor {
|
||||
|
||||
protected boolean refreshModelBeforeResult = false;
|
||||
|
||||
+3
@@ -66,7 +66,10 @@ import java.util.Set;
|
||||
* ...
|
||||
* </action>
|
||||
* </pre>
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ParameterRemoverInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ParameterRemoverInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ParameterRemoverInterceptor.class);
|
||||
|
||||
@@ -21,21 +21,38 @@ package com.opensymphony.xwork2.interceptor;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
|
||||
/**
|
||||
* PreResultListeners may be registered with an {@link ActionInvocation} to get a callback after the
|
||||
* {@link com.opensymphony.xwork2.Action} has been executed but before the {@link com.opensymphony.xwork2.Result}
|
||||
* is executed.
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.PreResultListener} instead.
|
||||
*/
|
||||
public interface PreResultListener {
|
||||
@Deprecated
|
||||
public interface PreResultListener extends org.apache.struts2.interceptor.PreResultListener {
|
||||
|
||||
@Override
|
||||
default void beforeResult(org.apache.struts2.ActionInvocation invocation, String resultCode) {
|
||||
beforeResult(ActionInvocation.adapt(invocation), resultCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* This callback method will be called after the {@link com.opensymphony.xwork2.Action} execution and
|
||||
* before the {@link com.opensymphony.xwork2.Result} execution.
|
||||
*
|
||||
* @param invocation the action invocation
|
||||
* @param resultCode the result code returned by the action (eg. <code>success</code>).
|
||||
*/
|
||||
void beforeResult(ActionInvocation invocation, String resultCode);
|
||||
|
||||
static PreResultListener adapt(org.apache.struts2.interceptor.PreResultListener actualListener) {
|
||||
if (actualListener instanceof PreResultListener) {
|
||||
return (PreResultListener) actualListener;
|
||||
}
|
||||
return actualListener != null ? new LegacyAdapter(actualListener) : null;
|
||||
}
|
||||
|
||||
class LegacyAdapter implements PreResultListener {
|
||||
|
||||
private final org.apache.struts2.interceptor.PreResultListener adaptee;
|
||||
|
||||
private LegacyAdapter(org.apache.struts2.interceptor.PreResultListener adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeResult(ActionInvocation invocation, String resultCode) {
|
||||
adaptee.beforeResult(invocation, resultCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
-24
@@ -19,8 +19,8 @@
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -28,7 +28,7 @@ import java.lang.reflect.Method;
|
||||
/**
|
||||
* <p>
|
||||
* A utility class for invoking prefixed methods in action class.
|
||||
*
|
||||
*
|
||||
* Interceptors that made use of this class are:
|
||||
* </p>
|
||||
* <ul>
|
||||
@@ -37,7 +37,7 @@ import java.lang.reflect.Method;
|
||||
* </ul>
|
||||
* *
|
||||
* <!-- START SNIPPET: javadocDefaultWorkflowInterceptor -->
|
||||
*
|
||||
*
|
||||
* <b>In DefaultWorkflowInterceptor</b>
|
||||
* <p>applies only when action implements {@link com.opensymphony.xwork2.Validateable}</p>
|
||||
* <ol>
|
||||
@@ -45,12 +45,12 @@ import java.lang.reflect.Method;
|
||||
* <li>else if the action class have validateDo{MethodName}(), it will be invoked</li>
|
||||
* <li>no matter if 1] or 2] is performed, if alwaysInvokeValidate property of the interceptor is "true" (which is by default "true"), validate() will be invoked.</li>
|
||||
* </ol>
|
||||
*
|
||||
*
|
||||
* <!-- END SNIPPET: javadocDefaultWorkflowInterceptor -->
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* <!-- START SNIPPET: javadocPrepareInterceptor -->
|
||||
*
|
||||
*
|
||||
* <b>In PrepareInterceptor</b>
|
||||
* <p>Applies only when action implements Preparable</p>
|
||||
* <ol>
|
||||
@@ -58,14 +58,14 @@ import java.lang.reflect.Method;
|
||||
* <li>else if the action class have prepareDo(MethodName()}(), it will be invoked</li>
|
||||
* <li>no matter if 1] or 2] is performed, if alwaysinvokePrepare property of the interceptor is "true" (which is by default "true"), prepare() will be invoked.</li>
|
||||
* </ol>
|
||||
*
|
||||
*
|
||||
* <!-- END SNIPPET: javadocPrepareInterceptor -->
|
||||
*
|
||||
*
|
||||
* @author Philip Luppens
|
||||
* @author tm_jee
|
||||
*/
|
||||
public class PrefixMethodInvocationUtil {
|
||||
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(PrefixMethodInvocationUtil.class);
|
||||
|
||||
private static final String DEFAULT_INVOCATION_METHODNAME = "execute";
|
||||
@@ -76,7 +76,7 @@ public class PrefixMethodInvocationUtil {
|
||||
* <p>
|
||||
* This method will prefix <code>actionInvocation</code>'s <code>ActionProxy</code>'s
|
||||
* <code>method</code> with <code>prefixes</code> before invoking the prefixed method.
|
||||
* Order of the <code>prefixes</code> is important, as this method will return once
|
||||
* Order of the <code>prefixes</code> is important, as this method will return once
|
||||
* a prefixed method is found in the action class.
|
||||
* </p>
|
||||
*
|
||||
@@ -89,7 +89,7 @@ public class PrefixMethodInvocationUtil {
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* Assuming <code>actionInvocation.getProxy(),getMethod()</code> returns "submit",
|
||||
* Assuming <code>actionInvocation.getProxy(),getMethod()</code> returns "submit",
|
||||
* the order of invocation would be as follows:-
|
||||
* </p>
|
||||
*
|
||||
@@ -99,12 +99,12 @@ public class PrefixMethodInvocationUtil {
|
||||
* </ol>
|
||||
*
|
||||
* <p>
|
||||
* If <code>prepareSubmit()</code> exists, it will be invoked and this method
|
||||
* will return, <code>prepareDoSubmit()</code> will NOT be invoked.
|
||||
* If <code>prepareSubmit()</code> exists, it will be invoked and this method
|
||||
* will return, <code>prepareDoSubmit()</code> will NOT be invoked.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* On the other hand, if <code>prepareDoSubmit()</code> does not exists, and
|
||||
* On the other hand, if <code>prepareDoSubmit()</code> does not exists, and
|
||||
* <code>prepareDoSubmit()</code> exists, it will be invoked.
|
||||
* </p>
|
||||
*
|
||||
@@ -119,29 +119,32 @@ public class PrefixMethodInvocationUtil {
|
||||
*/
|
||||
public static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException {
|
||||
Object action = actionInvocation.getAction();
|
||||
|
||||
|
||||
String methodName = actionInvocation.getProxy().getMethod();
|
||||
|
||||
|
||||
if (methodName == null) {
|
||||
// if null returns (possible according to the docs), use the default execute
|
||||
// if null returns (possible according to the docs), use the default execute
|
||||
methodName = DEFAULT_INVOCATION_METHODNAME;
|
||||
}
|
||||
|
||||
|
||||
Method method = getPrefixedMethod(prefixes, methodName, action);
|
||||
if (method != null) {
|
||||
method.invoke(action, new Object[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void invokePrefixMethod(org.apache.struts2.ActionInvocation actionInvocation, String[] prefixes) throws InvocationTargetException, IllegalAccessException {
|
||||
invokePrefixMethod(ActionInvocation.adapt(actionInvocation), prefixes);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a {@link Method} in <code>action</code>. The method
|
||||
* This method returns a {@link Method} in <code>action</code>. The method
|
||||
* returned is found by searching for method in <code>action</code> whose method name
|
||||
* is equals to the result of appending each <code>prefixes</code>
|
||||
* to <code>methodName</code>. Only the first method found will be returned, hence
|
||||
* the order of <code>prefixes</code> is important. If none is found this method
|
||||
* will return null.
|
||||
*
|
||||
*
|
||||
* @param prefixes the prefixes to prefix the <code>methodName</code>
|
||||
* @param methodName the method name to be prefixed with <code>prefixes</code>
|
||||
* @param action the action class of which the prefixed method is to be search for.
|
||||
@@ -162,7 +165,7 @@ public class PrefixMethodInvocationUtil {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This method capitalized the first character of <code>methodName</code>.
|
||||
|
||||
@@ -19,9 +19,7 @@
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.Preparable;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.struts2.Preparable;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
@@ -98,7 +96,10 @@ import java.lang.reflect.InvocationTargetException;
|
||||
* @author Philip Luppens
|
||||
* @author tm_jee
|
||||
* @see com.opensymphony.xwork2.Preparable
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.PrepareInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class PrepareInterceptor extends MethodFilterInterceptor {
|
||||
|
||||
private static final long serialVersionUID = -5216969014510719786L;
|
||||
|
||||
@@ -21,23 +21,8 @@ package com.opensymphony.xwork2.interceptor;
|
||||
import com.opensymphony.xwork2.ModelDriven;
|
||||
|
||||
/**
|
||||
* Adds the ability to set a model, probably retrieved from a given state.
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ScopedModelDriven} instead.
|
||||
*/
|
||||
public interface ScopedModelDriven<T> extends ModelDriven<T> {
|
||||
|
||||
/**
|
||||
* @param model sets the model
|
||||
*/
|
||||
void setModel(T model);
|
||||
|
||||
/**
|
||||
* Sets the key under which the model is stored
|
||||
* @param key The model key
|
||||
*/
|
||||
void setScopeKey(String key);
|
||||
|
||||
/**
|
||||
* @return the key under which the model is stored
|
||||
*/
|
||||
String getScopeKey();
|
||||
@Deprecated
|
||||
public interface ScopedModelDriven<T> extends org.apache.struts2.interceptor.ScopedModelDriven<T>, ModelDriven<T> {
|
||||
}
|
||||
|
||||
+15
-11
@@ -24,6 +24,7 @@ import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.interceptor.ScopedModelDriven;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
@@ -35,7 +36,7 @@ import java.util.Map;
|
||||
*
|
||||
* <p>This interceptor only activates on actions that implement the {@link ScopedModelDriven} interface. If
|
||||
* detected, it will retrieve the model class from the configured scope, then provide it to the Action.</p>
|
||||
*
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <p><u>Interceptor parameters:</u></p>
|
||||
@@ -45,7 +46,7 @@ import java.util.Map;
|
||||
* <ul>
|
||||
*
|
||||
* <li>className - The model class name. Defaults to the class name of the object returned by the getModel() method.</li>
|
||||
*
|
||||
*
|
||||
* <li>name - The key to use when storing or retrieving the instance in a scope. Defaults to the model
|
||||
* class name.</li>
|
||||
*
|
||||
@@ -66,42 +67,45 @@ import java.util.Map;
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
*
|
||||
*
|
||||
* <-- Basic usage -->
|
||||
* <interceptor name="scopedModelDriven" class="com.opensymphony.interceptor.ScopedModelDrivenInterceptor" />
|
||||
*
|
||||
*
|
||||
* <-- Using all available parameters -->
|
||||
* <interceptor name="gangsterForm" class="com.opensymphony.interceptor.ScopedModelDrivenInterceptor">
|
||||
* <param name="scope">session</param>
|
||||
* <param name="name">gangsterForm</param>
|
||||
* <param name="className">com.opensymphony.example.GangsterForm</param>
|
||||
* </interceptor>
|
||||
*
|
||||
*
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ScopedModelDrivenInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ScopedModelDrivenInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
|
||||
|
||||
|
||||
private static final String GET_MODEL = "getModel";
|
||||
private String scope;
|
||||
private String name;
|
||||
private String className;
|
||||
private ObjectFactory objectFactory;
|
||||
|
||||
|
||||
@Inject
|
||||
public void setObjectFactory(ObjectFactory factory) {
|
||||
this.objectFactory = factory;
|
||||
}
|
||||
|
||||
|
||||
protected Object resolveModel(ObjectFactory factory, ActionContext actionContext, String modelClassName, String modelScope, String modelName) throws Exception {
|
||||
Object model;
|
||||
Map<String, Object> scopeMap = actionContext.getContextMap();
|
||||
if ("session".equals(modelScope)) {
|
||||
scopeMap = actionContext.getSession();
|
||||
}
|
||||
|
||||
|
||||
model = scopeMap.get(modelName);
|
||||
if (model == null) {
|
||||
model = factory.buildBean(modelClassName, null);
|
||||
@@ -119,7 +123,7 @@ public class ScopedModelDrivenInterceptor extends AbstractInterceptor {
|
||||
if (modelDriven.getModel() == null) {
|
||||
ActionContext ctx = ActionContext.getContext();
|
||||
ActionConfig config = invocation.getProxy().getConfig();
|
||||
|
||||
|
||||
String cName = className;
|
||||
if (cName == null) {
|
||||
try {
|
||||
@@ -161,5 +165,5 @@ public class ScopedModelDrivenInterceptor extends AbstractInterceptor {
|
||||
*/
|
||||
public void setScope(String scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -20,11 +20,11 @@ package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.config.entities.Parameterizable;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.ClearableValueStack;
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
@@ -34,6 +34,7 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@@ -84,7 +85,10 @@ import java.util.Map;
|
||||
* </pre>
|
||||
*
|
||||
* @author Patrick Lightbody
|
||||
*
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.StaticParametersInterceptor} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class StaticParametersInterceptor extends AbstractInterceptor {
|
||||
|
||||
private boolean parse;
|
||||
|
||||
@@ -23,109 +23,84 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* ValidationAware classes can accept Action (class level) or field level error messages. Action level messages are kept
|
||||
* in a Collection. Field level error messages are kept in a Map from String field name to a List of field error msgs.
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ValidationAware} instead.
|
||||
*/
|
||||
public interface ValidationAware {
|
||||
@Deprecated
|
||||
public interface ValidationAware extends org.apache.struts2.interceptor.ValidationAware {
|
||||
|
||||
/**
|
||||
* Set the Collection of Action-level String error messages.
|
||||
*
|
||||
* @param errorMessages Collection of String error messages
|
||||
*/
|
||||
void setActionErrors(Collection<String> errorMessages);
|
||||
|
||||
/**
|
||||
* Get the Collection of Action-level error messages for this action. Error messages should not
|
||||
* be added directly here, as implementations are free to return a new Collection or an
|
||||
* Unmodifiable Collection.
|
||||
*
|
||||
* @return Collection of String error messages
|
||||
*/
|
||||
Collection<String> getActionErrors();
|
||||
|
||||
/**
|
||||
* Set the Collection of Action-level String messages (not errors).
|
||||
*
|
||||
* @param messages Collection of String messages (not errors).
|
||||
*/
|
||||
void setActionMessages(Collection<String> messages);
|
||||
|
||||
/**
|
||||
* Get the Collection of Action-level messages for this action. Messages should not be added
|
||||
* directly here, as implementations are free to return a new Collection or an Unmodifiable
|
||||
* Collection.
|
||||
*
|
||||
* @return Collection of String messages
|
||||
*/
|
||||
Collection<String> getActionMessages();
|
||||
|
||||
/**
|
||||
* Set the field error map of fieldname (String) to Collection of String error messages.
|
||||
*
|
||||
* @param errorMap field error map
|
||||
*/
|
||||
void setFieldErrors(Map<String, List<String>> errorMap);
|
||||
|
||||
/**
|
||||
* Get the field specific errors associated with this action. Error messages should not be added
|
||||
* directly here, as implementations are free to return a new Collection or an Unmodifiable
|
||||
* Collection.
|
||||
*
|
||||
* @return Map with errors mapped from fieldname (String) to Collection of String error messages
|
||||
*/
|
||||
Map<String, List<String>> getFieldErrors();
|
||||
|
||||
/**
|
||||
* Add an Action-level error message to this Action.
|
||||
*
|
||||
* @param anErrorMessage the error message
|
||||
*/
|
||||
void addActionError(String anErrorMessage);
|
||||
|
||||
/**
|
||||
* Add an Action-level message to this Action.
|
||||
*
|
||||
* @param aMessage the message
|
||||
*/
|
||||
void addActionMessage(String aMessage);
|
||||
|
||||
/**
|
||||
* Add an error message for a given field.
|
||||
*
|
||||
* @param fieldName name of field
|
||||
* @param errorMessage the error message
|
||||
*/
|
||||
void addFieldError(String fieldName, String errorMessage);
|
||||
|
||||
/**
|
||||
* Check whether there are any Action-level error messages.
|
||||
*
|
||||
* @return true if any Action-level error messages have been registered
|
||||
*/
|
||||
boolean hasActionErrors();
|
||||
|
||||
/**
|
||||
* Checks whether there are any Action-level messages.
|
||||
*
|
||||
* @return true if any Action-level messages have been registered
|
||||
*/
|
||||
boolean hasActionMessages();
|
||||
|
||||
/**
|
||||
* Checks whether there are any action errors or field errors.
|
||||
*
|
||||
* @return <code>(hasActionErrors() || hasFieldErrors())</code>
|
||||
*/
|
||||
default boolean hasErrors() {
|
||||
return hasActionErrors() || hasFieldErrors();
|
||||
static ValidationAware adapt(org.apache.struts2.interceptor.ValidationAware actualValidation) {
|
||||
if (actualValidation instanceof ValidationAware) {
|
||||
return (ValidationAware) actualValidation;
|
||||
}
|
||||
return actualValidation != null ? new LegacyAdapter(actualValidation) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether there are any field errors associated with this action.
|
||||
*
|
||||
* @return whether there are any field errors
|
||||
*/
|
||||
boolean hasFieldErrors();
|
||||
class LegacyAdapter implements ValidationAware {
|
||||
|
||||
private final org.apache.struts2.interceptor.ValidationAware adaptee;
|
||||
|
||||
private LegacyAdapter(org.apache.struts2.interceptor.ValidationAware adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionErrors(Collection<String> errorMessages) {
|
||||
adaptee.setActionErrors(errorMessages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getActionErrors() {
|
||||
return adaptee.getActionErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionMessages(Collection<String> messages) {
|
||||
adaptee.setActionMessages(messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getActionMessages() {
|
||||
return adaptee.getActionMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFieldErrors(Map<String, List<String>> errorMap) {
|
||||
adaptee.setFieldErrors(errorMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getFieldErrors() {
|
||||
return adaptee.getFieldErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addActionError(String anErrorMessage) {
|
||||
adaptee.addActionError(anErrorMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addActionMessage(String aMessage) {
|
||||
adaptee.addActionMessage(aMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFieldError(String fieldName, String errorMessage) {
|
||||
adaptee.addFieldError(fieldName, errorMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActionErrors() {
|
||||
return adaptee.hasActionErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActionMessages() {
|
||||
return adaptee.hasActionMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFieldErrors() {
|
||||
return adaptee.hasFieldErrors();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,22 +19,8 @@
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
/**
|
||||
* ValidationErrorAware classes can be notified about validation errors
|
||||
* before {@link com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor} will return 'inputResultName' result
|
||||
* to allow change or not the result name
|
||||
*
|
||||
* This interface can be only applied to action which already implements {@link ValidationAware} interface!
|
||||
*
|
||||
* @since 2.3.15
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ValidationErrorAware} instead.
|
||||
*/
|
||||
public interface ValidationErrorAware {
|
||||
|
||||
/**
|
||||
* Allows to notify action about occurred action/field errors
|
||||
*
|
||||
* @param currentResultName current result name, action can change it or return the same
|
||||
* @return new result name or passed currentResultName
|
||||
*/
|
||||
String actionErrorOccurred(final String currentResultName);
|
||||
|
||||
@Deprecated
|
||||
public interface ValidationErrorAware extends org.apache.struts2.interceptor.ValidationErrorAware {
|
||||
}
|
||||
|
||||
@@ -19,12 +19,8 @@
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
/**
|
||||
* ValidationWorkflowAware classes can programmatically change result name when errors occurred
|
||||
*
|
||||
* This interface can be only applied to action which already implements {@link ValidationAware} interface!
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.interceptor.ValidationWorkflowAware} instead.
|
||||
*/
|
||||
public interface ValidationWorkflowAware {
|
||||
|
||||
String getInputResultName();
|
||||
|
||||
@Deprecated
|
||||
public interface ValidationWorkflowAware extends org.apache.struts2.interceptor.ValidationWorkflowAware {
|
||||
}
|
||||
|
||||
@@ -70,11 +70,14 @@ public interface WithLazyParams {
|
||||
}
|
||||
|
||||
public Interceptor injectParams(Interceptor interceptor, Map<String, String> params, ActionContext invocationContext) {
|
||||
return (Interceptor) injectParams((org.apache.struts2.interceptor.Interceptor) interceptor, params, invocationContext);
|
||||
}
|
||||
|
||||
public org.apache.struts2.interceptor.Interceptor injectParams(org.apache.struts2.interceptor.Interceptor interceptor, Map<String, String> params, ActionContext invocationContext) {
|
||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
Object paramValue = textParser.evaluate(new char[]{ '$' }, entry.getValue(), valueEvaluator, TextParser.DEFAULT_LOOP_COUNT);
|
||||
ognlUtil.setProperty(entry.getKey(), paramValue, interceptor, invocationContext.getContextMap());
|
||||
}
|
||||
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -36,6 +36,7 @@ public class DefaultExcludedPatternsChecker implements ExcludedPatternsChecker {
|
||||
private static final Logger LOG = LogManager.getLogger(DefaultExcludedPatternsChecker.class);
|
||||
|
||||
public static final String[] EXCLUDED_PATTERNS = {
|
||||
"(^|\\%\\{)(#?top\\.)[^\\s]*",
|
||||
"(^|\\%\\{)((#?)(top(\\.|\\['|\\[\")|\\[\\d\\]\\.)?)(dojo|struts|session|request|response|application|servlet(Request|Response|Context)|parameters|context|_memberAccess)(\\.|\\[).*",
|
||||
".*(^|\\.|\\[|\\'|\"|get)class(\\(\\.|\\[|\\'|\").*",
|
||||
"actionErrors|actionMessages|fieldErrors"
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
package com.opensymphony.xwork2.util;
|
||||
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
|
||||
/**
|
||||
* @since 6.5.0
|
||||
@@ -35,7 +35,7 @@ public final class DebugUtils {
|
||||
log.error(message);
|
||||
if (action instanceof ValidationAware) {
|
||||
ValidationAware validationAware = (ValidationAware) action;
|
||||
validationAware.addActionError(message);
|
||||
validationAware.addActionMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,11 +20,11 @@ package com.opensymphony.xwork2.util;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ModelDriven;
|
||||
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProviderFactory;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ModelDriven;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.Locale;
|
||||
@@ -135,7 +135,7 @@ public class StrutsLocalizedTextProvider extends AbstractLocalizedTextProvider {
|
||||
* object. If so, repeat the entire process from the beginning with the object's class as
|
||||
* aClass and "address.state" as the message key.</li>
|
||||
* <li>If not found, look for the message in aClass' package hierarchy.</li>
|
||||
* <li>If still not found, look for the message in the default resource bundles
|
||||
* <li>If still not found, look for the message in the default resource bundles
|
||||
* (Note: the lookup is not repeated again if {@link #searchDefaultBundlesFirst} was <code>true</code>).</li>
|
||||
* <li>Return defaultMessage</li>
|
||||
* </ol>
|
||||
@@ -190,7 +190,7 @@ public class StrutsLocalizedTextProvider extends AbstractLocalizedTextProvider {
|
||||
* object. If so, repeat the entire process from the beginning with the object's class as
|
||||
* aClass and "address.state" as the message key.</li>
|
||||
* <li>If not found, look for the message in aClass' package hierarchy.</li>
|
||||
* <li>If still not found, look for the message in the default resource bundles
|
||||
* <li>If still not found, look for the message in the default resource bundles
|
||||
* (Note: the lookup is not repeated again if {@link #searchDefaultBundlesFirst} was <code>true</code>).</li>
|
||||
* <li>Return defaultMessage</li>
|
||||
* </ol>
|
||||
|
||||
@@ -23,144 +23,127 @@ import com.opensymphony.xwork2.ActionContext;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* ValueStack allows multiple beans to be pushed in and dynamic EL expressions to be evaluated against it. When
|
||||
* evaluating an expression, the stack will be searched down the stack, from the latest objects pushed in to the
|
||||
* earliest, looking for a bean with a getter or setter for the given property or a method of the given name (depending
|
||||
* on the expression being evaluated).
|
||||
* @deprecated since 6.7.0, use {@link org.apache.struts2.util.ValueStack} instead.
|
||||
*/
|
||||
public interface ValueStack {
|
||||
|
||||
String VALUE_STACK = "com.opensymphony.xwork2.util.ValueStack.ValueStack";
|
||||
|
||||
String REPORT_ERRORS_ON_NO_PROP = "com.opensymphony.xwork2.util.ValueStack.ReportErrorsOnNoProp";
|
||||
|
||||
/**
|
||||
* Gets the context for this value stack. The context holds all the information in the value stack and it's surroundings.
|
||||
*
|
||||
* @return the context.
|
||||
*/
|
||||
Map<String, Object> getContext();
|
||||
@Deprecated
|
||||
public interface ValueStack extends org.apache.struts2.util.ValueStack {
|
||||
|
||||
@Override
|
||||
ActionContext getActionContext();
|
||||
|
||||
/**
|
||||
* Sets the default type to convert to if no type is provided when getting a value.
|
||||
*
|
||||
* @param defaultType the new default type
|
||||
*/
|
||||
void setDefaultType(Class defaultType);
|
||||
static ValueStack adapt(org.apache.struts2.util.ValueStack actualStack) {
|
||||
if (actualStack instanceof ValueStack) {
|
||||
return (ValueStack) actualStack;
|
||||
}
|
||||
return actualStack != null ? new LegacyAdapter(actualStack) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a override map containing <code> key -> values </code> that takes precedent when doing find operations on the ValueStack.
|
||||
* <p>
|
||||
* See the unit test for ValueStackTest for examples.
|
||||
* </p>
|
||||
*
|
||||
* @param overrides overrides map.
|
||||
*/
|
||||
void setExprOverrides(Map<Object, Object> overrides);
|
||||
class LegacyAdapter implements ValueStack {
|
||||
|
||||
/**
|
||||
* Gets the override map if anyone exists.
|
||||
*
|
||||
* @return the override map, <tt>null</tt> if not set.
|
||||
*/
|
||||
Map<Object, Object> getExprOverrides();
|
||||
private final org.apache.struts2.util.ValueStack adaptee;
|
||||
|
||||
/**
|
||||
* Get the CompoundRoot which holds the objects pushed onto the stack
|
||||
*
|
||||
* @return the root
|
||||
*/
|
||||
CompoundRoot getRoot();
|
||||
private LegacyAdapter(org.apache.struts2.util.ValueStack adaptee) {
|
||||
this.adaptee = adaptee;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to set a property on a bean in the stack with the given expression using the default search order.
|
||||
*
|
||||
* @param expr the expression defining the path to the property to be set.
|
||||
* @param value the value to be set into the named property
|
||||
*/
|
||||
void setValue(String expr, Object value);
|
||||
@Override
|
||||
public Map<String, Object> getContext() {
|
||||
return adaptee.getContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to set a property on a bean in the stack with the given expression using the default search order.
|
||||
* N.B.: unlike #setValue(String,Object) it doesn't allow eval expression.
|
||||
* @param expr the expression defining the path to the property to be set.
|
||||
* @param value the value to be set into the named property
|
||||
*/
|
||||
void setParameter(String expr, Object value);
|
||||
@Override
|
||||
public ActionContext getActionContext() {
|
||||
return ActionContext.adapt(adaptee.getActionContext());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to set a property on a bean in the stack with the given expression using the default search order.
|
||||
*
|
||||
* @param expr the expression defining the path to the property to be set.
|
||||
* @param value the value to be set into the named property
|
||||
* @param throwExceptionOnFailure a flag to tell whether an exception should be thrown if there is no property with
|
||||
* the given name.
|
||||
*/
|
||||
void setValue(String expr, Object value, boolean throwExceptionOnFailure);
|
||||
@Override
|
||||
public void setDefaultType(Class defaultType) {
|
||||
adaptee.setDefaultType(defaultType);
|
||||
}
|
||||
|
||||
String findString(String expr);
|
||||
String findString(String expr, boolean throwExceptionOnFailure);
|
||||
@Override
|
||||
public void setExprOverrides(Map<Object, Object> overrides) {
|
||||
adaptee.setExprOverrides(overrides);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a value by evaluating the given expression against the stack in the default search order.
|
||||
*
|
||||
* @param expr the expression giving the path of properties to navigate to find the property value to return
|
||||
* @return the result of evaluating the expression
|
||||
*/
|
||||
Object findValue(String expr);
|
||||
@Override
|
||||
public Map<Object, Object> getExprOverrides() {
|
||||
return adaptee.getExprOverrides();
|
||||
}
|
||||
|
||||
Object findValue(String expr, boolean throwExceptionOnFailure);
|
||||
@Override
|
||||
public CompoundRoot getRoot() {
|
||||
return adaptee.getRoot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a value by evaluating the given expression against the stack in the default search order.
|
||||
*
|
||||
* @param expr the expression giving the path of properties to navigate to find the property value to return
|
||||
* @param asType the type to convert the return value to
|
||||
* @return the result of evaluating the expression
|
||||
*/
|
||||
Object findValue(String expr, Class asType);
|
||||
Object findValue(String expr, Class asType, boolean throwExceptionOnFailure);
|
||||
@Override
|
||||
public void setValue(String expr, Object value) {
|
||||
adaptee.setValue(expr, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object on the top of the stack <b>without</b> changing the stack.
|
||||
*
|
||||
* @return the object on the top.
|
||||
* @see CompoundRoot#peek()
|
||||
*/
|
||||
Object peek();
|
||||
@Override
|
||||
public void setParameter(String expr, Object value) {
|
||||
adaptee.setParameter(expr, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object on the top of the stack and <b>remove</b> it from the stack.
|
||||
*
|
||||
* @return the object on the top of the stack
|
||||
* @see CompoundRoot#pop()
|
||||
*/
|
||||
Object pop();
|
||||
@Override
|
||||
public void setValue(String expr, Object value, boolean throwExceptionOnFailure) {
|
||||
adaptee.setValue(expr, value, throwExceptionOnFailure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put this object onto the top of the stack
|
||||
*
|
||||
* @param o the object to be pushed onto the stack
|
||||
* @see CompoundRoot#push(Object)
|
||||
*/
|
||||
void push(Object o);
|
||||
@Override
|
||||
public String findString(String expr) {
|
||||
return adaptee.findString(expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an object on the stack with the given key
|
||||
* so it is retrievable by {@link #findValue(String)}, {@link #findValue(String, Class)}
|
||||
*
|
||||
* @param key the key
|
||||
* @param o the object
|
||||
*/
|
||||
void set(String key, Object o);
|
||||
@Override
|
||||
public String findString(String expr, boolean throwExceptionOnFailure) {
|
||||
return adaptee.findString(expr, throwExceptionOnFailure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of objects in the stack
|
||||
*
|
||||
* @return the number of objects in the stack
|
||||
*/
|
||||
int size();
|
||||
@Override
|
||||
public Object findValue(String expr) {
|
||||
return adaptee.findValue(expr);
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public Object findValue(String expr, boolean throwExceptionOnFailure) {
|
||||
return adaptee.findValue(expr, throwExceptionOnFailure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object findValue(String expr, Class asType) {
|
||||
return adaptee.findValue(expr, asType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object findValue(String expr, Class asType, boolean throwExceptionOnFailure) {
|
||||
return adaptee.findValue(expr, asType, throwExceptionOnFailure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object peek() {
|
||||
return adaptee.peek();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object pop() {
|
||||
return adaptee.pop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void push(Object o) {
|
||||
adaptee.push(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(String key, Object o) {
|
||||
adaptee.set(key, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return adaptee.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-4
@@ -18,13 +18,23 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.validator;
|
||||
|
||||
import com.opensymphony.xwork2.*;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.CompositeTextProvider;
|
||||
import com.opensymphony.xwork2.LocaleProvider;
|
||||
import com.opensymphony.xwork2.LocaleProviderFactory;
|
||||
import com.opensymphony.xwork2.StrutsTextProviderFactory;
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.TextProviderFactory;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* A default implementation of the {@link ValidatorContext} interface.
|
||||
@@ -233,8 +243,8 @@ public class DelegatingValidatorContext implements ValidatorContext {
|
||||
}
|
||||
|
||||
protected static ValidationAware makeValidationAware(Object object) {
|
||||
if (object instanceof ValidationAware) {
|
||||
return (ValidationAware) object;
|
||||
if (object instanceof org.apache.struts2.interceptor.ValidationAware) {
|
||||
return ValidationAware.adapt((org.apache.struts2.interceptor.ValidationAware) object);
|
||||
} else {
|
||||
return new LoggingValidationAware(object);
|
||||
}
|
||||
|
||||
@@ -20,13 +20,13 @@ package com.opensymphony.xwork2.validator;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ActionProxy;
|
||||
import com.opensymphony.xwork2.Validateable;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
|
||||
import com.opensymphony.xwork2.interceptor.PrefixMethodInvocationUtil;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.Validateable;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
@@ -71,9 +71,9 @@ import org.apache.logging.log4j.Logger;
|
||||
* <li>programmatic - Defaults to true. If true and the action is Validateable call validate(),
|
||||
* and any method that starts with "validate".
|
||||
* </li>
|
||||
*
|
||||
*
|
||||
* <li>declarative - Defaults to true. Perform validation based on xml or annotations.</li>
|
||||
*
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
@@ -90,14 +90,14 @@ import org.apache.logging.log4j.Logger;
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
*
|
||||
*
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
* <interceptor-ref name="params"/>
|
||||
* <interceptor-ref name="validation"/>
|
||||
* <interceptor-ref name="workflow"/>
|
||||
* <result name="success">good_result.ftl</result>
|
||||
* </action>
|
||||
*
|
||||
*
|
||||
* <-- in the following case myMethod of the action class will not
|
||||
* get validated -->
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
@@ -108,7 +108,7 @@ import org.apache.logging.log4j.Logger;
|
||||
* <interceptor-ref name="workflow"/>
|
||||
* <result name="success">good_result.ftl</result>
|
||||
* </action>
|
||||
*
|
||||
*
|
||||
* <-- in the following case only annotated methods of the action class will
|
||||
* be validated -->
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
@@ -138,9 +138,9 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
private final static String ALT_VALIDATE_PREFIX = "validateDo";
|
||||
|
||||
private boolean validateAnnotatedMethodOnly;
|
||||
|
||||
|
||||
private ActionValidatorManager actionValidatorManager;
|
||||
|
||||
|
||||
private boolean alwaysInvokeValidate = true;
|
||||
private boolean programmatic = true;
|
||||
private boolean declarative = true;
|
||||
@@ -149,11 +149,11 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
public void setActionValidatorManager(ActionValidatorManager mgr) {
|
||||
this.actionValidatorManager = mgr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines if {@link Validateable}'s <code>validate()</code> should be called,
|
||||
* as well as methods whose name that start with "validate". Defaults to "true".
|
||||
*
|
||||
*
|
||||
* @param programmatic <tt>true</tt> then <code>validate()</code> is invoked.
|
||||
*/
|
||||
public void setProgrammatic(boolean programmatic) {
|
||||
@@ -161,9 +161,9 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if validation based on annotations or xml should be performed. Defaults
|
||||
* Determines if validation based on annotations or xml should be performed. Defaults
|
||||
* to "true".
|
||||
*
|
||||
*
|
||||
* @param declarative <tt>true</tt> then perform validation based on annotations or xml.
|
||||
*/
|
||||
public void setDeclarative(boolean declarative) {
|
||||
@@ -171,9 +171,9 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if {@link Validateable}'s <code>validate()</code> should always
|
||||
* Determines if {@link Validateable}'s <code>validate()</code> should always
|
||||
* be invoked. Default to "true".
|
||||
*
|
||||
*
|
||||
* @param alwaysInvokeValidate <tt>true</tt> then <code>validate()</code> is always invoked.
|
||||
*/
|
||||
public void setAlwaysInvokeValidate(String alwaysInvokeValidate) {
|
||||
@@ -218,7 +218,7 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Validating {}/{} with method {}.", invocation.getProxy().getNamespace(), invocation.getProxy().getActionName(), method);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (declarative) {
|
||||
if (validateAnnotatedMethodOnly) {
|
||||
@@ -226,12 +226,12 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
} else {
|
||||
actionValidatorManager.validate(action, context);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (action instanceof Validateable && programmatic) {
|
||||
// keep exception that might occured in validateXXX or validateDoXXX
|
||||
Exception exception = null;
|
||||
|
||||
Exception exception = null;
|
||||
|
||||
Validateable validateable = (Validateable) action;
|
||||
LOG.debug("Invoking validate() on action {}", validateable);
|
||||
|
||||
@@ -239,19 +239,19 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
PrefixMethodInvocationUtil.invokePrefixMethod(invocation, new String[]{VALIDATE_PREFIX, ALT_VALIDATE_PREFIX});
|
||||
}
|
||||
catch(Exception e) {
|
||||
// If any exception occurred while doing reflection, we want
|
||||
// If any exception occurred while doing reflection, we want
|
||||
// validate() to be executed
|
||||
LOG.warn("an exception occured while executing the prefix method", e);
|
||||
exception = e;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (alwaysInvokeValidate) {
|
||||
validateable.validate();
|
||||
}
|
||||
|
||||
if (exception != null) {
|
||||
// rethrow if something is wrong while doing validateXXX / validateDoXXX
|
||||
|
||||
if (exception != null) {
|
||||
// rethrow if something is wrong while doing validateXXX / validateDoXXX
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
@@ -262,7 +262,7 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
doBeforeInvocation(invocation);
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns the context that will be used by the
|
||||
|
||||
@@ -0,0 +1,558 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.opensymphony.xwork2.conversion.impl.ConversionData;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import org.apache.struts2.action.Action;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The ActionContext is the context in which an {@link Action} is executed. Each context is basically a
|
||||
* container of objects an action needs for execution like the session, parameters, locale, etc.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The ActionContext is thread local which means that values stored in the ActionContext are
|
||||
* unique per thread. See the {@link ThreadLocal} class for more information. The benefit of
|
||||
* this is you don't need to worry about a user specific action context, you just get it:
|
||||
* </p>
|
||||
*
|
||||
* <code>ActionContext context = ActionContext.getContext();</code>
|
||||
*
|
||||
* <p>
|
||||
* Finally, because of the thread local usage you don't need to worry about making your actions thread safe.
|
||||
* </p>
|
||||
*
|
||||
* @author Patrick Lightbody
|
||||
* @author Bill Lynch (docs)
|
||||
*/
|
||||
public class ActionContext implements Serializable {
|
||||
|
||||
private static final ThreadLocal<ActionContext> actionContext = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Constant for the name of the action being executed.
|
||||
*/
|
||||
private static final String ACTION_NAME = "org.apache.struts2.ActionContext.name";
|
||||
|
||||
/**
|
||||
* Constant for the {@link ValueStack OGNL value stack}.
|
||||
*/
|
||||
private static final String VALUE_STACK = ValueStack.VALUE_STACK;
|
||||
|
||||
/**
|
||||
* Constant for the action's session.
|
||||
*/
|
||||
private static final String SESSION = "org.apache.struts2.ActionContext.session";
|
||||
|
||||
/**
|
||||
* Constant for the action's application context.
|
||||
*/
|
||||
private static final String APPLICATION = "org.apache.struts2.ActionContext.application";
|
||||
|
||||
/**
|
||||
* Constant for the action's parameters.
|
||||
*/
|
||||
private static final String PARAMETERS = "org.apache.struts2.ActionContext.parameters";
|
||||
|
||||
/**
|
||||
* Constant for the action's locale.
|
||||
*/
|
||||
private static final String LOCALE = "org.apache.struts2.ActionContext.locale";
|
||||
|
||||
/**
|
||||
* Constant for the action's {@link ActionInvocation invocation} context.
|
||||
*/
|
||||
private static final String ACTION_INVOCATION = "org.apache.struts2.ActionContext.actionInvocation";
|
||||
|
||||
/**
|
||||
* Constant for the map of type conversion errors.
|
||||
*/
|
||||
private static final String CONVERSION_ERRORS = "org.apache.struts2.ActionContext.conversionErrors";
|
||||
|
||||
/**
|
||||
* Constant for the container
|
||||
*/
|
||||
private static final String CONTAINER = "org.apache.struts2.ActionContext.container";
|
||||
|
||||
private final Map<String, Object> context;
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext initialized with another context.
|
||||
*
|
||||
* @param context a context map.
|
||||
*/
|
||||
protected ActionContext(Map<String, Object> context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext based on passed in Map
|
||||
*
|
||||
* @param context a map with context values
|
||||
* @return new ActionContext
|
||||
*/
|
||||
public static ActionContext of(Map<String, Object> context) {
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException("Context cannot be null!");
|
||||
}
|
||||
return new ActionContext(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext based on empty Map
|
||||
*
|
||||
* @return new ActionContext
|
||||
*/
|
||||
public static ActionContext of() {
|
||||
return of(new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the provided context with the current thread
|
||||
*
|
||||
* @param actionContext context to bind to the thread
|
||||
* @return context which was bound to the thread
|
||||
*/
|
||||
public static ActionContext bind(ActionContext actionContext) {
|
||||
ActionContext.setContext(actionContext);
|
||||
return ActionContext.getContext();
|
||||
}
|
||||
|
||||
public static boolean containsValueStack(Map<String, Object> context) {
|
||||
return context != null && context.containsKey(VALUE_STACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds this context with the current thread
|
||||
*
|
||||
* @return this context which was bound to the thread
|
||||
*/
|
||||
public ActionContext bind() {
|
||||
ActionContext.setContext(this);
|
||||
return ActionContext.getContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wipes out current ActionContext, use wisely!
|
||||
*/
|
||||
public static void clear() {
|
||||
actionContext.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action context for the current thread.
|
||||
*
|
||||
* @param context the action context.
|
||||
*/
|
||||
private static void setContext(ActionContext context) {
|
||||
actionContext.set(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ActionContext specific to the current thread.
|
||||
*
|
||||
* @return the ActionContext for the current thread, is never <tt>null</tt>.
|
||||
*/
|
||||
public static ActionContext getContext() {
|
||||
return actionContext.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action invocation (the execution state).
|
||||
*
|
||||
* @param actionInvocation the action execution state.
|
||||
*/
|
||||
public ActionContext withActionInvocation(ActionInvocation actionInvocation) {
|
||||
put(ACTION_INVOCATION, actionInvocation);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the action invocation (the execution state).
|
||||
*
|
||||
* @return the action invocation (the execution state).
|
||||
*/
|
||||
public ActionInvocation getActionInvocation() {
|
||||
return (ActionInvocation) get(ACTION_INVOCATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action's application context.
|
||||
*
|
||||
* @param application the action's application context.
|
||||
*/
|
||||
public ActionContext withApplication(Map<String, Object> application) {
|
||||
put(APPLICATION, application);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Map of the ServletContext when in a servlet environment or a generic application level Map otherwise.
|
||||
*
|
||||
* @return a Map of ServletContext or generic application level Map
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> getApplication() {
|
||||
return (Map<String, Object>) get(APPLICATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the context map.
|
||||
*
|
||||
* @return the context map.
|
||||
*/
|
||||
public Map<String, Object> getContextMap() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets conversion errors which occurred when executing the action.
|
||||
*
|
||||
* @param conversionErrors a Map of errors which occurred when executing the action.
|
||||
*/
|
||||
public ActionContext withConversionErrors(Map<String, ConversionData> conversionErrors) {
|
||||
put(CONVERSION_ERRORS, conversionErrors);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the map of conversion errors which occurred when executing the action.
|
||||
*
|
||||
* @return the map of conversion errors which occurred when executing the action or an empty map if
|
||||
* there were no errors.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, ConversionData> getConversionErrors() {
|
||||
Map<String, ConversionData> errors = (Map<String, ConversionData>) get(CONVERSION_ERRORS);
|
||||
|
||||
if (errors == null) {
|
||||
errors = withConversionErrors(new HashMap<>()).getConversionErrors();
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Locale for the current action.
|
||||
*
|
||||
* @param locale the Locale for the current action.
|
||||
*/
|
||||
public ActionContext withLocale(Locale locale) {
|
||||
put(LOCALE, locale);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Locale of the current action. If no locale was ever specified the platform's
|
||||
* {@link Locale#getDefault() default locale} is used.
|
||||
*
|
||||
* @return the Locale of the current action.
|
||||
*/
|
||||
public Locale getLocale() {
|
||||
Locale locale = (Locale) get(LOCALE);
|
||||
|
||||
if (locale == null) {
|
||||
locale = Locale.getDefault();
|
||||
withLocale(locale);
|
||||
}
|
||||
|
||||
return locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the current Action in the ActionContext.
|
||||
*
|
||||
* @param actionName the name of the current action.
|
||||
*/
|
||||
public ActionContext withActionName(String actionName) {
|
||||
put(ACTION_NAME, actionName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the current Action.
|
||||
*
|
||||
* @return the name of the current action.
|
||||
*/
|
||||
public String getActionName() {
|
||||
return (String) get(ACTION_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action parameters.
|
||||
*
|
||||
* @param parameters the parameters for the current action.
|
||||
*/
|
||||
public ActionContext withParameters(HttpParameters parameters) {
|
||||
put(PARAMETERS, parameters);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Map of the HttpServletRequest parameters when in a servlet environment or a generic Map of
|
||||
* parameters otherwise.
|
||||
*
|
||||
* @return a Map of HttpServletRequest parameters or a multipart map when in a servlet environment, or a
|
||||
* generic Map of parameters otherwise.
|
||||
*/
|
||||
public HttpParameters getParameters() {
|
||||
return (HttpParameters) get(PARAMETERS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a map of action session values.
|
||||
*
|
||||
* @param session the session values.
|
||||
*/
|
||||
public ActionContext withSession(Map<String, Object> session) {
|
||||
put(SESSION, session);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Map of HttpSession values when in a servlet environment or a generic session map otherwise.
|
||||
*
|
||||
* @return the Map of HttpSession values when in a servlet environment or a generic session map otherwise.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> getSession() {
|
||||
return (Map<String, Object>) get(SESSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the OGNL value stack.
|
||||
*
|
||||
* @param valueStack the OGNL value stack.
|
||||
*/
|
||||
public ActionContext withValueStack(ValueStack valueStack) {
|
||||
put(VALUE_STACK, valueStack);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OGNL value stack.
|
||||
*
|
||||
* @return the OGNL value stack.
|
||||
*/
|
||||
public ValueStack getValueStack() {
|
||||
return (ValueStack) get(VALUE_STACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the container for this request
|
||||
*
|
||||
* @param container The container
|
||||
*/
|
||||
public ActionContext withContainer(Container container) {
|
||||
put(CONTAINER, container);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the container for this request
|
||||
*
|
||||
* @return The container
|
||||
*/
|
||||
public Container getContainer() {
|
||||
return (Container) get(CONTAINER);
|
||||
}
|
||||
|
||||
public <T> T getInstance(Class<T> type) {
|
||||
Container cont = getContainer();
|
||||
if (cont != null) {
|
||||
return cont.getInstance(type);
|
||||
} else {
|
||||
throw new StrutsException("Cannot find an initialized container for this request.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value that is stored in the current ActionContext by doing a lookup using the value's key.
|
||||
*
|
||||
* @param key the key used to find the value.
|
||||
* @return the value that was found using the key or <tt>null</tt> if the key was not found.
|
||||
*/
|
||||
public Object get(String key) {
|
||||
return context.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a value in the current ActionContext. The value can be looked up using the key.
|
||||
*
|
||||
* @param key the key of the value.
|
||||
* @param value the value to be stored.
|
||||
*/
|
||||
public void put(String key, Object value) {
|
||||
context.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ServletContext associated with current action
|
||||
*
|
||||
* @return current ServletContext
|
||||
*/
|
||||
public ServletContext getServletContext() {
|
||||
return (ServletContext) get(StrutsStatics.SERVLET_CONTEXT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ServletContext to action context
|
||||
*
|
||||
* @param servletContext associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
public ActionContext withServletContext(ServletContext servletContext) {
|
||||
put(StrutsStatics.SERVLET_CONTEXT, servletContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ServletRequest associated with current action
|
||||
*
|
||||
* @return current ServletRequest
|
||||
*/
|
||||
public HttpServletRequest getServletRequest() {
|
||||
return (HttpServletRequest) get(StrutsStatics.HTTP_REQUEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ServletRequest to action context
|
||||
*
|
||||
* @param request associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
public ActionContext withServletRequest(HttpServletRequest request) {
|
||||
put(StrutsStatics.HTTP_REQUEST, request);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ServletResponse associated with current action
|
||||
*
|
||||
* @return current ServletResponse
|
||||
*/
|
||||
public HttpServletResponse getServletResponse() {
|
||||
return (HttpServletResponse) get(StrutsStatics.HTTP_RESPONSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ServletResponse to action context
|
||||
*
|
||||
* @param response associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
public ActionContext withServletResponse(HttpServletResponse response) {
|
||||
put(StrutsStatics.HTTP_RESPONSE, response);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets PageContext associated with current action
|
||||
*
|
||||
* @return current PageContext
|
||||
*/
|
||||
public PageContext getPageContext() {
|
||||
return (PageContext) get(StrutsStatics.PAGE_CONTEXT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns PageContext to action context
|
||||
*
|
||||
* @param pageContext associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
public ActionContext withPageContext(PageContext pageContext) {
|
||||
put(StrutsStatics.PAGE_CONTEXT, pageContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ActionMapping associated with current action
|
||||
*
|
||||
* @return current ActionMapping
|
||||
*/
|
||||
public ActionMapping getActionMapping() {
|
||||
return (ActionMapping) get(StrutsStatics.ACTION_MAPPING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns ActionMapping to action context
|
||||
*
|
||||
* @param actionMapping associated with current request
|
||||
* @return ActionContext
|
||||
*/
|
||||
public ActionContext withActionMapping(ActionMapping actionMapping) {
|
||||
put(StrutsStatics.ACTION_MAPPING, actionMapping);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns an extra context map to action context
|
||||
*
|
||||
* @param extraContext to add to the current action context
|
||||
* @return ActionContext
|
||||
*/
|
||||
public ActionContext withExtraContext(Map<String, Object> extraContext) {
|
||||
if (extraContext != null) {
|
||||
context.putAll(extraContext);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds arbitrary key to action context
|
||||
*
|
||||
* @param key a string
|
||||
* @param value an object
|
||||
* @return ActionContext
|
||||
*/
|
||||
public ActionContext with(String key, Object value) {
|
||||
put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object obj) {
|
||||
if (!(obj instanceof ActionContext)) {
|
||||
return false;
|
||||
}
|
||||
ActionContext other = (ActionContext) obj;
|
||||
return Objects.equals(getContextMap(), other.getContextMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return Objects.hash(getContextMap());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
|
||||
/**
|
||||
* Provides hooks for handling key action events
|
||||
*/
|
||||
public interface ActionEventListener {
|
||||
/**
|
||||
* Called after an action has been created.
|
||||
*
|
||||
* @param action The action
|
||||
* @param stack The current value stack
|
||||
* @return The action to use
|
||||
*/
|
||||
Object prepare(Object action, ValueStack stack);
|
||||
|
||||
/**
|
||||
* Called when an exception is thrown by the action
|
||||
*
|
||||
* @param t The exception/error that was thrown
|
||||
* @param stack The current value stack
|
||||
* @return A result code to execute, can be null
|
||||
*/
|
||||
String handleException(Throwable t, ValueStack stack);
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.struts2.action.Action;
|
||||
import org.apache.struts2.interceptor.PreResultListener;
|
||||
import org.apache.struts2.result.ActionChainResult;
|
||||
import org.apache.struts2.result.Result;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
|
||||
/**
|
||||
* An {@link ActionInvocation} represents the execution state of an {@link com.opensymphony.xwork2.Action}. It holds the Interceptors and the Action instance.
|
||||
* By repeated re-entrant execution of the <code>invoke()</code> method, initially by the {@link ActionProxy}, then by the Interceptors, the
|
||||
* Interceptors are all executed, and then the {@link Action} and the {@link com.opensymphony.xwork2.Result}.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @see ActionProxy
|
||||
*/
|
||||
public interface ActionInvocation {
|
||||
|
||||
/**
|
||||
* Get the Action associated with this ActionInvocation.
|
||||
*
|
||||
* @return the Action
|
||||
*/
|
||||
Object getAction();
|
||||
|
||||
/**
|
||||
* Gets whether this ActionInvocation has executed before.
|
||||
* This will be set after the Action and the Result have executed.
|
||||
*
|
||||
* @return <tt>true</tt> if this ActionInvocation has executed before.
|
||||
*/
|
||||
boolean isExecuted();
|
||||
|
||||
/**
|
||||
* Gets the ActionContext associated with this ActionInvocation. The ActionProxy is
|
||||
* responsible for setting this ActionContext onto the ThreadLocal before invoking
|
||||
* the ActionInvocation and resetting the old ActionContext afterwards.
|
||||
*
|
||||
* @return the ActionContext.
|
||||
*/
|
||||
ActionContext getInvocationContext();
|
||||
|
||||
/**
|
||||
* Get the ActionProxy holding this ActionInvocation.
|
||||
*
|
||||
* @return the ActionProxy.
|
||||
*/
|
||||
ActionProxy getProxy();
|
||||
|
||||
/**
|
||||
* If the ActionInvocation has been executed before and the Result is an instance of {@link ActionChainResult}, this method
|
||||
* will walk down the chain of <code>ActionChainResult</code>s until it finds a non-chain result, which will be returned. If the
|
||||
* ActionInvocation's result has not been executed before, the Result instance will be created and populated with
|
||||
* the result params.
|
||||
*
|
||||
* @return the result.
|
||||
* @throws Exception can be thrown.
|
||||
*/
|
||||
Result getResult() throws Exception;
|
||||
|
||||
/**
|
||||
* Gets the result code returned from this ActionInvocation.
|
||||
*
|
||||
* @return the result code
|
||||
*/
|
||||
String getResultCode();
|
||||
|
||||
/**
|
||||
* Sets the result code, possibly overriding the one returned by the
|
||||
* action.
|
||||
*
|
||||
* <p>
|
||||
* The "intended" purpose of this method is to allow PreResultListeners to
|
||||
* override the result code returned by the Action.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If this method is used before the Action executes, the Action's returned
|
||||
* result code will override what was set. However the Action could (if
|
||||
* specifically coded to do so) inspect the ActionInvocation to see that
|
||||
* someone "upstream" (e.g. an Interceptor) had suggested a value as the
|
||||
* result, and it could therefore return the same value itself.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If this method is called between the Action execution and the Result
|
||||
* execution, then the value set here will override the result code the
|
||||
* action had returned. Creating an Interceptor that implements
|
||||
* {@link PreResultListener} will give you this opportunity.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If this method is called after the Result has been executed, it will
|
||||
* have the effect of raising an IllegalStateException.
|
||||
* </p>
|
||||
*
|
||||
* @param resultCode the result code.
|
||||
* @throws IllegalStateException if called after the Result has been executed.
|
||||
* @see #isExecuted()
|
||||
*/
|
||||
void setResultCode(String resultCode);
|
||||
|
||||
/**
|
||||
* Gets the ValueStack associated with this ActionInvocation.
|
||||
*
|
||||
* @return the ValueStack
|
||||
*/
|
||||
ValueStack getStack();
|
||||
|
||||
/**
|
||||
* Register a {@link PreResultListener} to be notified after the Action is executed and
|
||||
* before the Result is executed.
|
||||
*
|
||||
* <p>
|
||||
* The ActionInvocation implementation must guarantee that listeners will be called in
|
||||
* the order in which they are registered.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Listener registration and execution does not need to be thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @param listener the listener to add.
|
||||
*/
|
||||
void addPreResultListener(PreResultListener listener);
|
||||
|
||||
/**
|
||||
* Invokes the next step in processing this ActionInvocation.
|
||||
*
|
||||
* <p>
|
||||
* If there are more Interceptors, this will call the next one. If Interceptors choose not to short-circuit
|
||||
* ActionInvocation processing and return their own return code, they will call invoke() to allow the next Interceptor
|
||||
* to execute. If there are no more Interceptors to be applied, the Action is executed.
|
||||
* If the {@link ActionProxy#getExecuteResult()} method returns <tt>true</tt>, the Result is also executed.
|
||||
* </p>
|
||||
*
|
||||
* @throws Exception can be thrown.
|
||||
* @return the return code.
|
||||
*/
|
||||
String invoke() throws Exception;
|
||||
|
||||
/**
|
||||
* Invokes only the Action (not Interceptors or Results).
|
||||
*
|
||||
* <p>
|
||||
* This is useful in rare situations where advanced usage with the interceptor/action/result workflow is
|
||||
* being manipulated for certain functionality.
|
||||
* </p>
|
||||
*
|
||||
* @return the return code.
|
||||
* @throws Exception can be thrown.
|
||||
*/
|
||||
String invokeActionOnly() throws Exception;
|
||||
|
||||
/**
|
||||
* Sets the action event listener to respond to key action events.
|
||||
*
|
||||
* @param listener the listener.
|
||||
*/
|
||||
void setActionEventListener(ActionEventListener listener);
|
||||
|
||||
void init(ActionProxy proxy);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
|
||||
/**
|
||||
* ActionProxy is an extra layer between XWork and the action so that different proxies are possible.
|
||||
*
|
||||
* <p>
|
||||
* An example of this would be a remote proxy, where the layer between XWork and the action might be RMI or SOAP.
|
||||
* </p>
|
||||
*
|
||||
* @author Jason Carreira
|
||||
*/
|
||||
public interface ActionProxy {
|
||||
|
||||
/**
|
||||
* Gets the Action instance for this Proxy.
|
||||
*
|
||||
* @return the Action instance
|
||||
*/
|
||||
Object getAction();
|
||||
|
||||
/**
|
||||
* Gets the alias name this ActionProxy is mapped to.
|
||||
*
|
||||
* @return the alias name
|
||||
*/
|
||||
String getActionName();
|
||||
|
||||
/**
|
||||
* Gets the ActionConfig this ActionProxy is built from.
|
||||
*
|
||||
* @return the ActionConfig
|
||||
*/
|
||||
ActionConfig getConfig();
|
||||
|
||||
/**
|
||||
* Sets whether this ActionProxy should also execute the Result after executing the Action.
|
||||
*
|
||||
* @param executeResult <tt>true</tt> to also execute the Result.
|
||||
*/
|
||||
void setExecuteResult(boolean executeResult);
|
||||
|
||||
/**
|
||||
* Gets the status of whether the ActionProxy is set to execute the Result after the Action is executed.
|
||||
*
|
||||
* @return the status
|
||||
*/
|
||||
boolean getExecuteResult();
|
||||
|
||||
ActionInvocation getInvocation();
|
||||
|
||||
/**
|
||||
* Gets the namespace the ActionConfig for this ActionProxy is mapped to.
|
||||
*
|
||||
* @return the namespace
|
||||
*/
|
||||
String getNamespace();
|
||||
|
||||
/**
|
||||
* Execute this ActionProxy. This will set the ActionContext from the ActionInvocation into the ActionContext
|
||||
* ThreadLocal before invoking the ActionInvocation, then set the old ActionContext back into the ThreadLocal.
|
||||
*
|
||||
* @return the result code returned from executing the ActionInvocation
|
||||
* @throws Exception can be thrown.
|
||||
* @see ActionInvocation
|
||||
*/
|
||||
String execute() throws Exception;
|
||||
|
||||
/**
|
||||
* Gets the method name to execute, or <tt>null</tt> if no method has been specified (meaning <code>execute</code> will be invoked).
|
||||
*
|
||||
* @return the method to execute
|
||||
*/
|
||||
String getMethod();
|
||||
|
||||
/**
|
||||
* Gets status of the method value's initialization.
|
||||
*
|
||||
* @return true if the method returned by getMethod() is not a default initializer value.
|
||||
*/
|
||||
boolean isMethodSpecified();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.opensymphony.xwork2.LocaleProvider;
|
||||
import com.opensymphony.xwork2.LocaleProviderFactory;
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.TextProviderFactory;
|
||||
import com.opensymphony.xwork2.ValidationAwareSupport;
|
||||
import com.opensymphony.xwork2.conversion.impl.ConversionData;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.action.Action;
|
||||
import org.apache.struts2.interceptor.ValidationAware;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Provides a default implementation for the most common actions.
|
||||
* See the documentation for all the interfaces this class implements for more detailed information.
|
||||
*/
|
||||
public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ActionSupport.class);
|
||||
|
||||
private final ValidationAwareSupport validationAware = new ValidationAwareSupport();
|
||||
|
||||
private transient TextProvider textProvider;
|
||||
private transient LocaleProvider localeProvider;
|
||||
|
||||
protected Container container;
|
||||
|
||||
@Override
|
||||
public void setActionErrors(Collection<String> errorMessages) {
|
||||
validationAware.setActionErrors(errorMessages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getActionErrors() {
|
||||
return validationAware.getActionErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setActionMessages(Collection<String> messages) {
|
||||
validationAware.setActionMessages(messages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getActionMessages() {
|
||||
return validationAware.getActionMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFieldErrors(Map<String, List<String>> errorMap) {
|
||||
validationAware.setFieldErrors(errorMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getFieldErrors() {
|
||||
return validationAware.getFieldErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return getLocaleProvider().getLocale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidLocaleString(String localeStr) {
|
||||
return getLocaleProvider().isValidLocaleString(localeStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidLocale(Locale locale) {
|
||||
return getLocaleProvider().isValidLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale toLocale(String localeStr) {
|
||||
return getLocaleProvider().toLocale(localeStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasKey(String key) {
|
||||
return getTextProvider().hasKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName) {
|
||||
return getTextProvider().getText(aTextName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, String defaultValue) {
|
||||
return getTextProvider().getText(aTextName, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, String defaultValue, String obj) {
|
||||
return getTextProvider().getText(aTextName, defaultValue, obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, List<?> args) {
|
||||
return getTextProvider().getText(aTextName, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String[] args) {
|
||||
return getTextProvider().getText(key, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String aTextName, String defaultValue, List<?> args) {
|
||||
return getTextProvider().getText(aTextName, defaultValue, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String defaultValue, String[] args) {
|
||||
return getTextProvider().getText(key, defaultValue, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String defaultValue, List<?> args, ValueStack stack) {
|
||||
return getTextProvider().getText(key, defaultValue, args, stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(String key, String defaultValue, String[] args, ValueStack stack) {
|
||||
return getTextProvider().getText(key, defaultValue, args, stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dedicated method to support I10N and conversion errors
|
||||
*
|
||||
* @param key message which contains formatting string
|
||||
* @param expr that should be formatted
|
||||
* @return formatted expr with format specified by key
|
||||
*/
|
||||
public String getFormatted(String key, String expr) {
|
||||
Map<String, ConversionData> conversionErrors = ActionContext.getContext().getConversionErrors();
|
||||
if (conversionErrors.containsKey(expr)) {
|
||||
String[] vals = (String[]) conversionErrors.get(expr).getValue();
|
||||
return vals[0];
|
||||
} else {
|
||||
final ValueStack valueStack = ValueStack.adapt(ActionContext.getContext().getValueStack());
|
||||
final Object val = valueStack.findValue(expr);
|
||||
return getText(key, Arrays.asList(val));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceBundle getTexts() {
|
||||
return getTextProvider().getTexts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceBundle getTexts(String aBundleName) {
|
||||
return getTextProvider().getTexts(aBundleName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addActionError(String anErrorMessage) {
|
||||
validationAware.addActionError(anErrorMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addActionMessage(String aMessage) {
|
||||
validationAware.addActionMessage(aMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFieldError(String fieldName, String errorMessage) {
|
||||
validationAware.addFieldError(fieldName, errorMessage);
|
||||
}
|
||||
|
||||
public String input() throws Exception {
|
||||
return INPUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* A default implementation that does nothing an returns "success".
|
||||
*
|
||||
* <p>
|
||||
* Subclasses should override this method to provide their business logic.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* See also {@link Action#execute()}.
|
||||
* </p>
|
||||
*
|
||||
* @return returns {@link #SUCCESS}
|
||||
* @throws Exception can be thrown by subclasses.
|
||||
*/
|
||||
@Override
|
||||
public String execute() throws Exception {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActionErrors() {
|
||||
return validationAware.hasActionErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActionMessages() {
|
||||
return validationAware.hasActionMessages();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasErrors() {
|
||||
return validationAware.hasErrors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFieldErrors() {
|
||||
return validationAware.hasFieldErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears field errors. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearFieldErrors() {
|
||||
validationAware.clearFieldErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears action errors. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearActionErrors() {
|
||||
validationAware.clearActionErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears messages. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearMessages() {
|
||||
validationAware.clearMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all errors. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearErrors() {
|
||||
validationAware.clearErrors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all errors and messages. Useful for Continuations and other situations
|
||||
* where you might want to clear parts of the state on the same action.
|
||||
*/
|
||||
public void clearErrorsAndMessages() {
|
||||
validationAware.clearErrorsAndMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* A default implementation that validates nothing.
|
||||
* Subclasses should override this method to provide validations.
|
||||
*/
|
||||
@Override
|
||||
public void validate() {
|
||||
// A default implementation that validates nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: pause-method -->
|
||||
* Stops the action invocation immediately (by throwing a PauseException) and causes the action invocation to return
|
||||
* the specified result, such as {@link #SUCCESS}, {@link #INPUT}, etc.
|
||||
*
|
||||
* <p>
|
||||
* The next time this action is invoked (and using the same continuation ID), the method will resume immediately
|
||||
* after where this method was called, with the entire call stack in the execute method restored.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Note: this method can <b>only</b> be called within the {@link #execute()} method.
|
||||
* </p>
|
||||
*
|
||||
* <!-- END SNIPPET: pause-method -->
|
||||
*
|
||||
* @param result the result to return - the same type of return value in the {@link #execute()} method.
|
||||
*/
|
||||
public void pause(String result) {
|
||||
}
|
||||
|
||||
/**
|
||||
* If called first time it will create {@link TextProviderFactory},
|
||||
* inject dependency (if {@link Container} is accesible) into in,
|
||||
* then will create new {@link TextProvider} and store it in a field
|
||||
* for future references and at the returns reference to that field
|
||||
*
|
||||
* @return reference to field with TextProvider
|
||||
*/
|
||||
protected TextProvider getTextProvider() {
|
||||
if (textProvider == null) {
|
||||
final TextProviderFactory tpf = getContainer().getInstance(TextProviderFactory.class);
|
||||
textProvider = tpf.createInstance(getClass());
|
||||
}
|
||||
return textProvider;
|
||||
}
|
||||
|
||||
protected LocaleProvider getLocaleProvider() {
|
||||
if (localeProvider == null) {
|
||||
final LocaleProviderFactory localeProviderFactory = getContainer().getInstance(LocaleProviderFactory.class);
|
||||
localeProvider = localeProviderFactory.createLocaleProvider();
|
||||
}
|
||||
return localeProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: This a temporary solution, maybe we should consider stop injecting container into beans
|
||||
*/
|
||||
protected Container getContainer() {
|
||||
if (container == null) {
|
||||
container = ActionContext.getContext().getContainer();
|
||||
if (container != null) {
|
||||
boolean devMode = Boolean.parseBoolean(container.getInstance(String.class, StrutsConstants.STRUTS_DEVMODE));
|
||||
if (devMode) {
|
||||
LOG.warn("Container is null, action was created manually? Fallback to ActionContext");
|
||||
} else {
|
||||
LOG.debug("Container is null, action was created manually? Fallback to ActionContext");
|
||||
}
|
||||
} else {
|
||||
LOG.warn("Container is null, action was created out of ActionContext scope?!?");
|
||||
}
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setContainer(Container container) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.struts2.interceptor.parameter.StrutsParameter;
|
||||
|
||||
/**
|
||||
* ModelDriven Actions provide a model object to be pushed onto the ValueStack
|
||||
* in addition to the Action itself, allowing a FormBean type approach like Struts.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
*/
|
||||
public interface ModelDriven<T> {
|
||||
|
||||
/**
|
||||
* Gets the model to be pushed onto the ValueStack instead of the Action itself.
|
||||
* <p>
|
||||
* Please be aware that all setters and getters of every depth on the object returned by this method are available
|
||||
* for user parameter injection!
|
||||
*
|
||||
* @return the model
|
||||
*/
|
||||
@StrutsParameter(depth = Integer.MAX_VALUE)
|
||||
T getModel();
|
||||
|
||||
}
|
||||
@@ -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 org.apache.struts2;
|
||||
|
||||
/**
|
||||
* Preparable Actions will have their <code>prepare()</code> method called if the {@link com.opensymphony.xwork2.interceptor.PrepareInterceptor}
|
||||
* is applied to the ActionConfig.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @see com.opensymphony.xwork2.interceptor.PrepareInterceptor
|
||||
*/
|
||||
public interface Preparable {
|
||||
|
||||
/**
|
||||
* This method is called to allow the action to prepare itself.
|
||||
*
|
||||
* @throws Exception thrown if a system level exception occurs.
|
||||
*/
|
||||
void prepare() throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Simple marker interface to indicate an object should <b>not</b> have its properties copied during chaining.
|
||||
*
|
||||
* @see com.opensymphony.xwork2.interceptor.ChainingInterceptor
|
||||
*/
|
||||
public interface Unchainable {
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Provides an interface in which a call for a validation check can be done.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @see com.opensymphony.xwork2.ActionSupport
|
||||
* @see com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor
|
||||
*/
|
||||
public interface Validateable {
|
||||
|
||||
/**
|
||||
* Performs validation.
|
||||
*/
|
||||
void validate();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* All actions <b>may</b> implement this interface, which exposes the <code>execute()</code> method.
|
||||
* <p>
|
||||
* However, as of XWork 1.1, this is <b>not</b> required and is only here to assist users. You are free to create POJOs
|
||||
* that honor the same contract defined by this interface without actually implementing the interface.
|
||||
* </p>
|
||||
*/
|
||||
public interface Action {
|
||||
|
||||
/**
|
||||
* The action execution was successful. Show result
|
||||
* view to the end user.
|
||||
*/
|
||||
String SUCCESS = "success";
|
||||
|
||||
/**
|
||||
* The action execution was successful but do not
|
||||
* show a view. This is useful for actions that are
|
||||
* handling the view in another fashion like redirect.
|
||||
*/
|
||||
String NONE = "none";
|
||||
|
||||
/**
|
||||
* The action execution was a failure.
|
||||
* Show an error view, possibly asking the
|
||||
* user to retry entering data.
|
||||
*/
|
||||
String ERROR = "error";
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* The action execution require more input
|
||||
* in order to succeed.
|
||||
* This result is typically used if a form
|
||||
* handling action has been executed so as
|
||||
* to provide defaults for a form. The
|
||||
* form associated with the handler should be
|
||||
* shown to the end user.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This result is also used if the given input
|
||||
* params are invalid, meaning the user
|
||||
* should try providing input again.
|
||||
* </p>
|
||||
*/
|
||||
String INPUT = "input";
|
||||
|
||||
/**
|
||||
* The action could not execute, since the
|
||||
* user most was not logged in. The login view
|
||||
* should be shown.
|
||||
*/
|
||||
String LOGIN = "login";
|
||||
|
||||
|
||||
/**
|
||||
* Where the logic of the action is executed.
|
||||
*
|
||||
* @return a string representing the logical result of the execution.
|
||||
* See constants in this interface for a list of standard result values.
|
||||
* @throws Exception thrown if a system level exception occurs.
|
||||
* <b>Note:</b> Application level exceptions should be handled by returning
|
||||
* an error value, such as <code>Action.ERROR</code>.
|
||||
*/
|
||||
String execute() throws Exception;
|
||||
|
||||
}
|
||||
@@ -215,8 +215,8 @@ public class ActionComponent extends ContextBean {
|
||||
|
||||
HttpParameters.Builder builder = HttpParameters.create().withParent(parentParams);
|
||||
|
||||
if (parameters != null) {
|
||||
builder = builder.withExtraParams(parameters);
|
||||
if (getAttributes() != null) {
|
||||
builder = builder.withExtraParams(getAttributes());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@@ -71,6 +71,10 @@ public class Component {
|
||||
protected boolean devMode = false;
|
||||
protected boolean escapeHtmlBody = false;
|
||||
protected ValueStack stack;
|
||||
/**
|
||||
* @deprecated use {@link #getAttributes} instead of directly depending on this field
|
||||
*/
|
||||
@Deprecated
|
||||
protected Map<String, Object> parameters;
|
||||
protected ActionMapper actionMapper;
|
||||
protected boolean throwExceptionOnELFailure;
|
||||
@@ -279,7 +283,7 @@ public class Component {
|
||||
*/
|
||||
protected StrutsException fieldError(String field, String errorMsg, Exception e) {
|
||||
String msg = "tag '" + getComponentName() + "', field '" + field +
|
||||
(parameters != null && parameters.containsKey("name") ? "', name '" + parameters.get("name") : "") +
|
||||
(getAttributes() != null && getAttributes().containsKey("name") ? "', name '" + getAttributes().get("name") : "") +
|
||||
"': " + errorMsg;
|
||||
throw new StrutsException(msg, e);
|
||||
}
|
||||
@@ -457,7 +461,7 @@ public class Component {
|
||||
* @param params the parameters to copy.
|
||||
*/
|
||||
public void copyParams(Map<String, Object> params) {
|
||||
stack.push(parameters);
|
||||
stack.push(getAttributes());
|
||||
stack.push(this);
|
||||
try {
|
||||
for (Map.Entry<String, Object> entry : params.entrySet()) {
|
||||
@@ -467,7 +471,7 @@ public class Component {
|
||||
// UI component attributes may contain hypens (e.g. data-ajax), but ognl
|
||||
// can't handle that, and there can't be a component property with a hypen
|
||||
// so into the parameters map it goes. See WW-4493
|
||||
parameters.put(key, entry.getValue());
|
||||
getAttributes().put(key, entry.getValue());
|
||||
} else {
|
||||
stack.setValue(key, entry.getValue());
|
||||
}
|
||||
@@ -496,18 +500,29 @@ public class Component {
|
||||
* Gets the parameters.
|
||||
*
|
||||
* @return the parameters. Is never <tt>null</tt>.
|
||||
* @deprecated since 6.7.0, use {@link #getAttributes()} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public Map<String, Object> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parameters.
|
||||
*
|
||||
* @return the parameters. Is never <tt>null</tt>.
|
||||
*/
|
||||
public Map<String, Object> getAttributes() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all the given parameters to this component's own parameters.
|
||||
*
|
||||
* @param params the parameters to add.
|
||||
*/
|
||||
public void addAllParameters(Map<String, Object> params) {
|
||||
parameters.putAll(params);
|
||||
getAttributes().putAll(params);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -522,7 +537,7 @@ public class Component {
|
||||
*/
|
||||
public void addParameter(String key, Object value) {
|
||||
if (key != null) {
|
||||
Map<String, Object> params = getParameters();
|
||||
Map<String, Object> params = getAttributes();
|
||||
|
||||
if (value == null) {
|
||||
params.remove(key);
|
||||
|
||||
@@ -164,7 +164,7 @@ public abstract class DoubleListUIBean extends ListUIBean {
|
||||
// ok, let's look it up
|
||||
Component form = findAncestor(Form.class);
|
||||
if (form != null) {
|
||||
addParameter("formName", form.getParameters().get("name"));
|
||||
addParameter("formName", form.getAttributes().get("name"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ public abstract class DoubleListUIBean extends ListUIBean {
|
||||
if (doubleId != null) {
|
||||
addParameter("doubleId", findString(doubleId));
|
||||
} else if (form != null) {
|
||||
addParameter("doubleId", form.getParameters().get("id") + "_" + escape(doubleName != null ? findString(doubleName) : null));
|
||||
addParameter("doubleId", form.getAttributes().get("id") + "_" + escape(doubleName != null ? findString(doubleName) : null));
|
||||
} else {
|
||||
addParameter("doubleId", escape(doubleName != null ? findString(doubleName) : null));
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public class DoubleSelect extends DoubleListUIBean {
|
||||
public void evaluateExtraParams() {
|
||||
super.evaluateExtraParams();
|
||||
StringBuilder onchangeParam = new StringBuilder();
|
||||
onchangeParam.append(getParameters().get("id")).append("Redirect(this.selectedIndex)");
|
||||
onchangeParam.append(getAttributes().get("id")).append("Redirect(this.selectedIndex)");
|
||||
if(StringUtils.isNotEmpty(this.onchange)) {
|
||||
onchangeParam.append(";").append(this.onchange);
|
||||
}
|
||||
|
||||
@@ -68,13 +68,13 @@ public class File extends UIBean {
|
||||
|
||||
Form form = (Form) findAncestor(Form.class);
|
||||
if (form != null) {
|
||||
String encType = (String) form.getParameters().get("enctype");
|
||||
String encType = (String) form.getAttributes().get("enctype");
|
||||
if (!"multipart/form-data".equals(encType)) {
|
||||
// uh oh, this isn't good! Let's warn the developer
|
||||
LOG.warn("Struts has detected a file upload UI tag (s:file) being used without a form set to enctype 'multipart/form-data'. This is probably an error!");
|
||||
}
|
||||
|
||||
String method = (String) form.getParameters().get("method");
|
||||
String method = (String) form.getAttributes().get("method");
|
||||
if (!"post".equalsIgnoreCase(method)) {
|
||||
// uh oh, this isn't good! Let's warn the developer
|
||||
LOG.warn("Struts has detected a file upload UI tag (s:file) being used without a form set to method 'POST'. This is probably an error!");
|
||||
|
||||
@@ -172,7 +172,7 @@ public class Form extends ClosingUIBean {
|
||||
|
||||
if (name == null) {
|
||||
//make the name the same as the id
|
||||
String id = (String) getParameters().get("id");
|
||||
String id = (String) getAttributes().get("id");
|
||||
if (StringUtils.isNotEmpty(id)) {
|
||||
addParameter("name", id);
|
||||
}
|
||||
@@ -204,7 +204,7 @@ public class Form extends ClosingUIBean {
|
||||
|
||||
// keep a collection of the tag names for anything special the templates might want to do (such as pure client
|
||||
// side validation)
|
||||
if (!parameters.containsKey("tagNames")) {
|
||||
if (!getAttributes().containsKey("tagNames")) {
|
||||
// we have this if check so we don't do this twice (on open and close of the template)
|
||||
addParameter("tagNames", new ArrayList());
|
||||
}
|
||||
@@ -242,7 +242,7 @@ public class Form extends ClosingUIBean {
|
||||
protected void evaluateClientSideJsEnablement(String actionName, String namespace, String actionMethod) {
|
||||
|
||||
// Only evaluate if Client-Side js is to be enable when validate=true
|
||||
Boolean validate = (Boolean) getParameters().get("validate");
|
||||
Boolean validate = (Boolean) getAttributes().get("validate");
|
||||
if (validate != null && validate) {
|
||||
|
||||
addParameter("performValidation", Boolean.FALSE);
|
||||
@@ -270,7 +270,7 @@ public class Form extends ClosingUIBean {
|
||||
}
|
||||
|
||||
public List getValidators(String name) {
|
||||
Class actionClass = (Class) getParameters().get("actionClass");
|
||||
Class actionClass = (Class) getAttributes().get("actionClass");
|
||||
if (actionClass == null) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
@@ -279,7 +279,7 @@ public class Form extends ClosingUIBean {
|
||||
ActionMapping mapping = actionMapper.getMappingFromActionName(formActionValue);
|
||||
|
||||
if (mapping == null) {
|
||||
mapping = actionMapper.getMappingFromActionName((String) getParameters().get("actionName"));
|
||||
mapping = actionMapper.getMappingFromActionName((String) getAttributes().get("actionName"));
|
||||
}
|
||||
|
||||
if (mapping == null) {
|
||||
|
||||
@@ -58,7 +58,7 @@ public abstract class FormButton extends ClosingUIBean {
|
||||
addParameter("type", submitType);
|
||||
|
||||
if (!BUTTON_TYPE_INPUT.equals(submitType) && (label == null)) {
|
||||
addParameter("label", getParameters().get("nameValue"));
|
||||
addParameter("label", getAttributes().get("nameValue"));
|
||||
}
|
||||
|
||||
if (action != null || method != null) {
|
||||
@@ -101,8 +101,8 @@ public abstract class FormButton extends ClosingUIBean {
|
||||
// this check is needed for backwards compatibility with 2.1.x
|
||||
tmpId = findString(id);
|
||||
} else {
|
||||
if (form != null && form.getParameters().get("id") != null) {
|
||||
tmpId = tmpId + form.getParameters().get("id").toString() + "_";
|
||||
if (form != null && form.getAttributes().get("id") != null) {
|
||||
tmpId = tmpId + form.getAttributes().get("id").toString() + "_";
|
||||
}
|
||||
if (name != null) {
|
||||
tmpId = tmpId + escape(findString(name));
|
||||
|
||||
@@ -137,14 +137,13 @@ public class Include extends Component {
|
||||
urlBuf.append(page);
|
||||
|
||||
// Add request parameters
|
||||
if (parameters.size() > 0) {
|
||||
if (!getAttributes().isEmpty()) {
|
||||
urlBuf.append('?');
|
||||
|
||||
String concat = "";
|
||||
|
||||
// Set parameters
|
||||
for (Object next : parameters.entrySet()) {
|
||||
Map.Entry entry = (Map.Entry) next;
|
||||
for (Map.Entry<String, Object> entry : getAttributes().entrySet()) {
|
||||
Object name = entry.getKey();
|
||||
List values = (List) entry.getValue();
|
||||
|
||||
@@ -234,11 +233,11 @@ public class Include extends Component {
|
||||
// instead, include tag requires that each parameter be a list of objects,
|
||||
// just like the HTTP servlet interfaces are (String[])
|
||||
if (value != null) {
|
||||
List currentValues = (List) parameters.get(key);
|
||||
List currentValues = (List) getAttributes().get(key);
|
||||
|
||||
if (currentValues == null) {
|
||||
currentValues = new ArrayList();
|
||||
parameters.put(key, currentValues);
|
||||
getAttributes().put(key, currentValues);
|
||||
}
|
||||
|
||||
currentValues.add(value);
|
||||
|
||||
@@ -174,7 +174,7 @@ public class InputTransferSelect extends ListUIBean {
|
||||
|
||||
|
||||
// key -> select tag id, value -> headerKey (if exists)
|
||||
Map formInputtransferselectIds = (Map) formAncestor.getParameters().get("inputtransferselectIds");
|
||||
Map formInputtransferselectIds = (Map) formAncestor.getAttributes().get("inputtransferselectIds");
|
||||
|
||||
// init lists
|
||||
if (formInputtransferselectIds == null) {
|
||||
@@ -182,13 +182,13 @@ public class InputTransferSelect extends ListUIBean {
|
||||
}
|
||||
|
||||
// id
|
||||
String tmpId = (String) getParameters().get("id");
|
||||
String tmpHeaderKey = (String) getParameters().get("headerKey");
|
||||
String tmpId = (String) getAttributes().get("id");
|
||||
String tmpHeaderKey = (String) getAttributes().get("headerKey");
|
||||
if (tmpId != null && (! formInputtransferselectIds.containsKey(tmpId))) {
|
||||
formInputtransferselectIds.put(tmpId, tmpHeaderKey);
|
||||
}
|
||||
|
||||
formAncestor.getParameters().put("inputtransferselectIds", formInputtransferselectIds);
|
||||
formAncestor.getAttributes().put("inputtransferselectIds", formInputtransferselectIds);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -81,8 +81,8 @@ public class Label extends UIBean {
|
||||
if (value != null) {
|
||||
addParameter("nameValue", findString(value));
|
||||
} else if (key != null) {
|
||||
Object nameValue = parameters.get("nameValue");
|
||||
if (nameValue == null || nameValue.toString().length() == 0) {
|
||||
Object nameValue = getAttributes().get("nameValue");
|
||||
if (nameValue == null || nameValue.toString().isEmpty()) {
|
||||
// get the label from a TextProvider (default value is the key)
|
||||
String providedLabel = TextProviderHelper.getText(key, key, stack);
|
||||
addParameter("nameValue", providedLabel);
|
||||
|
||||
@@ -67,7 +67,7 @@ public abstract class ListUIBean extends UIBean {
|
||||
Object value = null;
|
||||
|
||||
if (list == null) {
|
||||
list = parameters.get("list");
|
||||
list = getAttributes().get("list");
|
||||
}
|
||||
|
||||
if (list instanceof String) {
|
||||
|
||||
@@ -90,7 +90,7 @@ public class OptGroup extends Component {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@Inject
|
||||
public void setContainer(Container container) {
|
||||
container.inject(internalUiBean);
|
||||
@@ -106,7 +106,7 @@ public class OptGroup extends Component {
|
||||
internalUiBean.start(writer);
|
||||
internalUiBean.end(writer, body);
|
||||
|
||||
List listUiBeans = (List) select.getParameters().get(INTERNAL_LIST_UI_BEAN_LIST_PARAMETER_KEY);
|
||||
List listUiBeans = (List) select.getAttributes().get(INTERNAL_LIST_UI_BEAN_LIST_PARAMETER_KEY);
|
||||
if (listUiBeans == null) {
|
||||
listUiBeans = new ArrayList();
|
||||
}
|
||||
|
||||
@@ -287,8 +287,8 @@ public class OptionTransferSelect extends DoubleListUIBean {
|
||||
|
||||
|
||||
// key -> select tag id, value -> headerKey (if exists)
|
||||
Map formOptiontransferselectIds = (Map) formAncestor.getParameters().get("optiontransferselectIds");
|
||||
Map formOptiontransferselectDoubleIds = (Map) formAncestor.getParameters().get("optiontransferselectDoubleIds");
|
||||
Map formOptiontransferselectIds = (Map) formAncestor.getAttributes().get("optiontransferselectIds");
|
||||
Map formOptiontransferselectDoubleIds = (Map) formAncestor.getAttributes().get("optiontransferselectDoubleIds");
|
||||
|
||||
// init lists
|
||||
if (formOptiontransferselectIds == null) {
|
||||
@@ -300,21 +300,21 @@ public class OptionTransferSelect extends DoubleListUIBean {
|
||||
|
||||
|
||||
// id
|
||||
String tmpId = (String) getParameters().get("id");
|
||||
String tmpHeaderKey = (String) getParameters().get("headerKey");
|
||||
String tmpId = (String) getAttributes().get("id");
|
||||
String tmpHeaderKey = (String) getAttributes().get("headerKey");
|
||||
if (tmpId != null && (! formOptiontransferselectIds.containsKey(tmpId))) {
|
||||
formOptiontransferselectIds.put(tmpId, tmpHeaderKey);
|
||||
}
|
||||
|
||||
// doubleId
|
||||
String tmpDoubleId = (String) getParameters().get("doubleId");
|
||||
String tmpDoubleHeaderKey = (String) getParameters().get("doubleHeaderKey");
|
||||
String tmpDoubleId = (String) getAttributes().get("doubleId");
|
||||
String tmpDoubleHeaderKey = (String) getAttributes().get("doubleHeaderKey");
|
||||
if (tmpDoubleId != null && (! formOptiontransferselectDoubleIds.containsKey(tmpDoubleId))) {
|
||||
formOptiontransferselectDoubleIds.put(tmpDoubleId, tmpDoubleHeaderKey);
|
||||
}
|
||||
|
||||
formAncestor.getParameters().put("optiontransferselectIds", formOptiontransferselectIds);
|
||||
formAncestor.getParameters().put("optiontransferselectDoubleIds", formOptiontransferselectDoubleIds);
|
||||
formAncestor.getAttributes().put("optiontransferselectIds", formOptiontransferselectIds);
|
||||
formAncestor.getAttributes().put("optiontransferselectDoubleIds", formOptiontransferselectDoubleIds);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -174,7 +174,7 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
namespace, actionName);
|
||||
if (actionConfig != null) {
|
||||
|
||||
ActionMapping mapping = new ActionMapping(actionName, namespace, actionMethod, formComponent.parameters);
|
||||
ActionMapping mapping = new ActionMapping(actionName, namespace, actionMethod, formComponent.getAttributes());
|
||||
String result = urlHelper.buildUrl(formComponent.actionMapper.getUriFromActionMapping(mapping),
|
||||
formComponent.request, formComponent.response, queryStringResult.getQueryParams(), scheme, formComponent.includeContext, true, false, false);
|
||||
formComponent.addParameter("action", result);
|
||||
|
||||
@@ -73,7 +73,7 @@ public class Token extends UIBean {
|
||||
super.evaluateExtraParams();
|
||||
|
||||
String tokenName;
|
||||
Map parameters = getParameters();
|
||||
Map parameters = getAttributes();
|
||||
|
||||
if (parameters.containsKey("name")) {
|
||||
tokenName = (String) parameters.get("name");
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
@@ -32,6 +31,7 @@ import org.apache.struts2.components.template.Template;
|
||||
import org.apache.struts2.components.template.TemplateEngine;
|
||||
import org.apache.struts2.components.template.TemplateEngineManager;
|
||||
import org.apache.struts2.components.template.TemplateRenderingContext;
|
||||
import org.apache.struts2.dispatcher.AttributeMap;
|
||||
import org.apache.struts2.dispatcher.StaticContentLoader;
|
||||
import org.apache.struts2.util.ComponentUtils;
|
||||
import org.apache.struts2.util.TextProviderHelper;
|
||||
@@ -48,6 +48,10 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.struts2.dispatcher.DispatcherConstants.ATTRIBUTES;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* UIBean is the standard superclass of all Struts UI components.
|
||||
@@ -440,6 +444,9 @@ public abstract class UIBean extends Component {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(UIBean.class);
|
||||
|
||||
static final String TEMPLATE_DIR = "templateDir";
|
||||
static final String THEME = "theme";
|
||||
|
||||
protected static final String ATTR_FIELD_VALUE = "fieldValue";
|
||||
protected static final String ATTR_NAME_VALUE = "nameValue";
|
||||
protected static final String ATTR_VALUE = "value";
|
||||
@@ -591,7 +598,7 @@ public abstract class UIBean extends Component {
|
||||
|
||||
LOG.debug("Rendering template {}", template);
|
||||
|
||||
final TemplateRenderingContext context = new TemplateRenderingContext(template, writer, getStack(), getParameters(), this);
|
||||
final TemplateRenderingContext context = new TemplateRenderingContext(template, writer, getStack(), getAttributes(), this);
|
||||
engine.renderTemplate(context);
|
||||
}
|
||||
|
||||
@@ -602,13 +609,18 @@ public abstract class UIBean extends Component {
|
||||
result = findString(this.templateDir);
|
||||
}
|
||||
|
||||
// Check Request, Session, Application scopes
|
||||
if (isBlank(result)) {
|
||||
result = (String) getAttrMap().get(TEMPLATE_DIR);
|
||||
}
|
||||
|
||||
// Default template set
|
||||
if (StringUtils.isBlank(result)) {
|
||||
if (isBlank(result)) {
|
||||
result = defaultTemplateDir;
|
||||
}
|
||||
|
||||
// Defaults to 'template'
|
||||
if (StringUtils.isBlank(result)) {
|
||||
if (isBlank(result)) {
|
||||
result = "template";
|
||||
}
|
||||
|
||||
@@ -622,26 +634,36 @@ public abstract class UIBean extends Component {
|
||||
result = findString(this.theme);
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(result)) {
|
||||
if (isBlank(result)) {
|
||||
Form form = (Form) findAncestor(Form.class);
|
||||
if (form != null) {
|
||||
result = form.getTheme();
|
||||
}
|
||||
}
|
||||
|
||||
// Check Request, Session, Application scopes
|
||||
if (isBlank(result)) {
|
||||
result = (String) getAttrMap().get(THEME);
|
||||
}
|
||||
|
||||
// Default theme set
|
||||
if (StringUtils.isBlank(result)) {
|
||||
if (isBlank(result)) {
|
||||
result = defaultUITheme;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, Object> getAttrMap() {
|
||||
AttributeMap attrMap = (AttributeMap) getStack().getContext().get(ATTRIBUTES);
|
||||
return attrMap != null ? attrMap : emptyMap();
|
||||
}
|
||||
|
||||
public void evaluateParams() {
|
||||
String gotTheme = getTheme();
|
||||
|
||||
addParameter("templateDir", getTemplateDir());
|
||||
addParameter("theme", gotTheme);
|
||||
addParameter(TEMPLATE_DIR, getTemplateDir());
|
||||
addParameter(THEME, gotTheme);
|
||||
addParameter("template", template != null ? findString(template) : getDefaultTemplate());
|
||||
addParameter("dynamicAttributes", dynamicAttributes);
|
||||
addParameter("themeExpansionToken", uiThemeExpansionToken);
|
||||
@@ -655,7 +677,7 @@ public abstract class UIBean extends Component {
|
||||
if (this.key != null) {
|
||||
|
||||
if(this.name == null) {
|
||||
this.name = key;
|
||||
setName(key);
|
||||
}
|
||||
|
||||
if(this.label == null) {
|
||||
@@ -797,11 +819,11 @@ public abstract class UIBean extends Component {
|
||||
populateComponentHtmlId(form);
|
||||
|
||||
if (form != null ) {
|
||||
addParameter("form", form.getParameters());
|
||||
addParameter("form", form.getAttributes());
|
||||
|
||||
if ( translatedName != null ) {
|
||||
// list should have been created by the form component
|
||||
List<String> tags = (List<String>) form.getParameters().get("tagNames");
|
||||
List<String> tags = (List<String>) form.getAttributes().get("tagNames");
|
||||
tags.add(translatedName);
|
||||
}
|
||||
}
|
||||
@@ -833,19 +855,19 @@ public abstract class UIBean extends Component {
|
||||
}
|
||||
|
||||
//TODO: this is to keep backward compatibility, remove once when tooltipConfig is dropped
|
||||
String jsTooltipEnabled = (String) getParameters().get("jsTooltipEnabled");
|
||||
String jsTooltipEnabled = (String) getAttributes().get("jsTooltipEnabled");
|
||||
if (jsTooltipEnabled != null)
|
||||
this.javascriptTooltip = jsTooltipEnabled;
|
||||
|
||||
//TODO: this is to keep backward compatibility, remove once when tooltipConfig is dropped
|
||||
String tooltipIcon = (String) getParameters().get("tooltipIcon");
|
||||
String tooltipIcon = (String) getAttributes().get("tooltipIcon");
|
||||
if (tooltipIcon != null)
|
||||
this.addParameter("tooltipIconPath", tooltipIcon);
|
||||
if (this.tooltipIconPath != null)
|
||||
this.addParameter("tooltipIconPath", findString(this.tooltipIconPath));
|
||||
|
||||
//TODO: this is to keep backward compatibility, remove once when tooltipConfig is dropped
|
||||
String tooltipDelayParam = (String) getParameters().get("tooltipDelay");
|
||||
String tooltipDelayParam = (String) getAttributes().get("tooltipDelay");
|
||||
if (tooltipDelayParam != null)
|
||||
this.addParameter("tooltipDelay", tooltipDelayParam);
|
||||
if (this.tooltipDelay != null)
|
||||
@@ -882,8 +904,8 @@ public abstract class UIBean extends Component {
|
||||
*/
|
||||
protected void applyValueParameter(String translatedName) {
|
||||
// see if the value has been specified as a parameter already
|
||||
if (parameters.containsKey(ATTR_VALUE)) {
|
||||
parameters.put(ATTR_NAME_VALUE, parameters.get(ATTR_VALUE));
|
||||
if (getAttributes().containsKey(ATTR_VALUE)) {
|
||||
getAttributes().put(ATTR_NAME_VALUE, getAttributes().get(ATTR_VALUE));
|
||||
} else {
|
||||
if (evaluateNameValue()) {
|
||||
final Class<?> valueClazz = getValueClassType();
|
||||
@@ -969,7 +991,7 @@ public abstract class UIBean extends Component {
|
||||
}
|
||||
|
||||
protected Map<String, String> getTooltipConfig(UIBean component) {
|
||||
Object tooltipConfigObj = component.getParameters().get("tooltipConfig");
|
||||
Object tooltipConfigObj = component.getAttributes().get("tooltipConfig");
|
||||
Map<String, String> result = new LinkedHashMap<>();
|
||||
|
||||
if (tooltipConfigObj instanceof Map) {
|
||||
@@ -1030,7 +1052,7 @@ public abstract class UIBean extends Component {
|
||||
LOG.debug("Cannot determine id attribute for [{}], consider defining id, name or key attribute!", this);
|
||||
tryId = null;
|
||||
} else if (form != null) {
|
||||
tryId = form.getParameters().get("id") + "_" + generatedId;
|
||||
tryId = form.getAttributes().get("id") + "_" + generatedId;
|
||||
} else {
|
||||
tryId = generatedId;
|
||||
}
|
||||
@@ -1137,6 +1159,13 @@ public abstract class UIBean extends Component {
|
||||
|
||||
@StrutsTagAttribute(description="The name to set for element")
|
||||
public void setName(String name) {
|
||||
if (name != null && name.startsWith("$")) {
|
||||
LOG.error("The name attribute should not usually be a templating variable." +
|
||||
" This can cause a critical vulnerability if the resolved value is derived from user input." +
|
||||
" If you are certain that you require this behaviour, please use OGNL expression syntax ( %{expr} ) instead.",
|
||||
new IllegalStateException());
|
||||
return;
|
||||
}
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ public class URL extends ContextBean {
|
||||
|
||||
public URL(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
|
||||
super(stack);
|
||||
urlProvider = new ComponentUrlProvider(this, this.parameters);
|
||||
urlProvider = new ComponentUrlProvider(this, this.getAttributes());
|
||||
urlProvider.setHttpServletRequest(req);
|
||||
urlProvider.setHttpServletResponse(res);
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ import java.util.Map;
|
||||
* {@literal @}s.tag name="updownselect" tld-body-content="JSP" tld-tag-class="org.apache.struts2.views.jsp.ui.UpDownSelectTag"
|
||||
* description="Render a up down select element"
|
||||
*/
|
||||
@StrutsTag(name="updownselect", tldTagClass="org.apache.struts2.views.jsp.ui.UpDownSelectTag",
|
||||
@StrutsTag(name="updownselect", tldTagClass="org.apache.struts2.views.jsp.ui.UpDownSelectTag",
|
||||
description="Create a Select component with buttons to move the elements in the select component up and down")
|
||||
public class UpDownSelect extends Select {
|
||||
|
||||
@@ -136,13 +136,13 @@ public class UpDownSelect extends Select {
|
||||
// inform form ancestor that we are using a custom onSubmit
|
||||
enableAncestorFormCustomOnsubmit();
|
||||
|
||||
Map m = (Map) ancestorForm.getParameters().get("updownselectIds");
|
||||
Map m = (Map) ancestorForm.getAttributes().get("updownselectIds");
|
||||
if (m == null) {
|
||||
// map with key -> id , value -> headerKey
|
||||
m = new LinkedHashMap();
|
||||
}
|
||||
m.put(getParameters().get("id"), getParameters().get("headerKey"));
|
||||
ancestorForm.getParameters().put("updownselectIds", m);
|
||||
m.put(getAttributes().get("id"), getAttributes().get("headerKey"));
|
||||
ancestorForm.getAttributes().put("updownselectIds", m);
|
||||
}
|
||||
else {
|
||||
if (LOG.isWarnEnabled()) {
|
||||
|
||||
@@ -112,7 +112,7 @@ public class Dispatcher {
|
||||
*/
|
||||
public static final String REQUEST_POST_METHOD = "POST";
|
||||
|
||||
public static final String MULTIPART_FORM_DATA_REGEX = "^multipart/form-data(?:\\s*;\\s*boundary=[0-9a-zA-Z'()+_,\\-./:=?]{1,70})?(?:\\s*;\\s*charset=[a-zA-Z\\-0-9]{3,14})?";
|
||||
public static final String MULTIPART_FORM_DATA_REGEX = "^multipart/form-data(?:\\s*;\\s*boundary=[0-9a-zA-Z'\"()+_,\\-./:=?]{1,70})?(?:\\s*;\\s*charset=[a-zA-Z\\-0-9]{3,14})?";
|
||||
|
||||
private static final String CONFIG_SPLIT_REGEX = "\\s*,\\s*";
|
||||
|
||||
@@ -734,7 +734,7 @@ public class Dispatcher {
|
||||
// if the ActionMapping says to go straight to a result, do it!
|
||||
if (mapping.getResult() != null) {
|
||||
Result result = mapping.getResult();
|
||||
result.execute(proxy.getInvocation());
|
||||
result.execute((org.apache.struts2.ActionInvocation) proxy.getInvocation());
|
||||
} else {
|
||||
proxy.execute();
|
||||
}
|
||||
|
||||
+23
-4
@@ -20,6 +20,8 @@ package org.apache.struts2.dispatcher.multipart;
|
||||
|
||||
import com.opensymphony.xwork2.LocaleProviderFactory;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.security.DefaultExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
@@ -38,13 +40,15 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(AbstractMultiPartRequest.class);
|
||||
|
||||
private static final String EXCLUDED_FILE_PATTERN = ".*[<>&\"'|;\\\\/?*:]+.*|.*\\.\\..*";
|
||||
|
||||
/**
|
||||
* Defines the internal buffer size used during streaming operations.
|
||||
*/
|
||||
public static final int BUFFER_SIZE = 10240;
|
||||
|
||||
/**
|
||||
* Internal list of raised errors to be passed to the the Struts2 framework.
|
||||
* Internal list of raised errors to be passed to the Struts2 framework.
|
||||
*/
|
||||
protected List<LocalizedMessage> errors = new ArrayList<>();
|
||||
|
||||
@@ -80,6 +84,13 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
*/
|
||||
protected Locale defaultLocale = Locale.ENGLISH;
|
||||
|
||||
private final ExcludedPatternsChecker patternsChecker;
|
||||
|
||||
public AbstractMultiPartRequest() {
|
||||
patternsChecker = new DefaultExcludedPatternsChecker();
|
||||
((DefaultExcludedPatternsChecker) patternsChecker).setAdditionalExcludePatterns(EXCLUDED_FILE_PATTERN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bufferSize Sets the buffer size to be used.
|
||||
*/
|
||||
@@ -123,7 +134,7 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
|
||||
/**
|
||||
* @param request Inspect the servlet request and set the locale if one wasn't provided by
|
||||
* the Struts2 framework.
|
||||
* the Struts2 framework.
|
||||
*/
|
||||
protected void setLocale(HttpServletRequest request) {
|
||||
if (defaultLocale == null) {
|
||||
@@ -134,7 +145,7 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
/**
|
||||
* Build error message.
|
||||
*
|
||||
* @param e the Throwable/Exception
|
||||
* @param e the Throwable/Exception
|
||||
* @param args arguments
|
||||
* @return error message
|
||||
*/
|
||||
@@ -147,7 +158,7 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getErrors()
|
||||
*/
|
||||
*/
|
||||
public List<LocalizedMessage> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
@@ -169,4 +180,12 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileName file name to check
|
||||
* @return true if the file name is excluded
|
||||
*/
|
||||
protected boolean isExcluded(String fileName) {
|
||||
return patternsChecker.isExcluded(fileName).isExcluded();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+22
-8
@@ -44,6 +44,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.normalizeSpace;
|
||||
|
||||
/**
|
||||
* Multipart form data request adapter for Jakarta Commons Fileupload package.
|
||||
*/
|
||||
@@ -100,7 +102,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
protected void processUpload(HttpServletRequest request, String saveDir) throws FileUploadException, UnsupportedEncodingException {
|
||||
if (ServletFileUpload.isMultipartContent(request)) {
|
||||
for (FileItem item : parseRequest(request, saveDir)) {
|
||||
LOG.debug("Found file item: [{}]", sanitizeNewlines(item.getFieldName()));
|
||||
LOG.debug("Found file item: [{}]", normalizeSpace(item.getFieldName()));
|
||||
if (item.isFormField()) {
|
||||
processNormalFormField(item, request.getCharacterEncoding());
|
||||
} else {
|
||||
@@ -113,9 +115,19 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
protected void processFileField(FileItem item) {
|
||||
LOG.debug("Item is a file upload");
|
||||
|
||||
if (isExcluded(item.getName())) {
|
||||
LOG.warn("File name [{}] is not accepted", normalizeSpace(item.getName()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExcluded(item.getFieldName())) {
|
||||
LOG.warn("Field name [{}] is not accepted", normalizeSpace(item.getFieldName()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip file uploads that don't have a file name - meaning that no file was selected.
|
||||
if (item.getName() == null || item.getName().trim().isEmpty()) {
|
||||
LOG.debug("No file has been uploaded for the field: {}", sanitizeNewlines(item.getFieldName()));
|
||||
LOG.debug("No file has been uploaded for the field: {}", normalizeSpace(item.getFieldName()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -134,6 +146,11 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
try {
|
||||
LOG.debug("Item is a normal form field");
|
||||
|
||||
if (isExcluded(item.getFieldName())) {
|
||||
LOG.warn("Form field name [{}] is not accepted", normalizeSpace(item.getFieldName()));
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> values;
|
||||
if (params.get(item.getFieldName()) != null) {
|
||||
values = params.get(item.getFieldName());
|
||||
@@ -142,8 +159,8 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
}
|
||||
|
||||
long size = item.getSize();
|
||||
if (size > maxStringLength) {
|
||||
LOG.debug("Form field {} of size {} bytes exceeds limit of {}.", sanitizeNewlines(item.getFieldName()), size, maxStringLength);
|
||||
if (maxStringLength != null && size > maxStringLength) {
|
||||
LOG.debug("Form field [{}] of size [{}] bytes exceeds limit of [{}].", normalizeSpace(item.getFieldName()), size, maxStringLength);
|
||||
String errorKey = "struts.messages.upload.error.parameter.too.long";
|
||||
LocalizedMessage localizedMessage = new LocalizedMessage(this.getClass(), errorKey, null,
|
||||
new Object[]{item.getFieldName(), maxStringLength, size});
|
||||
@@ -359,7 +376,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
for (String name : names) {
|
||||
List<FileItem> items = files.get(name);
|
||||
for (FileItem item : items) {
|
||||
LOG.debug("Removing file {} {}", name, item);
|
||||
LOG.debug("Removing file [{}]", normalizeSpace(name));
|
||||
if (!item.isInMemory()) {
|
||||
item.delete();
|
||||
}
|
||||
@@ -367,7 +384,4 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
}
|
||||
}
|
||||
|
||||
private String sanitizeNewlines(String before) {
|
||||
return before.replaceAll("[\n\r]", "_");
|
||||
}
|
||||
}
|
||||
|
||||
+20
-7
@@ -45,6 +45,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.normalizeSpace;
|
||||
|
||||
/**
|
||||
* Multi-part form data request adapter for Jakarta Commons FileUpload package that
|
||||
* leverages the streaming API rather than the traditional non-streaming API.
|
||||
@@ -77,7 +79,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
File file = fileInfo.getFile();
|
||||
LOG.debug("Deleting file '{}'.", file.getName());
|
||||
if (!file.delete()) {
|
||||
LOG.warn("There was a problem attempting to delete file '{}'.", file.getName());
|
||||
LOG.warn("There was a problem attempting to delete file [{}].", file.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,7 +254,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
// prevent processing file field item if request size not allowed.
|
||||
if (!requestSizePermitted) {
|
||||
addFileSkippedError(itemStream.getName(), request);
|
||||
LOG.debug("Skipped stream '{}', request maximum size ({}) exceeded.", itemStream.getName(), maxSize);
|
||||
LOG.debug("Skipped stream [{}], request maximum size ({}) exceeded.", normalizeSpace(itemStream.getName()), maxSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -296,7 +298,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
* @param request the servlet request
|
||||
*/
|
||||
protected void addFileSkippedError(String fileName, HttpServletRequest request) {
|
||||
String exceptionMessage = "Skipped file " + fileName + "; request size limit exceeded.";
|
||||
String exceptionMessage = "Skipped file " + normalizeSpace(fileName) + "; request size limit exceeded.";
|
||||
long allowedMaxSize = maxSize != null ? maxSize : -1;
|
||||
FileSizeLimitExceededException exception = new FileUploadBase.FileSizeLimitExceededException(exceptionMessage, getRequestSize(request), allowedMaxSize);
|
||||
LocalizedMessage message = buildErrorMessage(exception, new Object[]{fileName, getRequestSize(request), allowedMaxSize});
|
||||
@@ -312,6 +314,10 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
*/
|
||||
protected void processFileItemStreamAsFormField(FileItemStream itemStream) {
|
||||
String fieldName = itemStream.getFieldName();
|
||||
if (isExcluded(fieldName)) {
|
||||
LOG.warn("Form field [{}] rejected!", normalizeSpace(fieldName));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
List<String> values;
|
||||
String fieldValue = Streams.asString(itemStream.openStream());
|
||||
@@ -323,7 +329,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
}
|
||||
values.add(fieldValue);
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Failed to handle form field '{}'.", fieldName, e);
|
||||
LOG.warn("Failed to handle form field [{}]", normalizeSpace(fieldName), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +342,12 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
protected void processFileItemStreamAsFileField(FileItemStream itemStream, String location) {
|
||||
// Skip file uploads that don't have a file name - meaning that no file was selected.
|
||||
if (itemStream.getName() == null || itemStream.getName().trim().isEmpty()) {
|
||||
LOG.debug("No file has been uploaded for the field: {}", itemStream.getFieldName());
|
||||
LOG.debug("No file has been uploaded for the field: {}", normalizeSpace(itemStream.getFieldName()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExcluded(itemStream.getName())) {
|
||||
LOG.warn("File field [{}] rejected", normalizeSpace(itemStream.getName()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -353,7 +364,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
try {
|
||||
file.delete();
|
||||
} catch (SecurityException se) {
|
||||
LOG.warn("Failed to delete '{}' due to security exception above.", file.getName(), se);
|
||||
LOG.warn("Failed to delete [{}] due to security exception above.", normalizeSpace(file.getName()), se);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -385,7 +396,9 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
}
|
||||
|
||||
File file = File.createTempFile(prefix + "_", suffix, new File(location));
|
||||
LOG.debug("Creating temporary file '{}' (originally '{}').", file.getName(), fileName);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Creating temporary file [{}] (originally [{}]).", file.getName(), normalizeSpace(fileName));
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,13 +20,14 @@ package org.apache.struts2.factory;
|
||||
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.Result;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.factory.ResultFactory;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.result.ParamNameAwareResult;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionException;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionExceptionHandler;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
import com.opensymphony.xwork2.result.ParamNameAwareResult;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -53,16 +54,36 @@ public class StrutsResultFactory implements ResultFactory {
|
||||
Result result = null;
|
||||
|
||||
if (resultClassName != null) {
|
||||
result = (Result) objectFactory.buildBean(resultClassName, extraContext);
|
||||
Object o = objectFactory.buildBean(resultClassName, extraContext);
|
||||
Map<String, String> params = resultConfig.getParams();
|
||||
if (params != null) {
|
||||
setParameters(extraContext, result, params);
|
||||
setParameters(extraContext, o, params);
|
||||
}
|
||||
if (o instanceof Result) {
|
||||
result = (Result) o;
|
||||
} else if (o instanceof org.apache.struts2.result.Result) {
|
||||
result = Result.adapt((org.apache.struts2.result.Result) o);
|
||||
}
|
||||
if (result == null) {
|
||||
throw new ConfigurationException("Class [" + resultClassName + "] does not implement Result", resultConfig);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void setParameters(Map<String, Object> extraContext, Result result, Map<String, String> params) {
|
||||
setParametersHelper(extraContext, result, params);
|
||||
}
|
||||
|
||||
protected void setParameters(Map<String, Object> extraContext, Object result, Map<String, String> params) {
|
||||
if (result instanceof Result) {
|
||||
setParameters(extraContext, (Result) result, params);
|
||||
} else {
|
||||
setParametersHelper(extraContext, result, params);
|
||||
}
|
||||
}
|
||||
|
||||
private void setParametersHelper(Map<String, Object> extraContext, Object result, Map<String, String> params) {
|
||||
for (Map.Entry<String, String> paramEntry : params.entrySet()) {
|
||||
try {
|
||||
String name = paramEntry.getKey();
|
||||
@@ -77,6 +98,18 @@ public class StrutsResultFactory implements ResultFactory {
|
||||
}
|
||||
|
||||
protected void setParameter(Result result, String name, String value, Map<String, Object> extraContext) {
|
||||
setParameterHelper(result, name, value, extraContext);
|
||||
}
|
||||
|
||||
private void setParameter(Object result, String name, String value, Map<String, Object> extraContext) {
|
||||
if (result instanceof Result) {
|
||||
setParameter((Result) result, name, value, extraContext);
|
||||
} else {
|
||||
setParameterHelper(result, name, value, extraContext);
|
||||
}
|
||||
}
|
||||
|
||||
private void setParameterHelper(Object result, String name, String value, Map<String, Object> extraContext) {
|
||||
if (result instanceof ParamNameAwareResult) {
|
||||
if (((ParamNameAwareResult) result).acceptableParameterName(name, value)) {
|
||||
reflectionProvider.setProperty(name, value, result, extraContext, true);
|
||||
@@ -85,5 +118,4 @@ public class StrutsResultFactory implements ResultFactory {
|
||||
reflectionProvider.setProperty(name, value, result, extraContext, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.opensymphony.xwork2.TextProviderFactory;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
|
||||
/**
|
||||
* Provides default implementations of optional lifecycle methods
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ package org.apache.struts2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ActionProxy;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.action.UploadedFilesAware;
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.LocalizedTextProvider;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.ParametersInterceptor;
|
||||
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.ExcludedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.ClearableValueStack;
|
||||
import com.opensymphony.xwork2.util.Evaluated;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ActionContext;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
*
|
||||
* The aim of this Interceptor is to alias a named parameter to a different named parameter. By acting as the glue
|
||||
* between actions sharing similar parameters (but with different names), it can help greatly with action chaining.
|
||||
*
|
||||
* <p>Action's alias expressions should be in the form of <code>#{ "name1" : "alias1", "name2" : "alias2" }</code>.
|
||||
* This means that assuming an action (or something else in the stack) has a value for the expression named <i>name1</i> and the
|
||||
* action this interceptor is applied to has a setter named <i>alias1</i>, <i>alias1</i> will be set with the value from
|
||||
* <i>name1</i>.
|
||||
* </p>
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <p><u>Interceptor parameters:</u></p>
|
||||
*
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li>aliasesKey (optional) - the name of the action parameter to look for the alias map (by default this is
|
||||
* <i>aliases</i>).</li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
*
|
||||
* <p><u>Extending the interceptor:</u></p>
|
||||
*
|
||||
* <!-- START SNIPPET: extending -->
|
||||
*
|
||||
* This interceptor does not have any known extension points.
|
||||
*
|
||||
* <!-- END SNIPPET: extending -->
|
||||
*
|
||||
* <p><u>Example code:</u></p>
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
* <!-- The value for the foo parameter will be applied as if it were named bar -->
|
||||
* <param name="aliases">#{ 'foo' : 'bar' }</param>
|
||||
*
|
||||
* <interceptor-ref name="alias"/>
|
||||
* <interceptor-ref name="basicStack"/>
|
||||
* <result name="success">good_result.ftl</result>
|
||||
* </action>
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
* @author Matthew Payne
|
||||
*/
|
||||
public class AliasInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(AliasInterceptor.class);
|
||||
|
||||
private static final String DEFAULT_ALIAS_KEY = "aliases";
|
||||
protected String aliasesKey = DEFAULT_ALIAS_KEY;
|
||||
|
||||
protected ValueStackFactory valueStackFactory;
|
||||
protected LocalizedTextProvider localizedTextProvider;
|
||||
protected boolean devMode = false;
|
||||
|
||||
private ExcludedPatternsChecker excludedPatterns;
|
||||
private AcceptedPatternsChecker acceptedPatterns;
|
||||
|
||||
@Inject(StrutsConstants.STRUTS_DEVMODE)
|
||||
public void setDevMode(String mode) {
|
||||
this.devMode = Boolean.parseBoolean(mode);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setValueStackFactory(ValueStackFactory valueStackFactory) {
|
||||
this.valueStackFactory = valueStackFactory;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setLocalizedTextProvider(LocalizedTextProvider localizedTextProvider) {
|
||||
this.localizedTextProvider = localizedTextProvider;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setExcludedPatterns(ExcludedPatternsChecker excludedPatterns) {
|
||||
this.excludedPatterns = excludedPatterns;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setAcceptedPatterns(AcceptedPatternsChecker acceptedPatterns) {
|
||||
this.acceptedPatterns = acceptedPatterns;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Sets the name of the action parameter to look for the alias map.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Default is <code>aliases</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param aliasesKey the name of the action parameter
|
||||
*/
|
||||
public void setAliasesKey(String aliasesKey) {
|
||||
this.aliasesKey = aliasesKey;
|
||||
}
|
||||
|
||||
@Override public String intercept(ActionInvocation invocation) throws Exception {
|
||||
|
||||
ActionConfig config = invocation.getProxy().getConfig();
|
||||
ActionContext ac = invocation.getInvocationContext();
|
||||
Object action = invocation.getAction();
|
||||
|
||||
// get the action's parameters
|
||||
final Map<String, String> parameters = config.getParams();
|
||||
|
||||
if (parameters.containsKey(aliasesKey)) {
|
||||
|
||||
String aliasExpression = parameters.get(aliasesKey);
|
||||
ValueStack stack = ac.getValueStack();
|
||||
Object obj = stack.findValue(aliasExpression);
|
||||
|
||||
if (obj instanceof Map) {
|
||||
//get secure stack
|
||||
ValueStack newStack = valueStackFactory.createValueStack(com.opensymphony.xwork2.util.ValueStack.adapt(stack));
|
||||
boolean clearableStack = newStack instanceof ClearableValueStack;
|
||||
if (clearableStack) {
|
||||
//if the stack's context can be cleared, do that to prevent OGNL
|
||||
//from having access to objects in the stack, see XW-641
|
||||
((ClearableValueStack)newStack).clearContextValues();
|
||||
Map<String, Object> context = newStack.getContext();
|
||||
ReflectionContextState.setCreatingNullObjects(context, true);
|
||||
ReflectionContextState.setDenyMethodExecution(context, true);
|
||||
ReflectionContextState.setReportingConversionErrors(context, true);
|
||||
|
||||
//keep locale from original context
|
||||
newStack.getActionContext().withLocale(stack.getActionContext().getLocale());
|
||||
}
|
||||
|
||||
// override
|
||||
Map aliases = (Map) obj;
|
||||
for (Object o : aliases.entrySet()) {
|
||||
Map.Entry entry = (Map.Entry) o;
|
||||
String name = entry.getKey().toString();
|
||||
if (isNotAcceptableExpression(name)) {
|
||||
continue;
|
||||
}
|
||||
String alias = (String) entry.getValue();
|
||||
if (isNotAcceptableExpression(alias)) {
|
||||
continue;
|
||||
}
|
||||
Evaluated value = new Evaluated(stack.findValue(name));
|
||||
if (!value.isDefined()) {
|
||||
// workaround
|
||||
HttpParameters contextParameters = ActionContext.getContext().getParameters();
|
||||
|
||||
if (null != contextParameters) {
|
||||
Parameter param = contextParameters.get(name);
|
||||
if (param.isDefined()) {
|
||||
value = new Evaluated(param.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (value.isDefined()) {
|
||||
try {
|
||||
newStack.setValue(alias, value.get());
|
||||
} catch (RuntimeException e) {
|
||||
if (devMode) {
|
||||
String developerNotification = localizedTextProvider.findText(ParametersInterceptor.class, "devmode.notification", ActionContext.getContext().getLocale(), "Developer Notification:\n{0}", new Object[]{
|
||||
"Unexpected Exception caught setting '" + entry.getKey() + "' on '" + action.getClass() + ": " + e.getMessage()
|
||||
});
|
||||
LOG.error(developerNotification);
|
||||
if (action instanceof ValidationAware) {
|
||||
((ValidationAware) action).addActionMessage(developerNotification);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clearableStack) {
|
||||
stack.getActionContext().withConversionErrors(newStack.getActionContext().getConversionErrors());
|
||||
}
|
||||
} else {
|
||||
LOG.debug("invalid alias expression: {}", aliasesKey);
|
||||
}
|
||||
}
|
||||
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
protected boolean isAccepted(String paramName) {
|
||||
AcceptedPatternsChecker.IsAccepted result = acceptedPatterns.isAccepted(paramName);
|
||||
if (result.isAccepted()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isExcluded(String paramName) {
|
||||
ExcludedPatternsChecker.IsExcluded result = excludedPatterns.isExcluded(paramName);
|
||||
if (!result.isExcluded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG.warn("Parameter [{}] matches excluded pattern [{}]! See Accepted / Excluded patterns at\n" +
|
||||
"https://struts.apache.org/security/#accepted--excluded-patterns",
|
||||
paramName, result.getExcludedPattern());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if expression contains vulnerable code
|
||||
*
|
||||
* @param expression of interceptor
|
||||
* @return true|false
|
||||
*/
|
||||
protected boolean isNotAcceptableExpression(String expression) {
|
||||
return isExcluded(expression) || !isAccepted(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a comma-delimited list of regular expressions to match
|
||||
* parameters that are allowed in the parameter map (aka whitelist).
|
||||
* <p>
|
||||
* Don't change the default unless you know what you are doing in terms
|
||||
* of security implications.
|
||||
* </p>
|
||||
*
|
||||
* @param commaDelim A comma-delimited list of regular expressions
|
||||
*/
|
||||
public void setAcceptParamNames(String commaDelim) {
|
||||
acceptedPatterns.setAcceptedPatterns(commaDelim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a comma-delimited list of regular expressions to match
|
||||
* parameters that should be removed from the parameter map.
|
||||
*
|
||||
* @param commaDelim A comma-delimited list of regular expressions
|
||||
*/
|
||||
public void setExcludeParams(String commaDelim) {
|
||||
excludedPatterns.setExcludedPatterns(commaDelim);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.ProxyUtil;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ActionInvocation;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.Unchainable;
|
||||
import org.apache.struts2.result.ActionChainResult;
|
||||
import org.apache.struts2.result.Result;
|
||||
import org.apache.struts2.util.ValueStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
* <p>
|
||||
* An interceptor that copies all the properties of every object in the value stack to the currently executing object,
|
||||
* except for any object that implements {@link Unchainable}. A collection of optional <i>includes</i> and
|
||||
* <i>excludes</i> may be provided to control how and which parameters are copied. Only includes or excludes may be
|
||||
* specified. Specifying both results in undefined behavior. See the javadocs for {@link ReflectionProvider#copy(Object, Object,
|
||||
* Map, Collection, Collection)} for more information.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> It is important to remember that this interceptor does nothing if there are no objects already on the stack.
|
||||
* <br>This means two things:
|
||||
* <br><b>One</b>, you can safely apply it to all your actions without any worry of adverse affects.
|
||||
* <br><b>Two</b>, it is up to you to ensure an object exists in the stack prior to invoking this action. The most typical way this is done
|
||||
* is through the use of the <b>chain</b> result type, which combines with this interceptor to make up the action
|
||||
* chaining feature.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> By default Errors, Field errors and Message aren't copied during chaining, to change the behaviour you can specify
|
||||
* the below three constants in struts.properties or struts.xml:
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>struts.chaining.copyErrors - set to true to copy Action Errors</li>
|
||||
* <li>struts.chaining.copyFieldErrors - set to true to copy Field Errors</li>
|
||||
* <li>struts.chaining.copyMessages - set to true to copy Action Messages</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* <u>Example:</u>
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <constant name="struts.xwork.chaining.copyErrors" value="true"/>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> By default actionErrors and actionMessages are excluded when copping object's properties.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: description -->
|
||||
* <u>Interceptor parameters:</u>
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
* <ul>
|
||||
* <li>excludes (optional) - the list of parameter names to exclude from copying (all others will be included).</li>
|
||||
* <li>includes (optional) - the list of parameter names to include when copying (all others will be excluded).</li>
|
||||
* </ul>
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
* <u>Extending the interceptor:</u>
|
||||
* <!-- START SNIPPET: extending -->
|
||||
* <p>
|
||||
* There are no known extension points to this interceptor.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: extending -->
|
||||
* <u>Example code:</u>
|
||||
*
|
||||
* <!-- START SNIPPET: example -->
|
||||
* <pre>
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
* <interceptor-ref name="basicStack"/>
|
||||
* <result name="success" type="chain">otherAction</result>
|
||||
* </action>
|
||||
* </pre>
|
||||
*
|
||||
* <pre>
|
||||
* <action name="otherAction" class="com.examples.OtherAction">
|
||||
* <interceptor-ref name="chain"/>
|
||||
* <interceptor-ref name="basicStack"/>
|
||||
* <result name="success">good_result.ftl</result>
|
||||
* </action>
|
||||
* </pre>
|
||||
* <!-- END SNIPPET: example -->
|
||||
*
|
||||
*
|
||||
* @author mrdon
|
||||
* @author tm_jee ( tm_jee(at)yahoo.co.uk )
|
||||
* @see ActionChainResult
|
||||
*/
|
||||
public class ChainingInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ChainingInterceptor.class);
|
||||
|
||||
private static final String ACTION_ERRORS = "actionErrors";
|
||||
private static final String FIELD_ERRORS = "fieldErrors";
|
||||
private static final String ACTION_MESSAGES = "actionMessages";
|
||||
|
||||
private boolean copyMessages = false;
|
||||
private boolean copyErrors = false;
|
||||
private boolean copyFieldErrors = false;
|
||||
|
||||
protected Collection<String> excludes;
|
||||
|
||||
protected Collection<String> includes;
|
||||
protected ReflectionProvider reflectionProvider;
|
||||
|
||||
@Inject
|
||||
public void setReflectionProvider(ReflectionProvider prov) {
|
||||
this.reflectionProvider = prov;
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_CHAINING_COPY_ERRORS, required = false)
|
||||
public void setCopyErrors(String copyErrors) {
|
||||
this.copyErrors = "true".equalsIgnoreCase(copyErrors);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_CHAINING_COPY_FIELD_ERRORS, required = false)
|
||||
public void setCopyFieldErrors(String copyFieldErrors) {
|
||||
this.copyFieldErrors = "true".equalsIgnoreCase(copyFieldErrors);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_CHAINING_COPY_MESSAGES, required = false)
|
||||
public void setCopyMessages(String copyMessages) {
|
||||
this.copyMessages = "true".equalsIgnoreCase(copyMessages);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
ValueStack stack = invocation.getStack();
|
||||
CompoundRoot root = stack.getRoot();
|
||||
if (shouldCopyStack(invocation, root)) {
|
||||
copyStack(invocation, root);
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
private void copyStack(ActionInvocation invocation, CompoundRoot root) {
|
||||
List list = prepareList(root);
|
||||
Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
|
||||
for (Object object : list) {
|
||||
if (shouldCopy(object)) {
|
||||
Object action = invocation.getAction();
|
||||
Class<?> editable = null;
|
||||
if(ProxyUtil.isProxy(action)) {
|
||||
editable = ProxyUtil.ultimateTargetClass(action);
|
||||
}
|
||||
reflectionProvider.copy(object, action, ctxMap, prepareExcludes(), includes, editable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<String> prepareExcludes() {
|
||||
Collection<String> localExcludes = excludes;
|
||||
if (!copyErrors || !copyMessages ||!copyFieldErrors) {
|
||||
if (localExcludes == null) {
|
||||
localExcludes = new HashSet<String>();
|
||||
if (!copyErrors) {
|
||||
localExcludes.add(ACTION_ERRORS);
|
||||
}
|
||||
if (!copyMessages) {
|
||||
localExcludes.add(ACTION_MESSAGES);
|
||||
}
|
||||
if (!copyFieldErrors) {
|
||||
localExcludes.add(FIELD_ERRORS);
|
||||
}
|
||||
}
|
||||
}
|
||||
return localExcludes;
|
||||
}
|
||||
|
||||
private boolean shouldCopy(Object o) {
|
||||
return o != null && !(o instanceof Unchainable);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List prepareList(CompoundRoot root) {
|
||||
List list = new ArrayList(root);
|
||||
list.remove(0);
|
||||
Collections.reverse(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
private boolean shouldCopyStack(ActionInvocation invocation, CompoundRoot root) throws Exception {
|
||||
Result result = invocation.getResult();
|
||||
return root.size() > 1 && (result == null || ActionChainResult.class.isAssignableFrom(result.getClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets list of parameter names to exclude
|
||||
*
|
||||
* @return the exclude list
|
||||
*/
|
||||
public Collection<String> getExcludes() {
|
||||
return excludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of parameter names to exclude from copying (all others will be included).
|
||||
*
|
||||
* @param excludes the excludes list as comma separated String
|
||||
*/
|
||||
public void setExcludes(String excludes) {
|
||||
this.excludes = TextParseUtil.commaDelimitedStringToSet(excludes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of parameter names to exclude from copying (all others will be included).
|
||||
*
|
||||
* @param excludes the excludes list
|
||||
*/
|
||||
public void setExcludesCollection(Collection<String> excludes) {
|
||||
this.excludes = excludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets list of parameter names to include
|
||||
*
|
||||
* @return the include list
|
||||
*/
|
||||
public Collection<String> getIncludes() {
|
||||
return includes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of parameter names to include when copying (all others will be excluded).
|
||||
*
|
||||
* @param includes the includes list as comma separated String
|
||||
*/
|
||||
public void setIncludes(String includes) {
|
||||
this.includes = TextParseUtil.commaDelimitedStringToSet(includes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the list of parameter names to include when copying (all others will be excluded).
|
||||
*
|
||||
* @param includes the includes list
|
||||
*/
|
||||
public void setIncludesCollection(Collection<String> includes) {
|
||||
this.includes = includes;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user