package org.marketcetera.strategy;
import static org.marketcetera.strategy.Status.RUNNING;
import static org.marketcetera.strategy.Status.STARTING;
import static org.marketcetera.strategy.Status.STOPPED;
import org.marketcetera.core.ClassVersion;
import org.marketcetera.event.impl.LogEventBuilder;
import org.marketcetera.util.log.I18NBoundMessage1P;
import org.marketcetera.util.log.SLF4JLoggerProxy;
/* $License$ */
/**
* Executes a given {@link Strategy}.
*
* @author <a href="mailto:colin@marketcetera.com">Colin DuPlantis</a>
* @version $Id: AbstractExecutor.java 16154 2012-07-14 16:34:05Z colin $
* @since 1.0.0
*/
@ClassVersion("$Id: AbstractExecutor.java 16154 2012-07-14 16:34:05Z colin $")
abstract class AbstractExecutor
implements Executor, Messages
{
/* (non-Javadoc)
* @see org.marketcetera.strategy.Executor#start()
*/
@Override
public final synchronized RunningStrategy start()
throws Exception
{
String script = getStrategy().getScript();
String processedScript = preprocess(script);
engine = getExecutionEngine();
engine.prepare(getStrategy(),
processedScript);
Object objectReturned = engine.start();
if(objectReturned == null) {
StrategyModule.log(LogEventBuilder.error().withMessage(STRATEGY_COMPILATION_NULL_RESULT,
String.valueOf(getStrategy())).create(),
getStrategy());
throw new StrategyException(new I18NBoundMessage1P(STRATEGY_COMPILATION_NULL_RESULT,
getStrategy().toString()));
}
if(objectReturned instanceof RunningStrategy) {
final RunningStrategy runningStrategy = (RunningStrategy)objectReturned;
// assertions can be disabled, in which case, a CCE will be thrown on the following line. In either case,
// this error is a development-time error and should not happen in the wild. This error is, in effect,
// a shout-out that the design of strategy needs to change. If, in the future, someone decides to create
// a strategy subclass that is not an instance of AbstractRunningStrategy, the whole approach needs to be
// re-thought.
assert(runningStrategy instanceof AbstractRunningStrategy);
assert(getStrategy() instanceof StrategyImpl);
AbstractRunningStrategy abstractRunningStrategy = (AbstractRunningStrategy)runningStrategy;
final StrategyImpl enclosingStrategy = (StrategyImpl)getStrategy();
// make the parameters available to the strategy
abstractRunningStrategy.setStrategy(getStrategy());
this.runningStrategy = runningStrategy;
enclosingStrategy.setRunningStrategy(runningStrategy);
// activate the strategy by causing its "onStart" method to be invoked.
// note that any status changes that result from execution of the start method need to be marked within
// the following loop.
try {
SLF4JLoggerProxy.debug(AbstractExecutor.class,
"{} start job beginning", //$NON-NLS-1$
getStrategy());
enclosingStrategy.setStatus(STARTING);
abstractRunningStrategy.start();
runningStrategy.onStart();
enclosingStrategy.setStatus(RUNNING);
return runningStrategy;
} catch (Exception e) {
// this means that the "onStart" method was never completed so the strategy never started
// this will cause a moduleCreationError in StrategyModule, which is what we want
StrategyModule.log(LogEventBuilder.error().withMessage(RUNTIME_ERROR,
getStrategy().toString(),
translateMethodName("onStart"), //$NON-NLS-1$
interpretRuntimeException(e))
.withException(e).create(),
getStrategy());
throw e;
}
} else {
StrategyModule.log(LogEventBuilder.error().withMessage(NO_STRATEGY_CLASS).create(),
getStrategy());
throw new StrategyException(NO_STRATEGY_CLASS);
}
}
/* (non-Javadoc)
* @see org.marketcetera.strategy.Executor#stop()
*/
@Override
public final synchronized void stop()
throws Exception
{
assert(runningStrategy != null);
assert(runningStrategy instanceof AbstractRunningStrategy);
assert(getStrategy() instanceof StrategyImpl);
AbstractRunningStrategy abstractRunningStrategy = (AbstractRunningStrategy)runningStrategy;
abstractRunningStrategy.stop();
final StrategyImpl enclosingStrategy = (StrategyImpl)getStrategy();
try {
SLF4JLoggerProxy.debug(AbstractExecutor.class,
"{} stop job beginning", //$NON-NLS-1$
getStrategy());
runningStrategy.onStop();
enclosingStrategy.setStatus(STOPPED);
} catch (Exception e) {
StrategyModule.log(LogEventBuilder.error().withMessage(RUNTIME_ERROR,
String.valueOf(getStrategy()),
translateMethodName("onStop"), //$NON-NLS-1$
interpretRuntimeException(e))
.withException(e).create(),
getStrategy());
throw e;
}
engine.stop();
}
/**
* Get the strategy value.
*
* @return a <code>Strategy</code> value
*/
final Strategy getStrategy()
{
return strategy;
}
/**
* Prepares the script to be executed.
*
* <p>Any work that needs to be done on the script before it can be executed is done here.
*
* @param inScript a <code>String</code> value containing the strategy script
* @return a <code>String</code> value containing the processed strategy script
* @throws StrategyException
*/
protected abstract String preprocess(String inScript)
throws StrategyException;
/**
* Gets the <code>ExecutionEngine</code> used to execute the strategy script.
*
* @return an <code>ExecutionEngine</code> value
* @throws StrategyException if an <code>ExecutionEngine</code> cannot be created
*/
protected abstract ExecutionEngine getExecutionEngine()
throws StrategyException;
/**
* Create a new ExecutorBase instance.
*
* @param inStrategy a <code>Strategy</code> value
*/
protected AbstractExecutor(Strategy inStrategy)
{
strategy = inStrategy;
}
/**
* the underlying strategy object
*/
private final Strategy strategy;
/**
* the object that executes the processed strategy
*/
private ExecutionEngine engine;
/**
* the object returned from the execution engine that represents that running strategy
*/
private RunningStrategy runningStrategy;
}