1 package org
.argeo
.slc
.runtime
;
3 import java
.util
.ArrayList
;
4 import java
.util
.HashMap
;
5 import java
.util
.Iterator
;
9 import org
.apache
.commons
.logging
.Log
;
10 import org
.apache
.commons
.logging
.LogFactory
;
11 import org
.argeo
.slc
.SlcException
;
12 import org
.argeo
.slc
.execution
.ExecutionContext
;
13 import org
.argeo
.slc
.execution
.ExecutionFlow
;
14 import org
.argeo
.slc
.execution
.ExecutionSpec
;
15 import org
.argeo
.slc
.execution
.ExecutionSpecAttribute
;
17 /** Default implementation of an execution flow. */
18 public class DefaultExecutionFlow
implements ExecutionFlow
{
19 private final static Log log
= LogFactory
.getLog(DefaultExecutionFlow
.class);
21 private final ExecutionSpec executionSpec
;
22 private String name
= null;
23 private Map
<String
, Object
> parameters
= new HashMap
<String
, Object
>();
24 private List
<Runnable
> executables
= new ArrayList
<Runnable
>();
28 private Boolean failOnError
= true;
30 // Only needed if stacked execution flows are used
31 private ExecutionContext executionContext
= null;
33 public DefaultExecutionFlow() {
34 this.executionSpec
= new DefaultExecutionSpec();
37 public DefaultExecutionFlow(ExecutionSpec executionSpec
) {
38 this.executionSpec
= executionSpec
;
41 public DefaultExecutionFlow(ExecutionSpec executionSpec
, Map
<String
, Object
> parameters
) {
42 // be sure to have an execution spec
43 this.executionSpec
= (executionSpec
== null) ?
new DefaultExecutionSpec() : executionSpec
;
45 // only parameters contained in the executionSpec can be set
46 for (String parameter
: parameters
.keySet()) {
47 if (!executionSpec
.getAttributes().containsKey(parameter
)) {
48 throw new SlcException("Parameter " + parameter
+ " is not defined in the ExecutionSpec");
53 this.parameters
.putAll(parameters
);
55 // check that all the required parameters are defined
56 // MapBindingResult errors = new MapBindingResult(parameters, "execution#"
58 Map
<String
, String
> errors
= new HashMap
<>();
59 for (String key
: executionSpec
.getAttributes().keySet()) {
60 ExecutionSpecAttribute attr
= executionSpec
.getAttributes().get(key
);
62 if (attr
.getIsImmutable() && !isSetAsParameter(key
)) {
63 errors
.put(key
, "Immutable but not set");
67 if (attr
.getIsConstant() && !isSetAsParameter(key
)) {
68 errors
.put(key
, "Constant but not set as parameter");
72 if (attr
.getIsHidden() && !isSetAsParameter(key
)) {
73 errors
.put(key
, "Hidden but not set as parameter");
78 if (!errors
.isEmpty())
79 throw new SlcException("Could not prepare execution flow: " + errors
.toString());
85 for (Runnable executable
: executables
) {
86 if (Thread
.interrupted()) {
87 log
.error("Flow '" + getName() + "' killed before '" + executable
+ "'");
88 Thread
.currentThread().interrupt();
90 // throw new ThreadDeath();
92 this.doExecuteRunnable(executable
);
94 } catch (RuntimeException e
) {
95 if (Thread
.interrupted()) {
96 log
.error("Flow '" + getName() + "' killed while receiving an unrelated exception", e
);
97 Thread
.currentThread().interrupt();
99 // throw new ThreadDeath();
104 log
.error("Execution flow failed," + " but process did not fail" + " because failOnError property"
105 + " is set to false: " + e
);
106 if (log
.isTraceEnabled())
113 * List sub-runnables that would be executed if run() method would be called.
115 public Iterator
<Runnable
> runnables() {
116 return executables
.iterator();
120 * If there is one and only one runnable wrapped return it, throw an exeception
123 public Runnable
getRunnable() {
124 if (executables
.size() == 1)
125 return executables
.get(0);
127 throw new SlcException("There are " + executables
.size() + " runnables in flow " + getName());
130 public void doExecuteRunnable(Runnable runnable
) {
132 if (executionContext
!= null)
133 if (runnable
instanceof ExecutionFlow
)
134 executionContext
.beforeFlow((ExecutionFlow
) runnable
);
137 if (executionContext
!= null)
138 if (runnable
instanceof ExecutionFlow
)
139 executionContext
.afterFlow((ExecutionFlow
) runnable
);
143 public void init() throws Exception
{
145 if (name
.charAt(0) == '/') {
146 path
= name
.substring(0, name
.lastIndexOf('/'));
151 for (Runnable executable
: executables
) {
152 if (executable
instanceof DefaultExecutionFlow
) {
153 // so we don't need to have DefaultExecutionFlow
154 // implementing StructureAware
155 // FIXME: probably has side effects
156 DefaultExecutionFlow flow
= (DefaultExecutionFlow
) executable
;
157 String newPath
= path
+ '/' + flow
.getName();
158 flow
.setPath(newPath
);
159 log
.warn(newPath
+ " was forcibly set on " + flow
);
165 public void setName(String name
) {
169 public void setExecutables(List
<Runnable
> executables
) {
170 this.executables
= executables
;
173 public void setParameters(Map
<String
, Object
> attributes
) {
174 this.parameters
= attributes
;
177 public String
getName() {
181 public ExecutionSpec
getExecutionSpec() {
182 return executionSpec
;
185 public Object
getParameter(String parameterName
) {
186 // Verify that there is a spec attribute
187 ExecutionSpecAttribute specAttr
= null;
188 if (executionSpec
.getAttributes().containsKey(parameterName
)) {
189 specAttr
= executionSpec
.getAttributes().get(parameterName
);
191 throw new SlcException("Key " + parameterName
+ " is not defined in the specifications of " + toString());
194 if (parameters
.containsKey(parameterName
)) {
195 Object paramValue
= parameters
.get(parameterName
);
198 if (specAttr
.getValue() != null) {
199 return specAttr
.getValue();
202 throw new SlcException("Key " + parameterName
+ " is not set as parameter in " + toString());
205 public Boolean
isSetAsParameter(String key
) {
206 return parameters
.containsKey(key
) || (executionSpec
.getAttributes().containsKey(key
)
207 && executionSpec
.getAttributes().get(key
).getValue() != null);
211 public String
toString() {
212 return new StringBuffer("Execution flow ").append(name
).toString();
216 public boolean equals(Object obj
) {
217 return ((ExecutionFlow
) obj
).getName().equals(name
);
221 public int hashCode() {
222 return name
.hashCode();
225 public String
getPath() {
229 public void setPath(String path
) {
233 public Boolean
getFailOnError() {
237 public void setFailOnError(Boolean failOnError
) {
238 this.failOnError
= failOnError
;
241 public void setExecutionContext(ExecutionContext executionContext
) {
242 this.executionContext
= executionContext
;