mirror of
https://github.com/apache/struts.git
synced 2026-08-06 15:17:00 +00:00
Merge pull request #621 from apache/WW-3737-custom-separator
[WW-3737] Allows to define a custom separator used to split patterns
This commit is contained in:
@@ -34,22 +34,22 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base JUnit TestCase to extend for XWork specific JUnit tests. Uses
|
||||
* Base JUnit TestCase to extend for XWork specific JUnit tests. Uses
|
||||
* the generic test setup for logic.
|
||||
*
|
||||
* @author plightbo
|
||||
*/
|
||||
public abstract class XWorkTestCase extends TestCase {
|
||||
|
||||
|
||||
protected ConfigurationManager configurationManager;
|
||||
protected Configuration configuration;
|
||||
protected Container container;
|
||||
protected ActionProxyFactory actionProxyFactory;
|
||||
|
||||
|
||||
public XWorkTestCase() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
configurationManager = XWorkTestCaseHelper.setUp();
|
||||
@@ -57,7 +57,7 @@ public abstract class XWorkTestCase extends TestCase {
|
||||
container = configuration.getContainer();
|
||||
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
XWorkTestCaseHelper.tearDown(configurationManager);
|
||||
@@ -66,34 +66,33 @@ public abstract class XWorkTestCase extends TestCase {
|
||||
container = null;
|
||||
actionProxyFactory = null;
|
||||
}
|
||||
|
||||
|
||||
protected void loadConfigurationProviders(ConfigurationProvider... providers) {
|
||||
configurationManager = XWorkTestCaseHelper.loadConfigurationProviders(configurationManager, providers);
|
||||
configuration = configurationManager.getConfiguration();
|
||||
container = configuration.getContainer();
|
||||
actionProxyFactory = container.getInstance(ActionProxyFactory.class);
|
||||
}
|
||||
|
||||
protected void loadButAdd(final Class<?> type, final Object impl) {
|
||||
|
||||
protected <T> void loadButAdd(final Class<T> type, final T impl) {
|
||||
loadButAdd(type, Container.DEFAULT_NAME, impl);
|
||||
}
|
||||
|
||||
protected void loadButAdd(final Class<?> type, final String name, final Object impl) {
|
||||
|
||||
protected <T> void loadButAdd(final Class<T> type, final String name, final T impl) {
|
||||
loadConfigurationProviders(new StubConfigurationProvider() {
|
||||
@Override
|
||||
public void register(ContainerBuilder builder,
|
||||
LocatableProperties props) throws ConfigurationException {
|
||||
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
|
||||
if (impl instanceof String || ClassUtils.isPrimitiveOrWrapper(impl.getClass())) {
|
||||
props.setProperty(name, "" + impl);
|
||||
} else {
|
||||
builder.factory(type, name, new Factory() {
|
||||
public Object create(Context context) throws Exception {
|
||||
builder.factory(type, name, new Factory<T>() {
|
||||
public T create(Context context) throws Exception {
|
||||
return impl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class type() {
|
||||
return impl.getClass();
|
||||
public Class<T> type() {
|
||||
return (Class<T>) impl.getClass();
|
||||
}
|
||||
}, Scope.SINGLETON);
|
||||
}
|
||||
|
||||
@@ -19,10 +19,26 @@ import com.opensymphony.xwork2.inject.util.ReferenceCache;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.*;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ReflectPermission;
|
||||
import java.security.AccessControlException;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Default {@link Container} implementation.
|
||||
@@ -39,11 +55,7 @@ class ContainerImpl implements Container {
|
||||
this.factories = factories;
|
||||
final Map<Class<?>, Set<String>> map = new HashMap<>();
|
||||
for (Key<?> key : factories.keySet()) {
|
||||
Set<String> names = map.get(key.getType());
|
||||
if (names == null) {
|
||||
names = new HashSet<>();
|
||||
map.put(key.getType(), names);
|
||||
}
|
||||
Set<String> names = map.computeIfAbsent(key.getType(), k -> new HashSet<>());
|
||||
names.add(key.getName());
|
||||
}
|
||||
|
||||
@@ -63,20 +75,20 @@ class ContainerImpl implements Container {
|
||||
* Field and method injectors.
|
||||
*/
|
||||
final Map<Class<?>, List<Injector>> injectors =
|
||||
new ReferenceCache<Class<?>, List<Injector>>() {
|
||||
@Override
|
||||
protected List<Injector> create(Class<?> key) {
|
||||
List<Injector> injectors = new ArrayList<>();
|
||||
addInjectors(key, injectors);
|
||||
return injectors;
|
||||
}
|
||||
};
|
||||
new ReferenceCache<Class<?>, List<Injector>>() {
|
||||
@Override
|
||||
protected List<Injector> create(Class<?> key) {
|
||||
List<Injector> injectors = new ArrayList<>();
|
||||
addInjectors(key, injectors);
|
||||
return injectors;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively adds injectors for fields and methods from the given class to the given list. Injects parent classes
|
||||
* before sub classes.
|
||||
*/
|
||||
void addInjectors(Class clazz, List<Injector> injectors) {
|
||||
void addInjectors(Class<?> clazz, List<Injector> injectors) {
|
||||
if (clazz == Object.class) {
|
||||
return;
|
||||
}
|
||||
@@ -97,38 +109,24 @@ class ContainerImpl implements Container {
|
||||
addInjectorsForMethods(clazz.getDeclaredMethods(), true, injectors);
|
||||
}
|
||||
|
||||
callInContext(new ContextualCallable<Void>() {
|
||||
public Void call(InternalContext context) {
|
||||
for (Injector injector : injectors) {
|
||||
injector.inject(context, null);
|
||||
}
|
||||
return null;
|
||||
callInContext((ContextualCallable<Void>) context -> {
|
||||
for (Injector injector : injectors) {
|
||||
injector.inject(context, null);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
void addInjectorsForMethods(Method[] methods, boolean statics, List<Injector> injectors) {
|
||||
addInjectorsForMembers(Arrays.asList(methods), statics, injectors,
|
||||
new InjectorFactory<Method>() {
|
||||
public Injector create(ContainerImpl container, Method method,
|
||||
String name) throws MissingDependencyException {
|
||||
return new MethodInjector(container, method, name);
|
||||
}
|
||||
});
|
||||
addInjectorsForMembers(Arrays.asList(methods), statics, injectors, MethodInjector::new);
|
||||
}
|
||||
|
||||
void addInjectorsForFields(Field[] fields, boolean statics, List<Injector> injectors) {
|
||||
addInjectorsForMembers(Arrays.asList(fields), statics, injectors,
|
||||
new InjectorFactory<Field>() {
|
||||
public Injector create(ContainerImpl container, Field field,
|
||||
String name) throws MissingDependencyException {
|
||||
return new FieldInjector(container, field, name);
|
||||
}
|
||||
});
|
||||
addInjectorsForMembers(Arrays.asList(fields), statics, injectors, FieldInjector::new);
|
||||
}
|
||||
|
||||
<M extends Member & AnnotatedElement> void addInjectorsForMembers(
|
||||
List<M> members, boolean statics, List<Injector> injectors, InjectorFactory<M> injectorFactory) {
|
||||
List<M> members, boolean statics, List<Injector> injectors, InjectorFactory<M> injectorFactory) {
|
||||
for (M member : members) {
|
||||
if (isStatic(member) == statics) {
|
||||
Inject inject = member.getAnnotation(Inject.class);
|
||||
@@ -148,12 +146,12 @@ class ContainerImpl implements Container {
|
||||
interface InjectorFactory<M extends Member & AnnotatedElement> {
|
||||
|
||||
Injector create(ContainerImpl container, M member, String name)
|
||||
throws MissingDependencyException;
|
||||
throws MissingDependencyException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a given {@link Member} is static or not.
|
||||
*
|
||||
*
|
||||
* @param member checked for the static modifier.
|
||||
* @return true if member is static, false otherwise.
|
||||
*/
|
||||
@@ -163,13 +161,13 @@ class ContainerImpl implements Container {
|
||||
|
||||
/**
|
||||
* Determines if a given {@link Member} is considered to be public for reflection usage or not.
|
||||
*
|
||||
*
|
||||
* @param member checked to see if it is public for reflection usage.
|
||||
* @return true if member is public for reflection usage, false otherwise.
|
||||
*/
|
||||
private static boolean isPublicForReflection(Member member) {
|
||||
return Modifier.isPublic(member.getModifiers()) &&
|
||||
Modifier.isPublic(member.getDeclaringClass().getModifiers());
|
||||
Modifier.isPublic(member.getDeclaringClass().getModifiers());
|
||||
}
|
||||
|
||||
static class FieldInjector implements Injector {
|
||||
@@ -179,7 +177,7 @@ class ContainerImpl implements Container {
|
||||
final ExternalContext<?> externalContext;
|
||||
|
||||
public FieldInjector(ContainerImpl container, Field field, String name)
|
||||
throws MissingDependencyException {
|
||||
throws MissingDependencyException {
|
||||
this.field = field;
|
||||
if (!isPublicForReflection(field) && !field.isAccessible()) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
@@ -190,7 +188,7 @@ class ContainerImpl implements Container {
|
||||
field.setAccessible(true);
|
||||
} catch (AccessControlException e) {
|
||||
throw new DependencyException("Security manager in use, could not access field: "
|
||||
+ field.getDeclaringClass().getName() + "(" + field.getName() + ")", e);
|
||||
+ field.getDeclaringClass().getName() + "(" + field.getName() + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,8 +223,12 @@ class ContainerImpl implements Container {
|
||||
* @param parameterTypes parameter types
|
||||
* @return injections
|
||||
*/
|
||||
<M extends AccessibleObject & Member> ParameterInjector<?>[]
|
||||
getParametersInjectors(M member, Annotation[][] annotations, Class[] parameterTypes, String defaultName) throws MissingDependencyException {
|
||||
<M extends AccessibleObject & Member> ParameterInjector<?>[] getParametersInjectors(
|
||||
M member,
|
||||
Annotation[][] annotations,
|
||||
Class<?>[] parameterTypes,
|
||||
String defaultName
|
||||
) throws MissingDependencyException {
|
||||
final List<ParameterInjector<?>> parameterInjectors = new ArrayList<>();
|
||||
|
||||
final Iterator<Annotation[]> annotationsIterator = Arrays.asList(annotations).iterator();
|
||||
@@ -247,12 +249,11 @@ class ContainerImpl implements Container {
|
||||
}
|
||||
|
||||
final ExternalContext<T> externalContext = ExternalContext.newInstance(member, key, this);
|
||||
return new ParameterInjector<T>(externalContext, factory);
|
||||
return new ParameterInjector<>(externalContext, factory);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private ParameterInjector<?>[] toArray(List<ParameterInjector<?>> parameterInjections) {
|
||||
return parameterInjections.toArray(new ParameterInjector[parameterInjections.size()]);
|
||||
return parameterInjections.toArray(new ParameterInjector[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,7 +262,7 @@ class ContainerImpl implements Container {
|
||||
Inject findInject(Annotation[] annotations) {
|
||||
for (Annotation annotation : annotations) {
|
||||
if (annotation.annotationType() == Inject.class) {
|
||||
return Inject.class.cast(annotation);
|
||||
return (Inject) annotation;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -283,7 +284,7 @@ class ContainerImpl implements Container {
|
||||
method.setAccessible(true);
|
||||
} catch (AccessControlException e) {
|
||||
throw new DependencyException("Security manager in use, could not access method: "
|
||||
+ name + "(" + method.getName() + ")", e);
|
||||
+ name + "(" + method.getName() + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +293,7 @@ class ContainerImpl implements Container {
|
||||
throw new DependencyException(method + " has no parameters to inject.");
|
||||
}
|
||||
parameterInjectors = container.getParametersInjectors(
|
||||
method, method.getParameterAnnotations(), parameterTypes, name);
|
||||
method, method.getParameterAnnotations(), parameterTypes, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -305,14 +306,12 @@ class ContainerImpl implements Container {
|
||||
}
|
||||
}
|
||||
|
||||
Map<Class<?>, ConstructorInjector> constructors =
|
||||
new ReferenceCache<Class<?>, ConstructorInjector>() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ConstructorInjector<?> create(Class<?> implementation) {
|
||||
return new ConstructorInjector(ContainerImpl.this, implementation);
|
||||
}
|
||||
};
|
||||
Map<Class<?>, ConstructorInjector<?>> constructors = new ReferenceCache<Class<?>, ConstructorInjector<?>>() {
|
||||
@Override
|
||||
protected ConstructorInjector<?> create(Class<?> implementation) {
|
||||
return new ConstructorInjector<>(ContainerImpl.this, implementation);
|
||||
}
|
||||
};
|
||||
|
||||
static class ConstructorInjector<T> {
|
||||
|
||||
@@ -334,7 +333,7 @@ class ContainerImpl implements Container {
|
||||
constructor.setAccessible(true);
|
||||
} catch (AccessControlException e) {
|
||||
throw new DependencyException("Security manager in use, could not access constructor: "
|
||||
+ implementation.getName() + "(" + constructor.getName() + ")", e);
|
||||
+ implementation.getName() + "(" + constructor.getName() + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,14 +358,14 @@ class ContainerImpl implements Container {
|
||||
}
|
||||
|
||||
ParameterInjector<?>[] constructParameterInjector(
|
||||
Inject inject, ContainerImpl container, Constructor<T> constructor) throws MissingDependencyException {
|
||||
Inject inject, ContainerImpl container, Constructor<T> constructor) throws MissingDependencyException {
|
||||
return constructor.getParameterTypes().length == 0
|
||||
? null // default constructor.
|
||||
: container.getParametersInjectors(
|
||||
constructor,
|
||||
constructor.getParameterAnnotations(),
|
||||
constructor.getParameterTypes(),
|
||||
inject.value()
|
||||
? null // default constructor.
|
||||
: container.getParametersInjectors(
|
||||
constructor,
|
||||
constructor.getParameterAnnotations(),
|
||||
constructor.getParameterTypes(),
|
||||
inject.value()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -378,7 +377,7 @@ class ContainerImpl implements Container {
|
||||
if (constructor.getAnnotation(Inject.class) != null) {
|
||||
if (found != null) {
|
||||
throw new DependencyException("More than one constructor annotated"
|
||||
+ " with @Inject found in " + implementation + ".");
|
||||
+ " with @Inject found in " + implementation + ".");
|
||||
}
|
||||
found = constructor;
|
||||
}
|
||||
@@ -466,7 +465,7 @@ class ContainerImpl implements Container {
|
||||
}
|
||||
}
|
||||
|
||||
private static Object[] getParameters(Member member, InternalContext context, ParameterInjector[] parameterInjectors) {
|
||||
private static Object[] getParameters(Member member, InternalContext context, ParameterInjector<?>[] parameterInjectors) {
|
||||
if (parameterInjectors == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -494,13 +493,12 @@ class ContainerImpl implements Container {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> T getInstance(Class<T> type, String name, InternalContext context) {
|
||||
final ExternalContext<?> previous = context.getExternalContext();
|
||||
final Key<T> key = Key.newInstance(type, name);
|
||||
context.setExternalContext(ExternalContext.newInstance(null, key, this));
|
||||
try {
|
||||
final InternalFactory o = getFactory(key);
|
||||
final InternalFactory<? extends T> o = getFactory(key);
|
||||
if (o != null) {
|
||||
return getFactory(key).create(context);
|
||||
} else {
|
||||
@@ -517,39 +515,25 @@ class ContainerImpl implements Container {
|
||||
|
||||
@Override
|
||||
public void inject(final Object o) {
|
||||
callInContext(new ContextualCallable<Void>() {
|
||||
public Void call(InternalContext context) {
|
||||
inject(o, context);
|
||||
return null;
|
||||
}
|
||||
callInContext((ContextualCallable<Void>) context -> {
|
||||
inject(o, context);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T inject(final Class<T> implementation) {
|
||||
return callInContext(new ContextualCallable<T>() {
|
||||
public T call(InternalContext context) {
|
||||
return inject(implementation, context);
|
||||
}
|
||||
});
|
||||
return callInContext(context -> inject(implementation, context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInstance(final Class<T> type, final String name) {
|
||||
return callInContext(new ContextualCallable<T>() {
|
||||
public T call(InternalContext context) {
|
||||
return getInstance(type, name, context);
|
||||
}
|
||||
});
|
||||
return callInContext(context -> getInstance(type, name, context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInstance(final Class<T> type) {
|
||||
return callInContext(new ContextualCallable<T>() {
|
||||
public T call(InternalContext context) {
|
||||
return getInstance(type, context);
|
||||
}
|
||||
});
|
||||
return callInContext(context -> getInstance(type, context));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -561,12 +545,7 @@ class ContainerImpl implements Container {
|
||||
return names;
|
||||
}
|
||||
|
||||
ThreadLocal<Object[]> localContext = new ThreadLocal<Object[]>() {
|
||||
@Override
|
||||
protected Object[] initialValue() {
|
||||
return new Object[1];
|
||||
}
|
||||
};
|
||||
ThreadLocal<Object[]> localContext = ThreadLocal.withInitial(() -> new Object[1]);
|
||||
|
||||
/**
|
||||
* Looks up thread local context. Creates (and removes) a new context if necessary.
|
||||
@@ -598,7 +577,7 @@ class ContainerImpl implements Container {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
<T> ConstructorInjector<T> getConstructor(Class<T> implementation) {
|
||||
return constructors.get(implementation);
|
||||
return (ConstructorInjector<T>) constructors.get(implementation);
|
||||
}
|
||||
|
||||
final ThreadLocal<Object> localScopeStrategy = new ThreadLocal<>();
|
||||
|
||||
@@ -56,6 +56,9 @@ public final class StrutsConstants {
|
||||
/** Comma separated list of patterns (java.util.regex.Pattern) to be excluded from Struts2-processing */
|
||||
public static final String STRUTS_ACTION_EXCLUDE_PATTERN = "struts.action.excludePattern";
|
||||
|
||||
/** A custom separator used to split list of patterns (java.util.regex.Pattern) to be excluded from Struts2-processing */
|
||||
public static final String STRUTS_ACTION_EXCLUDE_PATTERN_SEPARATOR = "struts.action.excludePattern.separator";
|
||||
|
||||
/** Whether to use the response encoding (JSP page encoding) for s:include tag processing (false - use STRUTS_I18N_ENCODING - by default) */
|
||||
public static final String STRUTS_TAG_INCLUDETAG_USERESPONSEENCODING = "struts.tag.includetag.useResponseEncoding";
|
||||
|
||||
|
||||
@@ -21,7 +21,12 @@ package org.apache.struts2.dispatcher;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -36,10 +41,9 @@ public class InitOperations {
|
||||
* Creates and initializes the dispatcher
|
||||
*
|
||||
* @param filterConfig host configuration
|
||||
*
|
||||
* @return the dispatcher
|
||||
*/
|
||||
public Dispatcher initDispatcher( HostConfig filterConfig ) {
|
||||
public Dispatcher initDispatcher(HostConfig filterConfig) {
|
||||
Dispatcher dispatcher = createDispatcher(filterConfig);
|
||||
dispatcher.init();
|
||||
return dispatcher;
|
||||
@@ -49,10 +53,10 @@ public class InitOperations {
|
||||
* Initializes the static content loader with the filter configuration
|
||||
*
|
||||
* @param filterConfig host configuration
|
||||
* @param dispatcher the dispatcher
|
||||
* @param dispatcher the dispatcher
|
||||
* @return the static content loader
|
||||
*/
|
||||
public StaticContentLoader initStaticContentLoader( HostConfig filterConfig, Dispatcher dispatcher ) {
|
||||
public StaticContentLoader initStaticContentLoader(HostConfig filterConfig, Dispatcher dispatcher) {
|
||||
StaticContentLoader loader = dispatcher.getContainer().getInstance(StaticContentLoader.class);
|
||||
loader.setHostConfig(filterConfig);
|
||||
return loader;
|
||||
@@ -60,7 +64,6 @@ public class InitOperations {
|
||||
|
||||
/**
|
||||
* @return The dispatcher on the thread.
|
||||
*
|
||||
* @throws IllegalStateException If there is no dispatcher available
|
||||
*/
|
||||
public Dispatcher findDispatcherOnThread() {
|
||||
@@ -75,12 +78,11 @@ public class InitOperations {
|
||||
* Create a {@link Dispatcher}
|
||||
*
|
||||
* @param filterConfig host configuration
|
||||
*
|
||||
* @return The dispatcher on the thread.
|
||||
*/
|
||||
protected Dispatcher createDispatcher(HostConfig filterConfig) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
for ( Iterator<String> parameterNames = filterConfig.getInitParameterNames(); parameterNames.hasNext(); ) {
|
||||
for (Iterator<String> parameterNames = filterConfig.getInitParameterNames(); parameterNames.hasNext(); ) {
|
||||
String name = parameterNames.next();
|
||||
String value = filterConfig.getInitParameter(name);
|
||||
params.put(name, value);
|
||||
@@ -96,20 +98,23 @@ public class InitOperations {
|
||||
* Extract a list of patterns to exclude from request filtering
|
||||
*
|
||||
* @param dispatcher The dispatcher to check for exclude pattern configuration
|
||||
*
|
||||
* @return a List of Patterns for request to exclude if apply, or <tt>null</tt>
|
||||
*
|
||||
* @see org.apache.struts2.StrutsConstants#STRUTS_ACTION_EXCLUDE_PATTERN
|
||||
*/
|
||||
public List<Pattern> buildExcludedPatternsList( Dispatcher dispatcher ) {
|
||||
return buildExcludedPatternsList(dispatcher.getContainer().getInstance(String.class, StrutsConstants.STRUTS_ACTION_EXCLUDE_PATTERN));
|
||||
public List<Pattern> buildExcludedPatternsList(Dispatcher dispatcher) {
|
||||
String excludePatterns = dispatcher.getContainer().getInstance(String.class, StrutsConstants.STRUTS_ACTION_EXCLUDE_PATTERN);
|
||||
String separator = dispatcher.getContainer().getInstance(String.class, StrutsConstants.STRUTS_ACTION_EXCLUDE_PATTERN_SEPARATOR);
|
||||
if (separator == null) {
|
||||
separator = ",";
|
||||
}
|
||||
return buildExcludedPatternsList(excludePatterns, separator);
|
||||
}
|
||||
|
||||
private List<Pattern> buildExcludedPatternsList( String patterns ) {
|
||||
|
||||
private List<Pattern> buildExcludedPatternsList(String patterns, String separator) {
|
||||
if (null != patterns && patterns.trim().length() != 0) {
|
||||
List<Pattern> list = new ArrayList<>();
|
||||
String[] tokens = patterns.split(",");
|
||||
for ( String token : tokens ) {
|
||||
String[] tokens = patterns.split(separator);
|
||||
for (String token : tokens) {
|
||||
list.add(Pattern.compile(token.trim()));
|
||||
}
|
||||
return Collections.unmodifiableList(list);
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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 com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
import com.opensymphony.xwork2.util.location.LocatableProperties;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
import org.apache.struts2.config.PropertiesConfigurationProvider;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class InitOperationsTest extends StrutsInternalTestCase {
|
||||
|
||||
public void testExcludePatterns() {
|
||||
// given
|
||||
loadConfigurationProviders(new PropertiesConfigurationProvider() {
|
||||
@Override
|
||||
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
|
||||
props.setProperty(StrutsConstants.STRUTS_ACTION_EXCLUDE_PATTERN, "/ns1/.*\\.json,/ns2/.*\\.json");
|
||||
}
|
||||
});
|
||||
|
||||
Dispatcher mockDispatcher = mock(Dispatcher.class);
|
||||
when(mockDispatcher.getContainer()).thenReturn(container);
|
||||
|
||||
// when
|
||||
InitOperations init = new InitOperations();
|
||||
List<Pattern> patterns = init.buildExcludedPatternsList(mockDispatcher);
|
||||
|
||||
// then
|
||||
assertThat(patterns).extracting(Pattern::toString).containsOnly(
|
||||
"/ns1/.*\\.json",
|
||||
"/ns2/.*\\.json"
|
||||
);
|
||||
}
|
||||
|
||||
public void testExcludePatternsUsingCustomSeparator() {
|
||||
// given
|
||||
loadConfigurationProviders(new PropertiesConfigurationProvider() {
|
||||
@Override
|
||||
public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException {
|
||||
props.setProperty(StrutsConstants.STRUTS_ACTION_EXCLUDE_PATTERN, "/ns1/[a-z]{1,10}.json///ns2/[a-z]{1,10}.json");
|
||||
props.setProperty(StrutsConstants.STRUTS_ACTION_EXCLUDE_PATTERN_SEPARATOR, "//");
|
||||
}
|
||||
});
|
||||
|
||||
Dispatcher mockDispatcher = mock(Dispatcher.class);
|
||||
when(mockDispatcher.getContainer()).thenReturn(container);
|
||||
|
||||
// when
|
||||
InitOperations init = new InitOperations();
|
||||
|
||||
String separator = container.getInstance(String.class, StrutsConstants.STRUTS_ACTION_EXCLUDE_PATTERN_SEPARATOR);
|
||||
List<Pattern> patterns = init.buildExcludedPatternsList(mockDispatcher);
|
||||
|
||||
// then
|
||||
assertThat(separator).isNotBlank().isEqualTo("//");
|
||||
assertThat(patterns).extracting(Pattern::toString).containsOnly(
|
||||
"/ns1/[a-z]{1,10}.json",
|
||||
"/ns2/[a-z]{1,10}.json"
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user