/*
* (c) Rob Gordon 2005
*/
package org.oddjob.framework;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaClass;
import org.apache.log4j.Logger;
import org.oddjob.Describeable;
import org.oddjob.FailedToStopException;
import org.oddjob.Reserved;
import org.oddjob.Resetable;
import org.oddjob.Stateful;
import org.oddjob.Stoppable;
import org.oddjob.arooa.ArooaConfigurationException;
import org.oddjob.arooa.ArooaSession;
import org.oddjob.arooa.convert.ArooaConversionException;
import org.oddjob.arooa.convert.ArooaConverter;
import org.oddjob.arooa.life.ComponentPersistException;
import org.oddjob.arooa.reflect.ArooaPropertyException;
import org.oddjob.arooa.reflect.BeanOverview;
import org.oddjob.arooa.reflect.PropertyAccessor;
import org.oddjob.describe.UniversalDescriber;
import org.oddjob.images.IconHelper;
import org.oddjob.logging.LogEnabled;
import org.oddjob.logging.LogHelper;
import org.oddjob.state.IsStoppable;
/**
* Base class for proxy creators.
*
*/
abstract public class BaseWrapper extends BaseComponent
implements Runnable, Stateful, Resetable, DynaBean, Stoppable,
LogEnabled, Describeable {
private transient Logger theLogger;
/**
* Return the object that is being proxied.
*
* @return The component being proxied.
*/
abstract protected Object getWrapped();
/**
* Sub classes must provide a dyna bean for properties.
*
* @return
*/
abstract protected DynaBean getDynaBean();
/**
* Subclass must provide the proxy.
*
* @return
*/
abstract protected Object getProxy();
/*
* (non-Javadoc)
* @see org.oddjob.framework.BaseComponent#logger()
*/
protected Logger logger() {
if (theLogger == null) {
String logger = LogHelper.getLogger(getWrapped());
if (logger == null) {
logger = LogHelper.uniqueLoggerName(getWrapped());
}
theLogger = Logger.getLogger(logger);
}
return theLogger;
}
/*
* (non-Javadoc)
* @see org.oddjob.logging.LogEnabled#loggerName()
*/
public String loggerName() {
return logger().getName();
}
/**
* Called by sub classes to configure the component.
*
* @throws ArooaConfigurationException
*/
protected void configure()
throws ArooaConfigurationException {
configure(getProxy());
}
protected void save() throws ComponentPersistException {
save(getProxy());
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object other) {
return other == getProxy();
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
return getWrapped().toString();
}
public boolean contains(String name, String key) {
return getDynaBean().contains(name, key);
}
public Object get(String name) {
return getDynaBean().get(name);
}
public Object get(String name, int index) {
return getDynaBean().get(name, index);
}
public Object get(String name, String key) {
return getDynaBean().get(name, key);
}
public DynaClass getDynaClass() {
return getDynaBean().getDynaClass();
}
public void remove(String name, String key) {
getDynaBean().remove(name, key);
}
public void set(String name, int index, Object value) {
getDynaBean().set(name, index, value);
}
public void set(String name, Object value) {
getDynaBean().set(name, value);
}
public void set(String name, String key, Object value) {
getDynaBean().set(name, key, value);
}
public final void stop() throws FailedToStopException {
stateHandler().assertAlive();
ComponentBoundry.push(loggerName(), this);
try {
final AtomicReference<String> icon = new AtomicReference<String>();
if (!stateHandler().waitToWhen(new IsStoppable(), new Runnable() {
public void run() {
logger().info("Stop requested.");
icon.set(iconHelper().currentId());
iconHelper().changeIcon(IconHelper.STOPPING);
}
})) {
return;
}
FailedToStopException failedToStopException = null;
try {
onStop();
new StopWait(this).run();
logger().info("Stopped.");
}
catch (RuntimeException e) {
failedToStopException = new FailedToStopException(this, e);
}
catch (FailedToStopException e) {
failedToStopException = e;
}
if (failedToStopException != null) {
stateHandler().waitToWhen(new IsStoppable(), new Runnable() {
public void run() {
iconHelper().changeIcon(icon.get());
}
});
throw failedToStopException;
}
}
finally {
ComponentBoundry.pop();
}
}
protected void onStop() throws FailedToStopException {}
/**
* Get the result. Use either the return value from the Callable or
* the result property if there is one.
* @return
* @throws ArooaConversionException
* @throws ArooaPropertyException
*/
protected int getResult(Object callableResult) throws ArooaPropertyException, ArooaConversionException {
ArooaSession session = getArooaSession();
if (session == null) {
// Must be running outside Oddjob from code.
return 0;
}
Integer result;
if (callableResult != null) {
result = session.getTools().getArooaConverter().convert(
callableResult, Integer.class);
}
else {
PropertyAccessor accessor = session.getTools().getPropertyAccessor();
BeanOverview overview = accessor.getBeanOverview(
getWrapped().getClass());
if (!overview.hasReadableProperty(
Reserved.RESULT_PROPERTY)) {
return 0;
}
ArooaConverter converter = session.getTools().getArooaConverter();
result = converter.convert(accessor.getProperty(
getWrapped(), Reserved.RESULT_PROPERTY),
Integer.class);
}
if (result == null) {
return 0;
}
return result.intValue();
}
/*
* (non-Javadoc)
* @see org.oddjob.Describeable#describe()
*/
@Override
public Map<String, String> describe() {
return new UniversalDescriber(getArooaSession()).describe(
getWrapped());
}
@Override
public void onDestroy() {
super.onDestroy();
try {
stop();
} catch (FailedToStopException e) {
logger().warn("Failed to stop during destroy.", e);
}
}
/**
* Helper class to find interfaces implemented by an object.
*
* @param object
*
* @return An array of the interface classes.
*/
public static Class<?>[] interfacesFor(Object object) {
List<Class<?>> results = new ArrayList<Class<?>>();
for (Class<?> cl = object.getClass(); cl != null; cl = cl.getSuperclass()) {
results.addAll(Arrays.asList((Class<?>[]) cl.getInterfaces()));
}
return (Class[]) results.toArray(new Class[results.size()]);
}
}