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; } }