1 package org
.argeo
.slc
.runtime
;
3 import static java
.lang
.System
.Logger
.Level
.ERROR
;
4 import static java
.lang
.System
.Logger
.Level
.WARNING
;
6 import java
.lang
.System
.Logger
.Level
;
7 import java
.util
.ArrayList
;
8 import java
.util
.HashMap
;
9 import java
.util
.Iterator
;
10 import java
.util
.List
;
13 import org
.argeo
.slc
.SlcException
;
14 import org
.argeo
.slc
.execution
.ExecutionContext
;
15 import org
.argeo
.slc
.execution
.ExecutionFlow
;
16 import org
.argeo
.slc
.execution
.ExecutionSpec
;
17 import org
.argeo
.slc
.execution
.ExecutionSpecAttribute
;
19 /** Default implementation of an execution flow. */
20 public class DefaultExecutionFlow
implements ExecutionFlow
{
21 private final static System
.Logger logger
= System
.getLogger(DefaultExecutionFlow
.class.getName());
23 private final ExecutionSpec executionSpec
;
24 private String name
= null;
25 private Map
<String
, Object
> parameters
= new HashMap
<String
, Object
>();
26 private List
<Runnable
> executables
= new ArrayList
<Runnable
>();
30 private Boolean failOnError
= true;
32 // Only needed if stacked execution flows are used
33 private ExecutionContext executionContext
= null;
35 public DefaultExecutionFlow() {
36 this.executionSpec
= new DefaultExecutionSpec();
39 public DefaultExecutionFlow(ExecutionSpec executionSpec
) {
40 this.executionSpec
= executionSpec
;
43 public DefaultExecutionFlow(ExecutionSpec executionSpec
, Map
<String
, Object
> parameters
) {
44 // be sure to have an execution spec
45 this.executionSpec
= (executionSpec
== null) ?
new DefaultExecutionSpec() : executionSpec
;
47 // only parameters contained in the executionSpec can be set
48 for (String parameter
: parameters
.keySet()) {
49 if (!executionSpec
.getAttributes().containsKey(parameter
)) {
50 throw new SlcException("Parameter " + parameter
+ " is not defined in the ExecutionSpec");
55 this.parameters
.putAll(parameters
);
57 // check that all the required parameters are defined
58 // MapBindingResult errors = new MapBindingResult(parameters, "execution#"
60 Map
<String
, String
> errors
= new HashMap
<>();
61 for (String key
: executionSpec
.getAttributes().keySet()) {
62 ExecutionSpecAttribute attr
= executionSpec
.getAttributes().get(key
);
64 if (attr
.getIsImmutable() && !isSetAsParameter(key
)) {
65 errors
.put(key
, "Immutable but not set");
69 if (attr
.getIsConstant() && !isSetAsParameter(key
)) {
70 errors
.put(key
, "Constant but not set as parameter");
74 if (attr
.getIsHidden() && !isSetAsParameter(key
)) {
75 errors
.put(key
, "Hidden but not set as parameter");
80 if (!errors
.isEmpty())
81 throw new SlcException("Could not prepare execution flow: " + errors
.toString());
87 for (Runnable executable
: executables
) {
88 if (Thread
.interrupted()) {
89 logger
.log(ERROR
, "Flow '" + getName() + "' killed before '" + executable
+ "'");
90 Thread
.currentThread().interrupt();
92 // throw new ThreadDeath();
94 this.doExecuteRunnable(executable
);
96 } catch (RuntimeException e
) {
97 if (Thread
.interrupted()) {
98 logger
.log(ERROR
, "Flow '" + getName() + "' killed while receiving an unrelated exception", e
);
99 Thread
.currentThread().interrupt();
101 // throw new ThreadDeath();
106 logger
.log(ERROR
, "Execution flow failed," + " but process did not fail"
107 + " because failOnError property" + " is set to false: " + e
);
108 if (logger
.isLoggable(Level
.TRACE
))
115 * List sub-runnables that would be executed if run() method would be called.
117 public Iterator
<Runnable
> runnables() {
118 return executables
.iterator();
122 * If there is one and only one runnable wrapped return it, throw an exeception
125 public Runnable
getRunnable() {
126 if (executables
.size() == 1)
127 return executables
.get(0);
129 throw new SlcException("There are " + executables
.size() + " runnables in flow " + getName());
132 public void doExecuteRunnable(Runnable runnable
) {
134 if (executionContext
!= null)
135 if (runnable
instanceof ExecutionFlow
)
136 executionContext
.beforeFlow((ExecutionFlow
) runnable
);
139 if (executionContext
!= null)
140 if (runnable
instanceof ExecutionFlow
)
141 executionContext
.afterFlow((ExecutionFlow
) runnable
);
145 public void init() throws Exception
{
147 if (name
.charAt(0) == '/') {
148 path
= name
.substring(0, name
.lastIndexOf('/'));
153 for (Runnable executable
: executables
) {
154 if (executable
instanceof DefaultExecutionFlow
) {
155 // so we don't need to have DefaultExecutionFlow
156 // implementing StructureAware
157 // FIXME: probably has side effects
158 DefaultExecutionFlow flow
= (DefaultExecutionFlow
) executable
;
159 String newPath
= path
+ '/' + flow
.getName();
160 flow
.setPath(newPath
);
161 logger
.log(WARNING
, newPath
+ " was forcibly set on " + flow
);
167 public void setName(String name
) {
171 public void setExecutables(List
<Runnable
> executables
) {
172 this.executables
= executables
;
175 public void setParameters(Map
<String
, Object
> attributes
) {
176 this.parameters
= attributes
;
179 public String
getName() {
183 public ExecutionSpec
getExecutionSpec() {
184 return executionSpec
;
187 public Object
getParameter(String parameterName
) {
188 // Verify that there is a spec attribute
189 ExecutionSpecAttribute specAttr
= null;
190 if (executionSpec
.getAttributes().containsKey(parameterName
)) {
191 specAttr
= executionSpec
.getAttributes().get(parameterName
);
193 throw new SlcException("Key " + parameterName
+ " is not defined in the specifications of " + toString());
196 if (parameters
.containsKey(parameterName
)) {
197 Object paramValue
= parameters
.get(parameterName
);
200 if (specAttr
.getValue() != null) {
201 return specAttr
.getValue();
204 throw new SlcException("Key " + parameterName
+ " is not set as parameter in " + toString());
207 public Boolean
isSetAsParameter(String key
) {
208 return parameters
.containsKey(key
) || (executionSpec
.getAttributes().containsKey(key
)
209 && executionSpec
.getAttributes().get(key
).getValue() != null);
213 public String
toString() {
214 return new StringBuffer("Execution flow ").append(name
).toString();
218 public boolean equals(Object obj
) {
219 return ((ExecutionFlow
) obj
).getName().equals(name
);
223 public int hashCode() {
224 return name
.hashCode();
227 public String
getPath() {
231 public void setPath(String path
) {
235 public Boolean
getFailOnError() {
239 public void setFailOnError(Boolean failOnError
) {
240 this.failOnError
= failOnError
;
243 public void setExecutionContext(ExecutionContext executionContext
) {
244 this.executionContext
= executionContext
;