2 * Copyright (C) 2007-2012 Argeo GmbH
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.slc
.core
.execution
;
18 import java
.util
.ArrayList
;
19 import java
.util
.HashMap
;
20 import java
.util
.Iterator
;
21 import java
.util
.List
;
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
.ExecutionContext
;
28 import org
.argeo
.slc
.execution
.ExecutionFlow
;
29 import org
.argeo
.slc
.execution
.ExecutionSpec
;
30 import org
.argeo
.slc
.execution
.ExecutionSpecAttribute
;
31 import org
.springframework
.beans
.factory
.BeanNameAware
;
32 import org
.springframework
.beans
.factory
.InitializingBean
;
33 import org
.springframework
.validation
.MapBindingResult
;
35 /** Default implementation of an execution flow. */
36 public class DefaultExecutionFlow
implements ExecutionFlow
, InitializingBean
,
38 private final static Log log
= LogFactory
39 .getLog(DefaultExecutionFlow
.class);
41 private final ExecutionSpec executionSpec
;
42 private String name
= null;
43 private Map
<String
, Object
> parameters
= new HashMap
<String
, Object
>();
44 private List
<Runnable
> executables
= new ArrayList
<Runnable
>();
48 private Boolean failOnError
= true;
50 // Only needed if stacked execution flows are used
51 private ExecutionContext executionContext
= null;
53 public DefaultExecutionFlow() {
54 this.executionSpec
= new DefaultExecutionSpec();
57 public DefaultExecutionFlow(ExecutionSpec executionSpec
) {
58 this.executionSpec
= executionSpec
;
61 public DefaultExecutionFlow(ExecutionSpec executionSpec
,
62 Map
<String
, Object
> parameters
) {
63 // be sure to have an execution spec
64 this.executionSpec
= (executionSpec
== null) ?
new DefaultExecutionSpec()
67 // only parameters contained in the executionSpec can be set
68 for (String parameter
: parameters
.keySet()) {
69 if (!executionSpec
.getAttributes().containsKey(parameter
)) {
70 throw new SlcException("Parameter " + parameter
71 + " is not defined in the ExecutionSpec");
76 this.parameters
.putAll(parameters
);
78 // check that all the required parameters are defined
79 MapBindingResult errors
= new MapBindingResult(parameters
, "execution#"
81 for (String key
: executionSpec
.getAttributes().keySet()) {
82 ExecutionSpecAttribute attr
= executionSpec
.getAttributes()
85 if (attr
.getIsImmutable() && !isSetAsParameter(key
)) {
86 errors
.rejectValue(key
, "Immutable but not set");
90 if (attr
.getIsConstant() && !isSetAsParameter(key
)) {
91 errors
.rejectValue(key
, "Constant but not set as parameter");
95 if (attr
.getIsHidden() && !isSetAsParameter(key
)) {
96 errors
.rejectValue(key
, "Hidden but not set as parameter");
101 if (errors
.hasErrors())
102 throw new SlcException("Could not prepare execution flow: "
103 + errors
.toString());
109 for (Runnable executable
: executables
) {
110 if (Thread
.interrupted()) {
111 log
.error("Flow '" + getName() + "' killed before '"
113 Thread
.currentThread().interrupt();
115 // throw new ThreadDeath();
117 this.doExecuteRunnable(executable
);
119 } catch (RuntimeException e
) {
120 if (Thread
.interrupted()) {
121 log
.error("Flow '" + getName()
122 + "' killed while receiving an unrelated exception", e
);
123 Thread
.currentThread().interrupt();
125 // throw new ThreadDeath();
130 log
.error("Execution flow failed,"
131 + " but process did not fail"
132 + " because failOnError property"
133 + " is set to false: " + e
);
134 if (log
.isTraceEnabled())
141 * List sub-runnables that would be executed if run() method would be
144 public Iterator
<Runnable
> runnables() {
145 return executables
.iterator();
149 * If there is one and only one runnable wrapped return it, throw an
150 * exeception otherwise.
152 public Runnable
getRunnable() {
153 if (executables
.size() == 1)
154 return executables
.get(0);
156 throw new SlcException("There are " + executables
.size()
157 + " runnables in flow " + getName());
160 public void doExecuteRunnable(Runnable runnable
) {
162 if (executionContext
!= null)
163 if (runnable
instanceof ExecutionFlow
)
164 executionContext
.beforeFlow((ExecutionFlow
) runnable
);
167 if (executionContext
!= null)
168 if (runnable
instanceof ExecutionFlow
)
169 executionContext
.afterFlow((ExecutionFlow
) runnable
);
173 public void afterPropertiesSet() throws Exception
{
175 if (name
.charAt(0) == '/') {
176 path
= name
.substring(0, name
.lastIndexOf('/'));
181 for (Runnable executable
: executables
) {
182 if (executable
instanceof DefaultExecutionFlow
) {
183 // so we don't need to have DefaultExecutionFlow
184 // implementing StructureAware
185 // FIXME: probably has side effects
186 DefaultExecutionFlow flow
= (DefaultExecutionFlow
) executable
;
187 String newPath
= path
+ '/' + flow
.getName();
188 flow
.setPath(newPath
);
189 log
.warn(newPath
+ " was forcibly set on " + flow
);
195 public void setBeanName(String name
) {
199 public void setExecutables(List
<Runnable
> executables
) {
200 this.executables
= executables
;
203 public void setParameters(Map
<String
, Object
> attributes
) {
204 this.parameters
= attributes
;
207 public String
getName() {
211 public ExecutionSpec
getExecutionSpec() {
212 return executionSpec
;
215 public Object
getParameter(String parameterName
) {
216 // Verify that there is a spec attribute
217 ExecutionSpecAttribute specAttr
= null;
218 if (executionSpec
.getAttributes().containsKey(parameterName
)) {
219 specAttr
= executionSpec
.getAttributes().get(parameterName
);
221 throw new SlcException("Key " + parameterName
222 + " is not defined in the specifications of " + toString());
225 if (parameters
.containsKey(parameterName
)) {
226 Object paramValue
= parameters
.get(parameterName
);
229 if (specAttr
.getValue() != null) {
230 return specAttr
.getValue();
233 throw new SlcException("Key " + parameterName
234 + " is not set as parameter in " + toString());
237 public Boolean
isSetAsParameter(String key
) {
238 return parameters
.containsKey(key
)
239 || (executionSpec
.getAttributes().containsKey(key
) && executionSpec
240 .getAttributes().get(key
).getValue() != null);
244 public String
toString() {
245 return new StringBuffer("Execution flow ").append(name
).toString();
249 public boolean equals(Object obj
) {
250 return ((ExecutionFlow
) obj
).getName().equals(name
);
254 public int hashCode() {
255 return name
.hashCode();
258 public String
getPath() {
262 public void setPath(String path
) {
266 public Boolean
getFailOnError() {
270 public void setFailOnError(Boolean failOnError
) {
271 this.failOnError
= failOnError
;
274 public void setExecutionContext(ExecutionContext executionContext
) {
275 this.executionContext
= executionContext
;