Compare commits

..

66 Commits

Author SHA1 Message Date
Lukasz Lenart 5054ff469a [maven-release-plugin] prepare release STRUTS_2_5_7 2016-12-02 08:26:30 +01:00
Lukasz Lenart 0f69b0c3fb Implements toString 2016-12-02 07:43:48 +01:00
Lukasz Lenart 09958919ca WW-4722 Adds description of storage parameter 2016-12-01 19:58:03 +01:00
Lukasz Lenart aabc90df6b WW-4722 Refactors store logic 2016-12-01 19:51:14 +01:00
Lukasz Lenart f515def5b8 WW-4722 Prepares ActionProxy to be used with test 2016-12-01 19:50:36 +01:00
Lukasz Lenart fddc6582e0 WW-4722 Reuses global fields and cleans up logging 2016-12-01 17:31:28 +01:00
Lukasz Lenart 8971b50810 WW-4722 Extracts logic to store locale in cookie into a method 2016-12-01 17:25:33 +01:00
Lukasz Lenart 6457f002d9 WW-4722 Refactors code to use predefined storage locatio 2016-12-01 17:21:22 +01:00
Lukasz Lenart 6e1ea61dc6 WW-4722 Allows predefine default store location 2016-12-01 16:55:42 +01:00
Lukasz Lenart bcea4c9baf WW-4722 Renames constant for better readability 2016-12-01 16:16:49 +01:00
Lukasz Lenart a1b89842c0 WW-4698 Uses lowercase prefix 2016-11-30 11:17:26 +01:00
Lukasz Lenart 03766980d1 WW-4698 Fixes test 2016-11-30 10:48:29 +01:00
Lukasz Lenart 1bf7de8d37 WW-4698 Fixes issue with injecting substitutor 2016-11-30 10:27:46 +01:00
Lukasz Lenart ad3a697d93 [maven-release-plugin] prepare for next development iteration 2016-11-28 21:15:56 +01:00
Lukasz Lenart 31a0768da3 [maven-release-plugin] prepare release STRUTS_2_5_6 2016-11-28 21:15:29 +01:00
Lukasz Lenart 0014f8935a WW-4721 Enables test 2016-11-28 17:12:34 +01:00
Lukasz Lenart 99bb671437 WW-4721 Enables rounding mode 2016-11-28 17:03:48 +01:00
Lukasz Lenart 9cde17b223 Makes createDispatcher protected to allow override it 2016-11-27 12:52:57 +01:00
Lukasz Lenart 6651089e82 Extracts creating new instances into dedicated methods to allow override them 2016-11-27 12:45:36 +01:00
Lukasz Lenart 8bb225c04c Increases accessibility of getSaveDir to allow override its implementation 2016-11-27 12:29:15 +01:00
Lukasz Lenart 32341681ed Adds unit test to cover converter's logic 2016-11-24 14:52:34 +01:00
Lukasz Lenart 1ff8a88a9d Fixes issue with NPE 2016-11-24 14:52:18 +01:00
Lukasz Lenart ae5605ff88 Merge branch 'master' into WW-4717 2016-11-23 15:15:15 +01:00
Lukasz Lenart 6d623ebb56 WW-4720 HttpParameters implements Map interface 2016-11-23 13:54:20 +01:00
Lukasz Lenart 7872fa80f9 WW-4719 Moves DefaultClassFinder implementation into Convention and ASM dependencies 2016-11-23 11:59:32 +01:00
Lukasz Lenart f03279fc1a WW-4570 Cleans up ASM and assemblies 2016-11-23 11:43:05 +01:00
Lukasz Lenart 4de8309d0a Extracts one base class 2016-11-22 20:02:22 +01:00
Lukasz Lenart de51e79718 Drops unused code 2016-11-22 18:03:14 +01:00
Lukasz Lenart 6280feb426 Reduces code duplication 2016-11-22 17:56:56 +01:00
Lukasz Lenart e152c15f78 Adds WARN to avoid using java.io.File 2016-11-22 17:44:02 +01:00
Lukasz Lenart 3fd909668a Adds default converter to handle converstion of internal file representation to File 2016-11-22 09:41:13 +01:00
Lukasz Lenart e86793482a Drops generic 2016-11-22 09:38:31 +01:00
Lukasz Lenart ec5fba7af9 Reverts back to pure File 2016-11-22 09:38:20 +01:00
Lukasz Lenart dca41a39bf Updates examples 2016-11-21 11:05:56 +01:00
Lukasz Lenart 407cd58279 Adjusts interceptor to use the new class 2016-11-21 11:05:47 +01:00
Lukasz Lenart 45edbcbe45 Uses the new class in implementation of MultiPartRequest 2016-11-21 11:05:33 +01:00
Lukasz Lenart fe05ca2095 Introduces a dedicated class to represent an uploaded file 2016-11-21 11:04:24 +01:00
Lukasz Lenart 6f7fcaa338 WW-4716 Allows create actions with all dependencies injected 2016-11-20 18:10:03 +01:00
Lukasz Lenart 321d9da095 Drops unused import 2016-11-18 10:34:14 +01:00
Lukasz Lenart bd99677b19 Escapes return value of toString() plus adds missing toString() implementations 2016-11-16 12:45:40 +01:00
Lukasz Lenart 8759bbc68a Reduces noise in the logs during development 2016-11-16 10:14:41 +01:00
Lukasz Lenart 931df54ab3 Optimises validator to reduce number of compiling pattern 2016-11-16 07:46:29 +01:00
Lukasz Lenart eb71d88696 Adds double check using Commons Validator 2016-11-16 07:31:05 +01:00
Lukasz Lenart 554b9dddb0 Trims input value 2016-11-16 07:30:46 +01:00
Lukasz Lenart a245226b7f WW-4715 Uses isDefined function instead of null-checking 2016-11-16 07:21:38 +01:00
Lukasz Lenart ef2939ffd0 WW-2561 Throws a Struts exception when there is a bad character in template 2016-11-13 11:16:40 +01:00
Lukasz Lenart 8aba301da0 WW-2454 Upgrades TestNG to latest 5.x version 2016-11-12 18:09:10 +01:00
Lukasz Lenart e1e2ea84a7 Fixes typos 2016-11-12 17:39:58 +01:00
Lukasz Lenart 986b43f314 WW-4701 Drop parameter if not defined 2016-11-12 17:39:43 +01:00
Lukasz Lenart a5092a24f2 WW-4711 Disables searching stack by default 2016-11-12 09:41:05 +01:00
Aleksandr Mashchenko a5817fecb3 Fix import for deprecated JUnit Assert 2016-11-11 23:15:16 +02:00
Lukasz Lenart 366366cdd8 WW-4712 Escapes default message 2016-11-11 11:57:29 +01:00
Lukasz Lenart 4e7a4b18c0 WW-4711 Disables evaluating ValueStack by default 2016-11-11 11:57:04 +01:00
Lukasz Lenart 996475d755 WW-4711 Disables evaluating ValueStack by default 2016-11-11 11:52:40 +01:00
Lukasz Lenart ab6750211b WW-4710 Restrict access to HttpParameters.toMap 2016-11-10 20:13:09 +01:00
Lukasz Lenart 70400f4a03 WW-4636 Fixes problem with File upload error message are always in default language 2016-11-07 20:15:15 +01:00
Lukasz Lenart b5240560ab WW-4702 WW-4707 Fixes issue with with list based parameters 2016-11-07 20:13:51 +01:00
Lukasz Lenart b287a9546a WW-4709 Defines toString as it's used in JSON serialisation 2016-11-07 20:13:51 +01:00
Aleksandr Mashchenko 33ac7ac49a WW-4636 - File upload error message always in default language 2016-11-07 20:13:51 +01:00
Aleksandr Mashchenko 8fe2bb8317 WW-4705 - Add support for long type to <s:date> tag 2016-11-01 19:01:44 +02:00
Lukasz Lenart 8699f639f3 WW-4704 Upgrades to OGNL 3.1.12 2016-10-28 08:47:33 +02:00
Lukasz Lenart 24a97d33e6 WW-4703 Increases container field visibility 2016-10-28 08:43:01 +02:00
Aleksandr Mashchenko 835cc7cd09 WW-4636 - File upload error message always in default language 2016-10-15 15:25:14 +03:00
Lukasz Lenart 1af1887037 Adds missing headers with license 2016-10-12 11:32:04 +02:00
Lukasz Lenart 8135abeca7 WW-4698 Implements System & ENV variables substitution 2016-10-12 11:23:24 +02:00
Lukasz Lenart 91d6691b0d [maven-release-plugin] prepare for next development iteration 2016-10-11 20:40:50 +02:00
122 changed files with 1557 additions and 609 deletions
+1 -1
View File
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.5.5</version>
<version>2.5.7</version>
</parent>
<artifactId>struts2-apps</artifactId>
<packaging>pom</packaging>
+2 -2
View File
@@ -26,12 +26,12 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-apps</artifactId>
<version>2.5.5</version>
<version>2.5.7</version>
</parent>
<artifactId>struts2-rest-showcase</artifactId>
<packaging>war</packaging>
<version>2.5.5</version>
<version>2.5.7</version>
<name>Struts 2 Rest Showcase Webapp</name>
<description>Struts 2 Rest Showcase Example</description>
+1 -1
View File
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-apps</artifactId>
<version>2.5.5</version>
<version>2.5.7</version>
</parent>
<artifactId>struts2-showcase</artifactId>
@@ -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
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.5.5</version>
<version>2.5.7</version>
</parent>
<artifactId>struts2-assembly</artifactId>
+1
View File
@@ -31,6 +31,7 @@
</formats>
<dependencySets>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
<scope>runtime</scope>
<excludes>
+1
View File
@@ -31,6 +31,7 @@
</formats>
<dependencySets>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
<scope>runtime</scope>
<excludes>
+1 -4
View File
@@ -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
View File
@@ -10,7 +10,7 @@
</parent>
<artifactId>struts2-bom</artifactId>
<version>2.5.5</version>
<version>2.5.7</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.7</struts-version.version>
</properties>
<build>
@@ -172,6 +172,6 @@
</dependencyManagement>
<scm>
<tag>STRUTS_2_5_5</tag>
<tag>STRUTS_2_5_7</tag>
</scm>
</project>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-osgi-bundles</artifactId>
<version>2.5.5</version>
<version>2.5.7</version>
</parent>
<artifactId>struts2-osgi-admin-bundle</artifactId>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-osgi-bundles</artifactId>
<version>2.5.5</version>
<version>2.5.7</version>
</parent>
<artifactId>struts2-osgi-demo-bundle</artifactId>
+1 -1
View File
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.5.5</version>
<version>2.5.7</version>
</parent>
<artifactId>struts2-osgi-bundles</artifactId>
+7 -10
View File
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-parent</artifactId>
<version>2.5.5</version>
<version>2.5.7</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>
@@ -37,7 +37,8 @@ public class ActionSupport implements Action, Validateable, ValidationAware, Tex
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);
@@ -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);
}
}
@@ -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);
}
@@ -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());
@@ -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>();
@@ -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
*
@@ -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
@@ -17,7 +17,7 @@ package com.opensymphony.xwork2.mock;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
import junit.framework.Assert;
import org.junit.Assert;
/**
@@ -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!");
}
}
@@ -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);
}
}
}
@@ -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 + '\'' +
'}';
}
}
}
@@ -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
*
@@ -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 int 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 = Integer.parseInt(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;
}
}
@@ -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.
*
@@ -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();
}
@@ -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());
@@ -70,7 +70,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,14 +27,13 @@ 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;
@@ -76,6 +74,9 @@ import java.util.Map;
* <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>
*
* <li>storage (optional) - the name of storage location, it can be <b>none</b>, <b>session</b> or <b>cookie</b>.
* By default this is <b>session</b></li>
*
* </ul>
*
* <!-- END SNIPPET: parameters -->
@@ -96,25 +97,29 @@ public class I18nInterceptor extends AbstractInterceptor {
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 +128,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,67 +148,83 @@ 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());
LocaleFinder localeFinder = new CookieLocaleFinder(invocation);
Locale locale = getLocaleFromParam(localeFinder.getRequestedLocale());
locale = storeLocale(invocation, locale, localeFinder.getStorage());
saveLocale(invocation, locale);
RequestOnlyLocaleFinder localeFinder = getLocaleFinder(invocation);
Locale locale = getLocaleFromParam(localeFinder.find());
locale = storeLocale(invocation, locale);
useLocale(invocation, locale);
if (LOG.isDebugEnabled()) {
LOG.debug("before Locale={}", invocation.getStack().findValue("locale"));
LOG.debug("Before action invocation Locale={}", invocation.getStack().findValue("locale"));
}
final String result = invocation.invoke();
if (LOG.isDebugEnabled()) {
LOG.debug("after Locale={}", invocation.getStack().findValue("locale"));
LOG.debug("intercept } ");
LOG.debug("After action invocation Locale={}", invocation.getStack().findValue("locale"));
}
return result;
}
protected RequestOnlyLocaleFinder getLocaleFinder(ActionInvocation invocation) {
RequestOnlyLocaleFinder localeFinder;
if (this.storage == Storage.COOKIE) {
localeFinder = new CookieLocaleFinder(invocation);
} else if (this.storage == Storage.SESSION) {
localeFinder = new SessionLocaleFinder(invocation);
} else {
localeFinder = new RequestOnlyLocaleFinder(invocation);
}
LOG.debug("Using LocaleFinder implementation {}", localeFinder.getClass().getName());
return localeFinder;
}
/**
* Store the locale to the chosen storage, like f. e. the session
*
* @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
*/
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);
Cookie cookie = new Cookie(DEFAULT_COOKIE_ATTRIBUTE, locale.toString());
cookie.setMaxAge(1209600); // two weeks
response.addCookie(cookie);
storage = Storage.SESSION;
protected Locale storeLocale(ActionInvocation invocation, Locale locale) {
if (locale == null) {
storage = Storage.NONE;
locale = readStoredLocale(invocation);
}
if (storage == Storage.COOKIE) {
storeLocaleInCookie(invocation, locale);
}
if (Storage.SESSION == storage) {
storeLocaleInSession(invocation, locale);
}
return locale;
}
protected void storeLocaleInCookie(ActionInvocation ignore, Locale locale) {
HttpServletResponse response = ServletActionContext.getResponse();
Cookie cookie = new Cookie(DEFAULT_COOKIE_ATTRIBUTE, locale.toString());
cookie.setMaxAge(1209600); // two weeks
response.addCookie(cookie);
}
protected void storeLocaleInSession(ActionInvocation invocation, Locale locale) {
//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);
}
session.put(attributeName, locale);
}
}
return locale;
}
/**
@@ -202,26 +232,23 @@ public class I18nInterceptor extends AbstractInterceptor {
* 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);
protected Locale readStoredLocale(ActionInvocation invocation) {
Locale locale = readStoredLocalFromSession(invocation);
if (locale != null) {
LOG.debug("Found stored Locale {} in session, using it!", locale);
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());
}
}
Locale cookie = readStoredLocaleFromCookie(invocation);
if (cookie != null) {
LOG.debug("Found stored Locale {} in cookies, using it!", locale);
return cookie;
}
return this.readStoredLocalFromCurrentInvocation(invocation);
LOG.debug("Neither locale was in session nor in cookies, searching current Invocation context");
return readStoredLocalFromCurrentInvocation(invocation);
}
/**
@@ -256,13 +283,31 @@ public class I18nInterceptor extends AbstractInterceptor {
return locale;
}
protected Locale readStoredLocalFromSession(ActionInvocation invocation, Map<String, Object> session) {
protected Locale readStoredLocalFromSession(ActionInvocation invocation) {
// 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;
Map<String, Object> session = invocation.getInvocationContext().getSession();
if (session != null) {
synchronized (session) {
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 readStoredLocaleFromCookie(ActionInvocation ignore) {
Cookie[] cookies = ServletActionContext.getRequest().getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (DEFAULT_COOKIE_ATTRIBUTE.equals(cookie.getName())) {
return getLocaleFromParam(cookie.getValue());
}
}
}
return null;
}
@@ -291,75 +336,78 @@ 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;
protected class RequestOnlyLocaleFinder {
protected ActionInvocation actionInvocation = null;
protected LocaleFinder(ActionInvocation invocation) {
protected RequestOnlyLocaleFinder(ActionInvocation invocation) {
actionInvocation = invocation;
find();
}
protected void find() {
//get requested locale
public String find() {
HttpParameters params = actionInvocation.getInvocationContext().getParameters();
storage = Storage.SESSION;
requestedLocale = findLocaleParameter(params, parameterName);
if (requestedLocale.isDefined()) {
return;
}
requestedLocale = findLocaleParameter(params, requestOnlyParameterName);
Parameter requestedLocale = findLocaleParameter(params, requestOnlyParameterName);
if (requestedLocale.isDefined()) {
storage = Storage.NONE;
return requestedLocale.getValue();
}
}
public Storage getStorage() {
return storage;
}
public String getRequestedLocale() {
return requestedLocale.getValue();
return null;
}
}
protected class CookieLocaleFinder extends LocaleFinder {
protected class SessionLocaleFinder extends RequestOnlyLocaleFinder {
protected SessionLocaleFinder(ActionInvocation invocation) {
super(invocation);
}
public String find() {
String requestOnlyLocale = super.find();
if (requestOnlyLocale != null) {
return requestOnlyLocale;
}
HttpParameters params = actionInvocation.getInvocationContext().getParameters();
Parameter requestedLocale = findLocaleParameter(params, parameterName);
if (requestedLocale.isDefined()) {
return requestedLocale.getValue();
}
return requestedLocale.getValue();
}
}
protected class CookieLocaleFinder extends RequestOnlyLocaleFinder {
protected CookieLocaleFinder(ActionInvocation invocation) {
super(invocation);
}
@Override
protected void find() {
//get requested locale
HttpParameters params = actionInvocation.getInvocationContext().getParameters();
storage = Storage.SESSION;
public String find() {
String requestOnlySessionLocale = super.find();
requestedLocale = findLocaleParameter(params, parameterName);
if (requestedLocale.isDefined()) {
return;
if (requestOnlySessionLocale != null) {
return requestOnlySessionLocale;
}
requestedLocale = findLocaleParameter(params, requestCookieParameterName);
HttpParameters params = actionInvocation.getInvocationContext().getParameters();
Parameter requestedLocale = findLocaleParameter(params, requestCookieParameterName);
if (requestedLocale.isDefined()) {
storage = Storage.COOKIE;
return;
}
requestedLocale = findLocaleParameter(params, requestOnlyParameterName);
if (requestedLocale.isDefined()) {
storage = Storage.NONE;
return requestedLocale.getValue();
}
return null;
}
}
@@ -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());
@@ -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) {
@@ -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
@@ -330,26 +328,7 @@ public class XSLTResult implements Result {
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)
@@ -385,6 +364,24 @@ 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)
adapterFactory = new AdapterFactory();
@@ -422,6 +419,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);
}
@@ -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
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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() {
@@ -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;
/**
@@ -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;
@@ -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);
}
}
@@ -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;
@@ -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);
}
}
@@ -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;
/**
@@ -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 {
@@ -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");
@@ -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);
@@ -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 {
@@ -10,7 +10,7 @@ import com.opensymphony.xwork2.XWorkTestCase;
import com.opensymphony.xwork2.config.entities.ActionConfig;
import com.opensymphony.xwork2.config.entities.InterceptorConfig;
import com.opensymphony.xwork2.validator.ValidationInterceptor;
import junit.framework.Assert;
import org.junit.Assert;
import org.easymock.EasyMock;
import org.easymock.IAnswer;
@@ -59,7 +59,7 @@ public class AnnotationParameterFilterInterceptorTest extends TestCase {
interceptor.intercept(invocation);
HttpParameters parameters = invocation.getInvocationContext().getParameters();
assertEquals("Parameter map should contain one entry", 1, parameters.getNames().size());
assertEquals("Parameter map should contain one entry", 1, parameters.keySet().size());
assertFalse(parameters.get("job").isDefined());
assertTrue(parameters.get("name").isDefined());
@@ -97,7 +97,7 @@ public class AnnotationParameterFilterInterceptorTest extends TestCase {
interceptor.intercept(invocation);
HttpParameters parameters = invocation.getInvocationContext().getParameters();
assertEquals("Paramwter map should contain one entry", 1, parameters.getNames().size());
assertEquals("Paramwter map should contain one entry", 1, parameters.keySet().size());
assertTrue(parameters.get("job").isDefined());
assertFalse(parameters.get("name").isDefined());
@@ -135,7 +135,7 @@ public class AnnotationParameterFilterInterceptorTest extends TestCase {
interceptor.intercept(invocation);
HttpParameters parameters = invocation.getInvocationContext().getParameters();
assertEquals("Parameter map should contain two entries", 2, parameters.getNames().size());
assertEquals("Parameter map should contain two entries", 2, parameters.keySet().size());
assertFalse(parameters.get("job").isDefined());
assertTrue(parameters.get("name").isDefined());
assertTrue(parameters.get("m1").isDefined());
@@ -175,7 +175,7 @@ public class AnnotationParameterFilterInterceptorTest extends TestCase {
interceptor.intercept(invocation);
HttpParameters parameters = invocation.getInvocationContext().getParameters();
assertEquals("Parameter map should contain two entries", 2, parameters.getNames().size());
assertEquals("Parameter map should contain two entries", 2, parameters.keySet().size());
assertTrue(parameters.get("job").isDefined());
assertFalse(parameters.get("name").isDefined());
assertFalse(parameters.get("m1").isDefined());
@@ -19,6 +19,7 @@ import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.XWorkTestCase;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.validator.validators.URLValidator;
import org.apache.commons.validator.routines.UrlValidator;
import java.util.HashMap;
import java.util.Map;
@@ -133,7 +134,7 @@ public class URLValidatorTest extends XWorkTestCase {
public void testValidUrlWithDefaultRegex() throws Exception {
URLValidator validator = new URLValidator();
Pattern pattern = Pattern.compile(validator.getUrlRegex());
Pattern pattern = Pattern.compile(validator.getUrlRegex(), Pattern.CASE_INSENSITIVE);
assertFalse(pattern.matcher("myapp://test.com").matches());
assertFalse(pattern.matcher("myap://test.com").matches());
@@ -146,9 +147,18 @@ public class URLValidatorTest extends XWorkTestCase {
assertTrue(pattern.matcher("https://www.opensymphony.com").matches());
assertTrue(pattern.matcher("https://www.opensymphony.com:443/login").matches());
assertTrue(pattern.matcher("http://localhost:8080/myapp").matches());
}
public void testValidUrlCaseInsesitive() throws Exception {
assertTrue(pattern.matcher("http://www.legalspace.com/__media__/js/netsoltrademark.php?d=www.a-vos-travaux.fr%2Facheter-un-aspirateur-sans-sac-pas-cher%2F").matches());
assertTrue(UrlValidator.getInstance().isValid("http://www.legalspace.com/__media__/js/netsoltrademark.php?d=www.a-vos-travaux.fr%2Facheter-un-aspirateur-sans-sac-pas-cher%2F"));
assertTrue(pattern.matcher("http://www.duadmin.isaev.Infoduadmin.Isaev.info/?a%5B%5D=%3Ca%20href%3Dhttp%3A%2F%2Fwww.aspert.fr%2Fun-seche-cheveux-lisseur-est-il-vraiment-utile%2F%3Eseche%20cheveux%20dyson%20test%3C%2Fa").matches());
assertTrue(UrlValidator.getInstance().isValid("http://www.duadmin.isaev.Infoduadmin.Isaev.info/?a%5B%5D=%3Ca%20href%3Dhttp%3A%2F%2Fwww.aspert.fr%2Fun-seche-cheveux-lisseur-est-il-vraiment-utile%2F%3Eseche%20cheveux%20dyson%20test%3C%2Fa"));
assertTrue(pattern.matcher("http://netsol-underconstruction-page-monitor-1.com/__media__/js/netsoltrademark.php?d=www.le-soutien-scolaire.fr%2Favis-et-test-comparatifs-des-robots-multifonctions%2F").matches());
assertTrue(UrlValidator.getInstance().isValid("http://netsol-underconstruction-page-monitor-1.com/__media__/js/netsoltrademark.php?d=www.le-soutien-scolaire.fr%2Favis-et-test-comparatifs-des-robots-multifonctions%2F"));
}
public void testValidUrlCaseInsensitive() throws Exception {
// given
final Map<String, Object> fieldErrors = new HashMap<>();
@@ -222,7 +232,7 @@ public class URLValidatorTest extends XWorkTestCase {
}
public String getTestingUrl5() {
return "http://yahoo.com/articles?id=123";
return "http://yahoo.com/articles?id=123\n";
}
}
@@ -25,7 +25,7 @@ import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.Result;
import com.opensymphony.xwork2.util.ValueStack;
import junit.framework.Assert;
import org.junit.Assert;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -47,7 +47,7 @@ public class ActionComponentTest extends StrutsInternalTestCase {
comp.addParameter("baz", new String[]{"jim", "sarah"});
HttpParameters params = comp.createParametersForContext();
assertNotNull(params);
assertEquals(2, params.getNames().size());
assertEquals(2, params.keySet().size());
assertEquals("bar", params.get("foo").getValue());
assertEquals(2, params.get("baz").getMultipleValues().length);
mockValueStack.verify();
@@ -0,0 +1,70 @@
package org.apache.struts2.conversion;
import org.apache.struts2.dispatcher.multipart.StrutsUploadedFile;
import org.apache.struts2.dispatcher.multipart.UploadedFile;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.lang.reflect.Member;
import java.util.Collections;
import java.util.Map;
import static org.fest.assertions.Assertions.assertThat;
public class UploadedFileConverterTest {
private Map<String, Object> context;
private Class target;
private Member member;
private String propertyName;
private File tempFile;
@Before
public void setUp() throws Exception {
context = Collections.emptyMap();
target = File.class;
member = File.class.getMethod("length");
propertyName = "ignore";
tempFile = File.createTempFile("struts", "test");
}
@After
public void tearDown() throws Exception {
tempFile.delete();
}
@Test
public void convertUploadedFileToFile() throws Exception {
// given
UploadedFileConverter ufc = new UploadedFileConverter();
UploadedFile uploadedFile = new StrutsUploadedFile(tempFile);
// when
Object result = ufc.convertValue(context, target, member, propertyName, uploadedFile, File.class);
// then
assertThat(result).isInstanceOf(File.class);
File file = (File) result;
assertThat(file.length()).isEqualTo(tempFile.length());
assertThat(file.getAbsolutePath()).isEqualTo(tempFile.getAbsolutePath());
}
@Test
public void convertUploadedFileArrayToFile() throws Exception {
// given
UploadedFileConverter ufc = new UploadedFileConverter();
UploadedFile[] uploadedFile = new UploadedFile[] { new StrutsUploadedFile(tempFile) };
// when
Object result = ufc.convertValue(context, target, member, propertyName, uploadedFile, File.class);
// then
assertThat(result).isInstanceOf(File.class);
File file = (File) result;
assertThat(file.length()).isEqualTo(tempFile.length());
assertThat(file.getAbsolutePath()).isEqualTo(tempFile.getAbsolutePath());
}
}
@@ -21,7 +21,7 @@
package org.apache.struts2.dispatcher;
import junit.framework.Assert;
import org.junit.Assert;
import org.apache.struts2.TestAction;
@@ -72,7 +72,7 @@ public class CheckboxInterceptorTest extends StrutsInternalTestCase {
interceptor.intercept(ai);
interceptor.destroy();
assertEquals(1, ai.getInvocationContext().getParameters().getNames().size());
assertEquals(1, ai.getInvocationContext().getParameters().keySet().size());
}
public void testPassthroughTwo() throws Exception {
@@ -85,7 +85,7 @@ public class CheckboxInterceptorTest extends StrutsInternalTestCase {
interceptor.intercept(ai);
interceptor.destroy();
assertEquals(2, ai.getInvocationContext().getParameters().getNames().size());
assertEquals(2, ai.getInvocationContext().getParameters().keySet().size());
}
public void testOneCheckboxTrue() throws Exception {
@@ -103,7 +103,7 @@ public class CheckboxInterceptorTest extends StrutsInternalTestCase {
HttpParameters parameters = ai.getInvocationContext().getParameters();
assertFalse(parameters.contains("__checkbox_superpower"));
assertEquals(3, parameters.getNames().size()); // should be 3 as __checkbox_ should be removed
assertEquals(3, parameters.keySet().size()); // should be 3 as __checkbox_ should be removed
assertEquals("true", parameters.get("superpower").getValue());
}
@@ -121,7 +121,7 @@ public class CheckboxInterceptorTest extends StrutsInternalTestCase {
HttpParameters parameters = ai.getInvocationContext().getParameters();
assertFalse(parameters.contains("__checkbox_superpower"));
assertEquals(3, parameters.getNames().size()); // should be 3 as __checkbox_ should be removed
assertEquals(3, parameters.keySet().size()); // should be 3 as __checkbox_ should be removed
assertEquals("false", parameters.get("superpower").getValue());
}
@@ -140,7 +140,7 @@ public class CheckboxInterceptorTest extends StrutsInternalTestCase {
HttpParameters parameters = ai.getInvocationContext().getParameters();
assertFalse(parameters.contains("__checkbox_superpower"));
assertEquals(3, parameters.getNames().size()); // should be 3 as __checkbox_ should be removed
assertEquals(3, parameters.keySet().size()); // should be 3 as __checkbox_ should be removed
assertEquals("off", parameters.get("superpower").getValue());
}
@@ -157,7 +157,7 @@ public class CheckboxInterceptorTest extends StrutsInternalTestCase {
HttpParameters parameters = ai.getInvocationContext().getParameters();
assertFalse(parameters.contains("__checkbox_superpower"));
assertEquals(2, parameters.getNames().size()); // should be 2 as __checkbox_ should be removed
assertEquals(2, parameters.keySet().size()); // should be 2 as __checkbox_ should be removed
assertFalse(parameters.get("superpower").isDefined());
}
@@ -179,7 +179,7 @@ public class CheckboxInterceptorTest extends StrutsInternalTestCase {
HttpParameters parameters = ai.getInvocationContext().getParameters();
assertFalse(parameters.contains("__checkbox_superpower"));
assertFalse(parameters.contains("__checkbox_cool"));
assertEquals(4, parameters.getNames().size()); // should be 4 as __checkbox_ should be removed
assertEquals(4, parameters.keySet().size()); // should be 4 as __checkbox_ should be removed
assertEquals("yes", parameters.get("superpower").getValue());
assertEquals("false", parameters.get("cool").getValue()); // will use false as default and not 'no'
}
@@ -203,7 +203,7 @@ public class CheckboxInterceptorTest extends StrutsInternalTestCase {
HttpParameters parameters = ai.getInvocationContext().getParameters();
assertFalse(parameters.contains("__checkbox_superpower"));
assertFalse(parameters.contains("__checkbox_cool"));
assertEquals(4, parameters.getNames().size()); // should be 4 as __checkbox_ should be removed
assertEquals(4, parameters.keySet().size()); // should be 4 as __checkbox_ should be removed
assertEquals("yes", parameters.get("superpower").getValue());
assertEquals("no", parameters.get("cool").getValue());
}
@@ -36,7 +36,7 @@ public class DateTextFieldInterceptorTest extends StrutsInternalTestCase {
interceptor.intercept(ai);
interceptor.destroy();
assertEquals(0, ai.getInvocationContext().getParameters().getNames().size());
assertEquals(0, ai.getInvocationContext().getParameters().keySet().size());
}
public void testOneDateTextField() throws Exception {
@@ -55,7 +55,7 @@ public class DateTextFieldInterceptorTest extends StrutsInternalTestCase {
assertFalse(parameters.contains("__month_name"));
assertFalse(parameters.contains("__day_name"));
assertTrue(parameters.contains("name"));
assertEquals(1, parameters.getNames().size());
assertEquals(1, parameters.keySet().size());
Date date = new SimpleDateFormat("yyyy-MM-dd").parse("2000-06-15");
assertEquals(date, parameters.get("name").getObject());
}
@@ -33,7 +33,9 @@ import org.apache.struts2.StrutsInternalTestCase;
import org.apache.struts2.TestAction;
import org.apache.struts2.dispatcher.HttpParameters;
import org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest;
import org.apache.struts2.dispatcher.multipart.StrutsUploadedFile;
import org.apache.struts2.dispatcher.multipart.MultiPartRequestWrapper;
import org.apache.struts2.dispatcher.multipart.UploadedFile;
import org.springframework.mock.web.MockHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
@@ -41,8 +43,10 @@ import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -51,6 +55,38 @@ import java.util.Map;
*/
public class FileUploadInterceptorTest extends StrutsInternalTestCase {
public static final UploadedFile EMPTY_FILE = new UploadedFile() {
@Override
public Long length() {
return 0L;
}
@Override
public String getName() {
return "";
}
@Override
public boolean isFile() {
return false;
}
@Override
public boolean delete() {
return false;
}
@Override
public String getAbsolutePath() {
return null;
}
@Override
public byte[] getContent() {
return new byte[0];
}
};
private FileUploadInterceptor interceptor;
private File tempDir;
private TestAction action;
@@ -58,7 +94,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
public void testAcceptFileWithEmptyAllowedTypesAndExtensions() throws Exception {
// when allowed type is empty
ValidationAwareSupport validation = new ValidationAwareSupport();
boolean ok = interceptor.acceptFile(action, new File(""), "filename", "text/plain", "inputName", validation);
boolean ok = interceptor.acceptFile(action, EMPTY_FILE, "filename", "text/plain", "inputName", validation);
assertTrue(ok);
assertTrue(validation.getFieldErrors().isEmpty());
@@ -70,7 +106,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
// when file is of allowed types
ValidationAwareSupport validation = new ValidationAwareSupport();
boolean ok = interceptor.acceptFile(action, new File(""), "filename.txt", "text/plain", "inputName", validation);
boolean ok = interceptor.acceptFile(action, EMPTY_FILE, "filename.txt", "text/plain", "inputName", validation);
assertTrue(ok);
assertTrue(validation.getFieldErrors().isEmpty());
@@ -78,7 +114,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
// when file is not of allowed types
validation = new ValidationAwareSupport();
boolean notOk = interceptor.acceptFile(action, new File(""), "filename.html", "text/html", "inputName", validation);
boolean notOk = interceptor.acceptFile(action, EMPTY_FILE, "filename.html", "text/html", "inputName", validation);
assertFalse(notOk);
assertFalse(validation.getFieldErrors().isEmpty());
@@ -90,7 +126,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
interceptor.setAllowedTypes("text/*");
ValidationAwareSupport validation = new ValidationAwareSupport();
boolean ok = interceptor.acceptFile(action, new File(""), "filename.txt", "text/plain", "inputName", validation);
boolean ok = interceptor.acceptFile(action, EMPTY_FILE, "filename.txt", "text/plain", "inputName", validation);
assertTrue(ok);
assertTrue(validation.getFieldErrors().isEmpty());
@@ -98,7 +134,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
interceptor.setAllowedTypes("text/h*");
validation = new ValidationAwareSupport();
boolean notOk = interceptor.acceptFile(action, new File(""), "filename.html", "text/plain", "inputName", validation);
boolean notOk = interceptor.acceptFile(action, EMPTY_FILE, "filename.html", "text/plain", "inputName", validation);
assertFalse(notOk);
assertFalse(validation.getFieldErrors().isEmpty());
@@ -110,7 +146,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
// when file is of allowed extensions
ValidationAwareSupport validation = new ValidationAwareSupport();
boolean ok = interceptor.acceptFile(action, new File(""), "filename.txt", "text/plain", "inputName", validation);
boolean ok = interceptor.acceptFile(action, EMPTY_FILE, "filename.txt", "text/plain", "inputName", validation);
assertTrue(ok);
assertTrue(validation.getFieldErrors().isEmpty());
@@ -118,7 +154,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
// when file is not of allowed extensions
validation = new ValidationAwareSupport();
boolean notOk = interceptor.acceptFile(action, new File(""), "filename.html", "text/html", "inputName", validation);
boolean notOk = interceptor.acceptFile(action, EMPTY_FILE, "filename.html", "text/html", "inputName", validation);
assertFalse(notOk);
assertFalse(validation.getFieldErrors().isEmpty());
@@ -127,7 +163,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
//test with multiple extensions
interceptor.setAllowedExtensions(".txt,.lol");
validation = new ValidationAwareSupport();
ok = interceptor.acceptFile(action, new File(""), "filename.lol", "text/plain", "inputName", validation);
ok = interceptor.acceptFile(action, EMPTY_FILE, "filename.lol", "text/plain", "inputName", validation);
assertTrue(ok);
assertTrue(validation.getFieldErrors().isEmpty());
@@ -162,7 +198,7 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
URL url = ClassLoaderUtil.getResource("log4j2.xml", FileUploadInterceptorTest.class);
File file = new File(new URI(url.toString()));
assertTrue("log4j2.xml should be in src/test folder", file.exists());
boolean notOk = interceptor.acceptFile(action, file, "filename", "text/html", "inputName", validation);
boolean notOk = interceptor.acceptFile(action, new StrutsUploadedFile(file), "filename", "text/html", "inputName", validation);
assertFalse(notOk);
assertFalse(validation.getFieldErrors().isEmpty());
@@ -260,8 +296,8 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
assertTrue(!action.hasErrors());
HttpParameters parameters = mai.getInvocationContext().getParameters();
assertTrue(parameters.getNames().size() == 3);
File[] files = (File[]) parameters.get("file").getObject();
assertTrue(parameters.keySet().size() == 3);
UploadedFile[] files = (UploadedFile[]) parameters.get("file").getObject();
String[] fileContentTypes = parameters.get("fileContentType").getMultipleValues();
String[] fileRealFilenames = parameters.get("fileFileName").getMultipleValues();
@@ -320,8 +356,8 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
interceptor.intercept(mai);
HttpParameters parameters = mai.getInvocationContext().getParameters();
assertEquals(3, parameters.getNames().size());
File[] files = (File[]) parameters.get("file").getObject();
assertEquals(3, parameters.keySet().size());
UploadedFile[] files = (UploadedFile[]) parameters.get("file").getObject();
String[] fileContentTypes = parameters.get("fileContentType").getMultipleValues();
String[] fileRealFilenames = parameters.get("fileFileName").getMultipleValues();
@@ -335,6 +371,44 @@ public class FileUploadInterceptorTest extends StrutsInternalTestCase {
assertNotNull("test1.html", fileRealFilenames[0]);
}
public void testMultipartRequestLocalizedError() throws Exception {
MockHttpServletRequest req = new MockHttpServletRequest();
req.setCharacterEncoding("text/html");
req.addHeader("Content-type", "multipart/form-data; boundary=---1234");
// inspired by the unit tests for jakarta commons fileupload
String content = ("-----1234\r\n" +
"Content-Disposition: form-data; name=\"file\"; filename=\"deleteme.txt\"\r\n" +
"Content-Type: text/html\r\n" +
"\r\n" +
"Unit test of FileUploadInterceptor" +
"\r\n" +
"-----1234--\r\n");
req.setContent(content.getBytes("US-ASCII"));
MyFileupAction action = new MyFileupAction();
MockActionInvocation mai = new MockActionInvocation();
mai.setAction(action);
mai.setResultCode("success");
mai.setInvocationContext(ActionContext.getContext());
Map<String, Object> param = new HashMap<>();
ActionContext.getContext().setParameters(HttpParameters.create(param).build());
// set German locale
ActionContext.getContext().setLocale(Locale.GERMAN);
ActionContext.getContext().put(ServletActionContext.HTTP_REQUEST, createMultipartRequest(req, 10));
interceptor.intercept(mai);
assertTrue(action.hasActionErrors());
Collection<String> errors = action.getActionErrors();
assertEquals(1, errors.size());
String msg = errors.iterator().next();
// the error message should contain at least this test
assertTrue(msg.startsWith("Der Request übertraf die maximal erlaubte Größe"));
}
private String encodeTextFile(String bondary, String endline, String name, String filename, String contentType, String content) {
final StringBuilder sb = new StringBuilder(64);
sb.append(endline);
@@ -25,6 +25,7 @@ import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.DefaultLocaleProvider;
import com.opensymphony.xwork2.mock.MockActionInvocation;
import com.opensymphony.xwork2.mock.MockActionProxy;
import junit.framework.TestCase;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsStatics;
@@ -78,7 +79,7 @@ public class I18nInterceptorTest extends TestCase {
}
public void testDenmarkLocaleRequestOnly() throws Exception {
prepare(I18nInterceptor.DEFAULT_REQUESTONLY_PARAMETER, "da_DK");
prepare(I18nInterceptor.DEFAULT_REQUEST_ONLY_PARAMETER, "da_DK");
interceptor.intercept(mai);
assertFalse(mai.getInvocationContext().getParameters().get(I18nInterceptor.DEFAULT_PARAMETER).isDefined()); // should have been removed
@@ -124,7 +125,7 @@ public class I18nInterceptorTest extends TestCase {
}
public void testWithVariantRequestOnly() throws Exception {
prepare(I18nInterceptor.DEFAULT_REQUESTONLY_PARAMETER, "ja_JP_JP");
prepare(I18nInterceptor.DEFAULT_REQUEST_ONLY_PARAMETER, "ja_JP_JP");
interceptor.intercept(mai);
assertFalse(mai.getInvocationContext().getParameters().get(I18nInterceptor.DEFAULT_PARAMETER).isDefined()); // should have been removed
@@ -187,6 +188,26 @@ public class I18nInterceptorTest extends TestCase {
assertEquals(locale1, locale);
}
public void testCookieCreation() throws Exception {
prepare(I18nInterceptor.DEFAULT_COOKIE_PARAMETER, "da_DK");
final Cookie cookie = new Cookie(I18nInterceptor.DEFAULT_COOKIE_ATTRIBUTE, "da_DK");
HttpServletResponse response = EasyMock.createMock(HttpServletResponse.class);
response.addCookie(CookieMatcher.eqCookie(cookie));
EasyMock.replay(response);
ac.put(StrutsStatics.HTTP_RESPONSE, response);
interceptor.setLocaleStorage(I18nInterceptor.Storage.COOKIE.name());
interceptor.intercept(mai);
EasyMock.verify(response);
assertNull(session.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)); // should not be stored here
assertNull(session.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)); // should not create a locale object
}
private void prepare(String key, Serializable value) {
Map<String, Serializable> params = new HashMap<>();
params.put(key, value);
@@ -214,9 +235,16 @@ public class I18nInterceptorTest extends TestCase {
return SUCCESS;
}
};
MockActionProxy proxy = new MockActionProxy();
proxy.setAction(action);
proxy.setNamespace("i18n");
proxy.setActionName("anAction");
mai = new MockActionInvocation();
((MockActionInvocation) mai).setAction(action);
((MockActionInvocation) mai).setInvocationContext(ac);
((MockActionInvocation) mai).setProxy(proxy);
}
public void tearDown() throws Exception {
@@ -255,23 +283,4 @@ public class I18nInterceptorTest extends TestCase {
}
}
public void testCookieCreation() throws Exception {
prepare(I18nInterceptor.DEFAULT_COOKIE_PARAMETER, "da_DK");
final Cookie cookie = new Cookie(I18nInterceptor.DEFAULT_COOKIE_ATTRIBUTE, "da_DK");
HttpServletResponse response = EasyMock.createMock(HttpServletResponse.class);
response.addCookie(CookieMatcher.eqCookie(cookie));
EasyMock.replay(response);
ac.put(StrutsStatics.HTTP_RESPONSE, response);
interceptor.intercept(mai);
EasyMock.verify(response);
Locale denmark = new Locale("da", "DK");
assertNotNull(session.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)); // should be stored here
assertEquals(denmark, session.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)); // should create a locale object
}
}
@@ -93,7 +93,7 @@ public class MultiselectInterceptorTest extends StrutsInternalTestCase {
HttpParameters parameters = ai.getInvocationContext().getParameters();
assertFalse(parameters.contains("__multiselect_superpower"));
assertEquals(3, parameters.getNames().size()); // should be 3 as __multiselect_ should be removed
assertEquals(3, parameters.keySet().size()); // should be 3 as __multiselect_ should be removed
assertEquals("robin", parameters.get("superpower").getValue());
}
@@ -111,7 +111,7 @@ public class MultiselectInterceptorTest extends StrutsInternalTestCase {
HttpParameters parameters = ai.getInvocationContext().getParameters();
assertFalse(parameters.contains("__multiselect_superpower"));
assertEquals(3, parameters.getNames().size()); // should be 3 as __multiselect_ should be removed
assertEquals(3, parameters.keySet().size()); // should be 3 as __multiselect_ should be removed
assertFalse(parameters.get("superpower").isDefined());
}
@@ -133,7 +133,7 @@ public class MultiselectInterceptorTest extends StrutsInternalTestCase {
HttpParameters parameters = ai.getInvocationContext().getParameters();
assertFalse(parameters.contains("__multiselect_superpower"));
assertFalse(parameters.contains("__multiselect_cool"));
assertEquals(4, parameters.getNames().size()); // should be 4 as __multiselect_ should be removed
assertEquals(4, parameters.keySet().size()); // should be 4 as __multiselect_ should be removed
assertEquals("yes", parameters.get("superpower").getValue());
assertFalse(parameters.get("cool").isDefined());
}
@@ -91,7 +91,7 @@ public class ServletConfigInterceptorTest extends StrutsInternalTestCase {
HttpParameters param = HttpParameters.create().build();
mai.getInvocationContext().setParameters(param);
mock.setParameters(param.toMap());
param.applyParameters(mock);
expectLastCall().times(1);
replay(mock);
@@ -227,7 +227,7 @@ public class ActionTagTest extends AbstractTagTest {
// check parameters, there should be one
ActionInvocation ai = component.getProxy().getInvocation();
ActionContext ac = ai.getInvocationContext();
assertEquals(1, ac.getParameters().getNames().size());
assertEquals(1, ac.getParameters().keySet().size());
}
public void testIngoreContextParamsTrue() throws Exception {
@@ -252,7 +252,7 @@ public class ActionTagTest extends AbstractTagTest {
// check parameters, there should be one
ActionInvocation ai = component.getProxy().getInvocation();
ActionContext ac = ai.getInvocationContext();
assertEquals(0, ac.getParameters().getNames().size());
assertEquals(0, ac.getParameters().keySet().size());
}
public void testNoNameDefined() throws Exception {
@@ -3,6 +3,7 @@ package org.apache.struts2.views.jsp;
import com.opensymphony.xwork2.ActionContext;
import org.apache.struts2.TestAction;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.Locale;
@@ -65,10 +66,7 @@ public class NumberTagTest extends AbstractTagTest {
// then
NumberFormat format = NumberFormat.getCurrencyInstance((Locale) context.get(ActionContext.LOCALE));
/*
TODO lukaszlenart: enable when switched to Java 1.6
format.setRoundingMode(RoundingMode.CEILING);
*/
String expected = format.format(120.0f);
assertEquals(expected, writer.toString());
@@ -84,7 +82,7 @@ public class NumberTagTest extends AbstractTagTest {
NumberTag tag = new NumberTag();
tag.setPageContext(pageContext);
tag.setName("floatNumber");
tag.setRoundingMode("ceiling");
tag.setRoundingMode("down");
// when
tag.doStartTag();
@@ -92,10 +90,7 @@ public class NumberTagTest extends AbstractTagTest {
// then
NumberFormat format = NumberFormat.getInstance((Locale) context.get(ActionContext.LOCALE));
/*
TODO lukaszlenart: enable when switched to Java 1.6
format.setRoundingMode(RoundingMode.CEILING);
*/
format.setRoundingMode(RoundingMode.DOWN);
String expected = format.format(120.45f);
assertEquals(expected, writer.toString());
@@ -218,10 +218,11 @@ public class TextTagTest extends AbstractTagTest {
assertEquals(value_int, writer.toString());
}
public void testTextTagSearchesStackByDefault() throws JspException {
public void testTextTagCanSearchStackToFindValue() throws JspException {
String key = "result";
tag.setName(key);
tag.setSearchValueStack("true");
final StringBuffer buffer = writer.getBuffer();
buffer.delete(0, buffer.length());
ValueStack newStack = container.getInstance(ValueStackFactory.class).createValueStack();
@@ -238,11 +239,10 @@ public class TextTagTest extends AbstractTagTest {
assertEquals("bar", writer.toString());
}
public void testTextTagDoNotSearchStack() throws JspException {
public void testTextTagDoNotSearchStackByDefault() throws JspException {
String key = "result";
tag.setName(key);
tag.setSearchValueStack("false");
final StringBuffer buffer = writer.getBuffer();
buffer.delete(0, buffer.length());
ValueStack newStack = container.getInstance(ValueStackFactory.class).createValueStack();
@@ -274,7 +274,7 @@ public class TextTagTest extends AbstractTagTest {
public void testWithNoMessageAndNoDefaultKeyReturned() throws JspException {
final String key = "key.does.not.exist";
tag.setName("'" + key + "'");
tag.setName(key);
tag.doStartTag();
tag.doEndTag();
assertEquals(key, writer.toString());
@@ -688,7 +688,7 @@ public class URLTagTest extends AbstractUITagTest {
ParamTag param1 = new ParamTag();
param1.setPageContext(pageContext);
param1.setName("paraWithSetValue");
param1.setName("paramWithSetValue");
param1.setValue("");
param1.setSuppressEmptyParameters(false);
param1.doStartTag();
@@ -696,7 +696,7 @@ public class URLTagTest extends AbstractUITagTest {
ParamTag param2 = new ParamTag();
param2.setPageContext(pageContext);
param2.setName("paraWithSetBody");
param2.setName("paramWithSetBody");
param2.setBodyContent(new MockBodyContent() {
@Override
public String getString() {
@@ -709,7 +709,7 @@ public class URLTagTest extends AbstractUITagTest {
ParamTag param3 = new ParamTag();
param3.setPageContext(pageContext);
param3.setName("paraWithSetValueSurpressed");
param3.setName("paramWithSetValueSuppressed");
param3.setValue("");
param3.setSuppressEmptyParameters(true);
param3.doStartTag();
@@ -717,7 +717,7 @@ public class URLTagTest extends AbstractUITagTest {
ParamTag param4 = new ParamTag();
param4.setPageContext(pageContext);
param4.setName("paraWithSetBodySurpressed");
param4.setName("paramWithSetBodySuppressed");
param4.setBodyContent(new MockBodyContent() {
@Override
public String getString() {
@@ -730,7 +730,7 @@ public class URLTagTest extends AbstractUITagTest {
tag.doEndTag();
assertEquals("/company.action?paraWithSetValue=&paraWithSetBody=", writer.toString());
assertEquals("/company.action?paramWithSetValue=&paramWithSetBody=", writer.toString());
}
protected void setUp() throws Exception {
@@ -102,6 +102,21 @@ public class DateTagTest extends AbstractTagTest {
assertEquals(formatted, writer.toString());
}
public void testCustomFormatLong() throws Exception {
String format = "yyyy/MM/dd hh:mm:ss";
Date date = new Date();
String formatted = new SimpleDateFormat(format).format(date);
// long
context.put("myDate", date.getTime());
tag.setName("myDate");
tag.setNice(false);
tag.setFormat(format);
tag.doStartTag();
tag.doEndTag();
assertEquals(formatted, writer.toString());
}
public void testDefaultFormat() throws Exception {
Date now = new Date();
String formatted = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM,
@@ -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
@@ -192,6 +190,17 @@ public class XSLTResultTest extends StrutsInternalTestCase {
}
}
public void testTransformWithBadCharacter() throws Exception {
result = new XSLTResult();
result.setStylesheetLocation("XSLTResultTest.bad.character.xsl");
try {
result.execute(mai);
fail("Should have thrown an exception");
} catch (Exception ex) {
assertEquals("Error transforming result", ex.getMessage());
}
}
public void testStatusCode() throws Exception {
result.setParse(false);
result.setStylesheetLocation("XSLTResultTest.xsl");
@@ -0,0 +1,30 @@
<!--
/*
* 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.
*/
-->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/TR/xhtml1/strict">
<xsl:template match="result">
<p>&#x1a;</p>
<xsl:copy-of select="document('XSLTResultTest-val.xml')"/>
</xsl:template>
</xsl:stylesheet>
@@ -0,0 +1,17 @@
<!DOCTYPE xwork PUBLIC
"-//Apache Struts//XWork 2.5//EN"
"http://struts.apache.org/dtds/xwork-2.5.dtd"
>
<xwork>
<constant name="foo" value="bar"/>
<constant name="user" value="${env.USER}"/>
<constant name="home" value="Current HOME = ${env.HOME}"/>
<constant name="os" value="Current OS = ${os.name}"/>
<constant name="unknown" value="Unknown = ${env.UNKNOWN:default}"/>
<constant name="struts.devMode" value="${env.STRUTS_DEV_MODE:false}"/>
</xwork>
+1 -1
View File
@@ -24,7 +24,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.5.5</version>
<version>2.5.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -25,7 +25,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.5.5</version>
<version>2.5.7</version>
</parent>
<artifactId>struts2-cdi-plugin</artifactId>
+1 -1
View File
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.5.5</version>
<version>2.5.7</version>
</parent>
<artifactId>struts2-config-browser-plugin</artifactId>
+11 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.5.5</version>
<version>2.5.7</version>
</parent>
<artifactId>struts2-convention-plugin</artifactId>
@@ -32,6 +32,16 @@
<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>
<!-- testing -->
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
@@ -13,12 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.util.finder;
package org.apache.struts2.convention;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.FileManager;
import com.opensymphony.xwork2.FileManagerFactory;
import com.opensymphony.xwork2.XWorkException;
import com.opensymphony.xwork2.util.finder.ClassFinder;
import com.opensymphony.xwork2.util.finder.ClassLoaderInterface;
import com.opensymphony.xwork2.util.finder.Test;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+1 -1
View File
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.5.5</version>
<version>2.5.7</version>
</parent>
<artifactId>struts2-dwr-plugin</artifactId>
+1 -1
View File
@@ -26,7 +26,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.5.5</version>
<version>2.5.7</version>
</parent>
<artifactId>struts2-embeddedjsp-plugin</artifactId>
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-plugins</artifactId>
<version>2.5.5</version>
<version>2.5.7</version>
</parent>
<artifactId>struts2-gxp-plugin</artifactId>

Some files were not shown because too many files have changed in this diff Show More