View Javadoc
1   /*
2    * Copyright (C) 2007-2012 Argeo GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.argeo.slc.core.execution;
17  
18  import java.util.HashMap;
19  import java.util.Map;
20  import java.util.Stack;
21  import java.util.UUID;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.argeo.slc.SlcException;
26  import org.argeo.slc.execution.ExecutionFlow;
27  import org.argeo.slc.execution.ExecutionSpecAttribute;
28  import org.argeo.slc.execution.ExecutionStack;
29  
30  /** Canonical implementation of an execution stack. */
31  public class DefaultExecutionStack implements ExecutionStack {
32  
33  	private final static Log log = LogFactory
34  			.getLog(DefaultExecutionStack.class);
35  
36  	private final Stack<ExecutionFlowRuntime> stack = new Stack<ExecutionFlowRuntime>();
37  
38  	public synchronized void enterFlow(ExecutionFlow executionFlow) {
39  		ExecutionFlowRuntime runtime = new ExecutionFlowRuntime(executionFlow);
40  		stack.push(runtime);
41  
42  		Map<String, ExecutionSpecAttribute> specAttrs = executionFlow
43  				.getExecutionSpec().getAttributes();
44  		for (String key : specAttrs.keySet()) {
45  			if (executionFlow.isSetAsParameter(key)) {
46  				runtime.getLocalVariables().put(key,
47  						executionFlow.getParameter(key));
48  			}
49  		}
50  	}
51  
52  	public synchronized String getCurrentStackLevelUuid() {
53  		return stack.peek().getUuid();
54  	}
55  
56  	public synchronized Integer getStackSize() {
57  		return stack.size();
58  	}
59  
60  	/**
61  	 * Looks for a set variable in the stack, starting at the upper flows
62  	 * 
63  	 * @return the variable or <code>null</code> if not found
64  	 */
65  	public synchronized Object findLocalVariable(String key) {
66  		Object obj = null;
67  		for (int i = 0; i < stack.size(); i++) {
68  			if (stack.get(i).getLocalVariables().containsKey(key)) {
69  				obj = stack.get(i).getLocalVariables().get(key);
70  				break;
71  			}
72  		}
73  		return obj;
74  	}
75  
76  	public synchronized void leaveFlow(ExecutionFlow executionFlow) {
77  		ExecutionFlowRuntime leftEf = stack.pop();
78  
79  		if (!leftEf.getExecutionFlow().getName()
80  				.equals(executionFlow.getName()))
81  			throw new SlcException("Asked to leave " + executionFlow
82  					+ " but last is " + leftEf);
83  
84  		leftEf.getScopedObjects().clear();
85  		leftEf.getLocalVariables().clear();
86  	}
87  
88  	public synchronized void addScopedObject(String name, Object obj) {
89  		ExecutionFlowRuntime runtime = stack.peek();
90  		// TODO: check that the object is not set yet ?
91  		if (log.isDebugEnabled()) {
92  			Object existing = findScopedObject(name);
93  			if (existing != null)
94  				log.warn("Scoped object " + name + " of type " + obj.getClass()
95  						+ " already registered in " + runtime);
96  		}
97  		runtime.getScopedObjects().put(name, obj);
98  	}
99  
100 	/** @return </code>null<code> if not found */
101 	public synchronized Object findScopedObject(String name) {
102 		Object obj = null;
103 		for (int i = stack.size() - 1; i >= 0; i--) {
104 			if (stack.get(i).getScopedObjects().containsKey(name)) {
105 				obj = stack.get(i).getScopedObjects().get(name);
106 				break;
107 			}
108 		}
109 		return obj;
110 	}
111 
112 	protected static class ExecutionFlowRuntime {
113 		private final ExecutionFlow executionFlow;
114 		private final Map<String, Object> scopedObjects = new HashMap<String, Object>();
115 		private final Map<String, Object> localVariables = new HashMap<String, Object>();
116 		private final String uuid = UUID.randomUUID().toString();
117 
118 		public ExecutionFlowRuntime(ExecutionFlow executionFlow) {
119 			this.executionFlow = executionFlow;
120 		}
121 
122 		public ExecutionFlow getExecutionFlow() {
123 			return executionFlow;
124 		}
125 
126 		public Map<String, Object> getScopedObjects() {
127 			return scopedObjects;
128 		}
129 
130 		public String getUuid() {
131 			return uuid;
132 		}
133 
134 		public Map<String, Object> getLocalVariables() {
135 			return localVariables;
136 		}
137 
138 		@Override
139 		public String toString() {
140 			return "Stack Level #" + uuid;
141 		}
142 
143 	}
144 }