mirror of
https://github.com/apache/struts.git
synced 2026-08-10 09:06:55 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e903739624 | |||
| a85328e74e | |||
| c3deb39237 | |||
| 483a0c8d01 |
@@ -14,5 +14,3 @@ github:
|
||||
del_branch_on_merge: true
|
||||
protected_branches:
|
||||
master: { }
|
||||
autolink_jira:
|
||||
- WW
|
||||
|
||||
@@ -20,14 +20,6 @@ on:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
security-events: write
|
||||
actions: read
|
||||
contents: read
|
||||
# Needed to access OIDC token.
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
@@ -46,7 +38,7 @@ jobs:
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
- name: Perform CodeQL Analysis
|
||||
|
||||
@@ -21,8 +21,6 @@ on:
|
||||
branches:
|
||||
- master
|
||||
|
||||
permissions: read-all
|
||||
|
||||
env:
|
||||
MAVEN_OPTS: -Xmx2048m -Xms1024m
|
||||
LANG: en_US.utf8
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.2.0</version>
|
||||
<version>6.1.2</version>
|
||||
</parent>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>6.2.0</version>
|
||||
<version>6.1.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-rest-showcase</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>6.2.0</version>
|
||||
<version>6.1.2</version>
|
||||
<name>Struts 2 Rest Showcase Webapp</name>
|
||||
<description>Struts 2 Rest Showcase Example</description>
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
|
||||
<struts>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>6.2.0</version>
|
||||
<version>6.1.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-showcase</artifactId>
|
||||
@@ -99,11 +99,6 @@
|
||||
<artifactId>struts2-velocity-plugin</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-xslt-plugin</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
|
||||
@@ -21,17 +21,16 @@
|
||||
package org.apache.struts2.showcase.chat;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
public class ChatLoginAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private ChatService chatService;
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
|
||||
private String name;
|
||||
|
||||
@@ -61,8 +60,8 @@ public class ChatLoginAction extends ActionSupport implements SessionAware {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
// === SessionAware ===
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,18 +21,17 @@
|
||||
package org.apache.struts2.showcase.chat;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
public class ChatLogoutAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private ChatService chatService;
|
||||
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
|
||||
|
||||
public ChatLogoutAction(ChatService chatService) {
|
||||
@@ -51,8 +50,8 @@ public class ChatLogoutAction extends ActionSupport implements SessionAware {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
// === SessionAware ===
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,17 +21,16 @@
|
||||
package org.apache.struts2.showcase.chat;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
public class EnterRoomAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private ChatService chatService;
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
private String roomName;
|
||||
|
||||
public String getRoomName() {
|
||||
@@ -57,9 +56,10 @@ public class EnterRoomAction extends ActionSupport implements SessionAware {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
// === SessionAware ===
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,18 +21,17 @@
|
||||
package org.apache.struts2.showcase.chat;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
public class ExitRoomAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String roomName;
|
||||
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
|
||||
public String getRoomName() {
|
||||
return roomName;
|
||||
@@ -55,9 +54,9 @@ public class ExitRoomAction extends ActionSupport implements SessionAware {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
// === SessionAware ===
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-7
@@ -21,11 +21,10 @@
|
||||
package org.apache.struts2.showcase.chat;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
public class SendMessageToRoomAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -34,7 +33,7 @@ public class SendMessageToRoomAction extends ActionSupport implements SessionAwa
|
||||
|
||||
private String roomName;
|
||||
private String message;
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
|
||||
|
||||
public SendMessageToRoomAction(ChatService chatService) {
|
||||
@@ -68,10 +67,9 @@ public class SendMessageToRoomAction extends ActionSupport implements SessionAwa
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+6
-8
@@ -21,16 +21,15 @@
|
||||
package org.apache.struts2.showcase.hangman;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
public class GetUpdatedHangmanAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private static final long serialVersionUID = 5506025785406043027L;
|
||||
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
private Hangman hangman;
|
||||
|
||||
|
||||
@@ -46,6 +45,10 @@ public class GetUpdatedHangmanAction extends ActionSupport implements SessionAwa
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public Hangman getHangman() {
|
||||
return hangman;
|
||||
}
|
||||
@@ -53,9 +56,4 @@ public class GetUpdatedHangmanAction extends ActionSupport implements SessionAwa
|
||||
public void setHangman(Hangman hangman) {
|
||||
this.hangman = hangman;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-8
@@ -21,16 +21,15 @@
|
||||
package org.apache.struts2.showcase.hangman;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
public class GuessCharacterAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private static final long serialVersionUID = 9050915577007590674L;
|
||||
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
private Character character;
|
||||
private Hangman hangman;
|
||||
|
||||
@@ -45,6 +44,10 @@ public class GuessCharacterAction extends ActionSupport implements SessionAware
|
||||
return hangman;
|
||||
}
|
||||
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public void setCharacter(Character character) {
|
||||
this.character = character;
|
||||
}
|
||||
@@ -52,9 +55,4 @@ public class GuessCharacterAction extends ActionSupport implements SessionAware
|
||||
public Character getCharacter() {
|
||||
return this.character;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-7
@@ -21,11 +21,10 @@
|
||||
package org.apache.struts2.showcase.hangman;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.struts2.action.SessionAware;
|
||||
|
||||
import static org.apache.struts2.showcase.hangman.HangmanConstants.HANGMAN_SESSION_KEY;
|
||||
|
||||
public class StartHangmanAction extends ActionSupport implements SessionAware {
|
||||
@@ -34,7 +33,7 @@ public class StartHangmanAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private HangmanService service;
|
||||
private Hangman hangman;
|
||||
private Map<String, Object> session;
|
||||
private Map session;
|
||||
|
||||
|
||||
public StartHangmanAction(HangmanService service) {
|
||||
@@ -54,8 +53,8 @@ public class StartHangmanAction extends ActionSupport implements SessionAware {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void withSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
// === SessionAware ===
|
||||
public void setSession(Map session) {
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.showcase.servlet;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestServlet extends HttpServlet {
|
||||
@Override
|
||||
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
||||
switch (request.getPathInfo()) {
|
||||
case "/forward":
|
||||
getServletContext().getRequestDispatcher("/dispatcher/dispatch.action").forward(request, response);
|
||||
break;
|
||||
default:
|
||||
response.sendError(404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,11 +21,9 @@
|
||||
package org.apache.struts2.showcase.xslt;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.ServletRequestAware;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.struts2.action.ServletRequestAware;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -55,6 +53,10 @@ public class JVMAction implements ServletRequestAware {
|
||||
return servletRequest;
|
||||
}
|
||||
|
||||
public void setServletRequest(HttpServletRequest servletRequest) {
|
||||
this.servletRequest = servletRequest;
|
||||
}
|
||||
|
||||
public Map<String, String> getEnvironment() {
|
||||
return environment;
|
||||
}
|
||||
@@ -98,9 +100,4 @@ public class JVMAction implements ServletRequestAware {
|
||||
this.systemProperties = systemProperties;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withServletRequest(HttpServletRequest request) {
|
||||
this.servletRequest = request;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="actionchaining" extends="struts-default" namespace="/actionchaining">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="async" extends="json-default" namespace="/async">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="conversion" namespace="/conversion" extends="struts-default">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="dispatcher" extends="struts-default" namespace="/dispatcher">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="filedownload" extends="struts-default" namespace="/filedownload">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="fileupload" extends="struts-default" namespace="/fileupload">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="freemarker" namespace="/freemarker" extends="struts-default">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="hangman" extends="struts-default" namespace="/hangman">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="interactive" namespace="/interactive" extends="struts-default">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="modelDriven" extends="struts-default" namespace="/modelDriven">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<!-- START SNIPPET: xworkSample -->
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="ui-tags" extends="velocity-default" namespace="/tags/ui">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<include file="struts-tags-ui.xml"/>
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="tiles" extends="tiles-default" namespace="/tiles">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
<struts>
|
||||
<package name="token" extends="struts-default" namespace="/token">
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
|
||||
|
||||
@@ -20,15 +20,12 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
|
||||
<bean type="org.apache.struts2.interceptor.exec.ExecutorProvider" name="threadPool"
|
||||
class="org.apache.struts2.showcase.wait.ThreadPoolExecutorProvider"/>
|
||||
|
||||
<constant name="struts.executor.provider" value="threadPool"/>
|
||||
<bean type="org.apache.struts2.interceptor.exec.ExecutorProvider" class="org.apache.struts2.showcase.wait.ThreadPoolExecutorProvider"/>
|
||||
|
||||
<package name="wait" extends="struts-default" namespace="/wait">
|
||||
<default-action-ref name="index"/>
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<package name="xslt" extends="xslt-default" namespace="/xslt">
|
||||
<package name="xslt" extends="struts-default" namespace="/xslt">
|
||||
<default-action-ref name="index"/>
|
||||
|
||||
<action name="index">
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<!-- START SNIPPET: xworkSample -->
|
||||
<struts>
|
||||
@@ -44,7 +44,7 @@
|
||||
<constant name="struts.serve.static" value="true" />
|
||||
<constant name="struts.serve.static.browserCache" value="false" />
|
||||
|
||||
<constant name="struts.action.excludePattern" value=".*/images/.*\.gif,.*/img/.*\.gif,.*/styles/.*\.css,.*/js/.*\.js,/testServlet/.*"/>
|
||||
<constant name="struts.action.excludePattern" value=".*/images/.*\.gif,.*/img/.*\.gif,.*/styles/.*\.css,.*/js/.*\.js"/>
|
||||
|
||||
<include file="struts-interactive.xml" />
|
||||
|
||||
|
||||
@@ -142,11 +142,6 @@
|
||||
<load-on-startup>4</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>testServlet</servlet-name>
|
||||
<servlet-class>org.apache.struts2.showcase.servlet.TestServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>dwr</servlet-name>
|
||||
<url-pattern>/dwr/*</url-pattern>
|
||||
@@ -167,11 +162,6 @@
|
||||
<url-pattern>/async/receiveNewMessages</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>testServlet</servlet-name>
|
||||
<url-pattern>/testServlet/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- END SNIPPET: dwr -->
|
||||
|
||||
<!-- SNIPPET START: example.velocity.filter.chain
|
||||
|
||||
+9
-2
@@ -32,6 +32,7 @@ public class DispatcherResultTest {
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/dispatcher/dispatch.action");
|
||||
|
||||
DomElement div = page.getElementById("dispatcher-result");
|
||||
|
||||
Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
}
|
||||
}
|
||||
@@ -39,10 +40,16 @@ public class DispatcherResultTest {
|
||||
@Test
|
||||
public void testDispatchingToAction() throws Exception {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/dispatcher/forward.action");
|
||||
|
||||
DomElement div = page.getElementById("dispatcher-result");
|
||||
Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
//DomElement div = page.getElementById("dispatcher-result");
|
||||
//Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
// support for forwarding to another action is broken on StrutsPrepareFilter/StrutsExecuteFilter
|
||||
// it only works in StrutsPrepareAndExecuteFilter
|
||||
// this will be fixed in Struts 6.1.x
|
||||
|
||||
Assert.assertEquals(404, page.getWebResponse().getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package it.org.apache.struts2.showcase;
|
||||
|
||||
import com.gargoylesoftware.htmlunit.WebClient;
|
||||
import com.gargoylesoftware.htmlunit.html.DomElement;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ForwardTest {
|
||||
|
||||
@Test
|
||||
public void testServletForwardingToAction() throws Exception {
|
||||
try (final WebClient webClient = new WebClient()) {
|
||||
// Struts excluded URL, as defined by struts.action.excludePattern
|
||||
final HtmlPage page = webClient.getPage(ParameterUtils.getBaseUrl() + "/testServlet/forward");
|
||||
|
||||
DomElement div = page.getElementById("dispatcher-result");
|
||||
Assert.assertEquals("This page is a result of \"dispatching\" to it from an action", div.asNormalizedText());
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.2.0</version>
|
||||
<version>6.1.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-assembly</artifactId>
|
||||
|
||||
+3
-8
@@ -29,7 +29,7 @@
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-bom</artifactId>
|
||||
<version>6.2.0</version>
|
||||
<version>6.1.2</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Struts 2 Bill of Materials</name>
|
||||
@@ -44,7 +44,7 @@
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<struts-version.version>6.2.0</struts-version.version>
|
||||
<struts-version.version>6.1.2</struts-version.version>
|
||||
<maven.site.skip>true</maven.site.skip>
|
||||
<maven.site.deploy.skip>true</maven.site.deploy.skip>
|
||||
</properties>
|
||||
@@ -181,16 +181,11 @@
|
||||
<artifactId>struts2-velocity-plugin</artifactId>
|
||||
<version>${struts-version.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-xslt-plugin</artifactId>
|
||||
<version>${struts-version.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<scm>
|
||||
<tag>STRUTS_6_2_0</tag>
|
||||
<tag>STRUTS_6_1_2</tag>
|
||||
<connection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</connection>
|
||||
<developerConnection>scm:git:https://gitbox.apache.org/repos/asf/struts.git</developerConnection>
|
||||
<url>https://github.com/apache/struts/</url>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>6.2.0</version>
|
||||
<version>6.1.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-admin-bundle</artifactId>
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
-->
|
||||
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>6.2.0</version>
|
||||
<version>6.1.2</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-demo-bundle</artifactId>
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
*/
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
|
||||
"https://struts.apache.org/dtds/struts-6.0.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"https://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<!-- Set some Struts 2 constants relevant to the OSGi Plugin.
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>6.2.0</version>
|
||||
<version>6.1.2</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.2.0</version>
|
||||
<version>6.1.2</version>
|
||||
</parent>
|
||||
<artifactId>struts2-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -20,17 +20,12 @@ package com.opensymphony.xwork2;
|
||||
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
@@ -101,9 +96,15 @@ public class ActionChainResult implements Result {
|
||||
*/
|
||||
private static final String CHAIN_HISTORY = "CHAIN_HISTORY";
|
||||
|
||||
/**
|
||||
* The result parameter name to set the name of the action to chain to.
|
||||
*/
|
||||
public static final String SKIP_ACTIONS_PARAM = "skipActions";
|
||||
|
||||
|
||||
private ActionProxy proxy;
|
||||
private String actionName;
|
||||
|
||||
|
||||
private String namespace;
|
||||
|
||||
private String methodName;
|
||||
@@ -132,6 +133,7 @@ public class ActionChainResult implements Result {
|
||||
this.skipActions = skipActions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param actionProxyFactory the actionProxyFactory to set
|
||||
*/
|
||||
@@ -170,6 +172,7 @@ public class ActionChainResult implements Result {
|
||||
this.skipActions = actions;
|
||||
}
|
||||
|
||||
|
||||
public void setMethod(String method) {
|
||||
this.methodName = method;
|
||||
}
|
||||
@@ -203,14 +206,18 @@ public class ActionChainResult implements Result {
|
||||
throw new IllegalArgumentException("Invocation cannot be null!");
|
||||
}
|
||||
|
||||
String finalNamespace = namespace != null ? translateVariables(namespace) : invocation.getProxy()
|
||||
.getNamespace();
|
||||
String finalActionName = translateVariables(actionName);
|
||||
String finalMethodName = methodName != null ? translateVariables(methodName) : null;
|
||||
ValueStack stack = invocation.getInvocationContext().getValueStack();
|
||||
String finalNamespace = this.namespace != null
|
||||
? TextParseUtil.translateVariables(namespace, stack)
|
||||
: invocation.getProxy().getNamespace();
|
||||
String finalActionName = TextParseUtil.translateVariables(actionName, stack);
|
||||
String finalMethodName = this.methodName != null
|
||||
? TextParseUtil.translateVariables(this.methodName, stack)
|
||||
: null;
|
||||
|
||||
if (isInChainHistory(finalNamespace, finalActionName, finalMethodName)) {
|
||||
addToHistory(finalNamespace, finalActionName, finalMethodName);
|
||||
throw new StrutsException("Infinite recursion detected: " + ActionChainResult.getChainHistory());
|
||||
throw new StrutsException("Infinite recursion detected: " + ActionChainResult.getChainHistory().toString());
|
||||
}
|
||||
|
||||
if (ActionChainResult.getChainHistory().isEmpty() && invocation.getProxy() != null) {
|
||||
@@ -218,7 +225,7 @@ public class ActionChainResult implements Result {
|
||||
}
|
||||
addToHistory(finalNamespace, finalActionName, finalMethodName);
|
||||
|
||||
Map<String, Object> extraContext = ActionContext.of()
|
||||
Map<String, Object> extraContext = ActionContext.of(new HashMap<>())
|
||||
.withValueStack(invocation.getInvocationContext().getValueStack())
|
||||
.withParameters(invocation.getInvocationContext().getParameters())
|
||||
.with(CHAIN_HISTORY, ActionChainResult.getChainHistory())
|
||||
@@ -230,25 +237,20 @@ public class ActionChainResult implements Result {
|
||||
proxy.execute();
|
||||
}
|
||||
|
||||
protected String translateVariables(String text) {
|
||||
return TextParseUtil.translateVariables(text, ActionContext.getContext().getValueStack());
|
||||
@Override public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
final ActionChainResult that = (ActionChainResult) o;
|
||||
|
||||
if (actionName != null ? !actionName.equals(that.actionName) : that.actionName != null) return false;
|
||||
if (methodName != null ? !methodName.equals(that.methodName) : that.methodName != null) return false;
|
||||
if (namespace != null ? !namespace.equals(that.namespace) : that.namespace != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ActionChainResult that = (ActionChainResult) o;
|
||||
return Objects.equals(actionName, that.actionName) && Objects.equals(methodName,
|
||||
that.methodName) && Objects.equals(namespace, that.namespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
@Override public int hashCode() {
|
||||
int result;
|
||||
result = (actionName != null ? actionName.hashCode() : 0);
|
||||
result = 31 * result + (namespace != null ? namespace.hashCode() : 0);
|
||||
@@ -258,15 +260,24 @@ public class ActionChainResult implements Result {
|
||||
|
||||
private boolean isInChainHistory(String namespace, String actionName, String methodName) {
|
||||
LinkedList<? extends String> chainHistory = ActionChainResult.getChainHistory();
|
||||
Set<String> skipActionsList = new HashSet<>();
|
||||
if (skipActions != null && skipActions.length() > 0) {
|
||||
String finalSkipActions = translateVariables(skipActions);
|
||||
skipActionsList.addAll(TextParseUtil.commaDelimitedStringToSet(finalSkipActions));
|
||||
|
||||
if (chainHistory == null) {
|
||||
return false;
|
||||
} else {
|
||||
// Actions to skip
|
||||
Set<String> skipActionsList = new HashSet<>();
|
||||
if (skipActions != null && skipActions.length() > 0) {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
String finalSkipActions = TextParseUtil.translateVariables(this.skipActions, stack);
|
||||
skipActionsList.addAll(TextParseUtil.commaDelimitedStringToSet(finalSkipActions));
|
||||
}
|
||||
if (!skipActionsList.contains(actionName)) {
|
||||
// Get if key is in the chain history
|
||||
return chainHistory.contains(makeKey(namespace, actionName, methodName));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
if (!skipActionsList.contains(actionName)) {
|
||||
return chainHistory.contains(makeKey(namespace, actionName, methodName));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void addToHistory(String namespace, String actionName, String methodName) {
|
||||
@@ -275,6 +286,10 @@ public class ActionChainResult implements Result {
|
||||
}
|
||||
|
||||
private String makeKey(String namespace, String actionName, String methodName) {
|
||||
return namespace + "/" + actionName + (methodName != null ? "!" + methodName : "");
|
||||
if (null == methodName) {
|
||||
return namespace + "/" + actionName;
|
||||
}
|
||||
|
||||
return namespace + "/" + actionName + "!" + methodName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,52 +58,79 @@ import java.util.Map;
|
||||
*/
|
||||
public class ActionContext implements Serializable {
|
||||
|
||||
private static final ThreadLocal<ActionContext> actionContext = new ThreadLocal<>();
|
||||
static ThreadLocal<ActionContext> actionContext = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Constant for the name of the action being executed.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String ACTION_NAME = "org.apache.struts2.ActionContext.name";
|
||||
@Deprecated
|
||||
public static final String ACTION_NAME = "com.opensymphony.xwork2.ActionContext.name";
|
||||
|
||||
/**
|
||||
* Constant for the {@link com.opensymphony.xwork2.util.ValueStack OGNL value stack}.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String VALUE_STACK = ValueStack.VALUE_STACK;
|
||||
@Deprecated
|
||||
public static final String VALUE_STACK = ValueStack.VALUE_STACK;
|
||||
|
||||
/**
|
||||
* Constant for the action's session.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String SESSION = "org.apache.struts2.ActionContext.session";
|
||||
@Deprecated
|
||||
public static final String SESSION = "com.opensymphony.xwork2.ActionContext.session";
|
||||
|
||||
/**
|
||||
* Constant for the action's application context.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String APPLICATION = "org.apache.struts2.ActionContext.application";
|
||||
@Deprecated
|
||||
public static final String APPLICATION = "com.opensymphony.xwork2.ActionContext.application";
|
||||
|
||||
/**
|
||||
* Constant for the action's parameters.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String PARAMETERS = "org.apache.struts2.ActionContext.parameters";
|
||||
@Deprecated
|
||||
public static final String PARAMETERS = "com.opensymphony.xwork2.ActionContext.parameters";
|
||||
|
||||
/**
|
||||
* Constant for the action's locale.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String LOCALE = "org.apache.struts2.ActionContext.locale";
|
||||
@Deprecated
|
||||
public static final String LOCALE = "com.opensymphony.xwork2.ActionContext.locale";
|
||||
|
||||
/**
|
||||
* Constant for the action's {@link com.opensymphony.xwork2.ActionInvocation invocation} context.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String ACTION_INVOCATION = "org.apache.struts2.ActionContext.actionInvocation";
|
||||
@Deprecated
|
||||
public static final String ACTION_INVOCATION = "com.opensymphony.xwork2.ActionContext.actionInvocation";
|
||||
|
||||
/**
|
||||
* Constant for the map of type conversion errors.
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String CONVERSION_ERRORS = "org.apache.struts2.ActionContext.conversionErrors";
|
||||
@Deprecated
|
||||
public static final String CONVERSION_ERRORS = "com.opensymphony.xwork2.ActionContext.conversionErrors";
|
||||
|
||||
/**
|
||||
* Constant for the container
|
||||
*
|
||||
* @deprecated scope will be narrowed to "private", use helper methods instead
|
||||
*/
|
||||
private static final String CONTAINER = "org.apache.struts2.ActionContext.container";
|
||||
@Deprecated
|
||||
public static final String CONTAINER = "com.opensymphony.xwork2.ActionContext.container";
|
||||
|
||||
private final Map<String, Object> context;
|
||||
|
||||
@@ -118,6 +145,7 @@ public class ActionContext implements Serializable {
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext based on passed in Map
|
||||
* and assign this instance to the current thread
|
||||
*
|
||||
* @param context a map with context values
|
||||
* @return new ActionContext
|
||||
@@ -129,15 +157,6 @@ public class ActionContext implements Serializable {
|
||||
return new ActionContext(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ActionContext based on empty Map
|
||||
*
|
||||
* @return new ActionContext
|
||||
*/
|
||||
public static ActionContext of() {
|
||||
return of(new HashMap<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the provided context with the current thread
|
||||
*
|
||||
@@ -192,7 +211,13 @@ public class ActionContext implements Serializable {
|
||||
* Sets the action invocation (the execution state).
|
||||
*
|
||||
* @param actionInvocation the action execution state.
|
||||
* @deprecated use {@link #withActionInvocation(ActionInvocation)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setActionInvocation(ActionInvocation actionInvocation) {
|
||||
put(ACTION_INVOCATION, actionInvocation);
|
||||
}
|
||||
|
||||
public ActionContext withActionInvocation(ActionInvocation actionInvocation) {
|
||||
put(ACTION_INVOCATION, actionInvocation);
|
||||
return this;
|
||||
@@ -211,7 +236,13 @@ public class ActionContext implements Serializable {
|
||||
* Sets the action's application context.
|
||||
*
|
||||
* @param application the action's application context.
|
||||
* @deprecated use {@link #withApplication(Map)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setApplication(Map<String, Object> application) {
|
||||
put(APPLICATION, application);
|
||||
}
|
||||
|
||||
public ActionContext withApplication(Map<String, Object> application) {
|
||||
put(APPLICATION, application);
|
||||
return this;
|
||||
@@ -240,7 +271,13 @@ public class ActionContext implements Serializable {
|
||||
* Sets conversion errors which occurred when executing the action.
|
||||
*
|
||||
* @param conversionErrors a Map of errors which occurred when executing the action.
|
||||
* @deprecated use {@link #withConversionErrors(Map)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setConversionErrors(Map<String, ConversionData> conversionErrors) {
|
||||
put(CONVERSION_ERRORS, conversionErrors);
|
||||
}
|
||||
|
||||
public ActionContext withConversionErrors(Map<String, ConversionData> conversionErrors) {
|
||||
put(CONVERSION_ERRORS, conversionErrors);
|
||||
return this;
|
||||
@@ -267,7 +304,13 @@ public class ActionContext implements Serializable {
|
||||
* Sets the Locale for the current action.
|
||||
*
|
||||
* @param locale the Locale for the current action.
|
||||
* @deprecated use {@link #withLocale(Locale)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setLocale(Locale locale) {
|
||||
put(LOCALE, locale);
|
||||
}
|
||||
|
||||
public ActionContext withLocale(Locale locale) {
|
||||
put(LOCALE, locale);
|
||||
return this;
|
||||
@@ -284,7 +327,7 @@ public class ActionContext implements Serializable {
|
||||
|
||||
if (locale == null) {
|
||||
locale = Locale.getDefault();
|
||||
withLocale(locale);
|
||||
setLocale(locale);
|
||||
}
|
||||
|
||||
return locale;
|
||||
@@ -293,13 +336,28 @@ public class ActionContext implements Serializable {
|
||||
/**
|
||||
* Sets the name of the current Action in the ActionContext.
|
||||
*
|
||||
* @param actionName the name of the current action.
|
||||
* @param name the name of the current action.
|
||||
* @deprecated use {@link #withActionName(String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setName(String name) {
|
||||
put(ACTION_NAME, name);
|
||||
}
|
||||
|
||||
public ActionContext withActionName(String actionName) {
|
||||
put(ACTION_NAME, actionName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the current Action.
|
||||
*
|
||||
* @return the name of the current action.
|
||||
*/
|
||||
public String getName() {
|
||||
return (String) get(ACTION_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the current Action.
|
||||
*
|
||||
@@ -314,6 +372,10 @@ public class ActionContext implements Serializable {
|
||||
*
|
||||
* @param parameters the parameters for the current action.
|
||||
*/
|
||||
public void setParameters(HttpParameters parameters) {
|
||||
put(PARAMETERS, parameters);
|
||||
}
|
||||
|
||||
public ActionContext withParameters(HttpParameters parameters) {
|
||||
put(PARAMETERS, parameters);
|
||||
return this;
|
||||
@@ -334,7 +396,13 @@ public class ActionContext implements Serializable {
|
||||
* Sets a map of action session values.
|
||||
*
|
||||
* @param session the session values.
|
||||
* @deprecated use {@link #withSession(Map)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setSession(Map<String, Object> session) {
|
||||
put(SESSION, session);
|
||||
}
|
||||
|
||||
public ActionContext withSession(Map<String, Object> session) {
|
||||
put(SESSION, session);
|
||||
return this;
|
||||
@@ -353,8 +421,14 @@ public class ActionContext implements Serializable {
|
||||
/**
|
||||
* Sets the OGNL value stack.
|
||||
*
|
||||
* @param valueStack the OGNL value stack.
|
||||
* @param stack the OGNL value stack.
|
||||
* @deprecated Use {@link #withValueStack(ValueStack)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setValueStack(ValueStack stack) {
|
||||
put(VALUE_STACK, stack);
|
||||
}
|
||||
|
||||
public ActionContext withValueStack(ValueStack valueStack) {
|
||||
put(VALUE_STACK, valueStack);
|
||||
return this;
|
||||
@@ -372,8 +446,14 @@ public class ActionContext implements Serializable {
|
||||
/**
|
||||
* Gets the container for this request
|
||||
*
|
||||
* @param container The container
|
||||
* @param cont The container
|
||||
* @deprecated use {@link #withContainer(Container)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setContainer(Container cont) {
|
||||
put(CONTAINER, cont);
|
||||
}
|
||||
|
||||
public ActionContext withContainer(Container container) {
|
||||
put(CONTAINER, container);
|
||||
return this;
|
||||
|
||||
@@ -101,7 +101,7 @@ public abstract class XWorkTestCase extends TestCase {
|
||||
}
|
||||
|
||||
protected Map<String, Object> createContextWithLocale(Locale locale) {
|
||||
return ActionContext.of()
|
||||
return ActionContext.of(new HashMap<>())
|
||||
.withLocale(locale)
|
||||
.getContextMap();
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@ import com.opensymphony.xwork2.config.impl.DefaultConfiguration;
|
||||
import com.opensymphony.xwork2.config.providers.StrutsDefaultConfigurationProvider;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.apache.struts2.StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
|
||||
/**
|
||||
@@ -42,11 +42,12 @@ public class ConfigurationManager {
|
||||
|
||||
protected static final Logger LOG = LogManager.getLogger(ConfigurationManager.class);
|
||||
protected Configuration configuration;
|
||||
private List<ContainerProvider> containerProviders = new ArrayList<>();
|
||||
private List<PackageProvider> packageProviders = new ArrayList<>();
|
||||
protected Lock providerLock = new ReentrantLock();
|
||||
private List<ContainerProvider> containerProviders = new CopyOnWriteArrayList<>();
|
||||
private List<PackageProvider> packageProviders = new CopyOnWriteArrayList<>();
|
||||
protected String defaultFrameworkBeanName;
|
||||
private boolean providersChanged = true;
|
||||
private boolean alwaysReloadConfigs = false;
|
||||
private boolean providersChanged = false;
|
||||
private boolean reloadConfigs = true; // for the first time
|
||||
|
||||
public ConfigurationManager(String name) {
|
||||
this.defaultFrameworkBeanName = name;
|
||||
@@ -58,69 +59,54 @@ public class ConfigurationManager {
|
||||
* @see com.opensymphony.xwork2.config.impl.DefaultConfiguration
|
||||
*/
|
||||
public synchronized Configuration getConfiguration() {
|
||||
if (wasConfigInitialised()) {
|
||||
if (configuration == null) {
|
||||
setConfiguration(createConfiguration(defaultFrameworkBeanName));
|
||||
try {
|
||||
configuration.reloadContainer(getContainerProviders());
|
||||
} catch (ConfigurationException e) {
|
||||
setConfiguration(null);
|
||||
throw new ConfigurationException("Unable to load configuration.", e);
|
||||
}
|
||||
} else {
|
||||
conditionalReload();
|
||||
}
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether configuration was initialised (was null)
|
||||
*/
|
||||
private boolean wasConfigInitialised() {
|
||||
if (configuration == null) {
|
||||
initialiseConfiguration();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void initialiseConfiguration() {
|
||||
if (containerProviders.isEmpty()) {
|
||||
addDefaultContainerProviders();
|
||||
}
|
||||
configuration = createConfiguration(defaultFrameworkBeanName);
|
||||
try {
|
||||
reload();
|
||||
} catch (ConfigurationException e) {
|
||||
configuration.destroy();
|
||||
configuration = null;
|
||||
providersChanged = true;
|
||||
throw new ConfigurationException("Unable to load configuration.", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addDefaultContainerProviders() {
|
||||
containerProviders.add(new StrutsDefaultConfigurationProvider());
|
||||
}
|
||||
|
||||
protected Configuration createConfiguration(String beanName) {
|
||||
return new DefaultConfiguration(beanName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all container providers and destroy managing Configuration instance
|
||||
*/
|
||||
public synchronized void destroyConfiguration() {
|
||||
clearContainerProviders();
|
||||
if (configuration != null) {
|
||||
configuration.destroy();
|
||||
configuration = null;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setConfiguration(Configuration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current list of ConfigurationProviders.
|
||||
* <p>
|
||||
* Get the current list of ConfigurationProviders. If no custom ConfigurationProviders have been added, this method
|
||||
* will return a list containing only a default ConfigurationProvider, {@link StrutsDefaultConfigurationProvider}.
|
||||
* If a custom ConfigurationProvider has been added, then the StrutsDefaultConfigurationProvider must be added by hand.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* TODO: The lazy instantiation of XmlConfigurationProvider should be refactored to be elsewhere. The behavior described above seems unintuitive.
|
||||
* </p>
|
||||
*
|
||||
* @return the list of registered ConfigurationProvider objects
|
||||
* @see ConfigurationProvider
|
||||
*/
|
||||
public synchronized List<ContainerProvider> getContainerProviders() {
|
||||
return new ArrayList<>(containerProviders);
|
||||
public List<ContainerProvider> getContainerProviders() {
|
||||
providerLock.lock();
|
||||
try {
|
||||
if (containerProviders.size() == 0) {
|
||||
containerProviders.add(new StrutsDefaultConfigurationProvider());
|
||||
}
|
||||
|
||||
return containerProviders;
|
||||
} finally {
|
||||
providerLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,9 +114,14 @@ public class ConfigurationManager {
|
||||
*
|
||||
* @param containerProviders list of {@link ConfigurationProvider} to be set
|
||||
*/
|
||||
public synchronized void setContainerProviders(List<ContainerProvider> containerProviders) {
|
||||
this.containerProviders = new ArrayList<>(containerProviders);
|
||||
providersChanged = true;
|
||||
public void setContainerProviders(List<ContainerProvider> containerProviders) {
|
||||
providerLock.lock();
|
||||
try {
|
||||
this.containerProviders = new CopyOnWriteArrayList<>(containerProviders);
|
||||
providersChanged = true;
|
||||
} finally {
|
||||
providerLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,32 +130,22 @@ public class ConfigurationManager {
|
||||
*
|
||||
* @param provider the ConfigurationProvider to register
|
||||
*/
|
||||
public synchronized void addContainerProvider(ContainerProvider provider) {
|
||||
public void addContainerProvider(ContainerProvider provider) {
|
||||
if (!containerProviders.contains(provider)) {
|
||||
containerProviders.add(provider);
|
||||
providersChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void removeContainerProvider(ContainerProvider provider) {
|
||||
if (containerProviders.remove(provider)) {
|
||||
destroyContainerProvider(provider);
|
||||
providersChanged = true;
|
||||
public void clearContainerProviders() {
|
||||
for (ContainerProvider containerProvider : containerProviders) {
|
||||
clearContainerProvider(containerProvider);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void clearContainerProviders() {
|
||||
destroyContainerProviders();
|
||||
containerProviders.clear();
|
||||
providersChanged = true;
|
||||
}
|
||||
|
||||
private void destroyContainerProviders() {
|
||||
LOG.debug("Destroying all providers.");
|
||||
containerProviders.forEach(this::destroyContainerProvider);
|
||||
}
|
||||
|
||||
private void destroyContainerProvider(ContainerProvider containerProvider) {
|
||||
private void clearContainerProvider(ContainerProvider containerProvider) {
|
||||
try {
|
||||
containerProvider.destroy();
|
||||
} catch (Exception e) {
|
||||
@@ -172,61 +153,80 @@ public class ConfigurationManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy its managing Configuration instance
|
||||
*/
|
||||
public synchronized void destroyConfiguration() {
|
||||
clearContainerProviders(); // let's destroy the ConfigurationProvider first
|
||||
containerProviders = new CopyOnWriteArrayList<>();
|
||||
if (configuration != null)
|
||||
configuration.destroy(); // let's destroy it first, before nulling it.
|
||||
configuration = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reloads the Configuration files if the configuration files indicate that they need to be reloaded.
|
||||
*/
|
||||
public synchronized void conditionalReload() {
|
||||
if (alwaysReloadConfigs || providersChanged) {
|
||||
if (reloadConfigs || providersChanged) {
|
||||
LOG.debug("Checking ConfigurationProviders for reload.");
|
||||
if (needReloadContainerProviders() || needReloadPackageProviders()) {
|
||||
destroyAndReload();
|
||||
List<ContainerProvider> providers = getContainerProviders();
|
||||
boolean reload = needReloadContainerProviders(providers);
|
||||
if (!reload) {
|
||||
reload = needReloadPackageProviders();
|
||||
}
|
||||
if (reload) {
|
||||
reloadProviders(providers);
|
||||
}
|
||||
updateReloadConfigsFlag();
|
||||
providersChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAlwaysReloadFlag() {
|
||||
boolean newValue = Boolean.parseBoolean(configuration.getContainer()
|
||||
.getInstance(String.class, STRUTS_CONFIGURATION_XML_RELOAD));
|
||||
if (alwaysReloadConfigs != newValue) {
|
||||
LOG.debug(
|
||||
"Updating [{}], current value is [{}], new value [{}]",
|
||||
STRUTS_CONFIGURATION_XML_RELOAD,
|
||||
String.valueOf(alwaysReloadConfigs),
|
||||
String.valueOf(newValue));
|
||||
alwaysReloadConfigs = newValue;
|
||||
private void updateReloadConfigsFlag() {
|
||||
reloadConfigs = Boolean.parseBoolean(configuration.getContainer().getInstance(String.class, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD));
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Updating [{}], current value is [{}], new value [{}]",
|
||||
StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, String.valueOf(reloadConfigs), String.valueOf(reloadConfigs));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean needReloadPackageProviders() {
|
||||
Optional<PackageProvider> provider = packageProviders.stream().filter(PackageProvider::needsReload).findAny();
|
||||
if (provider.isPresent()) {
|
||||
LOG.info("Detected package provider [{}] needs to be reloaded.", provider.get());
|
||||
return true;
|
||||
if (packageProviders != null) {
|
||||
for (PackageProvider provider : packageProviders) {
|
||||
if (provider.needsReload()) {
|
||||
LOG.info("Detected package provider [{}] needs to be reloaded. Reloading all providers.", provider);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean needReloadContainerProviders() {
|
||||
Optional<ContainerProvider> provider = containerProviders.stream().filter(ContainerProvider::needsReload).findAny();
|
||||
if (provider.isPresent()) {
|
||||
LOG.info("Detected container provider [{}] needs to be reloaded.", provider.get());
|
||||
return true;
|
||||
private boolean needReloadContainerProviders(List<ContainerProvider> providers) {
|
||||
for (ContainerProvider provider : providers) {
|
||||
if (provider.needsReload()) {
|
||||
LOG.info("Detected container provider [{}] needs to be reloaded. Reloading all providers.", provider);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public synchronized void destroyAndReload() {
|
||||
destroyContainerProviders();
|
||||
reload();
|
||||
private void reloadProviders(List<ContainerProvider> providers) {
|
||||
for (ContainerProvider containerProvider : containerProviders) {
|
||||
try {
|
||||
containerProvider.destroy();
|
||||
} catch (Exception e) {
|
||||
LOG.warn("error while destroying configuration provider [{}]", containerProvider, e);
|
||||
}
|
||||
}
|
||||
packageProviders = this.configuration.reloadContainer(providers);
|
||||
}
|
||||
|
||||
public synchronized void reload() {
|
||||
if (wasConfigInitialised()) {
|
||||
LOG.debug("Reloading all providers.");
|
||||
packageProviders = configuration.reloadContainer(containerProviders);
|
||||
providersChanged = false;
|
||||
updateAlwaysReloadFlag();
|
||||
}
|
||||
packageProviders = getConfiguration().reloadContainer(getContainerProviders());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
|
||||
/**
|
||||
* Provides beans and constants/properties for the Container
|
||||
*
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public interface ContainerProvider {
|
||||
@@ -32,29 +32,29 @@ public interface ContainerProvider {
|
||||
/**
|
||||
* Called before removed from the configuration manager
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
public void destroy();
|
||||
|
||||
/**
|
||||
* Initializes with the configuration
|
||||
* @param configuration The configuration
|
||||
* @throws ConfigurationException If anything goes wrong
|
||||
*/
|
||||
void init(Configuration configuration) throws ConfigurationException;
|
||||
|
||||
public void init(Configuration configuration) throws ConfigurationException;
|
||||
|
||||
/**
|
||||
* Tells whether the ContainerProvider should reload its configuration
|
||||
*
|
||||
* @return <tt>true</tt>, whether the ContainerProvider should reload its configuration, <tt>false</tt>otherwise.
|
||||
*/
|
||||
boolean needsReload();
|
||||
|
||||
public boolean needsReload();
|
||||
|
||||
/**
|
||||
* Registers beans and properties for the Container
|
||||
*
|
||||
*
|
||||
* @param builder The builder to register beans with
|
||||
* @param props The properties to register constants with
|
||||
* @throws ConfigurationException If anything goes wrong
|
||||
*/
|
||||
void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException;
|
||||
|
||||
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException;
|
||||
|
||||
}
|
||||
|
||||
-4
@@ -118,8 +118,6 @@ import org.apache.struts2.conversion.StrutsTypeConverterCreator;
|
||||
import org.apache.struts2.conversion.StrutsTypeConverterHolder;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.interceptor.exec.ExecutorProvider;
|
||||
import org.apache.struts2.interceptor.exec.StrutsExecutorProvider;
|
||||
import org.apache.struts2.url.QueryStringBuilder;
|
||||
import org.apache.struts2.url.QueryStringParser;
|
||||
import org.apache.struts2.url.StrutsQueryStringBuilder;
|
||||
@@ -244,8 +242,6 @@ public class StrutsDefaultConfigurationProvider implements ConfigurationProvider
|
||||
.factory(QueryStringParser.class, StrutsQueryStringParser.class, Scope.SINGLETON)
|
||||
.factory(UrlEncoder.class, StrutsUrlEncoder.class, Scope.SINGLETON)
|
||||
.factory(UrlDecoder.class, StrutsUrlDecoder.class, Scope.SINGLETON)
|
||||
|
||||
.factory(ExecutorProvider.class, StrutsExecutorProvider.class, Scope.SINGLETON)
|
||||
;
|
||||
|
||||
props.setProperty(StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION, Boolean.FALSE.toString());
|
||||
|
||||
+1067
-133
File diff suppressed because it is too large
Load Diff
-990
@@ -1,990 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package com.opensymphony.xwork2.config.providers;
|
||||
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.config.BeanSelectionProvider;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
import com.opensymphony.xwork2.config.ConfigurationUtil;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.config.entities.ExceptionMappingConfig;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorConfig;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorMapping;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorStackConfig;
|
||||
import com.opensymphony.xwork2.config.entities.PackageConfig;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.config.entities.ResultTypeConfig;
|
||||
import com.opensymphony.xwork2.config.entities.UnknownHandlerConfig;
|
||||
import com.opensymphony.xwork2.config.impl.LocatableFactory;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.inject.Scope;
|
||||
import com.opensymphony.xwork2.util.ClassLoaderUtil;
|
||||
import com.opensymphony.xwork2.util.DomHelper;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import com.opensymphony.xwork2.util.location.Location;
|
||||
import com.opensymphony.xwork2.util.location.LocationUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static com.opensymphony.xwork2.util.TextParseUtil.commaDelimitedStringToSet;
|
||||
import static java.lang.Boolean.parseBoolean;
|
||||
import static java.lang.Character.isLowerCase;
|
||||
import static java.lang.Character.toUpperCase;
|
||||
import static java.lang.String.format;
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
|
||||
import static org.apache.commons.lang3.StringUtils.trimToNull;
|
||||
|
||||
/**
|
||||
* This is a base XWork2 {@link ConfigurationProvider} for loading configuration from a parsed
|
||||
* {@link Document XML document}. By extending this class, configuration can be loaded from any source that an XML
|
||||
* document can be parsed from. Note that this class does not validate the document against any provided DTDs. For
|
||||
* loading configuration from an XML file with DTD validation, please see
|
||||
* {@link org.apache.struts2.config.StrutsXmlConfigurationProvider StrutsXmlConfigurationProvider}.
|
||||
*
|
||||
* @since 6.2.0
|
||||
*/
|
||||
public abstract class XmlDocConfigurationProvider implements ConfigurationProvider {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(XmlConfigurationProvider.class);
|
||||
|
||||
protected final Map<String, Element> declaredPackages = new HashMap<>();
|
||||
protected List<Document> documents;
|
||||
protected ObjectFactory objectFactory;
|
||||
protected Map<String, String> dtdMappings = new HashMap<>();
|
||||
protected Configuration configuration;
|
||||
protected boolean throwExceptionOnDuplicateBeans = true;
|
||||
protected ValueSubstitutor valueSubstitutor;
|
||||
|
||||
@Inject
|
||||
public void setObjectFactory(ObjectFactory objectFactory) {
|
||||
this.objectFactory = objectFactory;
|
||||
}
|
||||
|
||||
@Inject(required = false)
|
||||
public void setValueSubstitutor(ValueSubstitutor valueSubstitutor) {
|
||||
this.valueSubstitutor = valueSubstitutor;
|
||||
}
|
||||
|
||||
public XmlDocConfigurationProvider(Document... documents) {
|
||||
this.documents = Arrays.asList(documents);
|
||||
}
|
||||
|
||||
public void setThrowExceptionOnDuplicateBeans(boolean val) {
|
||||
this.throwExceptionOnDuplicateBeans = val;
|
||||
}
|
||||
|
||||
public void setDtdMappings(Map<String, String> mappings) {
|
||||
this.dtdMappings = Collections.unmodifiableMap(mappings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable map of DTD mappings
|
||||
*
|
||||
* @return map of DTD mappings
|
||||
*/
|
||||
public Map<String, String> getDtdMappings() {
|
||||
return dtdMappings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Configuration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
protected Class<?> loadClass(String className) throws ClassNotFoundException {
|
||||
return objectFactory.getClassInstance(className);
|
||||
}
|
||||
|
||||
public static void iterateElementChildren(Document doc, Consumer<Element> function) {
|
||||
iterateElementChildren(doc.getDocumentElement(), function);
|
||||
}
|
||||
|
||||
public static void iterateElementChildren(Node node, Consumer<Element> function) {
|
||||
iterateChildren(node, childNode -> {
|
||||
if (!(childNode instanceof Element)) {
|
||||
return;
|
||||
}
|
||||
function.accept((Element) childNode);
|
||||
});
|
||||
}
|
||||
|
||||
public static void iterateChildren(Node node, Consumer<Node> function) {
|
||||
NodeList children = node.getChildNodes();
|
||||
for (int i = 0; i < children.getLength(); i++) {
|
||||
function.accept(children.item(i));
|
||||
}
|
||||
}
|
||||
|
||||
public static void iterateChildrenByTagName(Element el, String tagName, Consumer<Element> function) {
|
||||
NodeList childrenByTag = el.getElementsByTagName(tagName);
|
||||
for (int i = 0; i < childrenByTag.getLength(); i++) {
|
||||
Element childEl = (Element) childrenByTag.item(i);
|
||||
function.accept(childEl);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException {
|
||||
Map<String, Node> loadedBeans = new HashMap<>();
|
||||
for (Document doc : documents) {
|
||||
iterateElementChildren(doc, child -> {
|
||||
switch (child.getNodeName()) {
|
||||
case "bean-selection": {
|
||||
registerBeanSelection(child, containerBuilder, props);
|
||||
break;
|
||||
}
|
||||
case "bean": {
|
||||
registerBean(child, loadedBeans, containerBuilder);
|
||||
break;
|
||||
}
|
||||
case "constant": {
|
||||
registerConstant(child, props);
|
||||
break;
|
||||
}
|
||||
case "unknown-handler-stack":
|
||||
registerUnknownHandlerStack(child);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerBeanSelection(Element child, ContainerBuilder containerBuilder, LocatableProperties props) {
|
||||
String name = child.getAttribute("name");
|
||||
String impl = child.getAttribute("class");
|
||||
try {
|
||||
Class<?> classImpl = loadClass(impl);
|
||||
if (BeanSelectionProvider.class.isAssignableFrom(classImpl)) {
|
||||
BeanSelectionProvider provider = (BeanSelectionProvider) classImpl.newInstance();
|
||||
provider.register(containerBuilder, props);
|
||||
} else {
|
||||
throw new ConfigurationException(format("The bean-provider: name:%s class:%s does not implement %s", name, impl, BeanSelectionProvider.class.getName()), child);
|
||||
}
|
||||
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
|
||||
throw new ConfigurationException(format("Unable to load bean-provider: name:%s class:%s", name, impl), e, child);
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerBean(Element child, Map<String, Node> loadedBeans, ContainerBuilder containerBuilder) {
|
||||
String type = child.getAttribute("type");
|
||||
String name = child.getAttribute("name");
|
||||
String impl = child.getAttribute("class");
|
||||
String onlyStatic = child.getAttribute("static");
|
||||
String scopeStr = child.getAttribute("scope");
|
||||
boolean optional = "true".equals(child.getAttribute("optional"));
|
||||
Scope scope = Scope.fromString(scopeStr);
|
||||
|
||||
if (name.isEmpty()) {
|
||||
name = Container.DEFAULT_NAME;
|
||||
}
|
||||
|
||||
try {
|
||||
Class<?> classImpl = ClassLoaderUtil.loadClass(impl, getClass());
|
||||
Class<?> classType = classImpl;
|
||||
if (!type.isEmpty()) {
|
||||
classType = ClassLoaderUtil.loadClass(type, getClass());
|
||||
}
|
||||
if ("true".equals(onlyStatic)) {
|
||||
// Force loading of class to detect no class def found exceptions
|
||||
classImpl.getDeclaredClasses();
|
||||
containerBuilder.injectStatics(classImpl);
|
||||
} else {
|
||||
if (containerBuilder.contains(classType, name)) {
|
||||
Location loc = LocationUtils.getLocation(loadedBeans.get(classType.getName() + name));
|
||||
if (throwExceptionOnDuplicateBeans) {
|
||||
throw new ConfigurationException(format("Bean type %s with the name %s has already been loaded by %s", classType, name, loc), child);
|
||||
}
|
||||
}
|
||||
|
||||
// Force loading of class to detect no class def found exceptions
|
||||
classImpl.getDeclaredConstructors();
|
||||
|
||||
LOG.debug("Loaded type: {} name: {} impl: {}", type, name, impl);
|
||||
containerBuilder.factory(classType, name, new LocatableFactory<>(name, classType, classImpl, scope, child), scope);
|
||||
}
|
||||
loadedBeans.put(classType.getName() + name, child);
|
||||
} catch (Throwable ex) {
|
||||
if (!optional) {
|
||||
throw new ConfigurationException("Unable to load bean: type:" + type + " class:" + impl, ex, child);
|
||||
} else {
|
||||
LOG.debug("Unable to load optional class: {}", impl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerConstant(Element child, LocatableProperties props) {
|
||||
String name = child.getAttribute("name");
|
||||
String value = child.getAttribute("value");
|
||||
|
||||
if (valueSubstitutor != null) {
|
||||
LOG.debug("Substituting value [{}] using [{}]", value, valueSubstitutor.getClass().getName());
|
||||
value = valueSubstitutor.substitute(value);
|
||||
}
|
||||
|
||||
props.setProperty(name, value, child);
|
||||
}
|
||||
|
||||
protected void registerUnknownHandlerStack(Element child) {
|
||||
List<UnknownHandlerConfig> unknownHandlerStack = new ArrayList<>();
|
||||
|
||||
iterateChildrenByTagName(child, "unknown-handler-ref", unknownHandler -> {
|
||||
Location location = LocationUtils.getLocation(unknownHandler);
|
||||
unknownHandlerStack.add(new UnknownHandlerConfig(unknownHandler.getAttribute("name"), location));
|
||||
});
|
||||
|
||||
if (!unknownHandlerStack.isEmpty()) {
|
||||
configuration.setUnknownHandlerStack(unknownHandlerStack);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needsReload() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadPackages() throws ConfigurationException {
|
||||
List<Element> reloads = new ArrayList<>();
|
||||
verifyPackageStructure();
|
||||
|
||||
for (Document doc : documents) {
|
||||
iterateElementChildren(doc, child -> {
|
||||
if ("package".equals(child.getNodeName())) {
|
||||
PackageConfig cfg = addPackage(child);
|
||||
if (cfg.isNeedsRefresh()) {
|
||||
reloads.add(child);
|
||||
}
|
||||
}
|
||||
});
|
||||
loadExtraConfiguration(doc);
|
||||
}
|
||||
|
||||
if (reloads.size() > 0) {
|
||||
reloadRequiredPackages(reloads);
|
||||
}
|
||||
|
||||
for (Document doc : documents) {
|
||||
loadExtraConfiguration(doc);
|
||||
}
|
||||
|
||||
declaredPackages.clear();
|
||||
configuration = null;
|
||||
}
|
||||
|
||||
private void verifyPackageStructure() {
|
||||
DirectedGraph<String> graph = new DirectedGraph<>();
|
||||
|
||||
for (Document doc : documents) {
|
||||
iterateElementChildren(doc, child -> {
|
||||
if (!"package".equals(child.getNodeName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
String packageName = child.getAttribute("name");
|
||||
declaredPackages.put(packageName, child);
|
||||
graph.addNode(packageName);
|
||||
|
||||
String extendsAttribute = child.getAttribute("extends");
|
||||
for (String parent : ConfigurationUtil.buildParentListFromString(extendsAttribute)) {
|
||||
graph.addNode(parent);
|
||||
graph.addEdge(packageName, parent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
CycleDetector<String> detector = new CycleDetector<>(graph);
|
||||
if (detector.containsCycle()) {
|
||||
StringBuilder builder = new StringBuilder("The following packages participate in cycles:");
|
||||
for (String packageName : detector.getVerticesInCycles()) {
|
||||
builder.append(" ");
|
||||
builder.append(packageName);
|
||||
}
|
||||
throw new ConfigurationException(builder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows subclasses to load extra information from the document
|
||||
*
|
||||
* @param doc The configuration document
|
||||
*/
|
||||
protected void loadExtraConfiguration(Document doc) {
|
||||
// no op
|
||||
}
|
||||
|
||||
private void reloadRequiredPackages(List<Element> reloads) {
|
||||
if (reloads.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Element> result = new ArrayList<>();
|
||||
for (Element pkg : reloads) {
|
||||
PackageConfig cfg = addPackage(pkg);
|
||||
if (cfg.isNeedsRefresh()) {
|
||||
result.add(pkg);
|
||||
}
|
||||
}
|
||||
if (!result.isEmpty() && result.size() != reloads.size()) {
|
||||
reloadRequiredPackages(result);
|
||||
return;
|
||||
}
|
||||
|
||||
// Print out error messages for all misconfigured inheritance packages
|
||||
for (Element rp : result) {
|
||||
String parent = rp.getAttribute("extends");
|
||||
if (!parent.isEmpty() && ConfigurationUtil.buildParentsFromString(configuration, parent).isEmpty()) {
|
||||
LOG.error("Unable to find parent packages {}", parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a PackageConfig from an XML element representing it.
|
||||
*
|
||||
* @param packageElement the given XML element
|
||||
* @return the package config
|
||||
* @throws ConfigurationException in case of configuration errors
|
||||
*/
|
||||
protected PackageConfig addPackage(Element packageElement) throws ConfigurationException {
|
||||
String packageName = packageElement.getAttribute("name");
|
||||
PackageConfig packageConfig = configuration.getPackageConfig(packageName);
|
||||
if (packageConfig != null) {
|
||||
LOG.debug("Package [{}] already loaded, skipping re-loading it and using existing PackageConfig [{}]", packageName, packageConfig);
|
||||
return packageConfig;
|
||||
}
|
||||
|
||||
PackageConfig.Builder newPackage = buildPackageContext(packageElement);
|
||||
|
||||
if (newPackage.isNeedsRefresh()) {
|
||||
return newPackage.build();
|
||||
}
|
||||
|
||||
LOG.debug("Loaded {}", newPackage);
|
||||
|
||||
// add result types (and default result) to this package
|
||||
addResultTypes(newPackage, packageElement);
|
||||
|
||||
// load the interceptors and interceptor stacks for this package
|
||||
loadInterceptors(newPackage, packageElement);
|
||||
|
||||
// load the default interceptor reference for this package
|
||||
loadDefaultInterceptorRef(newPackage, packageElement);
|
||||
|
||||
// load the default class ref for this package
|
||||
loadDefaultClassRef(newPackage, packageElement);
|
||||
|
||||
// load the global result list for this package
|
||||
loadGlobalResults(newPackage, packageElement);
|
||||
|
||||
loadGlobalAllowedMethods(newPackage, packageElement);
|
||||
|
||||
// load the global exception handler list for this package
|
||||
loadGlobalExceptionMappings(newPackage, packageElement);
|
||||
|
||||
// get actions
|
||||
iterateChildrenByTagName(packageElement, "action", actionElement -> addAction(actionElement, newPackage));
|
||||
|
||||
// load the default action reference for this package
|
||||
loadDefaultActionRef(newPackage, packageElement);
|
||||
|
||||
PackageConfig cfg = newPackage.build();
|
||||
configuration.addPackageConfig(cfg.getName(), cfg);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
protected void addAction(Element actionElement, PackageConfig.Builder packageContext) throws ConfigurationException {
|
||||
String name = actionElement.getAttribute("name");
|
||||
String className = actionElement.getAttribute("class");
|
||||
|
||||
Location location = DomHelper.getLocationObject(actionElement);
|
||||
|
||||
if (location == null) {
|
||||
LOG.warn("Location null for {}", className);
|
||||
}
|
||||
|
||||
if (!className.isEmpty() && !verifyAction(className, name, location)) {
|
||||
LOG.error("Unable to verify action [{}] with class [{}], from [{}]", name, className, location);
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, ResultConfig> results;
|
||||
try {
|
||||
results = buildResults(actionElement, packageContext);
|
||||
} catch (ConfigurationException e) {
|
||||
throw new ConfigurationException(
|
||||
format("Error building results for action %s in namespace %s", name, packageContext.getNamespace()),
|
||||
e,
|
||||
actionElement);
|
||||
}
|
||||
|
||||
ActionConfig actionConfig = buildActionConfig(actionElement, location, packageContext, results);
|
||||
packageContext.addActionConfig(actionConfig.getName(), actionConfig);
|
||||
|
||||
LOG.debug("Loaded {}{} in '{}' package: {}",
|
||||
isNotEmpty(packageContext.getNamespace()) ? (packageContext.getNamespace() + "/") : "",
|
||||
name, packageContext.getName(), actionConfig);
|
||||
}
|
||||
|
||||
protected ActionConfig buildActionConfig(Element actionElement,
|
||||
Location location,
|
||||
PackageConfig.Builder packageContext,
|
||||
Map<String, ResultConfig> results) {
|
||||
String actionName = actionElement.getAttribute("name");
|
||||
String className = actionElement.getAttribute("class");
|
||||
// methodName should be null if it's not set
|
||||
String methodName = trimToNull(actionElement.getAttribute("method"));
|
||||
|
||||
List<InterceptorMapping> interceptorList = buildInterceptorList(actionElement, packageContext);
|
||||
List<ExceptionMappingConfig> exceptionMappings = buildExceptionMappings(actionElement, packageContext);
|
||||
Set<String> allowedMethods = buildAllowedMethods(actionElement, packageContext);
|
||||
|
||||
return new ActionConfig.Builder(packageContext.getName(), actionName, className)
|
||||
.methodName(methodName)
|
||||
.addResultConfigs(results)
|
||||
.addInterceptors(interceptorList)
|
||||
.addExceptionMappings(exceptionMappings)
|
||||
.addParams(XmlHelper.getParams(actionElement))
|
||||
.setStrictMethodInvocation(packageContext.isStrictMethodInvocation())
|
||||
.addAllowedMethod(allowedMethods)
|
||||
.location(location)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.2.0, use {@link #verifyAction(String, Location)}
|
||||
*/
|
||||
@Deprecated
|
||||
protected boolean verifyAction(String className, String name, Location loc) {
|
||||
return verifyAction(className, loc);
|
||||
}
|
||||
|
||||
protected boolean verifyAction(String className, Location loc) {
|
||||
if (className.contains("{")) {
|
||||
LOG.debug("Action class [{}] contains a wildcard replacement value, so it can't be verified", className);
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
if (objectFactory.isNoArgConstructorRequired()) {
|
||||
Class<?> clazz = loadClass(className);
|
||||
if (!Modifier.isPublic(clazz.getModifiers())) {
|
||||
throw new ConfigurationException("Action class [" + className + "] is not public", loc);
|
||||
}
|
||||
clazz.getConstructor();
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
LOG.debug("Class not found for action [{}]", className, e);
|
||||
throw new ConfigurationException("Action class [" + className + "] not found", loc);
|
||||
} catch (NoSuchMethodException e) {
|
||||
LOG.debug("No constructor found for action [{}]", className, e);
|
||||
throw new ConfigurationException("Action class [" + className + "] does not have a public no-arg constructor", e, loc);
|
||||
} catch (RuntimeException ex) {
|
||||
// Probably not a big deal, like request or session-scoped Spring beans that need a real request
|
||||
LOG.info("Unable to verify action class [{}] exists at initialization", className);
|
||||
LOG.debug("Action verification cause", ex);
|
||||
} catch (Exception ex) {
|
||||
// Default to failing fast
|
||||
LOG.debug("Unable to verify action class [{}]", className, ex);
|
||||
throw new ConfigurationException(ex, loc);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void addResultTypes(PackageConfig.Builder packageContext, Element element) {
|
||||
iterateChildrenByTagName(element, "result-type", resultTypeElement -> {
|
||||
String name = resultTypeElement.getAttribute("name");
|
||||
String className = resultTypeElement.getAttribute("class");
|
||||
String def = resultTypeElement.getAttribute("default");
|
||||
|
||||
Location loc = DomHelper.getLocationObject(resultTypeElement);
|
||||
Class<?> clazz = verifyResultType(className, loc);
|
||||
if (clazz == null) {
|
||||
return;
|
||||
}
|
||||
String paramName = null;
|
||||
try {
|
||||
paramName = (String) clazz.getField("DEFAULT_PARAM").get(null);
|
||||
} catch (Throwable t) {
|
||||
LOG.debug("The result type [{}] doesn't have a default param [DEFAULT_PARAM] defined!", className, t);
|
||||
}
|
||||
packageContext.addResultTypeConfig(buildResultTypeConfig(resultTypeElement, loc, paramName));
|
||||
|
||||
if (BooleanUtils.toBoolean(def)) {
|
||||
packageContext.defaultResultType(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected ResultTypeConfig buildResultTypeConfig(Element resultTypeElement, Location location, String paramName) {
|
||||
String name = resultTypeElement.getAttribute("name");
|
||||
String className = resultTypeElement.getAttribute("class");
|
||||
ResultTypeConfig.Builder resultType = new ResultTypeConfig.Builder(name,
|
||||
className).defaultResultParam(paramName).location(location);
|
||||
Map<String, String> params = XmlHelper.getParams(resultTypeElement);
|
||||
if (!params.isEmpty()) {
|
||||
resultType.addParams(params);
|
||||
}
|
||||
return resultType.build();
|
||||
}
|
||||
|
||||
protected Class<?> verifyResultType(String className, Location loc) {
|
||||
try {
|
||||
return loadClass(className);
|
||||
} catch (ClassNotFoundException | NoClassDefFoundError e) {
|
||||
LOG.warn("Result class [{}] doesn't exist ({}) at {}, ignoring", className, e.getClass().getSimpleName(), loc, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>This method builds a package context by looking for the parents of this new package.</p>
|
||||
* <p>If no parents are found, it will return a root package.</p>
|
||||
*
|
||||
* @param packageElement the package element
|
||||
* @return the package config builder
|
||||
*/
|
||||
protected PackageConfig.Builder buildPackageContext(Element packageElement) {
|
||||
String parent = packageElement.getAttribute("extends");
|
||||
String abstractVal = packageElement.getAttribute("abstract");
|
||||
boolean isAbstract = parseBoolean(abstractVal);
|
||||
String name = defaultString(packageElement.getAttribute("name"));
|
||||
String namespace = defaultString(packageElement.getAttribute("namespace"));
|
||||
|
||||
// Strict DMI is enabled by default, it can be disabled by user
|
||||
boolean strictDMI = true;
|
||||
if (packageElement.hasAttribute("strict-method-invocation")) {
|
||||
strictDMI = parseBoolean(packageElement.getAttribute("strict-method-invocation"));
|
||||
}
|
||||
|
||||
PackageConfig.Builder cfg = new PackageConfig.Builder(name)
|
||||
.namespace(namespace)
|
||||
.isAbstract(isAbstract)
|
||||
.strictMethodInvocation(strictDMI)
|
||||
.location(DomHelper.getLocationObject(packageElement));
|
||||
|
||||
if (parent.isEmpty()) {
|
||||
return cfg;
|
||||
}
|
||||
|
||||
// has parents, let's look it up
|
||||
List<PackageConfig> parents = new ArrayList<>();
|
||||
for (String parentPackageName : ConfigurationUtil.buildParentListFromString(parent)) {
|
||||
if (configuration.getPackageConfigNames().contains(parentPackageName)) {
|
||||
parents.add(configuration.getPackageConfig(parentPackageName));
|
||||
} else if (declaredPackages.containsKey(parentPackageName)) {
|
||||
if (configuration.getPackageConfig(parentPackageName) == null) {
|
||||
addPackage(declaredPackages.get(parentPackageName));
|
||||
}
|
||||
parents.add(configuration.getPackageConfig(parentPackageName));
|
||||
} else {
|
||||
throw new ConfigurationException("Parent package is not defined: " + parentPackageName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (parents.isEmpty()) {
|
||||
cfg.needsRefresh(true);
|
||||
} else {
|
||||
cfg.addParents(parents);
|
||||
}
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a map of ResultConfig objects from below a given XML element.
|
||||
*
|
||||
* @param element the given XML element
|
||||
* @param packageContext the package context
|
||||
* @return map of result config objects
|
||||
*/
|
||||
protected Map<String, ResultConfig> buildResults(Element element, PackageConfig.Builder packageContext) {
|
||||
Map<String, ResultConfig> results = new LinkedHashMap<>();
|
||||
|
||||
iterateChildrenByTagName(element, "result", resultElement -> {
|
||||
Node parNode = resultElement.getParentNode();
|
||||
if (!parNode.equals(element) && !parNode.getNodeName().equals(element.getNodeName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
String resultName = resultElement.getAttribute("name");
|
||||
String resultType = resultElement.getAttribute("type");
|
||||
|
||||
// if you don't specify a name on <result/>, it defaults to "success"
|
||||
if (StringUtils.isEmpty(resultName)) {
|
||||
resultName = Action.SUCCESS;
|
||||
}
|
||||
|
||||
// there is no result type, so let's inherit from the parent package
|
||||
if (resultType.isEmpty()) {
|
||||
resultType = packageContext.getFullDefaultResultType();
|
||||
// now check if there is a result type now
|
||||
if (resultType.isEmpty()) {
|
||||
throw new ConfigurationException("No result type specified for result named '"
|
||||
+ resultName + "', perhaps the parent package does not specify the result type?", resultElement);
|
||||
}
|
||||
}
|
||||
|
||||
ResultTypeConfig config = packageContext.getResultType(resultType);
|
||||
if (config == null) {
|
||||
throw new ConfigurationException(format("There is no result type defined for type '%s' mapped with name '%s'. Did you mean '%s'?", resultType, resultName, guessResultType(resultType)), resultElement);
|
||||
}
|
||||
|
||||
String resultClass = config.getClassName();
|
||||
if (resultClass == null) {
|
||||
throw new ConfigurationException("Result type '" + resultType + "' is invalid");
|
||||
}
|
||||
|
||||
Set<String> resultNamesSet = commaDelimitedStringToSet(resultName);
|
||||
if (resultNamesSet.isEmpty()) {
|
||||
resultNamesSet.add(resultName);
|
||||
}
|
||||
|
||||
Map<String, String> params = buildResultParams(resultElement, config);
|
||||
Location location = DomHelper.getLocationObject(element);
|
||||
|
||||
for (String name : resultNamesSet) {
|
||||
ResultConfig resultConfig = buildResultConfig(name, config, location, params);
|
||||
results.put(resultConfig.getName(), resultConfig);
|
||||
}
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
protected ResultConfig buildResultConfig(String name,
|
||||
ResultTypeConfig config,
|
||||
Location location,
|
||||
Map<String, String> params) {
|
||||
return new ResultConfig.Builder(name, config.getClassName()).location(location).addParams(params).build();
|
||||
}
|
||||
|
||||
protected Map<String, String> buildResultParams(Element resultElement, ResultTypeConfig config) {
|
||||
Map<String, String> resultParams = XmlHelper.getParams(resultElement);
|
||||
|
||||
// maybe we just have a body - therefore a default parameter
|
||||
if (resultParams.isEmpty() && resultElement.getChildNodes().getLength() > 0) {
|
||||
// if <result ...>something</result> then we add a parameter of 'something' as this is the most used result param
|
||||
resultParams = new LinkedHashMap<>();
|
||||
|
||||
String paramName = config.getDefaultResultParam();
|
||||
if (paramName != null) {
|
||||
StringBuilder paramValue = new StringBuilder();
|
||||
iterateChildren(resultElement, child -> {
|
||||
if (child.getNodeType() == Node.TEXT_NODE) {
|
||||
String val = child.getNodeValue();
|
||||
if (val != null) {
|
||||
paramValue.append(val);
|
||||
}
|
||||
}
|
||||
});
|
||||
String val = paramValue.toString().trim();
|
||||
if (val.length() > 0) {
|
||||
resultParams.put(paramName, val);
|
||||
}
|
||||
} else {
|
||||
LOG.debug(
|
||||
"No default parameter defined for result [{}] of type [{}] ",
|
||||
config.getName(),
|
||||
config.getClassName());
|
||||
}
|
||||
}
|
||||
|
||||
// create new param map, so that the result param can override the config param
|
||||
Map<String, String> params = new LinkedHashMap<>();
|
||||
Map<String, String> configParams = config.getParams();
|
||||
if (configParams != null) {
|
||||
params.putAll(configParams);
|
||||
}
|
||||
params.putAll(resultParams);
|
||||
return params;
|
||||
}
|
||||
|
||||
protected static String guessResultType(String type) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean capNext = false;
|
||||
for (int x = 0; x < type.length(); x++) {
|
||||
char c = type.charAt(x);
|
||||
if (c == '-') {
|
||||
capNext = true;
|
||||
continue;
|
||||
} else if (isLowerCase(c) && capNext) {
|
||||
c = toUpperCase(c);
|
||||
capNext = false;
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.2.0, use {@link #buildExceptionMappings(Element)}
|
||||
*/
|
||||
@Deprecated
|
||||
protected List<ExceptionMappingConfig> buildExceptionMappings(Element element, PackageConfig.Builder packageContext) {
|
||||
return buildExceptionMappings(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a list of exception mapping objects from below a given XML element.
|
||||
*
|
||||
* @param element the given XML element
|
||||
* @return list of exception mapping config objects
|
||||
*/
|
||||
protected List<ExceptionMappingConfig> buildExceptionMappings(Element element) {
|
||||
List<ExceptionMappingConfig> exceptionMappings = new ArrayList<>();
|
||||
|
||||
iterateChildrenByTagName(element, "exception-mapping", ehElement -> {
|
||||
Node parNode = ehElement.getParentNode();
|
||||
if (!parNode.equals(element) && !parNode.getNodeName().equals(element.getNodeName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
String emName = ehElement.getAttribute("name");
|
||||
String exceptionClassName = ehElement.getAttribute("exception");
|
||||
String exceptionResult = ehElement.getAttribute("result");
|
||||
Map<String, String> params = XmlHelper.getParams(ehElement);
|
||||
if (emName.isEmpty()) {
|
||||
emName = exceptionResult;
|
||||
}
|
||||
|
||||
ExceptionMappingConfig ehConfig = new ExceptionMappingConfig.Builder(emName, exceptionClassName, exceptionResult)
|
||||
.addParams(params)
|
||||
.location(DomHelper.getLocationObject(ehElement))
|
||||
.build();
|
||||
exceptionMappings.add(ehConfig);
|
||||
});
|
||||
|
||||
return exceptionMappings;
|
||||
}
|
||||
|
||||
protected Set<String> buildAllowedMethods(Element element, PackageConfig.Builder packageContext) {
|
||||
NodeList allowedMethodsEls = element.getElementsByTagName("allowed-methods");
|
||||
|
||||
Set<String> allowedMethods;
|
||||
if (allowedMethodsEls.getLength() > 0) {
|
||||
// user defined 'allowed-methods' so used them whatever Strict DMI was enabled or not
|
||||
allowedMethods = new HashSet<>(packageContext.getGlobalAllowedMethods());
|
||||
// Fix for WW-5029 (concatenate all possible text node children)
|
||||
Node allowedMethodsNode = allowedMethodsEls.item(0);
|
||||
addAllowedMethodsToSet(allowedMethodsNode, allowedMethods);
|
||||
} else if (packageContext.isStrictMethodInvocation()) {
|
||||
// user enabled Strict DMI but didn't define action specific 'allowed-methods' so we use 'global-allowed-methods' only
|
||||
allowedMethods = new HashSet<>(packageContext.getGlobalAllowedMethods());
|
||||
} else {
|
||||
// Strict DMI is disabled so any method can be called
|
||||
allowedMethods = new HashSet<>();
|
||||
allowedMethods.add(ActionConfig.WILDCARD);
|
||||
}
|
||||
|
||||
LOG.debug("Collected allowed methods: {}", allowedMethods);
|
||||
|
||||
return Collections.unmodifiableSet(allowedMethods);
|
||||
}
|
||||
|
||||
protected void loadDefaultActionRef(PackageConfig.Builder packageContext, Element element) {
|
||||
NodeList resultTypeList = element.getElementsByTagName("default-action-ref");
|
||||
|
||||
if (resultTypeList.getLength() > 0) {
|
||||
Element defaultRefElement = (Element) resultTypeList.item(0);
|
||||
packageContext.defaultActionRef(defaultRefElement.getAttribute("name"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all the global results for this package from the XML element.
|
||||
*
|
||||
* @param packageContext the package context
|
||||
* @param packageElement the given XML element
|
||||
*/
|
||||
protected void loadGlobalResults(PackageConfig.Builder packageContext, Element packageElement) {
|
||||
NodeList globalResultList = packageElement.getElementsByTagName("global-results");
|
||||
|
||||
if (globalResultList.getLength() > 0) {
|
||||
Element globalResultElement = (Element) globalResultList.item(0);
|
||||
Map<String, ResultConfig> results = buildResults(globalResultElement, packageContext);
|
||||
packageContext.addGlobalResultConfigs(results);
|
||||
}
|
||||
}
|
||||
|
||||
protected void loadGlobalAllowedMethods(PackageConfig.Builder packageContext, Element packageElement) {
|
||||
NodeList globalAllowedMethodsElms = packageElement.getElementsByTagName("global-allowed-methods");
|
||||
|
||||
if (globalAllowedMethodsElms.getLength() > 0) {
|
||||
Set<String> globalAllowedMethods = new HashSet<>();
|
||||
// Fix for WW-5029 (concatenate all possible text node children)
|
||||
Node globalAllowedMethodsNode = globalAllowedMethodsElms.item(0);
|
||||
addAllowedMethodsToSet(globalAllowedMethodsNode, globalAllowedMethods);
|
||||
packageContext.addGlobalAllowedMethods(globalAllowedMethods);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void addAllowedMethodsToSet(Node allowedMethodsNode, Set<String> allowedMethodsSet) {
|
||||
if (allowedMethodsNode == null) {
|
||||
return;
|
||||
}
|
||||
StringBuilder allowedMethodsSB = new StringBuilder();
|
||||
iterateChildren(allowedMethodsNode, allowedMethodsChildNode -> {
|
||||
if (allowedMethodsChildNode != null && allowedMethodsChildNode.getNodeType() == Node.TEXT_NODE) {
|
||||
String childNodeValue = allowedMethodsChildNode.getNodeValue();
|
||||
childNodeValue = (childNodeValue != null ? childNodeValue.trim() : "");
|
||||
if (childNodeValue.length() > 0) {
|
||||
allowedMethodsSB.append(childNodeValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (allowedMethodsSB.length() > 0) {
|
||||
allowedMethodsSet.addAll(commaDelimitedStringToSet(allowedMethodsSB.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
protected void loadDefaultClassRef(PackageConfig.Builder packageContext, Element element) {
|
||||
NodeList defaultClassRefList = element.getElementsByTagName("default-class-ref");
|
||||
if (defaultClassRefList.getLength() > 0) {
|
||||
Element defaultClassRefElement = (Element) defaultClassRefList.item(0);
|
||||
packageContext.defaultClassRef(defaultClassRefElement.getAttribute("class"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all the global results for this package from the XML element.
|
||||
*
|
||||
* @param packageContext the package context
|
||||
* @param packageElement the given XML element
|
||||
*/
|
||||
protected void loadGlobalExceptionMappings(PackageConfig.Builder packageContext, Element packageElement) {
|
||||
NodeList globalExceptionMappingList = packageElement.getElementsByTagName("global-exception-mappings");
|
||||
|
||||
if (globalExceptionMappingList.getLength() > 0) {
|
||||
Element globalExceptionMappingElement = (Element) globalExceptionMappingList.item(0);
|
||||
List<ExceptionMappingConfig> exceptionMappings = buildExceptionMappings(globalExceptionMappingElement, packageContext);
|
||||
packageContext.addGlobalExceptionMappingConfigs(exceptionMappings);
|
||||
}
|
||||
}
|
||||
|
||||
protected List<InterceptorMapping> buildInterceptorList(Element element, PackageConfig.Builder context) throws ConfigurationException {
|
||||
List<InterceptorMapping> interceptorList = new ArrayList<>();
|
||||
|
||||
iterateChildrenByTagName(element, "interceptor-ref", interceptorRefElement -> {
|
||||
Node parNode = interceptorRefElement.getParentNode();
|
||||
if (!parNode.equals(element) && !parNode.getNodeName().equals(element.getNodeName())) {
|
||||
return;
|
||||
}
|
||||
List<InterceptorMapping> interceptors = lookupInterceptorReference(context, interceptorRefElement);
|
||||
interceptorList.addAll(interceptors);
|
||||
});
|
||||
|
||||
return interceptorList;
|
||||
}
|
||||
|
||||
protected void loadInterceptors(PackageConfig.Builder context, Element element) throws ConfigurationException {
|
||||
iterateChildrenByTagName(
|
||||
element,
|
||||
"interceptor",
|
||||
interceptorElement -> context.addInterceptorConfig(buildInterceptorConfig(interceptorElement)));
|
||||
loadInterceptorStacks(element, context);
|
||||
}
|
||||
|
||||
protected InterceptorConfig buildInterceptorConfig(Element interceptorElement) {
|
||||
String interceptorName = interceptorElement.getAttribute("name");
|
||||
String className = interceptorElement.getAttribute("class");
|
||||
|
||||
Map<String, String> params = XmlHelper.getParams(interceptorElement);
|
||||
return new InterceptorConfig.Builder(interceptorName, className)
|
||||
.addParams(params)
|
||||
.location(DomHelper.getLocationObject(interceptorElement))
|
||||
.build();
|
||||
}
|
||||
|
||||
protected void loadInterceptorStacks(Element element, PackageConfig.Builder context) throws ConfigurationException {
|
||||
iterateChildrenByTagName(element, "interceptor-stack", interceptorStackElement -> {
|
||||
InterceptorStackConfig config = loadInterceptorStack(interceptorStackElement, context);
|
||||
context.addInterceptorStackConfig(config);
|
||||
});
|
||||
}
|
||||
|
||||
protected InterceptorStackConfig loadInterceptorStack(Element element, PackageConfig.Builder context) throws ConfigurationException {
|
||||
String name = element.getAttribute("name");
|
||||
InterceptorStackConfig.Builder config = new InterceptorStackConfig.Builder(name)
|
||||
.location(DomHelper.getLocationObject(element));
|
||||
|
||||
iterateChildrenByTagName(element, "interceptor-ref", interceptorRefElement -> {
|
||||
List<InterceptorMapping> interceptors = lookupInterceptorReference(context, interceptorRefElement);
|
||||
config.addInterceptors(interceptors);
|
||||
});
|
||||
|
||||
return config.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the Interceptor Class from the interceptor-ref name and creates an instance, which is added to the
|
||||
* provided List, or, if this is a ref to a stack, it adds the Interceptor instances from the List to this stack.
|
||||
*
|
||||
* @param context The PackageConfig to look up the interceptor from
|
||||
* @param interceptorRefElement Element to pull interceptor ref data from
|
||||
* @return A list of Interceptor objects
|
||||
* @throws ConfigurationException in case of configuration errors
|
||||
*/
|
||||
protected List<InterceptorMapping> lookupInterceptorReference(PackageConfig.Builder context, Element interceptorRefElement) throws ConfigurationException {
|
||||
String refName = interceptorRefElement.getAttribute("name");
|
||||
Map<String, String> refParams = XmlHelper.getParams(interceptorRefElement);
|
||||
|
||||
Location loc = LocationUtils.getLocation(interceptorRefElement);
|
||||
return InterceptorBuilder.constructInterceptorReference(context, refName, refParams, loc, objectFactory);
|
||||
}
|
||||
|
||||
protected void loadDefaultInterceptorRef(PackageConfig.Builder packageContext, Element element) {
|
||||
NodeList resultTypeList = element.getElementsByTagName("default-interceptor-ref");
|
||||
|
||||
if (resultTypeList.getLength() > 0) {
|
||||
Element defaultRefElement = (Element) resultTypeList.item(0);
|
||||
packageContext.defaultInterceptorRef(defaultRefElement.getAttribute("name"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,25 +201,11 @@ public enum Scope {
|
||||
|
||||
<T> Callable<? extends T> toCallable(final InternalContext context,
|
||||
final InternalFactory<? extends T> factory) {
|
||||
return (Callable<T>) () -> InitializableFactory.wrapIfNeeded(factory).create(context);
|
||||
}
|
||||
|
||||
public static Scope fromString(String scopeStr) {
|
||||
switch (scopeStr) {
|
||||
case "prototype":
|
||||
return Scope.PROTOTYPE;
|
||||
case "request":
|
||||
return Scope.REQUEST;
|
||||
case "session":
|
||||
return Scope.SESSION;
|
||||
case "thread":
|
||||
return Scope.THREAD;
|
||||
case "wizard":
|
||||
return Scope.WIZARD;
|
||||
case "singleton":
|
||||
default:
|
||||
return Scope.SINGLETON;
|
||||
}
|
||||
return new Callable<T>() {
|
||||
public T call() throws Exception {
|
||||
return InitializableFactory.wrapIfNeeded(factory).create(context);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+16
-16
@@ -52,9 +52,9 @@ import java.util.Map;
|
||||
* <ul>
|
||||
*
|
||||
* <li>logEnabled (optional) - Should exceptions also be logged? (boolean true|false)</li>
|
||||
*
|
||||
*
|
||||
* <li>logLevel (optional) - what log level should we use (<code>trace, debug, info, warn, error, fatal</code>)? - defaut is <code>debug</code></li>
|
||||
*
|
||||
*
|
||||
* <li>logCategory (optional) - If provided we would use this category (eg. <code>com.mycompany.app</code>).
|
||||
* Default is to use <code>com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor</code>.</li>
|
||||
*
|
||||
@@ -102,7 +102,7 @@ import java.util.Map;
|
||||
* </xwork>
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* This second example will also log the exceptions using our own category
|
||||
* <code>com.mycompany.app.unhandled</code> at WARN level.
|
||||
@@ -117,8 +117,8 @@ import java.util.Map;
|
||||
* <interceptor-ref name="exception">
|
||||
* <param name="logEnabled">true</param>
|
||||
* <param name="logCategory">com.mycompany.app.unhandled</param>
|
||||
* <param name="logLevel">WARN</param>
|
||||
* </interceptor-ref>
|
||||
* <param name="logLevel">WARN</param>
|
||||
* </interceptor-ref>
|
||||
* <interceptor-ref name="i18n"/>
|
||||
* <interceptor-ref name="staticParams"/>
|
||||
* <interceptor-ref name="params"/>
|
||||
@@ -129,7 +129,7 @@ import java.util.Map;
|
||||
* </interceptors>
|
||||
*
|
||||
* <default-interceptor-ref name="exceptionmappingStack"/>
|
||||
*
|
||||
*
|
||||
* <global-results>
|
||||
* <result name="unhandledException">/unhandled-exception.jsp</result>
|
||||
* </global-results>
|
||||
@@ -137,12 +137,12 @@ import java.util.Map;
|
||||
* <global-exception-mappings>
|
||||
* <exception-mapping exception="java.lang.Exception" result="unhandledException"/>
|
||||
* </global-exception-mappings>
|
||||
*
|
||||
*
|
||||
* <action name="exceptionDemo" class="org.apache.struts2.showcase.exceptionmapping.ExceptionMappingAction">
|
||||
* <exception-mapping exception="org.apache.struts2.showcase.exceptionmapping.ExceptionMappingException"
|
||||
* result="damm"/>
|
||||
* <result name="input">index.jsp</result>
|
||||
* <result name="success">success.jsp</result>
|
||||
* <result name="success">success.jsp</result>
|
||||
* <result name="damm">damm.jsp</result>
|
||||
* </action>
|
||||
*
|
||||
@@ -151,18 +151,18 @@ import java.util.Map;
|
||||
* <!-- END SNIPPET: example2 -->
|
||||
* </pre>
|
||||
*
|
||||
* @author Matthew E. Porter (matthew dot porter at metissian dot com)
|
||||
* @author Matthew E. Porter (matthew dot porter at metissian dot com)
|
||||
* @author Claus Ibsen
|
||||
*/
|
||||
public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ExceptionMappingInterceptor.class);
|
||||
|
||||
protected Logger categoryLogger;
|
||||
protected boolean logEnabled = false;
|
||||
protected String logCategory;
|
||||
protected String logLevel;
|
||||
|
||||
|
||||
|
||||
public boolean isLogEnabled() {
|
||||
return logEnabled;
|
||||
@@ -204,7 +204,7 @@ public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
Map<String, String> mappingParams = mappingConfig.getParams();
|
||||
// create a mutable HashMap since some interceptors will remove parameters, and parameterMap is immutable
|
||||
HttpParameters parameters = HttpParameters.create(mappingParams).build();
|
||||
invocation.getInvocationContext().withParameters(parameters);
|
||||
invocation.getInvocationContext().setParameters(parameters);
|
||||
result = mappingConfig.getResult();
|
||||
publishException(invocation, new ExceptionHolder(e));
|
||||
} else {
|
||||
@@ -217,7 +217,7 @@ public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
|
||||
/**
|
||||
* Handles the logging of the exception.
|
||||
*
|
||||
*
|
||||
* @param e the exception to log.
|
||||
*/
|
||||
protected void handleLogging(Exception e) {
|
||||
@@ -231,10 +231,10 @@ public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
doLog(LOG, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs the actual logging.
|
||||
*
|
||||
*
|
||||
* @param logger the provided logger to use.
|
||||
* @param e the exception to log.
|
||||
*/
|
||||
@@ -243,7 +243,7 @@ public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
logger.debug(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ("trace".equalsIgnoreCase(logLevel)) {
|
||||
logger.trace(e.getMessage(), e);
|
||||
} else if ("debug".equalsIgnoreCase(logLevel)) {
|
||||
|
||||
@@ -30,8 +30,7 @@ package com.opensymphony.xwork2.interceptor;
|
||||
* parameters cannot be set by malicious users.
|
||||
* </p>
|
||||
*
|
||||
* @deprecated since Struts 6.2.0, use {@link org.apache.struts2.action.NoParameters}
|
||||
* @author Dick Zetterberg (dick@transitor.se)
|
||||
*/
|
||||
@Deprecated
|
||||
public interface NoParameters {
|
||||
}
|
||||
|
||||
+14
-14
@@ -34,33 +34,33 @@ import java.util.TreeMap;
|
||||
* <!-- START SNIPPET: description -->
|
||||
*
|
||||
* The Parameter Filter Interceptor blocks parameters from getting
|
||||
* to the rest of the stack or your action. You can use multiple
|
||||
* to the rest of the stack or your action. You can use multiple
|
||||
* parameter filter interceptors for a given action, so, for example,
|
||||
* you could use one in your default stack that filtered parameters
|
||||
* you wanted blocked from every action and those you wanted blocked
|
||||
* you wanted blocked from every action and those you wanted blocked
|
||||
* from an individual action you could add an additional interceptor
|
||||
* for each action.
|
||||
*
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
*
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
*
|
||||
* <ul>
|
||||
* <li>allowed - a comma delimited list of parameter prefixes
|
||||
* that are allowed to pass to the action</li>
|
||||
* <li>blocked - a comma delimited list of parameter prefixes
|
||||
* <li>blocked - a comma delimited list of parameter prefixes
|
||||
* that are not allowed to pass to the action</li>
|
||||
* <li>defaultBlock - boolean (default to false) whether by
|
||||
* default a given parameter is blocked. If true, then a parameter
|
||||
* must have a prefix in the allowed list in order to be able
|
||||
* must have a prefix in the allowed list in order to be able
|
||||
* to pass to the action
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* <p>The way parameters are filtered for the least configuration is that
|
||||
* if a string is in the allowed or blocked lists, then any parameter
|
||||
* that is a member of the object represented by the parameter is allowed
|
||||
* or blocked respectively.</p>
|
||||
*
|
||||
*
|
||||
* <p>For example, if the parameters are:
|
||||
* <ul>
|
||||
* <li>blocked: person,person.address.createDate,personDao</li>
|
||||
@@ -69,16 +69,16 @@ import java.util.TreeMap;
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* The parameters person.name, person.phoneNum etc would be blocked
|
||||
* The parameters person.name, person.phoneNum etc would be blocked
|
||||
* because 'person' is in the blocked list. However, person.address.street
|
||||
* and person.address.city would be allowed because person.address is
|
||||
* in the allowed list (the longer string determines permissions).</p>
|
||||
* in the allowed list (the longer string determines permissions).</p>
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
*
|
||||
* <!-- START SNIPPET: extending -->
|
||||
* There are no known extension points to this interceptor.
|
||||
* <!-- END SNIPPET: extending -->
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
* <interceptors>
|
||||
@@ -86,7 +86,7 @@ import java.util.TreeMap;
|
||||
* <interceptor name="parameterFilter" class="com.opensymphony.xwork2.interceptor.ParameterFilterInterceptor"/>
|
||||
* ...
|
||||
* </interceptors>
|
||||
*
|
||||
*
|
||||
* <action ....>
|
||||
* ...
|
||||
* <interceptor-ref name="parameterFilter">
|
||||
@@ -96,7 +96,7 @@ import java.util.TreeMap;
|
||||
* </action>
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @author Gabe
|
||||
*/
|
||||
public class ParameterFilterInterceptor extends AbstractInterceptor {
|
||||
@@ -133,7 +133,7 @@ public class ParameterFilterInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
}
|
||||
|
||||
invocation.getInvocationContext().withParameters(parameters);
|
||||
invocation.getInvocationContext().setParameters(parameters);
|
||||
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
+85
-67
@@ -23,102 +23,120 @@ import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.action.NoParameters;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
* This is a simple XWork interceptor that allows parameters (matching
|
||||
* one of the paramNames attribute csv value) to be
|
||||
* one of the paramNames attribute csv value) to be
|
||||
* removed from the parameter map if they match a certain value
|
||||
* (matching one of the paramValues attribute csv value), before they
|
||||
* are set on the action. A typical usage would be to want a dropdown/select
|
||||
* to map onto a boolean value on an action. The select had the options
|
||||
* none, yes and no with values -1, true and false. The true and false would
|
||||
* map across correctly. However the -1 would be set to false.
|
||||
* This was not desired as one might needed the value on the action to stay null.
|
||||
* This interceptor fixes this by preventing the parameter from ever reaching
|
||||
* (matching one of the paramValues attribute csv value), before they
|
||||
* are set on the action. A typical usage would be to want a dropdown/select
|
||||
* to map onto a boolean value on an action. The select had the options
|
||||
* none, yes and no with values -1, true and false. The true and false would
|
||||
* map across correctly. However the -1 would be set to false.
|
||||
* This was not desired as one might needed the value on the action to stay null.
|
||||
* This interceptor fixes this by preventing the parameter from ever reaching
|
||||
* the action.
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
*
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
* <ul>
|
||||
* <li>paramNames - A comma separated value (csv) indicating the parameter name
|
||||
* whose param value should be considered that if they match any of the
|
||||
* comma separated value (csv) from paramValues attribute, shall be
|
||||
* removed from the parameter map such that they will not be applied
|
||||
* to the action</li>
|
||||
* <li>paramValues - A comma separated value (csv) indicating the parameter value that if
|
||||
* matched shall have its parameter be removed from the parameter map
|
||||
* such that they will not be applied to the action</li>
|
||||
* <li>paramNames - A comma separated value (csv) indicating the parameter name
|
||||
* whose param value should be considered that if they match any of the
|
||||
* comma separated value (csv) from paramValues attribute, shall be
|
||||
* removed from the parameter map such that they will not be applied
|
||||
* to the action</li>
|
||||
* <li>paramValues - A comma separated value (csv) indicating the parameter value that if
|
||||
* matched shall have its parameter be removed from the parameter map
|
||||
* such that they will not be applied to the action</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
*
|
||||
*
|
||||
* <!-- START SNIPPET: extending -->
|
||||
* No intended extension point
|
||||
*
|
||||
* <!-- END SNIPPET: extending -->
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
*
|
||||
* <action name="sample" class="org.martingilday.Sample">
|
||||
* <interceptor-ref name="paramRemover">
|
||||
* <param name="paramNames">aParam,anotherParam</param>
|
||||
* <param name="paramValues">--,-1</param>
|
||||
* <param name="paramNames">aParam,anotherParam</param>
|
||||
* <param name="paramValues">--,-1</param>
|
||||
* </interceptor-ref>
|
||||
* <interceptor-ref name="defaultStack" />
|
||||
* ...
|
||||
* </action>
|
||||
*
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @author martin.gilday
|
||||
*/
|
||||
public class ParameterRemoverInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ParameterRemoverInterceptor.class);
|
||||
private static final Logger LOG = LogManager.getLogger(ParameterRemoverInterceptor.class);
|
||||
|
||||
private Set<String> paramNames = Collections.emptySet();
|
||||
private Set<String> paramValues = Collections.emptySet();
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
/**
|
||||
* Decide if the parameter should be removed from the parameter map based on
|
||||
* <code>paramNames</code> and <code>paramValues</code>.
|
||||
*
|
||||
* @see com.opensymphony.xwork2.interceptor.AbstractInterceptor
|
||||
*/
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
if (!(invocation.getAction() instanceof NoParameters)
|
||||
&& (null != this.paramNames)) {
|
||||
ActionContext ac = invocation.getInvocationContext();
|
||||
HttpParameters parameters = ac.getParameters();
|
||||
private Set<String> paramNames = Collections.emptySet();
|
||||
private Set<String> paramValues = Collections.emptySet();
|
||||
|
||||
if (parameters != null) {
|
||||
|
||||
/**
|
||||
* Decide if the parameter should be removed from the parameter map based on
|
||||
* <code>paramNames</code> and <code>paramValues</code>.
|
||||
*
|
||||
* @see com.opensymphony.xwork2.interceptor.AbstractInterceptor
|
||||
*/
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
if (!(invocation.getAction() instanceof NoParameters)
|
||||
&& (null != this.paramNames)) {
|
||||
ActionContext ac = invocation.getInvocationContext();
|
||||
HttpParameters parameters = ac.getParameters();
|
||||
|
||||
if (parameters != null) {
|
||||
for (String removeName : paramNames) {
|
||||
try {
|
||||
Parameter parameter = parameters.get(removeName);
|
||||
if (parameter.isDefined() && this.paramValues.contains(parameter.getValue())) {
|
||||
parameters.remove(removeName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to convert parameter to string", e);
|
||||
}
|
||||
try {
|
||||
Parameter parameter = parameters.get(removeName);
|
||||
if (parameter.isDefined() && this.paramValues.contains(parameter.getValue())) {
|
||||
parameters.remove(removeName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to convert parameter to string", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows <code>paramNames</code> attribute to be set as comma-separated-values (csv).
|
||||
*
|
||||
* @param paramNames the paramNames to set
|
||||
*/
|
||||
public void setParamNames(String paramNames) {
|
||||
this.paramNames = TextParseUtil.commaDelimitedStringToSet(paramNames);
|
||||
}
|
||||
/**
|
||||
* Allows <code>paramNames</code> attribute to be set as comma-separated-values (csv).
|
||||
*
|
||||
* @param paramNames the paramNames to set
|
||||
*/
|
||||
public void setParamNames(String paramNames) {
|
||||
this.paramNames = TextParseUtil.commaDelimitedStringToSet(paramNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows <code>paramValues</code> attribute to be set as a comma-separated-values (csv).
|
||||
*
|
||||
* @param paramValues the paramValues to set
|
||||
*/
|
||||
public void setParamValues(String paramValues) {
|
||||
this.paramValues = TextParseUtil.commaDelimitedStringToSet(paramValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows <code>paramValues</code> attribute to be set as a comma-separated-values (csv).
|
||||
*
|
||||
* @param paramValues the paramValues to set
|
||||
*/
|
||||
public void setParamValues(String paramValues) {
|
||||
this.paramValues = TextParseUtil.commaDelimitedStringToSet(paramValues);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -236,6 +236,6 @@ public class StaticParametersInterceptor extends AbstractInterceptor {
|
||||
combinedParams = HttpParameters.create(newParams);
|
||||
combinedParams = combinedParams.withExtraParams(previousParams);
|
||||
}
|
||||
ac.withParameters(combinedParams.build());
|
||||
ac.setParameters(combinedParams.build());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ public class AnnotationParameterFilterInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
}
|
||||
|
||||
invocation.getInvocationContext().withParameters(parameters);
|
||||
invocation.getInvocationContext().setParameters(parameters);
|
||||
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
@@ -26,13 +26,7 @@ import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionException;
|
||||
import ognl.ClassResolver;
|
||||
import ognl.Ognl;
|
||||
import ognl.OgnlContext;
|
||||
import ognl.OgnlException;
|
||||
import ognl.OgnlRuntime;
|
||||
import ognl.SimpleNode;
|
||||
import ognl.TypeConverter;
|
||||
import ognl.*;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -43,12 +37,7 @@ import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -77,12 +66,10 @@ public class OgnlUtil {
|
||||
private Set<Class<?>> excludedClasses;
|
||||
private Set<Pattern> excludedPackageNamePatterns;
|
||||
private Set<String> excludedPackageNames;
|
||||
private Set<Class<?>> excludedPackageExemptClasses;
|
||||
|
||||
private Set<Class<?>> devModeExcludedClasses;
|
||||
private Set<Pattern> devModeExcludedPackageNamePatterns;
|
||||
private Set<String> devModeExcludedPackageNames;
|
||||
private Set<Class<?>> devModeExcludedPackageExemptClasses;
|
||||
|
||||
private Container container;
|
||||
private boolean allowStaticFieldAccess = true;
|
||||
@@ -125,12 +112,10 @@ public class OgnlUtil {
|
||||
excludedClasses = Collections.unmodifiableSet(new HashSet<>());
|
||||
excludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
|
||||
excludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
|
||||
excludedPackageExemptClasses = Collections.unmodifiableSet(new HashSet<>());
|
||||
|
||||
devModeExcludedClasses = Collections.unmodifiableSet(new HashSet<>());
|
||||
devModeExcludedPackageNamePatterns = Collections.unmodifiableSet(new HashSet<>());
|
||||
devModeExcludedPackageNames = Collections.unmodifiableSet(new HashSet<>());
|
||||
devModeExcludedPackageExemptClasses = Collections.unmodifiableSet(new HashSet<>());
|
||||
|
||||
this.expressionCache = ognlExpressionCacheFactory.buildOgnlCache();
|
||||
this.beanInfoCache = ognlBeanInfoCacheFactory.buildOgnlCache();
|
||||
@@ -174,7 +159,7 @@ public class OgnlUtil {
|
||||
protected void setExcludedClasses(String commaDelimitedClasses) {
|
||||
Set<Class<?>> excludedClasses = new HashSet<>();
|
||||
excludedClasses.addAll(this.excludedClasses);
|
||||
excludedClasses.addAll(parseClasses(commaDelimitedClasses));
|
||||
excludedClasses.addAll(parseExcludedClasses(commaDelimitedClasses));
|
||||
this.excludedClasses = Collections.unmodifiableSet(excludedClasses);
|
||||
}
|
||||
|
||||
@@ -182,11 +167,11 @@ public class OgnlUtil {
|
||||
protected void setDevModeExcludedClasses(String commaDelimitedClasses) {
|
||||
Set<Class<?>> excludedClasses = new HashSet<>();
|
||||
excludedClasses.addAll(this.devModeExcludedClasses);
|
||||
excludedClasses.addAll(parseClasses(commaDelimitedClasses));
|
||||
excludedClasses.addAll(parseExcludedClasses(commaDelimitedClasses));
|
||||
this.devModeExcludedClasses = Collections.unmodifiableSet(excludedClasses);
|
||||
}
|
||||
|
||||
private Set<Class<?>> parseClasses(String commaDelimitedClasses) {
|
||||
private Set<Class<?>> parseExcludedClasses(String commaDelimitedClasses) {
|
||||
Set<String> classNames = TextParseUtil.commaDelimitedStringToSet(commaDelimitedClasses);
|
||||
Set<Class<?>> classes = new HashSet<>();
|
||||
|
||||
@@ -194,7 +179,7 @@ public class OgnlUtil {
|
||||
try {
|
||||
classes.add(Class.forName(className));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ConfigurationException("Cannot load class for exclusion/exemption configuration: " + className, e);
|
||||
throw new ConfigurationException("Cannot load excluded class: " + className, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,22 +229,6 @@ public class OgnlUtil {
|
||||
this.devModeExcludedPackageNames = Collections.unmodifiableSet(excludedPackageNames);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_EXCLUDED_PACKAGE_EXEMPT_CLASSES, required = false)
|
||||
public void setExcludedPackageExemptClasses(String commaDelimitedClasses) {
|
||||
Set<Class<?>> excludedPackageExemptClasses = new HashSet<>();
|
||||
excludedPackageExemptClasses.addAll(this.excludedPackageExemptClasses);
|
||||
excludedPackageExemptClasses.addAll(parseClasses(commaDelimitedClasses));
|
||||
this.excludedPackageExemptClasses = Collections.unmodifiableSet(excludedPackageExemptClasses);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_EXEMPT_CLASSES, required = false)
|
||||
public void setDevModeExcludedPackageExemptClasses(String commaDelimitedClasses) {
|
||||
Set<Class<?>> excludedPackageExemptClasses = new HashSet<>();
|
||||
excludedPackageExemptClasses.addAll(this.devModeExcludedPackageExemptClasses);
|
||||
excludedPackageExemptClasses.addAll(parseClasses(commaDelimitedClasses));
|
||||
this.devModeExcludedPackageExemptClasses = Collections.unmodifiableSet(excludedPackageExemptClasses);
|
||||
}
|
||||
|
||||
private Set<String> parseExcludedPackageNames(String commaDelimitedPackageNames) {
|
||||
return TextParseUtil.commaDelimitedStringToSet(commaDelimitedPackageNames);
|
||||
}
|
||||
@@ -276,10 +245,6 @@ public class OgnlUtil {
|
||||
return excludedPackageNames;
|
||||
}
|
||||
|
||||
public Set<Class<?>> getExcludedPackageExemptClasses() {
|
||||
return excludedPackageExemptClasses;
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected void setContainer(Container container) {
|
||||
this.container = container;
|
||||
@@ -882,12 +847,10 @@ public class OgnlUtil {
|
||||
memberAccess.setExcludedClasses(devModeExcludedClasses);
|
||||
memberAccess.setExcludedPackageNamePatterns(devModeExcludedPackageNamePatterns);
|
||||
memberAccess.setExcludedPackageNames(devModeExcludedPackageNames);
|
||||
memberAccess.setExcludedPackageExemptClasses(devModeExcludedPackageExemptClasses);
|
||||
} else {
|
||||
memberAccess.setExcludedClasses(excludedClasses);
|
||||
memberAccess.setExcludedPackageNamePatterns(excludedPackageNamePatterns);
|
||||
memberAccess.setExcludedPackageNames(excludedPackageNames);
|
||||
memberAccess.setExcludedPackageExemptClasses(excludedPackageExemptClasses);
|
||||
}
|
||||
|
||||
return Ognl.createDefaultContext(root, memberAccess, resolver, defaultConverter);
|
||||
|
||||
@@ -29,12 +29,7 @@ import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.MemberAccessValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionContextState;
|
||||
import ognl.MethodFailedException;
|
||||
import ognl.NoSuchPropertyException;
|
||||
import ognl.Ognl;
|
||||
import ognl.OgnlContext;
|
||||
import ognl.OgnlException;
|
||||
import ognl.PropertyAccessor;
|
||||
import ognl.*;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -92,7 +87,6 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
securityMemberAccess.setExcludedClasses(ognlUtil.getExcludedClasses());
|
||||
securityMemberAccess.setExcludedPackageNamePatterns(ognlUtil.getExcludedPackageNamePatterns());
|
||||
securityMemberAccess.setExcludedPackageNames(ognlUtil.getExcludedPackageNames());
|
||||
securityMemberAccess.setExcludedPackageExemptClasses(ognlUtil.getExcludedPackageExemptClasses());
|
||||
securityMemberAccess.setDisallowProxyMemberAccess(ognlUtil.isDisallowProxyMemberAccess());
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -48,7 +47,6 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
private Set<Class<?>> excludedClasses = Collections.emptySet();
|
||||
private Set<Pattern> excludedPackageNamePatterns = Collections.emptySet();
|
||||
private Set<String> excludedPackageNames = Collections.emptySet();
|
||||
private Set<Class<?>> excludedPackageExemptClasses = Collections.emptySet();
|
||||
private boolean disallowProxyMemberAccess;
|
||||
|
||||
/**
|
||||
@@ -96,12 +94,6 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
LOG.debug("Checking access for [target: {}, member: {}, property: {}]", target, member, propertyName);
|
||||
|
||||
final int memberModifiers = member.getModifiers();
|
||||
final Class<?> memberClass = member.getDeclaringClass();
|
||||
// target can be null in case of accessing static fields, since OGNL 3.2.8
|
||||
final Class<?> targetClass = Modifier.isStatic(memberModifiers) ? memberClass : target.getClass();
|
||||
if (!memberClass.isAssignableFrom(targetClass)) {
|
||||
throw new IllegalArgumentException("Target does not match member!");
|
||||
}
|
||||
|
||||
if (!checkPublicMemberAccess(memberModifiers)) {
|
||||
LOG.warn("Access to non-public [{}] is blocked!", member);
|
||||
@@ -124,29 +116,24 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Class<?> memberClass = member.getDeclaringClass();
|
||||
|
||||
if (isClassExcluded(memberClass)) {
|
||||
LOG.warn("Declaring class of member type [{}] is excluded!", member);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (targetClass != memberClass && isClassExcluded(targetClass)) {
|
||||
// Optimization: Already checked memberClass exclusion, so if-and-only-if targetClass == memberClass, this check is redundant.
|
||||
LOG.warn("Target class [{}] of target [{}] is excluded!", targetClass, target);
|
||||
// target can be null in case of accessing static fields, since OGNL 3.2.8
|
||||
final Class<?> targetClass = Modifier.isStatic(memberModifiers) ? memberClass : target.getClass();
|
||||
|
||||
if (isPackageExcluded(targetClass.getPackage(), memberClass.getPackage())) {
|
||||
LOG.warn("Package [{}] of target class [{}] of target [{}] or package [{}] of member [{}] are excluded!", targetClass.getPackage(), targetClass,
|
||||
target, memberClass.getPackage(), member);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (targetClass.getPackage() == null || memberClass.getPackage() == null) {
|
||||
LOG.warn("The use of the default (unnamed) package is discouraged!");
|
||||
}
|
||||
|
||||
if (isPackageExcluded(targetClass, memberClass)) {
|
||||
LOG.warn(
|
||||
"Package [{}] of target class [{}] of target [{}] or package [{}] of member [{}] are excluded!",
|
||||
targetClass.getPackage(),
|
||||
targetClass,
|
||||
target,
|
||||
memberClass.getPackage(),
|
||||
member);
|
||||
if (isClassExcluded(targetClass)) {
|
||||
LOG.warn("Target class [{}] of target [{}] is excluded!", targetClass, target);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -209,49 +196,29 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isPackageExcluded(Class<?> targetClass, Class<?> memberClass) {
|
||||
if (targetClass == null || memberClass == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Parameters should never be null - if member is static, targetClass should be the same as memberClass.");
|
||||
protected boolean isPackageExcluded(Package targetPackage, Package memberPackage) {
|
||||
if (targetPackage == null || memberPackage == null) {
|
||||
LOG.warn("The use of the default (unnamed) package is discouraged!");
|
||||
}
|
||||
|
||||
Set<Class<?>> classesToCheck = new HashSet<>();
|
||||
classesToCheck.add(targetClass);
|
||||
classesToCheck.add(memberClass);
|
||||
String targetPackageName = targetPackage == null ? "" : targetPackage.getName();
|
||||
String memberPackageName = memberPackage == null ? "" : memberPackage.getName();
|
||||
|
||||
for (Class<?> clazz : classesToCheck) {
|
||||
if (!isExcludedPackageExempt(clazz) && (isExcludedPackageNamePatterns(clazz) || isExcludedPackageNames(clazz))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected String toPackageName(Class<?> clazz) {
|
||||
if (clazz.getPackage() == null) {
|
||||
return "";
|
||||
} else {
|
||||
return clazz.getPackage().getName();
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isExcludedPackageNamePatterns(Class<?> clazz) {
|
||||
String packageName = toPackageName(clazz);
|
||||
for (Pattern pattern : excludedPackageNamePatterns) {
|
||||
if (pattern.matcher(packageName).matches()) {
|
||||
if (pattern.matcher(targetPackageName).matches() || pattern.matcher(memberPackageName).matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isExcludedPackageNames(Class<?> clazz) {
|
||||
String suffixedPackageName = toPackageName(clazz) + ".";
|
||||
for (String excludedPackageName : excludedPackageNames) {
|
||||
if (suffixedPackageName.startsWith(excludedPackageName)) {
|
||||
targetPackageName = targetPackageName + ".";
|
||||
memberPackageName = memberPackageName + ".";
|
||||
|
||||
for (String packageName : excludedPackageNames) {
|
||||
if (targetPackageName.startsWith(packageName) || memberPackageName.startsWith(packageName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -259,11 +226,12 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
if (clazz == Object.class || (clazz == Class.class && !allowStaticFieldAccess)) {
|
||||
return true;
|
||||
}
|
||||
return excludedClasses.stream().anyMatch(clazz::isAssignableFrom);
|
||||
}
|
||||
|
||||
protected boolean isExcludedPackageExempt(Class<?> clazz) {
|
||||
return excludedPackageExemptClasses.stream().anyMatch(clazz::equals);
|
||||
for (Class<?> excludedClass : excludedClasses) {
|
||||
if (clazz.isAssignableFrom(excludedClass)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isAcceptableProperty(String name) {
|
||||
@@ -319,10 +287,6 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
this.excludedPackageNames = excludedPackageNames;
|
||||
}
|
||||
|
||||
public void setExcludedPackageExemptClasses(Set<Class<?>> excludedPackageExemptClasses) {
|
||||
this.excludedPackageExemptClasses = excludedPackageExemptClasses;
|
||||
}
|
||||
|
||||
public void setDisallowProxyMemberAccess(boolean disallowProxyMemberAccess) {
|
||||
this.disallowProxyMemberAccess = disallowProxyMemberAccess;
|
||||
}
|
||||
|
||||
-5
@@ -109,11 +109,6 @@ public class XWorkListPropertyAccessor extends ListPropertyAccessor {
|
||||
if (listSize <= index) {
|
||||
Object result;
|
||||
|
||||
if (index > autoGrowCollectionLimit) {
|
||||
throw new OgnlException("Error auto growing collection size to " + index + " which limited to "
|
||||
+ autoGrowCollectionLimit);
|
||||
}
|
||||
|
||||
for (int i = listSize; i < index; i++) {
|
||||
list.add(null);
|
||||
}
|
||||
|
||||
@@ -18,11 +18,9 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.util;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.ClassUtils;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
@@ -54,7 +52,7 @@ public class AnnotationUtils {
|
||||
* @param clazz The {@link Class} to inspect
|
||||
* @param allFields list of all fields
|
||||
*/
|
||||
public static void addAllFields(Class<? extends Annotation> annotationClass, Class<?> clazz, List<Field> allFields) {
|
||||
public static void addAllFields(Class<? extends Annotation> annotationClass, Class clazz, List<Field> allFields) {
|
||||
|
||||
if (clazz == null) {
|
||||
return;
|
||||
@@ -78,7 +76,7 @@ public class AnnotationUtils {
|
||||
* @param clazz The {@link Class} to inspect
|
||||
* @param allMethods list of all methods
|
||||
*/
|
||||
public static void addAllMethods(Class<? extends Annotation> annotationClass, Class<?> clazz, List<Method> allMethods) {
|
||||
public static void addAllMethods(Class<? extends Annotation> annotationClass, Class clazz, List<Method> allMethods) {
|
||||
|
||||
if (clazz == null) {
|
||||
return;
|
||||
@@ -99,12 +97,12 @@ public class AnnotationUtils {
|
||||
* @param clazz The {@link Class} to inspect
|
||||
* @param allInterfaces list of all interfaces
|
||||
*/
|
||||
public static void addAllInterfaces(Class<?> clazz, List<Class<?>> allInterfaces) {
|
||||
public static void addAllInterfaces(Class clazz, List<Class> allInterfaces) {
|
||||
if (clazz == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Class<?>[] interfaces = clazz.getInterfaces();
|
||||
Class[] interfaces = clazz.getInterfaces();
|
||||
allInterfaces.addAll(Arrays.asList(interfaces));
|
||||
addAllInterfaces(clazz.getSuperclass(), allInterfaces);
|
||||
}
|
||||
@@ -191,21 +189,4 @@ public class AnnotationUtils {
|
||||
|
||||
return anns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Varargs version of <code>AnnotatedElement.isAnnotationPresent()</code>
|
||||
*
|
||||
* @see AnnotatedElement
|
||||
*/
|
||||
@SafeVarargs
|
||||
public static boolean isAnnotatedBy(AnnotatedElement annotatedElement, Class<? extends Annotation>... annotation) {
|
||||
if (ArrayUtils.isEmpty(annotation)) return false;
|
||||
|
||||
for (Class<? extends Annotation> c : annotation) {
|
||||
if (annotatedElement.isAnnotationPresent(c)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -87,8 +87,8 @@ public class NamedVariablePatternMatcher implements PatternMatcher<NamedVariable
|
||||
int s = 0;
|
||||
while (s < len) {
|
||||
int e = data.indexOf('{', s);
|
||||
if (e < 0 && data.indexOf('}', s) > -1) {
|
||||
throw new IllegalArgumentException("Missing opening '{' in [" + data + "]!");
|
||||
if (e < 0 && data.indexOf('}') > -1) {
|
||||
throw new IllegalArgumentException("Missing openning '{' in [" + data + "]!");
|
||||
}
|
||||
if (e < 0) {
|
||||
regex.append(Pattern.quote(data.substring(s)));
|
||||
|
||||
+327
-15
@@ -18,14 +18,20 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.validator;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.ActionProxy;
|
||||
import com.opensymphony.xwork2.*;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.ClassLoaderUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* AnnotationActionValidatorManager is the entry point into XWork's annotations-based validator framework.
|
||||
@@ -34,9 +40,185 @@ import java.util.List;
|
||||
* @author Rainer Hermanns
|
||||
* @author jepjep
|
||||
*/
|
||||
public class AnnotationActionValidatorManager extends DefaultActionValidatorManager {
|
||||
public class AnnotationActionValidatorManager implements ActionValidatorManager {
|
||||
|
||||
@Override
|
||||
/**
|
||||
* The file suffix for any validation file.
|
||||
*/
|
||||
protected static final String VALIDATION_CONFIG_SUFFIX = "-validation.xml";
|
||||
|
||||
private final Map<String, List<ValidatorConfig>> validatorCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
|
||||
private final Map<String, List<ValidatorConfig>> validatorFileCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
|
||||
private static final Logger LOG = LogManager.getLogger(AnnotationActionValidatorManager.class);
|
||||
|
||||
private ValidatorFactory validatorFactory;
|
||||
private ValidatorFileParser validatorFileParser;
|
||||
private FileManager fileManager;
|
||||
private boolean reloadingConfigs;
|
||||
private TextProviderFactory textProviderFactory;
|
||||
|
||||
@Inject
|
||||
public void setValidatorFactory(ValidatorFactory fac) {
|
||||
this.validatorFactory = fac;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setValidatorFileParser(ValidatorFileParser parser) {
|
||||
this.validatorFileParser = parser;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setFileManagerFactory(FileManagerFactory fileManagerFactory) {
|
||||
this.fileManager = fileManagerFactory.getFileManager();
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, required = false)
|
||||
public void setReloadingConfigs(String reloadingConfigs) {
|
||||
this.reloadingConfigs = Boolean.parseBoolean(reloadingConfigs);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setTextProviderFactory(TextProviderFactory textProviderFactory) {
|
||||
this.textProviderFactory = textProviderFactory;
|
||||
}
|
||||
|
||||
public List<Validator> getValidators(Class clazz, String context) {
|
||||
return getValidators(clazz, context, null);
|
||||
}
|
||||
|
||||
public List<Validator> getValidators(Class clazz, String context, String method) {
|
||||
final String validatorKey = buildValidatorKey(clazz, context);
|
||||
final List<ValidatorConfig> cfgs;
|
||||
|
||||
if (validatorCache.containsKey(validatorKey)) {
|
||||
if (reloadingConfigs) {
|
||||
validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, true, null));
|
||||
}
|
||||
} else {
|
||||
validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, false, null));
|
||||
}
|
||||
|
||||
// get the set of validator configs
|
||||
cfgs = new ArrayList<ValidatorConfig>(validatorCache.get(validatorKey));
|
||||
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
|
||||
// create clean instances of the validators for the caller's use
|
||||
ArrayList<Validator> validators = new ArrayList<>(cfgs.size());
|
||||
for (ValidatorConfig cfg : cfgs) {
|
||||
if (method == null || method.equals(cfg.getParams().get("methodName"))) {
|
||||
Validator validator = validatorFactory.getValidator(
|
||||
new ValidatorConfig.Builder(cfg)
|
||||
.removeParam("methodName")
|
||||
.build());
|
||||
validator.setValidatorType(cfg.getType());
|
||||
validator.setValueStack(stack);
|
||||
validators.add(validator);
|
||||
}
|
||||
}
|
||||
|
||||
return validators;
|
||||
}
|
||||
|
||||
public void validate(Object object, String context) throws ValidationException {
|
||||
validate(object, context, (String) null);
|
||||
}
|
||||
|
||||
public void validate(Object object, String context, String method) throws ValidationException {
|
||||
ValidatorContext validatorContext = new DelegatingValidatorContext(object, textProviderFactory);
|
||||
validate(object, context, validatorContext, method);
|
||||
}
|
||||
|
||||
public void validate(Object object, String context, ValidatorContext validatorContext) throws ValidationException {
|
||||
validate(object, context, validatorContext, null);
|
||||
}
|
||||
|
||||
public void validate(Object object, String context, ValidatorContext validatorContext, String method) throws ValidationException {
|
||||
List<Validator> validators = getValidators(object.getClass(), context, method);
|
||||
Set<String> shortcircuitedFields = null;
|
||||
|
||||
for (final Validator validator : validators) {
|
||||
try {
|
||||
validator.setValidatorContext(validatorContext);
|
||||
|
||||
LOG.debug("Running validator: {} for object {} and method {}", validator, object, method);
|
||||
|
||||
FieldValidator fValidator = null;
|
||||
String fullFieldName = null;
|
||||
|
||||
if (validator instanceof FieldValidator) {
|
||||
fValidator = (FieldValidator) validator;
|
||||
fullFieldName = fValidator.getValidatorContext().getFullFieldName(fValidator.getFieldName());
|
||||
|
||||
if ((shortcircuitedFields != null) && shortcircuitedFields.contains(fullFieldName)) {
|
||||
LOG.debug("Short-circuited, skipping");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (validator instanceof ShortCircuitableValidator && ((ShortCircuitableValidator) validator).isShortCircuit()) {
|
||||
// get number of existing errors
|
||||
List<String> errs = null;
|
||||
|
||||
if (fValidator != null) {
|
||||
if (validatorContext.hasFieldErrors()) {
|
||||
Collection<String> fieldErrors = validatorContext.getFieldErrors().get(fullFieldName);
|
||||
|
||||
if (fieldErrors != null) {
|
||||
errs = new ArrayList<>(fieldErrors);
|
||||
}
|
||||
}
|
||||
} else if (validatorContext.hasActionErrors()) {
|
||||
Collection<String> actionErrors = validatorContext.getActionErrors();
|
||||
|
||||
if (actionErrors != null) {
|
||||
errs = new ArrayList<>(actionErrors);
|
||||
}
|
||||
}
|
||||
|
||||
validator.validate(object);
|
||||
|
||||
if (fValidator != null) {
|
||||
if (validatorContext.hasFieldErrors()) {
|
||||
Collection<String> errCol = validatorContext.getFieldErrors().get(fullFieldName);
|
||||
|
||||
if ((errCol != null) && !errCol.equals(errs)) {
|
||||
LOG.debug("Short-circuiting on field validation");
|
||||
|
||||
if (shortcircuitedFields == null) {
|
||||
shortcircuitedFields = new TreeSet<String>();
|
||||
}
|
||||
|
||||
shortcircuitedFields.add(fullFieldName);
|
||||
}
|
||||
}
|
||||
} else if (validatorContext.hasActionErrors()) {
|
||||
Collection<String> errCol = validatorContext.getActionErrors();
|
||||
|
||||
if ((errCol != null) && !errCol.equals(errs)) {
|
||||
LOG.debug("Short-circuiting");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
validator.validate(object);
|
||||
} finally {
|
||||
validator.setValidatorContext(null);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a key for validators - used when caching validators.
|
||||
*
|
||||
* @param clazz the action.
|
||||
* @param context context
|
||||
* @return a validator key which is the class name plus context.
|
||||
*/
|
||||
protected String buildValidatorKey(Class clazz, String context) {
|
||||
ActionInvocation invocation = ActionContext.getContext().getActionInvocation();
|
||||
ActionProxy proxy = invocation.getProxy();
|
||||
@@ -48,11 +230,20 @@ public class AnnotationActionValidatorManager extends DefaultActionValidatorMana
|
||||
sb.append(config.getPackageName());
|
||||
sb.append("/");
|
||||
}
|
||||
// WW-2996: key needs to use the name of the action from the config file, instead of the url,
|
||||
// so wildcard actions will have the same validator
|
||||
// WW-3753: Using the config name instead of the context only for wildcard actions to keep the flexibility
|
||||
// provided by the original design (such as mapping different contexts to the same action and method if desired)
|
||||
// WW-4536: Using NamedVariablePatternMatcher allows defines actions with patterns enclosed with '{}'
|
||||
|
||||
// the key needs to use the name of the action from the config file,
|
||||
// instead of the url, so wild card actions will have the same validator
|
||||
// see WW-2996
|
||||
|
||||
// UPDATE:
|
||||
// WW-3753 Using the config name instead of the context only for
|
||||
// wild card actions to keep the flexibility provided
|
||||
// by the original design (such as mapping different contexts
|
||||
// to the same action and method if desired)
|
||||
|
||||
// UPDATE:
|
||||
// WW-4536 Using NameVariablePatternMatcher allows defines actions
|
||||
// with patterns enclosed with '{}', it's similar case to WW-3753
|
||||
String configName = config.getName();
|
||||
if (configName.contains(ActionConfig.WILDCARD) || (configName.contains("{") && configName.contains("}"))) {
|
||||
sb.append(configName);
|
||||
@@ -61,22 +252,143 @@ public class AnnotationActionValidatorManager extends DefaultActionValidatorMana
|
||||
} else {
|
||||
sb.append(context);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ValidatorConfig> buildAliasValidatorConfigs(Class aClass, String context, boolean checkFile) {
|
||||
private List<ValidatorConfig> buildAliasValidatorConfigs(Class aClass, String context, boolean checkFile) {
|
||||
String fileName = aClass.getName().replace('.', '/') + "-" + context.replace('/', '-') + VALIDATION_CONFIG_SUFFIX;
|
||||
|
||||
return loadFile(fileName, aClass, checkFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
protected List<ValidatorConfig> buildClassValidatorConfigs(Class aClass, boolean checkFile) {
|
||||
|
||||
String fileName = aClass.getName().replace('.', '/') + VALIDATION_CONFIG_SUFFIX;
|
||||
|
||||
List<ValidatorConfig> result = new ArrayList<>(loadFile(fileName, aClass, checkFile));
|
||||
|
||||
AnnotationValidationConfigurationBuilder builder = new AnnotationValidationConfigurationBuilder(validatorFactory);
|
||||
|
||||
List<ValidatorConfig> annotationResult = new ArrayList<>(builder.buildAnnotationClassValidatorConfigs(aClass));
|
||||
|
||||
result.addAll(annotationResult);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>This method 'collects' all the validator configurations for a given
|
||||
* action invocation.</p>
|
||||
*
|
||||
* <p>It will traverse up the class hierarchy looking for validators for every super class
|
||||
* and directly implemented interface of the current action, as well as adding validators for
|
||||
* any alias of this invocation. Nifty!</p>
|
||||
*
|
||||
* <p>Given the following class structure:</p>
|
||||
* <pre>
|
||||
* interface Thing;
|
||||
* interface Animal extends Thing;
|
||||
* interface Quadraped extends Animal;
|
||||
* class AnimalImpl implements Animal;
|
||||
* class QuadrapedImpl extends AnimalImpl implements Quadraped;
|
||||
* class Dog extends QuadrapedImpl;
|
||||
* </pre>
|
||||
*
|
||||
* <p>This method will look for the following config files for Dog:</p>
|
||||
* <pre>
|
||||
* Animal
|
||||
* Animal-context
|
||||
* AnimalImpl
|
||||
* AnimalImpl-context
|
||||
* Quadraped
|
||||
* Quadraped-context
|
||||
* QuadrapedImpl
|
||||
* QuadrapedImpl-context
|
||||
* Dog
|
||||
* Dog-context
|
||||
* </pre>
|
||||
*
|
||||
* <p>Note that the validation rules for Thing is never looked for because no class in the
|
||||
* hierarchy directly implements Thing.</p>
|
||||
*
|
||||
* @param clazz the Class to look up validators for.
|
||||
* @param context the context to use when looking up validators.
|
||||
* @param checkFile true if the validation config file should be checked to see if it has been
|
||||
* updated.
|
||||
* @param checked the set of previously checked class-contexts, null if none have been checked
|
||||
* @return a list of validator configs for the given class and context.
|
||||
*/
|
||||
private List<ValidatorConfig> buildValidatorConfigs(Class clazz, String context, boolean checkFile, Set<String> checked) {
|
||||
List<ValidatorConfig> validatorConfigs = new ArrayList<>();
|
||||
|
||||
if (checked == null) {
|
||||
checked = new TreeSet<>();
|
||||
} else if (checked.contains(clazz.getName())) {
|
||||
return validatorConfigs;
|
||||
}
|
||||
|
||||
if (clazz.isInterface()) {
|
||||
Class[] interfaces = clazz.getInterfaces();
|
||||
|
||||
for (Class anInterface : interfaces) {
|
||||
validatorConfigs.addAll(buildValidatorConfigs(anInterface, context, checkFile, checked));
|
||||
}
|
||||
} else {
|
||||
if (!clazz.equals(Object.class)) {
|
||||
validatorConfigs.addAll(buildValidatorConfigs(clazz.getSuperclass(), context, checkFile, checked));
|
||||
}
|
||||
}
|
||||
|
||||
// look for validators for implemented interfaces
|
||||
Class[] interfaces = clazz.getInterfaces();
|
||||
|
||||
for (Class anInterface1 : interfaces) {
|
||||
if (checked.contains(anInterface1.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
validatorConfigs.addAll(buildClassValidatorConfigs(anInterface1, checkFile));
|
||||
|
||||
if (context != null) {
|
||||
validatorConfigs.addAll(buildAliasValidatorConfigs(anInterface1, context, checkFile));
|
||||
}
|
||||
|
||||
checked.add(anInterface1.getName());
|
||||
}
|
||||
|
||||
validatorConfigs.addAll(buildClassValidatorConfigs(clazz, checkFile));
|
||||
|
||||
if (context != null) {
|
||||
validatorConfigs.addAll(buildAliasValidatorConfigs(clazz, context, checkFile));
|
||||
}
|
||||
|
||||
checked.add(clazz.getName());
|
||||
|
||||
return validatorConfigs;
|
||||
}
|
||||
|
||||
private List<ValidatorConfig> loadFile(String fileName, Class clazz, boolean checkFile) {
|
||||
List<ValidatorConfig> retList = Collections.emptyList();
|
||||
|
||||
URL fileUrl = ClassLoaderUtil.getResource(fileName, clazz);
|
||||
|
||||
if ((checkFile && fileManager.fileNeedsReloading(fileUrl)) || !validatorFileCache.containsKey(fileName)) {
|
||||
try (InputStream is = fileManager.loadFile(fileUrl)) {
|
||||
if (is != null) {
|
||||
retList = new ArrayList<>(validatorFileParser.parseActionValidatorConfigs(validatorFactory, is, fileName));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Caught exception while loading file {}", fileName, e);
|
||||
}
|
||||
|
||||
validatorFileCache.put(fileName, retList);
|
||||
} else {
|
||||
retList = validatorFileCache.get(fileName);
|
||||
}
|
||||
|
||||
return retList;
|
||||
}
|
||||
}
|
||||
|
||||
+153
-154
@@ -32,16 +32,7 @@ import org.apache.struts2.StrutsConstants;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static java.util.Collections.synchronizedMap;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -62,30 +53,29 @@ import static java.util.Collections.synchronizedMap;
|
||||
*/
|
||||
public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
|
||||
/**
|
||||
* The file suffix for any validation file.
|
||||
*/
|
||||
private final static Logger LOG = LogManager.getLogger(DefaultActionValidatorManager.class);
|
||||
|
||||
/** The file suffix for any validation file. */
|
||||
protected static final String VALIDATION_CONFIG_SUFFIX = "-validation.xml";
|
||||
|
||||
protected final Map<String, List<ValidatorConfig>> validatorCache = synchronizedMap(new HashMap<>());
|
||||
protected final Map<String, List<ValidatorConfig>> validatorFileCache = synchronizedMap(new HashMap<>());
|
||||
private static final Logger LOG = LogManager.getLogger(DefaultActionValidatorManager.class);
|
||||
private final Map<String, List<ValidatorConfig>> validatorCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
|
||||
private final Map<String, List<ValidatorConfig>> validatorFileCache = Collections.synchronizedMap(new HashMap<String, List<ValidatorConfig>>());
|
||||
|
||||
protected ValidatorFactory validatorFactory;
|
||||
protected ValidatorFileParser validatorFileParser;
|
||||
protected FileManager fileManager;
|
||||
protected boolean reloadingConfigs;
|
||||
protected TextProviderFactory textProviderFactory;
|
||||
|
||||
@Inject
|
||||
public void setValidatorFactory(ValidatorFactory fac) {
|
||||
this.validatorFactory = fac;
|
||||
}
|
||||
private ValidatorFactory validatorFactory;
|
||||
private ValidatorFileParser validatorFileParser;
|
||||
private FileManager fileManager;
|
||||
private boolean reloadingConfigs;
|
||||
private TextProviderFactory textProviderFactory;
|
||||
|
||||
@Inject
|
||||
public void setValidatorFileParser(ValidatorFileParser parser) {
|
||||
this.validatorFileParser = parser;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setValidatorFactory(ValidatorFactory fac) {
|
||||
this.validatorFactory = fac;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setFileManagerFactory(FileManagerFactory fileManagerFactory) {
|
||||
@@ -102,137 +92,153 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
this.textProviderFactory = textProviderFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Validator> getValidators(Class clazz, String context) {
|
||||
return getValidators(clazz, context, null);
|
||||
}
|
||||
|
||||
public synchronized List<Validator> getValidators(Class clazz, String context, String method) {
|
||||
final String validatorKey = buildValidatorKey(clazz, context);
|
||||
|
||||
if (validatorCache.containsKey(validatorKey)) {
|
||||
if (reloadingConfigs) {
|
||||
validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, true, null));
|
||||
}
|
||||
} else {
|
||||
validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, false, null));
|
||||
}
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
|
||||
// get the set of validator configs
|
||||
List<ValidatorConfig> cfgs = validatorCache.get(validatorKey);
|
||||
|
||||
// create clean instances of the validators for the caller's use
|
||||
ArrayList<Validator> validators = new ArrayList<>(cfgs.size());
|
||||
for (ValidatorConfig cfg : cfgs) {
|
||||
if (method == null || method.equals(cfg.getParams().get("methodName"))) {
|
||||
Validator validator = validatorFactory.getValidator(cfg);
|
||||
validator.setValidatorType(cfg.getType());
|
||||
validator.setValueStack(stack);
|
||||
validators.add(validator);
|
||||
}
|
||||
}
|
||||
return validators;
|
||||
}
|
||||
|
||||
public void validate(Object object, String context) throws ValidationException {
|
||||
validate(object, context, (String) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object object, String context, String method) throws ValidationException {
|
||||
ValidatorContext validatorContext = new DelegatingValidatorContext(object, textProviderFactory);
|
||||
validate(object, context, validatorContext, method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object object, String context, ValidatorContext validatorContext) throws ValidationException {
|
||||
validate(object, context, validatorContext, null);
|
||||
}
|
||||
|
||||
public void validate(Object object, String context, ValidatorContext validatorContext, String method) throws ValidationException {
|
||||
List<Validator> validators = getValidators(object.getClass(), context, method);
|
||||
Set<String> shortcircuitedFields = null;
|
||||
|
||||
for (final Validator validator : validators) {
|
||||
try {
|
||||
validator.setValidatorContext(validatorContext);
|
||||
|
||||
LOG.debug("Running validator: {} for object {} and method {}", validator, object, method);
|
||||
|
||||
FieldValidator fValidator = null;
|
||||
String fullFieldName = null;
|
||||
|
||||
if (validator instanceof FieldValidator) {
|
||||
fValidator = (FieldValidator) validator;
|
||||
fullFieldName = fValidator.getValidatorContext().getFullFieldName(fValidator.getFieldName());
|
||||
|
||||
if ((shortcircuitedFields != null) && shortcircuitedFields.contains(fullFieldName)) {
|
||||
LOG.debug("Short-circuited, skipping");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (validator instanceof ShortCircuitableValidator && ((ShortCircuitableValidator) validator).isShortCircuit()) {
|
||||
// get number of existing errors
|
||||
List<String> errs = null;
|
||||
|
||||
if (fValidator != null) {
|
||||
if (validatorContext.hasFieldErrors()) {
|
||||
Collection<String> fieldErrors = validatorContext.getFieldErrors().get(fullFieldName);
|
||||
|
||||
if (fieldErrors != null) {
|
||||
errs = new ArrayList<>(fieldErrors);
|
||||
}
|
||||
}
|
||||
} else if (validatorContext.hasActionErrors()) {
|
||||
Collection<String> actionErrors = validatorContext.getActionErrors();
|
||||
|
||||
if (actionErrors != null) {
|
||||
errs = new ArrayList<String>(actionErrors);
|
||||
}
|
||||
}
|
||||
|
||||
validator.validate(object);
|
||||
|
||||
if (fValidator != null) {
|
||||
if (validatorContext.hasFieldErrors()) {
|
||||
Collection<String> errCol = validatorContext.getFieldErrors().get(fullFieldName);
|
||||
|
||||
if ((errCol != null) && !errCol.equals(errs)) {
|
||||
LOG.debug("Short-circuiting on field validation");
|
||||
|
||||
if (shortcircuitedFields == null) {
|
||||
shortcircuitedFields = new TreeSet<>();
|
||||
}
|
||||
|
||||
shortcircuitedFields.add(fullFieldName);
|
||||
}
|
||||
}
|
||||
} else if (validatorContext.hasActionErrors()) {
|
||||
Collection<String> errCol = validatorContext.getActionErrors();
|
||||
|
||||
if ((errCol != null) && !errCol.equals(errs)) {
|
||||
LOG.debug("Short-circuiting");
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
validator.validate(object);
|
||||
}
|
||||
finally {
|
||||
validator.setValidatorContext(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a key for validators - used when caching validators.
|
||||
*
|
||||
* @param clazz the action.
|
||||
* @param context context
|
||||
* @param context the action's context.
|
||||
* @return a validator key which is the class name plus context.
|
||||
*/
|
||||
protected String buildValidatorKey(Class clazz, String context) {
|
||||
return clazz.getName() + "/" + context;
|
||||
protected static String buildValidatorKey(Class clazz, String context) {
|
||||
StringBuilder sb = new StringBuilder(clazz.getName());
|
||||
sb.append("/");
|
||||
sb.append(context);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected Validator getValidatorFromValidatorConfig(ValidatorConfig config, ValueStack stack) {
|
||||
Validator validator = validatorFactory.getValidator(config);
|
||||
validator.setValidatorType(config.getType());
|
||||
validator.setValueStack(stack);
|
||||
return validator;
|
||||
private List<ValidatorConfig> buildAliasValidatorConfigs(Class aClass, String context, boolean checkFile) {
|
||||
String fileName = aClass.getName().replace('.', '/') + "-" + context + VALIDATION_CONFIG_SUFFIX;
|
||||
|
||||
return loadFile(fileName, aClass, checkFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Validator> getValidators(Class clazz, String context, String method) {
|
||||
String validatorKey = buildValidatorKey(clazz, context);
|
||||
private List<ValidatorConfig> buildClassValidatorConfigs(Class aClass, boolean checkFile) {
|
||||
String fileName = aClass.getName().replace('.', '/') + VALIDATION_CONFIG_SUFFIX;
|
||||
|
||||
if (!validatorCache.containsKey(validatorKey)) {
|
||||
validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, false, null));
|
||||
} else if (reloadingConfigs) {
|
||||
validatorCache.put(validatorKey, buildValidatorConfigs(clazz, context, true, null));
|
||||
}
|
||||
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
List<ValidatorConfig> configs = validatorCache.get(validatorKey);
|
||||
List<Validator> validators = new ArrayList<>();
|
||||
for (ValidatorConfig config : configs) {
|
||||
if (method == null || method.equals(config.getParams().get("methodName"))) {
|
||||
validators.add(getValidatorFromValidatorConfig(config, stack));
|
||||
}
|
||||
}
|
||||
return validators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Validator> getValidators(Class clazz, String context) {
|
||||
return getValidators(clazz, context, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object object, String context, ValidatorContext validatorContext, String method) throws ValidationException {
|
||||
List<Validator> validators = getValidators(object.getClass(), context, method);
|
||||
Set<String> shortcircuitedFields = null;
|
||||
|
||||
for (Validator validator : validators) {
|
||||
validator.setValidatorContext(validatorContext);
|
||||
|
||||
LOG.debug("Running validator: {} for object {} and method {}", validator, object, method);
|
||||
|
||||
FieldValidator fValidator = null;
|
||||
String fullFieldName = null;
|
||||
|
||||
if (validator instanceof FieldValidator) {
|
||||
fValidator = (FieldValidator) validator;
|
||||
fullFieldName = validatorContext.getFullFieldName(fValidator.getFieldName());
|
||||
|
||||
if ((shortcircuitedFields != null) && shortcircuitedFields.contains(fullFieldName)) {
|
||||
LOG.debug("Short-circuited, skipping");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (validator instanceof ShortCircuitableValidator && ((ShortCircuitableValidator) validator).isShortCircuit()) {
|
||||
// get number of existing errors
|
||||
List<String> errs = null;
|
||||
|
||||
if (fValidator != null) {
|
||||
if (validatorContext.hasFieldErrors()) {
|
||||
Collection<String> fieldErrors = validatorContext.getFieldErrors().get(fullFieldName);
|
||||
|
||||
if (fieldErrors != null) {
|
||||
errs = new ArrayList<>(fieldErrors);
|
||||
}
|
||||
}
|
||||
} else if (validatorContext.hasActionErrors()) {
|
||||
Collection<String> actionErrors = validatorContext.getActionErrors();
|
||||
|
||||
if (actionErrors != null) {
|
||||
errs = new ArrayList<>(actionErrors);
|
||||
}
|
||||
}
|
||||
|
||||
validator.validate(object);
|
||||
|
||||
if (fValidator != null) {
|
||||
if (validatorContext.hasFieldErrors()) {
|
||||
Collection<String> errCol = validatorContext.getFieldErrors().get(fullFieldName);
|
||||
|
||||
if ((errCol != null) && !errCol.equals(errs)) {
|
||||
LOG.debug("Short-circuiting on field validation");
|
||||
|
||||
if (shortcircuitedFields == null) {
|
||||
shortcircuitedFields = new TreeSet<>();
|
||||
}
|
||||
|
||||
shortcircuitedFields.add(fullFieldName);
|
||||
}
|
||||
}
|
||||
} else if (validatorContext.hasActionErrors()) {
|
||||
Collection<String> errCol = validatorContext.getActionErrors();
|
||||
|
||||
if ((errCol != null) && !errCol.equals(errs)) {
|
||||
LOG.debug("Short-circuiting");
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
validator.validate(object);
|
||||
}
|
||||
return loadFile(fileName, aClass, checkFile);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,18 +276,18 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
* <p>Note that the validation rules for Thing is never looked for because no class in the
|
||||
* hierarchy directly implements Thing.</p>
|
||||
*
|
||||
* @param clazz the Class to look up validators for.
|
||||
* @param context the context to use when looking up validators.
|
||||
* @param clazz the Class to look up validators for.
|
||||
* @param context the context to use when looking up validators.
|
||||
* @param checkFile true if the validation config file should be checked to see if it has been
|
||||
* updated.
|
||||
* @param checked the set of previously checked class-contexts, null if none have been checked
|
||||
* updated.
|
||||
* @param checked the set of previously checked class-contexts, null if none have been checked
|
||||
* @return a list of validator configs for the given class and context.
|
||||
*/
|
||||
protected List<ValidatorConfig> buildValidatorConfigs(Class clazz, String context, boolean checkFile, Set<String> checked) {
|
||||
private List<ValidatorConfig> buildValidatorConfigs(Class clazz, String context, boolean checkFile, Set<String> checked) {
|
||||
List<ValidatorConfig> validatorConfigs = new ArrayList<>();
|
||||
|
||||
if (checked == null) {
|
||||
checked = new TreeSet<>();
|
||||
checked = new TreeSet<String>();
|
||||
} else if (checked.contains(clazz.getName())) {
|
||||
return validatorConfigs;
|
||||
}
|
||||
@@ -289,7 +295,7 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
if (clazz.isInterface()) {
|
||||
for (Class anInterface : clazz.getInterfaces()) {
|
||||
validatorConfigs.addAll(buildValidatorConfigs(anInterface, context, checkFile, checked));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!clazz.equals(Object.class)) {
|
||||
validatorConfigs.addAll(buildValidatorConfigs(clazz.getSuperclass(), context, checkFile, checked));
|
||||
@@ -301,44 +307,37 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
if (checked.contains(anInterface1.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
validatorConfigs.addAll(buildClassValidatorConfigs(anInterface1, checkFile));
|
||||
|
||||
if (context != null) {
|
||||
validatorConfigs.addAll(buildAliasValidatorConfigs(anInterface1, context, checkFile));
|
||||
}
|
||||
|
||||
checked.add(anInterface1.getName());
|
||||
}
|
||||
|
||||
validatorConfigs.addAll(buildClassValidatorConfigs(clazz, checkFile));
|
||||
|
||||
if (context != null) {
|
||||
validatorConfigs.addAll(buildAliasValidatorConfigs(clazz, context, checkFile));
|
||||
}
|
||||
|
||||
checked.add(clazz.getName());
|
||||
|
||||
return validatorConfigs;
|
||||
}
|
||||
|
||||
protected List<ValidatorConfig> buildAliasValidatorConfigs(Class aClass, String context, boolean checkFile) {
|
||||
String fileName = aClass.getName().replace('.', '/') + "-" + context + VALIDATION_CONFIG_SUFFIX;
|
||||
return loadFile(fileName, aClass, checkFile);
|
||||
}
|
||||
|
||||
protected List<ValidatorConfig> buildClassValidatorConfigs(Class aClass, boolean checkFile) {
|
||||
String fileName = aClass.getName().replace('.', '/') + VALIDATION_CONFIG_SUFFIX;
|
||||
return loadFile(fileName, aClass, checkFile);
|
||||
}
|
||||
|
||||
protected List<ValidatorConfig> loadFile(String fileName, Class clazz, boolean checkFile) {
|
||||
private List<ValidatorConfig> loadFile(String fileName, Class clazz, boolean checkFile) {
|
||||
List<ValidatorConfig> retList = Collections.emptyList();
|
||||
|
||||
URL fileUrl = ClassLoaderUtil.getResource(fileName, clazz);
|
||||
|
||||
if ((checkFile && fileManager.fileNeedsReloading(fileUrl)) || !validatorFileCache.containsKey(fileName)) {
|
||||
try (InputStream is = fileManager.loadFile(fileUrl)) {
|
||||
if (is != null) {
|
||||
retList = new ArrayList<>(validatorFileParser.parseActionValidatorConfigs(validatorFactory, is, fileName));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Caught exception while closing file {}", fileName, e);
|
||||
LOG.error("Caught exception while loading file {}", fileName, e);
|
||||
}
|
||||
|
||||
validatorFileCache.put(fileName, retList);
|
||||
|
||||
+1
-1
@@ -138,7 +138,7 @@ public class VisitorFieldValidator extends FieldValidatorSupport {
|
||||
|
||||
stack.push(object);
|
||||
|
||||
String visitorContext = (context == null) ? ActionContext.getContext().getActionName() : context;
|
||||
String visitorContext = (context == null) ? ActionContext.getContext().getName() : context;
|
||||
|
||||
if (value instanceof Collection) {
|
||||
Collection coll = (Collection) value;
|
||||
|
||||
@@ -139,17 +139,12 @@ public final class StrutsConstants {
|
||||
/** A global flag to enable/disable html body escaping in tags, can be overwritten per tag */
|
||||
public static final String STRUTS_UI_ESCAPE_HTML_BODY = "struts.ui.escapeHtmlBody";
|
||||
|
||||
/** The maximum size of a multipart request (file upload) */
|
||||
/** The maximize size of a multipart request (file upload) */
|
||||
public static final String STRUTS_MULTIPART_MAXSIZE = "struts.multipart.maxSize";
|
||||
|
||||
/** The maximum number of files allowed in a multipart request */
|
||||
/** The maximized number of files allowed to upload */
|
||||
public static final String STRUTS_MULTIPART_MAXFILES = "struts.multipart.maxFiles";
|
||||
|
||||
/** The maximum length of a string parameter in a multipart request. */
|
||||
public static final String STRUTS_MULTIPART_MAX_STRING_LENGTH = "struts.multipart.maxStringLength";
|
||||
|
||||
/** The maximum size per file in a multipart request */
|
||||
public static final String STRUTS_MULTIPART_MAXFILESIZE = "struts.multipart.maxFileSize";
|
||||
/** The directory to use for storing uploaded files */
|
||||
public static final String STRUTS_MULTIPART_SAVEDIR = "struts.multipart.saveDir";
|
||||
|
||||
@@ -185,6 +180,9 @@ public final class StrutsConstants {
|
||||
@Deprecated
|
||||
public static final String STRUTS_OBJECTFACTORY_SPRING_ENABLE_AOP_SUPPORT = "struts.objectFactory.spring.enableAopSupport";
|
||||
|
||||
/** Whether or not XSLT templates should not be cached */
|
||||
public static final String STRUTS_XSLT_NOCACHE = "struts.xslt.nocache";
|
||||
|
||||
/** Location of additional configuration properties files to load */
|
||||
public static final String STRUTS_CUSTOM_PROPERTIES = "struts.custom.properties";
|
||||
|
||||
@@ -406,26 +404,27 @@ public final class StrutsConstants {
|
||||
/** Enables action: prefix */
|
||||
public static final String STRUTS_MAPPER_ACTION_PREFIX_ENABLED = "struts.mapper.action.prefix.enabled";
|
||||
|
||||
/**
|
||||
* Enables access to actions in other namespaces than current with action: prefix
|
||||
* @deprecated it will be removed soon, please refactor your application
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String STRUTS_MAPPER_ACTION_PREFIX_CROSSNAMESPACES = "struts.mapper.action.prefix.crossNamespaces";
|
||||
|
||||
public static final String DEFAULT_TEMPLATE_TYPE_CONFIG_KEY = "struts.ui.templateSuffix";
|
||||
|
||||
/** Allows override default DispatcherErrorHandler */
|
||||
public static final String STRUTS_DISPATCHER_ERROR_HANDLER = "struts.dispatcher.errorHandler";
|
||||
|
||||
/** Comma delimited set of excluded classes which cannot be accessed via OGNL expressions. Matching is done on both target and member classes of OGNL expression. Note that superclasses of listed classes are also used for matching. */
|
||||
/** Comma delimited set of excluded classes and package names which cannot be accessed via expressions */
|
||||
public static final String STRUTS_EXCLUDED_CLASSES = "struts.excludedClasses";
|
||||
/** Comma delimited set of RegEx to match against package names of target and member classes of OGNL expressions. If matched, they cannot be accessed. */
|
||||
public static final String STRUTS_EXCLUDED_PACKAGE_NAME_PATTERNS = "struts.excludedPackageNamePatterns";
|
||||
/** Comma delimited set of package names, of which all its classes, and all classes in its subpackages, cannot be accessed via OGNL expressions. Matching is done on both target and member classes of OGNL expression. */
|
||||
public static final String STRUTS_EXCLUDED_PACKAGE_NAMES = "struts.excludedPackageNames";
|
||||
/** Comma delimited set of exempt classes from matching against excludedPackageNames and excludedPackageNamePatterns. As matching for excluded packages is done on both target and member classes of OGNL expression, an exemption must exist for each match. */
|
||||
public static final String STRUTS_EXCLUDED_PACKAGE_EXEMPT_CLASSES = "struts.excludedPackageExemptClasses";
|
||||
|
||||
/** Comma delimited set of excluded classes and package names which cannot be accessed via expressions in devMode */
|
||||
public static final String STRUTS_DEV_MODE_EXCLUDED_CLASSES = "struts.devMode.excludedClasses";
|
||||
public static final String STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAME_PATTERNS = "struts.devMode.excludedPackageNamePatterns";
|
||||
public static final String STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAMES = "struts.devMode.excludedPackageNames";
|
||||
public static final String STRUTS_DEV_MODE_EXCLUDED_PACKAGE_EXEMPT_CLASSES = "struts.devMode.excludedPackageExemptClasses";
|
||||
|
||||
|
||||
/** Dedicated services to check if passed string is excluded/accepted */
|
||||
public static final String STRUTS_EXCLUDED_PATTERNS_CHECKER = "struts.excludedPatterns.checker";
|
||||
@@ -469,7 +468,4 @@ public final class StrutsConstants {
|
||||
|
||||
/** A global flag to set property {@link org.apache.struts2.components.Checkbox#setSubmitUnchecked(String)} */
|
||||
public static final String STRUTS_UI_CHECKBOX_SUBMIT_UNCHECKED = "struts.ui.checkbox.submitUnchecked";
|
||||
|
||||
/** See {@link org.apache.struts2.interceptor.exec.ExecutorProvider} */
|
||||
public static final String STRUTS_EXECUTOR_PROVIDER = "struts.executor.provider";
|
||||
}
|
||||
|
||||
@@ -31,18 +31,20 @@ import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.StrutsStatics;
|
||||
import org.apache.struts2.dispatcher.Dispatcher;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.RequestMap;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapper;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
import org.apache.struts2.views.annotations.StrutsTag;
|
||||
import org.apache.struts2.views.annotations.StrutsTagAttribute;
|
||||
import org.apache.struts2.views.jsp.TagUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.jsp.PageContext;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -51,7 +53,7 @@ import java.util.Map;
|
||||
* namespace. The body content of the tag is used to render the results from the Action. Any result processor defined
|
||||
* for this action in struts.xml will be ignored, <i>unless</i> the executeResult parameter is specified.</p>
|
||||
* <!-- END SNIPPET: javadoc -->
|
||||
* <p>
|
||||
*
|
||||
* <!-- START SNIPPET: params -->
|
||||
* <ul>
|
||||
* <li>id (String) - the id (if specified) to put the action under stack's context.
|
||||
@@ -109,8 +111,9 @@ import java.util.Map;
|
||||
* <s:property value="#attr.stringByAction" />
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
@StrutsTag(name = "action", tldTagClass = "org.apache.struts2.views.jsp.ActionTag", description = "Execute an action from within a view")
|
||||
@StrutsTag(name="action", tldTagClass="org.apache.struts2.views.jsp.ActionTag", description="Execute an action from within a view")
|
||||
public class ActionComponent extends ContextBean {
|
||||
private static final Logger LOG = LogManager.getLogger(ActionComponent.class);
|
||||
|
||||
@@ -140,7 +143,7 @@ public class ActionComponent extends ContextBean {
|
||||
public void setActionProxyFactory(ActionProxyFactory actionProxyFactory) {
|
||||
this.actionProxyFactory = actionProxyFactory;
|
||||
}
|
||||
|
||||
|
||||
@Inject
|
||||
public void setValueStackFactory(ValueStackFactory valueStackFactory) {
|
||||
this.valueStackFactory = valueStackFactory;
|
||||
@@ -160,7 +163,7 @@ public class ActionComponent extends ContextBean {
|
||||
try {
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
LOG.warn("error while trying to flush writer ", e);
|
||||
LOG.warn("error while trying to flush writer ", e);
|
||||
}
|
||||
}
|
||||
executeAction();
|
||||
@@ -185,11 +188,11 @@ public class ActionComponent extends ContextBean {
|
||||
Dispatcher du = Dispatcher.getInstance();
|
||||
Map<String, Object> extraContext = du.createContextMap(
|
||||
new RequestMap(req),
|
||||
newParams,
|
||||
session,
|
||||
application,
|
||||
req,
|
||||
res);
|
||||
newParams,
|
||||
session,
|
||||
application,
|
||||
req,
|
||||
res);
|
||||
|
||||
ValueStack newStack = valueStackFactory.createValueStack(stack);
|
||||
|
||||
@@ -203,7 +206,7 @@ public class ActionComponent extends ContextBean {
|
||||
/**
|
||||
* Creates parameters map using parameters from the value stack and component parameters. Any non-String array
|
||||
* values will be converted into a single-value String array.
|
||||
*
|
||||
*
|
||||
* @return A map of String[] parameters
|
||||
*/
|
||||
protected HttpParameters createParametersForContext() {
|
||||
@@ -230,6 +233,8 @@ public class ActionComponent extends ContextBean {
|
||||
* attempt to derive a namespace using buildNamespace(). The ActionProxy
|
||||
* and the namespace will be saved into the instance variables proxy and
|
||||
* namespace respectively.
|
||||
*
|
||||
* @see org.apache.struts2.views.jsp.TagUtils#buildNamespace
|
||||
*/
|
||||
protected void executeAction() {
|
||||
String actualName = findString(name, "name", "Action name is required. Example: updatePerson");
|
||||
@@ -249,7 +254,7 @@ public class ActionComponent extends ContextBean {
|
||||
String namespace;
|
||||
|
||||
if (this.namespace == null) {
|
||||
namespace = getNamespace(getStack());
|
||||
namespace = TagUtils.buildNamespace(actionMapper, getStack(), req);
|
||||
} else {
|
||||
namespace = findString(this.namespace);
|
||||
}
|
||||
@@ -286,32 +291,32 @@ public class ActionComponent extends ContextBean {
|
||||
}
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(required = true, description = "Name of the action to be executed (without the extension suffix eg. .action)")
|
||||
@StrutsTagAttribute(required=true,description="Name of the action to be executed (without the extension suffix eg. .action)")
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "Namespace for action to call", defaultValue = "namespace from where tag is used")
|
||||
@StrutsTagAttribute(description="Namespace for action to call", defaultValue="namespace from where tag is used")
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "Whether the result of this action (probably a view) should be executed/rendered", type = "Boolean", defaultValue = "false")
|
||||
@StrutsTagAttribute(description="Whether the result of this action (probably a view) should be executed/rendered", type="Boolean", defaultValue="false")
|
||||
public void setExecuteResult(boolean executeResult) {
|
||||
this.executeResult = executeResult;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "Whether the request parameters are to be included when the action is invoked", type = "Boolean", defaultValue = "false")
|
||||
@StrutsTagAttribute(description="Whether the request parameters are to be included when the action is invoked", type="Boolean", defaultValue="false")
|
||||
public void setIgnoreContextParams(boolean ignoreContextParams) {
|
||||
this.ignoreContextParams = ignoreContextParams;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "Whether the writer should be flush upon end of action component tag, default to true", type = "Boolean", defaultValue = "true")
|
||||
@StrutsTagAttribute(description="Whether the writer should be flush upon end of action component tag, default to true", type="Boolean", defaultValue="true")
|
||||
public void setFlush(boolean flush) {
|
||||
this.flush = flush;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "Whether an exception should be rethrown, if the target action throws an exception", type = "Boolean", defaultValue = "false")
|
||||
@StrutsTagAttribute(description="Whether an exception should be rethrown, if the target action throws an exception", type="Boolean", defaultValue="false")
|
||||
public void setRethrowException(boolean rethrowException) {
|
||||
this.rethrowException = rethrowException;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
*/
|
||||
package org.apache.struts2.components;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.security.NotExcludedAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
@@ -36,6 +34,7 @@ import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
import org.apache.struts2.util.ComponentUtils;
|
||||
import org.apache.struts2.util.FastByteArrayOutputStream;
|
||||
import org.apache.struts2.views.annotations.StrutsTagAttribute;
|
||||
import org.apache.struts2.views.jsp.TagUtils;
|
||||
import org.apache.struts2.views.util.UrlHelper;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -373,8 +372,8 @@ public class Component {
|
||||
* evaluating to String.class, else the whole <code>expression</code> is evaluated
|
||||
* against the stack.
|
||||
*
|
||||
* @param expression OGNL expression.
|
||||
* @param toType the type expected to find.
|
||||
* @param expression OGNL expression.
|
||||
* @param toType the type expected to find.
|
||||
* @return the Object found, or <tt>null</tt> if not found.
|
||||
*/
|
||||
protected Object findValue(String expression, Class<?> toType) {
|
||||
@@ -430,7 +429,7 @@ public class Component {
|
||||
String result;
|
||||
|
||||
if (namespace == null) {
|
||||
result = getNamespace(stack);
|
||||
result = TagUtils.buildNamespace(actionMapper, stack, req);
|
||||
} else {
|
||||
result = findString(namespace);
|
||||
}
|
||||
@@ -442,12 +441,6 @@ public class Component {
|
||||
return result;
|
||||
}
|
||||
|
||||
protected String getNamespace(ValueStack stack) {
|
||||
ActionContext context = ActionContext.of(stack.getContext());
|
||||
ActionInvocation invocation = context.getActionInvocation();
|
||||
return invocation.getProxy().getNamespace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes this component's parameter Map as well as the component itself on to the stack
|
||||
* and then copies the supplied parameters over. Because the component's parameter Map is
|
||||
@@ -588,12 +581,12 @@ public class Component {
|
||||
* <em>Note:</em> All Tag classes that extend {@link org.apache.struts2.views.jsp.StrutsBodyTagSupport} must implement a setter for
|
||||
* this attribute (same name), and it must be defined at the Tag class level.
|
||||
* Defining a setter in the superclass alone is insufficient (results in "Cannot find a setter method for the attribute").
|
||||
* <p>
|
||||
*
|
||||
* See {@link org.apache.struts2.views.jsp.StrutsBodyTagSupport#clearTagStateForTagPoolingServers() for additional details.
|
||||
*
|
||||
* @param performClearTagStateForTagPoolingServers true if tag state should be cleared, false otherwise.
|
||||
*/
|
||||
@StrutsTagAttribute(description = "Whether to clear all tag state during doEndTag() processing (if applicable)", type = "Boolean", defaultValue = "false")
|
||||
@StrutsTagAttribute(description="Whether to clear all tag state during doEndTag() processing (if applicable)", type="Boolean", defaultValue="false")
|
||||
public void setPerformClearTagStateForTagPoolingServers(boolean performClearTagStateForTagPoolingServers) {
|
||||
this.performClearTagStateForTagPoolingServers = performClearTagStateForTagPoolingServers;
|
||||
}
|
||||
@@ -616,7 +609,7 @@ public class Component {
|
||||
}
|
||||
|
||||
LOG.warn("Expression [{}] isn't allowed by pattern [{}]! See Accepted / Excluded patterns at\n" +
|
||||
"https://struts.apache.org/security/", expression, isAllowed.getAllowedPattern());
|
||||
"https://struts.apache.org/security/", expression, isAllowed.getAllowedPattern());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import java.io.Writer;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
@@ -295,9 +294,7 @@ public class Date extends ContextBean {
|
||||
// find the name on the valueStack
|
||||
Object dateObject = findValue(name);
|
||||
if (dateObject instanceof java.sql.Date) {
|
||||
date = ((java.sql.Date) dateObject).toLocalDate().atTime(LocalTime.now(tz)).atZone(tz);
|
||||
} else if (dateObject instanceof java.sql.Time) {
|
||||
date = ((java.sql.Time) dateObject).toLocalTime().atDate(ZonedDateTime.now(tz).toLocalDate()).atZone(tz);
|
||||
date = ((java.sql.Date) dateObject).toLocalDate().atStartOfDay(tz);
|
||||
} else if (dateObject instanceof java.util.Date) {
|
||||
date = ((java.util.Date) dateObject).toInstant().atZone(tz);
|
||||
} else if (dateObject instanceof Calendar) {
|
||||
@@ -308,8 +305,6 @@ public class Date extends ContextBean {
|
||||
date = ((LocalDateTime) dateObject).atZone(tz);
|
||||
} else if (dateObject instanceof LocalDate) {
|
||||
date = ((LocalDate) dateObject).atStartOfDay(tz);
|
||||
} else if (dateObject instanceof LocalTime) {
|
||||
date = ((LocalTime) dateObject).atDate(ZonedDateTime.now(tz).toLocalDate()).atZone(tz);
|
||||
} else if (dateObject instanceof Instant) {
|
||||
date = ((Instant) dateObject).atZone(tz);
|
||||
} else {
|
||||
|
||||
@@ -26,17 +26,13 @@ import com.opensymphony.xwork2.config.entities.InterceptorMapping;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptorUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.validator.ActionValidatorManager;
|
||||
import com.opensymphony.xwork2.validator.FieldValidator;
|
||||
import com.opensymphony.xwork2.validator.ValidationException;
|
||||
import com.opensymphony.xwork2.validator.ValidationInterceptor;
|
||||
import com.opensymphony.xwork2.validator.Validator;
|
||||
import com.opensymphony.xwork2.validator.ValidatorContext;
|
||||
import com.opensymphony.xwork2.validator.*;
|
||||
import com.opensymphony.xwork2.validator.validators.VisitorFieldValidator;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
import org.apache.struts2.views.annotations.StrutsTag;
|
||||
import org.apache.struts2.views.annotations.StrutsTagAttribute;
|
||||
import org.apache.struts2.views.jsp.TagUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -76,7 +72,7 @@ import java.util.Set;
|
||||
* from it and using UrlHelper to generate the final url.
|
||||
* </li>
|
||||
* </ol>
|
||||
* <p>
|
||||
*
|
||||
* <!-- END SNIPPET: javadoc -->
|
||||
*
|
||||
* <p><b>Examples</b></p>
|
||||
@@ -88,12 +84,13 @@ import java.util.Set;
|
||||
*
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
@StrutsTag(
|
||||
name = "form",
|
||||
tldTagClass = "org.apache.struts2.views.jsp.ui.FormTag",
|
||||
description = "Renders an input form",
|
||||
allowDynamicAttributes = true)
|
||||
name="form",
|
||||
tldTagClass="org.apache.struts2.views.jsp.ui.FormTag",
|
||||
description="Renders an input form",
|
||||
allowDynamicAttributes=true)
|
||||
public class Form extends ClosingUIBean {
|
||||
public static final String OPEN_TEMPLATE = "form";
|
||||
public static final String TEMPLATE = "form-close";
|
||||
@@ -150,7 +147,7 @@ public class Form extends ClosingUIBean {
|
||||
|
||||
@Inject
|
||||
public void setUrlRenderer(UrlRenderer urlRenderer) {
|
||||
this.urlRenderer = urlRenderer;
|
||||
this.urlRenderer = urlRenderer;
|
||||
}
|
||||
|
||||
@Inject
|
||||
@@ -160,9 +157,9 @@ public class Form extends ClosingUIBean {
|
||||
|
||||
|
||||
/*
|
||||
* Revised for Portlet actionURL as form action, and add wwAction as hidden
|
||||
* field. Refer to template.simple/form.vm
|
||||
*/
|
||||
* Revised for Portlet actionURL as form action, and add wwAction as hidden
|
||||
* field. Refer to template.simple/form.vm
|
||||
*/
|
||||
@Override
|
||||
protected void evaluateExtraParams() {
|
||||
super.evaluateExtraParams();
|
||||
@@ -173,9 +170,9 @@ public class Form extends ClosingUIBean {
|
||||
if (name == null) {
|
||||
//make the name the same as the id
|
||||
String id = (String) getParameters().get("id");
|
||||
if (StringUtils.isNotEmpty(id)) {
|
||||
if (StringUtils.isNotEmpty(id)) {
|
||||
addParameter("name", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (onsubmit != null) {
|
||||
@@ -234,9 +231,8 @@ public class Form extends ClosingUIBean {
|
||||
|
||||
/**
|
||||
* Evaluate client side JavaScript Enablement.
|
||||
*
|
||||
* @param actionName the actioName to check for
|
||||
* @param namespace the namespace to check for
|
||||
* @param actionName the actioName to check for
|
||||
* @param namespace the namespace to check for
|
||||
* @param actionMethod the method to ckeck for
|
||||
*/
|
||||
protected void evaluateClientSideJsEnablement(String actionName, String namespace, String actionMethod) {
|
||||
@@ -279,7 +275,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) getParameters().get("actionName"));
|
||||
}
|
||||
|
||||
if (mapping == null) {
|
||||
@@ -292,7 +288,7 @@ public class Form extends ClosingUIBean {
|
||||
if (isValidateAnnotatedMethodOnly(actionName)) {
|
||||
methodName = mapping.getMethod();
|
||||
}
|
||||
|
||||
|
||||
List<Validator> actionValidators = actionValidatorManager.getValidators(actionClass, actionName, methodName);
|
||||
List<Validator> validators = new ArrayList<>();
|
||||
|
||||
@@ -303,7 +299,7 @@ public class Form extends ClosingUIBean {
|
||||
|
||||
private boolean isValidateAnnotatedMethodOnly(String actionName) {
|
||||
RuntimeConfiguration runtimeConfiguration = configuration.getRuntimeConfiguration();
|
||||
String actionNamespace = getNamespace(stack);
|
||||
String actionNamespace = TagUtils.buildNamespace(actionMapper, stack, request);
|
||||
ActionConfig actionConfig = runtimeConfiguration.getActionConfig(actionNamespace, actionName);
|
||||
|
||||
if (actionConfig != null) {
|
||||
@@ -359,84 +355,64 @@ public class Form extends ClosingUIBean {
|
||||
public static class FieldVisitorValidatorWrapper implements FieldValidator {
|
||||
private FieldValidator fieldValidator;
|
||||
private String namePrefix;
|
||||
|
||||
public FieldVisitorValidatorWrapper(FieldValidator fv, String namePrefix) {
|
||||
this.fieldValidator = fv;
|
||||
this.namePrefix = namePrefix;
|
||||
}
|
||||
|
||||
public String getValidatorType() {
|
||||
return "field-visitor";
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return namePrefix + fieldValidator.getFieldName();
|
||||
}
|
||||
|
||||
public FieldValidator getFieldValidator() {
|
||||
return fieldValidator;
|
||||
}
|
||||
|
||||
public void setFieldValidator(FieldValidator fieldValidator) {
|
||||
this.fieldValidator = fieldValidator;
|
||||
}
|
||||
|
||||
public String getDefaultMessage() {
|
||||
return fieldValidator.getDefaultMessage();
|
||||
}
|
||||
|
||||
public String getMessage(Object object) {
|
||||
return fieldValidator.getMessage(object);
|
||||
}
|
||||
|
||||
public String getMessageKey() {
|
||||
return fieldValidator.getMessageKey();
|
||||
}
|
||||
|
||||
public String[] getMessageParameters() {
|
||||
return fieldValidator.getMessageParameters();
|
||||
}
|
||||
|
||||
public ValidatorContext getValidatorContext() {
|
||||
return fieldValidator.getValidatorContext();
|
||||
}
|
||||
|
||||
public void setDefaultMessage(String message) {
|
||||
fieldValidator.setDefaultMessage(message);
|
||||
}
|
||||
|
||||
public void setFieldName(String fieldName) {
|
||||
fieldValidator.setFieldName(fieldName);
|
||||
}
|
||||
|
||||
public void setMessageKey(String key) {
|
||||
fieldValidator.setMessageKey(key);
|
||||
}
|
||||
|
||||
public void setMessageParameters(String[] messageParameters) {
|
||||
fieldValidator.setMessageParameters(messageParameters);
|
||||
}
|
||||
|
||||
public void setValidatorContext(ValidatorContext validatorContext) {
|
||||
fieldValidator.setValidatorContext(validatorContext);
|
||||
}
|
||||
|
||||
public void setValidatorType(String type) {
|
||||
fieldValidator.setValidatorType(type);
|
||||
}
|
||||
|
||||
public void setValueStack(ValueStack stack) {
|
||||
fieldValidator.setValueStack(stack);
|
||||
}
|
||||
|
||||
public void validate(Object object) throws ValidationException {
|
||||
fieldValidator.validate(object);
|
||||
}
|
||||
|
||||
public String getNamePrefix() {
|
||||
return namePrefix;
|
||||
}
|
||||
|
||||
public void setNamePrefix(String namePrefix) {
|
||||
this.namePrefix = namePrefix;
|
||||
}
|
||||
@@ -445,7 +421,7 @@ public class Form extends ClosingUIBean {
|
||||
/**
|
||||
* Return type of visited object.
|
||||
*
|
||||
* @param actionClass action class
|
||||
* @param actionClass action class
|
||||
* @param visitorFieldName field name
|
||||
* @return type of visited object
|
||||
*/
|
||||
@@ -475,68 +451,68 @@ public class Form extends ClosingUIBean {
|
||||
return sequence++;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "HTML onsubmit attribute")
|
||||
@StrutsTagAttribute(description="HTML onsubmit attribute")
|
||||
public void setOnsubmit(String onsubmit) {
|
||||
this.onsubmit = onsubmit;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "HTML onreset attribute")
|
||||
@StrutsTagAttribute(description="HTML onreset attribute")
|
||||
public void setOnreset(String onreset) {
|
||||
this.onreset = onreset;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "Set action name to submit to, without .action suffix", defaultValue = "current action")
|
||||
@StrutsTagAttribute(description="Set action name to submit to, without .action suffix", defaultValue="current action")
|
||||
public void setAction(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "HTML form target attribute")
|
||||
@StrutsTagAttribute(description="HTML form target attribute")
|
||||
public void setTarget(String target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "HTML form enctype attribute")
|
||||
@StrutsTagAttribute(description="HTML form enctype attribute")
|
||||
public void setEnctype(String enctype) {
|
||||
this.enctype = enctype;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "HTML form method attribute")
|
||||
@StrutsTagAttribute(description="HTML form method attribute")
|
||||
public void setMethod(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "Namespace for action to submit to", defaultValue = "current namespace")
|
||||
@StrutsTagAttribute(description="Namespace for action to submit to", defaultValue="current namespace")
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "Whether client side/remote validation should be performed. Only" +
|
||||
" useful with theme xhtml/ajax", type = "Boolean", defaultValue = "false")
|
||||
@StrutsTagAttribute(description="Whether client side/remote validation should be performed. Only" +
|
||||
" useful with theme xhtml/ajax", type="Boolean", defaultValue="false")
|
||||
public void setValidate(String validate) {
|
||||
this.validate = validate;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "The portlet mode to display after the form submit")
|
||||
@StrutsTagAttribute(description="The portlet mode to display after the form submit")
|
||||
public void setPortletMode(String portletMode) {
|
||||
this.portletMode = portletMode;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "The window state to display after the form submit")
|
||||
@StrutsTagAttribute(description="The window state to display after the form submit")
|
||||
public void setWindowState(String windowState) {
|
||||
this.windowState = windowState;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "The accepted charsets for this form. The values may be comma or blank delimited.")
|
||||
@StrutsTagAttribute(description="The accepted charsets for this form. The values may be comma or blank delimited.")
|
||||
public void setAcceptcharset(String acceptcharset) {
|
||||
this.acceptcharset = acceptcharset;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "Id of element that will receive the focus when page loads.")
|
||||
@StrutsTagAttribute(description="Id of element that will receive the focus when page loads.")
|
||||
public void setFocusElement(String focusElement) {
|
||||
this.focusElement = focusElement;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "Whether actual context should be included in URL", type = "Boolean", defaultValue = "true")
|
||||
@StrutsTagAttribute(description="Whether actual context should be included in URL", type="Boolean", defaultValue="true")
|
||||
public void setIncludeContext(boolean includeContext) {
|
||||
this.includeContext = includeContext;
|
||||
}
|
||||
|
||||
@@ -96,33 +96,33 @@ public abstract class FormButton extends ClosingUIBean {
|
||||
* </ol>
|
||||
*/
|
||||
protected void populateComponentHtmlId(Form form) {
|
||||
String tmpId = "";
|
||||
String _tmp_id = "";
|
||||
if (id != null) {
|
||||
// this check is needed for backwards compatibility with 2.1.x
|
||||
tmpId = findString(id);
|
||||
_tmp_id = findString(id);
|
||||
} else {
|
||||
if (form != null && form.getParameters().get("id") != null) {
|
||||
tmpId = tmpId + form.getParameters().get("id").toString() + "_";
|
||||
_tmp_id = _tmp_id + form.getParameters().get("id").toString() + "_";
|
||||
}
|
||||
if (name != null) {
|
||||
tmpId = tmpId + escape(findString(name));
|
||||
_tmp_id = _tmp_id + escape(name);
|
||||
} else if (action != null || method != null) {
|
||||
if (action != null) {
|
||||
tmpId = tmpId + escape(findString(action));
|
||||
_tmp_id = _tmp_id + escape(action);
|
||||
}
|
||||
if (method != null) {
|
||||
tmpId = tmpId + "_" + escape(findString(method));
|
||||
_tmp_id = _tmp_id + "_" + escape(method);
|
||||
}
|
||||
} else {
|
||||
// if form is null, this component is used, without a form, i guess
|
||||
// there's not much we could do then.
|
||||
if (form != null) {
|
||||
tmpId = tmpId + form.getSequence();
|
||||
_tmp_id = _tmp_id + form.getSequence();
|
||||
}
|
||||
}
|
||||
}
|
||||
addParameter("id", tmpId);
|
||||
addParameter("escapedId", escape(tmpId));
|
||||
addParameter("id", _tmp_id);
|
||||
addParameter("escapedId", escape(_tmp_id));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -159,10 +159,10 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
QueryStringParser.Result queryStringResult = queryStringParser.empty();
|
||||
Map<String, Object> actionParams = null;
|
||||
if (action != null && action.indexOf('?') > 0) {
|
||||
String queryString = action.substring(action.indexOf('?') + 1);
|
||||
queryStringResult = queryStringParser.parse(queryString);
|
||||
actionParams = queryStringParser.parse(queryString, false);
|
||||
action = action.substring(0, action.indexOf('?'));
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
|
||||
ActionMapping mapping = new ActionMapping(actionName, namespace, actionMethod, formComponent.parameters);
|
||||
String result = urlHelper.buildUrl(formComponent.actionMapper.getUriFromActionMapping(mapping),
|
||||
formComponent.request, formComponent.response, queryStringResult.getQueryParams(), scheme, formComponent.includeContext, true, false, false);
|
||||
formComponent.request, formComponent.response, actionParams, scheme, formComponent.includeContext, true, false, false);
|
||||
formComponent.addParameter("action", result);
|
||||
|
||||
// let's try to get the actual action class and name
|
||||
@@ -213,7 +213,7 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
LOG.warn("No configuration found for the specified action: '{}' in namespace: '{}'. Form action defaulting to 'action' attribute's literal value.", actionName, namespace);
|
||||
}
|
||||
|
||||
String result = urlHelper.buildUrl(action, formComponent.request, formComponent.response, queryStringResult.getQueryParams(), scheme, formComponent.includeContext, true);
|
||||
String result = urlHelper.buildUrl(action, formComponent.request, formComponent.response, actionParams, scheme, formComponent.includeContext, true);
|
||||
formComponent.addParameter("action", result);
|
||||
|
||||
// namespace: cut out anything between the start and the last /
|
||||
@@ -291,11 +291,7 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
|
||||
private void includeGetParameters(UrlProvider urlComponent) {
|
||||
String query = extractQueryString(urlComponent);
|
||||
QueryStringParser.Result result = queryStringParser.parse(query);
|
||||
mergeRequestParameters(urlComponent.getValue(), urlComponent.getParameters(), result.getQueryParams());
|
||||
if (!result.getQueryFragment().isEmpty()) {
|
||||
urlComponent.setAnchor(result.getQueryFragment());
|
||||
}
|
||||
mergeRequestParameters(urlComponent.getValue(), urlComponent.getParameters(), queryStringParser.parse(query, false));
|
||||
}
|
||||
|
||||
private String extractQueryString(UrlProvider urlComponent) {
|
||||
@@ -343,7 +339,7 @@ public class ServletUrlRenderer implements UrlRenderer {
|
||||
if (StringUtils.contains(value, "?")) {
|
||||
String queryString = value.substring(value.indexOf('?') + 1);
|
||||
|
||||
mergedParams = new LinkedHashMap<>(queryStringParser.parse(queryString).getQueryParams());
|
||||
mergedParams = queryStringParser.parse(queryString, false);
|
||||
for (Map.Entry<String, ?> entry : contextParameters.entrySet()) {
|
||||
if (!mergedParams.containsKey(entry.getKey())) {
|
||||
mergedParams.put(entry.getKey(), entry.getValue());
|
||||
|
||||
@@ -34,7 +34,7 @@ public class SimpleDateFormatAdapter implements DateFormatter {
|
||||
DateFormat df;
|
||||
Locale locale = ActionContext.getContext().getLocale();
|
||||
if (format == null) {
|
||||
df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
|
||||
df = SimpleDateFormat.getDateInstance(DateFormat.MEDIUM, locale);
|
||||
} else {
|
||||
df = new SimpleDateFormat(format, locale);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ import org.apache.struts2.dispatcher.DispatcherErrorHandler;
|
||||
import org.apache.struts2.dispatcher.StaticContentLoader;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapper;
|
||||
import org.apache.struts2.dispatcher.multipart.MultiPartRequest;
|
||||
import org.apache.struts2.interceptor.exec.ExecutorProvider;
|
||||
import org.apache.struts2.url.QueryStringBuilder;
|
||||
import org.apache.struts2.url.QueryStringParser;
|
||||
import org.apache.struts2.url.UrlDecoder;
|
||||
@@ -439,8 +438,6 @@ public class StrutsBeanSelectionProvider extends AbstractBeanSelectionProvider {
|
||||
alias(UrlEncoder.class, StrutsConstants.STRUTS_URL_ENCODER, builder, props, Scope.SINGLETON);
|
||||
alias(UrlDecoder.class, StrutsConstants.STRUTS_URL_DECODER, builder, props, Scope.SINGLETON);
|
||||
|
||||
alias(ExecutorProvider.class, StrutsConstants.STRUTS_EXECUTOR_PROVIDER, builder, props, Scope.SINGLETON);
|
||||
|
||||
switchDevMode(props);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,13 +33,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Collections.unmodifiableMap;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Override Xwork class so we can use an arbitrary config file
|
||||
@@ -47,25 +41,10 @@ import static java.util.Collections.unmodifiableMap;
|
||||
public class StrutsXmlConfigurationProvider extends XmlConfigurationProvider {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(StrutsXmlConfigurationProvider.class);
|
||||
private static final Map<String, String> STRUTS_DTD_MAPPINGS = unmodifiableMap(new HashMap<String, String>() {{
|
||||
put("-//Apache Software Foundation//DTD Struts Configuration 2.0//EN", "struts-2.0.dtd");
|
||||
put("-//Apache Software Foundation//DTD Struts Configuration 2.1//EN", "struts-2.1.dtd");
|
||||
put("-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN", "struts-2.1.7.dtd");
|
||||
put("-//Apache Software Foundation//DTD Struts Configuration 2.3//EN", "struts-2.3.dtd");
|
||||
put("-//Apache Software Foundation//DTD Struts Configuration 2.5//EN", "struts-2.5.dtd");
|
||||
put("-//Apache Software Foundation//DTD Struts Configuration 6.0//EN", "struts-6.0.dtd");
|
||||
}});
|
||||
private File baseDir = null;
|
||||
private final String filename;
|
||||
private final String reloadKey;
|
||||
private final ServletContext servletContext;
|
||||
|
||||
/**
|
||||
* Constructs the Struts configuration provider using the default struts.xml and no ServletContext
|
||||
*/
|
||||
public StrutsXmlConfigurationProvider() {
|
||||
this("struts.xml", null);
|
||||
}
|
||||
private String filename;
|
||||
private String reloadKey;
|
||||
private ServletContext servletContext;
|
||||
|
||||
/**
|
||||
* Constructs the configuration provider
|
||||
@@ -74,7 +53,7 @@ public class StrutsXmlConfigurationProvider extends XmlConfigurationProvider {
|
||||
*/
|
||||
@Deprecated
|
||||
public StrutsXmlConfigurationProvider(boolean errorIfMissing) {
|
||||
this("struts.xml", null);
|
||||
this("struts.xml", errorIfMissing, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,35 +62,35 @@ public class StrutsXmlConfigurationProvider extends XmlConfigurationProvider {
|
||||
* @param filename file with Struts configuration
|
||||
*/
|
||||
public StrutsXmlConfigurationProvider(String filename) {
|
||||
this(filename, null);
|
||||
this(filename, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the Struts configuration provider
|
||||
* Constructs the configuration provider
|
||||
*
|
||||
* @param filename The filename to look for
|
||||
* @param errorIfMissing If we should throw an exception if the file can't be found, @deprecated and should be dropped
|
||||
* @param ctx Our ServletContext
|
||||
*/
|
||||
public StrutsXmlConfigurationProvider(String filename, ServletContext ctx) {
|
||||
super(filename);
|
||||
public StrutsXmlConfigurationProvider(String filename, @Deprecated boolean errorIfMissing, ServletContext ctx) {
|
||||
super(filename, errorIfMissing);
|
||||
this.servletContext = ctx;
|
||||
this.filename = filename;
|
||||
this.reloadKey = "configurationReload-" + filename;
|
||||
setDtdMappings(STRUTS_DTD_MAPPINGS);
|
||||
reloadKey = "configurationReload-" + filename;
|
||||
Map<String,String> dtdMappings = new HashMap<String,String>(getDtdMappings());
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.0//EN", "struts-2.0.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.1//EN", "struts-2.1.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN", "struts-2.1.7.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.3//EN", "struts-2.3.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.5//EN", "struts-2.5.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 6.0//EN", "struts-6.0.dtd");
|
||||
setDtdMappings(dtdMappings);
|
||||
File file = new File(filename);
|
||||
if (file.getParent() != null) {
|
||||
this.baseDir = file.getParentFile();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.2.0, use {@link #StrutsXmlConfigurationProvider(String, ServletContext)}
|
||||
*/
|
||||
@Deprecated
|
||||
public StrutsXmlConfigurationProvider(String filename, @Deprecated boolean errorIfMissing, ServletContext ctx) {
|
||||
this(filename, ctx);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.opensymphony.xwork2.config.providers.XmlConfigurationProvider#register(com.opensymphony.xwork2.inject.ContainerBuilder, java.util.Properties)
|
||||
*/
|
||||
|
||||
@@ -18,10 +18,6 @@
|
||||
*/
|
||||
package org.apache.struts2.config.entities;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.StaticContentLoader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -31,6 +27,10 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.StaticContentLoader;
|
||||
|
||||
public class ConstantConfig {
|
||||
private Boolean devMode;
|
||||
private Boolean i18nReload;
|
||||
@@ -65,8 +65,6 @@ public class ConstantConfig {
|
||||
private String uiThemeExpansionToken;
|
||||
private Long multipartMaxSize;
|
||||
private Long multipartMaxFiles;
|
||||
private Long multipartMaxFileSize;
|
||||
private Long multipartMaxStringLength;
|
||||
private String multipartSaveDir;
|
||||
private Integer multipartBufferSize;
|
||||
private BeanConfig multipartParser;
|
||||
@@ -129,11 +127,9 @@ public class ConstantConfig {
|
||||
private Set<Class<?>> excludedClasses;
|
||||
private List<Pattern> excludedPackageNamePatterns;
|
||||
private Set<String> excludedPackageNames;
|
||||
private Set<Class<?>> excludedPackageExemptClasses;
|
||||
private Set<Class<?>> devModeExcludedClasses;
|
||||
private List<Pattern> devModeExcludedPackageNamePatterns;
|
||||
private Set<String> devModeExcludedPackageNames;
|
||||
private Set<Class<?>> devModeExcludedPackageExemptClasses;
|
||||
private BeanConfig excludedPatternsChecker;
|
||||
private BeanConfig acceptedPatternsChecker;
|
||||
private BeanConfig notExcludedAcceptedPatternsChecker;
|
||||
@@ -201,8 +197,6 @@ public class ConstantConfig {
|
||||
map.put(StrutsConstants.STRUTS_UI_THEME_EXPANSION_TOKEN, uiThemeExpansionToken);
|
||||
map.put(StrutsConstants.STRUTS_MULTIPART_MAXSIZE, Objects.toString(multipartMaxSize, null));
|
||||
map.put(StrutsConstants.STRUTS_MULTIPART_MAXFILES, Objects.toString(multipartMaxFiles, null));
|
||||
map.put(StrutsConstants.STRUTS_MULTIPART_MAXFILESIZE, Objects.toString(multipartMaxFileSize, null));
|
||||
map.put(StrutsConstants.STRUTS_MULTIPART_MAX_STRING_LENGTH, Objects.toString(multipartMaxStringLength, null));
|
||||
map.put(StrutsConstants.STRUTS_MULTIPART_SAVEDIR, multipartSaveDir);
|
||||
map.put(StrutsConstants.STRUTS_MULTIPART_BUFFERSIZE, Objects.toString(multipartBufferSize, null));
|
||||
map.put(StrutsConstants.STRUTS_MULTIPART_PARSER, beanConfToString(multipartParser));
|
||||
@@ -212,6 +206,7 @@ public class ConstantConfig {
|
||||
map.put(StrutsConstants.STRUTS_OBJECTFACTORY_SPRING_AUTOWIRE_ALWAYS_RESPECT, Objects.toString(objectFactorySpringAutoWireAlwaysRespect, null));
|
||||
map.put(StrutsConstants.STRUTS_OBJECTFACTORY_SPRING_USE_CLASS_CACHE, Objects.toString(objectFactorySpringUseClassCache, null));
|
||||
map.put(StrutsConstants.STRUTS_OBJECTFACTORY_SPRING_ENABLE_AOP_SUPPORT, Objects.toString(objectFactorySpringEnableAopSupport, null));
|
||||
map.put(StrutsConstants.STRUTS_XSLT_NOCACHE, Objects.toString(xsltNocache, null));
|
||||
map.put(StrutsConstants.STRUTS_CUSTOM_PROPERTIES, StringUtils.join(customProperties, ','));
|
||||
map.put(StrutsConstants.STRUTS_CUSTOM_I18N_RESOURCES, StringUtils.join(customI18nResources, ','));
|
||||
map.put(StrutsConstants.STRUTS_MAPPER_CLASS, beanConfToString(mapperClass));
|
||||
@@ -258,16 +253,15 @@ public class ConstantConfig {
|
||||
map.put(StrutsConstants.STRUTS_ALLOWED_METHOD_NAMES, Objects.toString(allowedMethodNames, null));
|
||||
map.put(StrutsConstants.STRUTS_DEFAULT_METHOD_NAME, defaultMethodName);
|
||||
map.put(StrutsConstants.STRUTS_MAPPER_ACTION_PREFIX_ENABLED, Objects.toString(mapperActionPrefixEnabled, null));
|
||||
map.put(StrutsConstants.STRUTS_MAPPER_ACTION_PREFIX_CROSSNAMESPACES, Objects.toString(mapperActionPrefixCrossNamespaces, null));
|
||||
map.put(StrutsConstants.DEFAULT_TEMPLATE_TYPE_CONFIG_KEY, uiTemplateSuffix);
|
||||
map.put(StrutsConstants.STRUTS_DISPATCHER_ERROR_HANDLER, beanConfToString(dispatcherErrorHandler));
|
||||
map.put(StrutsConstants.STRUTS_EXCLUDED_CLASSES, classesToString(excludedClasses));
|
||||
map.put(StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAME_PATTERNS, StringUtils.join(excludedPackageNamePatterns, ','));
|
||||
map.put(StrutsConstants.STRUTS_EXCLUDED_PACKAGE_NAMES, StringUtils.join(excludedPackageNames, ','));
|
||||
map.put(StrutsConstants.STRUTS_EXCLUDED_PACKAGE_EXEMPT_CLASSES, classesToString(excludedPackageExemptClasses));
|
||||
map.put(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_CLASSES, classesToString(devModeExcludedClasses));
|
||||
map.put(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAME_PATTERNS, StringUtils.join(devModeExcludedPackageNamePatterns, ','));
|
||||
map.put(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_NAMES, StringUtils.join(devModeExcludedPackageNames, ','));
|
||||
map.put(StrutsConstants.STRUTS_DEV_MODE_EXCLUDED_PACKAGE_EXEMPT_CLASSES, classesToString(devModeExcludedPackageExemptClasses));
|
||||
map.put(StrutsConstants.STRUTS_EXCLUDED_PATTERNS_CHECKER, beanConfToString(excludedPatternsChecker));
|
||||
map.put(StrutsConstants.STRUTS_ACCEPTED_PATTERNS_CHECKER, beanConfToString(acceptedPatternsChecker));
|
||||
map.put(StrutsConstants.STRUTS_NOT_EXCLUDED_ACCEPTED_PATTERNS_CHECKER, beanConfToString(notExcludedAcceptedPatternsChecker));
|
||||
@@ -596,22 +590,6 @@ public class ConstantConfig {
|
||||
this.multipartMaxFiles = multipartMaxFiles;
|
||||
}
|
||||
|
||||
public Long getMultipartMaxFileSize() {
|
||||
return multipartMaxFileSize;
|
||||
}
|
||||
|
||||
public void setMultipartMaxFileSize(Long multipartMaxFileSize) {
|
||||
this.multipartMaxFileSize = multipartMaxFileSize;
|
||||
}
|
||||
|
||||
public Long getMultipartMaxStringLength() {
|
||||
return multipartMaxStringLength;
|
||||
}
|
||||
|
||||
public void setMultipartMaxStringLength(Long multipartMaxStringLength) {
|
||||
this.multipartMaxStringLength = multipartMaxStringLength;
|
||||
}
|
||||
|
||||
public String getMultipartSaveDir() {
|
||||
return multipartSaveDir;
|
||||
}
|
||||
@@ -1208,14 +1186,6 @@ public class ConstantConfig {
|
||||
this.excludedPackageNames = excludedPackageNames;
|
||||
}
|
||||
|
||||
public Set<Class<?>> getExcludedPackageExemptClasses() {
|
||||
return excludedPackageExemptClasses;
|
||||
}
|
||||
|
||||
public void setExcludedPackageExemptClasses(Set<Class<?>> excludedPackageExemptClasses) {
|
||||
this.excludedPackageExemptClasses = excludedPackageExemptClasses;
|
||||
}
|
||||
|
||||
public Set<Class<?>> getDevModeExcludedClasses() {
|
||||
return devModeExcludedClasses;
|
||||
}
|
||||
@@ -1240,14 +1210,6 @@ public class ConstantConfig {
|
||||
this.devModeExcludedPackageNames = devModeExcludedPackageNames;
|
||||
}
|
||||
|
||||
public Set<Class<?>> getDevModeExcludedPackageExemptClasses() {
|
||||
return devModeExcludedPackageExemptClasses;
|
||||
}
|
||||
|
||||
public void setDevModeExcludedPackageExemptClasses(Set<Class<?>> devModeExcludedPackageExemptClasses) {
|
||||
this.devModeExcludedPackageExemptClasses = devModeExcludedPackageExemptClasses;
|
||||
}
|
||||
|
||||
public BeanConfig getExcludedPatternsChecker() {
|
||||
return excludedPatternsChecker;
|
||||
}
|
||||
|
||||
@@ -18,13 +18,9 @@
|
||||
*/
|
||||
package org.apache.struts2.dispatcher;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A simple implementation of the {@link java.util.Map} interface to handle a collection of attributes and
|
||||
@@ -32,12 +28,12 @@ import javax.servlet.ServletContext;
|
||||
* enumerates over all servlet context attributes and init parameters and returns a collection of both.
|
||||
* Note, this will occur lazily - only when the entry set is asked for.
|
||||
*/
|
||||
public class ApplicationMap extends AbstractMap<String, Object> implements Serializable {
|
||||
public class ApplicationMap extends AbstractMap implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 9136809763083228202L;
|
||||
|
||||
private ServletContext context;
|
||||
private Set<Entry<String, Object>> entries;
|
||||
private Set<Object> entries;
|
||||
|
||||
|
||||
/**
|
||||
@@ -45,7 +41,7 @@ public class ApplicationMap extends AbstractMap<String, Object> implements Seria
|
||||
*
|
||||
* @param ctx the servlet context
|
||||
*/
|
||||
public ApplicationMap(final ServletContext ctx) {
|
||||
public ApplicationMap(ServletContext ctx) {
|
||||
this.context = ctx;
|
||||
}
|
||||
|
||||
@@ -53,14 +49,13 @@ public class ApplicationMap extends AbstractMap<String, Object> implements Seria
|
||||
/**
|
||||
* Removes all entries from the Map and removes all attributes from the servlet context.
|
||||
*/
|
||||
@Override
|
||||
public void clear() {
|
||||
entries = null;
|
||||
|
||||
Enumeration<String> e = context.getAttributeNames();
|
||||
Enumeration e = context.getAttributeNames();
|
||||
|
||||
while (e.hasMoreElements()) {
|
||||
context.removeAttribute(e.nextElement());
|
||||
context.removeAttribute(e.nextElement().toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,20 +64,39 @@ public class ApplicationMap extends AbstractMap<String, Object> implements Seria
|
||||
*
|
||||
* @return a Set of all servlet context attributes as well as context init parameters.
|
||||
*/
|
||||
@Override
|
||||
public Set<Entry<String, Object>> entrySet() {
|
||||
public Set entrySet() {
|
||||
if (entries == null) {
|
||||
entries = new HashSet<>();
|
||||
|
||||
// Add servlet context attributes
|
||||
Enumeration<String> enumeration = context.getAttributeNames();
|
||||
Enumeration enumeration = context.getAttributeNames();
|
||||
|
||||
while (enumeration.hasMoreElements()) {
|
||||
final String key = enumeration.nextElement();
|
||||
final String key = enumeration.nextElement().toString();
|
||||
final Object value = context.getAttribute(key);
|
||||
entries.add(new StringObjectEntry(key, value) {
|
||||
@Override
|
||||
public Object setValue(final Object obj) {
|
||||
entries.add(new Map.Entry() {
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Map.Entry)) {
|
||||
return false;
|
||||
}
|
||||
Map.Entry entry = (Map.Entry) obj;
|
||||
|
||||
return ((key == null) ? (entry.getKey() == null) : key.equals(entry.getKey())) && ((value == null) ? (entry.getValue() == null) : value.equals(entry.getValue()));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return ((key == null) ? 0 : key.hashCode()) ^ ((value == null) ? 0 : value.hashCode());
|
||||
}
|
||||
|
||||
public Object getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Object setValue(Object obj) {
|
||||
context.setAttribute(key, obj);
|
||||
|
||||
return value;
|
||||
@@ -94,11 +108,31 @@ public class ApplicationMap extends AbstractMap<String, Object> implements Seria
|
||||
enumeration = context.getInitParameterNames();
|
||||
|
||||
while (enumeration.hasMoreElements()) {
|
||||
final String key = enumeration.nextElement();
|
||||
final String key = enumeration.nextElement().toString();
|
||||
final Object value = context.getInitParameter(key);
|
||||
entries.add(new StringObjectEntry(key, value) {
|
||||
@Override
|
||||
public Object setValue(final Object obj) {
|
||||
entries.add(new Map.Entry() {
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Map.Entry)) {
|
||||
return false;
|
||||
}
|
||||
Map.Entry entry = (Map.Entry) obj;
|
||||
|
||||
return ((key == null) ? (entry.getKey() == null) : key.equals(entry.getKey())) && ((value == null) ? (entry.getValue() == null) : value.equals(entry.getValue()));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return ((key == null) ? 0 : key.hashCode()) ^ ((value == null) ? 0 : value.hashCode());
|
||||
}
|
||||
|
||||
public Object getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Object setValue(Object obj) {
|
||||
context.setAttribute(key, obj);
|
||||
|
||||
return value;
|
||||
@@ -117,12 +151,13 @@ public class ApplicationMap extends AbstractMap<String, Object> implements Seria
|
||||
* @param key the entry key.
|
||||
* @return the servlet context attribute or init parameter or <tt>null</tt> if the entry is not found.
|
||||
*/
|
||||
public Object get(final String key) {
|
||||
public Object get(Object key) {
|
||||
// Try context attributes first, then init params
|
||||
// This gives the proper shadowing effects
|
||||
Object value = context.getAttribute(key);
|
||||
String keyString = key.toString();
|
||||
Object value = context.getAttribute(keyString);
|
||||
|
||||
return (value == null) ? context.getInitParameter(key) : value;
|
||||
return (value == null) ? context.getInitParameter(keyString) : value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,13 +167,10 @@ public class ApplicationMap extends AbstractMap<String, Object> implements Seria
|
||||
* @param value the value to set.
|
||||
* @return the attribute that was just set.
|
||||
*/
|
||||
@Override
|
||||
public Object put(final String key, final Object value) {
|
||||
public Object put(Object key, Object value) {
|
||||
Object oldValue = get(key);
|
||||
entries = null;
|
||||
|
||||
context.setAttribute(key, value);
|
||||
|
||||
context.setAttribute(key.toString(), value);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@@ -148,11 +180,11 @@ public class ApplicationMap extends AbstractMap<String, Object> implements Seria
|
||||
* @param key the attribute to remove.
|
||||
* @return the entry that was just removed.
|
||||
*/
|
||||
public Object remove(final String key) {
|
||||
public Object remove(Object key) {
|
||||
entries = null;
|
||||
|
||||
Object value = get(key);
|
||||
context.removeAttribute(key);
|
||||
context.removeAttribute(key.toString());
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -108,17 +109,15 @@ public class Dispatcher {
|
||||
|
||||
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*";
|
||||
|
||||
/**
|
||||
* Provide a thread local instance.
|
||||
*/
|
||||
private static final ThreadLocal<Dispatcher> instance = new ThreadLocal<>();
|
||||
private static ThreadLocal<Dispatcher> instance = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* Store list of DispatcherListeners.
|
||||
*/
|
||||
private static final List<DispatcherListener> dispatcherListeners = new CopyOnWriteArrayList<>();
|
||||
private static List<DispatcherListener> dispatcherListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
/**
|
||||
* Store state of StrutsConstants.STRUTS_DEVMODE setting.
|
||||
@@ -354,7 +353,7 @@ public class Dispatcher {
|
||||
try {
|
||||
((ObjectFactoryDestroyable) objectFactory).destroy();
|
||||
} catch (Exception e) {
|
||||
// catch any exception that may occur during destroy() and log it
|
||||
// catch any exception that may occurred during destroy() and log it
|
||||
LOG.error("Exception occurred while destroying ObjectFactory [{}]", objectFactory.toString(), e);
|
||||
}
|
||||
}
|
||||
@@ -428,36 +427,24 @@ public class Dispatcher {
|
||||
if (configPaths == null) {
|
||||
configPaths = DEFAULT_CONFIGURATION_PATHS;
|
||||
}
|
||||
loadConfigPaths(configPaths);
|
||||
}
|
||||
|
||||
private void loadConfigPaths(String configPaths) {
|
||||
String[] files = configPaths.split(CONFIG_SPLIT_REGEX);
|
||||
String[] files = configPaths.split("\\s*[,]\\s*");
|
||||
for (String file : files) {
|
||||
if (file.endsWith(".xml")) {
|
||||
configurationManager.addContainerProvider(createStrutsXmlConfigurationProvider(file, servletContext));
|
||||
configurationManager.addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid configuration file name");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected XmlConfigurationProvider createStrutsXmlConfigurationProvider(String filename, ServletContext ctx) {
|
||||
return new StrutsXmlConfigurationProvider(filename, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.2.0, use {@link #createStrutsXmlConfigurationProvider(String, ServletContext)}
|
||||
*/
|
||||
@Deprecated
|
||||
protected XmlConfigurationProvider createStrutsXmlConfigurationProvider(String filename, boolean errorIfMissing, ServletContext ctx) {
|
||||
return createStrutsXmlConfigurationProvider(filename, ctx);
|
||||
return new StrutsXmlConfigurationProvider(filename, errorIfMissing, ctx);
|
||||
}
|
||||
|
||||
private void init_JavaConfigurations() {
|
||||
String configClasses = initParams.get("javaConfigClasses");
|
||||
if (configClasses != null) {
|
||||
String[] classes = configClasses.split(CONFIG_SPLIT_REGEX);
|
||||
String[] classes = configClasses.split("\\s*[,]\\s*");
|
||||
for (String cname : classes) {
|
||||
try {
|
||||
Class<?> cls = ClassLoaderUtil.loadClass(cname, this.getClass());
|
||||
@@ -481,7 +468,7 @@ public class Dispatcher {
|
||||
private void init_CustomConfigurationProviders() {
|
||||
String configProvs = initParams.get("configProviders");
|
||||
if (configProvs != null) {
|
||||
String[] classes = configProvs.split(CONFIG_SPLIT_REGEX);
|
||||
String[] classes = configProvs.split("\\s*[,]\\s*");
|
||||
for (String cname : classes) {
|
||||
try {
|
||||
Class cls = ClassLoaderUtil.loadClass(cname, this.getClass());
|
||||
@@ -526,13 +513,6 @@ public class Dispatcher {
|
||||
configurationManager.addContainerProvider(new StrutsBeanSelectionProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
* `struts-deferred.xml` can be used to load configuration which is sensitive to loading order such as 'bean-selection' elements
|
||||
*/
|
||||
private void init_DeferredXmlConfigurations() {
|
||||
loadConfigPaths("struts-deferred.xml");
|
||||
}
|
||||
|
||||
private Container init_PreloadConfiguration() {
|
||||
return getContainer();
|
||||
}
|
||||
@@ -566,7 +546,6 @@ public class Dispatcher {
|
||||
init_CustomConfigurationProviders(); // [5]
|
||||
init_FilterInitParameters(); // [6]
|
||||
init_AliasStandardObjects(); // [7]
|
||||
init_DeferredXmlConfigurations();
|
||||
|
||||
Container container = init_PreloadConfiguration();
|
||||
container.inject(this);
|
||||
@@ -670,7 +649,7 @@ public class Dispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
protected ActionProxy prepareActionProxy(Map<String, Object> extraContext, String actionNamespace, String actionName, String actionMethod) {
|
||||
private ActionProxy prepareActionProxy(Map<String, Object> extraContext, String actionNamespace, String actionName, String actionMethod) {
|
||||
ActionProxy proxy;
|
||||
//check if we are probably in an async resuming
|
||||
ActionInvocation invocation = ActionContext.getContext().getActionInvocation();
|
||||
@@ -689,12 +668,12 @@ public class Dispatcher {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
protected ActionProxy createActionProxy(String namespace, String name, String method, Map<String, Object> extraContext) {
|
||||
private ActionProxy createActionProxy(String namespace, String name, String method, Map<String, Object> extraContext) {
|
||||
ActionProxyFactory actionProxyFactory = getContainer().getInstance(ActionProxyFactory.class);
|
||||
return actionProxyFactory.createActionProxy(namespace, name, method, extraContext, true, false);
|
||||
}
|
||||
|
||||
protected boolean isSameAction(ActionProxy actionProxy, String namespace, String actionName, String method) {
|
||||
private boolean isSameAction(ActionProxy actionProxy, String namespace, String actionName, String method) {
|
||||
return Objects.equals(namespace, actionProxy.getNamespace())
|
||||
&& Objects.equals(actionName, actionProxy.getActionName())
|
||||
&& Objects.equals(method, actionProxy.getMethod());
|
||||
@@ -770,7 +749,7 @@ public class Dispatcher {
|
||||
Map<String, Object> applicationMap,
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
Map<String, Object> extraContext = ActionContext.of()
|
||||
Map<String, Object> extraContext = ActionContext.of(new HashMap<>())
|
||||
.withParameters(parameters)
|
||||
.withSession(sessionMap)
|
||||
.withApplication(applicationMap)
|
||||
|
||||
@@ -18,12 +18,15 @@
|
||||
*/
|
||||
package org.apache.struts2.dispatcher;
|
||||
|
||||
import org.apache.struts2.interceptor.ParameterAware;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
@@ -78,6 +81,10 @@ public class HttpParameters implements Map<String, Parameter>, Cloneable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void applyParameters(ParameterAware parameterAware) {
|
||||
parameterAware.setParameters(toMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return parameters.size();
|
||||
|
||||
@@ -47,43 +47,17 @@ public class PrepareOperations {
|
||||
/**
|
||||
* Maintains per-request override of devMode configuration.
|
||||
*/
|
||||
private static final ThreadLocal<Boolean> devModeOverride = new InheritableThreadLocal<>();
|
||||
private static ThreadLocal<Boolean> devModeOverride = new InheritableThreadLocal<>();
|
||||
|
||||
|
||||
private final Dispatcher dispatcher;
|
||||
private Dispatcher dispatcher;
|
||||
private static final String STRUTS_ACTION_MAPPING_KEY = "struts.actionMapping";
|
||||
private static final String NO_ACTION_MAPPING = "noActionMapping";
|
||||
private static final String PREPARE_COUNTER = "__prepare_recursion_counter";
|
||||
private static final String WRAP_COUNTER = "__wrap_recursion_counter";
|
||||
public static final String CLEANUP_RECURSION_COUNTER = "__cleanup_recursion_counter";
|
||||
|
||||
public PrepareOperations(Dispatcher dispatcher) {
|
||||
this.dispatcher = dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called by {@link org.apache.struts2.dispatcher.filter.StrutsPrepareFilter} to track how many times this
|
||||
* request has been filtered.
|
||||
*/
|
||||
public void trackRecursion(HttpServletRequest request) {
|
||||
incrementRecursionCounter(request, PREPARE_COUNTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up request. When paired with {@link #trackRecursion}, only cleans up once the first filter instance has
|
||||
* completed, preventing cleanup by recursive filter calls - i.e. before the request is completely processed.
|
||||
*/
|
||||
public void cleanupRequest(final HttpServletRequest request) {
|
||||
decrementRecursionCounter(request, PREPARE_COUNTER, () -> {
|
||||
try {
|
||||
dispatcher.cleanUpRequest(request);
|
||||
} finally {
|
||||
ActionContext.clear();
|
||||
Dispatcher.setInstance(null);
|
||||
devModeOverride.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the action context and initializes the thread local
|
||||
*
|
||||
@@ -94,6 +68,12 @@ public class PrepareOperations {
|
||||
*/
|
||||
public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
|
||||
ActionContext ctx;
|
||||
int counter = 1;
|
||||
Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
|
||||
if (oldCounter != null) {
|
||||
counter = oldCounter + 1;
|
||||
}
|
||||
|
||||
ActionContext oldContext = ActionContext.getContext();
|
||||
if (oldContext != null) {
|
||||
// detected existing context, so we are probably in a forward
|
||||
@@ -106,9 +86,35 @@ public class PrepareOperations {
|
||||
ctx = ActionContext.of(stack.getContext()).bind();
|
||||
}
|
||||
}
|
||||
request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up a request of thread locals
|
||||
*
|
||||
* @param request servlet request
|
||||
*/
|
||||
public void cleanupRequest(HttpServletRequest request) {
|
||||
Integer counterVal = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
|
||||
if (counterVal != null) {
|
||||
counterVal -= 1;
|
||||
request.setAttribute(CLEANUP_RECURSION_COUNTER, counterVal);
|
||||
if (counterVal > 0 ) {
|
||||
LOG.debug("skipping cleanup counter={}", counterVal);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// always clean up the thread request, even if an action hasn't been executed
|
||||
try {
|
||||
dispatcher.cleanUpRequest(request);
|
||||
} finally {
|
||||
ActionContext.clear();
|
||||
Dispatcher.setInstance(null);
|
||||
devModeOverride.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the dispatcher to the dispatcher thread local
|
||||
*/
|
||||
@@ -128,15 +134,14 @@ public class PrepareOperations {
|
||||
|
||||
/**
|
||||
* Wraps the request with the Struts wrapper that handles multipart requests better
|
||||
* Also tracks additional calls to this method on the same request.
|
||||
*
|
||||
* @param request servlet request
|
||||
* @param oldRequest servlet request
|
||||
*
|
||||
* @return The new request, if there is one
|
||||
* @throws ServletException on any servlet related error
|
||||
*/
|
||||
public HttpServletRequest wrapRequest(HttpServletRequest request) throws ServletException {
|
||||
incrementRecursionCounter(request, WRAP_COUNTER);
|
||||
public HttpServletRequest wrapRequest(HttpServletRequest oldRequest) throws ServletException {
|
||||
HttpServletRequest request = oldRequest;
|
||||
try {
|
||||
// Wrap request first, just in case it is multipart/form-data
|
||||
// parameters might not be accessible through before encoding (ww-1278)
|
||||
@@ -148,14 +153,6 @@ public class PrepareOperations {
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be called after whenever {@link #wrapRequest} is called. Ensures the request is only cleaned up at the
|
||||
* instance it was initially wrapped in the case of multiple wrap calls - i.e. filter recursion.
|
||||
*/
|
||||
public void cleanupWrappedRequest(final HttpServletRequest request) {
|
||||
decrementRecursionCounter(request, WRAP_COUNTER, () -> dispatcher.cleanUpRequest(request));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and optionally creates an {@link ActionMapping}. It first looks in the current request to see if one
|
||||
* has already been found, otherwise, it creates it and stores it in the request. No mapping will be created in the
|
||||
@@ -175,7 +172,7 @@ public class PrepareOperations {
|
||||
* has already been found, otherwise, it creates it and stores it in the request. No mapping will be created in the
|
||||
* case of static resource requests or unidentifiable requests for other servlets, for example.
|
||||
* @param forceLookup if true, the action mapping will be looked up from the ActionMapper instance, ignoring if there is one
|
||||
* in the request or not
|
||||
* in the request or not
|
||||
*
|
||||
* @param request servlet request
|
||||
* @param response servlet response
|
||||
@@ -183,24 +180,18 @@ public class PrepareOperations {
|
||||
* @return the action mapping
|
||||
*/
|
||||
public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) {
|
||||
ActionMapping mapping = null;
|
||||
|
||||
Object mappingAttr = request.getAttribute(STRUTS_ACTION_MAPPING_KEY);
|
||||
if (mappingAttr == null || forceLookup) {
|
||||
ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY);
|
||||
if (mapping == null || forceLookup) {
|
||||
try {
|
||||
mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager());
|
||||
if (mapping != null) {
|
||||
request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping);
|
||||
} else {
|
||||
request.setAttribute(STRUTS_ACTION_MAPPING_KEY, NO_ACTION_MAPPING);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
if (dispatcher.isHandleException() || dispatcher.isDevMode()) {
|
||||
dispatcher.sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
|
||||
}
|
||||
}
|
||||
} else if (!NO_ACTION_MAPPING.equals(mappingAttr)) {
|
||||
mapping = (ActionMapping) mappingAttr;
|
||||
}
|
||||
|
||||
return mapping;
|
||||
@@ -229,14 +220,13 @@ public class PrepareOperations {
|
||||
*
|
||||
* @return <tt>true</tt> if the request URI matches one of the given patterns
|
||||
*/
|
||||
public boolean isUrlExcluded(HttpServletRequest request, List<Pattern> excludedPatterns) {
|
||||
if (excludedPatterns == null) {
|
||||
return false;
|
||||
}
|
||||
String uri = RequestUtils.getUri(request);
|
||||
for (Pattern pattern : excludedPatterns) {
|
||||
if (pattern.matcher(uri).matches()) {
|
||||
return true;
|
||||
public boolean isUrlExcluded( HttpServletRequest request, List<Pattern> excludedPatterns ) {
|
||||
if (excludedPatterns != null) {
|
||||
String uri = RequestUtils.getUri(request);
|
||||
for ( Pattern pattern : excludedPatterns ) {
|
||||
if (pattern.matcher(uri).matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -263,6 +253,7 @@ public class PrepareOperations {
|
||||
|
||||
/**
|
||||
* Clear any override of the static devMode value being applied to the current thread.
|
||||
*
|
||||
* This can be useful for any situation where {@link #overrideDevMode(boolean)} might be called
|
||||
* in a flow where {@link #cleanupRequest(javax.servlet.http.HttpServletRequest)} does not get called.
|
||||
* May be very situational (such as some unit tests), but may have other utility as well.
|
||||
@@ -271,30 +262,4 @@ public class PrepareOperations {
|
||||
devModeOverride.remove(); // Remove current thread's value, enxure next read returns it to initialValue (typically null).
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to potentially count recursive executions with a request attribute. Should be used in conjunction
|
||||
* with {@link #decrementRecursionCounter}.
|
||||
*/
|
||||
public static void incrementRecursionCounter(HttpServletRequest request, String attributeName) {
|
||||
Integer setCounter = (Integer) request.getAttribute(attributeName);
|
||||
if (setCounter == null) {
|
||||
setCounter = 0;
|
||||
}
|
||||
request.setAttribute(attributeName, ++setCounter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to count execution completions with a request attribute, and optionally execute some code
|
||||
* (e.g. cleanup) once all recursive executions have completed. Should be used in conjunction with
|
||||
* {@link #incrementRecursionCounter}.
|
||||
*/
|
||||
public static void decrementRecursionCounter(HttpServletRequest request, String attributeName, Runnable runnable) {
|
||||
Integer setCounter = (Integer) request.getAttribute(attributeName);
|
||||
if (setCounter != null) {
|
||||
request.setAttribute(attributeName, --setCounter);
|
||||
}
|
||||
if ((setCounter == null || setCounter == 0) && runnable != null) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,11 +28,11 @@ import java.util.Set;
|
||||
/**
|
||||
* A simple implementation of the {@link java.util.Map} interface to handle a collection of request attributes.
|
||||
*/
|
||||
public class RequestMap extends AbstractMap<String, Object> implements Serializable {
|
||||
public class RequestMap extends AbstractMap implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -7675640869293787926L;
|
||||
|
||||
private Set<Entry<String, Object>> entries;
|
||||
private Set<Object> entries;
|
||||
private HttpServletRequest request;
|
||||
|
||||
/**
|
||||
@@ -48,13 +48,12 @@ public class RequestMap extends AbstractMap<String, Object> implements Serializa
|
||||
/**
|
||||
* Removes all attributes from the request as well as clears entries in this map.
|
||||
*/
|
||||
@Override
|
||||
public void clear() {
|
||||
entries = null;
|
||||
Enumeration<String> keys = request.getAttributeNames();
|
||||
Enumeration keys = request.getAttributeNames();
|
||||
|
||||
while (keys.hasMoreElements()) {
|
||||
String key = keys.nextElement();
|
||||
String key = (String) keys.nextElement();
|
||||
request.removeAttribute(key);
|
||||
}
|
||||
}
|
||||
@@ -64,19 +63,38 @@ public class RequestMap extends AbstractMap<String, Object> implements Serializa
|
||||
*
|
||||
* @return a Set of attributes from the http request.
|
||||
*/
|
||||
@Override
|
||||
public Set<Entry<String, Object>> entrySet() {
|
||||
public Set entrySet() {
|
||||
if (entries == null) {
|
||||
entries = new HashSet<>();
|
||||
|
||||
Enumeration<String> enumeration = request.getAttributeNames();
|
||||
Enumeration enumeration = request.getAttributeNames();
|
||||
|
||||
while (enumeration.hasMoreElements()) {
|
||||
final String key = enumeration.nextElement();
|
||||
final String key = enumeration.nextElement().toString();
|
||||
final Object value = request.getAttribute(key);
|
||||
entries.add(new StringObjectEntry(key, value) {
|
||||
@Override
|
||||
public Object setValue(final Object obj) {
|
||||
entries.add(new Entry() {
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Entry)) {
|
||||
return false;
|
||||
}
|
||||
Entry entry = (Entry) obj;
|
||||
|
||||
return ((key == null) ? (entry.getKey() == null) : key.equals(entry.getKey())) && ((value == null) ? (entry.getValue() == null) : value.equals(entry.getValue()));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return ((key == null) ? 0 : key.hashCode()) ^ ((value == null) ? 0 : value.hashCode());
|
||||
}
|
||||
|
||||
public Object getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Object setValue(Object obj) {
|
||||
request.setAttribute(key, obj);
|
||||
|
||||
return value;
|
||||
@@ -94,8 +112,8 @@ public class RequestMap extends AbstractMap<String, Object> implements Serializa
|
||||
* @param key the name of the request attribute.
|
||||
* @return the request attribute or <tt>null</tt> if it doesn't exist.
|
||||
*/
|
||||
public Object get(final String key) {
|
||||
return request.getAttribute(key);
|
||||
public Object get(Object key) {
|
||||
return request.getAttribute(key.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,13 +123,10 @@ public class RequestMap extends AbstractMap<String, Object> implements Serializa
|
||||
* @param value the value to set.
|
||||
* @return the object that was just set.
|
||||
*/
|
||||
@Override
|
||||
public Object put(final String key, final Object value) {
|
||||
public Object put(Object key, Object value) {
|
||||
Object oldValue = get(key);
|
||||
entries = null;
|
||||
|
||||
request.setAttribute(key, value);
|
||||
|
||||
request.setAttribute(key.toString(), value);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@@ -121,11 +136,11 @@ public class RequestMap extends AbstractMap<String, Object> implements Serializa
|
||||
* @param key the name of the attribute to remove.
|
||||
* @return the value that was removed or <tt>null</tt> if the value was not found (and hence, not removed).
|
||||
*/
|
||||
public Object remove(final String key) {
|
||||
public Object remove(Object key) {
|
||||
entries = null;
|
||||
|
||||
Object value = get(key);
|
||||
request.removeAttribute(key);
|
||||
request.removeAttribute(key.toString());
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -21,33 +21,29 @@ package org.apache.struts2.dispatcher;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.Serializable;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A simple implementation of the {@link java.util.Map} interface to handle a collection of HTTP session
|
||||
* attributes. The {@link #entrySet()} method enumerates over all session attributes and creates a Set of entries.
|
||||
* Note, this will occur lazily - only when the entry set is asked for.
|
||||
*/
|
||||
public class SessionMap extends AbstractMap<String, Object> implements Serializable {
|
||||
public class SessionMap<K, V> extends AbstractMap<K, V> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 4678843241638046854L;
|
||||
|
||||
protected HttpSession session;
|
||||
protected Set<Entry<String, Object>> entries;
|
||||
protected Set<Map.Entry<K, V>> entries;
|
||||
protected HttpServletRequest request;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new session map given a http servlet request. Note, the enumeration of request
|
||||
* Creates a new session map given a http servlet request. Note, ths enumeration of request
|
||||
* attributes will occur when the map entries are asked for.
|
||||
*
|
||||
* @param request the http servlet request object.
|
||||
*/
|
||||
public SessionMap(final HttpServletRequest request) {
|
||||
public SessionMap(HttpServletRequest request) {
|
||||
// note, holding on to this request and relying on lazy session initalization will not work
|
||||
// if you are running your action invocation in a background task, such as using the
|
||||
// "execAndWait" interceptor
|
||||
@@ -74,7 +70,7 @@ public class SessionMap extends AbstractMap<String, Object> implements Serializa
|
||||
* Removes all attributes from the session as well as clears entries in this
|
||||
* map.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void clear() {
|
||||
if (session == null) {
|
||||
return;
|
||||
@@ -82,7 +78,7 @@ public class SessionMap extends AbstractMap<String, Object> implements Serializa
|
||||
|
||||
synchronized (session.getId().intern()) {
|
||||
entries = null;
|
||||
final Enumeration<String> attributeNamesEnum = session.getAttributeNames();
|
||||
Enumeration<String> attributeNamesEnum = session.getAttributeNames();
|
||||
while (attributeNamesEnum.hasMoreElements()) {
|
||||
session.removeAttribute(attributeNamesEnum.nextElement());
|
||||
}
|
||||
@@ -95,8 +91,8 @@ public class SessionMap extends AbstractMap<String, Object> implements Serializa
|
||||
*
|
||||
* @return a Set of attributes from the http session.
|
||||
*/
|
||||
@Override
|
||||
public Set<Entry<String, Object>> entrySet() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<java.util.Map.Entry<K, V>> entrySet() {
|
||||
if (session == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
@@ -105,17 +101,37 @@ public class SessionMap extends AbstractMap<String, Object> implements Serializa
|
||||
if (entries == null) {
|
||||
entries = new HashSet<>();
|
||||
|
||||
final Enumeration<String> enumeration = session.getAttributeNames();
|
||||
Enumeration<?> enumeration = session.getAttributeNames();
|
||||
|
||||
while (enumeration.hasMoreElements()) {
|
||||
final String key = enumeration.nextElement();
|
||||
final String key = enumeration.nextElement().toString();
|
||||
final Object value = session.getAttribute(key);
|
||||
entries.add(new StringObjectEntry(key, value) {
|
||||
@Override
|
||||
public Object setValue(final Object obj) {
|
||||
entries.add(new Map.Entry<K, V>() {
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Map.Entry)) {
|
||||
return false;
|
||||
}
|
||||
Map.Entry<K, V> entry = (Map.Entry<K, V>) obj;
|
||||
|
||||
return ((key == null) ? (entry.getKey() == null) : key.equals(entry.getKey())) && ((value == null) ? (entry.getValue() == null) : value.equals(entry.getValue()));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return ((key == null) ? 0 : key.hashCode()) ^ ((value == null) ? 0 : value.hashCode());
|
||||
}
|
||||
|
||||
public K getKey() {
|
||||
return (K) key;
|
||||
}
|
||||
|
||||
public V getValue() {
|
||||
return (V) value;
|
||||
}
|
||||
|
||||
public V setValue(Object obj) {
|
||||
session.setAttribute(key, obj);
|
||||
|
||||
return value;
|
||||
return (V) value;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -127,21 +143,18 @@ public class SessionMap extends AbstractMap<String, Object> implements Serializa
|
||||
|
||||
/**
|
||||
* Returns the session attribute associated with the given key or <tt>null</tt> if it doesn't exist.
|
||||
*
|
||||
* <b>Note:</b> Must use the same signature as {@link java.util.AbstractMap#get(java.lang.Object)} to ensure the
|
||||
* expected specialized behaviour is performed here (and not the generic ancestor behaviour).
|
||||
*
|
||||
* @param key the name of the session attribute.
|
||||
* @return the session attribute or <tt>null</tt> if it doesn't exist.
|
||||
*/
|
||||
@Override
|
||||
public Object get(final Object key) {
|
||||
@SuppressWarnings("unchecked")
|
||||
public V get(Object key) {
|
||||
if (session == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
synchronized (session.getId().intern()) {
|
||||
return session.getAttribute(key != null ? key.toString() : null);
|
||||
return (V) session.getAttribute(key.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,17 +165,16 @@ public class SessionMap extends AbstractMap<String, Object> implements Serializa
|
||||
* @param value the value to set.
|
||||
* @return the object that was just set.
|
||||
*/
|
||||
@Override
|
||||
public Object put(final String key, final Object value) {
|
||||
public V put(K key, V value) {
|
||||
synchronized (this) {
|
||||
if (session == null) {
|
||||
session = request.getSession(true);
|
||||
}
|
||||
}
|
||||
synchronized (session.getId().intern()) {
|
||||
final Object oldValue = get(key);
|
||||
V oldValue = get(key);
|
||||
entries = null;
|
||||
session.setAttribute(key, value);
|
||||
session.setAttribute(key.toString(), value);
|
||||
return oldValue;
|
||||
}
|
||||
}
|
||||
@@ -170,14 +182,10 @@ public class SessionMap extends AbstractMap<String, Object> implements Serializa
|
||||
/**
|
||||
* Removes the specified session attribute.
|
||||
*
|
||||
* <b>Note:</b> Must use the same signature as {@link java.util.AbstractMap#remove(java.lang.Object)} to ensure the
|
||||
* expected specialized behaviour is performed here (and not the generic ancestor behaviour).
|
||||
*
|
||||
* @param key the name of the attribute to remove.
|
||||
* @return the value that was removed or <tt>null</tt> if the value was not found (and hence, not removed).
|
||||
*/
|
||||
@Override
|
||||
public Object remove(final Object key) {
|
||||
public V remove(Object key) {
|
||||
if (session == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -185,9 +193,8 @@ public class SessionMap extends AbstractMap<String, Object> implements Serializa
|
||||
synchronized (session.getId().intern()) {
|
||||
entries = null;
|
||||
|
||||
final String keyAsString = (key != null ? key.toString() : null);
|
||||
final Object value = get(keyAsString);
|
||||
session.removeAttribute(keyAsString);
|
||||
V value = get(key);
|
||||
session.removeAttribute(key.toString());
|
||||
|
||||
return value;
|
||||
}
|
||||
@@ -197,21 +204,16 @@ public class SessionMap extends AbstractMap<String, Object> implements Serializa
|
||||
/**
|
||||
* Checks if the specified session attribute with the given key exists.
|
||||
*
|
||||
* <b>Note:</b> Must use the same signature as {@link java.util.AbstractMap#containsKey(java.lang.Object)} to ensure the
|
||||
* expected specialized behaviour is performed here (and not the generic ancestor behaviour).
|
||||
*
|
||||
* @param key the name of the session attribute.
|
||||
* @return <tt>true</tt> if the session attribute exits or <tt>false</tt> if it doesn't exist.
|
||||
*/
|
||||
@Override
|
||||
public boolean containsKey(final Object key) {
|
||||
public boolean containsKey(Object key) {
|
||||
if (session == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
synchronized (session.getId().intern()) {
|
||||
final String keyAsString = (key != null ? key.toString() : null);
|
||||
return (session.getAttribute(keyAsString) != null);
|
||||
return (session.getAttribute(key.toString()) != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.dispatcher;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
abstract class StringObjectEntry implements Entry<String, Object> {
|
||||
private String key;
|
||||
private Object value;
|
||||
|
||||
StringObjectEntry(final String key, final Object value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (!(obj instanceof Entry)) {
|
||||
return false;
|
||||
}
|
||||
Entry<?, ?> entry = (Entry<?, ?>) obj;
|
||||
|
||||
return keyEquals(entry) && valueEquals(entry);
|
||||
}
|
||||
|
||||
private boolean keyEquals(final Entry<?, ?> entry) {
|
||||
return (key == null) ? (entry.getKey() == null) : key.equals(entry.getKey());
|
||||
}
|
||||
|
||||
private boolean valueEquals(Entry<?, ?> entry) {
|
||||
return (value == null) ? (entry.getValue() == null) : value.equals(entry.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return ((key == null) ? 0 : key.hashCode()) ^ ((value == null) ? 0 : value.hashCode());
|
||||
}
|
||||
}
|
||||
@@ -20,17 +20,12 @@ package org.apache.struts2.dispatcher.filter;
|
||||
|
||||
import org.apache.struts2.StrutsStatics;
|
||||
import org.apache.struts2.dispatcher.Dispatcher;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
import org.apache.struts2.dispatcher.ExecuteOperations;
|
||||
import org.apache.struts2.dispatcher.InitOperations;
|
||||
import org.apache.struts2.dispatcher.PrepareOperations;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
@@ -51,43 +46,14 @@ public class StrutsExecuteFilter implements StrutsStatics, Filter {
|
||||
|
||||
protected synchronized void lazyInit() {
|
||||
if (execute == null) {
|
||||
InitOperations init = createInitOperations();
|
||||
InitOperations init = new InitOperations();
|
||||
Dispatcher dispatcher = init.findDispatcherOnThread();
|
||||
init.initStaticContentLoader(new FilterHostConfig(filterConfig), dispatcher);
|
||||
|
||||
prepare = createPrepareOperations(dispatcher);
|
||||
execute = createExecuteOperations(dispatcher);
|
||||
prepare = new PrepareOperations(dispatcher);
|
||||
execute = new ExecuteOperations(dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link InitOperations} to be used during
|
||||
* initialising {@link Dispatcher}
|
||||
*
|
||||
* @return instance of {@link InitOperations}
|
||||
*/
|
||||
protected InitOperations createInitOperations() {
|
||||
return new InitOperations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link PrepareOperations} to be used during
|
||||
* initialising {@link Dispatcher}
|
||||
*
|
||||
* @return instance of {@link PrepareOperations}
|
||||
*/
|
||||
protected PrepareOperations createPrepareOperations(Dispatcher dispatcher) {
|
||||
return new PrepareOperations(dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link ExecuteOperations} to be used during
|
||||
* initialising {@link Dispatcher}
|
||||
*
|
||||
* @return instance of {@link ExecuteOperations}
|
||||
*/
|
||||
protected ExecuteOperations createExecuteOperations(Dispatcher dispatcher) {
|
||||
return new ExecuteOperations(dispatcher);
|
||||
}
|
||||
|
||||
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
|
||||
@@ -107,15 +73,22 @@ public class StrutsExecuteFilter implements StrutsStatics, Filter {
|
||||
|
||||
ActionMapping mapping = prepare.findActionMapping(request, response);
|
||||
|
||||
if (mapping != null) {
|
||||
//if recursion counter is > 1, it means we are in a "forward", in that case a mapping will still be
|
||||
//in the request, if we handle it, it will lead to an infinite loop, see WW-3077
|
||||
Integer recursionCounter = (Integer) request.getAttribute(PrepareOperations.CLEANUP_RECURSION_COUNTER);
|
||||
|
||||
if (mapping == null || recursionCounter > 1) {
|
||||
boolean handled = execute.executeStaticResourceRequest(request, response);
|
||||
if (!handled) {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
} else {
|
||||
execute.executeAction(request, response, mapping);
|
||||
} else if (!execute.executeStaticResourceRequest(request, response)) {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean excludeUrl(HttpServletRequest request) {
|
||||
return Boolean.TRUE.equals(request.getAttribute(StrutsPrepareFilter.REQUEST_EXCLUDED_FROM_ACTION_MAPPING));
|
||||
return request.getAttribute(StrutsPrepareFilter.REQUEST_EXCLUDED_FROM_ACTION_MAPPING) != null;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
|
||||
+22
-37
@@ -23,10 +23,10 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.RequestUtils;
|
||||
import org.apache.struts2.StrutsStatics;
|
||||
import org.apache.struts2.dispatcher.Dispatcher;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
import org.apache.struts2.dispatcher.ExecuteOperations;
|
||||
import org.apache.struts2.dispatcher.InitOperations;
|
||||
import org.apache.struts2.dispatcher.PrepareOperations;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
@@ -50,7 +50,7 @@ public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {
|
||||
|
||||
protected PrepareOperations prepare;
|
||||
protected ExecuteOperations execute;
|
||||
protected List<Pattern> excludedPatterns;
|
||||
protected List<Pattern> excludedPatterns = null;
|
||||
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
InitOperations init = createInitOperations();
|
||||
@@ -62,7 +62,6 @@ public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {
|
||||
|
||||
prepare = createPrepareOperations(dispatcher);
|
||||
execute = createExecuteOperations(dispatcher);
|
||||
// Note: Currently, excluded patterns are not refreshed following an XWork config reload
|
||||
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
|
||||
|
||||
postInit(dispatcher, filterConfig);
|
||||
@@ -107,7 +106,7 @@ public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {
|
||||
/**
|
||||
* Callback for post initialization
|
||||
*
|
||||
* @param dispatcher the dispatcher
|
||||
* @param dispatcher the dispatcher
|
||||
* @param filterConfig the filter config
|
||||
*/
|
||||
protected void postInit(Dispatcher dispatcher, FilterConfig filterConfig) {
|
||||
@@ -119,48 +118,34 @@ public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {
|
||||
HttpServletResponse response = (HttpServletResponse) res;
|
||||
|
||||
try {
|
||||
prepare.trackRecursion(request);
|
||||
String uri = RequestUtils.getUri(request);
|
||||
if (prepare.isUrlExcluded(request, excludedPatterns)) {
|
||||
LOG.trace("Request: {} is excluded from handling by Struts, passing request to other filters", uri);
|
||||
if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
|
||||
LOG.trace("Request {} is excluded from handling by Struts, passing request to other filters", uri);
|
||||
chain.doFilter(request, response);
|
||||
} else {
|
||||
tryHandleRequest(chain, request, response, uri);
|
||||
LOG.trace("Checking if {} is a static resource", uri);
|
||||
boolean handled = execute.executeStaticResourceRequest(request, response);
|
||||
if (!handled) {
|
||||
LOG.trace("Uri {} is not a static resource, assuming action", uri);
|
||||
prepare.setEncodingAndLocale(request, response);
|
||||
prepare.createActionContext(request, response);
|
||||
prepare.assignDispatcherToThread();
|
||||
HttpServletRequest wrappedRequest = prepare.wrapRequest(request);
|
||||
ActionMapping mapping = prepare.findActionMapping(wrappedRequest, response, true);
|
||||
if (mapping == null) {
|
||||
LOG.trace("Cannot find mapping for {}, passing to other filters", uri);
|
||||
chain.doFilter(request, response);
|
||||
} else {
|
||||
LOG.trace("Found mapping {} for {}", mapping, uri);
|
||||
execute.executeAction(wrappedRequest, response, mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
prepare.cleanupRequest(request);
|
||||
}
|
||||
}
|
||||
|
||||
private void tryHandleRequest(FilterChain chain, HttpServletRequest request, HttpServletResponse response, String uri) throws IOException, ServletException {
|
||||
LOG.trace("Checking if: {} is a static resource", uri);
|
||||
boolean handled = execute.executeStaticResourceRequest(request, response);
|
||||
if (!handled) {
|
||||
LOG.trace("Uri: {} is not a static resource, assuming action", uri);
|
||||
handleRequest(chain, request, response, uri);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRequest(FilterChain chain, HttpServletRequest request, HttpServletResponse response, String uri) throws ServletException, IOException {
|
||||
prepare.setEncodingAndLocale(request, response);
|
||||
prepare.createActionContext(request, response);
|
||||
prepare.assignDispatcherToThread();
|
||||
|
||||
HttpServletRequest wrappedRequest = prepare.wrapRequest(request);
|
||||
try {
|
||||
ActionMapping mapping = prepare.findActionMapping(wrappedRequest, response, true);
|
||||
if (mapping == null) {
|
||||
LOG.trace("Cannot find mapping for: {}, passing to other filters", uri);
|
||||
chain.doFilter(request, response);
|
||||
} else {
|
||||
LOG.trace("Found mapping: {} for: {}", mapping, uri);
|
||||
execute.executeAction(wrappedRequest, response, mapping);
|
||||
}
|
||||
} finally {
|
||||
prepare.cleanupWrappedRequest(wrappedRequest);
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
prepare.cleanupDispatcher();
|
||||
}
|
||||
|
||||
@@ -43,17 +43,16 @@ public class StrutsPrepareFilter implements StrutsStatics, Filter {
|
||||
protected static final String REQUEST_EXCLUDED_FROM_ACTION_MAPPING = StrutsPrepareFilter.class.getName() + ".REQUEST_EXCLUDED_FROM_ACTION_MAPPING";
|
||||
|
||||
protected PrepareOperations prepare;
|
||||
protected List<Pattern> excludedPatterns;
|
||||
protected List<Pattern> excludedPatterns = null;
|
||||
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
InitOperations init = createInitOperations();
|
||||
InitOperations init = new InitOperations();
|
||||
Dispatcher dispatcher = null;
|
||||
try {
|
||||
FilterHostConfig config = new FilterHostConfig(filterConfig);
|
||||
dispatcher = init.initDispatcher(config);
|
||||
|
||||
prepare = createPrepareOperations(dispatcher);
|
||||
// Note: Currently, excluded patterns are not refreshed following an XWork config reload
|
||||
prepare = new PrepareOperations(dispatcher);
|
||||
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
|
||||
|
||||
postInit(dispatcher, filterConfig);
|
||||
@@ -65,26 +64,6 @@ public class StrutsPrepareFilter implements StrutsStatics, Filter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link InitOperations} to be used during
|
||||
* initialising {@link Dispatcher}
|
||||
*
|
||||
* @return instance of {@link InitOperations}
|
||||
*/
|
||||
protected InitOperations createInitOperations() {
|
||||
return new InitOperations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link PrepareOperations} to be used during
|
||||
* initialising {@link Dispatcher}
|
||||
*
|
||||
* @return instance of {@link PrepareOperations}
|
||||
*/
|
||||
protected PrepareOperations createPrepareOperations(Dispatcher dispatcher) {
|
||||
return new PrepareOperations(dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for post initialization
|
||||
*
|
||||
@@ -99,25 +78,18 @@ public class StrutsPrepareFilter implements StrutsStatics, Filter {
|
||||
HttpServletRequest request = (HttpServletRequest) req;
|
||||
HttpServletResponse response = (HttpServletResponse) res;
|
||||
|
||||
boolean didWrap = false;
|
||||
try {
|
||||
prepare.trackRecursion(request);
|
||||
if (prepare.isUrlExcluded(request, excludedPatterns)) {
|
||||
request.setAttribute(REQUEST_EXCLUDED_FROM_ACTION_MAPPING, true);
|
||||
if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
|
||||
request.setAttribute(REQUEST_EXCLUDED_FROM_ACTION_MAPPING, new Object());
|
||||
} else {
|
||||
request.setAttribute(REQUEST_EXCLUDED_FROM_ACTION_MAPPING, false);
|
||||
prepare.setEncodingAndLocale(request, response);
|
||||
prepare.createActionContext(request, response);
|
||||
prepare.assignDispatcherToThread();
|
||||
request = prepare.wrapRequest(request);
|
||||
didWrap = true;
|
||||
prepare.findActionMapping(request, response, true);
|
||||
prepare.findActionMapping(request, response);
|
||||
}
|
||||
chain.doFilter(request, response);
|
||||
} finally {
|
||||
if (didWrap) {
|
||||
prepare.cleanupWrappedRequest(request);
|
||||
}
|
||||
prepare.cleanupRequest(request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,6 +132,7 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
protected String defaultMethodName = "execute";
|
||||
|
||||
private boolean allowActionPrefix = false;
|
||||
private boolean allowActionCrossNamespaceAccess = false;
|
||||
|
||||
protected List<String> extensions = new ArrayList<String>() {{
|
||||
add("action");
|
||||
@@ -161,12 +162,12 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
}
|
||||
}
|
||||
String actionName = cleanupActionName(name);
|
||||
if (allowSlashesInActionNames) {
|
||||
if (allowSlashesInActionNames && !allowActionCrossNamespaceAccess) {
|
||||
if (actionName.startsWith("/")) {
|
||||
actionName = actionName.substring(1);
|
||||
}
|
||||
}
|
||||
if (!allowSlashesInActionNames) {
|
||||
if (!allowSlashesInActionNames && !allowActionCrossNamespaceAccess) {
|
||||
if (actionName.lastIndexOf('/') != -1) {
|
||||
actionName = actionName.substring(actionName.lastIndexOf('/') + 1);
|
||||
}
|
||||
@@ -240,6 +241,16 @@ public class DefaultActionMapper implements ActionMapper {
|
||||
this.allowActionPrefix = BooleanUtils.toBoolean(allowActionPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 6.1.0 - please refactor your application to avoid using this functionality
|
||||
* @param allowActionCrossNamespaceAccess true to enable cross namespace action access
|
||||
*/
|
||||
@Deprecated
|
||||
@Inject(value = StrutsConstants.STRUTS_MAPPER_ACTION_PREFIX_CROSSNAMESPACES)
|
||||
public void setAllowActionCrossNamespaceAccess(String allowActionCrossNamespaceAccess) {
|
||||
this.allowActionCrossNamespaceAccess = BooleanUtils.toBoolean(allowActionCrossNamespaceAccess);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setContainer(Container container) {
|
||||
this.container = container;
|
||||
|
||||
+1
-21
@@ -58,16 +58,6 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
*/
|
||||
protected Long maxFiles;
|
||||
|
||||
/**
|
||||
* Specifies the maximum length of a string parameter in a multipart request.
|
||||
*/
|
||||
protected Long maxStringLength;
|
||||
|
||||
/**
|
||||
* Specifies the maximum size per file in the request.
|
||||
*/
|
||||
protected Long maxFileSize;
|
||||
|
||||
/**
|
||||
* Specifies the buffer size to use during streaming.
|
||||
*/
|
||||
@@ -94,7 +84,7 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxSize Injects the Struts multipart request maximum size.
|
||||
* @param maxSize Injects the Struts multiple part maximum size.
|
||||
*/
|
||||
@Inject(StrutsConstants.STRUTS_MULTIPART_MAXSIZE)
|
||||
public void setMaxSize(String maxSize) {
|
||||
@@ -106,16 +96,6 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
this.maxFiles = Long.parseLong(maxFiles);
|
||||
}
|
||||
|
||||
@Inject(value = StrutsConstants.STRUTS_MULTIPART_MAXFILESIZE, required = false)
|
||||
public void setMaxFileSize(String maxFileSize) {
|
||||
this.maxFileSize = Long.parseLong(maxFileSize);
|
||||
}
|
||||
|
||||
@Inject(StrutsConstants.STRUTS_MULTIPART_MAX_STRING_LENGTH)
|
||||
public void setMaxStringLength(String maxStringLength) {
|
||||
this.maxStringLength = Long.parseLong(maxStringLength);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setLocaleProviderFactory(LocaleProviderFactory localeProviderFactory) {
|
||||
defaultLocale = localeProviderFactory.createLocaleProvider().getLocale();
|
||||
|
||||
+3
-20
@@ -70,14 +70,11 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
setLocale(request);
|
||||
processUpload(request, saveDir);
|
||||
} catch (FileUploadException e) {
|
||||
LOG.debug("Request exceeded size limit!", e);
|
||||
LOG.warn("Request exceeded size limit!", e);
|
||||
LocalizedMessage errorMessage;
|
||||
if (e instanceof FileUploadBase.SizeLimitExceededException) {
|
||||
FileUploadBase.SizeLimitExceededException ex = (FileUploadBase.SizeLimitExceededException) e;
|
||||
errorMessage = buildErrorMessage(e, new Object[]{ex.getPermittedSize(), ex.getActualSize()});
|
||||
} else if (e instanceof FileUploadBase.FileSizeLimitExceededException) {
|
||||
FileUploadBase.FileSizeLimitExceededException ex = (FileUploadBase.FileSizeLimitExceededException) e;
|
||||
errorMessage = buildErrorMessage(e, new Object[]{ex.getFileName(), ex.getPermittedSize(), ex.getActualSize()});
|
||||
} else if (e instanceof FileCountLimitExceededException) {
|
||||
FileCountLimitExceededException ex = (FileCountLimitExceededException) e;
|
||||
errorMessage = buildErrorMessage(e, new Object[]{ex.getLimit()});
|
||||
@@ -89,7 +86,7 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
errors.add(errorMessage);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Unable to parse request", e);
|
||||
LOG.warn("Unable to parse request", e);
|
||||
LocalizedMessage errorMessage = buildErrorMessage(e, new Object[]{});
|
||||
if (!errors.contains(errorMessage)) {
|
||||
errors.add(errorMessage);
|
||||
@@ -140,19 +137,8 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
values = new ArrayList<>();
|
||||
}
|
||||
|
||||
long size = item.getSize();
|
||||
if (size == 0) {
|
||||
if (item.getSize() == 0) {
|
||||
values.add(StringUtils.EMPTY);
|
||||
} else if (size > maxStringLength) {
|
||||
String errorKey = "struts.messages.upload.error.parameter.too.long";
|
||||
LocalizedMessage localizedMessage = new LocalizedMessage(this.getClass(), errorKey, null,
|
||||
new Object[] { item.getFieldName(), maxStringLength, size });
|
||||
|
||||
if (!errors.contains(localizedMessage)) {
|
||||
errors.add(localizedMessage);
|
||||
}
|
||||
return;
|
||||
|
||||
} else if (charset != null) {
|
||||
values.add(item.getString(charset));
|
||||
} else {
|
||||
@@ -180,9 +166,6 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
if (maxFiles != null) {
|
||||
upload.setFileCountMax(maxFiles);
|
||||
}
|
||||
if (maxFileSize != null) {
|
||||
upload.setFileSizeMax(maxFileSize);
|
||||
}
|
||||
return upload;
|
||||
}
|
||||
|
||||
|
||||
+13
-20
@@ -29,20 +29,9 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.dispatcher.LocalizedMessage;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Multi-part form data request adapter for Jakarta Commons FileUpload package that
|
||||
@@ -194,7 +183,7 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
setLocale(request);
|
||||
processUpload(request, saveDir);
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Error occurred during parsing of multi part request", e);
|
||||
LOG.warn("Error occurred during parsing of multi part request", e);
|
||||
LocalizedMessage errorMessage = buildErrorMessage(e, new Object[]{});
|
||||
if (!errors.contains(errorMessage)) {
|
||||
errors.add(errorMessage);
|
||||
@@ -226,9 +215,6 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
if (maxFiles != null) {
|
||||
servletFileUpload.setFileCountMax(maxFiles);
|
||||
}
|
||||
if (maxFileSize != null) {
|
||||
servletFileUpload.setFileSizeMax(maxFileSize);
|
||||
}
|
||||
FileItemIterator i = servletFileUpload.getItemIterator(request);
|
||||
|
||||
// Iterate the file items
|
||||
@@ -249,9 +235,10 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
else {
|
||||
|
||||
// prevent processing file field item if request size not allowed.
|
||||
// also warn user in the logs.
|
||||
if (!requestSizePermitted) {
|
||||
addFileSkippedError(itemStream.getName(), request);
|
||||
LOG.debug("Skipped stream '{}', request maximum size ({}) exceeded.", itemStream.getName(), maxSize);
|
||||
LOG.warn("Skipped stream '{}', request maximum size ({}) exceeded.", itemStream.getName(), maxSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -274,9 +261,10 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
// if maxSize is specified as -1, there is no sanity check and it's
|
||||
// safe to return true for any request, delegating the failure
|
||||
// checks later in the upload process.
|
||||
if (maxSize == null || maxSize == -1 || request == null) {
|
||||
if ((maxSize != null && maxSize == -1) || request == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return request.getContentLength() < maxSize;
|
||||
}
|
||||
|
||||
@@ -285,7 +273,12 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
* @return the request content length.
|
||||
*/
|
||||
protected long getRequestSize(HttpServletRequest request) {
|
||||
return request != null ? request.getContentLength() : 0;
|
||||
long requestSize = 0;
|
||||
if (request != null) {
|
||||
requestSize = request.getContentLength();
|
||||
}
|
||||
|
||||
return requestSize;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,10 +19,11 @@
|
||||
package org.apache.struts2.dispatcher.servlet;
|
||||
|
||||
import org.apache.struts2.dispatcher.Dispatcher;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
import org.apache.struts2.dispatcher.ExecuteOperations;
|
||||
import org.apache.struts2.dispatcher.InitOperations;
|
||||
import org.apache.struts2.dispatcher.PrepareOperations;
|
||||
import org.apache.struts2.dispatcher.mapper.ActionMapping;
|
||||
import org.apache.struts2.dispatcher.servlet.ServletHostConfig;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
+2
-2
@@ -75,7 +75,7 @@ public class ActionMappingParametersInterceptor extends ParametersInterceptor {
|
||||
|
||||
/**
|
||||
* Get the parameter map from ActionMapping associated with the provided ActionContext.
|
||||
*
|
||||
*
|
||||
* @param ac The action context
|
||||
* @return the parameters from the action mapping in the context. If none found, returns an empty map.
|
||||
*/
|
||||
@@ -102,6 +102,6 @@ public class ActionMappingParametersInterceptor extends ParametersInterceptor {
|
||||
HttpParameters previousParams = ac.getParameters();
|
||||
HttpParameters.Builder combinedParams = HttpParameters.create().withParent(previousParams).withExtraParams(newParams);
|
||||
|
||||
ac.withParameters(combinedParams.buildNoNestedWrapping());
|
||||
ac.setParameters(combinedParams.buildNoNestedWrapping());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Actions that want to be aware of the application Map object should implement this interface.
|
||||
* This will give them access to a Map where they can put objects that should be available
|
||||
* to other parts of the application.
|
||||
* </p>
|
||||
* <p>
|
||||
* Typical uses are configuration objects and caches.
|
||||
* </p>
|
||||
* @deprecated please use {@link org.apache.struts2.action.ApplicationAware} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ApplicationAware {
|
||||
|
||||
/**
|
||||
* Sets the map of application properties in the implementing class.
|
||||
*
|
||||
* @param application a Map of application properties.
|
||||
* @deprecated please use {@link org.apache.struts2.action.ApplicationAware#withApplication(Map)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setApplication(Map<String,Object> application);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user