]> git.argeo.org Git - gpl/argeo-slc.git/blob - legacy/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableCallFlow.java
Merge remote-tracking branch 'origin/master' into testing
[gpl/argeo-slc.git] / legacy / org.argeo.slc.spring / src / org / argeo / slc / core / execution / generator / RunnableCallFlow.java
1 package org.argeo.slc.core.execution.generator;
2
3 import java.util.ArrayList;
4 import java.util.Iterator;
5 import java.util.List;
6 import java.util.Map;
7
8 import org.apache.commons.logging.Log;
9 import org.apache.commons.logging.LogFactory;
10 import org.argeo.slc.SlcException;
11 import org.argeo.slc.core.execution.DefaultExecutionSpec;
12 import org.argeo.slc.execution.ExecutionContext;
13 import org.argeo.slc.execution.ExecutionFlow;
14 import org.argeo.slc.execution.ExecutionSpec;
15 import org.springframework.context.ApplicationContext;
16 import org.springframework.context.ApplicationContextAware;
17
18 /**
19 * Execution Flow calling a list of <code>Runnable</code> (identified by their
20 * bean name in the Spring Application Context) after configuring the Execution
21 * context and a Map potentially shared by the called <code>Runnable</code>
22 *
23 */
24 public class RunnableCallFlow implements ExecutionFlow, ApplicationContextAware {
25
26 private final static Log log = LogFactory.getLog(RunnableCallFlow.class);
27
28 /**
29 * Key in the execution context for the index of the call (e.g. 0 for the
30 * first runnable called, ...)
31 */
32 public final static String VAR_CALL_INDEX = "slcVar.runnableCallFlow.callIndex";
33
34 /**
35 * Name of the flow. Also bean name
36 */
37 private String name;
38
39 /**
40 * Path of the flow
41 */
42 private String path;
43
44 /**
45 * Whether an exception in a <code>Runnable</code> shall stop the execution
46 * of the flow
47 */
48 private Boolean failOnError = true;
49
50 /**
51 * List of <code>Runnable</code> to call, with bean name, execution
52 * variables and context values
53 */
54 private List<RunnableCall> runnableCalls;
55
56 /**
57 * Map potentially referenced by called flows. Updated with the context
58 * values of a Runnable before calling it.
59 */
60 private Map<String, Object> sharedContextValuesMap;
61
62 /**
63 * ExecutionSpec of the flow. Does not contain any attribute.
64 */
65 private ExecutionSpec executionSpec = new DefaultExecutionSpec();
66
67 /**
68 * Reference to the ExecutionContext
69 */
70 private ExecutionContext executionContext;
71
72 /**
73 * Reference to the Spring <code>ApplicationContext</code>. Set via
74 * <code>setApplicationContext</code>, the class implementing
75 * <code>ApplicationContextAware</code>
76 */
77 private ApplicationContext applicationContext;
78
79 /**
80 * Runs a <code>Runnable</code> after configuring the Execution Context and
81 * <code>sharedContextValuesMap</code>
82 *
83 * @param runnable
84 * the <code>Runnable</code> to call
85 * @param executionVariables
86 * the variables to add to the <code>ExecutionContext</code>
87 * @param contextValues
88 * the variables to add to <code>sharedContextValuesMap</code>
89 * @param callIndex
90 * index of the call (0 for the first called
91 * <code>Runnable</code>) set as variable of the
92 * <code>ExecutionContext</code>
93 */
94 private void run(Runnable runnable, Map<String, Object> executionVariables,
95 Map<String, Object> contextValues, int callIndex) {
96 // add all variables to the Execution Context
97 for (Map.Entry<String, Object> entry : executionVariables.entrySet()) {
98 executionContext.setVariable(entry.getKey(), entry.getValue());
99 }
100
101 // add call Index Variable
102 executionContext.setVariable(VAR_CALL_INDEX, callIndex);
103
104 // clear sharedContextValues and add all values of contextValues
105 if (sharedContextValuesMap != null) {
106 sharedContextValuesMap.clear();
107 sharedContextValuesMap.putAll(contextValues);
108 }
109
110 // then run the runnable
111 doExecuteRunnable(runnable);
112 }
113
114 public void doExecuteRunnable(Runnable runnable) {
115 runnable.run();
116 }
117
118 /**
119 * Executes the flow. For each <code>RunnableCall</code>, the corresponding
120 * flow is retrieved from the Spring Application Context, the
121 * <code>ExecutionContext</code> and <code>sharedContextValuesMap</code> are
122 * configured and the <code>Runnable</code> is called.
123 */
124 public void run() {
125 if (applicationContext == null) {
126 throw new SlcException("No ApplicationContext defined");
127 }
128
129 try {
130 for (int callIndex = 0; callIndex < runnableCalls.size(); ++callIndex) {
131 RunnableCall runnableCall = runnableCalls.get(callIndex);
132 Object bean = applicationContext.getBean(
133 runnableCall.getBeanName(), Runnable.class);
134 if (log.isDebugEnabled())
135 log.debug("Running flow '" + runnableCall.getBeanName()
136 + "'");
137 run((Runnable) bean, runnableCall.getExecutionVariables(),
138 runnableCall.getContextValues(), callIndex);
139 }
140 } catch (RuntimeException e) {
141 if (failOnError)
142 throw e;
143 else {
144 log.error("Execution flow failed,"
145 + " but process did not fail"
146 + " because failOnError property"
147 + " is set to false: " + e);
148 if (log.isTraceEnabled())
149 e.printStackTrace();
150 }
151 }
152 }
153
154 public Iterator<Runnable> runnables() {
155 List<Runnable> runnables = new ArrayList<Runnable>();
156 for (int callIndex = 0; callIndex < runnableCalls.size(); ++callIndex) {
157 RunnableCall runnableCall = runnableCalls.get(callIndex);
158 Object bean = applicationContext.getBean(
159 runnableCall.getBeanName(), Runnable.class);
160 runnables.add((Runnable) bean);
161 }
162 return runnables.iterator();
163 }
164
165 public Runnable getRunnable() {
166 if (runnableCalls.size() == 1)
167 return runnables().next();
168 else
169 throw new SlcException("There are " + runnableCalls.size()
170 + " runnables in flow " + getName());
171 }
172
173 @Override
174 public String toString() {
175 return new StringBuffer("RunnableCallFlow ").append(name).toString();
176 }
177
178 public ExecutionSpec getExecutionSpec() {
179 return executionSpec;
180 }
181
182 public String getName() {
183 return name;
184 }
185
186 public Object getParameter(String key) {
187 throw new SlcException("RunnableCallFlow have no parameters");
188 }
189
190 public String getPath() {
191 return path;
192 }
193
194 public Boolean isSetAsParameter(String key) {
195 // The ExecutionSpec having no attribute,
196 // always return false
197 return false;
198 }
199
200 public void setName(String name) {
201 this.name = name;
202 }
203
204 public void setPath(String path) {
205 this.path = path;
206 }
207
208 public void setExecutionContext(ExecutionContext executionContext) {
209 this.executionContext = executionContext;
210 }
211
212 public void setRunnableCalls(List<RunnableCall> runnableCalls) {
213 this.runnableCalls = runnableCalls;
214 }
215
216 public void setApplicationContext(ApplicationContext applicationContext) {
217 this.applicationContext = applicationContext;
218 }
219
220 public void setSharedContextValuesMap(Map<String, Object> contextValues) {
221 this.sharedContextValuesMap = contextValues;
222 }
223
224 public void setFailOnError(Boolean failOnError) {
225 this.failOnError = failOnError;
226 }
227
228 }