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