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