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