package org.argeo.slc.runtime; import java.util.HashMap; import java.util.Map; import java.util.Stack; import java.util.UUID; import org.argeo.api.slc.SlcException; import org.argeo.api.slc.execution.ExecutionFlow; import org.argeo.api.slc.execution.ExecutionSpecAttribute; import org.argeo.api.slc.execution.ExecutionStack; /** Canonical implementation of an execution stack. */ public class DefaultExecutionStack implements ExecutionStack { private final Stack stack = new Stack(); public synchronized void enterFlow(ExecutionFlow executionFlow) { ExecutionFlowRuntime runtime = new ExecutionFlowRuntime(executionFlow); stack.push(runtime); Map 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 null 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 null 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 scopedObjects = new HashMap(); private final Map localVariables = new HashMap(); private final String uuid = UUID.randomUUID().toString(); public ExecutionFlowRuntime(ExecutionFlow executionFlow) { this.executionFlow = executionFlow; } public ExecutionFlow getExecutionFlow() { return executionFlow; } public Map getScopedObjects() { return scopedObjects; } public String getUuid() { return uuid; } public Map getLocalVariables() { return localVariables; } @Override public String toString() { return "Stack Level #" + uuid; } } }