]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlow.java
Document and improve execution model
[gpl/argeo-slc.git] / runtime / org.argeo.slc.core / src / main / java / org / argeo / slc / core / execution / DefaultExecutionFlow.java
1 /*
2 * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
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
17 package org.argeo.slc.core.execution;
18
19 import java.util.ArrayList;
20 import java.util.HashMap;
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.core.structure.tree.TreeSPath;
28 import org.argeo.slc.core.structure.tree.TreeSRegistry;
29 import org.argeo.slc.execution.ExecutionFlow;
30 import org.argeo.slc.execution.ExecutionSpec;
31 import org.argeo.slc.execution.ExecutionSpecAttribute;
32 import org.argeo.slc.structure.StructureAware;
33 import org.argeo.slc.structure.StructureRegistry;
34 import org.springframework.aop.scope.ScopedObject;
35 import org.springframework.beans.factory.BeanNameAware;
36 import org.springframework.beans.factory.InitializingBean;
37 import org.springframework.validation.MapBindingResult;
38
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.getIsParameter() && !isSetAsParameter(key)) {
87 errors.rejectValue(key, "Parameter not set");
88 break;
89 }
90
91 if (attr.getIsFrozen() && !isSetAsParameter(key)) {
92 errors.rejectValue(key, "Frozen 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 this.doExecuteRunnable(executable);
112 }
113 } catch (RuntimeException e) {
114 if (failOnError)
115 throw e;
116 else {
117 log.error("Execution flow failed,"
118 + " but process did not fail"
119 + " because failOnError property"
120 + " is set to false: " + e);
121 if (log.isTraceEnabled())
122 e.printStackTrace();
123 }
124 }
125 }
126
127 public void doExecuteRunnable(Runnable runnable) {
128 runnable.run();
129 }
130
131 @SuppressWarnings(value = { "unchecked" })
132 public void afterPropertiesSet() throws Exception {
133 if (path == null) {
134 if (name.charAt(0) == '/') {
135 path = name.substring(0, name.lastIndexOf('/'));
136 }
137 }
138
139 if (path != null) {
140 for (Runnable executable : executables) {
141 if (executable instanceof StructureAware
142 && !(executable instanceof ScopedObject)) {
143 ((StructureAware<TreeSPath>) executable).notifyCurrentPath(
144 registry, new TreeSPath(path));
145 } else if (executable instanceof DefaultExecutionFlow) {
146 // so we don't need to have DefaultExecutionFlow
147 // implementing StructureAware
148 // FIXME: probably has side effects
149 DefaultExecutionFlow flow = (DefaultExecutionFlow) executable;
150 String newPath = path + '/' + flow.getName();
151 flow.setPath(newPath);
152 log.warn(newPath + " was forcibly set on " + flow);
153 }
154 }
155 }
156 }
157
158 public void setBeanName(String name) {
159 this.name = name;
160 }
161
162 public void setExecutables(List<Runnable> executables) {
163 this.executables = executables;
164 }
165
166 public void setParameters(Map<String, Object> attributes) {
167 this.parameters = attributes;
168 }
169
170 public String getName() {
171 return name;
172 }
173
174 public ExecutionSpec getExecutionSpec() {
175 return executionSpec;
176 }
177
178 public Object getParameter(String parameterName) {
179 // Verify that there is a spec attribute
180 ExecutionSpecAttribute specAttr = null;
181 if (executionSpec.getAttributes().containsKey(parameterName)) {
182 specAttr = executionSpec.getAttributes().get(parameterName);
183 } else {
184 throw new SlcException("Key " + parameterName
185 + " is not defined in the specifications of " + toString());
186 }
187
188 if (parameters.containsKey(parameterName)) {
189 Object paramValue = parameters.get(parameterName);
190 return paramValue;
191 } else {
192 if (specAttr.getValue() != null) {
193 return specAttr.getValue();
194 }
195 }
196 throw new SlcException("Key " + parameterName
197 + " is not set as parameter in " + toString());
198 }
199
200 public Boolean isSetAsParameter(String key) {
201 return parameters.containsKey(key)
202 || (executionSpec.getAttributes().containsKey(key) && executionSpec
203 .getAttributes().get(key).getValue() != null);
204 }
205
206 @Override
207 public String toString() {
208 return new StringBuffer("Execution flow ").append(name).toString();
209 }
210
211 @Override
212 public boolean equals(Object obj) {
213 return ((ExecutionFlow) obj).getName().equals(name);
214 }
215
216 @Override
217 public int hashCode() {
218 return name.hashCode();
219 }
220
221 public String getPath() {
222 return path;
223 }
224
225 public void setPath(String path) {
226 this.path = path;
227 }
228
229 public void setRegistry(StructureRegistry<TreeSPath> registry) {
230 this.registry = registry;
231 }
232
233 public Boolean getFailOnError() {
234 return failOnError;
235 }
236
237 public void setFailOnError(Boolean failOnError) {
238 this.failOnError = failOnError;
239 }
240
241 }