]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/DefaultExecutionFlow.java
Prepare next development cycle
[gpl/argeo-slc.git] / runtime / DefaultExecutionFlow.java
1 package org.argeo.slc.runtime;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Map;
8
9 import org.apache.commons.logging.Log;
10 import org.apache.commons.logging.LogFactory;
11 import org.argeo.slc.SlcException;
12 import org.argeo.slc.execution.ExecutionContext;
13 import org.argeo.slc.execution.ExecutionFlow;
14 import org.argeo.slc.execution.ExecutionSpec;
15 import org.argeo.slc.execution.ExecutionSpecAttribute;
16
17 /** Default implementation of an execution flow. */
18 public class DefaultExecutionFlow implements ExecutionFlow {
19 private final static Log log = LogFactory.getLog(DefaultExecutionFlow.class);
20
21 private final ExecutionSpec executionSpec;
22 private String name = null;
23 private Map<String, Object> parameters = new HashMap<String, Object>();
24 private List<Runnable> executables = new ArrayList<Runnable>();
25
26 private String path;
27
28 private Boolean failOnError = true;
29
30 // Only needed if stacked execution flows are used
31 private ExecutionContext executionContext = null;
32
33 public DefaultExecutionFlow() {
34 this.executionSpec = new DefaultExecutionSpec();
35 }
36
37 public DefaultExecutionFlow(ExecutionSpec executionSpec) {
38 this.executionSpec = executionSpec;
39 }
40
41 public DefaultExecutionFlow(ExecutionSpec executionSpec, Map<String, Object> parameters) {
42 // be sure to have an execution spec
43 this.executionSpec = (executionSpec == null) ? new DefaultExecutionSpec() : executionSpec;
44
45 // only parameters contained in the executionSpec can be set
46 for (String parameter : parameters.keySet()) {
47 if (!executionSpec.getAttributes().containsKey(parameter)) {
48 throw new SlcException("Parameter " + parameter + " is not defined in the ExecutionSpec");
49 }
50 }
51
52 // set the parameters
53 this.parameters.putAll(parameters);
54
55 // check that all the required parameters are defined
56 // MapBindingResult errors = new MapBindingResult(parameters, "execution#"
57 // + getName());
58 Map<String, String> errors = new HashMap<>();
59 for (String key : executionSpec.getAttributes().keySet()) {
60 ExecutionSpecAttribute attr = executionSpec.getAttributes().get(key);
61
62 if (attr.getIsImmutable() && !isSetAsParameter(key)) {
63 errors.put(key, "Immutable but not set");
64 break;
65 }
66
67 if (attr.getIsConstant() && !isSetAsParameter(key)) {
68 errors.put(key, "Constant but not set as parameter");
69 break;
70 }
71
72 if (attr.getIsHidden() && !isSetAsParameter(key)) {
73 errors.put(key, "Hidden but not set as parameter");
74 break;
75 }
76 }
77
78 if (!errors.isEmpty())
79 throw new SlcException("Could not prepare execution flow: " + errors.toString());
80
81 }
82
83 public void run() {
84 try {
85 for (Runnable executable : executables) {
86 if (Thread.interrupted()) {
87 log.error("Flow '" + getName() + "' killed before '" + executable + "'");
88 Thread.currentThread().interrupt();
89 return;
90 // throw new ThreadDeath();
91 }
92 this.doExecuteRunnable(executable);
93 }
94 } catch (RuntimeException e) {
95 if (Thread.interrupted()) {
96 log.error("Flow '" + getName() + "' killed while receiving an unrelated exception", e);
97 Thread.currentThread().interrupt();
98 return;
99 // throw new ThreadDeath();
100 }
101 if (failOnError)
102 throw e;
103 else {
104 log.error("Execution flow failed," + " but process did not fail" + " because failOnError property"
105 + " is set to false: " + e);
106 if (log.isTraceEnabled())
107 e.printStackTrace();
108 }
109 }
110 }
111
112 /**
113 * List sub-runnables that would be executed if run() method would be called.
114 */
115 public Iterator<Runnable> runnables() {
116 return executables.iterator();
117 }
118
119 /**
120 * If there is one and only one runnable wrapped return it, throw an exeception
121 * otherwise.
122 */
123 public Runnable getRunnable() {
124 if (executables.size() == 1)
125 return executables.get(0);
126 else
127 throw new SlcException("There are " + executables.size() + " runnables in flow " + getName());
128 }
129
130 public void doExecuteRunnable(Runnable runnable) {
131 try {
132 if (executionContext != null)
133 if (runnable instanceof ExecutionFlow)
134 executionContext.beforeFlow((ExecutionFlow) runnable);
135 runnable.run();
136 } finally {
137 if (executionContext != null)
138 if (runnable instanceof ExecutionFlow)
139 executionContext.afterFlow((ExecutionFlow) runnable);
140 }
141 }
142
143 public void init() throws Exception {
144 if (path == null) {
145 if (name.charAt(0) == '/') {
146 path = name.substring(0, name.lastIndexOf('/'));
147 }
148 }
149
150 if (path != null) {
151 for (Runnable executable : executables) {
152 if (executable instanceof DefaultExecutionFlow) {
153 // so we don't need to have DefaultExecutionFlow
154 // implementing StructureAware
155 // FIXME: probably has side effects
156 DefaultExecutionFlow flow = (DefaultExecutionFlow) executable;
157 String newPath = path + '/' + flow.getName();
158 flow.setPath(newPath);
159 log.warn(newPath + " was forcibly set on " + flow);
160 }
161 }
162 }
163 }
164
165 public void setName(String name) {
166 this.name = name;
167 }
168
169 public void setExecutables(List<Runnable> executables) {
170 this.executables = executables;
171 }
172
173 public void setParameters(Map<String, Object> attributes) {
174 this.parameters = attributes;
175 }
176
177 public String getName() {
178 return name;
179 }
180
181 public ExecutionSpec getExecutionSpec() {
182 return executionSpec;
183 }
184
185 public Object getParameter(String parameterName) {
186 // Verify that there is a spec attribute
187 ExecutionSpecAttribute specAttr = null;
188 if (executionSpec.getAttributes().containsKey(parameterName)) {
189 specAttr = executionSpec.getAttributes().get(parameterName);
190 } else {
191 throw new SlcException("Key " + parameterName + " is not defined in the specifications of " + toString());
192 }
193
194 if (parameters.containsKey(parameterName)) {
195 Object paramValue = parameters.get(parameterName);
196 return paramValue;
197 } else {
198 if (specAttr.getValue() != null) {
199 return specAttr.getValue();
200 }
201 }
202 throw new SlcException("Key " + parameterName + " is not set as parameter in " + toString());
203 }
204
205 public Boolean isSetAsParameter(String key) {
206 return parameters.containsKey(key) || (executionSpec.getAttributes().containsKey(key)
207 && executionSpec.getAttributes().get(key).getValue() != null);
208 }
209
210 @Override
211 public String toString() {
212 return new StringBuffer("Execution flow ").append(name).toString();
213 }
214
215 @Override
216 public boolean equals(Object obj) {
217 return ((ExecutionFlow) obj).getName().equals(name);
218 }
219
220 @Override
221 public int hashCode() {
222 return name.hashCode();
223 }
224
225 public String getPath() {
226 return path;
227 }
228
229 public void setPath(String path) {
230 this.path = path;
231 }
232
233 public Boolean getFailOnError() {
234 return failOnError;
235 }
236
237 public void setFailOnError(Boolean failOnError) {
238 this.failOnError = failOnError;
239 }
240
241 public void setExecutionContext(ExecutionContext executionContext) {
242 this.executionContext = executionContext;
243 }
244
245 }