/*
* Copyright (c) 2005, Rob Gordon.
*/
package org.oddjob.framework;
import java.beans.ExceptionListener;
import org.apache.commons.beanutils.DynaBean;
import org.oddjob.FailedToStopException;
import org.oddjob.arooa.life.ComponentPersistException;
import org.oddjob.images.IconHelper;
import org.oddjob.images.StateIcons;
import org.oddjob.persist.Persistable;
import org.oddjob.state.IsAnyState;
import org.oddjob.state.IsExecutable;
import org.oddjob.state.IsHardResetable;
import org.oddjob.state.IsSoftResetable;
import org.oddjob.state.IsStoppable;
import org.oddjob.state.ServiceState;
import org.oddjob.state.ServiceStateChanger;
import org.oddjob.state.ServiceStateHandler;
/**
* Wraps a Service object and adds state to it.
* <p>
*
* @author Rob Gordon.
*/
public class ServiceWrapper extends BaseWrapper
implements ComponentWrapper {
/** Handle state. */
private final ServiceStateHandler stateHandler;
/** Used to notify clients of an icon change. */
private final IconHelper iconHelper;
/** Perform state changes. */
private final ServiceStateChanger stateChanger;
private final ServiceAdaptor service;
private final Object wrapped;
private final DynaBean dynaBean;
private final Object proxy;
/**
* Create a new instance wrapping a service.
*
* @param service
* @param proxy
*/
public ServiceWrapper(ServiceAdaptor service, Object proxy) {
this.service = service;
this.proxy = proxy;
this.wrapped = service.getComponent();
this.dynaBean = new WrapDynaBean(wrapped);
stateHandler = new ServiceStateHandler(this);
iconHelper = new IconHelper(this,
StateIcons.iconFor(stateHandler.getState()));
stateChanger = new ServiceStateChanger(stateHandler, iconHelper,
new Persistable() {
@Override
public void persist() throws ComponentPersistException {
save();
}
});
}
@Override
protected ServiceStateHandler stateHandler() {
return stateHandler;
}
@Override
protected IconHelper iconHelper() {
return iconHelper;
}
protected ServiceStateChanger getStateChanger() {
return stateChanger;
}
public Object getWrapped() {
return wrapped;
}
protected DynaBean getDynaBean() {
return dynaBean;
}
protected Object getProxy() {
return proxy;
}
@Override
protected void save(Object compoonent) {
// Services don't persist. Maybe they should.
}
public void run() {
ComponentBoundry.push(loggerName(), wrapped);
try {
if (!stateHandler.waitToWhen(new IsExecutable(), new Runnable() {
public void run() {
getStateChanger().setState(ServiceState.STARTING);
}
})) {
return;
}
logger().info("Starting.");
try {
if (Thread.interrupted()) {
throw new InterruptedException(
"Service Thread interrupt flag set. " +
"Please ensure previous jobs clean up after " +
"themselves to guarantee consistent behaviour.");
}
service.acceptExceptionListener(new ExceptionListener() {
@Override
public void exceptionThrown(Exception e) {
exceptionFromComponent(e);
}
});
configure();
service.start();
logger().info("Started.");
stateHandler.waitToWhen(new IsAnyState(), new Runnable() {
public void run() {
getStateChanger().setState(ServiceState.STARTED);
}
});
}
catch (final Throwable t) {
logger().error("Exception starting service:", t);
stateHandler.waitToWhen(new IsAnyState(), new Runnable() {
public void run() {
getStateChanger().setStateException(t);
}
});
}
}
finally {
ComponentBoundry.pop();
}
}
/**
* Used by the exception handler callback.
*
* @param e
*/
protected void exceptionFromComponent(final Exception e) {
logger().error("Exception starting service:", e);
if (!stateHandler.waitToWhen(new IsStoppable(), new Runnable() {
public void run() {
getStateChanger().setStateException(e);
}
})) {
throw new IllegalStateException("Service has not started.");
}
}
protected void onStop() throws FailedToStopException {
ComponentBoundry.push(loggerName(), wrapped);
try {
service.stop();
stateHandler.waitToWhen(new IsAnyState(), new Runnable() {
public void run() {
getStateChanger().setState(ServiceState.STOPPED);
}
});
}
catch (Exception e) {
throw new FailedToStopException(service, e);
}
finally {
ComponentBoundry.pop();
}
}
/**
* Perform a soft reset on the job.
*/
public boolean softReset() {
ComponentBoundry.push(loggerName(), wrapped);
try {
return stateHandler.waitToWhen(new IsSoftResetable(), new Runnable() {
public void run() {
getStateChanger().setState(ServiceState.STARTABLE);
logger().info("Soft Reset complete.");
}
});
}
finally {
ComponentBoundry.pop();
}
}
/**
* Perform a hard reset on the job.
*/
public boolean hardReset() {
ComponentBoundry.push(loggerName(), wrapped);
try {
return stateHandler.waitToWhen(new IsHardResetable(), new Runnable() {
public void run() {
getStateChanger().setState(ServiceState.STARTABLE);
logger().info("Hard Reset complete.");
}
});
}
finally {
ComponentBoundry.pop();
}
}
/**
* Internal method to fire state.
*/
protected void fireDestroyedState() {
if (!stateHandler().waitToWhen(new IsAnyState(), new Runnable() {
public void run() {
stateHandler().setState(ServiceState.DESTROYED);
stateHandler().fireEvent();
}
})) {
throw new IllegalStateException("[" + ServiceWrapper.this + "] Failed set state DESTROYED");
}
logger().debug("[" + this + "] Destroyed.");
}
}