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