package org.g4studio.core.mvc.xstruts.chain.commands.generic;
import java.lang.reflect.InvocationTargetException;
import org.apache.commons.beanutils.ConstructorUtils;
import org.apache.commons.chain.Catalog;
import org.apache.commons.chain.CatalogFactory;
import org.apache.commons.chain.Command;
import org.apache.commons.chain.Context;
import org.apache.commons.chain.Filter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.g4studio.core.mvc.xstruts.chain.commands.util.ClassUtils;
/**
* <p>
* Variant on chain LookupCommand which can optionally wrap the context it
* passes to the looked up command in an alternative class.
* </p>
*/
public class WrappingLookupCommand implements Filter {
/**
* Provide Commons Logging instance for this class.
*/
private static final Log LOG = LogFactory.getLog(WrappingLookupCommand.class);
// ------------------------------------------------------ Instance Variables
/**
* <p>
* Field for property.
* </p>
*/
private String catalogName = null;
/**
* <p>
* Field for property.
* </p>
*/
private String name = null;
/**
* <p>
* Field for property.
* </p>
*/
private String nameKey = null;
/**
* <p>
* Field for property.
* </p>
*/
private String wrapperClassName = null;
/**
* <p>
* Field for property.
* </p>
*/
private boolean optional = false;
/**
* <p>
* Zero-argument constructor.
* </p>
*/
public WrappingLookupCommand() {
catalogName = null;
name = null;
nameKey = null;
optional = false;
}
/**
* <p>
* Return CatalogName property.
* </p>
*
* @return Value of CatalogName property.
*/
public String getCatalogName() {
return catalogName;
}
/**
* <p>
* Set CatalogName property.
* </p>
*
* @param catalogName
* New value for CatalogName
*/
public void setCatalogName(String catalogName) {
this.catalogName = catalogName;
}
/**
* <p>
* Retrieve Name property.
* </p>
*
* @return Value of Name property
*/
public String getName() {
return name;
}
/**
* <p>
* Set Name property.
* </p>
*
* @param name
* New value for Name
*/
public void setName(String name) {
this.name = name;
}
/**
* <p>
* Return NameKey property.
* </p>
*
* @return Value of NameKey property.
*/
public String getNameKey() {
return nameKey;
}
/**
* <p>
* Set NameKey property.
* </p>
*
* @param nameKey
* New value for NameKey
*/
public void setNameKey(String nameKey) {
this.nameKey = nameKey;
}
/**
* <p>
* Test Optional property.
* </p>
*
* @return TRUE if Optional is TRUE.
*/
public boolean isOptional() {
return optional;
}
/**
* <p>
* Set Optional property.
* </p>
*
* @param optional
* New value for Optional
*/
public void setOptional(boolean optional) {
this.optional = optional;
}
/**
* <p>
* Return the WrapperClass property.
* </p>
*
* @return The WrapperClass property
*/
public String getWrapperClassName() {
return wrapperClassName;
}
/**
* <p>
* Set WrappClassName property.
* </p>
*
* @param wrapperClassName
* The name of a WrapperClass
*/
public void setWrapperClassName(String wrapperClassName) {
this.wrapperClassName = wrapperClassName;
}
/**
* <p>
* Invoke the Command for a Context, returning TRUE if processing should
* halt.
* </p>
*
* @param context
* Our ActionContext
* @return TRUE if processing should halt
* @throws Exception
* On any error
*/
public boolean execute(Context context) throws Exception {
if (LOG.isTraceEnabled()) {
LOG.trace("execute [" + this + "]");
}
Command command = getCommand(context);
if (command != null) {
return command.execute(getContext(context));
} else {
return false;
}
}
/**
* <p>
* Process the Exception for any Command that is a filter.
* </p>
*
* @param context
* Our ActionContext
* @param exception
* The Exception thrown by another Comamnd in a Chain
* @return TRUE if there is a Filter to process
*/
public boolean postprocess(Context context, Exception exception) {
Command command = getCommand(context);
if ((command != null) && (command instanceof Filter)) {
try {
return ((Filter) command).postprocess(getContext(context), exception);
} catch (NoSuchMethodException ex) {
LOG.error("Error wrapping context in postprocess", ex);
} catch (IllegalAccessException ex) {
LOG.error("Error wrapping context in postprocess", ex);
} catch (InvocationTargetException ex) {
LOG.error("Error wrapping context in postprocess", ex);
} catch (InstantiationException ex) {
LOG.error("Error wrapping context in postprocess", ex);
} catch (ClassNotFoundException ex) {
LOG.error("Error wrapping context in postprocess", ex);
}
}
return false;
}
/**
* <p>
* Return the Command to process for this Context.
* </p>
*
* @param context
* The Context we are processing
* @return The Command to process for this Context
*/
protected Command getCommand(Context context) {
CatalogFactory catalogFactory = CatalogFactory.getInstance();
String catalogName = getCatalogName();
Catalog catalog;
if (catalogName == null) {
catalog = catalogFactory.getCatalog();
catalogName = "{default}"; // for debugging purposes
} else {
catalog = catalogFactory.getCatalog(catalogName);
}
if (catalog == null) {
throw new IllegalArgumentException("Cannot find catalog '" + catalogName + "'");
}
Command command;
String name = getName();
if (name == null) {
name = (String) context.get(getNameKey());
}
if (name != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Lookup command " + name + " in catalog " + catalogName);
}
command = catalog.getCommand(name);
if (LOG.isDebugEnabled()) {
LOG.debug("Found command " + command + ";" + " optional: " + isOptional());
}
if ((command == null) && !isOptional()) {
throw new IllegalArgumentException("Cannot find command " + "'" + name + "' in catalog '" + catalogName
+ "'");
} else {
return command;
}
} else {
throw new IllegalArgumentException("No command name");
}
}
/**
* <p>
* If the wrapperClassName property is not null, return a Context of the
* type specified by wrapperClassName, instantiated using a single-arg
* constructor which takes the context passed as an argument to this method.
* </p>
*
* <p>
* This method throws an exception if the wrapperClass cannot be found, or
* if there are any errors instantiating the wrapping context.
* </p>
*
* @param context
* Context we are processing
* @return Context wrapper
* @throws ClassNotFoundException
* On failed instantiation
* @throws InstantiationException
* On failed instantiation
* @throws InvocationTargetException
* On failed instantiation
* @throws IllegalAccessException
* On failed instantiation
* @throws NoSuchMethodException
* On failed instantiation
*/
protected Context getContext(Context context) throws ClassNotFoundException, InstantiationException,
InvocationTargetException, IllegalAccessException, NoSuchMethodException {
if (wrapperClassName == null) {
if (LOG.isDebugEnabled()) {
LOG.debug("No defined wrapper class; " + "returning original context.");
}
return context;
}
if (LOG.isDebugEnabled()) {
LOG.debug("Looking for wrapper class: " + wrapperClassName);
}
Class wrapperClass = ClassUtils.getApplicationClass(wrapperClassName);
if (LOG.isDebugEnabled()) {
LOG.debug("Instantiating wrapper class");
}
return (Context) ConstructorUtils.invokeConstructor(wrapperClass, new Object[] { context });
}
}