mirror of
https://github.com/apache/struts.git
synced 2026-08-07 15:46:57 +00:00
WW-4540 Implements Strict DMI aka SMI
This commit is contained in:
@@ -194,12 +194,11 @@ public class DefaultActionProxy implements ActionProxy, Serializable {
|
||||
|
||||
resolveMethod();
|
||||
|
||||
if (!config.isAllowedMethod(method)) {
|
||||
throw new ConfigurationException("Invalid method: " + method + " for action " + actionName);
|
||||
if (config.isAllowedMethod(method)) {
|
||||
invocation.init(this);
|
||||
} else {
|
||||
throw new ConfigurationException("This method: " + method + " for action " + actionName + " is not allowed!");
|
||||
}
|
||||
|
||||
invocation.init(this);
|
||||
|
||||
} finally {
|
||||
UtilTimerStack.pop(profileKey);
|
||||
}
|
||||
|
||||
@@ -145,4 +145,5 @@ public class DefaultUnknownHandlerManager implements UnknownHandlerManager {
|
||||
public List<UnknownHandler> getUnknownHandlers() {
|
||||
return unknownHandlers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,4 +43,5 @@ public interface UnknownHandlerManager {
|
||||
boolean hasUnknownHandlers();
|
||||
|
||||
List<UnknownHandler> getUnknownHandlers();
|
||||
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ public class ActionConfig extends Located implements Serializable {
|
||||
|
||||
public static final String DEFAULT_METHOD = "execute";
|
||||
public static final String WILDCARD = "*";
|
||||
public static final String REGEX_WILDCARD = "regex:.*";
|
||||
|
||||
protected List<InterceptorMapping> interceptors; // a list of interceptorMapping Objects eg. List<InterceptorMapping>
|
||||
protected Map<String,String> params;
|
||||
@@ -52,17 +53,17 @@ public class ActionConfig extends Located implements Serializable {
|
||||
protected String methodName;
|
||||
protected String packageName;
|
||||
protected String name;
|
||||
protected Set<String> allowedMethods;
|
||||
protected AllowedMethods allowedMethods;
|
||||
|
||||
protected ActionConfig(String packageName, String name, String className) {
|
||||
this.packageName = packageName;
|
||||
this.name = name;
|
||||
this.className = className;
|
||||
params = new LinkedHashMap<String, String>();
|
||||
results = new LinkedHashMap<String, ResultConfig>();
|
||||
interceptors = new ArrayList<InterceptorMapping>();
|
||||
exceptionMappings = new ArrayList<ExceptionMappingConfig>();
|
||||
allowedMethods = new HashSet<String>();
|
||||
params = new LinkedHashMap<>();
|
||||
results = new LinkedHashMap<>();
|
||||
interceptors = new ArrayList<>();
|
||||
exceptionMappings = new ArrayList<>();
|
||||
allowedMethods = AllowedMethods.build(new HashSet<>(Collections.singletonList(DEFAULT_METHOD)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,7 +80,7 @@ public class ActionConfig extends Located implements Serializable {
|
||||
this.interceptors = new ArrayList<>(orig.interceptors);
|
||||
this.results = new LinkedHashMap<>(orig.results);
|
||||
this.exceptionMappings = new ArrayList<>(orig.exceptionMappings);
|
||||
this.allowedMethods = new HashSet<>(orig.allowedMethods);
|
||||
this.allowedMethods = AllowedMethods.build(orig.allowedMethods.list());
|
||||
this.location = orig.location;
|
||||
}
|
||||
|
||||
@@ -100,7 +101,7 @@ public class ActionConfig extends Located implements Serializable {
|
||||
}
|
||||
|
||||
public Set<String> getAllowedMethods() {
|
||||
return allowedMethods;
|
||||
return allowedMethods.list();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,11 +129,7 @@ public class ActionConfig extends Located implements Serializable {
|
||||
}
|
||||
|
||||
public boolean isAllowedMethod(String method) {
|
||||
if (allowedMethods.size() == 1 && WILDCARD.equals(allowedMethods.iterator().next())) {
|
||||
return true;
|
||||
} else {
|
||||
return method.equals(methodName != null ? methodName : DEFAULT_METHOD) || allowedMethods.contains(method);
|
||||
}
|
||||
return method.equals(methodName != null ? methodName : DEFAULT_METHOD) || allowedMethods.isAllowed(method);
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o) {
|
||||
@@ -214,15 +211,16 @@ public class ActionConfig extends Located implements Serializable {
|
||||
public static class Builder implements InterceptorListHolder{
|
||||
|
||||
protected ActionConfig target;
|
||||
private boolean gotMethods;
|
||||
protected Set<String> allowedMethods;
|
||||
|
||||
public Builder(ActionConfig toClone) {
|
||||
target = new ActionConfig(toClone);
|
||||
addAllowedMethod(toClone.getAllowedMethods());
|
||||
allowedMethods = toClone.getAllowedMethods();
|
||||
}
|
||||
|
||||
public Builder(String packageName, String name, String className) {
|
||||
target = new ActionConfig(packageName, name, className);
|
||||
allowedMethods = new HashSet<>();
|
||||
}
|
||||
|
||||
public Builder packageName(String name) {
|
||||
@@ -249,6 +247,7 @@ public class ActionConfig extends Located implements Serializable {
|
||||
|
||||
public Builder methodName(String method) {
|
||||
target.methodName = method;
|
||||
addAllowedMethod(method);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -312,15 +311,14 @@ public class ActionConfig extends Located implements Serializable {
|
||||
}
|
||||
|
||||
public Builder addAllowedMethod(String methodName) {
|
||||
target.allowedMethods.add(methodName);
|
||||
if (methodName != null) {
|
||||
allowedMethods.add(methodName);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addAllowedMethod(Collection<String> methods) {
|
||||
if (methods != null) {
|
||||
gotMethods = true;
|
||||
target.allowedMethods.addAll(methods);
|
||||
}
|
||||
allowedMethods.addAll(methods);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -330,22 +328,16 @@ public class ActionConfig extends Located implements Serializable {
|
||||
}
|
||||
|
||||
public ActionConfig build() {
|
||||
embalmTarget();
|
||||
target.params = Collections.unmodifiableMap(target.params);
|
||||
target.results = Collections.unmodifiableMap(target.results);
|
||||
target.interceptors = Collections.unmodifiableList(target.interceptors);
|
||||
target.exceptionMappings = Collections.unmodifiableList(target.exceptionMappings);
|
||||
target.allowedMethods = AllowedMethods.build(allowedMethods);
|
||||
|
||||
ActionConfig result = target;
|
||||
target = new ActionConfig(target);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void embalmTarget() {
|
||||
if (!gotMethods && target.allowedMethods.isEmpty()) {
|
||||
target.allowedMethods.add(WILDCARD);
|
||||
}
|
||||
|
||||
target.params = Collections.unmodifiableMap(target.params);
|
||||
target.results = Collections.unmodifiableMap(target.results);
|
||||
target.interceptors = Collections.unmodifiableList(target.interceptors);
|
||||
target.exceptionMappings = Collections.unmodifiableList(target.exceptionMappings);
|
||||
target.allowedMethods = Collections.unmodifiableSet(target.allowedMethods);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
package com.opensymphony.xwork2.config.entities;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class AllowedMethods {
|
||||
|
||||
private Set<AllowedMethod> allowedMethods;
|
||||
|
||||
public static AllowedMethods build(Set<String> methods) {
|
||||
|
||||
Set<AllowedMethod> allowedMethods = new HashSet<>();
|
||||
for (String method : methods) {
|
||||
boolean isPattern = false;
|
||||
int len = method.length();
|
||||
StringBuilder ret = new StringBuilder();
|
||||
char c;
|
||||
for (int x = 0; x < len; x++) {
|
||||
c = method.charAt(x);
|
||||
if (x < len - 2 && c == '{' && '}' == method.charAt(x + 2)) {
|
||||
ret.append("(.*)");
|
||||
isPattern = true;
|
||||
x += 2;
|
||||
} else {
|
||||
ret.append(c);
|
||||
}
|
||||
}
|
||||
if (isPattern && !method.startsWith("regex:")) {
|
||||
allowedMethods.add(new PatternAllowedMethod(ret.toString(), method));
|
||||
} else if (method.startsWith("regex:")) {
|
||||
String pattern = method.substring(method.indexOf(":") + 1);
|
||||
allowedMethods.add(new PatternAllowedMethod(pattern, method));
|
||||
} else {
|
||||
allowedMethods.add(new LiteralAllowedMethod(ret.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
return new AllowedMethods(allowedMethods);
|
||||
}
|
||||
|
||||
private AllowedMethods(Set<AllowedMethod> methods) {
|
||||
this.allowedMethods = Collections.unmodifiableSet(methods);
|
||||
}
|
||||
|
||||
public boolean isAllowed(String method) {
|
||||
for (AllowedMethod allowedMethod : allowedMethods) {
|
||||
if (allowedMethod.isAllowed(method)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Set<String> list() {
|
||||
Set<String> result = new HashSet<>();
|
||||
for (AllowedMethod allowedMethod : allowedMethods) {
|
||||
result.add(allowedMethod.original());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
AllowedMethods that = (AllowedMethods) o;
|
||||
|
||||
return allowedMethods.equals(that.allowedMethods);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return allowedMethods.hashCode();
|
||||
}
|
||||
|
||||
private interface AllowedMethod {
|
||||
boolean isAllowed(String methodName);
|
||||
|
||||
String original();
|
||||
}
|
||||
|
||||
private static class PatternAllowedMethod implements AllowedMethod {
|
||||
|
||||
private final Pattern allowedMethodPattern;
|
||||
private String original;
|
||||
|
||||
public PatternAllowedMethod(String pattern, String original) {
|
||||
this.original = original;
|
||||
allowedMethodPattern = Pattern.compile(pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed(String methodName) {
|
||||
return allowedMethodPattern.matcher(methodName).matches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String original() {
|
||||
return original;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
PatternAllowedMethod that = (PatternAllowedMethod) o;
|
||||
|
||||
return original.equals(that.original);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return original.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PatternAllowedMethod{" +
|
||||
"allowedMethodPattern=" + allowedMethodPattern +
|
||||
", original='" + original + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
private static class LiteralAllowedMethod implements AllowedMethod {
|
||||
|
||||
private String allowedMethod;
|
||||
|
||||
public LiteralAllowedMethod(String allowedMethod) {
|
||||
this.allowedMethod = allowedMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed(String methodName) {
|
||||
return methodName.equals(allowedMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String original() {
|
||||
return allowedMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
LiteralAllowedMethod that = (LiteralAllowedMethod) o;
|
||||
|
||||
return allowedMethod.equals(that.allowedMethod);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return allowedMethod.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LiteralAllowedMethod{" +
|
||||
"allowedMethod='" + allowedMethod + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,6 +40,7 @@ public class PackageConfig extends Located implements Comparable, Serializable,
|
||||
|
||||
protected Map<String, ActionConfig> actionConfigs;
|
||||
protected Map<String, ResultConfig> globalResultConfigs;
|
||||
protected Set<String> globalAllowedMethods;
|
||||
protected Map<String, Object> interceptorConfigs;
|
||||
protected Map<String, ResultTypeConfig> resultTypeConfigs;
|
||||
protected List<ExceptionMappingConfig> globalExceptionMappingConfigs;
|
||||
@@ -52,11 +53,13 @@ public class PackageConfig extends Located implements Comparable, Serializable,
|
||||
protected String namespace = "";
|
||||
protected boolean isAbstract = false;
|
||||
protected boolean needsRefresh;
|
||||
protected boolean strictMethodInvocation = true;
|
||||
|
||||
protected PackageConfig(String name) {
|
||||
this.name = name;
|
||||
actionConfigs = new LinkedHashMap<>();
|
||||
globalResultConfigs = new LinkedHashMap<>();
|
||||
globalAllowedMethods = new HashSet<>();
|
||||
interceptorConfigs = new LinkedHashMap<>();
|
||||
resultTypeConfigs = new LinkedHashMap<>();
|
||||
globalExceptionMappingConfigs = new ArrayList<>();
|
||||
@@ -74,11 +77,13 @@ public class PackageConfig extends Located implements Comparable, Serializable,
|
||||
this.needsRefresh = orig.needsRefresh;
|
||||
this.actionConfigs = new LinkedHashMap<>(orig.actionConfigs);
|
||||
this.globalResultConfigs = new LinkedHashMap<>(orig.globalResultConfigs);
|
||||
this.globalAllowedMethods = new LinkedHashSet<>(orig.globalAllowedMethods);
|
||||
this.interceptorConfigs = new LinkedHashMap<>(orig.interceptorConfigs);
|
||||
this.resultTypeConfigs = new LinkedHashMap<>(orig.resultTypeConfigs);
|
||||
this.globalExceptionMappingConfigs = new ArrayList<>(orig.globalExceptionMappingConfigs);
|
||||
this.parents = new ArrayList<>(orig.parents);
|
||||
this.location = orig.location;
|
||||
this.strictMethodInvocation = orig.strictMethodInvocation;
|
||||
}
|
||||
|
||||
public boolean isAbstract() {
|
||||
@@ -327,7 +332,6 @@ public class PackageConfig extends Located implements Comparable, Serializable,
|
||||
return resultTypeConfigs;
|
||||
}
|
||||
|
||||
|
||||
public boolean isNeedsRefresh() {
|
||||
return needsRefresh;
|
||||
}
|
||||
@@ -342,80 +346,64 @@ public class PackageConfig extends Located implements Comparable, Serializable,
|
||||
return globalExceptionMappingConfigs;
|
||||
}
|
||||
|
||||
public boolean isStrictMethodInvocation() {
|
||||
return strictMethodInvocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
if (!(o instanceof PackageConfig)) {
|
||||
PackageConfig that = (PackageConfig) o;
|
||||
|
||||
if (isAbstract != that.isAbstract) return false;
|
||||
if (needsRefresh != that.needsRefresh) return false;
|
||||
if (strictMethodInvocation != that.strictMethodInvocation) return false;
|
||||
if (actionConfigs != null ? !actionConfigs.equals(that.actionConfigs) : that.actionConfigs != null)
|
||||
return false;
|
||||
}
|
||||
|
||||
final PackageConfig packageConfig = (PackageConfig) o;
|
||||
|
||||
if (isAbstract != packageConfig.isAbstract) {
|
||||
if (globalResultConfigs != null ? !globalResultConfigs.equals(that.globalResultConfigs) : that.globalResultConfigs != null)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((actionConfigs != null) ? (!actionConfigs.equals(packageConfig.actionConfigs)) : (packageConfig.actionConfigs != null)) {
|
||||
if (globalAllowedMethods != null ? !globalAllowedMethods.equals(that.globalAllowedMethods) : that.globalAllowedMethods != null)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((defaultResultType != null) ? (!defaultResultType.equals(packageConfig.defaultResultType)) : (packageConfig.defaultResultType != null)) {
|
||||
if (interceptorConfigs != null ? !interceptorConfigs.equals(that.interceptorConfigs) : that.interceptorConfigs != null)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((defaultClassRef != null) ? (!defaultClassRef.equals(packageConfig.defaultClassRef)) : (packageConfig.defaultClassRef != null)) {
|
||||
if (resultTypeConfigs != null ? !resultTypeConfigs.equals(that.resultTypeConfigs) : that.resultTypeConfigs != null)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((globalResultConfigs != null) ? (!globalResultConfigs.equals(packageConfig.globalResultConfigs)) : (packageConfig.globalResultConfigs != null)) {
|
||||
if (globalExceptionMappingConfigs != null ? !globalExceptionMappingConfigs.equals(that.globalExceptionMappingConfigs) : that.globalExceptionMappingConfigs != null)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((interceptorConfigs != null) ? (!interceptorConfigs.equals(packageConfig.interceptorConfigs)) : (packageConfig.interceptorConfigs != null)) {
|
||||
if (parents != null ? !parents.equals(that.parents) : that.parents != null) return false;
|
||||
if (defaultInterceptorRef != null ? !defaultInterceptorRef.equals(that.defaultInterceptorRef) : that.defaultInterceptorRef != null)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((name != null) ? (!name.equals(packageConfig.name)) : (packageConfig.name != null)) {
|
||||
if (defaultActionRef != null ? !defaultActionRef.equals(that.defaultActionRef) : that.defaultActionRef != null)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((namespace != null) ? (!namespace.equals(packageConfig.namespace)) : (packageConfig.namespace != null)) {
|
||||
if (defaultResultType != null ? !defaultResultType.equals(that.defaultResultType) : that.defaultResultType != null)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((parents != null) ? (!parents.equals(packageConfig.parents)) : (packageConfig.parents != null)) {
|
||||
if (defaultClassRef != null ? !defaultClassRef.equals(that.defaultClassRef) : that.defaultClassRef != null)
|
||||
return false;
|
||||
}
|
||||
if (!name.equals(that.name)) return false;
|
||||
return !(namespace != null ? !namespace.equals(that.namespace) : that.namespace != null);
|
||||
|
||||
if ((resultTypeConfigs != null) ? (!resultTypeConfigs.equals(packageConfig.resultTypeConfigs)) : (packageConfig.resultTypeConfigs != null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((globalExceptionMappingConfigs != null) ? (!globalExceptionMappingConfigs.equals(packageConfig.globalExceptionMappingConfigs)) : (packageConfig.globalExceptionMappingConfigs != null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
result = ((name != null) ? name.hashCode() : 0);
|
||||
result = (29 * result) + ((parents != null) ? parents.hashCode() : 0);
|
||||
result = (29 * result) + ((actionConfigs != null) ? actionConfigs.hashCode() : 0);
|
||||
result = (29 * result) + ((globalResultConfigs != null) ? globalResultConfigs.hashCode() : 0);
|
||||
result = (29 * result) + ((interceptorConfigs != null) ? interceptorConfigs.hashCode() : 0);
|
||||
result = (29 * result) + ((resultTypeConfigs != null) ? resultTypeConfigs.hashCode() : 0);
|
||||
result = (29 * result) + ((globalExceptionMappingConfigs != null) ? globalExceptionMappingConfigs.hashCode() : 0);
|
||||
result = (29 * result) + ((defaultResultType != null) ? defaultResultType.hashCode() : 0);
|
||||
result = (29 * result) + ((defaultClassRef != null) ? defaultClassRef.hashCode() : 0);
|
||||
result = (29 * result) + ((namespace != null) ? namespace.hashCode() : 0);
|
||||
result = (29 * result) + (isAbstract ? 1 : 0);
|
||||
|
||||
int result = actionConfigs != null ? actionConfigs.hashCode() : 0;
|
||||
result = 31 * result + (globalResultConfigs != null ? globalResultConfigs.hashCode() : 0);
|
||||
result = 31 * result + (globalAllowedMethods != null ? globalAllowedMethods.hashCode() : 0);
|
||||
result = 31 * result + (interceptorConfigs != null ? interceptorConfigs.hashCode() : 0);
|
||||
result = 31 * result + (resultTypeConfigs != null ? resultTypeConfigs.hashCode() : 0);
|
||||
result = 31 * result + (globalExceptionMappingConfigs != null ? globalExceptionMappingConfigs.hashCode() : 0);
|
||||
result = 31 * result + (parents != null ? parents.hashCode() : 0);
|
||||
result = 31 * result + (defaultInterceptorRef != null ? defaultInterceptorRef.hashCode() : 0);
|
||||
result = 31 * result + (defaultActionRef != null ? defaultActionRef.hashCode() : 0);
|
||||
result = 31 * result + (defaultResultType != null ? defaultResultType.hashCode() : 0);
|
||||
result = 31 * result + (defaultClassRef != null ? defaultClassRef.hashCode() : 0);
|
||||
result = 31 * result + name.hashCode();
|
||||
result = 31 * result + (namespace != null ? namespace.hashCode() : 0);
|
||||
result = 31 * result + (isAbstract ? 1 : 0);
|
||||
result = 31 * result + (needsRefresh ? 1 : 0);
|
||||
result = 31 * result + (strictMethodInvocation ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -445,7 +433,7 @@ public class PackageConfig extends Located implements Comparable, Serializable,
|
||||
public static class Builder implements InterceptorLocator {
|
||||
|
||||
protected PackageConfig target;
|
||||
private boolean strictDMI;
|
||||
private boolean strictDMI = true;
|
||||
|
||||
public Builder(String name) {
|
||||
target = new PackageConfig(name);
|
||||
@@ -528,6 +516,26 @@ public class PackageConfig extends Located implements Comparable, Serializable,
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<String> getGlobalAllowedMethods() {
|
||||
Set <String> allowedMethods = target.globalAllowedMethods;
|
||||
allowedMethods.addAll(getParentsAllowedMethods(target.parents));
|
||||
return allowedMethods;
|
||||
}
|
||||
|
||||
public Set<String> getParentsAllowedMethods(List<PackageConfig> parents) {
|
||||
Set<String> allowedMethods = new HashSet<>();
|
||||
for (PackageConfig parent : parents) {
|
||||
allowedMethods.addAll(parent.globalAllowedMethods);
|
||||
allowedMethods.addAll(getParentsAllowedMethods(parent.getParents()));
|
||||
}
|
||||
return allowedMethods;
|
||||
}
|
||||
|
||||
public Builder addGlobalAllowedMethods(Set<String> allowedMethods) {
|
||||
target.globalAllowedMethods.addAll(allowedMethods);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder addExceptionMappingConfig(ExceptionMappingConfig exceptionMappingConfig) {
|
||||
target.globalExceptionMappingConfigs.add(exceptionMappingConfig);
|
||||
return this;
|
||||
@@ -592,28 +600,24 @@ public class PackageConfig extends Located implements Comparable, Serializable,
|
||||
}
|
||||
|
||||
public Builder strictMethodInvocation(boolean strict) {
|
||||
strictDMI = strict;
|
||||
target.strictMethodInvocation = strict;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isStrictMethodInvocation() {
|
||||
return strictDMI;
|
||||
return target.strictMethodInvocation;
|
||||
}
|
||||
|
||||
public PackageConfig build() {
|
||||
embalmTarget();
|
||||
PackageConfig result = target;
|
||||
target = new PackageConfig(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void embalmTarget() {
|
||||
target.actionConfigs = Collections.unmodifiableMap(target.actionConfigs);
|
||||
target.globalResultConfigs = Collections.unmodifiableMap(target.globalResultConfigs);
|
||||
target.interceptorConfigs = Collections.unmodifiableMap(target.interceptorConfigs);
|
||||
target.resultTypeConfigs = Collections.unmodifiableMap(target.resultTypeConfigs);
|
||||
target.globalExceptionMappingConfigs = Collections.unmodifiableList(target.globalExceptionMappingConfigs);
|
||||
target.parents = Collections.unmodifiableList(target.parents);
|
||||
PackageConfig result = target;
|
||||
target = new PackageConfig(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -77,7 +77,7 @@ public class ActionConfigMatcher extends AbstractMatcher<ActionConfig> implement
|
||||
Map<String, String> vars) {
|
||||
|
||||
String methodName = convertParam(orig.getMethodName(), vars);
|
||||
if (!orig.isAllowedMethod(methodName)) {
|
||||
if (methodName != null && !orig.isAllowedMethod(methodName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+67
-18
@@ -15,12 +15,24 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.config.providers;
|
||||
|
||||
import com.opensymphony.xwork2.*;
|
||||
import com.opensymphony.xwork2.Action;
|
||||
import com.opensymphony.xwork2.FileManager;
|
||||
import com.opensymphony.xwork2.FileManagerFactory;
|
||||
import com.opensymphony.xwork2.ObjectFactory;
|
||||
import com.opensymphony.xwork2.XWorkException;
|
||||
import com.opensymphony.xwork2.config.Configuration;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.config.ConfigurationProvider;
|
||||
import com.opensymphony.xwork2.config.ConfigurationUtil;
|
||||
import com.opensymphony.xwork2.config.entities.*;
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.config.entities.ExceptionMappingConfig;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorConfig;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorMapping;
|
||||
import com.opensymphony.xwork2.config.entities.InterceptorStackConfig;
|
||||
import com.opensymphony.xwork2.config.entities.PackageConfig;
|
||||
import com.opensymphony.xwork2.config.entities.ResultConfig;
|
||||
import com.opensymphony.xwork2.config.entities.ResultTypeConfig;
|
||||
import com.opensymphony.xwork2.config.entities.UnknownHandlerConfig;
|
||||
import com.opensymphony.xwork2.config.impl.LocatableFactory;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.ContainerBuilder;
|
||||
@@ -47,7 +59,17 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
/**
|
||||
@@ -90,6 +112,7 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
|
||||
this.errorIfMissing = errorIfMissing;
|
||||
|
||||
Map<String, String> mappings = new HashMap<>();
|
||||
mappings.put("-//Apache Struts//XWork 2.5//EN", "xwork-2.5.dtd");
|
||||
mappings.put("-//Apache Struts//XWork 2.3//EN", "xwork-2.3.dtd");
|
||||
mappings.put("-//Apache Struts//XWork 2.1.3//EN", "xwork-2.1.3.dtd");
|
||||
mappings.put("-//Apache Struts//XWork 2.1//EN", "xwork-2.1.dtd");
|
||||
@@ -522,8 +545,10 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
|
||||
// load the global result list for this package
|
||||
loadGlobalResults(newPackage, packageElement);
|
||||
|
||||
loadGlobalAllowedMethods(newPackage, packageElement);
|
||||
|
||||
// load the global exception handler list for this package
|
||||
loadGobalExceptionMappings(newPackage, packageElement);
|
||||
loadGlobalExceptionMappings(newPackage, packageElement);
|
||||
|
||||
// get actions
|
||||
NodeList actionList = packageElement.getElementsByTagName("action");
|
||||
@@ -623,12 +648,11 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
|
||||
boolean isAbstract = Boolean.parseBoolean(abstractVal);
|
||||
String name = StringUtils.defaultString(packageElement.getAttribute("name"));
|
||||
String namespace = StringUtils.defaultString(packageElement.getAttribute("namespace"));
|
||||
String strictDMIVal = StringUtils.defaultString(packageElement.getAttribute("strict-method-invocation"));
|
||||
boolean strictDMI = Boolean.parseBoolean(strictDMIVal);
|
||||
|
||||
if (StringUtils.isNotEmpty(packageElement.getAttribute("externalReferenceResolver"))) {
|
||||
throw new ConfigurationException("The 'externalReferenceResolver' attribute has been removed. Please use " +
|
||||
"a custom ObjectFactory or Interceptor.", packageElement);
|
||||
// Strict DMI is enabled by default, it can disabled by user
|
||||
boolean strictDMI = true;
|
||||
if (packageElement.hasAttribute("strict-method-invocation")) {
|
||||
strictDMI = Boolean.parseBoolean(packageElement.getAttribute("strict-method-invocation"));
|
||||
}
|
||||
|
||||
PackageConfig.Builder cfg = new PackageConfig.Builder(name)
|
||||
@@ -825,19 +849,28 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
|
||||
protected Set<String> buildAllowedMethods(Element element, PackageConfig.Builder packageContext) {
|
||||
NodeList allowedMethodsEls = element.getElementsByTagName("allowed-methods");
|
||||
|
||||
Set<String> allowedMethods = null;
|
||||
|
||||
Set<String> allowedMethods;
|
||||
if (allowedMethodsEls.getLength() > 0) {
|
||||
allowedMethods = new HashSet<>();
|
||||
Node n = allowedMethodsEls.item(0).getFirstChild();
|
||||
if (n != null) {
|
||||
String s = n.getNodeValue().trim();
|
||||
if (s.length() > 0) {
|
||||
allowedMethods = TextParseUtil.commaDelimitedStringToSet(s);
|
||||
// user defined 'allowed-methods' so used them whatever Strict DMI was enabled or not
|
||||
allowedMethods = packageContext.getGlobalAllowedMethods();
|
||||
|
||||
if (allowedMethodsEls.getLength() > 0) {
|
||||
allowedMethods = new HashSet<>();
|
||||
Node n = allowedMethodsEls.item(0).getFirstChild();
|
||||
if (n != null) {
|
||||
String s = n.getNodeValue().trim();
|
||||
if (s.length() > 0) {
|
||||
allowedMethods = TextParseUtil.commaDelimitedStringToSet(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (packageContext.isStrictMethodInvocation()) {
|
||||
// user enabled Strict DMI but didn't defined action specific 'allowed-methods' so we use 'global-allowed-methods' only
|
||||
allowedMethods = packageContext.getGlobalAllowedMethods();
|
||||
} else {
|
||||
// Strict DMI is disabled to any method can be called
|
||||
allowedMethods = new HashSet<>();
|
||||
allowedMethods.add(ActionConfig.REGEX_WILDCARD);
|
||||
}
|
||||
|
||||
return allowedMethods;
|
||||
@@ -877,6 +910,22 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
|
||||
}
|
||||
}
|
||||
|
||||
protected void loadGlobalAllowedMethods(PackageConfig.Builder packageContext, Element packageElement) {
|
||||
NodeList globalAllowedMethodsElms = packageElement.getElementsByTagName("global-allowed-methods");
|
||||
|
||||
if (globalAllowedMethodsElms.getLength() > 0) {
|
||||
Set<String> globalAllowedMethods = new HashSet<>();
|
||||
Node n = globalAllowedMethodsElms.item(0).getFirstChild();
|
||||
if (n != null) {
|
||||
String s = n.getNodeValue().trim();
|
||||
if (s.length() > 0) {
|
||||
globalAllowedMethods = TextParseUtil.commaDelimitedStringToSet(s);
|
||||
}
|
||||
}
|
||||
packageContext.addGlobalAllowedMethods(globalAllowedMethods);
|
||||
}
|
||||
}
|
||||
|
||||
protected void loadDefaultClassRef(PackageConfig.Builder packageContext, Element element) {
|
||||
NodeList defaultClassRefList = element.getElementsByTagName("default-class-ref");
|
||||
if (defaultClassRefList.getLength() > 0) {
|
||||
@@ -891,7 +940,7 @@ public class XmlConfigurationProvider implements ConfigurationProvider {
|
||||
* @param packageContext the package context
|
||||
* @param packageElement the given XML element
|
||||
*/
|
||||
protected void loadGobalExceptionMappings(PackageConfig.Builder packageContext, Element packageElement) {
|
||||
protected void loadGlobalExceptionMappings(PackageConfig.Builder packageContext, Element packageElement) {
|
||||
NodeList globalExceptionMappingList = packageElement.getElementsByTagName("global-exception-mappings");
|
||||
|
||||
if (globalExceptionMappingList.getLength() > 0) {
|
||||
|
||||
@@ -75,6 +75,7 @@ public class StrutsXmlConfigurationProvider extends XmlConfigurationProvider {
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.1//EN", "struts-2.1.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN", "struts-2.1.7.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.3//EN", "struts-2.3.dtd");
|
||||
dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.5//EN", "struts-2.5.dtd");
|
||||
setDtdMappings(dtdMappings);
|
||||
File file = new File(filename);
|
||||
if (file.getParent() != null) {
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
/*
|
||||
* $Id: struts-2.0.dtd 651946 2008-04-27 13:41:38Z apetrelli $
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
<!-- START SNIPPET: strutsDtd -->
|
||||
|
||||
<!--
|
||||
Struts configuration DTD.
|
||||
Use the following DOCTYPE
|
||||
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
-->
|
||||
|
||||
<!ELEMENT struts ((package|include|bean|constant)*, unknown-handler-stack?)>
|
||||
<!ATTLIST struts
|
||||
order CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT package (result-types?, interceptors?, default-interceptor-ref?, default-action-ref?, default-class-ref?, global-results?, global-allowed-methods?, global-exception-mappings?, action*)>
|
||||
<!ATTLIST package
|
||||
name CDATA #REQUIRED
|
||||
extends CDATA #IMPLIED
|
||||
namespace CDATA #IMPLIED
|
||||
abstract CDATA #IMPLIED
|
||||
strict-method-invocation (true|false) "true"
|
||||
>
|
||||
|
||||
<!ELEMENT result-types (result-type+)>
|
||||
|
||||
<!ELEMENT result-type (param*)>
|
||||
<!ATTLIST result-type
|
||||
name CDATA #REQUIRED
|
||||
class CDATA #REQUIRED
|
||||
default (true|false) "false"
|
||||
>
|
||||
|
||||
<!ELEMENT interceptors (interceptor|interceptor-stack)+>
|
||||
|
||||
<!ELEMENT interceptor (param*)>
|
||||
<!ATTLIST interceptor
|
||||
name CDATA #REQUIRED
|
||||
class CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT interceptor-stack (interceptor-ref*)>
|
||||
<!ATTLIST interceptor-stack
|
||||
name CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT interceptor-ref (param*)>
|
||||
<!ATTLIST interceptor-ref
|
||||
name CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT default-interceptor-ref (#PCDATA)>
|
||||
<!ATTLIST default-interceptor-ref
|
||||
name CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT default-action-ref (#PCDATA)>
|
||||
<!ATTLIST default-action-ref
|
||||
name CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT default-class-ref (#PCDATA)>
|
||||
<!ATTLIST default-class-ref
|
||||
class CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT global-results (result+)>
|
||||
|
||||
<!ELEMENT global-allowed-methods (#PCDATA)>
|
||||
|
||||
<!ELEMENT global-exception-mappings (exception-mapping+)>
|
||||
|
||||
<!ELEMENT action ((param|result|interceptor-ref|exception-mapping)*,allowed-methods?)>
|
||||
<!ATTLIST action
|
||||
name CDATA #REQUIRED
|
||||
class CDATA #IMPLIED
|
||||
method CDATA #IMPLIED
|
||||
converter CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT param (#PCDATA)>
|
||||
<!ATTLIST param
|
||||
name CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT result (#PCDATA|param)*>
|
||||
<!ATTLIST result
|
||||
name CDATA #IMPLIED
|
||||
type CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT exception-mapping (#PCDATA|param)*>
|
||||
<!ATTLIST exception-mapping
|
||||
name CDATA #IMPLIED
|
||||
exception CDATA #REQUIRED
|
||||
result CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT allowed-methods (#PCDATA)>
|
||||
|
||||
<!ELEMENT include (#PCDATA)>
|
||||
<!ATTLIST include
|
||||
file CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT bean (#PCDATA)>
|
||||
<!ATTLIST bean
|
||||
type CDATA #IMPLIED
|
||||
name CDATA #IMPLIED
|
||||
class CDATA #REQUIRED
|
||||
scope CDATA #IMPLIED
|
||||
static CDATA #IMPLIED
|
||||
optional CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT constant (#PCDATA)>
|
||||
<!ATTLIST constant
|
||||
name CDATA #REQUIRED
|
||||
value CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT unknown-handler-stack (unknown-handler-ref*)>
|
||||
<!ELEMENT unknown-handler-ref (#PCDATA)>
|
||||
<!ATTLIST unknown-handler-ref
|
||||
name CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!-- END SNIPPET: strutsDtd -->
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
and {@link com.opensymphony.xwork2.inject.Inject}
|
||||
-->
|
||||
<!DOCTYPE struts PUBLIC
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.3.dtd">
|
||||
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
|
||||
@@ -165,7 +165,7 @@
|
||||
<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" />
|
||||
|
||||
<package name="struts-default" abstract="true">
|
||||
<package name="struts-default" abstract="true" strict-method-invocation="true">
|
||||
<result-types>
|
||||
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
|
||||
<result-type name="dispatcher" class="org.apache.struts2.result.ServletDispatcherResult" default="true"/>
|
||||
@@ -361,6 +361,9 @@
|
||||
<default-interceptor-ref name="defaultStack"/>
|
||||
|
||||
<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
|
||||
|
||||
<global-allowed-methods>execute,input,back,cancel,browse,save,delete,list,index</global-allowed-methods>
|
||||
|
||||
</package>
|
||||
|
||||
</struts>
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- START SNIPPET: xworkDtd -->
|
||||
|
||||
<!--
|
||||
XWork configuration DTD.
|
||||
Use the following DOCTYPE
|
||||
|
||||
<!DOCTYPE xwork PUBLIC
|
||||
"-//Apache Struts//XWork 2.5//EN"
|
||||
"http://struts.apache.org/dtds/xwork-2.5.dtd">
|
||||
-->
|
||||
|
||||
<!ELEMENT xwork ((package|include|bean|constant)*, unknown-handler-stack?)>
|
||||
<!ATTLIST xwork
|
||||
order CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT package (result-types?, interceptors?, default-interceptor-ref?, default-action-ref?, default-class-ref?, global-results?, global-allowed-methods?, global-exception-mappings?, action*)>
|
||||
<!ATTLIST package
|
||||
name CDATA #REQUIRED
|
||||
extends CDATA #IMPLIED
|
||||
namespace CDATA #IMPLIED
|
||||
abstract CDATA #IMPLIED
|
||||
strict-method-invocation (true|false) "true"
|
||||
>
|
||||
|
||||
<!ELEMENT result-types (result-type+)>
|
||||
|
||||
<!ELEMENT result-type (param*)>
|
||||
<!ATTLIST result-type
|
||||
name CDATA #REQUIRED
|
||||
class CDATA #REQUIRED
|
||||
default (true|false) "false"
|
||||
>
|
||||
|
||||
<!ELEMENT interceptors (interceptor|interceptor-stack)+>
|
||||
|
||||
<!ELEMENT interceptor (param*)>
|
||||
<!ATTLIST interceptor
|
||||
name CDATA #REQUIRED
|
||||
class CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT interceptor-stack (interceptor-ref*)>
|
||||
<!ATTLIST interceptor-stack
|
||||
name CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT interceptor-ref (param*)>
|
||||
<!ATTLIST interceptor-ref
|
||||
name CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT default-interceptor-ref (#PCDATA)>
|
||||
<!ATTLIST default-interceptor-ref
|
||||
name CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT default-action-ref (#PCDATA)>
|
||||
<!ATTLIST default-action-ref
|
||||
name CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT default-class-ref (#PCDATA)>
|
||||
<!ATTLIST default-class-ref
|
||||
class CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT global-results (result+)>
|
||||
|
||||
<!ELEMENT global-allowed-methods (#PCDATA)>
|
||||
|
||||
<!ELEMENT global-exception-mappings (exception-mapping+)>
|
||||
|
||||
<!ELEMENT action ((param|result|interceptor-ref|exception-mapping)*,allowed-methods?)>
|
||||
<!ATTLIST action
|
||||
name CDATA #REQUIRED
|
||||
class CDATA #IMPLIED
|
||||
method CDATA #IMPLIED
|
||||
converter CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT param (#PCDATA)>
|
||||
<!ATTLIST param
|
||||
name CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT result (#PCDATA|param)*>
|
||||
<!ATTLIST result
|
||||
name CDATA #IMPLIED
|
||||
type CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT exception-mapping (#PCDATA|param)*>
|
||||
<!ATTLIST exception-mapping
|
||||
name CDATA #IMPLIED
|
||||
exception CDATA #REQUIRED
|
||||
result CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT allowed-methods (#PCDATA)>
|
||||
|
||||
<!ELEMENT include (#PCDATA)>
|
||||
<!ATTLIST include
|
||||
file CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT bean (#PCDATA)>
|
||||
<!ATTLIST bean
|
||||
type CDATA #IMPLIED
|
||||
name CDATA #IMPLIED
|
||||
class CDATA #REQUIRED
|
||||
scope CDATA #IMPLIED
|
||||
static CDATA #IMPLIED
|
||||
optional CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT constant (#PCDATA)>
|
||||
<!ATTLIST constant
|
||||
name CDATA #REQUIRED
|
||||
value CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT unknown-handler-stack (unknown-handler-ref*)>
|
||||
<!ELEMENT unknown-handler-ref (#PCDATA)>
|
||||
<!ATTLIST unknown-handler-ref
|
||||
name CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!-- END SNIPPET: xworkDtd -->
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.opensymphony.xwork2;
|
||||
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
|
||||
import com.opensymphony.xwork2.mock.MockResult;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -45,12 +46,14 @@ public class ActionInvocationTest extends XWorkTestCase {
|
||||
|
||||
public void testCommandInvocationUnknownHandler() throws Exception {
|
||||
|
||||
DefaultActionProxy baseActionProxy = (DefaultActionProxy) actionProxyFactory.createActionProxy(
|
||||
"baz", "unknownMethodTest", "unknownmethod", null);
|
||||
UnknownHandler unknownHandler = new UnknownHandler() {
|
||||
public ActionConfig handleUnknownAction(String namespace, String actionName) throws XWorkException { return null;}
|
||||
public ActionConfig handleUnknownAction(String namespace, String actionName) throws XWorkException {
|
||||
return new ActionConfig.Builder("test", actionName, ActionSupport.class.getName())
|
||||
.addAllowedMethod("unknownmethod")
|
||||
.build();
|
||||
}
|
||||
public Result handleUnknownResult(ActionContext actionContext, String actionName, ActionConfig actionConfig, String resultCode) throws XWorkException {
|
||||
return null;
|
||||
return new MockResult();
|
||||
}
|
||||
public Object handleUnknownActionMethod(Object action, String methodName) {
|
||||
if (methodName.equals("unknownmethod")) {
|
||||
@@ -63,6 +66,12 @@ public class ActionInvocationTest extends XWorkTestCase {
|
||||
|
||||
UnknownHandlerManagerMock uhm = new UnknownHandlerManagerMock();
|
||||
uhm.addUnknownHandler(unknownHandler);
|
||||
|
||||
loadButAdd(UnknownHandlerManager.class, uhm);
|
||||
|
||||
DefaultActionProxy baseActionProxy = (DefaultActionProxy) actionProxyFactory.createActionProxy(
|
||||
"baz", "unknownMethodTest", "unknownmethod", null);
|
||||
|
||||
((DefaultActionInvocation)baseActionProxy.getInvocation()).setUnknownHandlerManager(uhm);
|
||||
|
||||
assertEquals("found", baseActionProxy.execute());
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.opensymphony.xwork2.config.entities;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class AllowedMethodsTest extends TestCase {
|
||||
|
||||
public void testLiteralMethods() throws Exception {
|
||||
// given
|
||||
String method = "myMethod";
|
||||
Set<String> literals = new HashSet<>();
|
||||
literals.add(method);
|
||||
|
||||
// when
|
||||
AllowedMethods allowedMethods = AllowedMethods.build(literals);
|
||||
|
||||
// then
|
||||
assertEquals(1, allowedMethods.list().size());
|
||||
assertTrue(allowedMethods.isAllowed(method));
|
||||
assertFalse(allowedMethods.isAllowed("someOtherMethod"));
|
||||
}
|
||||
|
||||
public void testWidlcardMethods() throws Exception {
|
||||
// given
|
||||
String method = "my{1}";
|
||||
Set<String> literals = new HashSet<>();
|
||||
literals.add(method);
|
||||
|
||||
// when
|
||||
AllowedMethods allowedMethods = AllowedMethods.build(literals);
|
||||
|
||||
// then
|
||||
assertEquals(1, allowedMethods.list().size());
|
||||
assertTrue(allowedMethods.isAllowed("myMethod"));
|
||||
assertFalse(allowedMethods.isAllowed("someOtherMethod"));
|
||||
}
|
||||
|
||||
public void testRegexMethods() throws Exception {
|
||||
// given
|
||||
String method = "regex:my([a-zA-Z].*)";
|
||||
Set<String> literals = new HashSet<>();
|
||||
literals.add(method);
|
||||
|
||||
// when
|
||||
AllowedMethods allowedMethods = AllowedMethods.build(literals);
|
||||
|
||||
// then
|
||||
assertEquals(1, allowedMethods.list().size());
|
||||
assertTrue(allowedMethods.isAllowed("myMethod"));
|
||||
assertFalse(allowedMethods.isAllowed("someOtherMethod"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,5 +30,63 @@ public class PackageConfigTest extends XWorkTestCase {
|
||||
|
||||
assertEquals("ref2", cfg.getFullDefaultInterceptorRef());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testStrictDMIInheritance() {
|
||||
// given
|
||||
PackageConfig parent = new PackageConfig.Builder("parent").build();
|
||||
|
||||
// when
|
||||
PackageConfig child = new PackageConfig.Builder("child")
|
||||
.addParent(parent)
|
||||
.build();
|
||||
|
||||
// then
|
||||
assertTrue(child.isStrictMethodInvocation());
|
||||
}
|
||||
|
||||
public void testStrictDMIInheritanceDisabledInParentPackage() {
|
||||
// given
|
||||
PackageConfig parent = new PackageConfig.Builder("parent")
|
||||
.strictMethodInvocation(false)
|
||||
.build();
|
||||
|
||||
// when
|
||||
PackageConfig child = new PackageConfig.Builder("child")
|
||||
.addParent(parent)
|
||||
.build();
|
||||
|
||||
// then
|
||||
assertTrue(child.isStrictMethodInvocation());
|
||||
}
|
||||
|
||||
public void testStrictDMIInheritanceDisabledInBothPackage() {
|
||||
// given
|
||||
PackageConfig parent = new PackageConfig.Builder("parent")
|
||||
.strictMethodInvocation(false)
|
||||
.build();
|
||||
|
||||
// when
|
||||
PackageConfig child = new PackageConfig.Builder("child")
|
||||
.addParent(parent)
|
||||
.strictMethodInvocation(false)
|
||||
.build();
|
||||
|
||||
// then
|
||||
assertFalse(child.isStrictMethodInvocation());
|
||||
}
|
||||
|
||||
public void testStrictDMIInheritanceDisabledInChildPackage() {
|
||||
// given
|
||||
PackageConfig parent = new PackageConfig.Builder("parent").build();
|
||||
|
||||
// when
|
||||
PackageConfig child = new PackageConfig.Builder("child")
|
||||
.addParent(parent)
|
||||
.strictMethodInvocation(false)
|
||||
.build();
|
||||
|
||||
// then
|
||||
assertFalse(child.isStrictMethodInvocation());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-2
@@ -164,7 +164,9 @@ public class XmlConfigurationProviderActionsTest extends ConfigurationTestBase {
|
||||
params.put("bar", "23");
|
||||
|
||||
ActionConfig barWithPackageDefaultClassRefConfig =
|
||||
new ActionConfig.Builder("", "Bar", "").addParams(params).build();
|
||||
new ActionConfig.Builder("", "Bar", "")
|
||||
.addParams(params)
|
||||
.build();
|
||||
|
||||
// execute the configuration
|
||||
provider.init(configuration);
|
||||
@@ -188,7 +190,9 @@ public class XmlConfigurationProviderActionsTest extends ConfigurationTestBase {
|
||||
params.put("bar", "23");
|
||||
|
||||
ActionConfig barWithoutClassNameConfig =
|
||||
new ActionConfig.Builder("", "BarWithoutClassName", "").addParams(params).build();
|
||||
new ActionConfig.Builder("", "BarWithoutClassName", "")
|
||||
.addParams(params)
|
||||
.build();
|
||||
|
||||
// execute the configuration
|
||||
provider.init(configuration);
|
||||
|
||||
+2
-2
@@ -59,7 +59,7 @@ public class XmlConfigurationProviderAllowedMethodsTest extends ConfigurationTes
|
||||
assertFalse(action.isAllowedMethod("xyz"));
|
||||
|
||||
action = (ActionConfig) actionConfigs.get("Baz");
|
||||
assertEquals(2, action.getAllowedMethods().size());
|
||||
assertEquals(3, action.getAllowedMethods().size());
|
||||
assertFalse(action.isAllowedMethod("execute"));
|
||||
assertTrue(action.isAllowedMethod("foo"));
|
||||
assertTrue(action.isAllowedMethod("bar"));
|
||||
@@ -114,7 +114,7 @@ public class XmlConfigurationProviderAllowedMethodsTest extends ConfigurationTes
|
||||
assertFalse(action.isAllowedMethod("xyz"));
|
||||
|
||||
action = (ActionConfig) actionConfigs.get("Baz");
|
||||
assertEquals(2, action.getAllowedMethods().size());
|
||||
assertEquals(3, action.getAllowedMethods().size());
|
||||
assertFalse(action.isAllowedMethod("execute"));
|
||||
assertTrue(action.isAllowedMethod("foo"));
|
||||
assertTrue(action.isAllowedMethod("bar"));
|
||||
|
||||
+3
-3
@@ -32,15 +32,15 @@ public class XmlConfigurationProviderExceptionMappingsTest extends Configuration
|
||||
|
||||
exceptionMappings.add(
|
||||
new ExceptionMappingConfig.Builder("spooky-result", "com.opensymphony.xwork2.SpookyException", "spooky-result")
|
||||
.build());
|
||||
.build());
|
||||
results.put("spooky-result", new ResultConfig.Builder("spooky-result", MockResult.class.getName()).build());
|
||||
|
||||
Map<String, String> resultParams = new HashMap<>();
|
||||
resultParams.put("actionName", "bar.vm");
|
||||
results.put("specificLocationResult",
|
||||
new ResultConfig.Builder("specificLocationResult", ActionChainResult.class.getName())
|
||||
.addParams(resultParams)
|
||||
.build());
|
||||
.addParams(resultParams)
|
||||
.build());
|
||||
|
||||
ActionConfig expectedAction = new ActionConfig.Builder("default", "Bar", SimpleAction.class.getName())
|
||||
.addParams(parameters)
|
||||
|
||||
@@ -127,6 +127,7 @@ public class TestConfigurationProvider implements ConfigurationProvider {
|
||||
.addActionConfig("testActionTagAction", new ActionConfig.Builder("", "", TestAction.class.getName())
|
||||
.addResultConfig(new ResultConfig.Builder(Action.SUCCESS, TestActionTagResult.class.getName()).build())
|
||||
.addResultConfig(new ResultConfig.Builder(Action.INPUT, TestActionTagResult.class.getName()).build())
|
||||
.addAllowedMethod("input")
|
||||
.build())
|
||||
.build();
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
>
|
||||
|
||||
<xwork>
|
||||
<package name="default">
|
||||
<package name="default" strict-method-invocation="false">
|
||||
<action name="Default">
|
||||
</action>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!DOCTYPE xwork PUBLIC
|
||||
"-//Apache Struts//XWork 2.0//EN"
|
||||
"http://struts.apache.org/dtds/xwork-2.0.dtd"
|
||||
"-//Apache Struts//XWork 2.5//EN"
|
||||
"http://struts.apache.org/dtds/xwork-2.5.dtd"
|
||||
>
|
||||
<!-- "file:///temp/ross/xwork/src/etc/xwork-1.0.dtd" -->
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
</result>
|
||||
</global-results>
|
||||
|
||||
<global-allowed-methods>execute,input,back,cancel,browse</global-allowed-methods>
|
||||
|
||||
<action name="Foo" class="com.opensymphony.xwork2.SimpleAction">
|
||||
<param name="foo">17</param>
|
||||
<param name="bar">23</param>
|
||||
|
||||
+6
@@ -28,6 +28,7 @@ import com.opensymphony.xwork2.config.providers.InterceptorBuilder;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.util.ClassLoaderUtil;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -67,6 +68,8 @@ public class ConventionUnknownHandler implements UnknownHandler {
|
||||
private ConventionsService conventionsService;
|
||||
private String nameSeparator;
|
||||
|
||||
protected Set<String> allowedMethods = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Constructs the unknown handler.
|
||||
*
|
||||
@@ -102,6 +105,8 @@ public class ConventionUnknownHandler implements UnknownHandler {
|
||||
}
|
||||
|
||||
this.redirectToSlash = Boolean.parseBoolean(redirectToSlash);
|
||||
|
||||
allowedMethods = TextParseUtil.commaDelimitedStringToSet("execute,input,back,cancel,browse");
|
||||
}
|
||||
|
||||
public ActionConfig handleUnknownAction(String namespace, String actionName)
|
||||
@@ -398,4 +403,5 @@ public class ConventionUnknownHandler implements UnknownHandler {
|
||||
this.ext = ext;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+26
-6
@@ -42,6 +42,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.StrutsConstants;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.apache.struts2.convention.annotation.*;
|
||||
import org.apache.struts2.convention.annotation.AllowedMethods;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -652,6 +653,8 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder {
|
||||
String actionPackage = actionClass.getPackage().getName();
|
||||
LOG.debug("Processing class [{}] in package [{}]", actionClass.getName(), actionPackage);
|
||||
|
||||
Set<String> allowedMethods = getAllowedMethods(actionClass);
|
||||
|
||||
// Determine the default namespace and action name
|
||||
List<String> namespaces = determineActionNamespace(actionClass);
|
||||
for (String namespace : namespaces) {
|
||||
@@ -692,7 +695,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder {
|
||||
|
||||
// Build the default
|
||||
if (!found) {
|
||||
createActionConfig(defaultPackageConfig, actionClass, defaultActionName, DEFAULT_METHOD, null);
|
||||
createActionConfig(defaultPackageConfig, actionClass, defaultActionName, DEFAULT_METHOD, null, allowedMethods);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -706,14 +709,14 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder {
|
||||
actionClass, action);
|
||||
}
|
||||
|
||||
createActionConfig(pkgCfg, actionClass, defaultActionName, method, action);
|
||||
createActionConfig(pkgCfg, actionClass, defaultActionName, method, action, allowedMethods);
|
||||
}
|
||||
}
|
||||
|
||||
// some actions will not have any @Action or a default method, like the rest actions
|
||||
// where the action mapper is the one that finds the right method at runtime
|
||||
if (map.isEmpty() && mapAllMatches && actionAnnotation == null && actionsAnnotation == null) {
|
||||
createActionConfig(defaultPackageConfig, actionClass, defaultActionName, null, actionAnnotation);
|
||||
createActionConfig(defaultPackageConfig, actionClass, defaultActionName, null, actionAnnotation, allowedMethods);
|
||||
}
|
||||
|
||||
//if there are @Actions or @Action at the class level, create the mappings for them
|
||||
@@ -721,9 +724,9 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder {
|
||||
if (actionsAnnotation != null) {
|
||||
List<Action> actionAnnotations = checkActionsAnnotation(actionsAnnotation);
|
||||
for (Action actionAnnotation2 : actionAnnotations)
|
||||
createActionConfig(defaultPackageConfig, actionClass, defaultActionName, methodName, actionAnnotation2);
|
||||
createActionConfig(defaultPackageConfig, actionClass, defaultActionName, methodName, actionAnnotation2, allowedMethods);
|
||||
} else if (actionAnnotation != null)
|
||||
createActionConfig(defaultPackageConfig, actionClass, defaultActionName, methodName, actionAnnotation);
|
||||
createActionConfig(defaultPackageConfig, actionClass, defaultActionName, methodName, actionAnnotation, allowedMethods);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -736,6 +739,15 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> getAllowedMethods(Class<?> actionClass) {
|
||||
AllowedMethods annotation = AnnotationUtils.findAnnotation(actionClass, AllowedMethods.class);
|
||||
if (annotation == null) {
|
||||
return Collections.emptySet();
|
||||
} else {
|
||||
return TextParseUtil.commaDelimitedStringToSet(annotation.value());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interfaces, enums, annotations, and abstract classes cannot be instantiated.
|
||||
* @param actionClass class to check
|
||||
@@ -896,7 +908,7 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder {
|
||||
* @param annotation The ActionName annotation that might override the action name and possibly
|
||||
*/
|
||||
protected void createActionConfig(PackageConfig.Builder pkgCfg, Class<?> actionClass, String actionName,
|
||||
String actionMethod, Action annotation) {
|
||||
String actionMethod, Action annotation, Set<String> allowedMethods) {
|
||||
String className = actionClass.getName();
|
||||
if (annotation != null) {
|
||||
actionName = annotation.value() != null && annotation.value().equals(Action.DEFAULT_VALUE) ? actionName : annotation.value();
|
||||
@@ -909,6 +921,14 @@ public class PackageBasedActionConfigBuilder implements ActionConfigBuilder {
|
||||
ActionConfig.Builder actionConfig = new ActionConfig.Builder(pkgCfg.getName(), actionName, className);
|
||||
actionConfig.methodName(actionMethod);
|
||||
|
||||
if (pkgCfg.isStrictMethodInvocation()) {
|
||||
actionConfig.addAllowedMethod(actionMethod);
|
||||
actionConfig.addAllowedMethod(allowedMethods);
|
||||
actionConfig.addAllowedMethod(pkgCfg.getGlobalAllowedMethods());
|
||||
} else {
|
||||
actionConfig.addAllowedMethod(ActionConfig.REGEX_WILDCARD);
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Creating action config for class [{}], name [{}] and package name [{}] in namespace [{}]",
|
||||
actionClass.toString(), actionName, pkgCfg.getName(), pkgCfg.getNamespace());
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package org.apache.struts2.convention.annotation;
|
||||
|
||||
import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <!-- START SNIPPET: javadoc -->
|
||||
* <p>
|
||||
* This annotation allows actions to specify allowed action methods
|
||||
* to limit access to any other public action's methods
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This annotation can be used directly on Action classes or
|
||||
* in the <strong>package-info.java</strong> class in order
|
||||
* to specify global allowed methods for all sub-packages.
|
||||
* </p>
|
||||
* <!-- END SNIPPET: javadoc -->
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.PACKAGE})
|
||||
@Retention(value = RetentionPolicy.RUNTIME)
|
||||
public @interface AllowedMethods {
|
||||
|
||||
String value() default ActionConfig.DEFAULT_METHOD;
|
||||
|
||||
}
|
||||
+56
-4
@@ -29,6 +29,7 @@ import com.opensymphony.xwork2.factory.DefaultResultFactory;
|
||||
import com.opensymphony.xwork2.inject.Container;
|
||||
import com.opensymphony.xwork2.inject.Scope.Strategy;
|
||||
import com.opensymphony.xwork2.ognl.OgnlReflectionProvider;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import com.opensymphony.xwork2.util.fs.DefaultFileManager;
|
||||
import com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory;
|
||||
import com.opensymphony.xwork2.util.reflection.ReflectionException;
|
||||
@@ -37,6 +38,9 @@ import org.apache.struts2.convention.actions.DefaultResultPathAction;
|
||||
import org.apache.struts2.convention.actions.NoAnnotationAction;
|
||||
import org.apache.struts2.convention.actions.Skip;
|
||||
import org.apache.struts2.convention.actions.action.*;
|
||||
import org.apache.struts2.convention.actions.allowedmethods.ClassLevelAllowedMethodsAction;
|
||||
import org.apache.struts2.convention.actions.allowedmethods.PackageLevelAllowedMethodsAction;
|
||||
import org.apache.struts2.convention.actions.allowedmethods.sub.PackageLevelAllowedMethodsChildAction;
|
||||
import org.apache.struts2.convention.actions.chain.ChainedAction;
|
||||
import org.apache.struts2.convention.actions.defaultinterceptor.SingleActionNameAction2;
|
||||
import org.apache.struts2.convention.actions.exception.ExceptionsActionLevelAction;
|
||||
@@ -125,8 +129,10 @@ public class PackageBasedActionConfigBuilderTest extends TestCase {
|
||||
new ResultTypeConfig.Builder("chain",
|
||||
ActionChainResult.class.getName()).defaultResultParam("actionName").build()};
|
||||
|
||||
Set<String> globalAllowedMethods = TextParseUtil.commaDelimitedStringToSet("execute,browse,cancel,input");
|
||||
|
||||
PackageConfig strutsDefault = makePackageConfig("struts-default", null, null, "dispatcher",
|
||||
defaultResults, defaultInterceptors, defaultInterceptorStacks);
|
||||
defaultResults, defaultInterceptors, defaultInterceptorStacks, globalAllowedMethods);
|
||||
|
||||
PackageConfig packageLevelParentPkg = makePackageConfig("package-level", null, null, null);
|
||||
PackageConfig classLevelParentPkg = makePackageConfig("class-level", null, null, null);
|
||||
@@ -151,6 +157,16 @@ public class PackageBasedActionConfigBuilderTest extends TestCase {
|
||||
"/parentpackage", packageLevelParentPkg, null);
|
||||
PackageConfig packageLevelSubPkg = makePackageConfig("org.apache.struts2.convention.actions.parentpackage.sub#package-level#/parentpackage/sub",
|
||||
"/parentpackage/sub", packageLevelParentPkg, null);
|
||||
|
||||
// Unexpected method call build(class org.apache.struts2.convention.actions.allowedmethods.PackageLevelAllowedMethodsAction, null, "package-level-allowed-methods", PackageConfig: [org.apache.struts2.convention.actions.allowedmethods#struts-default#/allowedmethods] for namespace [/allowedmethods] with parents [[PackageConfig: [struts-default] for namespace [] with parents [[]]]]):
|
||||
PackageConfig packageLevelAllowedMethodsPkg = makePackageConfig("org.apache.struts2.convention.actions.allowedmethods#struts-default#/allowedmethods",
|
||||
"/allowedmethods", strutsDefault, null);
|
||||
PackageConfig packageLevelAllowedMethodsSubPkg = makePackageConfig("org.apache.struts2.convention.actions.allowedmethods.sub#struts-default#/allowedmethods/sub",
|
||||
"/allowedmethods/sub", strutsDefault, null);
|
||||
|
||||
PackageConfig classLevelAllowedMethodsPkg = makePackageConfig("org.apache.struts2.convention.actions.allowedmethods#struts-default#/allowedmethods",
|
||||
"/allowedmethods", strutsDefault, null);
|
||||
|
||||
PackageConfig differentPkg = makePackageConfig("org.apache.struts2.convention.actions.parentpackage#class-level#/parentpackage",
|
||||
"/parentpackage", classLevelParentPkg, null);
|
||||
PackageConfig differentSubPkg = makePackageConfig("org.apache.struts2.convention.actions.parentpackage.sub#class-level#/parentpackage/sub",
|
||||
@@ -261,6 +277,11 @@ public class PackageBasedActionConfigBuilderTest extends TestCase {
|
||||
expect(resultMapBuilder.build(ClassLevelParentPackageAction.class, null, "class-level-parent-package", differentPkg)).andReturn(results);
|
||||
expect(resultMapBuilder.build(ClassLevelParentPackageChildAction.class, null, "class-level-parent-package-child", differentSubPkg)).andReturn(results);
|
||||
|
||||
/* org.apache.struts2.convention.actions.allowedmethods */
|
||||
expect(resultMapBuilder.build(ClassLevelAllowedMethodsAction.class, null, "class-level-allowed-methods", classLevelAllowedMethodsPkg)).andReturn(results);
|
||||
expect(resultMapBuilder.build(PackageLevelAllowedMethodsAction.class, null, "package-level-allowed-methods", packageLevelAllowedMethodsPkg)).andReturn(results);
|
||||
expect(resultMapBuilder.build(PackageLevelAllowedMethodsChildAction.class, null, "package-level-allowed-methods-child", packageLevelAllowedMethodsSubPkg)).andReturn(results);
|
||||
|
||||
/* org.apache.struts2.convention.actions.result */
|
||||
expect(resultMapBuilder.build(ClassLevelResultAction.class, null, "class-level-result", resultPkg)).andReturn(results);
|
||||
expect(resultMapBuilder.build(ClassLevelResultsAction.class, null, "class-level-results", resultPkg)).andReturn(results);
|
||||
@@ -450,7 +471,7 @@ public class PackageBasedActionConfigBuilderTest extends TestCase {
|
||||
verifyActionConfig(pkgConfig, "", org.apache.struts2.convention.actions.idx.Index.class, "execute", pkgConfig.getName());
|
||||
verifyActionConfig(pkgConfig, "index", org.apache.struts2.convention.actions.idx.Index.class, "execute", pkgConfig.getName());
|
||||
verifyActionConfig(pkgConfig, "idx2", org.apache.struts2.convention.actions.idx.idx2.Index.class, "execute",
|
||||
"org.apache.struts2.convention.actions.idx.idx2#struts-default#/idx/idx2");
|
||||
"org.apache.struts2.convention.actions.idx.idx2#struts-default#/idx/idx2");
|
||||
|
||||
/* org.apache.struts2.convention.actions.defaultinterceptor */
|
||||
pkgConfig = configuration.getPackageConfig("org.apache.struts2.convention.actions.defaultinterceptor#struts-default#/defaultinterceptor");
|
||||
@@ -514,6 +535,33 @@ public class PackageBasedActionConfigBuilderTest extends TestCase {
|
||||
verifyActionConfig(pkgConfig, "package-level-parent-package-child", PackageLevelParentPackageChildAction.class, "execute", pkgConfig.getName());
|
||||
assertEquals("package-level", pkgConfig.getParents().get(0).getName());
|
||||
|
||||
/* org.apache.struts2.convention.actions.allowedmethods class level */
|
||||
pkgConfig = configuration.getPackageConfig("org.apache.struts2.convention.actions.allowedmethods#struts-default#/allowedmethods");
|
||||
assertNotNull(pkgConfig);
|
||||
assertEquals(2, pkgConfig.getActionConfigs().size());
|
||||
verifyActionConfig(pkgConfig, "class-level-allowed-methods", ClassLevelAllowedMethodsAction.class, "execute", pkgConfig.getName());
|
||||
assertEquals("struts-default", pkgConfig.getParents().get(0).getName());
|
||||
|
||||
ActionConfig actionConfig = pkgConfig.getActionConfigs().get("class-level-allowed-methods");
|
||||
assertEquals(actionConfig.getAllowedMethods().size(), 5);
|
||||
assertTrue(actionConfig.getAllowedMethods().contains("execute"));
|
||||
assertTrue(actionConfig.getAllowedMethods().contains("end"));
|
||||
assertTrue(actionConfig.getAllowedMethods().contains("input"));
|
||||
|
||||
/* org.apache.struts2.convention.actions.allowedmethods.sub package level */
|
||||
pkgConfig = configuration.getPackageConfig("org.apache.struts2.convention.actions.allowedmethods.sub#struts-default#/allowedmethods/sub");
|
||||
assertNotNull(pkgConfig);
|
||||
assertEquals(1, pkgConfig.getActionConfigs().size());
|
||||
verifyActionConfig(pkgConfig, "package-level-allowed-methods-child", PackageLevelAllowedMethodsChildAction.class, "execute", pkgConfig.getName());
|
||||
assertEquals("struts-default", pkgConfig.getParents().get(0).getName());
|
||||
|
||||
actionConfig = pkgConfig.getActionConfigs().get("package-level-allowed-methods-child");
|
||||
assertEquals(actionConfig.getAllowedMethods().size(), 6);
|
||||
assertTrue(actionConfig.getAllowedMethods().contains("execute"));
|
||||
assertTrue(actionConfig.getAllowedMethods().contains("home"));
|
||||
assertTrue(actionConfig.getAllowedMethods().contains("start"));
|
||||
assertTrue(actionConfig.getAllowedMethods().contains("input"));
|
||||
|
||||
/* org.apache.struts2.convention.actions.result */
|
||||
pkgConfig = configuration.getPackageConfig("org.apache.struts2.convention.actions.result#struts-default#/result");
|
||||
assertNotNull(pkgConfig);
|
||||
@@ -631,12 +679,12 @@ public class PackageBasedActionConfigBuilderTest extends TestCase {
|
||||
|
||||
private PackageConfig makePackageConfig(String name, String namespace, PackageConfig parent,
|
||||
String defaultResultType, ResultTypeConfig... results) {
|
||||
return makePackageConfig(name, namespace, parent, defaultResultType, results, null, null);
|
||||
return makePackageConfig(name, namespace, parent, defaultResultType, results, null, null, null);
|
||||
}
|
||||
|
||||
private PackageConfig makePackageConfig(String name, String namespace, PackageConfig parent,
|
||||
String defaultResultType, ResultTypeConfig[] results, List<InterceptorConfig> interceptors,
|
||||
List<InterceptorStackConfig> interceptorStacks) {
|
||||
List<InterceptorStackConfig> interceptorStacks, Set<String> globalAllowedMethods) {
|
||||
PackageConfig.Builder builder = new PackageConfig.Builder(name);
|
||||
if (namespace != null) {
|
||||
builder.namespace(namespace);
|
||||
@@ -663,6 +711,10 @@ public class PackageBasedActionConfigBuilderTest extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
if (globalAllowedMethods != null) {
|
||||
builder.addGlobalAllowedMethods(globalAllowedMethods);
|
||||
}
|
||||
|
||||
return new MyPackageConfig(builder.build());
|
||||
}
|
||||
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package org.apache.struts2.convention.actions.allowedmethods;
|
||||
|
||||
import org.apache.struts2.convention.annotation.AllowedMethods;
|
||||
|
||||
@AllowedMethods("end")
|
||||
public class ClassLevelAllowedMethodsAction {
|
||||
|
||||
public String execute() { return null; }
|
||||
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package org.apache.struts2.convention.actions.allowedmethods;
|
||||
|
||||
public class PackageLevelAllowedMethodsAction {
|
||||
|
||||
public String execute() { return null; }
|
||||
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* $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.
|
||||
*/
|
||||
@org.apache.struts2.convention.annotation.AllowedMethods("home,start")
|
||||
package org.apache.struts2.convention.actions.allowedmethods;
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package org.apache.struts2.convention.actions.allowedmethods.sub;
|
||||
|
||||
import org.apache.struts2.convention.actions.allowedmethods.PackageLevelAllowedMethodsAction;
|
||||
|
||||
public class PackageLevelAllowedMethodsChildAction extends PackageLevelAllowedMethodsAction {
|
||||
|
||||
public String execute() { return null; }
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user