package org.argeo.slc.core.execution.generator;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.slc.SlcException;
import org.argeo.slc.core.execution.DefaultExecutionSpec;
import org.argeo.slc.execution.ExecutionContext;
import org.argeo.slc.execution.ExecutionFlow;
import org.argeo.slc.execution.ExecutionSpec;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* Execution Flow calling a list of Runnable
(identified by their bean
* name in the Spring Application Context) after configuring the Execution
* context and a Map potentially shared by the called Runnable
*
*/
public class RunnableCallFlow implements ExecutionFlow, ApplicationContextAware {
private final static Log log = LogFactory.getLog(RunnableCallFlow.class);
/**
* Key in the execution context for the index of the call (e.g. 0
* for the first runnable called, ...)
*/
public final static String VAR_CALL_INDEX = "slcVar.runnableCallFlow.callIndex";
/**
* Name of the flow. Also bean name
*/
private String name;
/**
* Path of the flow
*/
private String path;
/**
* Whether an exception in a Runnable
shall
* stop the execution of the flow
*/
private Boolean failOnError = true;
/**
* List of Runnable
to call, with bean name, execution variables and
* context values
*/
private List runnableCalls;
/**
* Map potentially referenced by called flows. Updated with
* the context values of a Runnable before calling it.
*/
private Map sharedContextValuesMap;
/**
* ExecutionSpec of the flow. Does not contain any
* attribute.
*/
private ExecutionSpec executionSpec = new DefaultExecutionSpec();
/**
* Reference to the ExecutionContext
*/
private ExecutionContext executionContext;
/**
* Reference to the Spring ApplicationContext
.
* Set via setApplicationContext
, the class implementing
* ApplicationContextAware
*/
private ApplicationContext applicationContext;
/**
* Runs a Runnable
after configuring the Execution Context
* and sharedContextValuesMap
* @param runnable the Runnable
to call
* @param executionVariables the variables to add to the ExecutionContext
* @param contextValues the variables to add to sharedContextValuesMap
* @param callIndex index of the call (0 for the first called Runnable
)
* set as variable of the ExecutionContext
*/
private void run(Runnable runnable, Map executionVariables, Map contextValues, int callIndex) {
// add all variables to the Execution Context
for(Map.Entry entry : executionVariables.entrySet()) {
executionContext.setVariable(entry.getKey(), entry.getValue());
}
// add call Index Variable
executionContext.setVariable(VAR_CALL_INDEX, callIndex);
// clear sharedContextValues and add all values of contextValues
if(sharedContextValuesMap != null) {
sharedContextValuesMap.clear();
sharedContextValuesMap.putAll(contextValues);
}
// then run the runnable
runnable.run();
}
/**
* Executes the flow.
* For each RunnableCall
, the corresponding flow
* is retrieved from the Spring Application Context, the
* ExecutionContext
and sharedContextValuesMap
* are configured and the Runnable
is called.
*/
public void run() {
if (applicationContext == null) {
throw new SlcException("No ApplicationContext defined");
}
try {
for(int callIndex = 0; callIndex < runnableCalls.size(); ++callIndex) {
RunnableCall runnableCall = runnableCalls.get(callIndex);
Object bean = applicationContext.getBean(runnableCall.getBeanName(), Runnable.class);
if(log.isDebugEnabled())
log.debug("Running flow '" + runnableCall.getBeanName() + "'");
run((Runnable)bean, runnableCall.getExecutionVariables(), runnableCall.getContextValues(), callIndex);
}
} catch (RuntimeException e) {
if (failOnError)
throw e;
else {
log.error("Execution flow failed,"
+ " but process did not fail"
+ " because failOnError property"
+ " is set to false: " + e);
if (log.isTraceEnabled())
e.printStackTrace();
}
}
}
public ExecutionSpec getExecutionSpec() {
return executionSpec;
}
public String getName() {
return name;
}
public Object getParameter(String key) {
throw new SlcException("RunnableCallFlow have no parameters");
}
public String getPath() {
return path;
}
public Boolean isSetAsParameter(String key) {
// The ExecutionSpec having no attribute,
// always return false
return false;
}
public void setName(String name) {
this.name = name;
}
public void setPath(String path) {
this.path = path;
}
public void setExecutionContext(ExecutionContext executionContext) {
this.executionContext = executionContext;
}
public void setRunnableCalls(List runnableCalls) {
this.runnableCalls = runnableCalls;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public void setSharedContextValuesMap(Map contextValues) {
this.sharedContextValuesMap = contextValues;
}
public void setFailOnError(Boolean failOnError) {
this.failOnError = failOnError;
}
}