+/*
+ * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
+ *
+ * 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.core.execution;
+import java.util.Collections;
import java.util.Date;
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.ExecutionContext;
-import org.argeo.slc.execution.ExecutionFlow;
-import org.argeo.slc.execution.ExecutionSpecAttribute;
-
-public class MapExecutionContext implements ExecutionContext {
-
- private final static Log log = LogFactory.getLog(MapExecutionContext.class);
+import org.springframework.beans.BeanWrapper;
+import org.springframework.beans.BeanWrapperImpl;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
- private final Stack<ExecutionFlowRuntime> stack = new Stack<ExecutionFlowRuntime>();
-
- // TODO: make it thread safe?
- private final Map<String, Object> variables = new HashMap<String, Object>();
+public class MapExecutionContext implements ExecutionContext,
+ ApplicationContextAware {
+ private final Map<String, Object> variables = Collections
+ .synchronizedMap(new HashMap<String, Object>());
private final String uuid;
- private final Date creationDate = new Date();
+ private ApplicationContext applicationContext;
public MapExecutionContext() {
uuid = UUID.randomUUID().toString();
variables.put(VAR_EXECUTION_CONTEXT_ID, uuid);
+ variables.put(VAR_EXECUTION_CONTEXT_CREATION_DATE, new Date());
}
- public void addVariables(
- Map<? extends String, ? extends Object> variablesToAdd) {
- variables.putAll(variablesToAdd);
- }
-
- public void enterFlow(ExecutionFlow executionFlow) {
- ExecutionFlowRuntime runtime = new ExecutionFlowRuntime(executionFlow);
- stack.push(runtime);
- variables.put(VAR_FLOW_ID, runtime.getUuid());
- variables.put(VAR_FLOW_NAME, runtime.getExecutionFlow().getName());
-
- if (log.isDebugEnabled())
- log.debug(depthSpaces(stack.size()) + "=> " + executionFlow + " #"
- + uuid + ", depth=" + stack.size());
-
- Map<String, ExecutionSpecAttribute> specAttrs = executionFlow
- .getExecutionSpec().getAttributes();
- for (String key : specAttrs.keySet()) {
- // ExecutionSpecAttribute esa = specAttrs.get(key);
- if (executionFlow.isSetAsParameter(key)) {
- runtime.getLocalVariables().put(key,
- executionFlow.getParameter(key));
- if (log.isTraceEnabled())
- log.trace(depthSpaces(stack.size()) + "Add '" + key
- + "' as local variable.");
+ public void setVariable(String key, Object value) {
+ // check if we do not refer to a bean
+ int lastInd = key.lastIndexOf('.');
+ if (applicationContext != null && lastInd > 0) {
+ String beanName = key.substring(0, lastInd);
+ String propertyName = key.substring(lastInd + 1);
+ if (applicationContext.containsBean(beanName)) {
+ BeanWrapper beanWrapper = new BeanWrapperImpl(
+ applicationContext.getBean(beanName));
+ if (!beanWrapper.isWritableProperty(propertyName))
+ throw new SlcException("No writable property "
+ + propertyName + " in bean " + beanName);
+ beanWrapper.setPropertyValue(propertyName, value);
}
}
+ variables.put(key, value);
}
public Object getVariable(String key) {
- Object obj = findVariable(key);
- if (obj == null)
- throw new SlcException("Variable '" + key + "' not found.");
- return obj;
- }
-
- public Object findVariable(String key) {
- Object obj = null;
-
- // Look if the variable is set in the global execution variables
- // (i.e. the variable was overridden)
- if (variables.containsKey(key))
- obj = variables.get(key);
-
- // if the variable was not found, look in the stack starting at the
- // upper flows
- if (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;
- }
+ // check if we do not refer to a bean
+ int lastInd = key.lastIndexOf('.');
+ if (applicationContext != null && lastInd > 0) {
+ String beanName = key.substring(0, lastInd);
+ String propertyName = key.substring(lastInd + 1);
+ if (applicationContext.containsBean(beanName)) {
+ BeanWrapper beanWrapper = new BeanWrapperImpl(
+ applicationContext.getBean(beanName));
+ if (!beanWrapper.isReadableProperty(propertyName))
+ throw new SlcException("No readable property "
+ + propertyName + " in bean " + beanName);
+ Object obj = beanWrapper.getPropertyValue(propertyName);
+ return obj;
}
}
- return obj;
- }
-
- private static String depthSpaces(int depth) {
- StringBuffer buf = new StringBuffer(depth * 2);
- for (int i = 0; i < depth; i++)
- buf.append(" ");
- return buf.toString();
- }
-
- public void leaveFlow(ExecutionFlow executionFlow) {
- if (log.isDebugEnabled())
- log.debug(depthSpaces(stack.size()) + "<= " + executionFlow + " #"
- + uuid + ", depth=" + stack.size());
-
- 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 void addScopedObject(String name, Object obj) {
- // TODO: check that the object is not set yet ?
- stack.peek().getScopedObjects().put(name, obj);
- }
-
- /** return null if not found */
- public 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;
+ return variables.get(key);
}
public String getUuid() {
return uuid;
}
- public Date getCreationDate() {
- return creationDate;
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof ExecutionContext)
+ return uuid.equals(((ExecutionContext) obj).getUuid());
+ return false;
}
- private 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 getClass().getSimpleName() + "#" + uuid;
+ }
+ public void setApplicationContext(ApplicationContext applicationContext)
+ throws BeansException {
+ this.applicationContext = applicationContext;
}
+
}