X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=org.argeo.slc.runtime%2Fsrc%2Forg%2Fargeo%2Fslc%2Fruntime%2FDefaultExecutionFlow.java;fp=org.argeo.slc.runtime%2Fsrc%2Forg%2Fargeo%2Fslc%2Fruntime%2FDefaultExecutionFlow.java;h=289f660e1093d04f8acdb1cdb918a45a74e0d915;hb=810d3b29b3678cbe4b9a6af8e281757c6e820ee4;hp=0000000000000000000000000000000000000000;hpb=f8a9ca2e0faabe1e0cdcd3537da34e02a0e55f57;p=gpl%2Fargeo-slc.git diff --git a/org.argeo.slc.runtime/src/org/argeo/slc/runtime/DefaultExecutionFlow.java b/org.argeo.slc.runtime/src/org/argeo/slc/runtime/DefaultExecutionFlow.java new file mode 100644 index 000000000..289f660e1 --- /dev/null +++ b/org.argeo.slc.runtime/src/org/argeo/slc/runtime/DefaultExecutionFlow.java @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.runtime; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.execution.ExecutionContext; +import org.argeo.slc.execution.ExecutionFlow; +import org.argeo.slc.execution.ExecutionSpec; +import org.argeo.slc.execution.ExecutionSpecAttribute; + +/** Default implementation of an execution flow. */ +public class DefaultExecutionFlow implements ExecutionFlow { + private final static Log log = LogFactory.getLog(DefaultExecutionFlow.class); + + private final ExecutionSpec executionSpec; + private String name = null; + private Map parameters = new HashMap(); + private List executables = new ArrayList(); + + private String path; + + private Boolean failOnError = true; + + // Only needed if stacked execution flows are used + private ExecutionContext executionContext = null; + + public DefaultExecutionFlow() { + this.executionSpec = new DefaultExecutionSpec(); + } + + public DefaultExecutionFlow(ExecutionSpec executionSpec) { + this.executionSpec = executionSpec; + } + + public DefaultExecutionFlow(ExecutionSpec executionSpec, Map parameters) { + // be sure to have an execution spec + this.executionSpec = (executionSpec == null) ? new DefaultExecutionSpec() : executionSpec; + + // only parameters contained in the executionSpec can be set + for (String parameter : parameters.keySet()) { + if (!executionSpec.getAttributes().containsKey(parameter)) { + throw new SlcException("Parameter " + parameter + " is not defined in the ExecutionSpec"); + } + } + + // set the parameters + this.parameters.putAll(parameters); + + // check that all the required parameters are defined +// MapBindingResult errors = new MapBindingResult(parameters, "execution#" +// + getName()); + Map errors = new HashMap<>(); + for (String key : executionSpec.getAttributes().keySet()) { + ExecutionSpecAttribute attr = executionSpec.getAttributes().get(key); + + if (attr.getIsImmutable() && !isSetAsParameter(key)) { + errors.put(key, "Immutable but not set"); + break; + } + + if (attr.getIsConstant() && !isSetAsParameter(key)) { + errors.put(key, "Constant but not set as parameter"); + break; + } + + if (attr.getIsHidden() && !isSetAsParameter(key)) { + errors.put(key, "Hidden but not set as parameter"); + break; + } + } + + if (!errors.isEmpty()) + throw new SlcException("Could not prepare execution flow: " + errors.toString()); + + } + + public void run() { + try { + for (Runnable executable : executables) { + if (Thread.interrupted()) { + log.error("Flow '" + getName() + "' killed before '" + executable + "'"); + Thread.currentThread().interrupt(); + return; + // throw new ThreadDeath(); + } + this.doExecuteRunnable(executable); + } + } catch (RuntimeException e) { + if (Thread.interrupted()) { + log.error("Flow '" + getName() + "' killed while receiving an unrelated exception", e); + Thread.currentThread().interrupt(); + return; + // throw new ThreadDeath(); + } + if (failOnError) + throw e; + else { + log.error("Execution flow failed," + " but process did not fail" + " because failOnError property" + + " is set to false: " + e); + if (log.isTraceEnabled()) + e.printStackTrace(); + } + } + } + + /** + * List sub-runnables that would be executed if run() method would be called. + */ + public Iterator runnables() { + return executables.iterator(); + } + + /** + * If there is one and only one runnable wrapped return it, throw an exeception + * otherwise. + */ + public Runnable getRunnable() { + if (executables.size() == 1) + return executables.get(0); + else + throw new SlcException("There are " + executables.size() + " runnables in flow " + getName()); + } + + public void doExecuteRunnable(Runnable runnable) { + try { + if (executionContext != null) + if (runnable instanceof ExecutionFlow) + executionContext.beforeFlow((ExecutionFlow) runnable); + runnable.run(); + } finally { + if (executionContext != null) + if (runnable instanceof ExecutionFlow) + executionContext.afterFlow((ExecutionFlow) runnable); + } + } + + public void init() throws Exception { + if (path == null) { + if (name.charAt(0) == '/') { + path = name.substring(0, name.lastIndexOf('/')); + } + } + + if (path != null) { + for (Runnable executable : executables) { + if (executable instanceof DefaultExecutionFlow) { + // so we don't need to have DefaultExecutionFlow + // implementing StructureAware + // FIXME: probably has side effects + DefaultExecutionFlow flow = (DefaultExecutionFlow) executable; + String newPath = path + '/' + flow.getName(); + flow.setPath(newPath); + log.warn(newPath + " was forcibly set on " + flow); + } + } + } + } + + public void setName(String name) { + this.name = name; + } + + public void setExecutables(List executables) { + this.executables = executables; + } + + public void setParameters(Map attributes) { + this.parameters = attributes; + } + + public String getName() { + return name; + } + + public ExecutionSpec getExecutionSpec() { + return executionSpec; + } + + public Object getParameter(String parameterName) { + // Verify that there is a spec attribute + ExecutionSpecAttribute specAttr = null; + if (executionSpec.getAttributes().containsKey(parameterName)) { + specAttr = executionSpec.getAttributes().get(parameterName); + } else { + throw new SlcException("Key " + parameterName + " is not defined in the specifications of " + toString()); + } + + if (parameters.containsKey(parameterName)) { + Object paramValue = parameters.get(parameterName); + return paramValue; + } else { + if (specAttr.getValue() != null) { + return specAttr.getValue(); + } + } + throw new SlcException("Key " + parameterName + " is not set as parameter in " + toString()); + } + + public Boolean isSetAsParameter(String key) { + return parameters.containsKey(key) || (executionSpec.getAttributes().containsKey(key) + && executionSpec.getAttributes().get(key).getValue() != null); + } + + @Override + public String toString() { + return new StringBuffer("Execution flow ").append(name).toString(); + } + + @Override + public boolean equals(Object obj) { + return ((ExecutionFlow) obj).getName().equals(name); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public Boolean getFailOnError() { + return failOnError; + } + + public void setFailOnError(Boolean failOnError) { + this.failOnError = failOnError; + } + + public void setExecutionContext(ExecutionContext executionContext) { + this.executionContext = executionContext; + } + +}