mirror of
https://github.com/apache/struts.git
synced 2026-08-08 16:16:58 +00:00
Compare commits
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f0f4e9ece7 | |||
| 45580718ab | |||
| 87f113ebb2 | |||
| 0023d9664b | |||
| ee27b6604a | |||
| 7f80ef1bb5 | |||
| 253799c6c5 | |||
| 20c54df03a | |||
| ff8d731594 | |||
| 880c4c2d33 | |||
| d12bb7cddb | |||
| f48c9620fc | |||
| fc6ffba9cf | |||
| 08e181a4fe | |||
| a7f4e255b0 | |||
| 2b12f06b01 | |||
| b9c05a7181 | |||
| 14d56fbb93 | |||
| 97419283ea | |||
| 55fed53764 | |||
| 98979423a1 | |||
| 3144b6c995 | |||
| 3ce21403ee | |||
| e38a71365a | |||
| f78d90ee22 | |||
| 7e4d1b45ea | |||
| 4727265e59 | |||
| 4281e31864 | |||
| baffa9a68b | |||
| 484ce1d191 | |||
| 5054ff469a | |||
| 0f69b0c3fb | |||
| 09958919ca | |||
| aabc90df6b | |||
| f515def5b8 | |||
| fddc6582e0 | |||
| 8971b50810 | |||
| 6457f002d9 | |||
| 6e1ea61dc6 | |||
| bcea4c9baf | |||
| a1b89842c0 | |||
| 03766980d1 | |||
| 1bf7de8d37 | |||
| ad3a697d93 | |||
| 31a0768da3 | |||
| 0014f8935a | |||
| 99bb671437 | |||
| 9cde17b223 | |||
| 6651089e82 | |||
| 8bb225c04c | |||
| 32341681ed | |||
| 1ff8a88a9d | |||
| ae5605ff88 | |||
| 6d623ebb56 | |||
| 7872fa80f9 | |||
| f03279fc1a | |||
| 4de8309d0a | |||
| de51e79718 | |||
| 6280feb426 | |||
| e152c15f78 | |||
| 3fd909668a | |||
| e86793482a | |||
| ec5fba7af9 | |||
| dca41a39bf | |||
| 407cd58279 | |||
| 45edbcbe45 | |||
| fe05ca2095 | |||
| 6f7fcaa338 | |||
| 321d9da095 | |||
| bd99677b19 | |||
| 8759bbc68a | |||
| 931df54ab3 | |||
| eb71d88696 | |||
| 554b9dddb0 | |||
| a245226b7f | |||
| ef2939ffd0 | |||
| 8aba301da0 | |||
| e1e2ea84a7 | |||
| 986b43f314 | |||
| a5092a24f2 | |||
| a5817fecb3 | |||
| 366366cdd8 | |||
| 4e7a4b18c0 | |||
| 996475d755 | |||
| ab6750211b | |||
| 70400f4a03 | |||
| b5240560ab | |||
| b287a9546a | |||
| 33ac7ac49a | |||
| 8fe2bb8317 | |||
| 8699f639f3 | |||
| 24a97d33e6 | |||
| 835cc7cd09 | |||
| 1af1887037 | |||
| 8135abeca7 | |||
| 91d6691b0d |
+1
-1
@@ -26,7 +26,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>2.5.5</version>
|
||||
<version>2.5.10</version>
|
||||
</parent>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>2.5.5</version>
|
||||
<version>2.5.10</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-rest-showcase</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<version>2.5.5</version>
|
||||
<version>2.5.10</version>
|
||||
<name>Struts 2 Rest Showcase Webapp</name>
|
||||
<description>Struts 2 Rest Showcase Example</description>
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-apps</artifactId>
|
||||
<version>2.5.5</version>
|
||||
<version>2.5.10</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-showcase</artifactId>
|
||||
|
||||
+2
-8
@@ -24,23 +24,17 @@ package org.apache.struts2.showcase.chat;
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.struts2.dispatcher.SessionMap;
|
||||
|
||||
public class ChatAuthenticationInterceptor implements Interceptor {
|
||||
public class ChatAuthenticationInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOG = LogManager.getLogger(ChatAuthenticationInterceptor.class);
|
||||
public static final String USER_SESSION_KEY = "chatUserSessionKey";
|
||||
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
public void init() {
|
||||
}
|
||||
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
|
||||
LOG.debug("Authenticating chat user");
|
||||
|
||||
@@ -23,7 +23,7 @@ package org.apache.struts2.showcase.chat;
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
@@ -32,7 +32,7 @@ import javax.servlet.http.HttpSession;
|
||||
/**
|
||||
* Authenticate showcase chat example, make sure everyone have a username.
|
||||
*/
|
||||
public class ChatInterceptor implements Interceptor {
|
||||
public class ChatInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ChatInterceptor.class);
|
||||
|
||||
@@ -40,12 +40,6 @@ public class ChatInterceptor implements Interceptor {
|
||||
|
||||
public static final String CHAT_USER_SESSION_KEY = "ChatUserSessionKey";
|
||||
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
public void init() {
|
||||
}
|
||||
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
HttpSession session = (HttpSession) ActionContext.getContext().get(ActionContext.SESSION);
|
||||
User chatUser = (User) session.getAttribute(CHAT_USER_SESSION_KEY);
|
||||
|
||||
+3
-3
@@ -34,9 +34,9 @@ import java.util.List;
|
||||
*/
|
||||
public class MultipleFileUploadUsingListAction extends ActionSupport {
|
||||
|
||||
private List<File> uploads = new ArrayList<File>();
|
||||
private List<String> uploadFileNames = new ArrayList<String>();
|
||||
private List<String> uploadContentTypes = new ArrayList<String>();
|
||||
private List<File> uploads = new ArrayList<>();
|
||||
private List<String> uploadFileNames = new ArrayList<>();
|
||||
private List<String> uploadContentTypes = new ArrayList<>();
|
||||
|
||||
|
||||
public List<File> getUpload() {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>2.5.5</version>
|
||||
<version>2.5.10</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-assembly</artifactId>
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
</formats>
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<useProjectArtifact>false</useProjectArtifact>
|
||||
<outputDirectory>lib</outputDirectory>
|
||||
<scope>runtime</scope>
|
||||
<excludes>
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
</formats>
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<useProjectArtifact>false</useProjectArtifact>
|
||||
<outputDirectory>lib</outputDirectory>
|
||||
<scope>runtime</scope>
|
||||
<excludes>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
</formats>
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<useProjectArtifact>true</useProjectArtifact>
|
||||
<useProjectArtifact>false</useProjectArtifact>
|
||||
<useTransitiveDependencies>true</useTransitiveDependencies>
|
||||
<outputDirectory>lib</outputDirectory>
|
||||
<includes>
|
||||
@@ -40,9 +40,6 @@
|
||||
<include>org.apache.commons:commons-lang3</include>
|
||||
<include>org.apache.logging.log4j:log4j-api</include>
|
||||
<include>ognl:ognl</include>
|
||||
<include>org.ow2.asm:asm</include>
|
||||
<include>org.ow2.asm:asm-tree</include>
|
||||
<include>org.ow2.asm:asm-commons</include>
|
||||
<include>org.javassist:javassist</include>
|
||||
<include>commons-fileupload:commons-fileupload</include>
|
||||
<include>commons-io:commons-io</include>
|
||||
|
||||
+3
-3
@@ -10,7 +10,7 @@
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-bom</artifactId>
|
||||
<version>2.5.5</version>
|
||||
<version>2.5.10</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Struts 2 Bill of Materials</name>
|
||||
@@ -25,7 +25,7 @@
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<struts-version.version>2.5.5</struts-version.version>
|
||||
<struts-version.version>2.5.10</struts-version.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
@@ -172,6 +172,6 @@
|
||||
</dependencyManagement>
|
||||
|
||||
<scm>
|
||||
<tag>STRUTS_2_5_5</tag>
|
||||
<tag>STRUTS_2_5_10</tag>
|
||||
</scm>
|
||||
</project>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>2.5.5</version>
|
||||
<version>2.5.10</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-admin-bundle</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
<version>2.5.5</version>
|
||||
<version>2.5.10</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-demo-bundle</artifactId>
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>2.5.5</version>
|
||||
<version>2.5.10</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>struts2-osgi-bundles</artifactId>
|
||||
|
||||
+7
-10
@@ -26,7 +26,7 @@
|
||||
<parent>
|
||||
<groupId>org.apache.struts</groupId>
|
||||
<artifactId>struts2-parent</artifactId>
|
||||
<version>2.5.5</version>
|
||||
<version>2.5.10</version>
|
||||
</parent>
|
||||
<artifactId>struts2-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
@@ -266,14 +266,6 @@
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
@@ -409,7 +401,6 @@
|
||||
<artifactId>testng</artifactId>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
<classifier>jdk15</classifier>
|
||||
</dependency>
|
||||
|
||||
<!-- SLF4J support -->
|
||||
@@ -433,5 +424,11 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-validator</groupId>
|
||||
<artifactId>commons-validator</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -19,25 +19,21 @@ import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* Provides a default implementation for the most common actions.
|
||||
* See the documentation for all the interfaces this class implements for more detailed information.
|
||||
*/
|
||||
public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable {
|
||||
|
||||
protected static Logger LOG = LogManager.getLogger(ActionSupport.class);
|
||||
|
||||
private final ValidationAwareSupport validationAware = new ValidationAwareSupport();
|
||||
|
||||
private transient TextProvider textProvider;
|
||||
private Container container;
|
||||
|
||||
protected Container container;
|
||||
|
||||
public void setActionErrors(Collection<String> errorMessages) {
|
||||
validationAware.setActionErrors(errorMessages);
|
||||
|
||||
@@ -21,7 +21,9 @@ import com.opensymphony.xwork2.config.entities.InterceptorMapping;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import com.opensymphony.xwork2.interceptor.PreResultListener;
|
||||
import com.opensymphony.xwork2.interceptor.WithLazyParams;
|
||||
import com.opensymphony.xwork2.ognl.OgnlUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
@@ -67,6 +69,7 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
protected Container container;
|
||||
protected UnknownHandlerManager unknownHandlerManager;
|
||||
protected OgnlUtil ognlUtil;
|
||||
protected WithLazyParams.LazyParamInjector lazyParamInjector;
|
||||
|
||||
public DefaultActionInvocation(final Map<String, Object> extraContext, final boolean pushAction) {
|
||||
this.extraContext = extraContext;
|
||||
@@ -233,11 +236,15 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
}
|
||||
|
||||
if (interceptors.hasNext()) {
|
||||
final InterceptorMapping interceptor = interceptors.next();
|
||||
String interceptorMsg = "interceptor: " + interceptor.getName();
|
||||
final InterceptorMapping interceptorMapping = interceptors.next();
|
||||
String interceptorMsg = "interceptorMapping: " + interceptorMapping.getName();
|
||||
UtilTimerStack.push(interceptorMsg);
|
||||
try {
|
||||
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
|
||||
Interceptor interceptor = interceptorMapping.getInterceptor();
|
||||
if (interceptor instanceof WithLazyParams) {
|
||||
interceptor = lazyParamInjector.injectParams(interceptor, interceptorMapping.getParams(), invocationContext);
|
||||
}
|
||||
resultCode = interceptor.intercept(DefaultActionInvocation.this);
|
||||
} finally {
|
||||
UtilTimerStack.pop(interceptorMsg);
|
||||
}
|
||||
@@ -400,6 +407,13 @@ public class DefaultActionInvocation implements ActionInvocation {
|
||||
invocationContext.setName(proxy.getActionName());
|
||||
|
||||
createInterceptors(proxy);
|
||||
|
||||
prepareLazyParamInjector(invocationContext.getValueStack());
|
||||
}
|
||||
|
||||
protected void prepareLazyParamInjector(ValueStack valueStack) {
|
||||
lazyParamInjector = new WithLazyParams.LazyParamInjector(valueStack);
|
||||
container.inject(lazyParamInjector);
|
||||
}
|
||||
|
||||
protected void createInterceptors(ActionProxy proxy) {
|
||||
|
||||
@@ -19,6 +19,8 @@ package com.opensymphony.xwork2.config.entities;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <code>InterceptorMapping</code>
|
||||
@@ -30,10 +32,16 @@ public class InterceptorMapping implements Serializable {
|
||||
|
||||
private String name;
|
||||
private Interceptor interceptor;
|
||||
private final Map<String, String> params;
|
||||
|
||||
public InterceptorMapping(String name, Interceptor interceptor) {
|
||||
this(name, interceptor, new HashMap<String, String>());
|
||||
}
|
||||
|
||||
public InterceptorMapping(String name, Interceptor interceptor, Map<String, String> params) {
|
||||
this.name = name;
|
||||
this.interceptor = interceptor;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -44,6 +52,10 @@ public class InterceptorMapping implements Serializable {
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
public Map<String, String> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -65,7 +77,7 @@ public class InterceptorMapping implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InterceptorMapping: [" + name + "] => [" + interceptor.getClass().getName() + ']';
|
||||
return "InterceptorMapping: [" + name + "] => [" + interceptor.getClass().getName() + "] with params [" + params + "]" ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ package com.opensymphony.xwork2.config.impl;
|
||||
import com.opensymphony.xwork2.*;
|
||||
import com.opensymphony.xwork2.config.*;
|
||||
import com.opensymphony.xwork2.config.entities.*;
|
||||
import com.opensymphony.xwork2.config.providers.EnvsValueSubstitutor;
|
||||
import com.opensymphony.xwork2.config.providers.InterceptorBuilder;
|
||||
import com.opensymphony.xwork2.config.providers.ValueSubstitutor;
|
||||
import com.opensymphony.xwork2.conversion.*;
|
||||
import com.opensymphony.xwork2.conversion.impl.*;
|
||||
import com.opensymphony.xwork2.factory.*;
|
||||
@@ -265,6 +267,8 @@ public class DefaultConfiguration implements Configuration {
|
||||
builder.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON);
|
||||
builder.factory(OgnlUtil.class, Scope.SINGLETON);
|
||||
|
||||
builder.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON);
|
||||
|
||||
builder.constant(XWorkConstants.DEV_MODE, "false");
|
||||
builder.constant(XWorkConstants.LOG_MISSING_PROPERTIES, "false");
|
||||
builder.constant(XWorkConstants.ENABLE_OGNL_EVAL_EXPRESSION, "false");
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2002-2006,2009 The Apache Software Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.opensymphony.xwork2.config.providers;
|
||||
|
||||
import org.apache.commons.lang3.text.StrSubstitutor;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class EnvsValueSubstitutor implements ValueSubstitutor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(EnvsValueSubstitutor.class);
|
||||
|
||||
protected StrSubstitutor strSubstitutor;
|
||||
|
||||
public EnvsValueSubstitutor() {
|
||||
strSubstitutor = new StrSubstitutor(System.getenv());
|
||||
strSubstitutor.setVariablePrefix("${env.");
|
||||
strSubstitutor.setVariableSuffix('}');
|
||||
strSubstitutor.setValueDelimiter(":");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String substitute(String value) {
|
||||
LOG.debug("Substituting value {} with proper System variable or environment variable", value);
|
||||
|
||||
String substituted = StrSubstitutor.replaceSystemProperties(value);
|
||||
return strSubstitutor.replace(substituted);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import com.opensymphony.xwork2.util.location.Location;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -43,7 +44,6 @@ public class InterceptorBuilder {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(InterceptorBuilder.class);
|
||||
|
||||
|
||||
/**
|
||||
* Builds a list of interceptors referenced by the refName in the supplied PackageConfig (InterceptorMapping object).
|
||||
*
|
||||
@@ -67,13 +67,11 @@ public class InterceptorBuilder {
|
||||
InterceptorConfig config = (InterceptorConfig) referencedConfig;
|
||||
Interceptor inter;
|
||||
try {
|
||||
|
||||
inter = objectFactory.buildInterceptor(config, refParams);
|
||||
result.add(new InterceptorMapping(refName, inter));
|
||||
result.add(new InterceptorMapping(refName, inter, refParams));
|
||||
} catch (ConfigurationException ex) {
|
||||
LOG.warn("Unable to load config class {} at {} probably due to a missing jar, which might be fine if you never plan to use the {} interceptor",
|
||||
config.getClassName(), ex.getLocation(), config.getName());
|
||||
LOG.error("Unable to load config class {}", config.getClassName(), ex);
|
||||
LOG.warn(new ParameterizedMessage("Unable to load config class {} at {} probably due to a missing jar, which might be fine if you never plan to use the {} interceptor",
|
||||
config.getClassName(), ex.getLocation(), config.getName()), ex);
|
||||
}
|
||||
|
||||
} else if (referencedConfig instanceof InterceptorStackConfig) {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2002-2006,2009 The Apache Software Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.opensymphony.xwork2.config.providers;
|
||||
|
||||
/**
|
||||
* @since Apache Struts 2.5.6
|
||||
*/
|
||||
public interface ValueSubstitutor {
|
||||
|
||||
String substitute(String value);
|
||||
|
||||
}
|
||||
+11
@@ -4,6 +4,8 @@ import com.opensymphony.xwork2.ActionProxyFactory;
|
||||
import com.opensymphony.xwork2.DefaultActionProxyFactory;
|
||||
import com.opensymphony.xwork2.factory.DefaultUnknownHandlerFactory;
|
||||
import com.opensymphony.xwork2.factory.UnknownHandlerFactory;
|
||||
import com.opensymphony.xwork2.ognl.accessor.HttpParametersPropertyAccessor;
|
||||
import com.opensymphony.xwork2.ognl.accessor.ParameterPropertyAccessor;
|
||||
import com.opensymphony.xwork2.security.AcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker;
|
||||
import com.opensymphony.xwork2.security.DefaultExcludedPatternsChecker;
|
||||
@@ -88,6 +90,8 @@ import com.opensymphony.xwork2.validator.ValidatorFileParser;
|
||||
import ognl.MethodAccessor;
|
||||
import ognl.PropertyAccessor;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -145,10 +149,12 @@ public class XWorkConfigurationProvider implements ConfigurationProvider {
|
||||
.factory(PatternMatcher.class, WildcardHelper.class, Scope.SINGLETON)
|
||||
.factory(ReflectionProvider.class, OgnlReflectionProvider.class, Scope.SINGLETON)
|
||||
.factory(ReflectionContextFactory.class, OgnlReflectionContextFactory.class, Scope.SINGLETON)
|
||||
|
||||
.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Object.class.getName(), ObjectAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Iterator.class.getName(), XWorkIteratorPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Enumeration.class.getName(), XWorkEnumerationAccessor.class, Scope.SINGLETON)
|
||||
|
||||
.factory(UnknownHandlerManager.class, DefaultUnknownHandlerManager.class, Scope.SINGLETON)
|
||||
|
||||
// silly workarounds for ognl since there is no way to flush its caches
|
||||
@@ -160,6 +166,9 @@ public class XWorkConfigurationProvider implements ConfigurationProvider {
|
||||
.factory(PropertyAccessor.class, Map.class.getName(), XWorkMapPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Collection.class.getName(), XWorkCollectionPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, ObjectProxy.class.getName(), ObjectProxyPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, HttpParameters.class.getName(), HttpParametersPropertyAccessor.class, Scope.SINGLETON)
|
||||
.factory(PropertyAccessor.class, Parameter.class.getName(), ParameterPropertyAccessor.class, Scope.SINGLETON)
|
||||
|
||||
.factory(MethodAccessor.class, Object.class.getName(), XWorkMethodAccessor.class, Scope.SINGLETON)
|
||||
.factory(MethodAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON)
|
||||
|
||||
@@ -180,6 +189,8 @@ public class XWorkConfigurationProvider implements ConfigurationProvider {
|
||||
|
||||
.factory(ExcludedPatternsChecker.class, DefaultExcludedPatternsChecker.class, Scope.PROTOTYPE)
|
||||
.factory(AcceptedPatternsChecker.class, DefaultAcceptedPatternsChecker.class, Scope.PROTOTYPE)
|
||||
|
||||
.factory(ValueSubstitutor.class, EnvsValueSubstitutor.class, Scope.SINGLETON)
|
||||
;
|
||||
|
||||
props.setProperty(StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION, Boolean.FALSE.toString());
|
||||
|
||||
+14
-2
@@ -98,6 +98,7 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
|
||||
private Map<String, Element> declaredPackages = new HashMap<>();
|
||||
|
||||
private FileManager fileManager;
|
||||
private ValueSubstitutor valueSubstitutor;
|
||||
|
||||
public XmlConfigurationProvider() {
|
||||
this("xwork.xml", true);
|
||||
@@ -141,6 +142,11 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
|
||||
this.fileManager = fileManagerFactory.getFileManager();
|
||||
}
|
||||
|
||||
@Inject(required = false)
|
||||
public void setValueSubstitutor(ValueSubstitutor valueSubstitutor) {
|
||||
this.valueSubstitutor = valueSubstitutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable map of DTD mappings
|
||||
*
|
||||
@@ -270,6 +276,12 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
|
||||
} else if ("constant".equals(nodeName)) {
|
||||
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, childNode);
|
||||
} else if (nodeName.equals("unknown-handler-stack")) {
|
||||
List<UnknownHandlerConfig> unknownHandlerStack = new ArrayList<UnknownHandlerConfig>();
|
||||
@@ -745,7 +757,7 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
|
||||
{
|
||||
// if <result ...>something</result> then we add a parameter of 'something' as this is the most used result param
|
||||
if (resultElement.getChildNodes().getLength() >= 1) {
|
||||
resultParams = new LinkedHashMap<String, String>();
|
||||
resultParams = new LinkedHashMap<>();
|
||||
|
||||
String paramName = config.getDefaultResultParam();
|
||||
if (paramName != null) {
|
||||
@@ -763,7 +775,7 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
|
||||
resultParams.put(paramName, val);
|
||||
}
|
||||
} else {
|
||||
LOG.warn("No default parameter defined for result [{}] of type [{}] ", config.getName(), config.getClassName());
|
||||
LOG.debug("No default parameter defined for result [{}] of type [{}] ", config.getName(), config.getClassName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,10 @@ import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorConfig;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import com.opensymphony.xwork2.interceptor.WithLazyParams;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -15,6 +18,8 @@ import java.util.Map;
|
||||
*/
|
||||
public class DefaultInterceptorFactory implements InterceptorFactory {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(DefaultInterceptorFactory.class);
|
||||
|
||||
private ObjectFactory objectFactory;
|
||||
private ReflectionProvider reflectionProvider;
|
||||
|
||||
@@ -40,7 +45,12 @@ public class DefaultInterceptorFactory implements InterceptorFactory {
|
||||
try {
|
||||
// interceptor instances are long-lived and used across user sessions, so don't try to pass in any extra context
|
||||
Object o = objectFactory.buildBean(interceptorClassName, null);
|
||||
reflectionProvider.setProperties(params, o);
|
||||
if (o instanceof WithLazyParams) {
|
||||
LOG.debug("Interceptor {} is marked with interface {} and params will be set during action invocation",
|
||||
interceptorClassName, WithLazyParams.class.getName());
|
||||
} else {
|
||||
reflectionProvider.setProperties(params, o);
|
||||
}
|
||||
|
||||
if (o instanceof Interceptor) {
|
||||
Interceptor interceptor = (Interceptor) o;
|
||||
|
||||
+1
-1
@@ -153,7 +153,7 @@ import java.util.Map;
|
||||
*/
|
||||
public class ExceptionMappingInterceptor extends AbstractInterceptor {
|
||||
|
||||
protected static final Logger LOG = LogManager.getLogger(ExceptionMappingInterceptor.class);
|
||||
private static final Logger LOG = LogManager.getLogger(ExceptionMappingInterceptor.class);
|
||||
|
||||
protected Logger categoryLogger;
|
||||
protected boolean logEnabled = false;
|
||||
|
||||
@@ -70,7 +70,8 @@ import java.util.Set;
|
||||
* @see com.opensymphony.xwork2.validator.ValidationInterceptor
|
||||
*/
|
||||
public abstract class MethodFilterInterceptor extends AbstractInterceptor {
|
||||
protected transient Logger log = LogManager.getLogger(getClass());
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(MethodFilterInterceptor.class);
|
||||
|
||||
protected Set<String> excludeMethods = Collections.emptySet();
|
||||
protected Set<String> includeMethods = Collections.emptySet();
|
||||
@@ -104,7 +105,7 @@ public abstract class MethodFilterInterceptor extends AbstractInterceptor {
|
||||
// ValidationInterceptor
|
||||
boolean applyMethod = MethodFilterInterceptorUtil.applyMethod(excludeMethods, includeMethods, method);
|
||||
if (!applyMethod) {
|
||||
log.debug("Skipping Interceptor... Method [{}] found in exclude list.", method);
|
||||
LOG.debug("Skipping Interceptor... Method [{}] found in exclude list.", method);
|
||||
}
|
||||
return applyMethod;
|
||||
}
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ public class ParameterFilterInterceptor extends AbstractInterceptor {
|
||||
|
||||
Map<String, Boolean> includesExcludesMap = getIncludesExcludesMap();
|
||||
|
||||
for (String param : parameters.getNames()) {
|
||||
for (String param : parameters.keySet()) {
|
||||
boolean currentAllowed = !isDefaultBlock();
|
||||
|
||||
for (String currRule : includesExcludesMap.keySet()) {
|
||||
|
||||
@@ -168,7 +168,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
acceptableParameters = new TreeMap<>();
|
||||
}
|
||||
|
||||
for (String name : params.getNames()) {
|
||||
for (String name : params.keySet()) {
|
||||
Parameter parameter = params.get(name);
|
||||
if (isAcceptableParameter(name, action)) {
|
||||
acceptableParameters.put(name, parameter);
|
||||
@@ -203,13 +203,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
String name = entry.getKey();
|
||||
Parameter value = entry.getValue();
|
||||
try {
|
||||
if (value instanceof Parameter.File) {
|
||||
newStack.setParameter(name, value.getObject());
|
||||
} else if (value.isMultiple()) {
|
||||
newStack.setParameter(name, value.getMultipleValues());
|
||||
} else {
|
||||
newStack.setParameter(name, value.getValue());
|
||||
}
|
||||
newStack.setParameter(name, value.getObject());
|
||||
} catch (RuntimeException e) {
|
||||
if (devMode) {
|
||||
notifyDeveloperParameterException(action, name, e.getMessage());
|
||||
@@ -268,7 +262,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
}
|
||||
|
||||
StringBuilder logEntry = new StringBuilder();
|
||||
for (String name : parameters.getNames()) {
|
||||
for (String name : parameters.keySet()) {
|
||||
logEntry.append(String.valueOf(name));
|
||||
logEntry.append(" => ");
|
||||
logEntry.append(parameters.get(name).getValue());
|
||||
@@ -288,7 +282,7 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
protected boolean isWithinLengthLimit( String name ) {
|
||||
boolean matchLength = name.length() <= paramNameMaxLength;
|
||||
if (!matchLength) {
|
||||
notifyDeveloper("Parameter [{}] is too long, allowed length is [{}]", name, String.valueOf(paramNameMaxLength));
|
||||
LOG.debug("Parameter [{}] is too long, allowed length is [{}]", name, String.valueOf(paramNameMaxLength));
|
||||
}
|
||||
return matchLength;
|
||||
}
|
||||
@@ -298,27 +292,19 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
|
||||
if (result.isAccepted()) {
|
||||
return true;
|
||||
}
|
||||
notifyDeveloper("Parameter [{}] didn't match accepted pattern [{}]!", paramName, result.getAcceptedPattern());
|
||||
LOG.debug("Parameter [{}] didn't match accepted pattern [{}]!", paramName, result.getAcceptedPattern());
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isExcluded(String paramName) {
|
||||
ExcludedPatternsChecker.IsExcluded result = excludedPatterns.isExcluded(paramName);
|
||||
if (result.isExcluded()) {
|
||||
notifyDeveloper("Parameter [{}] matches excluded pattern [{}]!", paramName, result.getExcludedPattern());
|
||||
LOG.debug("Parameter [{}] matches excluded pattern [{}]!", paramName, result.getExcludedPattern());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void notifyDeveloper(String message, String... parameters) {
|
||||
if (devMode) {
|
||||
LOG.warn(message, parameters);
|
||||
} else {
|
||||
LOG.debug(message, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to order the parameters or not
|
||||
*
|
||||
|
||||
@@ -93,7 +93,8 @@ import org.apache.logging.log4j.Logger;
|
||||
* @author Claus Ibsen
|
||||
*/
|
||||
public class TimerInterceptor extends AbstractInterceptor {
|
||||
protected static final Logger LOG = LogManager.getLogger(TimerInterceptor.class);
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(TimerInterceptor.class);
|
||||
|
||||
protected Logger categoryLogger;
|
||||
protected String logCategory;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.opensymphony.xwork2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.ognl.OgnlUtil;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.TextParser;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interceptors marked with this interface won't be fully initialised during initialisation.
|
||||
* Appropriated params will be injected just before usage of the interceptor.
|
||||
*
|
||||
* Please be aware that in such case {@link Interceptor#init()} method must be prepared for this.
|
||||
*
|
||||
* @since 2.5.9
|
||||
*/
|
||||
public interface WithLazyParams {
|
||||
|
||||
class LazyParamInjector {
|
||||
|
||||
protected OgnlUtil ognlUtil;
|
||||
protected TextParser textParser;
|
||||
protected ReflectionProvider reflectionProvider;
|
||||
|
||||
private final TextParseUtil.ParsedValueEvaluator valueEvaluator;
|
||||
|
||||
public LazyParamInjector(final ValueStack valueStack) {
|
||||
valueEvaluator = new TextParseUtil.ParsedValueEvaluator() {
|
||||
public Object evaluate(String parsedValue) {
|
||||
return valueStack.findValue(parsedValue); // no asType !!!
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setTextParser(TextParser textParser) {
|
||||
this.textParser = textParser;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setReflectionProvider(ReflectionProvider reflectionProvider) {
|
||||
this.reflectionProvider = reflectionProvider;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setOgnlUtil(OgnlUtil ognlUtil) {
|
||||
this.ognlUtil = ognlUtil;
|
||||
}
|
||||
|
||||
public Interceptor injectParams(Interceptor interceptor, Map<String, String> params, ActionContext invocationContext) {
|
||||
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||
Object paramValue = textParser.evaluate(new char[]{ '$' }, entry.getValue(), valueEvaluator, TextParser.DEFAULT_LOOP_COUNT);
|
||||
ognlUtil.setProperty(entry.getKey(), paramValue, interceptor, invocationContext.getContextMap());
|
||||
}
|
||||
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -54,7 +54,7 @@ public class AnnotationParameterFilterInterceptor extends AbstractInterceptor {
|
||||
AnnotationUtils.addAllFields(Allowed.class, model.getClass(), annotatedFields);
|
||||
}
|
||||
|
||||
for (String paramName : parameters.getNames()) {
|
||||
for (String paramName : parameters.keySet()) {
|
||||
boolean allowed = false;
|
||||
|
||||
for (Field field : annotatedFields) {
|
||||
@@ -76,7 +76,7 @@ public class AnnotationParameterFilterInterceptor extends AbstractInterceptor {
|
||||
AnnotationUtils.addAllFields(Blocked.class, model.getClass(), annotatedFields);
|
||||
}
|
||||
|
||||
for (String paramName : parameters.getNames()) {
|
||||
for (String paramName : parameters.keySet()) {
|
||||
for (Field field : annotatedFields) {
|
||||
//TODO only matches exact field names. need to change to it matches start of ognl expression
|
||||
//i.e take param name up to first . (period) and match against that
|
||||
|
||||
@@ -16,16 +16,15 @@
|
||||
package com.opensymphony.xwork2.mock;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import junit.framework.Assert;
|
||||
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
* Mock for an {@link com.opensymphony.xwork2.interceptor.Interceptor}.
|
||||
*
|
||||
* @author Jason Carreira
|
||||
*/
|
||||
public class MockInterceptor implements Interceptor {
|
||||
public class MockInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final long serialVersionUID = 2692551676567227756L;
|
||||
|
||||
@@ -57,12 +56,6 @@ public class MockInterceptor implements Interceptor {
|
||||
return foo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to let an interceptor clean up any resources it has allocated.
|
||||
*/
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
@@ -101,13 +94,6 @@ public class MockInterceptor implements Interceptor {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after an Interceptor is created, but before any requests are processed using the intercept() methodName. This
|
||||
* gives the Interceptor a chance to initialize any needed resources.
|
||||
*/
|
||||
public void init() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the
|
||||
* request by the DefaultActionInvocation or to short-circuit the processing and just return a String return code.
|
||||
|
||||
@@ -52,19 +52,20 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
|
||||
public static final String THROW_EXCEPTION_ON_FAILURE = OgnlValueStack.class.getName() + ".throwExceptionOnFailure";
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(OgnlValueStack.class);
|
||||
|
||||
private static final long serialVersionUID = 370737852934925530L;
|
||||
|
||||
private static final String MAP_IDENTIFIER_KEY = "com.opensymphony.xwork2.util.OgnlValueStack.MAP_IDENTIFIER_KEY";
|
||||
private static final Logger LOG = LogManager.getLogger(OgnlValueStack.class);
|
||||
|
||||
CompoundRoot root;
|
||||
transient Map<String, Object> context;
|
||||
Class defaultType;
|
||||
Map<Object, Object> overrides;
|
||||
transient OgnlUtil ognlUtil;
|
||||
transient SecurityMemberAccess securityMemberAccess;
|
||||
protected CompoundRoot root;
|
||||
protected transient Map<String, Object> context;
|
||||
protected Class defaultType;
|
||||
protected Map<Object, Object> overrides;
|
||||
protected transient OgnlUtil ognlUtil;
|
||||
protected transient SecurityMemberAccess securityMemberAccess;
|
||||
|
||||
private transient XWorkConverter converter;
|
||||
|
||||
private boolean devMode;
|
||||
private boolean logMissingProperties;
|
||||
|
||||
@@ -189,7 +190,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
context.remove(REPORT_ERRORS_ON_NO_PROP);
|
||||
}
|
||||
|
||||
private void handleRuntimeException(String expr, Object value, boolean throwExceptionOnFailure, RuntimeException re) {
|
||||
protected void handleRuntimeException(String expr, Object value, boolean throwExceptionOnFailure, RuntimeException re) {
|
||||
if (throwExceptionOnFailure) {
|
||||
String message = ErrorMessageBuilder.create()
|
||||
.errorSettingExpressionWithValue(expr, value)
|
||||
@@ -200,7 +201,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
}
|
||||
}
|
||||
|
||||
private void handleOgnlException(String expr, Object value, boolean throwExceptionOnFailure, OgnlException e) {
|
||||
protected void handleOgnlException(String expr, Object value, boolean throwExceptionOnFailure, OgnlException e) {
|
||||
boolean shouldLog = shouldLogMissingPropertyWarning(e);
|
||||
String msg = null;
|
||||
if (throwExceptionOnFailure || shouldLog) {
|
||||
@@ -242,7 +243,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
}
|
||||
}
|
||||
|
||||
private void setupExceptionOnFailure(boolean throwExceptionOnFailure) {
|
||||
protected void setupExceptionOnFailure(boolean throwExceptionOnFailure) {
|
||||
if (throwExceptionOnFailure) {
|
||||
context.put(THROW_EXCEPTION_ON_FAILURE, true);
|
||||
}
|
||||
@@ -255,7 +256,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
return tryFindValue(expr);
|
||||
}
|
||||
|
||||
private Object handleOtherException(String expr, boolean throwExceptionOnFailure, Exception e) {
|
||||
protected Object handleOtherException(String expr, boolean throwExceptionOnFailure, Exception e) {
|
||||
logLookupFailure(expr, e);
|
||||
|
||||
if (throwExceptionOnFailure)
|
||||
@@ -322,7 +323,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
return tryFindValue(expr, asType);
|
||||
}
|
||||
|
||||
private Object handleOgnlException(String expr, boolean throwExceptionOnFailure, OgnlException e) {
|
||||
protected Object handleOgnlException(String expr, boolean throwExceptionOnFailure, OgnlException e) {
|
||||
Object ret = findInContext(expr);
|
||||
if (ret == null) {
|
||||
if (shouldLogMissingPropertyWarning(e)) {
|
||||
@@ -335,7 +336,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
return ret;
|
||||
}
|
||||
|
||||
private boolean shouldLogMissingPropertyWarning(OgnlException e) {
|
||||
protected boolean shouldLogMissingPropertyWarning(OgnlException e) {
|
||||
return (e instanceof NoSuchPropertyException || e instanceof MethodFailedException)
|
||||
&& devMode && logMissingProperties;
|
||||
}
|
||||
@@ -359,7 +360,7 @@ public class OgnlValueStack implements Serializable, ValueStack, ClearableValueS
|
||||
return ognlUtil.getValue(expr, context, root, asType);
|
||||
}
|
||||
|
||||
private Object findInContext(String name) {
|
||||
protected Object findInContext(String name) {
|
||||
return getContext().get(name);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,11 +38,11 @@ import java.util.Set;
|
||||
*/
|
||||
public class OgnlValueStackFactory implements ValueStackFactory {
|
||||
|
||||
private XWorkConverter xworkConverter;
|
||||
private CompoundRootAccessor compoundRootAccessor;
|
||||
private TextProvider textProvider;
|
||||
private Container container;
|
||||
private boolean allowStaticMethodAccess;
|
||||
protected XWorkConverter xworkConverter;
|
||||
protected CompoundRootAccessor compoundRootAccessor;
|
||||
protected TextProvider textProvider;
|
||||
protected Container container;
|
||||
protected boolean allowStaticMethodAccess;
|
||||
|
||||
@Inject
|
||||
public void setXWorkConverter(XWorkConverter converter) {
|
||||
|
||||
@@ -53,6 +53,8 @@ public class SecurityMemberAccess extends DefaultMemberAccess {
|
||||
|
||||
@Override
|
||||
public boolean isAccessible(Map context, Object target, Member member, String propertyName) {
|
||||
LOG.debug("Checking access for [target: {}, member: {}, property: {}] is deprecated!", target, member, propertyName);
|
||||
|
||||
if (checkEnumAccess(target, member)) {
|
||||
LOG.trace("Allowing access to enum: {}", target);
|
||||
return true;
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.opensymphony.xwork2.ognl.accessor;
|
||||
|
||||
import ognl.ObjectPropertyAccessor;
|
||||
import ognl.OgnlException;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpParametersPropertyAccessor extends ObjectPropertyAccessor {
|
||||
|
||||
@Override
|
||||
public Object getProperty(Map context, Object target, Object oname) throws OgnlException {
|
||||
HttpParameters parameters = (HttpParameters) target;
|
||||
return parameters.get(String.valueOf(oname)).getObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(Map context, Object target, Object oname, Object value) throws OgnlException {
|
||||
throw new OgnlException("Access to " + target.getClass().getName() + " is read-only!");
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.opensymphony.xwork2.ognl.accessor;
|
||||
|
||||
import ognl.ObjectPropertyAccessor;
|
||||
import ognl.OgnlException;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ParameterPropertyAccessor extends ObjectPropertyAccessor {
|
||||
|
||||
@Override
|
||||
public Object getProperty(Map context, Object target, Object oname) throws OgnlException {
|
||||
if (target instanceof Parameter) {
|
||||
if ("value".equalsIgnoreCase(String.valueOf(oname))) {
|
||||
throw new OgnlException("Access to " + oname + " is not allowed! Call parameter name directly!");
|
||||
}
|
||||
return ((Parameter) target).getObject();
|
||||
}
|
||||
return super.getProperty(context, target, oname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(Map context, Object target, Object oname, Object value) throws OgnlException {
|
||||
if (target instanceof Parameter) {
|
||||
throw new OgnlException("Access to " + target.getClass().getName() + " is read-only!");
|
||||
} else {
|
||||
super.setProperty(context, target, oname, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,12 +20,16 @@ package com.opensymphony.xwork2.util;
|
||||
import com.opensymphony.xwork2.XWorkException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Vector;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
* This class is an utility class that will search through the classpath
|
||||
@@ -88,10 +92,24 @@ public class ClassPathFinder {
|
||||
} catch (URISyntaxException e) {
|
||||
continue;
|
||||
}
|
||||
File entry = new File(entryURI) ;
|
||||
Vector<String> results = checkEntries(entry.list(), entry, "");
|
||||
if (results != null ) {
|
||||
matches.addAll(results);
|
||||
File entry = new File(entryURI);
|
||||
if (entry.isFile() && entry.toString().endsWith(".jar")) {
|
||||
try {
|
||||
ZipInputStream zip = new ZipInputStream(new FileInputStream(entry));
|
||||
for (ZipEntry zipEntry = zip.getNextEntry(); zipEntry != null; zipEntry = zip.getNextEntry()) {
|
||||
boolean doesMatch = patternMatcher.match(new HashMap<String, String>(), zipEntry.getName(), compiledPattern);
|
||||
if (doesMatch) {
|
||||
matches.add(zipEntry.getName());
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
Vector<String> results = checkEntries(entry.list(), entry, "");
|
||||
if (results != null) {
|
||||
matches.addAll(results);
|
||||
}
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
|
||||
@@ -31,8 +31,6 @@ import java.util.*;
|
||||
*/
|
||||
public class TextParseUtil {
|
||||
|
||||
private static final int MAX_RECURSION = 1;
|
||||
|
||||
/**
|
||||
* Converts all instances of ${...}, and %{...} in <code>expression</code> to the value returned
|
||||
* by a call to {@link ValueStack#findValue(java.lang.String)}. If an item cannot
|
||||
@@ -108,7 +106,7 @@ public class TextParseUtil {
|
||||
* @return Converted object from variable translation.
|
||||
*/
|
||||
public static Object translateVariables(char open, String expression, ValueStack stack, Class asType, ParsedValueEvaluator evaluator) {
|
||||
return translateVariables(new char[]{open} , expression, stack, asType, evaluator, MAX_RECURSION);
|
||||
return translateVariables(new char[]{open} , expression, stack, asType, evaluator, TextParser.DEFAULT_LOOP_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,7 +120,7 @@ public class TextParseUtil {
|
||||
* @return Converted object from variable translation.
|
||||
*/
|
||||
public static Object translateVariables(char[] openChars, String expression, ValueStack stack, Class asType, ParsedValueEvaluator evaluator) {
|
||||
return translateVariables(openChars, expression, stack, asType, evaluator, MAX_RECURSION);
|
||||
return translateVariables(openChars, expression, stack, asType, evaluator, TextParser.DEFAULT_LOOP_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,7 +176,7 @@ public class TextParseUtil {
|
||||
* @return converted objects
|
||||
*/
|
||||
public static Collection<String> translateVariablesCollection(String expression, ValueStack stack, boolean excludeEmptyElements, ParsedValueEvaluator evaluator) {
|
||||
return translateVariablesCollection(new char[]{'$', '%'}, expression, stack, excludeEmptyElements, evaluator, MAX_RECURSION);
|
||||
return translateVariablesCollection(new char[]{'$', '%'}, expression, stack, excludeEmptyElements, evaluator, TextParser.DEFAULT_LOOP_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,6 +6,8 @@ package com.opensymphony.xwork2.util;
|
||||
*/
|
||||
public interface TextParser {
|
||||
|
||||
int DEFAULT_LOOP_COUNT = 1;
|
||||
|
||||
Object evaluate(char[] openChars, String expression, TextParseUtil.ParsedValueEvaluator evaluator, int maxLoopCount);
|
||||
|
||||
}
|
||||
|
||||
@@ -129,15 +129,15 @@ import org.apache.logging.log4j.Logger;
|
||||
*/
|
||||
public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ValidationInterceptor.class);
|
||||
|
||||
private final static String VALIDATE_PREFIX = "validate";
|
||||
private final static String ALT_VALIDATE_PREFIX = "validateDo";
|
||||
|
||||
private boolean validateAnnotatedMethodOnly;
|
||||
|
||||
private ActionValidatorManager actionValidatorManager;
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(ValidationInterceptor.class);
|
||||
|
||||
private final static String VALIDATE_PREFIX = "validate";
|
||||
private final static String ALT_VALIDATE_PREFIX = "validateDo";
|
||||
|
||||
private boolean alwaysInvokeValidate = true;
|
||||
private boolean programmatic = true;
|
||||
private boolean declarative = true;
|
||||
@@ -212,8 +212,8 @@ public class ValidationInterceptor extends MethodFilterInterceptor {
|
||||
String context = this.getValidationContext(proxy);
|
||||
String method = proxy.getMethod();
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Validating {}/{} with method {}.", invocation.getProxy().getNamespace(), invocation.getProxy().getActionName(), method);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Validating {}/{} with method {}.", invocation.getProxy().getNamespace(), invocation.getProxy().getActionName(), method);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ package com.opensymphony.xwork2.validator.validators;
|
||||
* The regular expression used to validate that the string is an email address is:
|
||||
*
|
||||
* <pre>
|
||||
* \\b^['_a-z0-9-\\+]+(\\.['_a-z0-9-\\+]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*\\.([a-z]{2}|aero|arpa|asia|biz|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|nato|net|org|pro|tel|travel|xxx|tech|cat)$\\b
|
||||
* \\b^['_a-z0-9-\\+]+(\\.['_a-z0-9-\\+]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*\\.([a-z]{2,6})$\\b
|
||||
* </pre>
|
||||
*
|
||||
* You can also specify expression, caseSensitive and trim params as a OGNL expression, see the example below.
|
||||
@@ -78,9 +78,7 @@ package com.opensymphony.xwork2.validator.validators;
|
||||
*/
|
||||
public class EmailValidator extends RegexFieldValidator {
|
||||
|
||||
// see XW-371
|
||||
public static final String EMAIL_ADDRESS_PATTERN =
|
||||
"\\b^['_a-z0-9-\\+]+(\\.['_a-z0-9-\\+]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*\\.([a-z]{2}|aero|arpa|asia|biz|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|nato|net|org|pro|tel|travel|xxx|tech|cat)$\\b";
|
||||
public static final String EMAIL_ADDRESS_PATTERN = "\\b^['_a-z0-9-\\+]+(\\.['_a-z0-9-\\+]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*\\.([a-z]{2,6})$\\b";
|
||||
|
||||
public EmailValidator() {
|
||||
setRegex(EMAIL_ADDRESS_PATTERN);
|
||||
|
||||
@@ -17,6 +17,8 @@ package com.opensymphony.xwork2.validator.validators;
|
||||
|
||||
import com.opensymphony.xwork2.validator.ValidationException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -42,8 +44,25 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public class URLValidator extends FieldValidatorSupport {
|
||||
|
||||
private String urlRegex;
|
||||
private static final Logger LOG = LogManager.getLogger(URLValidator.class);
|
||||
|
||||
public static final String DEFAULT_URL_REGEX = "^(https?|ftp):\\/\\/" +
|
||||
"(([a-z0-9$_\\.\\+!\\*\\'\\(\\),;\\?&=-]|%[0-9a-f]{2})+" +
|
||||
"(:([a-z0-9$_\\.\\+!\\*\\'\\(\\),;\\?&=-]|%[0-9a-f]{2})+)?" +
|
||||
"@)?(#?" +
|
||||
")((([a-z0-9]\\.|[a-z0-9][a-z0-9-]*[a-z0-9]\\.)*" +
|
||||
"[a-z][a-z0-9-]*[a-z0-9]" +
|
||||
"|((\\d|[1-9]\\d|1\\d{2}|2[0-4][0-9]|25[0-5])\\.){3}" +
|
||||
"(\\d|[1-9]\\d|1\\d{2}|2[0-4][0-9]|25[0-5])" +
|
||||
")(:\\d+)?" +
|
||||
")(((\\/{0,1}([a-z0-9$_\\.\\+!\\*\\'\\(\\),;:@&=-]|%[0-9a-f]{2})*)*" +
|
||||
"(\\?([a-z0-9$_\\.\\+!\\*\\'\\(\\),;:@&=-]|%[0-9a-f]{2})*)" +
|
||||
"?)?)?" +
|
||||
"(#([a-z0-9$_\\.\\+!\\*\\'\\(\\),;:@&=-]|%[0-9a-f]{2})*)?" +
|
||||
"$";
|
||||
|
||||
private String urlRegexExpression;
|
||||
private Pattern urlPattern = Pattern.compile(DEFAULT_URL_REGEX, Pattern.CASE_INSENSITIVE);
|
||||
|
||||
public void validate(Object object) throws ValidationException {
|
||||
String fieldName = getFieldName();
|
||||
@@ -55,11 +74,26 @@ public class URLValidator extends FieldValidatorSupport {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(value.getClass().equals(String.class)) || !Pattern.compile(getUrlRegex(), Pattern.CASE_INSENSITIVE).matcher(String.valueOf(value)).matches()) {
|
||||
String stringValue = String.valueOf(value).trim();
|
||||
|
||||
if (!(value.getClass().equals(String.class)) || !getUrlPattern().matcher(stringValue).matches()) {
|
||||
addFieldError(fieldName, object);
|
||||
}
|
||||
}
|
||||
|
||||
protected Pattern getUrlPattern() {
|
||||
if (StringUtils.isNotEmpty(urlRegexExpression)) {
|
||||
String regex = (String) parse(urlRegexExpression, String.class);
|
||||
if (regex == null) {
|
||||
LOG.warn("Provided URL Regex expression [{}] was evaluated to null! Falling back to default!", urlRegexExpression);
|
||||
urlPattern = Pattern.compile(DEFAULT_URL_REGEX, Pattern.CASE_INSENSITIVE);
|
||||
} else {
|
||||
urlPattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
}
|
||||
return urlPattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used to support client-side validation, it's based on
|
||||
* http://stackoverflow.com/questions/161738/what-is-the-best-regular-expression-to-check-if-a-string-is-a-valid-url
|
||||
@@ -67,30 +101,11 @@ public class URLValidator extends FieldValidatorSupport {
|
||||
* @return regex to validate URLs
|
||||
*/
|
||||
public String getUrlRegex() {
|
||||
if (StringUtils.isNotEmpty(urlRegexExpression)) {
|
||||
return (String) parse(urlRegexExpression, String.class);
|
||||
} else if (StringUtils.isNotEmpty(urlRegex)) {
|
||||
return urlRegex;
|
||||
} else {
|
||||
return "^(https?|ftp):\\/\\/" +
|
||||
"(([a-z0-9$_\\.\\+!\\*\\'\\(\\),;\\?&=-]|%[0-9a-f]{2})+" +
|
||||
"(:([a-z0-9$_\\.\\+!\\*\\'\\(\\),;\\?&=-]|%[0-9a-f]{2})+)?" +
|
||||
"@)?(#?" +
|
||||
")((([a-z0-9]\\.|[a-z0-9][a-z0-9-]*[a-z0-9]\\.)*" +
|
||||
"[a-z][a-z0-9-]*[a-z0-9]" +
|
||||
"|((\\d|[1-9]\\d|1\\d{2}|2[0-4][0-9]|25[0-5])\\.){3}" +
|
||||
"(\\d|[1-9]\\d|1\\d{2}|2[0-4][0-9]|25[0-5])" +
|
||||
")(:\\d+)?" +
|
||||
")(((\\/{0,1}([a-z0-9$_\\.\\+!\\*\\'\\(\\),;:@&=-]|%[0-9a-f]{2})*)*" +
|
||||
"(\\?([a-z0-9$_\\.\\+!\\*\\'\\(\\),;:@&=-]|%[0-9a-f]{2})*)" +
|
||||
"?)?)?" +
|
||||
"(#([a-z0-9$_\\.\\+!\\*\\'\\(\\),;:@&=-]|%[0-9a-f]{2})*)?" +
|
||||
"$";
|
||||
}
|
||||
return getUrlPattern().pattern();
|
||||
}
|
||||
|
||||
public void setUrlRegex(String urlRegex) {
|
||||
this.urlRegex = urlRegex;
|
||||
urlPattern = Pattern.compile(urlRegex, Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
|
||||
public void setUrlRegexExpression(String urlRegexExpression) {
|
||||
|
||||
@@ -288,8 +288,10 @@ public class Date extends ContextBean {
|
||||
Object dateObject = findValue(name);
|
||||
if (dateObject instanceof java.util.Date) {
|
||||
date = (java.util.Date) dateObject;
|
||||
} else if(dateObject instanceof Calendar){
|
||||
} else if (dateObject instanceof Calendar) {
|
||||
date = ((Calendar) dateObject).getTime();
|
||||
} else if (dateObject instanceof Long) {
|
||||
date = new java.util.Date((long) dateObject);
|
||||
} else {
|
||||
if (devMode) {
|
||||
String developerNotification = LocalizedTextUtil.findText(
|
||||
@@ -299,12 +301,12 @@ public class Date extends ContextBean {
|
||||
"Developer Notification:\n{0}",
|
||||
new Object[]{
|
||||
"Expression [" + name + "] passed to <s:date/> tag which was evaluated to [" + dateObject + "]("
|
||||
+ (dateObject != null ? dateObject.getClass() : "null") + ") isn't instance of java.util.Date nor java.util.Calendar!"
|
||||
+ (dateObject != null ? dateObject.getClass() : "null") + ") isn't instance of java.util.Date nor java.util.Calendar nor long!"
|
||||
}
|
||||
);
|
||||
LOG.warn(developerNotification);
|
||||
} else {
|
||||
LOG.debug("Expression [{}] passed to <s:date/> tag which was evaluated to [{}]({}) isn't instance of java.util.Date nor java.util.Calendar!",
|
||||
LOG.debug("Expression [{}] passed to <s:date/> tag which was evaluated to [{}]({}) isn't instance of java.util.Date nor java.util.Calendar nor long!",
|
||||
name, dateObject, (dateObject != null ? dateObject.getClass() : "null"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.apache.struts2.components;
|
||||
|
||||
/*
|
||||
* $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
|
||||
@@ -23,6 +16,7 @@ package org.apache.struts2.components;
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.struts2.components;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
@@ -33,6 +27,7 @@ import org.apache.struts2.views.annotations.StrutsTagAttribute;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Currency;
|
||||
|
||||
@@ -154,16 +149,14 @@ public class Number extends ContextBean {
|
||||
setRoundingMode(format);
|
||||
|
||||
String msg = format.format(number);
|
||||
if (msg != null) {
|
||||
try {
|
||||
if (getVar() == null) {
|
||||
writer.write(msg);
|
||||
} else {
|
||||
putInContext(msg);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Could not write out Number tag", e);
|
||||
try {
|
||||
if (getVar() == null) {
|
||||
writer.write(msg);
|
||||
} else {
|
||||
putInContext(msg);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Could not write out Number tag", e);
|
||||
}
|
||||
}
|
||||
return super.end(writer, "");
|
||||
@@ -221,8 +214,6 @@ public class Number extends ContextBean {
|
||||
}
|
||||
|
||||
private void setRoundingMode(NumberFormat format) {
|
||||
/*
|
||||
TODO lukaszlenart: enable when switched to Java 1.6
|
||||
if (roundingMode != null) {
|
||||
roundingMode = findString(roundingMode);
|
||||
if ("ceiling".equals(roundingMode)) {
|
||||
@@ -245,7 +236,6 @@ public class Number extends ContextBean {
|
||||
LOG.error("Could not recognise a roundingMode of [" + roundingMode + "]");
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private NumberFormat getNumberFormat() {
|
||||
@@ -275,12 +265,12 @@ public class Number extends ContextBean {
|
||||
return format;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "Type of number formatter (currency, integer, number or percent, default is number)", rtexprvalue = false)
|
||||
@StrutsTagAttribute(description = "Type of number formatter (currency, integer, number or percent, default is number)")
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description = "The currency to use for a currency format", type = "String", defaultValue = "")
|
||||
@StrutsTagAttribute(description = "The currency to use for a currency format")
|
||||
public void setCurrency(String currency) {
|
||||
this.currency = currency;
|
||||
}
|
||||
@@ -408,7 +398,7 @@ public class Number extends ContextBean {
|
||||
/**
|
||||
* @param roundingMode the roundingMode to set
|
||||
*/
|
||||
@StrutsTagAttribute(description = "The rounding mode to use - not implemented yet as this required Java 1.6", type = "String")
|
||||
@StrutsTagAttribute(description = "The rounding mode to use, possible values: ceiling, down, floor, half-down, half-even, half-up, unnecessary, up")
|
||||
public void setRoundingMode(String roundingMode) {
|
||||
this.roundingMode = roundingMode;
|
||||
}
|
||||
|
||||
@@ -138,6 +138,8 @@ public class Param extends Component {
|
||||
if (suppressEmptyParameters) {
|
||||
if (value != null && StringUtils.isNotBlank(value.toString())) {
|
||||
component.addParameter(name, value);
|
||||
} else {
|
||||
component.addParameter(name, null);
|
||||
}
|
||||
} else if (value == null || StringUtils.isBlank(value.toString())) {
|
||||
component.addParameter(name, "");
|
||||
@@ -151,6 +153,8 @@ public class Param extends Component {
|
||||
} else {
|
||||
if (!(suppressEmptyParameters && StringUtils.isBlank(body))) {
|
||||
component.addParameter(findString(name), body);
|
||||
} else {
|
||||
component.addParameter(findString(name), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ import java.util.List;
|
||||
*
|
||||
* <p>
|
||||
* If the named message is not found in a property file, then the body of the
|
||||
* tag will be used as default message. If no body is used, then the stack will
|
||||
* tag will be used as default message. If no body is used, then the stack can
|
||||
* be searched, and if a value is returned, it will written to the output.
|
||||
* If no value is found on the stack, the key of the message will be written out.
|
||||
* </p>
|
||||
@@ -115,9 +115,10 @@ import java.util.List;
|
||||
tldTagClass="org.apache.struts2.views.jsp.TextTag",
|
||||
description="Render a I18n text message")
|
||||
public class Text extends ContextBean implements Param.UnnamedParametric {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(Text.class);
|
||||
|
||||
protected List values = Collections.EMPTY_LIST;
|
||||
protected List<Object> values = Collections.emptyList();
|
||||
protected String actualName;
|
||||
protected String name;
|
||||
protected String searchStack;
|
||||
@@ -131,7 +132,7 @@ public class Text extends ContextBean implements Param.UnnamedParametric {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="Search the stack if property is not found on resources", type = "Boolean", defaultValue = "true")
|
||||
@StrutsTagAttribute(description="Search the stack if property is not found on resources", type = "Boolean", defaultValue = "false")
|
||||
public void setSearchValueStack(String searchStack) {
|
||||
this.searchStack = searchStack;
|
||||
}
|
||||
@@ -152,8 +153,13 @@ public class Text extends ContextBean implements Param.UnnamedParametric {
|
||||
defaultMessage = actualName;
|
||||
}
|
||||
|
||||
Boolean doSearchStack = searchStack != null ? (Boolean) findValue(searchStack, Boolean.class) : true;
|
||||
String msg = TextProviderHelper.getText(actualName, defaultMessage, values, getStack(), doSearchStack == null || doSearchStack);
|
||||
Boolean doSearchStack = false;
|
||||
if (searchStack != null) {
|
||||
Object value = findValue(searchStack, Boolean.class);
|
||||
doSearchStack = value != null ? (Boolean) value : false;
|
||||
}
|
||||
|
||||
String msg = TextProviderHelper.getText(actualName, defaultMessage, values, getStack(), doSearchStack);
|
||||
|
||||
if (msg != null) {
|
||||
try {
|
||||
@@ -176,7 +182,7 @@ public class Text extends ContextBean implements Param.UnnamedParametric {
|
||||
|
||||
public void addParameter(Object value) {
|
||||
if (values.isEmpty()) {
|
||||
values = new ArrayList(4);
|
||||
values = new ArrayList<>(4);
|
||||
}
|
||||
|
||||
values.add(value);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.struts2.conversion;
|
||||
|
||||
import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverter;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.dispatcher.multipart.UploadedFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Member;
|
||||
import java.util.Map;
|
||||
|
||||
public class UploadedFileConverter extends DefaultTypeConverter {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(UploadedFileConverter.class);
|
||||
|
||||
@Override
|
||||
public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType) {
|
||||
if (File.class.equals(toType)) {
|
||||
LOG.debug("Converting {} into {}, consider switching to {} and do not access {} directly!",
|
||||
File.class.getName(), UploadedFile.class.getName(), UploadedFile.class.getName(), File.class.getName());
|
||||
|
||||
Object obj;
|
||||
if (value.getClass().isArray() && Array.getLength(value) == 1) {
|
||||
obj = Array.get(value, 0);
|
||||
} else {
|
||||
obj = value;
|
||||
}
|
||||
|
||||
if (obj instanceof UploadedFile) {
|
||||
UploadedFile file = (UploadedFile) obj;
|
||||
if (file.getContent() instanceof File) {
|
||||
return file.getContent();
|
||||
}
|
||||
return new File(file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
return super.convertValue(context, target, member, propertyName, value, toType);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -690,7 +690,7 @@ public class Dispatcher {
|
||||
*
|
||||
* @return the path to save uploaded files to
|
||||
*/
|
||||
private String getSaveDir() {
|
||||
protected String getSaveDir() {
|
||||
String saveDir = multipartSaveDir.trim();
|
||||
|
||||
if (saveDir.equals("")) {
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
/*
|
||||
* 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 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;
|
||||
@@ -8,7 +31,8 @@ import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public class HttpParameters implements Cloneable {
|
||||
@SuppressWarnings("unchecked")
|
||||
public class HttpParameters implements Map<String, Parameter>, Cloneable {
|
||||
|
||||
private Map<String, Parameter> parameters;
|
||||
|
||||
@@ -24,18 +48,6 @@ public class HttpParameters implements Cloneable {
|
||||
return new Builder(new HashMap<String, Object>());
|
||||
}
|
||||
|
||||
public Parameter get(String name) {
|
||||
if (parameters.containsKey(name)) {
|
||||
return parameters.get(name);
|
||||
} else {
|
||||
return new Parameter.EmptyHttpParameter(name);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> getNames() {
|
||||
return new TreeSet<>(parameters.keySet());
|
||||
}
|
||||
|
||||
public HttpParameters remove(Set<String> paramsToRemove) {
|
||||
for (String paramName : paramsToRemove) {
|
||||
parameters.remove(paramName);
|
||||
@@ -53,6 +65,12 @@ public class HttpParameters implements Cloneable {
|
||||
return parameters.containsKey(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Access to this method will be restricted with the next versiob
|
||||
* @deprecated since 2.5.6, do not use it
|
||||
* TODO: reduce access level to `private`
|
||||
*/
|
||||
@Deprecated
|
||||
public Map<String, String[]> toMap() {
|
||||
Map<String, String[]> result = new HashMap<>(parameters.size());
|
||||
for (Map.Entry<String, Parameter> entry : parameters.entrySet()) {
|
||||
@@ -66,6 +84,79 @@ public class HttpParameters implements Cloneable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void applyParameters(ParameterAware parameterAware) {
|
||||
parameterAware.setParameters(toMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return parameters.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return parameters.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return parameters.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return parameters.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameter get(Object key) {
|
||||
if (parameters.containsKey(key)) {
|
||||
return parameters.get(key);
|
||||
} else {
|
||||
return new Parameter.Empty(String.valueOf(key));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameter put(String key, Parameter value) {
|
||||
throw new IllegalAccessError("HttpParameters are immutable, you cannot put value directly!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameter remove(Object key) {
|
||||
throw new IllegalAccessError("HttpParameters are immutable, you cannot remove object directly!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends Parameter> m) {
|
||||
throw new IllegalAccessError("HttpParameters are immutable, you cannot put values directly!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new IllegalAccessError("HttpParameters are immutable, you cannot clear values directly!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
return Collections.unmodifiableSet(new TreeSet<>(parameters.keySet()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Parameter> values() {
|
||||
return Collections.unmodifiableCollection(parameters.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, Parameter>> entrySet() {
|
||||
return Collections.unmodifiableSet(parameters.entrySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return parameters.toString();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private Map<String, Object> requestParameterMap;
|
||||
private HttpParameters parent;
|
||||
|
||||
@@ -109,7 +109,7 @@ public class InitOperations {
|
||||
*
|
||||
* @return The dispatcher on the thread.
|
||||
*/
|
||||
private Dispatcher createDispatcher( HostConfig filterConfig ) {
|
||||
protected Dispatcher createDispatcher(HostConfig filterConfig) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {
|
||||
String name = (String) e.next();
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* $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.dispatcher;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class LocalizedMessage {
|
||||
private final Class clazz;
|
||||
private final String textKey;
|
||||
private final String defaultMessage;
|
||||
private final Object[] args;
|
||||
|
||||
public LocalizedMessage(Class clazz, String textKey, String defaultMessage, Object[] args) {
|
||||
this.clazz = clazz;
|
||||
this.textKey = textKey;
|
||||
this.defaultMessage = defaultMessage;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public Class getClazz() {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public String getTextKey() {
|
||||
return textKey;
|
||||
}
|
||||
|
||||
public String getDefaultMessage() {
|
||||
return defaultMessage;
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Arrays.hashCode(args);
|
||||
result = prime * result + ((clazz == null) ? 0 : clazz.hashCode());
|
||||
result = prime * result + ((defaultMessage == null) ? 0 : defaultMessage.hashCode());
|
||||
result = prime * result + ((textKey == null) ? 0 : textKey.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
LocalizedMessage other = (LocalizedMessage) obj;
|
||||
if (!Arrays.equals(args, other.args)) {
|
||||
return false;
|
||||
}
|
||||
if (clazz == null) {
|
||||
if (other.clazz != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!clazz.equals(other.clazz)) {
|
||||
return false;
|
||||
}
|
||||
if (defaultMessage == null) {
|
||||
if (other.defaultMessage != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!defaultMessage.equals(other.defaultMessage)) {
|
||||
return false;
|
||||
}
|
||||
if (textKey == null) {
|
||||
if (other.textKey != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!textKey.equals(other.textKey)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
package org.apache.struts2.dispatcher;
|
||||
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public interface Parameter {
|
||||
|
||||
String getName();
|
||||
@@ -82,19 +81,32 @@ public interface Parameter {
|
||||
public Object getObject() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
class File extends Request {
|
||||
public File(String name, Object value) {
|
||||
super(name, value);
|
||||
@Override
|
||||
public String toString() {
|
||||
return StringEscapeUtils.escapeHtml4(getValue());
|
||||
}
|
||||
}
|
||||
|
||||
class EmptyHttpParameter implements Parameter {
|
||||
class File extends Request {
|
||||
|
||||
public File(String name, Object value) {
|
||||
super(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "File{" +
|
||||
"name='" + getName() + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
class Empty implements Parameter {
|
||||
|
||||
private String name;
|
||||
|
||||
public EmptyHttpParameter(String name) {
|
||||
public Empty(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@@ -127,6 +139,13 @@ public interface Parameter {
|
||||
public Object getObject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Empty{" +
|
||||
"name='" + name + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+33
-3
@@ -55,7 +55,7 @@ public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {
|
||||
protected List<Pattern> excludedPatterns = null;
|
||||
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
InitOperations init = new InitOperations();
|
||||
InitOperations init = createInitOperations();
|
||||
Dispatcher dispatcher = null;
|
||||
try {
|
||||
FilterHostConfig config = new FilterHostConfig(filterConfig);
|
||||
@@ -63,8 +63,8 @@ public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {
|
||||
dispatcher = init.initDispatcher(config);
|
||||
init.initStaticContentLoader(config, dispatcher);
|
||||
|
||||
prepare = new PrepareOperations(dispatcher);
|
||||
execute = new ExecuteOperations(dispatcher);
|
||||
prepare = createPrepareOperations(dispatcher);
|
||||
execute = createExecuteOperations(dispatcher);
|
||||
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
|
||||
|
||||
postInit(dispatcher, filterConfig);
|
||||
@@ -76,6 +76,36 @@ public class StrutsPrepareAndExecuteFilter 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for post initialization
|
||||
*
|
||||
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
package org.apache.struts2.dispatcher.multipart;
|
||||
|
||||
import com.opensymphony.xwork2.LocaleProvider;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.LocalizedMessage;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Abstract class with some helper methods, it should be used
|
||||
* when starting development of another implementation of {@link MultiPartRequest}
|
||||
*/
|
||||
public abstract class AbstractMultiPartRequest implements MultiPartRequest {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(AbstractMultiPartRequest.class);
|
||||
|
||||
/**
|
||||
* Defines the internal buffer size used during streaming operations.
|
||||
*/
|
||||
public static final int BUFFER_SIZE = 10240;
|
||||
|
||||
/**
|
||||
* Internal list of raised errors to be passed to the the Struts2 framework.
|
||||
*/
|
||||
protected List<LocalizedMessage> errors = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Specifies the maximum size of the entire request.
|
||||
*/
|
||||
protected long maxSize;
|
||||
protected boolean maxSizeProvided;
|
||||
|
||||
/**
|
||||
* Specifies the buffer size to use during streaming.
|
||||
*/
|
||||
protected int bufferSize = BUFFER_SIZE;
|
||||
|
||||
protected String defaultEncoding;
|
||||
|
||||
/**
|
||||
* Localization to be used regarding errors.
|
||||
*/
|
||||
protected Locale defaultLocale = Locale.ENGLISH;
|
||||
|
||||
/**
|
||||
* @param bufferSize Sets the buffer size to be used.
|
||||
*/
|
||||
@Inject(value = StrutsConstants.STRUTS_MULTIPART_BUFFERSIZE, required = false)
|
||||
public void setBufferSize(String bufferSize) {
|
||||
this.bufferSize = Integer.parseInt(bufferSize);
|
||||
}
|
||||
|
||||
@Inject(StrutsConstants.STRUTS_I18N_ENCODING)
|
||||
public void setDefaultEncoding(String enc) {
|
||||
this.defaultEncoding = enc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param maxSize Injects the Struts multiple part maximum size.
|
||||
*/
|
||||
@Inject(StrutsConstants.STRUTS_MULTIPART_MAXSIZE)
|
||||
public void setMaxSize(String maxSize) {
|
||||
this.maxSizeProvided = true;
|
||||
this.maxSize = Long.parseLong(maxSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param provider Injects the Struts locale provider.
|
||||
*/
|
||||
@Inject
|
||||
public void setLocaleProvider(LocaleProvider provider) {
|
||||
defaultLocale = provider.getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param request Inspect the servlet request and set the locale if one wasn't provided by
|
||||
* the Struts2 framework.
|
||||
*/
|
||||
protected void setLocale(HttpServletRequest request) {
|
||||
if (defaultLocale == null) {
|
||||
defaultLocale = request.getLocale();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build error message.
|
||||
*
|
||||
* @param e the Throwable/Exception
|
||||
* @param args arguments
|
||||
* @return error message
|
||||
*/
|
||||
protected LocalizedMessage buildErrorMessage(Throwable e, Object[] args) {
|
||||
String errorKey = "struts.messages.upload.error." + e.getClass().getSimpleName();
|
||||
LOG.debug("Preparing error message for key: [{}]", errorKey);
|
||||
|
||||
return new LocalizedMessage(this.getClass(), errorKey, e.getMessage(), args);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getErrors()
|
||||
*/
|
||||
public List<LocalizedMessage> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
}
|
||||
+9
-47
@@ -21,8 +21,6 @@
|
||||
|
||||
package org.apache.struts2.dispatcher.multipart;
|
||||
|
||||
import com.opensymphony.xwork2.LocaleProvider;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.LocalizedTextUtil;
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.apache.commons.fileupload.FileUploadBase;
|
||||
@@ -33,7 +31,7 @@ import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.LocalizedMessage;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.File;
|
||||
@@ -45,7 +43,7 @@ import java.util.*;
|
||||
/**
|
||||
* Multipart form data request adapter for Jakarta Commons Fileupload package.
|
||||
*/
|
||||
public class JakartaMultiPartRequest implements MultiPartRequest {
|
||||
public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
|
||||
|
||||
static final Logger LOG = LogManager.getLogger(JakartaMultiPartRequest.class);
|
||||
|
||||
@@ -55,22 +53,6 @@ public class JakartaMultiPartRequest implements MultiPartRequest {
|
||||
// maps parameter name -> List of param values
|
||||
protected Map<String, List<String>> params = new HashMap<>();
|
||||
|
||||
// any errors while processing this request
|
||||
protected List<String> errors = new ArrayList<>();
|
||||
|
||||
protected long maxSize;
|
||||
private Locale defaultLocale = Locale.ENGLISH;
|
||||
|
||||
@Inject(StrutsConstants.STRUTS_MULTIPART_MAXSIZE)
|
||||
public void setMaxSize(String maxSize) {
|
||||
this.maxSize = Long.parseLong(maxSize);
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setLocaleProvider(LocaleProvider provider) {
|
||||
defaultLocale = provider.getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new request wrapper to handle multi-part data using methods adapted from Jason Pell's
|
||||
* multipart classes (see class description).
|
||||
@@ -85,39 +67,26 @@ public class JakartaMultiPartRequest implements MultiPartRequest {
|
||||
processUpload(request, saveDir);
|
||||
} catch (FileUploadException e) {
|
||||
LOG.warn("Request exceeded size limit!", e);
|
||||
String errorMessage = null;
|
||||
|
||||
LocalizedMessage errorMessage;
|
||||
if(e instanceof FileUploadBase.SizeLimitExceededException) {
|
||||
FileUploadBase.SizeLimitExceededException ex = (FileUploadBase.SizeLimitExceededException) e;
|
||||
errorMessage = buildErrorMessage(e, new Object[]{ex.getPermittedSize(), ex.getActualSize()});
|
||||
} else {
|
||||
errorMessage = buildErrorMessage(e, new Object[]{});
|
||||
}
|
||||
|
||||
|
||||
if (!errors.contains(errorMessage)) {
|
||||
errors.add(errorMessage);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Unable to parse request", e);
|
||||
String errorMessage = buildErrorMessage(e, new Object[]{});
|
||||
LocalizedMessage errorMessage = buildErrorMessage(e, new Object[]{});
|
||||
if (!errors.contains(errorMessage)) {
|
||||
errors.add(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void setLocale(HttpServletRequest request) {
|
||||
if (defaultLocale == null) {
|
||||
defaultLocale = request.getLocale();
|
||||
}
|
||||
}
|
||||
|
||||
protected String buildErrorMessage(Throwable e, Object[] args) {
|
||||
String errorKey = "struts.messages.upload.error." + e.getClass().getSimpleName();
|
||||
LOG.debug("Preparing error message for key: [{}]", errorKey);
|
||||
return LocalizedTextUtil.findText(this.getClass(), errorKey, defaultLocale, e.getMessage(), args);
|
||||
}
|
||||
|
||||
protected void processUpload(HttpServletRequest request, String saveDir) throws FileUploadException, UnsupportedEncodingException {
|
||||
for (FileItem item : parseRequest(request, saveDir)) {
|
||||
LOG.debug("Found file item: [{}]", item.getFieldName());
|
||||
@@ -222,14 +191,14 @@ public class JakartaMultiPartRequest implements MultiPartRequest {
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFile(java.lang.String)
|
||||
*/
|
||||
public File[] getFile(String fieldName) {
|
||||
public UploadedFile[] getFile(String fieldName) {
|
||||
List<FileItem> items = files.get(fieldName);
|
||||
|
||||
if (items == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<File> fileList = new ArrayList<>(items.size());
|
||||
List<UploadedFile> fileList = new ArrayList<>(items.size());
|
||||
for (FileItem fileItem : items) {
|
||||
File storeLocation = ((DiskFileItem) fileItem).getStoreLocation();
|
||||
if (fileItem.isInMemory() && storeLocation != null && !storeLocation.exists()) {
|
||||
@@ -239,10 +208,10 @@ public class JakartaMultiPartRequest implements MultiPartRequest {
|
||||
LOG.error("Cannot write uploaded empty file to disk: {}", storeLocation.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
fileList.add(storeLocation);
|
||||
fileList.add(new StrutsUploadedFile(storeLocation));
|
||||
}
|
||||
|
||||
return fileList.toArray(new File[fileList.size()]);
|
||||
return fileList.toArray(new UploadedFile[fileList.size()]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -312,13 +281,6 @@ public class JakartaMultiPartRequest implements MultiPartRequest {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getErrors()
|
||||
*/
|
||||
public List<String> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the canonical name of the given file.
|
||||
*
|
||||
|
||||
+8
-117
@@ -1,8 +1,5 @@
|
||||
package org.apache.struts2.dispatcher.multipart;
|
||||
|
||||
import com.opensymphony.xwork2.LocaleProvider;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.LocalizedTextUtil;
|
||||
import org.apache.commons.fileupload.FileItemIterator;
|
||||
import org.apache.commons.fileupload.FileItemStream;
|
||||
import org.apache.commons.fileupload.FileUploadBase;
|
||||
@@ -11,7 +8,7 @@ import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||
import org.apache.commons.fileupload.util.Streams;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.LocalizedMessage;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.*;
|
||||
@@ -26,15 +23,10 @@ import java.util.*;
|
||||
* @author Chris Cranford
|
||||
* @since 2.3.18
|
||||
*/
|
||||
public class JakartaStreamMultiPartRequest implements MultiPartRequest {
|
||||
public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
|
||||
|
||||
static final Logger LOG = LogManager.getLogger(JakartaStreamMultiPartRequest.class);
|
||||
|
||||
/**
|
||||
* Defines the internal buffer size used during streaming operations.
|
||||
*/
|
||||
private static final int BUFFER_SIZE = 10240;
|
||||
|
||||
/**
|
||||
* Map between file fields and file data.
|
||||
*/
|
||||
@@ -45,55 +37,6 @@ public class JakartaStreamMultiPartRequest implements MultiPartRequest {
|
||||
*/
|
||||
private Map<String, List<String>> parameters = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Internal list of raised errors to be passed to the the Struts2 framework.
|
||||
*/
|
||||
private List<String> errors = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Internal list of non-critical messages to be passed to the Struts2 framework.
|
||||
*/
|
||||
private List<String> messages = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Specifies the maximum size of the entire request.
|
||||
*/
|
||||
private Long maxSize;
|
||||
|
||||
/**
|
||||
* Specifies the buffer size to use during streaming.
|
||||
*/
|
||||
private int bufferSize = BUFFER_SIZE;
|
||||
|
||||
/**
|
||||
* Localization to be used regarding errors.
|
||||
*/
|
||||
private Locale defaultLocale = Locale.ENGLISH;
|
||||
|
||||
/**
|
||||
* @param maxSize Injects the Struts multiple part maximum size.
|
||||
*/
|
||||
@Inject(StrutsConstants.STRUTS_MULTIPART_MAXSIZE)
|
||||
public void setMaxSize(String maxSize) {
|
||||
this.maxSize = Long.parseLong(maxSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bufferSize Sets the buffer size to be used.
|
||||
*/
|
||||
@Inject(value = StrutsConstants.STRUTS_MULTIPART_BUFFERSIZE, required = false)
|
||||
public void setBufferSize(String bufferSize) {
|
||||
this.bufferSize = Integer.parseInt(bufferSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param provider Injects the Struts locale provider.
|
||||
*/
|
||||
@Inject
|
||||
public void setLocaleProvider(LocaleProvider provider) {
|
||||
defaultLocale = provider.getLocale();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#cleanUp()
|
||||
*/
|
||||
@@ -127,37 +70,21 @@ public class JakartaStreamMultiPartRequest implements MultiPartRequest {
|
||||
return types.toArray(new String[types.size()]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getErrors()
|
||||
*/
|
||||
public List<String> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows interceptor to fetch non-critical messages that can be passed to the action.
|
||||
*
|
||||
* @return list of string messages
|
||||
*/
|
||||
public List<String> getMesssages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.apache.struts2.dispatcher.multipart.MultiPartRequest#getFile(java.lang.String)
|
||||
*/
|
||||
public File[] getFile(String fieldName) {
|
||||
public UploadedFile[] getFile(String fieldName) {
|
||||
List<FileInfo> infos = fileInfos.get(fieldName);
|
||||
if (infos == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<File> files = new ArrayList<>(infos.size());
|
||||
List<UploadedFile> files = new ArrayList<>(infos.size());
|
||||
for (FileInfo fileInfo : infos) {
|
||||
files.add(fileInfo.getFile());
|
||||
files.add(new StrutsUploadedFile(fileInfo.getFile()));
|
||||
}
|
||||
|
||||
return files.toArray(new File[files.size()]);
|
||||
return files.toArray(new UploadedFile[files.size()]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -239,23 +166,13 @@ public class JakartaStreamMultiPartRequest implements MultiPartRequest {
|
||||
processUpload(request, saveDir);
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Error occurred during parsing of multi part request", e);
|
||||
String errorMessage = buildErrorMessage(e, new Object[]{});
|
||||
LocalizedMessage errorMessage = buildErrorMessage(e, new Object[]{});
|
||||
if (!errors.contains(errorMessage)) {
|
||||
errors.add(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param request Inspect the servlet request and set the locale if one wasn't provided by
|
||||
* the Struts2 framework.
|
||||
*/
|
||||
protected void setLocale(HttpServletRequest request) {
|
||||
if (defaultLocale == null) {
|
||||
defaultLocale = request.getLocale();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the upload.
|
||||
*
|
||||
@@ -349,7 +266,7 @@ public class JakartaStreamMultiPartRequest implements MultiPartRequest {
|
||||
private void addFileSkippedError(String fileName, HttpServletRequest request) {
|
||||
String exceptionMessage = "Skipped file " + fileName + "; request size limit exceeded.";
|
||||
FileSizeLimitExceededException exception = new FileUploadBase.FileSizeLimitExceededException(exceptionMessage, getRequestSize(request), maxSize);
|
||||
String message = buildErrorMessage(exception, new Object[]{fileName, getRequestSize(request), maxSize});
|
||||
LocalizedMessage message = buildErrorMessage(exception, new Object[]{fileName, getRequestSize(request), maxSize});
|
||||
if (!errors.contains(message)) {
|
||||
errors.add(message);
|
||||
}
|
||||
@@ -500,32 +417,6 @@ public class JakartaStreamMultiPartRequest implements MultiPartRequest {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build error message.
|
||||
*
|
||||
* @param e the Throwable/Exception
|
||||
* @param args arguments
|
||||
* @return error message
|
||||
*/
|
||||
private String buildErrorMessage(Throwable e, Object[] args) {
|
||||
String errorKey = "struts.message.upload.error." + e.getClass().getSimpleName();
|
||||
LOG.debug("Preparing error message for key: [{}]", errorKey);
|
||||
return LocalizedTextUtil.findText(this.getClass(), errorKey, defaultLocale, e.getMessage(), args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build action message.
|
||||
*
|
||||
* @param e the Throwable/Exception
|
||||
* @param args arguments
|
||||
* @return action message
|
||||
*/
|
||||
private String buildMessage(Throwable e, Object[] args) {
|
||||
String messageKey = "struts.message.upload.message." + e.getClass().getSimpleName();
|
||||
LOG.debug("Preparing message for key: [{}]", messageKey);
|
||||
return LocalizedTextUtil.findText(this.getClass(), messageKey, defaultLocale, e.getMessage(), args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal data structure used to store a reference to information needed
|
||||
* to later pass post processing data to the <code>FileUploadInterceptor</code>.
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
package org.apache.struts2.dispatcher.multipart;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.struts2.dispatcher.LocalizedMessage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
@@ -33,14 +36,14 @@ import java.util.List;
|
||||
*/
|
||||
public interface MultiPartRequest {
|
||||
|
||||
public void parse(HttpServletRequest request, String saveDir) throws IOException;
|
||||
void parse(HttpServletRequest request, String saveDir) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns an enumeration of the parameter names for uploaded files
|
||||
*
|
||||
* @return an enumeration of the parameter names for uploaded files
|
||||
*/
|
||||
public Enumeration<String> getFileParameterNames();
|
||||
Enumeration<String> getFileParameterNames();
|
||||
|
||||
/**
|
||||
* Returns the content type(s) of the file(s) associated with the specified field name
|
||||
@@ -51,16 +54,16 @@ public interface MultiPartRequest {
|
||||
* @return an array of content encoding for the specified input field name or <tt>null</tt> if
|
||||
* no content type was specified.
|
||||
*/
|
||||
public String[] getContentType(String fieldName);
|
||||
String[] getContentType(String fieldName);
|
||||
|
||||
/**
|
||||
* Returns a {@link java.io.File} object for the filename specified or <tt>null</tt> if no files
|
||||
* Returns a {@link UploadedFile} object for the filename specified or <tt>null</tt> if no files
|
||||
* are associated with the given field name.
|
||||
*
|
||||
* @param fieldName input field name
|
||||
* @return a File[] object for files associated with the specified input field name
|
||||
* @return a UploadedFile[] object for files associated with the specified input field name
|
||||
*/
|
||||
public File[] getFile(String fieldName);
|
||||
UploadedFile[] getFile(String fieldName);
|
||||
|
||||
/**
|
||||
* Returns a String[] of file names for files associated with the specified input field name
|
||||
@@ -68,7 +71,7 @@ public interface MultiPartRequest {
|
||||
* @param fieldName input field name
|
||||
* @return a String[] of file names for files associated with the specified input field name
|
||||
*/
|
||||
public String[] getFileNames(String fieldName);
|
||||
String[] getFileNames(String fieldName);
|
||||
|
||||
/**
|
||||
* Returns the file system name(s) of files associated with the given field name or
|
||||
@@ -77,7 +80,7 @@ public interface MultiPartRequest {
|
||||
* @param fieldName input field name
|
||||
* @return the file system name(s) of files associated with the given field name
|
||||
*/
|
||||
public String[] getFilesystemName(String fieldName);
|
||||
String[] getFilesystemName(String fieldName);
|
||||
|
||||
/**
|
||||
* Returns the specified request parameter.
|
||||
@@ -85,14 +88,14 @@ public interface MultiPartRequest {
|
||||
* @param name the name of the parameter to get
|
||||
* @return the parameter or <tt>null</tt> if it was not found.
|
||||
*/
|
||||
public String getParameter(String name);
|
||||
String getParameter(String name);
|
||||
|
||||
/**
|
||||
* Returns an enumeration of String parameter names.
|
||||
*
|
||||
* @return an enumeration of String parameter names.
|
||||
*/
|
||||
public Enumeration<String> getParameterNames();
|
||||
Enumeration<String> getParameterNames();
|
||||
|
||||
/**
|
||||
* Returns a list of all parameter values associated with a parameter name. If there is only
|
||||
@@ -101,7 +104,7 @@ public interface MultiPartRequest {
|
||||
* @param name the name of the parameter.
|
||||
* @return an array of all values associated with the parameter name.
|
||||
*/
|
||||
public String[] getParameterValues(String name);
|
||||
String[] getParameterValues(String name);
|
||||
|
||||
/**
|
||||
* Returns a list of error messages that may have occurred while processing the request.
|
||||
@@ -112,11 +115,11 @@ public interface MultiPartRequest {
|
||||
*
|
||||
* @return a list of Strings that represent various errors during parsing
|
||||
*/
|
||||
public List<String> getErrors();
|
||||
List<LocalizedMessage> getErrors();
|
||||
|
||||
/**
|
||||
* Cleans up all uploaded file, should be called at the end of request
|
||||
*/
|
||||
public void cleanUp();
|
||||
void cleanUp();
|
||||
|
||||
}
|
||||
|
||||
+8
-7
@@ -25,6 +25,7 @@ import com.opensymphony.xwork2.LocaleProvider;
|
||||
import com.opensymphony.xwork2.util.LocalizedTextUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.dispatcher.LocalizedMessage;
|
||||
import org.apache.struts2.dispatcher.StrutsRequestWrapper;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -60,7 +61,7 @@ public class MultiPartRequestWrapper extends StrutsRequestWrapper {
|
||||
|
||||
protected static final Logger LOG = LogManager.getLogger(MultiPartRequestWrapper.class);
|
||||
|
||||
private Collection<String> errors;
|
||||
private Collection<LocalizedMessage> errors;
|
||||
private MultiPartRequest multi;
|
||||
private Locale defaultLocale = Locale.ENGLISH;
|
||||
|
||||
@@ -83,7 +84,7 @@ public class MultiPartRequestWrapper extends StrutsRequestWrapper {
|
||||
setLocale(request);
|
||||
try {
|
||||
multi.parse(request, saveDir);
|
||||
for (String error : multi.getErrors()) {
|
||||
for (LocalizedMessage error : multi.getErrors()) {
|
||||
addError(error);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@@ -102,10 +103,10 @@ public class MultiPartRequestWrapper extends StrutsRequestWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
protected String buildErrorMessage(Throwable e, Object[] args) {
|
||||
protected LocalizedMessage buildErrorMessage(Throwable e, Object[] args) {
|
||||
String errorKey = "struts.messages.upload.error." + e.getClass().getSimpleName();
|
||||
LOG.debug("Preparing error message for key: [{}]", errorKey);
|
||||
return LocalizedTextUtil.findText(this.getClass(), errorKey, defaultLocale, e.getMessage(), args);
|
||||
return new LocalizedMessage(this.getClass(), errorKey, e.getMessage(), args);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,7 +143,7 @@ public class MultiPartRequestWrapper extends StrutsRequestWrapper {
|
||||
* @param fieldName input field name
|
||||
* @return a File[] object for files associated with the specified input field name
|
||||
*/
|
||||
public File[] getFiles(String fieldName) {
|
||||
public UploadedFile[] getFiles(String fieldName) {
|
||||
if (multi == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -234,7 +235,7 @@ public class MultiPartRequestWrapper extends StrutsRequestWrapper {
|
||||
*
|
||||
* @return the error Collection.
|
||||
*/
|
||||
public Collection<String> getErrors() {
|
||||
public Collection<LocalizedMessage> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
@@ -243,7 +244,7 @@ public class MultiPartRequestWrapper extends StrutsRequestWrapper {
|
||||
*
|
||||
* @param anErrorMessage the error message to report.
|
||||
*/
|
||||
protected void addError(String anErrorMessage) {
|
||||
protected void addError(LocalizedMessage anErrorMessage) {
|
||||
if (!errors.contains(anErrorMessage)) {
|
||||
errors.add(anErrorMessage);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.struts2.dispatcher.multipart;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class StrutsUploadedFile implements UploadedFile {
|
||||
|
||||
private File file;
|
||||
|
||||
public StrutsUploadedFile(File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long length() {
|
||||
return file.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return file.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
return file.isFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete() {
|
||||
return file.delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAbsolutePath() {
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getContent() {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.struts2.dispatcher.multipart;
|
||||
|
||||
/**
|
||||
* Virtual representation of a uploaded file used by {@link MultiPartRequest}
|
||||
*/
|
||||
public interface UploadedFile {
|
||||
|
||||
Long length();
|
||||
|
||||
String getName();
|
||||
|
||||
boolean isFile();
|
||||
|
||||
boolean delete();
|
||||
|
||||
String getAbsolutePath();
|
||||
|
||||
Object getContent();
|
||||
|
||||
}
|
||||
@@ -63,7 +63,7 @@ public class CheckboxInterceptor extends AbstractInterceptor {
|
||||
HttpParameters parameters = ai.getInvocationContext().getParameters();
|
||||
Map<String, Parameter> extraParams = new HashMap<>();
|
||||
|
||||
for (String name : parameters.getNames()) {
|
||||
for (String name : parameters.keySet()) {
|
||||
if (name.startsWith("__checkbox_")) {
|
||||
String checkboxName = name.substring("__checkbox_".length());
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
@@ -12,7 +12,7 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class DateTextFieldInterceptor implements Interceptor {
|
||||
public class DateTextFieldInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(DateTextFieldInterceptor.class);
|
||||
|
||||
@@ -56,12 +56,6 @@ public class DateTextFieldInterceptor implements Interceptor {
|
||||
return values();
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
public void init() {
|
||||
}
|
||||
|
||||
public String intercept(ActionInvocation ai) throws Exception {
|
||||
HttpParameters parameters = ai.getInvocationContext().getParameters();
|
||||
@@ -70,7 +64,7 @@ public class DateTextFieldInterceptor implements Interceptor {
|
||||
DateWord[] dateWords = DateWord.getAll();
|
||||
|
||||
// Get all the values of date type
|
||||
Set<String> names = parameters.getNames();
|
||||
Set<String> names = parameters.keySet();
|
||||
for (String name : names) {
|
||||
|
||||
for (DateWord dateWord : dateWords) {
|
||||
|
||||
@@ -26,12 +26,15 @@ import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import com.opensymphony.xwork2.util.LocalizedTextUtil;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.dispatcher.LocalizedMessage;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
|
||||
import org.apache.struts2.dispatcher.multipart.UploadedFile;
|
||||
import org.apache.struts2.util.ContentTypeMatcher;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -256,9 +259,9 @@ public class FileUploadInterceptor extends AbstractInterceptor {
|
||||
MultiPartRequestWrapper multiWrapper = (MultiPartRequestWrapper) request;
|
||||
|
||||
if (multiWrapper.hasErrors()) {
|
||||
for (String error : multiWrapper.getErrors()) {
|
||||
for (LocalizedMessage error : multiWrapper.getErrors()) {
|
||||
if (validation != null) {
|
||||
validation.addActionError(error);
|
||||
validation.addActionError(LocalizedTextUtil.findText(error.getClazz(), error.getTextKey(), ActionContext.getContext().getLocale(), error.getDefaultMessage(), error.getArgs()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,9 +281,9 @@ public class FileUploadInterceptor extends AbstractInterceptor {
|
||||
|
||||
if (isNonEmpty(fileName)) {
|
||||
// get a File object for the uploaded File
|
||||
File[] files = multiWrapper.getFiles(inputName);
|
||||
UploadedFile[] files = multiWrapper.getFiles(inputName);
|
||||
if (files != null && files.length > 0) {
|
||||
List<File> acceptedFiles = new ArrayList<>(files.length);
|
||||
List<UploadedFile> acceptedFiles = new ArrayList<>(files.length);
|
||||
List<String> acceptedContentTypes = new ArrayList<>(files.length);
|
||||
List<String> acceptedFileNames = new ArrayList<>(files.length);
|
||||
String contentTypeName = inputName + "ContentType";
|
||||
@@ -296,7 +299,7 @@ public class FileUploadInterceptor extends AbstractInterceptor {
|
||||
|
||||
if (!acceptedFiles.isEmpty()) {
|
||||
Map<String, Parameter> newParams = new HashMap<>();
|
||||
newParams.put(inputName, new Parameter.File(inputName, acceptedFiles.toArray(new File[acceptedFiles.size()])));
|
||||
newParams.put(inputName, new Parameter.File(inputName, acceptedFiles.toArray(new UploadedFile[acceptedFiles.size()])));
|
||||
newParams.put(contentTypeName, new Parameter.File(contentTypeName, acceptedContentTypes.toArray(new String[acceptedContentTypes.size()])));
|
||||
newParams.put(fileNameName, new Parameter.File(fileNameName, acceptedFileNames.toArray(new String[acceptedFileNames.size()])));
|
||||
ac.getParameters().appendAll(newParams);
|
||||
@@ -330,7 +333,7 @@ public class FileUploadInterceptor extends AbstractInterceptor {
|
||||
* logging.
|
||||
* @return true if the proposed file is acceptable by contentType and size.
|
||||
*/
|
||||
protected boolean acceptFile(Object action, File file, String filename, String contentType, String inputName, ValidationAware validation) {
|
||||
protected boolean acceptFile(Object action, UploadedFile file, String filename, String contentType, String inputName, ValidationAware validation) {
|
||||
boolean fileIsAcceptable = false;
|
||||
|
||||
// If it's null the upload failed
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.LocaleProvider;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
@@ -28,93 +27,48 @@ import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import com.opensymphony.xwork2.util.LocalizedTextUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsStatics;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
* <p>
|
||||
* An interceptor that handles setting the locale specified in a session as the locale for the current action request.
|
||||
* In addition, this interceptor will look for a specific HTTP request parameter and set the locale to whatever value is
|
||||
* provided, it also looks for specific cookie to read locale from. This means that this interceptor can be used to allow
|
||||
* for your application to dynamically change the locale for the user's session or, alternatively, only for the current
|
||||
* request (since XWork 2.1.3).
|
||||
* This is very useful for applications that require multi-lingual support and want the user to
|
||||
* be able to set his or her language preference at any point. The locale parameter is removed during the execution of
|
||||
* this interceptor, ensuring that properties aren't set on an action (such as request_locale) that have no typical
|
||||
* corresponding setter in your action.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* For example, using the default parameter name, a request to <b>foo.action?request_locale=en_US</b>, then the
|
||||
* locale for US English is saved in the user's session and will be used for all future requests.
|
||||
* If there is no locale set (for example with the first visit), the interceptor uses the browser locale.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <!-- START SNIPPET: parameters -->
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li>parameterName (optional) - the name of the HTTP request parameter that dictates the locale to switch to and save
|
||||
* in the session. By default this is <b>request_locale</b></li>
|
||||
*
|
||||
* <li>requestCookieParameterName (optional) - the name of the HTTP request parameter that dictates the locale to switch to
|
||||
* and save in a cookien. By default this is <b>request_cookie_locale</b></li>
|
||||
*
|
||||
* <li>requestOnlyParameterName (optional) - the name of the HTTP request parameter that dictates the locale to switch to
|
||||
* for the current request only, without saving it in the session. By default this is <b>request_only_locale</b></li>
|
||||
*
|
||||
* <li>attributeName (optional) - the name of the session key to store the selected locale. By default this is
|
||||
* <b>WW_TRANS_I18N_LOCALE</b></li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <!-- END SNIPPET: parameters -->
|
||||
*
|
||||
* <!-- START SNIPPET: example -->
|
||||
* <interceptor name="i18nCookie" class="org.apache.struts2.interceptor.I18nInterceptor"/>
|
||||
*
|
||||
* <action name="someAction" class="com.examples.SomeAction">
|
||||
* <interceptor-ref name="i18nCookie"/>
|
||||
* <interceptor-ref name="basicStack"/>
|
||||
* <result name="success">good_result.ftl</result>
|
||||
* </action>
|
||||
* <!-- END SNIPPET: example -->
|
||||
*/
|
||||
*/
|
||||
public class I18nInterceptor extends AbstractInterceptor {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(I18nInterceptor.class);
|
||||
|
||||
public static final String DEFAULT_SESSION_ATTRIBUTE = "WW_TRANS_I18N_LOCALE";
|
||||
public static final String DEFAULT_PARAMETER = "request_locale";
|
||||
public static final String DEFAULT_REQUESTONLY_PARAMETER = "request_only_locale";
|
||||
public static final String DEFAULT_REQUEST_ONLY_PARAMETER = "request_only_locale";
|
||||
public static final String DEFAULT_COOKIE_ATTRIBUTE = DEFAULT_SESSION_ATTRIBUTE;
|
||||
public static final String DEFAULT_COOKIE_PARAMETER = "request_cookie_locale";
|
||||
|
||||
protected String parameterName = DEFAULT_PARAMETER;
|
||||
protected String requestOnlyParameterName = DEFAULT_REQUESTONLY_PARAMETER;
|
||||
protected String requestOnlyParameterName = DEFAULT_REQUEST_ONLY_PARAMETER;
|
||||
protected String attributeName = DEFAULT_SESSION_ATTRIBUTE;
|
||||
protected String requestCookieParameterName = DEFAULT_COOKIE_PARAMETER;
|
||||
protected Storage storage = Storage.SESSION;
|
||||
|
||||
protected LocaleProvider localeProvider;
|
||||
|
||||
// Request-Only = None
|
||||
protected enum Storage { COOKIE, SESSION, NONE }
|
||||
|
||||
protected String requestCookieParameterName = DEFAULT_COOKIE_PARAMETER;
|
||||
|
||||
public void setParameterName(String parameterName) {
|
||||
this.parameterName = parameterName;
|
||||
}
|
||||
|
||||
public void setAttributeName(String attributeName) {
|
||||
this.attributeName = attributeName;
|
||||
}
|
||||
|
||||
public void setRequestOnlyParameterName(String requestOnlyParameterName) {
|
||||
this.requestOnlyParameterName = requestOnlyParameterName;
|
||||
}
|
||||
@@ -123,8 +77,17 @@ public class I18nInterceptor extends AbstractInterceptor {
|
||||
this.requestCookieParameterName = requestCookieParameterName;
|
||||
}
|
||||
|
||||
public void setAttributeName(String attributeName) {
|
||||
this.attributeName = attributeName;
|
||||
public void setLocaleStorage(String storageName) {
|
||||
if (storageName == null || "".equals(storageName)) {
|
||||
this.storage = Storage.NONE;
|
||||
} else {
|
||||
try {
|
||||
this.storage = Storage.valueOf(storageName.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warn(new ParameterizedMessage("Wrong storage name [{}] was defined, falling back to {}", storageName, Storage.SESSION), e);
|
||||
this.storage = Storage.SESSION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
@@ -134,94 +97,53 @@ public class I18nInterceptor extends AbstractInterceptor {
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("intercept '{}/{}' {",
|
||||
invocation.getProxy().getNamespace(), invocation.getProxy().getActionName());
|
||||
LOG.debug("Intercept '{}/{}'", invocation.getProxy().getNamespace(), invocation.getProxy().getActionName());
|
||||
|
||||
LocaleHandler localeHandler = getLocaleHandler(invocation);
|
||||
Locale locale = localeHandler.find();
|
||||
|
||||
if (locale == null) {
|
||||
locale = localeHandler.read(invocation);
|
||||
}
|
||||
|
||||
LocaleFinder localeFinder = new CookieLocaleFinder(invocation);
|
||||
Locale locale = getLocaleFromParam(localeFinder.getRequestedLocale());
|
||||
locale = storeLocale(invocation, locale, localeFinder.getStorage());
|
||||
saveLocale(invocation, locale);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("before Locale={}", invocation.getStack().findValue("locale"));
|
||||
if (localeHandler.shouldStore()) {
|
||||
locale = localeHandler.store(invocation, locale);
|
||||
}
|
||||
|
||||
final String result = invocation.invoke();
|
||||
useLocale(invocation, locale);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("after Locale={}", invocation.getStack().findValue("locale"));
|
||||
LOG.debug("intercept } ");
|
||||
LOG.debug("Before action invocation Locale={}", invocation.getStack().findValue("locale"));
|
||||
}
|
||||
|
||||
return result;
|
||||
try {
|
||||
return invocation.invoke();
|
||||
} finally {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("After action invocation Locale={}", invocation.getStack().findValue("locale"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the locale to the chosen storage, like f. e. the session
|
||||
* Override this method to use your own implementation of {@link LocaleHandler}
|
||||
*
|
||||
* @param invocation the action invocation
|
||||
* @param locale the locale to store
|
||||
* @param storage the place to store this locale (like Storage.SESSSION)
|
||||
*
|
||||
* @return the locale
|
||||
* @param invocation current action invocation context
|
||||
* @return instance of {@link LocaleHandler}
|
||||
*/
|
||||
protected Locale storeLocale(ActionInvocation invocation, Locale locale, Storage storage) {
|
||||
if (storage == Storage.COOKIE) {
|
||||
ActionContext ac = invocation.getInvocationContext();
|
||||
HttpServletResponse response = (HttpServletResponse) ac.get(StrutsStatics.HTTP_RESPONSE);
|
||||
protected LocaleHandler getLocaleHandler(ActionInvocation invocation) {
|
||||
LocaleHandler localeHandler;
|
||||
|
||||
Cookie cookie = new Cookie(DEFAULT_COOKIE_ATTRIBUTE, locale.toString());
|
||||
cookie.setMaxAge(1209600); // two weeks
|
||||
response.addCookie(cookie);
|
||||
|
||||
storage = Storage.SESSION;
|
||||
if (this.storage == Storage.COOKIE) {
|
||||
localeHandler = new CookieLocaleHandler(invocation);
|
||||
} else if (this.storage == Storage.SESSION) {
|
||||
localeHandler = new SessionLocaleHandler(invocation);
|
||||
} else {
|
||||
localeHandler = new RequestOnlyLocaleHandler(invocation);
|
||||
}
|
||||
|
||||
//save it in session
|
||||
Map<String, Object> session = invocation.getInvocationContext().getSession();
|
||||
|
||||
if (session != null) {
|
||||
synchronized (session) {
|
||||
if (locale == null) {
|
||||
storage = Storage.NONE;
|
||||
locale = readStoredLocale(invocation, session);
|
||||
}
|
||||
|
||||
if (Storage.SESSION == storage) {
|
||||
session.put(attributeName, locale);
|
||||
}
|
||||
}
|
||||
}
|
||||
return locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the locale from the session, and if not found from the
|
||||
* current invocation (=browser)
|
||||
*
|
||||
* @param invocation the current invocation
|
||||
* @param session the current session
|
||||
* @return the read locale
|
||||
*/
|
||||
protected Locale readStoredLocale(ActionInvocation invocation, Map<String, Object> session) {
|
||||
Locale locale = this.readStoredLocalFromSession(invocation, session);
|
||||
|
||||
if (locale != null) {
|
||||
return locale;
|
||||
}
|
||||
|
||||
Cookie[] cookies = ServletActionContext.getRequest().getCookies();
|
||||
if (cookies != null) {
|
||||
for (Cookie cookie : cookies) {
|
||||
if (DEFAULT_COOKIE_ATTRIBUTE.equals(cookie.getName())) {
|
||||
return getLocaleFromParam(cookie.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.readStoredLocalFromCurrentInvocation(invocation);
|
||||
LOG.debug("Using LocaleFinder implementation {}", localeHandler.getClass().getName());
|
||||
return localeHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,7 +165,7 @@ public class I18nInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
}
|
||||
if (locale != null) {
|
||||
LOG.debug("Applied request locale: {}", locale);
|
||||
LOG.debug("Found locale: {}", locale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,27 +178,8 @@ public class I18nInterceptor extends AbstractInterceptor {
|
||||
return locale;
|
||||
}
|
||||
|
||||
protected Locale readStoredLocalFromSession(ActionInvocation invocation, Map<String, Object> session) {
|
||||
// check session for saved locale
|
||||
Object sessionLocale = session.get(attributeName);
|
||||
if (sessionLocale != null && sessionLocale instanceof Locale) {
|
||||
Locale locale = (Locale) sessionLocale;
|
||||
LOG.debug("Applied session locale: {}", locale);
|
||||
return locale;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Locale readStoredLocalFromCurrentInvocation(ActionInvocation invocation) {
|
||||
// no overriding locale definition found, stay with current invocation (=browser) locale
|
||||
Locale locale = invocation.getInvocationContext().getLocale();
|
||||
if (locale != null) {
|
||||
LOG.debug("Applied invocation context locale: {}", locale);
|
||||
}
|
||||
return locale;
|
||||
}
|
||||
|
||||
protected Parameter findLocaleParameter(HttpParameters params, String parameterName) {
|
||||
protected Parameter findLocaleParameter(ActionInvocation invocation, String parameterName) {
|
||||
HttpParameters params = invocation.getInvocationContext().getParameters();
|
||||
Parameter requestedLocale = params.get(parameterName);
|
||||
params.remove(parameterName);
|
||||
if (requestedLocale.isDefined()) {
|
||||
@@ -291,75 +194,185 @@ public class I18nInterceptor extends AbstractInterceptor {
|
||||
* @param invocation The ActionInvocation.
|
||||
* @param locale The locale to save.
|
||||
*/
|
||||
protected void saveLocale(ActionInvocation invocation, Locale locale) {
|
||||
protected void useLocale(ActionInvocation invocation, Locale locale) {
|
||||
invocation.getInvocationContext().setLocale(locale);
|
||||
}
|
||||
|
||||
protected class LocaleFinder {
|
||||
protected Storage storage = Storage.SESSION;
|
||||
protected Parameter requestedLocale = null;
|
||||
/**
|
||||
* Uses to handle reading/storing Locale from/in different locations
|
||||
*/
|
||||
protected interface LocaleHandler {
|
||||
Locale find();
|
||||
Locale read(ActionInvocation invocation);
|
||||
Locale store(ActionInvocation invocation, Locale locale);
|
||||
boolean shouldStore();
|
||||
}
|
||||
|
||||
protected class RequestOnlyLocaleHandler implements LocaleHandler {
|
||||
|
||||
protected ActionInvocation actionInvocation = null;
|
||||
protected boolean shouldStore = true;
|
||||
|
||||
protected LocaleFinder(ActionInvocation invocation) {
|
||||
protected RequestOnlyLocaleHandler(ActionInvocation invocation) {
|
||||
actionInvocation = invocation;
|
||||
find();
|
||||
}
|
||||
|
||||
protected void find() {
|
||||
//get requested locale
|
||||
HttpParameters params = actionInvocation.getInvocationContext().getParameters();
|
||||
public Locale find() {
|
||||
LOG.debug("Searching locale in request under parameter {}", requestOnlyParameterName);
|
||||
|
||||
storage = Storage.SESSION;
|
||||
|
||||
requestedLocale = findLocaleParameter(params, parameterName);
|
||||
Parameter requestedLocale = findLocaleParameter(actionInvocation, requestOnlyParameterName);
|
||||
if (requestedLocale.isDefined()) {
|
||||
return;
|
||||
return getLocaleFromParam(requestedLocale.getValue());
|
||||
}
|
||||
|
||||
requestedLocale = findLocaleParameter(params, requestOnlyParameterName);
|
||||
if (requestedLocale.isDefined()) {
|
||||
storage = Storage.NONE;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale store(ActionInvocation invocation, Locale locale) {
|
||||
return locale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale read(ActionInvocation invocation) {
|
||||
LOG.debug("Searching current Invocation context");
|
||||
// no overriding locale definition found, stay with current invocation (=browser) locale
|
||||
Locale locale = invocation.getInvocationContext().getLocale();
|
||||
if (locale != null) {
|
||||
LOG.debug("Applied invocation context locale: {}", locale);
|
||||
}
|
||||
return locale;
|
||||
}
|
||||
|
||||
public Storage getStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
public String getRequestedLocale() {
|
||||
return requestedLocale.getValue();
|
||||
@Override
|
||||
public boolean shouldStore() {
|
||||
return shouldStore;
|
||||
}
|
||||
}
|
||||
|
||||
protected class CookieLocaleFinder extends LocaleFinder {
|
||||
protected CookieLocaleFinder(ActionInvocation invocation) {
|
||||
protected class SessionLocaleHandler extends RequestOnlyLocaleHandler {
|
||||
|
||||
protected SessionLocaleHandler(ActionInvocation invocation) {
|
||||
super(invocation);
|
||||
}
|
||||
|
||||
public Locale find() {
|
||||
Locale requestOnlyLocale = super.find();
|
||||
|
||||
if (requestOnlyLocale != null) {
|
||||
LOG.debug("Found locale under request only param, it won't be stored in session!");
|
||||
shouldStore = false;
|
||||
return requestOnlyLocale;
|
||||
}
|
||||
|
||||
LOG.debug("Searching locale in request under parameter {}", parameterName);
|
||||
Parameter requestedLocale = findLocaleParameter(actionInvocation, parameterName);
|
||||
if (requestedLocale.isDefined()) {
|
||||
return getLocaleFromParam(requestedLocale.getValue());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale store(ActionInvocation invocation, Locale locale) {
|
||||
//save it in session
|
||||
Map<String, Object> session = invocation.getInvocationContext().getSession();
|
||||
|
||||
if (session != null) {
|
||||
String sessionId = ServletActionContext.getRequest().getSession().getId();
|
||||
synchronized (sessionId.intern()) {
|
||||
session.put(attributeName, locale);
|
||||
}
|
||||
}
|
||||
return locale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale read(ActionInvocation invocation) {
|
||||
Locale locale = null;
|
||||
|
||||
LOG.debug("Checks session for saved locale");
|
||||
Map<String, Object> session = invocation.getInvocationContext().getSession();
|
||||
|
||||
if (session != null) {
|
||||
String sessionId = ServletActionContext.getRequest().getSession().getId();
|
||||
synchronized (sessionId.intern()) {
|
||||
Object sessionLocale = session.get(attributeName);
|
||||
if (sessionLocale != null && sessionLocale instanceof Locale) {
|
||||
locale = (Locale) sessionLocale;
|
||||
LOG.debug("Applied session locale: {}", locale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (locale == null) {
|
||||
LOG.debug("No Locale defined in session, fetching from current request and it won't be stored in session!");
|
||||
shouldStore = false;
|
||||
locale = super.read(invocation);
|
||||
} else {
|
||||
LOG.debug("Found stored Locale {} in session, using it!", locale);
|
||||
}
|
||||
|
||||
return locale;
|
||||
}
|
||||
}
|
||||
|
||||
protected class CookieLocaleHandler extends RequestOnlyLocaleHandler {
|
||||
protected CookieLocaleHandler(ActionInvocation invocation) {
|
||||
super(invocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void find() {
|
||||
//get requested locale
|
||||
HttpParameters params = actionInvocation.getInvocationContext().getParameters();
|
||||
storage = Storage.SESSION;
|
||||
public Locale find() {
|
||||
Locale requestOnlySessionLocale = super.find();
|
||||
|
||||
requestedLocale = findLocaleParameter(params, parameterName);
|
||||
|
||||
if (requestedLocale.isDefined()) {
|
||||
return;
|
||||
if (requestOnlySessionLocale != null) {
|
||||
shouldStore = false;
|
||||
return requestOnlySessionLocale;
|
||||
}
|
||||
|
||||
requestedLocale = findLocaleParameter(params, requestCookieParameterName);
|
||||
LOG.debug("Searching locale in request under parameter {}", requestCookieParameterName);
|
||||
Parameter requestedLocale = findLocaleParameter(actionInvocation, requestCookieParameterName);
|
||||
if (requestedLocale.isDefined()) {
|
||||
storage = Storage.COOKIE;
|
||||
return;
|
||||
return getLocaleFromParam(requestedLocale.getValue());
|
||||
}
|
||||
|
||||
requestedLocale = findLocaleParameter(params, requestOnlyParameterName);
|
||||
if (requestedLocale.isDefined()) {
|
||||
storage = Storage.NONE;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale store(ActionInvocation invocation, Locale locale) {
|
||||
HttpServletResponse response = ServletActionContext.getResponse();
|
||||
|
||||
Cookie cookie = new Cookie(attributeName, locale.toString());
|
||||
cookie.setMaxAge(1209600); // two weeks
|
||||
response.addCookie(cookie);
|
||||
|
||||
return locale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale read(ActionInvocation invocation) {
|
||||
Locale locale = null;
|
||||
|
||||
Cookie[] cookies = ServletActionContext.getRequest().getCookies();
|
||||
if (cookies != null) {
|
||||
for (Cookie cookie : cookies) {
|
||||
if (attributeName.equals(cookie.getName())) {
|
||||
locale = getLocaleFromParam(cookie.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (locale == null) {
|
||||
LOG.debug("No Locale defined in cookie, fetching from current request and it won't be stored!");
|
||||
shouldStore = false;
|
||||
locale = super.read(invocation);
|
||||
} else {
|
||||
LOG.debug("Found stored Locale {} in cookie, using it!", locale);
|
||||
}
|
||||
return locale;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,10 @@ public class MessageStoreInterceptor extends AbstractInterceptor {
|
||||
before(invocation);
|
||||
|
||||
LOG.trace("Registering listener to store messages before result will be executed");
|
||||
invocation.addPreResultListener(new MessageStorePreResultListener(this));
|
||||
MessageStorePreResultListener preResultListener = createPreResultListener(invocation);
|
||||
preResultListener.init(this);
|
||||
|
||||
invocation.addPreResultListener(preResultListener);
|
||||
|
||||
String result = invocation.invoke();
|
||||
|
||||
@@ -212,6 +215,10 @@ public class MessageStoreInterceptor extends AbstractInterceptor {
|
||||
return result;
|
||||
}
|
||||
|
||||
protected MessageStorePreResultListener createPreResultListener(ActionInvocation invocation) {
|
||||
return new MessageStorePreResultListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the retrieving of field errors / action messages / field errors, which is
|
||||
* done before action invocation, and the <code>operationMode</code> is 'RETRIEVE'.
|
||||
|
||||
+29
-17
@@ -26,8 +26,7 @@ import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.result.ServletActionRedirectResult;
|
||||
import org.apache.struts2.result.ServletRedirectResult;
|
||||
import org.apache.struts2.result.Redirectable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -36,26 +35,25 @@ import java.util.Map;
|
||||
* just before result will be executed. It must be done that way as after result will be executed
|
||||
* HttpSession cannot be modified (response was already sent to browser).
|
||||
*/
|
||||
class MessageStorePreResultListener implements PreResultListener {
|
||||
public class MessageStorePreResultListener implements PreResultListener {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(MessageStorePreResultListener.class);
|
||||
|
||||
private MessageStoreInterceptor interceptor;
|
||||
protected MessageStoreInterceptor interceptor;
|
||||
|
||||
public MessageStorePreResultListener(MessageStoreInterceptor interceptor) {
|
||||
public void init(MessageStoreInterceptor interceptor) {
|
||||
this.interceptor = interceptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeResult(ActionInvocation invocation, String resultCode) {
|
||||
|
||||
boolean isCommitted = ServletActionContext.getResponse().isCommitted();
|
||||
boolean isCommitted = isCommitted();
|
||||
if (isCommitted) {
|
||||
LOG.trace("Response was already committed, cannot store messages!");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isInvalidated = ServletActionContext.getRequest().getSession(false) == null;
|
||||
boolean isInvalidated = isInvalidated();
|
||||
if (isInvalidated) {
|
||||
LOG.trace("Session was invalidated or never created, cannot store messages!");
|
||||
return;
|
||||
@@ -69,15 +67,7 @@ class MessageStorePreResultListener implements PreResultListener {
|
||||
|
||||
String reqOperationMode = interceptor.getRequestOperationMode(invocation);
|
||||
|
||||
boolean isRedirect = false;
|
||||
try {
|
||||
ResultConfig resultConfig = invocation.getProxy().getConfig().getResults().get(resultCode);
|
||||
if (resultConfig != null) {
|
||||
isRedirect = ServletRedirectResult.class.isAssignableFrom(Class.forName(resultConfig.getClassName()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Cannot read result!", e);
|
||||
}
|
||||
boolean isRedirect = isRedirect(invocation, resultCode);
|
||||
|
||||
if (MessageStoreInterceptor.STORE_MODE.equalsIgnoreCase(reqOperationMode) ||
|
||||
MessageStoreInterceptor.STORE_MODE.equalsIgnoreCase(interceptor.getOperationModel()) ||
|
||||
@@ -97,4 +87,26 @@ class MessageStorePreResultListener implements PreResultListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isCommitted() {
|
||||
return ServletActionContext.getResponse().isCommitted();
|
||||
}
|
||||
|
||||
protected boolean isInvalidated() {
|
||||
return ServletActionContext.getRequest().getSession(false) == null;
|
||||
}
|
||||
|
||||
protected boolean isRedirect(ActionInvocation invocation, String resultCode) {
|
||||
boolean isRedirect = false;
|
||||
try {
|
||||
ResultConfig resultConfig = invocation.getProxy().getConfig().getResults().get(resultCode);
|
||||
if (resultConfig != null) {
|
||||
isRedirect = Redirectable.class.isAssignableFrom(Class.forName(resultConfig.getClassName()));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Cannot read result!", e);
|
||||
}
|
||||
return isRedirect;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ public class MultiselectInterceptor extends AbstractInterceptor {
|
||||
HttpParameters parameters = ai.getInvocationContext().getParameters();
|
||||
Map<String, Parameter> newParams = new HashMap<>();
|
||||
|
||||
for (String name : parameters.getNames()) {
|
||||
for (String name : parameters.keySet()) {
|
||||
if (name.startsWith("__multiselect_")) {
|
||||
String key = name.substring("__multiselect_".length());
|
||||
|
||||
|
||||
+4
-3
@@ -27,6 +27,7 @@ import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import com.opensymphony.xwork2.util.profiling.UtilTimerStack;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.dispatcher.Parameter;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
@@ -93,9 +94,9 @@ public class ProfilingActivationInterceptor extends AbstractInterceptor {
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
if (devMode) {
|
||||
Object val = invocation.getInvocationContext().getParameters().get(profilingKey);
|
||||
if (val != null) {
|
||||
String sval = (val instanceof String ? (String)val : ((String[])val)[0]);
|
||||
Parameter val = invocation.getInvocationContext().getParameters().get(profilingKey);
|
||||
if (val.isDefined()) {
|
||||
String sval = val.getValue();
|
||||
boolean enable = BooleanUtils.toBoolean(sval);
|
||||
UtilTimerStack.setActive(enable);
|
||||
invocation.getInvocationContext().getParameters().remove(profilingKey);
|
||||
|
||||
@@ -299,7 +299,7 @@ public class ScopeInterceptor extends AbstractInterceptor implements PreResultLi
|
||||
}
|
||||
}
|
||||
|
||||
if (ActionContext.getContext().getParameters().get(sessionReset) != null) {
|
||||
if (ActionContext.getContext().getParameters().get(sessionReset).isDefined()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ public class ServletConfigInterceptor extends AbstractInterceptor implements Str
|
||||
}
|
||||
|
||||
if (action instanceof ParameterAware) {
|
||||
((ParameterAware) action).setParameters(context.getParameters().toMap());
|
||||
context.getParameters().applyParameters((ParameterAware) action);
|
||||
}
|
||||
|
||||
if (action instanceof HttpParametersAware) {
|
||||
|
||||
@@ -26,6 +26,8 @@ import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.util.TokenHelper;
|
||||
|
||||
@@ -116,7 +118,7 @@ import javax.servlet.http.HttpSession;
|
||||
*/
|
||||
public class TokenInterceptor extends MethodFilterInterceptor {
|
||||
|
||||
private static final long serialVersionUID = -6680894220590585506L;
|
||||
private static final Logger LOG = LogManager.getLogger(TokenInterceptor.class);
|
||||
|
||||
public static final String INVALID_TOKEN_CODE = "invalid.token";
|
||||
|
||||
@@ -135,7 +137,7 @@ public class TokenInterceptor extends MethodFilterInterceptor {
|
||||
*/
|
||||
@Override
|
||||
protected String doIntercept(ActionInvocation invocation) throws Exception {
|
||||
log.debug("Intercepting invocation to check for valid transaction token.");
|
||||
LOG.debug("Intercepting invocation to check for valid transaction token.");
|
||||
return handleToken(invocation);
|
||||
}
|
||||
|
||||
@@ -143,7 +145,7 @@ public class TokenInterceptor extends MethodFilterInterceptor {
|
||||
//see WW-2902: we need to use the real HttpSession here, as opposed to the map
|
||||
//that wraps the session, because a new wrap is created on every request
|
||||
HttpSession session = ServletActionContext.getRequest().getSession(true);
|
||||
synchronized (session) {
|
||||
synchronized (session.getId().intern()) {
|
||||
if (!TokenHelper.validToken()) {
|
||||
return handleInvalidToken(invocation);
|
||||
}
|
||||
@@ -165,7 +167,7 @@ public class TokenInterceptor extends MethodFilterInterceptor {
|
||||
if (action instanceof ValidationAware) {
|
||||
((ValidationAware) action).addActionError(errorMessage);
|
||||
} else {
|
||||
log.warn(errorMessage);
|
||||
LOG.warn(errorMessage);
|
||||
}
|
||||
|
||||
return INVALID_TOKEN_CODE;
|
||||
|
||||
+16
-9
@@ -22,10 +22,13 @@
|
||||
package org.apache.struts2.interceptor.validation;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.AnnotationUtils;
|
||||
import com.opensymphony.xwork2.validator.ValidationInterceptor;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
@@ -38,19 +41,20 @@ import java.util.Collection;
|
||||
*/
|
||||
public class AnnotationValidationInterceptor extends ValidationInterceptor {
|
||||
|
||||
/** Auto-generated serialization id */
|
||||
private static final long serialVersionUID = 1813272797367431184L;
|
||||
private static final Logger LOG = LogManager.getLogger(AnnotationValidationInterceptor.class);
|
||||
|
||||
protected String doIntercept(ActionInvocation invocation) throws Exception {
|
||||
|
||||
Object action = invocation.getAction();
|
||||
if (action != null) {
|
||||
Method method = getActionMethod(action.getClass(), invocation.getProxy().getMethod());
|
||||
Collection<Method> annotatedMethods = AnnotationUtils.getAnnotatedMethods(action.getClass(), SkipValidation.class);
|
||||
if (annotatedMethods.contains(method))
|
||||
return invocation.invoke();
|
||||
|
||||
//check if method overwites an annotated method
|
||||
Collection<Method> annotatedMethods = AnnotationUtils.getAnnotatedMethods(action.getClass(), SkipValidation.class);
|
||||
if (annotatedMethods.contains(method)) {
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
LOG.debug("Check if method overrides an annotated method");
|
||||
Class clazz = action.getClass().getSuperclass();
|
||||
while (clazz != null) {
|
||||
annotatedMethods = AnnotationUtils.getAnnotatedMethods(clazz, SkipValidation.class);
|
||||
@@ -69,9 +73,12 @@ public class AnnotationValidationInterceptor extends ValidationInterceptor {
|
||||
return super.doIntercept(invocation);
|
||||
}
|
||||
|
||||
// FIXME: This is copied from DefaultActionInvocation but should be exposed through the interface
|
||||
protected Method getActionMethod(Class<?> actionClass, String methodName) throws NoSuchMethodException {
|
||||
return actionClass.getMethod(methodName);
|
||||
protected Method getActionMethod(Class<?> actionClass, String methodName) {
|
||||
try {
|
||||
return actionClass.getMethod(methodName);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new ConfigurationException("Wrong method was defined as an action method: " + methodName, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.apache.struts2.result;
|
||||
|
||||
/**
|
||||
* Marking interface for results which perform browser redirection
|
||||
*/
|
||||
public interface Redirectable {
|
||||
|
||||
}
|
||||
@@ -123,7 +123,7 @@ import java.util.List;
|
||||
*
|
||||
* @see ActionMapper
|
||||
*/
|
||||
public class ServletActionRedirectResult extends ServletRedirectResult implements ReflectionExceptionHandler {
|
||||
public class ServletActionRedirectResult extends ServletRedirectResult implements ReflectionExceptionHandler, Redirectable {
|
||||
|
||||
private static final long serialVersionUID = -9042425229314584066L;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsStatics;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
import org.apache.struts2.views.util.UrlHelper;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
@@ -142,14 +143,17 @@ public class ServletDispatcherResult extends StrutsResultSupport {
|
||||
// see WW-2120
|
||||
if (StringUtils.isNotEmpty(finalLocation) && finalLocation.indexOf("?") > 0) {
|
||||
String queryString = finalLocation.substring(finalLocation.indexOf("?") + 1);
|
||||
Map<String, Object> parameters = getParameters(invocation);
|
||||
HttpParameters parameters = getParameters(invocation);
|
||||
Map<String, Object> queryParams = urlHelper.parseQueryString(queryString, true);
|
||||
if (queryParams != null && !queryParams.isEmpty())
|
||||
parameters.putAll(queryParams);
|
||||
if (queryParams != null && !queryParams.isEmpty()) {
|
||||
parameters = HttpParameters.create(queryParams).withParent(parameters).build();
|
||||
invocation.getInvocationContext().setParameters(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
// if the view doesn't exist, let's do a 404
|
||||
if (dispatcher == null) {
|
||||
LOG.warn("Location {} not found!", finalLocation);
|
||||
response.sendError(404, "result '" + finalLocation + "' not found");
|
||||
return;
|
||||
}
|
||||
@@ -171,9 +175,8 @@ public class ServletDispatcherResult extends StrutsResultSupport {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> getParameters(ActionInvocation invocation) {
|
||||
return (Map<String, Object>) invocation.getInvocationContext().getContextMap().get("parameters");
|
||||
protected HttpParameters getParameters(ActionInvocation invocation) {
|
||||
return invocation.getInvocationContext().getParameters();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ import static javax.servlet.http.HttpServletResponse.SC_FOUND;
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
public class ServletRedirectResult extends StrutsResultSupport implements ReflectionExceptionHandler {
|
||||
public class ServletRedirectResult extends StrutsResultSupport implements ReflectionExceptionHandler, Redirectable {
|
||||
|
||||
private static final long serialVersionUID = 6316947346435301270L;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ package org.apache.struts2.util;
|
||||
|
||||
import com.opensymphony.xwork2.TextProvider;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -48,7 +49,7 @@ public class TextProviderHelper {
|
||||
* @return the message if found, otherwise the defaultMessage
|
||||
*/
|
||||
public static String getText(String key, String defaultMessage, List<Object> args, ValueStack stack) {
|
||||
return getText(key, defaultMessage, args, stack, true);
|
||||
return getText(key, defaultMessage, args, stack, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,6 +87,9 @@ public class TextProviderHelper {
|
||||
if (msg == null) {
|
||||
// use the defaultMessage literal value
|
||||
msg = defaultMessage;
|
||||
msg = StringEscapeUtils.escapeEcmaScript(msg);
|
||||
msg = StringEscapeUtils.escapeHtml4(msg);
|
||||
LOG.debug("Message for key '{}' is null, returns escaped default message [{}]", key, msg);
|
||||
}
|
||||
|
||||
if (LOG.isWarnEnabled()) {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
/*
|
||||
* $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
|
||||
@@ -45,162 +43,8 @@ import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: description -->
|
||||
*
|
||||
* XSLTResult uses XSLT to transform an action object to XML. The recent version
|
||||
* has been specifically modified to deal with Xalan flaws. When using Xalan you
|
||||
* may notice that even though you have a very minimal stylesheet like this one
|
||||
* <pre>
|
||||
* <xsl:template match="/result">
|
||||
* <result/>
|
||||
* </xsl:template></pre>
|
||||
*
|
||||
* <p>
|
||||
* Xalan would still iterate through every property of your action and all
|
||||
* its descendants.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If you had double-linked objects, Xalan would work forever analysing an
|
||||
* infinite object tree. Even if your stylesheet was not constructed to process
|
||||
* them all. It's because the current Xalan eagerly and extensively converts
|
||||
* everything to its internal DTM model before further processing.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* That's why there's a loop eliminator added that works by indexing every
|
||||
* object-property combination during processing. If it notices that some
|
||||
* object's property was already walked through, it doesn't go any deeper.
|
||||
* Say you have two objects, x and y, with the following properties set
|
||||
* (pseudocode):
|
||||
* </p>
|
||||
* <pre>
|
||||
* x.y = y;
|
||||
* and
|
||||
* y.x = x;
|
||||
* action.x=x;</pre>
|
||||
*
|
||||
* <p>
|
||||
* Due to that modification, the resulting XML document based on x would be:
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <result>
|
||||
* <x>
|
||||
* <y/>
|
||||
* </x>
|
||||
* </result></pre>
|
||||
*
|
||||
* <p>
|
||||
* Without it there would be endless x/y/x/y/x/y/... elements.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The XSLTResult code tries also to deal with the fact that DTM model is built
|
||||
* in a manner that children are processed before siblings. The result is that if
|
||||
* there is object x that is both set in action's x property, and very deeply
|
||||
* under action's a property then it would only appear under a, not under x.
|
||||
* That's not what we expect, and that's why XSLTResult allows objects to repeat
|
||||
* in various places to some extent.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Sometimes the object mesh is still very dense and you may notice that even
|
||||
* though you have a relatively simple stylesheet, execution takes a tremendous
|
||||
* amount of time. To help you to deal with that obstacle of Xalan, you may
|
||||
* attach regexp filters to elements paths (xpath).
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> In your .xsl file the root match must be named <tt>result</tt>.
|
||||
* <br>This example will output the username by using <tt>getUsername</tt> on your
|
||||
* action class:
|
||||
* <pre>
|
||||
* <xsl:template match="result">
|
||||
* <html>
|
||||
* <body>
|
||||
* Hello <xsl:value-of select="username"/> how are you?
|
||||
* </body>
|
||||
* </html>
|
||||
* </xsl:template>
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* In the following example the XSLT result would only walk through action's
|
||||
* properties without their childs. It would also skip every property that has
|
||||
* "hugeCollection" in their name. Element's path is first compared to
|
||||
* excludingPattern - if it matches it's no longer processed. Then it is
|
||||
* compared to matchingPattern and processed only if there's a match.
|
||||
* </p>
|
||||
*
|
||||
* <!-- END SNIPPET: description -->
|
||||
*
|
||||
* <pre><!-- START SNIPPET: description.example -->
|
||||
* <result name="success" type="xslt">
|
||||
* <param name="location">foo.xslt</param>
|
||||
* <param name="matchingPattern">^/result/[^/*]$</param>
|
||||
* <param name="excludingPattern">.*(hugeCollection).*</param>
|
||||
* </result>
|
||||
* <!-- END SNIPPET: description.example --></pre>
|
||||
*
|
||||
* <p>
|
||||
* In the following example the XSLT result would use the action's user property
|
||||
* instead of the action as it's base document and walk through it's properties.
|
||||
* The exposedValue uses an ognl expression to derive it's value.
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <result name="success" type="xslt">
|
||||
* <param name="location">foo.xslt</param>
|
||||
* <param name="exposedValue">user$</param>
|
||||
* </result>
|
||||
* </pre>
|
||||
* *
|
||||
* <b>This result type takes the following parameters:</b>
|
||||
*
|
||||
* <!-- START SNIPPET: params -->
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li><b>location (default)</b> - the location to go to after execution.</li>
|
||||
* <li><b>encoding</b> - character encoding used in XML, default UTF-8.</li>
|
||||
*
|
||||
* <li><b>parse</b> - true by default. If set to false, the location param will
|
||||
* not be parsed for Ognl expressions.</li>
|
||||
*
|
||||
* <!--
|
||||
* <li><b>matchingPattern</b> - Pattern that matches only desired elements, by
|
||||
* default it matches everything.</li>
|
||||
*
|
||||
* <li><b>excludingPattern</b> - Pattern that eliminates unwanted elements, by
|
||||
* default it matches none.</li>
|
||||
* -->
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* <code>struts.properties</code> related configuration:
|
||||
* </p>
|
||||
* <ul>
|
||||
*
|
||||
* <li><b>struts.xslt.nocache</b> - Defaults to false. If set to true, disables
|
||||
* stylesheet caching. Good for development, bad for production.</li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* <!-- END SNIPPET: params -->
|
||||
* <p>
|
||||
* <b>Example:</b>
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* <!-- START SNIPPET: example -->
|
||||
* <result name="success" type="xslt">foo.xslt</result>
|
||||
* <!-- END SNIPPET: example -->
|
||||
* </pre>
|
||||
*
|
||||
* XSLTResult uses XSLT to transform an action object to XML.
|
||||
*/
|
||||
public class XSLTResult implements Result {
|
||||
|
||||
@@ -235,7 +79,7 @@ public class XSLTResult implements Result {
|
||||
/** Indicates the property name patterns which should be excluded from the xml. */
|
||||
private String excludingPattern;
|
||||
|
||||
/** Indicates the ognl expression respresenting the bean which is to be exposed as xml. */
|
||||
/** Indicates the ognl expression representing the bean which is to be exposed as xml. */
|
||||
private String exposedValue;
|
||||
|
||||
/** Indicates the status to return in the response */
|
||||
@@ -260,8 +104,6 @@ public class XSLTResult implements Result {
|
||||
}
|
||||
|
||||
public void setStylesheetLocation(String location) {
|
||||
if (location == null)
|
||||
throw new IllegalArgumentException("Null location");
|
||||
this.stylesheetLocation = location;
|
||||
}
|
||||
|
||||
@@ -308,12 +150,15 @@ public class XSLTResult implements Result {
|
||||
long startTime = System.currentTimeMillis();
|
||||
String location = getStylesheetLocation();
|
||||
|
||||
if (location == null) {
|
||||
throw new IllegalArgumentException("Parameter 'stylesheetLocation' cannot be null!");
|
||||
}
|
||||
|
||||
if (parse) {
|
||||
ValueStack stack = ActionContext.getContext().getValueStack();
|
||||
location = TextParseUtil.translateVariables(location, stack);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
HttpServletResponse response = ServletActionContext.getResponse();
|
||||
response.setStatus(status);
|
||||
@@ -326,36 +171,20 @@ public class XSLTResult implements Result {
|
||||
if (location != null) {
|
||||
templates = getTemplates(location);
|
||||
transformer = templates.newTransformer();
|
||||
} else
|
||||
} else {
|
||||
transformer = TransformerFactory.newInstance().newTransformer();
|
||||
}
|
||||
|
||||
transformer.setURIResolver(getURIResolver());
|
||||
transformer.setErrorListener(new ErrorListener() {
|
||||
|
||||
public void error(TransformerException exception)
|
||||
throws TransformerException {
|
||||
throw new StrutsException("Error transforming result", exception);
|
||||
}
|
||||
|
||||
public void fatalError(TransformerException exception)
|
||||
throws TransformerException {
|
||||
throw new StrutsException("Fatal error transforming result", exception);
|
||||
}
|
||||
|
||||
public void warning(TransformerException exception)
|
||||
throws TransformerException {
|
||||
if (LOG.isWarnEnabled()) {
|
||||
LOG.warn(exception.getMessage(), exception);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
transformer.setErrorListener(buildErrorListener());
|
||||
|
||||
String mimeType;
|
||||
if (templates == null)
|
||||
if (templates == null) {
|
||||
mimeType = "text/xml"; // no stylesheet, raw xml
|
||||
else
|
||||
} else {
|
||||
mimeType = templates.getOutputProperties().getProperty(OutputKeys.MEDIA_TYPE);
|
||||
}
|
||||
|
||||
if (mimeType == null) {
|
||||
// guess (this is a servlet, so text/html might be the best guess)
|
||||
mimeType = "text/html";
|
||||
@@ -385,9 +214,28 @@ public class XSLTResult implements Result {
|
||||
}
|
||||
}
|
||||
|
||||
protected ErrorListener buildErrorListener() {
|
||||
return new ErrorListener() {
|
||||
|
||||
public void error(TransformerException exception) throws TransformerException {
|
||||
throw new StrutsException("Error transforming result", exception);
|
||||
}
|
||||
|
||||
public void fatalError(TransformerException exception) throws TransformerException {
|
||||
throw new StrutsException("Fatal error transforming result", exception);
|
||||
}
|
||||
|
||||
public void warning(TransformerException exception) throws TransformerException {
|
||||
LOG.warn(exception.getMessage(), exception);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
protected AdapterFactory getAdapterFactory() {
|
||||
if (adapterFactory == null)
|
||||
if (adapterFactory == null) {
|
||||
adapterFactory = new AdapterFactory();
|
||||
}
|
||||
return adapterFactory;
|
||||
}
|
||||
|
||||
@@ -400,8 +248,7 @@ public class XSLTResult implements Result {
|
||||
* function. The default is an instance of ServletURIResolver, which operates relative to the servlet context.
|
||||
*/
|
||||
protected URIResolver getURIResolver() {
|
||||
return new ServletURIResolver(
|
||||
ServletActionContext.getServletContext());
|
||||
return new ServletURIResolver(ServletActionContext.getServletContext());
|
||||
}
|
||||
|
||||
protected Templates getTemplates(final String path) throws TransformerException, IOException {
|
||||
@@ -422,6 +269,7 @@ public class XSLTResult implements Result {
|
||||
|
||||
TransformerFactory factory = TransformerFactory.newInstance();
|
||||
factory.setURIResolver(getURIResolver());
|
||||
factory.setErrorListener(buildErrorListener());
|
||||
templates = factory.newTemplates(new StreamSource(resource.openStream()));
|
||||
templatesCache.put(path, templates);
|
||||
}
|
||||
@@ -430,8 +278,7 @@ public class XSLTResult implements Result {
|
||||
return templates;
|
||||
}
|
||||
|
||||
protected Source getDOMSourceForStack(Object value)
|
||||
throws IllegalAccessException, InstantiationException {
|
||||
protected Source getDOMSourceForStack(Object value) throws IllegalAccessException, InstantiationException {
|
||||
return new DOMSource(getAdapterFactory().adaptDocument("result", value) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ struts.messages.invalid.file=Could not find a Filename for {0}. Verify that a va
|
||||
struts.messages.invalid.content.type=Could not find a Content-Type for {0}. Verify that a valid file was submitted.
|
||||
struts.messages.removing.file=Removing file {0} {1}
|
||||
struts.messages.error.uploading=Error uploading: {0}
|
||||
struts.messages.error.file.too.large=The file is to large to be uploaded: {0} "{1}" "{2}" {3}
|
||||
struts.messages.error.file.too.large=The file is too large to be uploaded: {0} "{1}" "{2}" {3}
|
||||
struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3}
|
||||
struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
<!-- constant name="struts.excludedPackageNamePatterns" value="^java\.lang\..*,^ognl.*,^(?!javax\.servlet\..+)(javax\..+)" / -->
|
||||
|
||||
<!-- this is simpler version of the above used with string comparison -->
|
||||
<constant name="struts.excludedPackageNames" value="java.lang.,ognl,javax" />
|
||||
<constant name="struts.excludedPackageNames" value="java.lang.,ognl,javax,freemarker.core,freemarker.template" />
|
||||
|
||||
<bean class="com.opensymphony.xwork2.ObjectFactory" name="struts"/>
|
||||
<bean type="com.opensymphony.xwork2.factory.ResultFactory" name="struts" class="org.apache.struts2.factory.StrutsResultFactory" />
|
||||
@@ -152,6 +152,8 @@
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Map" class="com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="java.util.Collection" class="com.opensymphony.xwork2.ognl.accessor.XWorkCollectionPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="com.opensymphony.xwork2.ognl.ObjectProxy" class="com.opensymphony.xwork2.ognl.accessor.ObjectProxyPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="org.apache.struts2.dispatcher.HttpParameters" class="com.opensymphony.xwork2.ognl.accessor.HttpParametersPropertyAccessor" />
|
||||
<bean type="ognl.PropertyAccessor" name="org.apache.struts2.dispatcher.Parameter" class="com.opensymphony.xwork2.ognl.accessor.ParameterPropertyAccessor" />
|
||||
|
||||
<bean type="ognl.MethodAccessor" name="java.lang.Object" class="com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor" />
|
||||
<bean type="ognl.MethodAccessor" name="com.opensymphony.xwork2.util.CompoundRoot" class="com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor" />
|
||||
@@ -173,6 +175,8 @@
|
||||
<bean type="com.opensymphony.xwork2.security.ExcludedPatternsChecker" name="struts" class="com.opensymphony.xwork2.security.DefaultExcludedPatternsChecker" scope="prototype" />
|
||||
<bean type="com.opensymphony.xwork2.security.AcceptedPatternsChecker" name="struts" class="com.opensymphony.xwork2.security.DefaultAcceptedPatternsChecker" scope="prototype" />
|
||||
|
||||
<bean type="com.opensymphony.xwork2.config.providers.ValueSubstitutor" class="com.opensymphony.xwork2.config.providers.EnvsValueSubstitutor" scope="singleton"/>
|
||||
|
||||
<package name="struts-default" abstract="true" strict-method-invocation="true">
|
||||
<result-types>
|
||||
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
java.io.File=org.apache.struts2.conversion.UploadedFileConverter
|
||||
@@ -103,7 +103,7 @@ Please do not edit it directly.
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The rounding mode to use - not implemented yet as this required Java 1.6</td>
|
||||
<td align="left" valign="top">The rounding mode to use, possible values: ceiling, down, floor, half-down, half-even, half-up, unnecessary, up</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">type</td>
|
||||
|
||||
@@ -44,7 +44,7 @@ Please do not edit it directly.
|
||||
<tr>
|
||||
<td align="left" valign="top">searchValueStack</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">true</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">Boolean</td>
|
||||
<td align="left" valign="top">Search the stack if property is not found on resources</td>
|
||||
|
||||
@@ -90,7 +90,7 @@ public class ActionContextTest extends XWorkTestCase {
|
||||
|
||||
public void testParameters() {
|
||||
context.setParameters(HttpParameters.create().build());
|
||||
assertEquals(0, context.getParameters().getNames().size());
|
||||
assertEquals(0, context.getParameters().keySet().size());
|
||||
}
|
||||
|
||||
public void testConversionErrors() {
|
||||
|
||||
@@ -3,16 +3,20 @@ package com.opensymphony.xwork2;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorMapping;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
|
||||
import com.opensymphony.xwork2.mock.MockActionProxy;
|
||||
import com.opensymphony.xwork2.mock.MockContainer;
|
||||
import com.opensymphony.xwork2.mock.MockInterceptor;
|
||||
import com.opensymphony.xwork2.mock.MockLazyInterceptor;
|
||||
import com.opensymphony.xwork2.ognl.OgnlUtil;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
@@ -298,6 +302,36 @@ public class DefaultActionInvocationTest extends XWorkTestCase {
|
||||
assertEquals("success", result);
|
||||
}
|
||||
|
||||
public void testInvokeWithLazyParams() throws Exception {
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
params.put("blah", "this is blah");
|
||||
|
||||
HashMap<String, Object> extraContext = new HashMap<>();
|
||||
extraContext.put(ActionContext.PARAMETERS, HttpParameters.create(params).build());
|
||||
|
||||
DefaultActionInvocation defaultActionInvocation = new DefaultActionInvocation(extraContext, true);
|
||||
container.inject(defaultActionInvocation);
|
||||
|
||||
ActionProxy actionProxy = actionProxyFactory.createActionProxy( "", "LazyFoo", null, extraContext);
|
||||
defaultActionInvocation.init(actionProxy);
|
||||
defaultActionInvocation.invoke();
|
||||
|
||||
SimpleAction action = (SimpleAction) defaultActionInvocation.getAction();
|
||||
|
||||
assertEquals("this is blah", action.getBlah());
|
||||
assertEquals("this is blah", action.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
// ensure we're using the default configuration, not simple config
|
||||
XmlConfigurationProvider configurationProvider = new XmlConfigurationProvider("xwork-sample.xml");
|
||||
container.inject(configurationProvider);
|
||||
loadConfigurationProviders(configurationProvider);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DefaultActionInvocationTester extends DefaultActionInvocation {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import junit.framework.Assert;
|
||||
import org.junit.Assert;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,6 +51,8 @@ public class SimpleAction extends ActionSupport {
|
||||
private String aliasDest;
|
||||
private Map<String, String> protectedMap = new HashMap<>();
|
||||
private Map<String, String> existingMap = new HashMap<>();
|
||||
|
||||
private List<TestBean> beanList;
|
||||
|
||||
public static boolean resultCalled;
|
||||
|
||||
@@ -261,4 +263,12 @@ public class SimpleAction extends ActionSupport {
|
||||
public void setShortFoo(short shortFoo) {
|
||||
this.shortFoo = shortFoo;
|
||||
}
|
||||
|
||||
public List<TestBean> getBeanList() {
|
||||
return beanList;
|
||||
}
|
||||
|
||||
public void setBeanList(List<TestBean> beanList) {
|
||||
this.beanList = beanList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
import com.opensymphony.xwork2.interceptor.Interceptor;
|
||||
import junit.framework.Assert;
|
||||
import org.junit.Assert;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
+1
-2
@@ -36,8 +36,7 @@ public abstract class ConfigurationTestBase extends XWorkTestCase {
|
||||
container = configuration.getContainer();
|
||||
|
||||
XmlConfigurationProvider prov = new XmlConfigurationProvider(filename, true);
|
||||
prov.setObjectFactory(container.getInstance(ObjectFactory.class));
|
||||
prov.setFileManagerFactory(container.getInstance(FileManagerFactory.class));
|
||||
container.inject(prov);
|
||||
prov.init(configuration);
|
||||
prov.loadPackages();
|
||||
return prov;
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.opensymphony.xwork2.config.providers;
|
||||
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
|
||||
|
||||
public class EnvsValueSubstitutorTest extends StrutsInternalTestCase {
|
||||
|
||||
public void testSimpleValue() throws Exception {
|
||||
// given
|
||||
String expected = System.getenv("USER");
|
||||
ValueSubstitutor substitutor = new EnvsValueSubstitutor();
|
||||
|
||||
// when
|
||||
String actual = substitutor.substitute("${env.USER}");
|
||||
|
||||
// then
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
public void testNoSubstitution() throws Exception {
|
||||
// given
|
||||
ValueSubstitutor substitutor = new EnvsValueSubstitutor();
|
||||
|
||||
// when
|
||||
String actual = substitutor.substitute("val1");
|
||||
|
||||
// then
|
||||
assertEquals("val1", actual);
|
||||
}
|
||||
}
|
||||
+15
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Copyright 2002-2006,2009 The Apache Software Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.opensymphony.xwork2.config.providers;
|
||||
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2002-2006,2009 The Apache Software Foundation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.opensymphony.xwork2.config.providers;
|
||||
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
public class XmlConfigurationProviderEnvsSubstitutionTest extends ConfigurationTestBase {
|
||||
|
||||
public void testSubstitution() throws ConfigurationException {
|
||||
final String filename = "com/opensymphony/xwork2/config/providers/xwork-test-envs-substitution.xml";
|
||||
ConfigurationProvider provider = buildConfigurationProvider(filename);
|
||||
|
||||
configurationManager.addContainerProvider(provider);
|
||||
configurationManager.reload();
|
||||
configuration = configurationManager.getConfiguration();
|
||||
container = configuration.getContainer();
|
||||
|
||||
String foo = container.getInstance(String.class, "foo");
|
||||
assertEquals("bar", foo);
|
||||
|
||||
String user = container.getInstance(String.class, "user");
|
||||
assertEquals(System.getenv("USER"), user);
|
||||
|
||||
String home = container.getInstance(String.class, "home");
|
||||
assertEquals("Current HOME = " + System.getenv("HOME"), home);
|
||||
|
||||
String os = container.getInstance(String.class, "os");
|
||||
assertEquals("Current OS = " + System.getProperty("os.name"), os);
|
||||
|
||||
String unknown = container.getInstance(String.class, "unknown");
|
||||
assertEquals("Unknown = default", unknown);
|
||||
|
||||
String devMode = container.getInstance(String.class, StrutsConstants.STRUTS_DEVMODE);
|
||||
assertEquals("false", devMode);
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -22,7 +22,7 @@ import com.opensymphony.xwork2.config.entities.InterceptorMapping;
|
||||
import com.opensymphony.xwork2.config.entities.PackageConfig;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.interceptor.ParametersInterceptor;
|
||||
import junit.framework.Assert;
|
||||
import org.junit.Assert;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
+4
@@ -41,6 +41,10 @@ public class XmlConfigurationProviderWildCardIncludeTest extends ConfigurationTe
|
||||
assertNotNull(defaultTwoPackage);
|
||||
assertEquals("default-2", defaultTwoPackage.getName());
|
||||
|
||||
PackageConfig defaultPackage = configuration.getPackageConfig("default");
|
||||
assertNotNull(defaultPackage);
|
||||
assertEquals("default", defaultPackage.getName());
|
||||
|
||||
configurationManager.addContainerProvider(provider);
|
||||
configurationManager.reload();
|
||||
|
||||
|
||||
+1
-1
@@ -116,7 +116,7 @@ public class ParameterFilterInterceptorTest extends XWorkTestCase {
|
||||
}
|
||||
|
||||
private Collection getParameterNames() {
|
||||
return ((HttpParameters)contextMap.get(ActionContext.PARAMETERS)).getNames();
|
||||
return ((HttpParameters)contextMap.get(ActionContext.PARAMETERS)).keySet();
|
||||
}
|
||||
|
||||
public void runAction() throws Exception {
|
||||
|
||||
+3
-3
@@ -50,7 +50,7 @@ public class ParameterRemoverInterceptorTest extends TestCase {
|
||||
interceptor.intercept(actionInvocation);
|
||||
|
||||
HttpParameters params = (HttpParameters) contextMap.get(ActionContext.PARAMETERS);
|
||||
assertEquals(params.getNames().size(), 2);
|
||||
assertEquals(params.keySet().size(), 2);
|
||||
assertTrue(params.contains("param3"));
|
||||
assertTrue(params.contains("param"));
|
||||
assertEquals(params.get("param3").getValue(), "paramValue3");
|
||||
@@ -76,7 +76,7 @@ public class ParameterRemoverInterceptorTest extends TestCase {
|
||||
interceptor.intercept(actionInvocation);
|
||||
|
||||
HttpParameters params = (HttpParameters) contextMap.get(ActionContext.PARAMETERS);
|
||||
assertEquals(params.getNames().size(), 0);
|
||||
assertEquals(params.keySet().size(), 0);
|
||||
|
||||
verify(actionInvocation);
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public class ParameterRemoverInterceptorTest extends TestCase {
|
||||
interceptor.intercept(actionInvocation);
|
||||
|
||||
HttpParameters params = (HttpParameters) contextMap.get(ActionContext.PARAMETERS);
|
||||
assertEquals(params.getNames().size(), 2);
|
||||
assertEquals(params.keySet().size(), 2);
|
||||
assertTrue(params.contains("param1"));
|
||||
assertTrue(params.contains("param2"));
|
||||
assertEquals(params.get("param1").getValue(), "paramValueOne");
|
||||
|
||||
+17
-1
@@ -29,7 +29,7 @@ import com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor;
|
||||
import com.opensymphony.xwork2.util.CompoundRoot;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.ValueStackFactory;
|
||||
import junit.framework.Assert;
|
||||
import org.junit.Assert;
|
||||
import ognl.OgnlContext;
|
||||
import ognl.PropertyAccessor;
|
||||
import org.apache.struts2.dispatcher.HttpParameters;
|
||||
@@ -712,6 +712,22 @@ public class ParametersInterceptorTest extends XWorkTestCase {
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
public void testBeanListSingleValue() throws Exception {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("beanList.name", new String[] { "Superman" });
|
||||
|
||||
HashMap<String, Object> extraContext = new HashMap<>();
|
||||
extraContext.put(ActionContext.PARAMETERS, HttpParameters.create(params).build());
|
||||
|
||||
ActionProxy proxy = actionProxyFactory.createActionProxy("",
|
||||
MockConfigurationProvider.PARAM_INTERCEPTOR_ACTION_NAME, null, extraContext);
|
||||
proxy.execute();
|
||||
SimpleAction action = (SimpleAction) proxy.getAction();
|
||||
assertNotNull(action);
|
||||
assertNotNull(action.getBeanList());
|
||||
assertFalse(action.getBeanList().isEmpty());
|
||||
}
|
||||
|
||||
private ValueStack injectValueStack(Map<String, Object> actual) {
|
||||
ValueStack stack = createStubValueStack(actual);
|
||||
container.inject(stack);
|
||||
|
||||
+1
-1
@@ -133,7 +133,7 @@ public class StaticParametersInterceptorTest extends XWorkTestCase {
|
||||
|
||||
assertEquals(before, ActionContext.getContext().getValueStack().size());
|
||||
assertEquals("${top.hero}", user.getName());
|
||||
assertEquals(0, ActionContext.getContext().getParameters().getNames().size());
|
||||
assertEquals(0, ActionContext.getContext().getParameters().keySet().size());
|
||||
}
|
||||
|
||||
public void testFewParametersParse() throws Exception {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user