/*
* $Id: ActionConfig.java 480593 2006-11-29 15:17:52Z niallp $
*
* 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.struts.config;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.util.RequestUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
/**
* <p>A JavaBean representing the configuration information of an
* <code><action></code> element from a Struts module configuration
* file.</p>
*
* @version $Rev: 480593 $ $Date: 2006-11-29 16:17:52 +0100 (Wed, 29 Nov 2006) $
* @since Struts 1.1
*/
public class ActionConfig extends BaseConfig {
private static final Log log = LogFactory.getLog(ActionConfig.class);
// ----------------------------------------------------- Instance Variables
/**
* <p> The set of exception handling configurations for this action, if
* any, keyed by the <code>type</code> property. </p>
*/
protected HashMap exceptions = new HashMap();
/**
* <p> The set of local forward configurations for this action, if any,
* keyed by the <code>name</code> property. </p>
*/
protected HashMap forwards = new HashMap();
// ------------------------------------------------------------- Properties
/**
* <p> The module configuration with which we are associated. </p>
*/
protected ModuleConfig moduleConfig = null;
/**
* <p> The request-scope or session-scope attribute name under which our
* form bean is accessed, if it is different from the form bean's
* specified <code>name</code>. </p>
*/
protected String attribute = null;
/**
* <p>The internal identification of this action mapping. Identifications are
* not inheritable and must be unique within a module.</p>
*
* @since Struts 1.3.6
*/
protected String actionId = null;
/**
* <p>The path of the ActionConfig that this object should inherit
* properties from.</p> </p>
*/
protected String inherit = null;
/**
* Indicates whether the "cancellable " property has been set or not.
*/
private boolean cancellableSet = false;
/**
* <p>Can this Action be cancelled? [false]</p> <p> By default, when an
* Action is cancelled, validation is bypassed and the Action should not
* execute the business operation. If a request tries to cancel an Action
* when cancellable is not set, a "InvalidCancelException" is thrown.
* </p>
*/
protected boolean cancellable = false;
/**
* <p> Have the inheritance values for this class been applied?</p>
*/
protected boolean extensionProcessed = false;
/**
* <p> Context-relative path of the web application resource that will
* process this request via RequestDispatcher.forward(), instead of
* instantiating and calling the <code>Action</code> class specified by
* "type". Exactly one of <code>forward</code>, <code>include</code>, or
* <code>type</code> must be specified. </p>
*/
protected String forward = null;
/**
* <p> Context-relative path of the web application resource that will
* process this request via RequestDispatcher.include(), instead of
* instantiating and calling the <code>Action</code> class specified by
* "type". Exactly one of <code>forward</code>, <code>include</code>, or
* <code>type</code> must be specified. </p>
*/
protected String include = null;
/**
* <p> Context-relative path of the input form to which control should be
* returned if a validation error is encountered. Required if "name" is
* specified and the input bean returns validation errors. </p>
*/
protected String input = null;
/**
* <p> Fully qualified Java class name of the <code>MultipartRequestHandler</code>
* implementation class used to process multi-part request data for this
* Action. </p>
*/
protected String multipartClass = null;
/**
* <p> Name of the form bean, if any, associated with this Action. </p>
*/
protected String name = null;
/**
* <p> General purpose configuration parameter that can be used to pass
* extra information to the Action instance selected by this Action.
* Struts does not itself use this value in any way. </p>
*/
protected String parameter = null;
/**
* <p> Context-relative path of the submitted request, starting with a
* slash ("/") character, and omitting any filename extension if extension
* mapping is being used. </p>
*/
protected String path = null;
/**
* <p> Prefix used to match request parameter names to form bean property
* names, if any. </p>
*/
protected String prefix = null;
/**
* <p> Comma-delimited list of security role names allowed to request this
* Action. </p>
*/
protected String roles = null;
/**
* <p> The set of security role names used to authorize access to this
* Action, as an array for faster access. </p>
*/
protected String[] roleNames = new String[0];
/**
* <p> Identifier of the scope ("request" or "session") within which our
* form bean is accessed, if any. </p>
*/
protected String scope = "session";
/**
* <p> Suffix used to match request parameter names to form bean property
* names, if any. </p>
*/
protected String suffix = null;
/**
* <p> Fully qualified Java class name of the <code>Action</code> class to
* be used to process requests for this mapping if the
* <code>forward</code> and <code>include</code> properties are not set.
* Exactly one of <code>forward</code>, <code>include</code>, or
* <code>type</code> must be specified.
*/
protected String type = null;
/**
* <p> Indicates Action be configured as the default one for this module,
* when true.
*/
protected boolean unknown = false;
/**
* Indicates whether the "validate" property has been set or not.
*/
private boolean validateSet = false;
/**
* <p> Should the <code>validate()</code> method of the form bean
* associated with this action be called?
*/
protected boolean validate = true;
/**
* <p> The name of a <code>commons-chain</code> command which should be
* executed as part of the processing of this action.
*
* @since Struts 1.3.0
*/
protected String command = null;
/**
* <p> The name of a <code>commons-chain</code> catalog in which
* <code>command</code> should be sought. If a <code>command</code> is
* defined and this property is undefined, the "default" catalog will be
* used. This is likely to be infrequently used after a future release of
* <code>commons-chain</code> supports a one-string expression of a
* catalog/chain combination.
*
* @since Struts 1.3.0
*/
protected String catalog = null;
/**
* <p>The internal name of this action mapping. If an action has a name, it may be used
* as a shortcut in a URI. For example, an action with an identification of "editPerson"
* may be internally forwarded as "editPerson?id=1" which will then resolve to the
* real URI path at execution time.</p>
*
* @return the actionId
* @since Struts 1.3.6
*/
public String getActionId() {
return this.actionId;
}
/**
* <p>The internal name of this action mapping. The name is not inheritable,
* may not contain a forward slash, and must be unique within a module. </p>
*
* @param actionId the action identifier
* @since Struts 1.3.6
* @throws IllegalStateException if the configuration is frozen
* @throws IllegalArgumentException if the identifier contains a forward slash
*/
public void setActionId(String actionId) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
if ((actionId != null) && (actionId.indexOf("/") > -1)) {
throw new IllegalArgumentException("actionId '" + actionId + "' may not contain a forward slash");
}
this.actionId = actionId;
}
/**
* <p> The module configuration with which we are associated.
*/
public ModuleConfig getModuleConfig() {
return (this.moduleConfig);
}
/**
* <p> The module configuration with which we are associated.
*/
public void setModuleConfig(ModuleConfig moduleConfig) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.moduleConfig = moduleConfig;
}
/**
* <p> Returns the request-scope or session-scope attribute name under
* which our form bean is accessed, if it is different from the form
* bean's specified <code>name</code>.
*
* @return attribute name under which our form bean is accessed.
*/
public String getAttribute() {
if (this.attribute == null) {
return (this.name);
} else {
return (this.attribute);
}
}
/**
* <p> Set the request-scope or session-scope attribute name under which
* our form bean is accessed, if it is different from the form bean's
* specified <code>name</code>.
*
* @param attribute the request-scope or session-scope attribute name
* under which our form bean is access.
*/
public void setAttribute(String attribute) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.attribute = attribute;
}
/**
* <p>Accessor for cancellable property</p>
*
* @return True if Action can be cancelled
*/
public boolean getCancellable() {
return (this.cancellable);
}
/**
* <p>Mutator for for cancellable property</p>
*
* @param cancellable
*/
public void setCancellable(boolean cancellable) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.cancellable = cancellable;
this.cancellableSet = true;
}
/**
* <p>Returns the path of the ActionConfig that this object should inherit
* properties from.</p>
*
* @return the path of the ActionConfig that this object should inherit
* properties from.
*/
public String getExtends() {
return (this.inherit);
}
/**
* <p>Set the path of the ActionConfig that this object should inherit
* properties from.</p>
*
* @param inherit the path of the ActionConfig that this object should
* inherit properties from.
*/
public void setExtends(String inherit) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.inherit = inherit;
}
public boolean isExtensionProcessed() {
return extensionProcessed;
}
/**
* <p> Returns context-relative path of the web application resource that
* will process this request.
*
* @return context-relative path of the web application resource that will
* process this request.
*/
public String getForward() {
return (this.forward);
}
/**
* <p> Set the context-relative path of the web application resource that
* will process this request. Exactly one of <code>forward</code>,
* <code>include</code>, or <code>type</code> must be specified.
*
* @param forward context-relative path of the web application resource
* that will process this request.
*/
public void setForward(String forward) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.forward = forward;
}
/**
* <p> Context-relative path of the web application resource that will
* process this request.
*
* @return Context-relative path of the web application resource that will
* process this request.
*/
public String getInclude() {
return (this.include);
}
/**
* <p> Set context-relative path of the web application resource that will
* process this request. Exactly one of <code>forward</code>,
* <code>include</code>, or <code>type</code> must be specified.
*
* @param include context-relative path of the web application resource
* that will process this request.
*/
public void setInclude(String include) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.include = include;
}
/**
* <p> Get the context-relative path of the input form to which control
* should be returned if a validation error is encountered.
*
* @return context-relative path of the input form to which control should
* be returned if a validation error is encountered.
*/
public String getInput() {
return (this.input);
}
/**
* <p> Set the context-relative path of the input form to which control
* should be returned if a validation error is encountered. Required if
* "name" is specified and the input bean returns validation errors.
*
* @param input context-relative path of the input form to which control
* should be returned if a validation error is encountered.
*/
public void setInput(String input) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.input = input;
}
/**
* <p> Return the fully qualified Java class name of the
* <code>MultipartRequestHandler</code> implementation class used to
* process multi-part request data for this Action.
*/
public String getMultipartClass() {
return (this.multipartClass);
}
/**
* <p> Set the fully qualified Java class name of the
* <code>MultipartRequestHandler</code> implementation class used to
* process multi-part request data for this Action.
*
* @param multipartClass fully qualified class name of the
* <code>MultipartRequestHandler</code>
* implementation class.
*/
public void setMultipartClass(String multipartClass) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.multipartClass = multipartClass;
}
/**
* <p> Return name of the form bean, if any, associated with this Action.
*/
public String getName() {
return (this.name);
}
/**
* @param name name of the form bean associated with this Action.
*/
public void setName(String name) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.name = name;
}
/**
* <p> Return general purpose configuration parameter that can be used to
* pass extra information to the Action instance selected by this Action.
* Struts does not itself use this value in any way.
*/
public String getParameter() {
return (this.parameter);
}
/**
* <p> General purpose configuration parameter that can be used to pass
* extra information to the Action instance selected by this Action.
* Struts does not itself use this value in any way.
*
* @param parameter General purpose configuration parameter.
*/
public void setParameter(String parameter) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.parameter = parameter;
}
/**
* <p> Return context-relative path of the submitted request, starting
* with a slash ("/") character, and omitting any filename extension if
* extension mapping is being used.
*/
public String getPath() {
return (this.path);
}
/**
* <p> Set context-relative path of the submitted request, starting with a
* slash ("/") character, and omitting any filename extension if extension
* mapping is being used.
*
* @param path context-relative path of the submitted request.
*/
public void setPath(String path) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.path = path;
}
/**
* <p> Retruns prefix used to match request parameter names to form bean
* property names, if any.
*/
public String getPrefix() {
return (this.prefix);
}
/**
* @param prefix Prefix used to match request parameter names to form bean
* property names, if any.
*/
public void setPrefix(String prefix) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.prefix = prefix;
}
public String getRoles() {
return (this.roles);
}
public void setRoles(String roles) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.roles = roles;
if (roles == null) {
roleNames = new String[0];
return;
}
ArrayList list = new ArrayList();
while (true) {
int comma = roles.indexOf(',');
if (comma < 0) {
break;
}
list.add(roles.substring(0, comma).trim());
roles = roles.substring(comma + 1);
}
roles = roles.trim();
if (roles.length() > 0) {
list.add(roles);
}
roleNames = (String[]) list.toArray(new String[list.size()]);
}
/**
* <p> Get array of security role names used to authorize access to this
* Action.
*/
public String[] getRoleNames() {
return (this.roleNames);
}
/**
* <p> Get the scope ("request" or "session") within which our form bean
* is accessed, if any.
*/
public String getScope() {
return (this.scope);
}
/**
* @param scope scope ("request" or "session") within which our form bean
* is accessed, if any.
*/
public void setScope(String scope) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.scope = scope;
}
/**
* <p> Return suffix used to match request parameter names to form bean
* property names, if any. </p>
*/
public String getSuffix() {
return (this.suffix);
}
/**
* @param suffix Suffix used to match request parameter names to form bean
* property names, if any.
*/
public void setSuffix(String suffix) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.suffix = suffix;
}
public String getType() {
return (this.type);
}
public void setType(String type) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.type = type;
}
/**
* <p> Determine whether Action is configured as the default one for this
* module. </p>
*/
public boolean getUnknown() {
return (this.unknown);
}
/**
* @param unknown Indicates Action is configured as the default one for
* this module, when true.
*/
public void setUnknown(boolean unknown) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.unknown = unknown;
}
public boolean getValidate() {
return (this.validate);
}
public void setValidate(boolean validate) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.validate = validate;
this.validateSet = true;
}
/**
* <p> Get the name of a <code>commons-chain</code> command which should
* be executed as part of the processing of this action. </p>
*
* @return name of a <code>commons-chain</code> command which should be
* executed as part of the processing of this action.
* @since Struts 1.3.0
*/
public String getCommand() {
return (this.command);
}
/**
* <p> Get the name of a <code>commons-chain</code> catalog in which a
* specified command should be sought. This is likely to be infrequently
* used after a future release of <code>commons-chain</code> supports a
* one-string expression of a catalog/chain combination. </p>
*
* @return name of a <code>commons-chain</code> catalog in which a
* specified command should be sought.
* @since Struts 1.3.0
*/
public String getCatalog() {
return (this.catalog);
}
/**
* <p> Set the name of a <code>commons-chain</code> command which should
* be executed as part of the processing of this action. </p>
*
* @param command name of a <code>commons-chain</code> command which
* should be executed as part of the processing of this
* action.
* @since Struts 1.3.0
*/
public void setCommand(String command) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.command = command;
}
/**
* <p> Set the name of a <code>commons-chain</code> catalog in which a
* specified command should be sought. This is likely to be infrequently
* used after a future release of <code>commons-chain</code> supports a
* one-string expression of a catalog/chain combination. </p>
*
* @param catalog name of a <code>commons-chain</code> catalog in which a
* specified command should be sought.
* @since Struts 1.3.0
*/
public void setCatalog(String catalog) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
this.catalog = catalog;
}
// ------------------------------------------------------ Protected Methods
/**
* <p>Traces the hierarchy of this object to check if any of the ancestors
* is extending this instance.</p>
*
* @param moduleConfig The configuration for the module being configured.
* @return true if circular inheritance was detected.
*/
protected boolean checkCircularInheritance(ModuleConfig moduleConfig) {
String ancestorPath = getExtends();
while (ancestorPath != null) {
// check if we have the same path as an ancestor
if (getPath().equals(ancestorPath)) {
return true;
}
// get our ancestor's ancestor
ActionConfig ancestor = moduleConfig.findActionConfig(ancestorPath);
if (ancestor != null) {
ancestorPath = ancestor.getExtends();
} else {
ancestorPath = null;
}
}
return false;
}
/**
* <p>Compare the exception handlers of this action with that of the given
* and copy those that are not present.</p>
*
* @param baseConfig The action config to copy handlers from.
* @see #inheritFrom(ActionConfig)
*/
protected void inheritExceptionHandlers(ActionConfig baseConfig)
throws ClassNotFoundException, IllegalAccessException,
InstantiationException, InvocationTargetException {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
// Inherit exception handler configs
ExceptionConfig[] baseHandlers = baseConfig.findExceptionConfigs();
for (int i = 0; i < baseHandlers.length; i++) {
ExceptionConfig baseHandler = baseHandlers[i];
// Do we have this handler?
ExceptionConfig copy =
this.findExceptionConfig(baseHandler.getType());
if (copy == null) {
// We don't have this, so let's copy it
copy =
(ExceptionConfig) RequestUtils.applicationInstance(baseHandler.getClass()
.getName());
BeanUtils.copyProperties(copy, baseHandler);
this.addExceptionConfig(copy);
copy.setProperties(baseHandler.copyProperties());
} else {
// process any extension that this config might have
copy.processExtends(getModuleConfig(), this);
}
}
}
/**
* <p>Compare the forwards of this action with that of the given and copy
* those that are not present.</p>
*
* @param baseConfig The action config to copy forwards from.
* @see #inheritFrom(ActionConfig)
*/
protected void inheritForwards(ActionConfig baseConfig)
throws ClassNotFoundException, IllegalAccessException,
InstantiationException, InvocationTargetException {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
// Inherit forward configs
ForwardConfig[] baseForwards = baseConfig.findForwardConfigs();
for (int i = 0; i < baseForwards.length; i++) {
ForwardConfig baseForward = baseForwards[i];
// Do we have this forward?
ForwardConfig copy = this.findForwardConfig(baseForward.getName());
if (copy == null) {
// We don't have this, so let's copy it
copy =
(ForwardConfig) RequestUtils.applicationInstance(baseForward.getClass()
.getName());
BeanUtils.copyProperties(copy, baseForward);
this.addForwardConfig(copy);
copy.setProperties(baseForward.copyProperties());
} else {
// process any extension for this forward
copy.processExtends(getModuleConfig(), this);
}
}
}
// --------------------------------------------------------- Public Methods
/**
* <p> Add a new <code>ExceptionConfig</code> instance to the set
* associated with this action. </p>
*
* @param config The new configuration instance to be added
* @throws IllegalStateException if this module configuration has been
* frozen
*/
public void addExceptionConfig(ExceptionConfig config) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
exceptions.put(config.getType(), config);
}
/**
* <p> Add a new <code>ForwardConfig</code> instance to the set of global
* forwards associated with this action. </p>
*
* @param config The new configuration instance to be added
* @throws IllegalStateException if this module configuration has been
* frozen
*/
public void addForwardConfig(ForwardConfig config) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
forwards.put(config.getName(), config);
}
/**
* <p> Return the exception configuration for the specified type, if any;
* otherwise return <code>null</code>. </p>
*
* @param type Exception class name to find a configuration for
*/
public ExceptionConfig findExceptionConfig(String type) {
return ((ExceptionConfig) exceptions.get(type));
}
/**
* <p> Return the exception configurations for this action. If there are
* none, a zero-length array is returned. </p>
*/
public ExceptionConfig[] findExceptionConfigs() {
ExceptionConfig[] results = new ExceptionConfig[exceptions.size()];
return ((ExceptionConfig[]) exceptions.values().toArray(results));
}
/**
* <p>Find and return the <code>ExceptionConfig</code> instance defining
* how <code>Exceptions</code> of the specified type should be handled.
* This is performed by checking local and then global configurations for
* the specified exception's class, and then looking up the superclass
* chain (again checking local and then global configurations). If no
* handler configuration can be found, return <code>null</code>.</p>
*
* <p>Introduced in <code>ActionMapping</code> in Struts 1.1, but pushed
* up to <code>ActionConfig</code> in Struts 1.2.0.</p>
*
* @param type Exception class for which to find a handler
* @since Struts 1.2.0
*/
public ExceptionConfig findException(Class type) {
// Check through the entire superclass hierarchy as needed
ExceptionConfig config;
while (true) {
// Check for a locally defined handler
String name = type.getName();
log.debug("findException: look locally for " + name);
config = findExceptionConfig(name);
if (config != null) {
return (config);
}
// Check for a globally defined handler
log.debug("findException: look globally for " + name);
config = getModuleConfig().findExceptionConfig(name);
if (config != null) {
return (config);
}
// Loop again for our superclass (if any)
type = type.getSuperclass();
if (type == null) {
break;
}
}
return (null); // No handler has been configured
}
/**
* <p> Return the forward configuration for the specified key, if any;
* otherwise return <code>null</code>. </p>
*
* @param name Name of the forward configuration to return
*/
public ForwardConfig findForwardConfig(String name) {
return ((ForwardConfig) forwards.get(name));
}
/**
* <p> Return all forward configurations for this module. If there are
* none, a zero-length array is returned. </p>
*/
public ForwardConfig[] findForwardConfigs() {
ForwardConfig[] results = new ForwardConfig[forwards.size()];
return ((ForwardConfig[]) forwards.values().toArray(results));
}
/**
* <p> Freeze the configuration of this action. </p>
*/
public void freeze() {
super.freeze();
ExceptionConfig[] econfigs = findExceptionConfigs();
for (int i = 0; i < econfigs.length; i++) {
econfigs[i].freeze();
}
ForwardConfig[] fconfigs = findForwardConfigs();
for (int i = 0; i < fconfigs.length; i++) {
fconfigs[i].freeze();
}
}
/**
* <p>Inherit values that have not been overridden from the provided
* config object. Subclasses overriding this method should verify that
* the given parameter is of a class that contains a property it is trying
* to inherit:</p>
*
* <pre>
* if (config instanceof MyCustomConfig) {
* MyCustomConfig myConfig =
* (MyCustomConfig) config;
*
* if (getMyCustomProp() == null) {
* setMyCustomProp(myConfig.getMyCustomProp());
* }
* }
* </pre>
*
* <p>If the given <code>config</code> is extending another object, those
* extensions should be resolved before it's used as a parameter to this
* method.</p>
*
* @param config The object that this instance will be inheriting its
* values from.
* @see #processExtends(ModuleConfig)
*/
public void inheritFrom(ActionConfig config)
throws ClassNotFoundException, IllegalAccessException,
InstantiationException, InvocationTargetException {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
// Inherit values that have not been overridden
if (getAttribute() == null) {
setAttribute(config.getAttribute());
}
if (!cancellableSet) {
setCancellable(config.getCancellable());
}
if (getCatalog() == null) {
setCatalog(config.getCatalog());
}
if (getCommand() == null) {
setCommand(config.getCommand());
}
if (getForward() == null) {
setForward(config.getForward());
}
if (getInclude() == null) {
setInclude(config.getInclude());
}
if (getInput() == null) {
setInput(config.getInput());
}
if (getMultipartClass() == null) {
setMultipartClass(config.getMultipartClass());
}
if (getName() == null) {
setName(config.getName());
}
if (getParameter() == null) {
setParameter(config.getParameter());
}
if (getPath() == null) {
setPath(config.getPath());
}
if (getPrefix() == null) {
setPrefix(config.getPrefix());
}
if (getRoles() == null) {
setRoles(config.getRoles());
}
if (getScope().equals("session")) {
setScope(config.getScope());
}
if (getSuffix() == null) {
setSuffix(config.getSuffix());
}
if (getType() == null) {
setType(config.getType());
}
if (!getUnknown()) {
setUnknown(config.getUnknown());
}
if (!validateSet) {
setValidate(config.getValidate());
}
inheritExceptionHandlers(config);
inheritForwards(config);
inheritProperties(config);
}
/**
* <p>Inherit configuration information from the ActionConfig that this
* instance is extending. This method verifies that any action config
* object that it inherits from has also had its processExtends() method
* called.</p>
*
* @param moduleConfig The {@link ModuleConfig} that this bean is from.
* @see #inheritFrom(ActionConfig)
*/
public void processExtends(ModuleConfig moduleConfig)
throws ClassNotFoundException, IllegalAccessException,
InstantiationException, InvocationTargetException {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
String ancestorPath = getExtends();
if ((!extensionProcessed) && (ancestorPath != null)) {
ActionConfig baseConfig =
moduleConfig.findActionConfig(ancestorPath);
if (baseConfig == null) {
throw new NullPointerException("Unable to find "
+ "action for '" + ancestorPath + "' to extend.");
}
// Check against circular inheritance and make sure the base
// config's own extends has been processed already
if (checkCircularInheritance(moduleConfig)) {
throw new IllegalArgumentException(
"Circular inheritance detected for action " + getPath());
}
// Make sure the ancestor's own extension has been processed.
if (!baseConfig.isExtensionProcessed()) {
baseConfig.processExtends(moduleConfig);
}
// Copy values from the base config
inheritFrom(baseConfig);
}
extensionProcessed = true;
}
/**
* <p> Remove the specified exception configuration instance. </p>
*
* @param config ExceptionConfig instance to be removed
* @throws IllegalStateException if this module configuration has been
* frozen
*/
public void removeExceptionConfig(ExceptionConfig config) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
exceptions.remove(config.getType());
}
/**
* <p> Remove the specified forward configuration instance. </p>
*
* @param config ForwardConfig instance to be removed
* @throws IllegalStateException if this module configuration has been
* frozen
*/
public void removeForwardConfig(ForwardConfig config) {
if (configured) {
throw new IllegalStateException("Configuration is frozen");
}
forwards.remove(config.getName());
}
/**
* <p> Return a String representation of this object. </p>
*/
public String toString() {
StringBuffer sb = new StringBuffer("ActionConfig[");
sb.append("cancellable=");
sb.append(cancellable);
sb.append(",path=");
sb.append(path);
sb.append(",validate=");
sb.append(validate);
if (actionId != null) {
sb.append(",actionId=");
sb.append(actionId);
}
if (attribute != null) {
sb.append(",attribute=");
sb.append(attribute);
}
if (catalog != null) {
sb.append(",catalog=");
sb.append(catalog);
}
if (command != null) {
sb.append(",command=");
sb.append(command);
}
if (inherit != null) {
sb.append(",extends=");
sb.append(inherit);
}
if (forward != null) {
sb.append(",forward=");
sb.append(forward);
}
if (include != null) {
sb.append(",include=");
sb.append(include);
}
if (input != null) {
sb.append(",input=");
sb.append(input);
}
if (multipartClass != null) {
sb.append(",multipartClass=");
sb.append(multipartClass);
}
if (name != null) {
sb.append(",name=");
sb.append(name);
}
if (parameter != null) {
sb.append(",parameter=");
sb.append(parameter);
}
if (prefix != null) {
sb.append(",prefix=");
sb.append(prefix);
}
if (roles != null) {
sb.append(",roles=");
sb.append(roles);
}
if (scope != null) {
sb.append(",scope=");
sb.append(scope);
}
if (suffix != null) {
sb.append(",suffix=");
sb.append(suffix);
}
if (type != null) {
sb.append(",type=");
sb.append(type);
}
return (sb.toString());
}
}