package org.oddjob.beanbus.mega;
import org.apache.log4j.Logger;
import org.oddjob.FailedToStopException;
import org.oddjob.Stateful;
import org.oddjob.Stoppable;
import org.oddjob.beanbus.AbstractBusConductor;
import org.oddjob.beanbus.BusConductor;
import org.oddjob.beanbus.BusCrashException;
import org.oddjob.beanbus.BusPhase;
import org.oddjob.state.State;
import org.oddjob.state.StateCondition;
import org.oddjob.state.StateConditions;
import org.oddjob.state.StateEvent;
import org.oddjob.state.StateListener;
/**
* Adapts a {@link Stateful} into a {@Link BusConductor}.
*
* @author rob
*
*/
public class StatefulBusConductorAdapter extends AbstractBusConductor
implements BusConductor {
private static final Logger logger =
Logger.getLogger(StatefulBusConductorAdapter.class);
// javacc via ant wont resolve FINISHED if it's in-lined
// No idea why!!!!
private final static StateCondition FINISHED = StateConditions.FINISHED;
private final Stateful stateful;
private volatile boolean started;
private volatile boolean crashed;
private final StateListener stateListener =
new StateListener() {
@Override
public void jobStateChange(StateEvent event) {
State state = event.getState();
if (state.isReady()) {
crashed = false;
}
else if (state.isStoppable() && !started) {
try {
fireBusStarting();
try {
fireTripBeginning();
} catch (BusCrashException e) {
fireBusCrashed(BusPhase.TRIP_BEGINNING, e);
crashed = true;
}
} catch (BusCrashException e) {
fireBusCrashed(BusPhase.BUS_STARTING, e);
crashed = true;
}
started = true;
}
else if (FINISHED.test(state) && started) {
if (!crashed) {
if (state.isException()) {
fireBusCrashed(BusPhase.BUS_RUNNING,
new BusCrashException(
"Stateful Conductor Exception",
event.getException()));
}
else {
try {
fireTripEnding();
try {
fireBusStopping();
} catch (BusCrashException e) {
fireBusCrashed(BusPhase.BUS_STOPPING, e);
}
} catch (BusCrashException e) {
fireBusCrashed(BusPhase.TRIP_ENDING, e);
}
}
}
fireBusTerminated();
started = false;
}
}
};
public StatefulBusConductorAdapter(Stateful stateful) {
this.stateful = stateful;
stateful.addStateListener(stateListener);
}
@Override
public void cleanBus() throws BusCrashException {
fireTripEnding();
fireTripBeginning();
}
@Override
public void requestBusStop() {
fireBusStopRequested(started);
if (stateful instanceof Stoppable) {
try {
((Stoppable) stateful).stop();
} catch (FailedToStopException e) {
logger.error("[" + stateful + "] Failed to stop.", e);
}
}
else {
logger.info("[" + stateful + "] is not stoppable, " +
"will need to wait for it to stop.");
}
}
/**
* Must be called to remove listener.
*/
public void close() {
stateful.removeStateListener(stateListener);
}
@Override
public String toString() {
return getClass().getSimpleName() + " for [" + stateful + "]";
}
}