/*
* Copyright 2002-2006,2009 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.opensymphony.xwork2.config.entities;
import com.opensymphony.xwork2.util.location.Located;
import com.opensymphony.xwork2.util.location.Location;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.Serializable;
import java.util.*;
/**
* Configuration for Package.
*
* <p>
* In the xml configuration file this is defined as the <code>package</code> tag.
* </p>
*
* @author Rainer Hermanns
* @version $Revision$
*/
public class PackageConfig extends Located implements Comparable, Serializable, InterceptorLocator {
private static final Logger LOG = LogManager.getLogger(PackageConfig.class);
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;
protected List<PackageConfig> parents;
protected String defaultInterceptorRef;
protected String defaultActionRef;
protected String defaultResultType;
protected String defaultClassRef;
protected String name;
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<>();
parents = new ArrayList<>();
}
protected PackageConfig(PackageConfig orig) {
this.defaultInterceptorRef = orig.defaultInterceptorRef;
this.defaultActionRef = orig.defaultActionRef;
this.defaultResultType = orig.defaultResultType;
this.defaultClassRef = orig.defaultClassRef;
this.name = orig.name;
this.namespace = orig.namespace;
this.isAbstract = orig.isAbstract;
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() {
return isAbstract;
}
public Map<String, ActionConfig> getActionConfigs() {
return actionConfigs;
}
/**
* returns the Map of all the ActionConfigs available in the current package.
* ActionConfigs defined in ancestor packages will be included in this Map.
*
* @return a Map of ActionConfig Objects with the action name as the key
* @see ActionConfig
*/
public Map<String, ActionConfig> getAllActionConfigs() {
Map<String, ActionConfig> retMap = new LinkedHashMap<>();
if (!parents.isEmpty()) {
for (PackageConfig parent : parents) {
retMap.putAll(parent.getAllActionConfigs());
}
}
retMap.putAll(getActionConfigs());
return retMap;
}
/**
* returns the Map of all the global ResultConfigs available in the current package.
* Global ResultConfigs defined in ancestor packages will be included in this Map.
*
* @return a Map of Result Objects with the result name as the key
* @see ResultConfig
*/
public Map<String, ResultConfig> getAllGlobalResults() {
Map<String, ResultConfig> retMap = new LinkedHashMap<>();
if (!parents.isEmpty()) {
for (PackageConfig parentConfig : parents) {
retMap.putAll(parentConfig.getAllGlobalResults());
}
}
retMap.putAll(getGlobalResultConfigs());
return retMap;
}
/**
* returns the Map of all InterceptorConfigs and InterceptorStackConfigs available in the current package.
* InterceptorConfigs defined in ancestor packages will be included in this Map.
*
* @return a Map of InterceptorConfig and InterceptorStackConfig Objects with the ref-name as the key
* @see InterceptorConfig
* @see InterceptorStackConfig
*/
public Map<String, Object> getAllInterceptorConfigs() {
Map<String, Object> retMap = new LinkedHashMap<>();
if (!parents.isEmpty()) {
for (PackageConfig parentContext : parents) {
retMap.putAll(parentContext.getAllInterceptorConfigs());
}
}
retMap.putAll(getInterceptorConfigs());
return retMap;
}
/**
* returns the Map of all the ResultTypeConfigs available in the current package.
* ResultTypeConfigs defined in ancestor packages will be included in this Map.
*
* @return a Map of ResultTypeConfig Objects with the result type name as the key
* @see ResultTypeConfig
*/
public Map<String, ResultTypeConfig> getAllResultTypeConfigs() {
Map<String, ResultTypeConfig> retMap = new LinkedHashMap<>();
if (!parents.isEmpty()) {
for (PackageConfig parentContext : parents) {
retMap.putAll(parentContext.getAllResultTypeConfigs());
}
}
retMap.putAll(getResultTypeConfigs());
return retMap;
}
/**
* returns the List of all the ExceptionMappingConfigs available in the current package.
* ExceptionMappingConfigs defined in ancestor packages will be included in this list.
*
* @return a List of ExceptionMappingConfigs Objects with the result type name as the key
* @see ExceptionMappingConfig
*/
public List<ExceptionMappingConfig> getAllExceptionMappingConfigs() {
List<ExceptionMappingConfig> allExceptionMappings = new ArrayList<>();
if (!parents.isEmpty()) {
for (PackageConfig parentContext : parents) {
allExceptionMappings.addAll(parentContext.getAllExceptionMappingConfigs());
}
}
allExceptionMappings.addAll(getGlobalExceptionMappingConfigs());
return allExceptionMappings;
}
public String getDefaultInterceptorRef() {
return defaultInterceptorRef;
}
public String getDefaultActionRef() {
return defaultActionRef;
}
public String getDefaultClassRef() {
if ((defaultClassRef == null) && !parents.isEmpty()) {
for (PackageConfig parent : parents) {
String parentDefault = parent.getDefaultClassRef();
if (parentDefault != null) {
return parentDefault;
}
}
}
return defaultClassRef;
}
/**
* @return the default result type for this package.
*/
public String getDefaultResultType() {
return defaultResultType;
}
/**
* @return the default interceptor-ref name. If this is not set on this PackageConfig, it searches the parent
* PackageConfigs in order until it finds one.
*/
public String getFullDefaultInterceptorRef() {
if ((defaultInterceptorRef == null) && !parents.isEmpty()) {
for (PackageConfig parent : parents) {
String parentDefault = parent.getFullDefaultInterceptorRef();
if (parentDefault != null) {
return parentDefault;
}
}
}
return defaultInterceptorRef;
}
/**
* @return the default action-ref name. If this is not set on this PackageConfig, it searches the parent
* PackageConfigs in order until it finds one.
*/
public String getFullDefaultActionRef() {
if ((defaultActionRef == null) && !parents.isEmpty()) {
for (PackageConfig parent : parents) {
String parentDefault = parent.getFullDefaultActionRef();
if (parentDefault != null) {
return parentDefault;
}
}
}
return defaultActionRef;
}
/**
* <p>
* Returns the default result type for this package.
* </p>
*
* <p>
* If there is no default result type, but this package has parents - we will try to
* look up the default result type of a parent.
* </p>
*
* @return the default result type for this package.
*/
public String getFullDefaultResultType() {
if ((defaultResultType == null) && !parents.isEmpty()) {
for (PackageConfig parent : parents) {
String parentDefault = parent.getFullDefaultResultType();
if (parentDefault != null) {
return parentDefault;
}
}
}
return defaultResultType;
}
/**
* gets the global ResultConfigs local to this package
*
* @return a Map of ResultConfig objects keyed by result name
* @see ResultConfig
*/
public Map<String, ResultConfig> getGlobalResultConfigs() {
return globalResultConfigs;
}
/**
* gets the InterceptorConfigs and InterceptorStackConfigs local to this package
*
* @return a Map of InterceptorConfig and InterceptorStackConfig objects keyed by ref-name
* @see InterceptorConfig
* @see InterceptorStackConfig
*/
public Map<String, Object> getInterceptorConfigs() {
return interceptorConfigs;
}
public String getName() {
return name;
}
public String getNamespace() {
return namespace;
}
public List<PackageConfig> getParents() {
return new ArrayList<>(parents);
}
/**
* gets the ResultTypeConfigs local to this package
*
* @return a Map of ResultTypeConfig objects keyed by result name
* @see ResultTypeConfig
*/
public Map<String, ResultTypeConfig> getResultTypeConfigs() {
return resultTypeConfigs;
}
public boolean isNeedsRefresh() {
return needsRefresh;
}
/**
* gets the ExceptionMappingConfigs local to this package
*
* @return a Map of ExceptionMappingConfig objects keyed by result name
* @see ExceptionMappingConfig
*/
public List<ExceptionMappingConfig> getGlobalExceptionMappingConfigs() {
return globalExceptionMappingConfigs;
}
/**
* gets the GlobalAllowedMethods local to this package
*
* @return a Set of method names allowed to be executed if strict method invocation is enabled
*/
public Set<String> getGlobalAllowedMethods() { return Collections.unmodifiableSet(globalAllowedMethods); }
public boolean isStrictMethodInvocation() {
return strictMethodInvocation;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
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;
if (globalResultConfigs != null ? !globalResultConfigs.equals(that.globalResultConfigs) : that.globalResultConfigs != null)
return false;
if (globalAllowedMethods != null ? !globalAllowedMethods.equals(that.globalAllowedMethods) : that.globalAllowedMethods != null)
return false;
if (interceptorConfigs != null ? !interceptorConfigs.equals(that.interceptorConfigs) : that.interceptorConfigs != null)
return false;
if (resultTypeConfigs != null ? !resultTypeConfigs.equals(that.resultTypeConfigs) : that.resultTypeConfigs != null)
return false;
if (globalExceptionMappingConfigs != null ? !globalExceptionMappingConfigs.equals(that.globalExceptionMappingConfigs) : that.globalExceptionMappingConfigs != null)
return false;
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 (defaultActionRef != null ? !defaultActionRef.equals(that.defaultActionRef) : that.defaultActionRef != null)
return false;
if (defaultResultType != null ? !defaultResultType.equals(that.defaultResultType) : that.defaultResultType != null)
return false;
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);
}
@Override
public int hashCode() {
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;
}
@Override
public String toString() {
return "PackageConfig: [" + name + "] for namespace [" + namespace + "] with parents [" + parents + "]";
}
public int compareTo(Object o) {
PackageConfig other = (PackageConfig) o;
String full = namespace + "!" + name;
String otherFull = other.namespace + "!" + other.name;
// note, this isn't perfect (could come from different parents), but it is "good enough"
return full.compareTo(otherFull);
}
public Object getInterceptorConfig(String name) {
return getAllInterceptorConfigs().get(name);
}
/**
* The builder for this object. An instance of this object is the only way to construct a new instance. The
* purpose is to enforce the immutability of the object. The methods are structured in a way to support chaining.
* After setting any values you need, call the {@link #build()} method to create the object.
*/
public static class Builder implements InterceptorLocator {
protected PackageConfig target;
private boolean strictDMI = true;
public Builder(String name) {
target = new PackageConfig(name);
}
public Builder(PackageConfig config) {
target = new PackageConfig(config);
}
public Builder name(String name) {
target.name = name;
return this;
}
public Builder isAbstract(boolean isAbstract) {
target.isAbstract = isAbstract;
return this;
}
public Builder defaultInterceptorRef(String name) {
target.defaultInterceptorRef = name;
return this;
}
public Builder defaultActionRef(String name) {
target.defaultActionRef = name;
return this;
}
public Builder defaultClassRef(String defaultClassRef) {
target.defaultClassRef = defaultClassRef;
return this;
}
/**
* sets the default Result type for this package
*
* @param defaultResultType set the default result type
*
* @return this builder
*/
public Builder defaultResultType(String defaultResultType) {
target.defaultResultType = defaultResultType;
return this;
}
public Builder namespace(String namespace) {
if (namespace == null) {
target.namespace = "";
} else {
target.namespace = namespace;
}
return this;
}
public Builder needsRefresh(boolean needsRefresh) {
target.needsRefresh = needsRefresh;
return this;
}
public Builder addActionConfig(String name, ActionConfig action) {
target.actionConfigs.put(name, action);
return this;
}
public Builder addParents(List<PackageConfig> parents) {
for (PackageConfig config : parents) {
addParent(config);
}
return this;
}
public Builder addGlobalResultConfig(ResultConfig resultConfig) {
target.globalResultConfigs.put(resultConfig.getName(), resultConfig);
return this;
}
public Builder addGlobalResultConfigs(Map<String, ResultConfig> resultConfigs) {
target.globalResultConfigs.putAll(resultConfigs);
return this;
}
public Set<String> getGlobalAllowedMethods() {
Set <String> allowedMethods = target.globalAllowedMethods;
allowedMethods.addAll(getParentsAllowedMethods(target.parents));
return Collections.unmodifiableSet(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;
}
public Builder addGlobalExceptionMappingConfigs(List<ExceptionMappingConfig> exceptionMappingConfigs) {
target.globalExceptionMappingConfigs.addAll(exceptionMappingConfigs);
return this;
}
public Builder addInterceptorConfig(InterceptorConfig config) {
target.interceptorConfigs.put(config.getName(), config);
return this;
}
public Builder addInterceptorStackConfig(InterceptorStackConfig config) {
target.interceptorConfigs.put(config.getName(), config);
return this;
}
public Builder addParent(PackageConfig parent) {
target.parents.add(0, parent);
return this;
}
public Builder addResultTypeConfig(ResultTypeConfig config) {
target.resultTypeConfigs.put(config.getName(), config);
return this;
}
public Builder location(Location loc) {
target.location = loc;
return this;
}
public boolean isNeedsRefresh() {
return target.needsRefresh;
}
public String getDefaultClassRef() {
return target.defaultClassRef;
}
public String getName() {
return target.name;
}
public String getNamespace() {
return target.namespace;
}
public String getFullDefaultResultType() {
return target.getFullDefaultResultType();
}
public ResultTypeConfig getResultType(String type) {
return target.getAllResultTypeConfigs().get(type);
}
public Object getInterceptorConfig(String name) {
return target.getAllInterceptorConfigs().get(name);
}
public Builder strictMethodInvocation(boolean strict) {
target.strictMethodInvocation = strict;
return this;
}
public boolean isStrictMethodInvocation() {
return target.strictMethodInvocation;
}
public PackageConfig build() {
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
public String toString() {
return "[BUILDER] " + target.toString();
}
}
}