--- /dev/null
+package org.argeo.slc.runtime;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+import java.util.UUID;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.slc.SlcException;
+import org.argeo.slc.execution.ExecutionFlow;
+import org.argeo.slc.execution.ExecutionSpecAttribute;
+import org.argeo.slc.execution.ExecutionStack;
+
+/** Canonical implementation of an execution stack. */
+public class DefaultExecutionStack implements ExecutionStack {
+
+ private final static Log log = LogFactory
+ .getLog(DefaultExecutionStack.class);
+
+ private final Stack<ExecutionFlowRuntime> stack = new Stack<ExecutionFlowRuntime>();
+
+ public synchronized void enterFlow(ExecutionFlow executionFlow) {
+ ExecutionFlowRuntime runtime = new ExecutionFlowRuntime(executionFlow);
+ stack.push(runtime);
+
+ Map<String, ExecutionSpecAttribute> specAttrs = executionFlow
+ .getExecutionSpec().getAttributes();
+ for (String key : specAttrs.keySet()) {
+ if (executionFlow.isSetAsParameter(key)) {
+ runtime.getLocalVariables().put(key,
+ executionFlow.getParameter(key));
+ }
+ }
+ }
+
+ public synchronized String getCurrentStackLevelUuid() {
+ return stack.peek().getUuid();
+ }
+
+ public synchronized Integer getStackSize() {
+ return stack.size();
+ }
+
+ /**
+ * Looks for a set variable in the stack, starting at the upper flows
+ *
+ * @return the variable or <code>null</code> if not found
+ */
+ public synchronized Object findLocalVariable(String key) {
+ Object obj = null;
+ for (int i = 0; i < stack.size(); i++) {
+ if (stack.get(i).getLocalVariables().containsKey(key)) {
+ obj = stack.get(i).getLocalVariables().get(key);
+ break;
+ }
+ }
+ return obj;
+ }
+
+ public synchronized void leaveFlow(ExecutionFlow executionFlow) {
+ ExecutionFlowRuntime leftEf = stack.pop();
+
+ if (!leftEf.getExecutionFlow().getName()
+ .equals(executionFlow.getName()))
+ throw new SlcException("Asked to leave " + executionFlow
+ + " but last is " + leftEf);
+
+ leftEf.getScopedObjects().clear();
+ leftEf.getLocalVariables().clear();
+ }
+
+ public synchronized void addScopedObject(String name, Object obj) {
+ ExecutionFlowRuntime runtime = stack.peek();
+ // TODO: check that the object is not set yet ?
+ if (log.isDebugEnabled()) {
+ Object existing = findScopedObject(name);
+ if (existing != null)
+ log.warn("Scoped object " + name + " of type " + obj.getClass()
+ + " already registered in " + runtime);
+ }
+ runtime.getScopedObjects().put(name, obj);
+ }
+
+ /** @return </code>null<code> if not found */
+ public synchronized Object findScopedObject(String name) {
+ Object obj = null;
+ for (int i = stack.size() - 1; i >= 0; i--) {
+ if (stack.get(i).getScopedObjects().containsKey(name)) {
+ obj = stack.get(i).getScopedObjects().get(name);
+ break;
+ }
+ }
+ return obj;
+ }
+
+ protected static class ExecutionFlowRuntime {
+ private final ExecutionFlow executionFlow;
+ private final Map<String, Object> scopedObjects = new HashMap<String, Object>();
+ private final Map<String, Object> localVariables = new HashMap<String, Object>();
+ private final String uuid = UUID.randomUUID().toString();
+
+ public ExecutionFlowRuntime(ExecutionFlow executionFlow) {
+ this.executionFlow = executionFlow;
+ }
+
+ public ExecutionFlow getExecutionFlow() {
+ return executionFlow;
+ }
+
+ public Map<String, Object> getScopedObjects() {
+ return scopedObjects;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public Map<String, Object> getLocalVariables() {
+ return localVariables;
+ }
+
+ @Override
+ public String toString() {
+ return "Stack Level #" + uuid;
+ }
+
+ }
+}