]> git.argeo.org Git - gpl/argeo-slc.git/commitdiff
Refactor runtime
authorMathieu Baudier <mbaudier@argeo.org>
Tue, 30 Jun 2009 14:16:48 +0000 (14:16 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Tue, 30 Jun 2009 14:16:48 +0000 (14:16 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@2631 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

17 files changed:
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlow.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionStack.java [new file with mode: 0644]
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionAspect.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionFinishedEvent.java [deleted file]
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionScope.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/Executor.java [deleted file]
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/FileExecutionResources.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/InstantiationPostProcessor.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/MapExecutionContext.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/NewExecutionEvent.java [deleted file]
runtime/org.argeo.slc.core/src/main/resources/org/argeo/slc/core/execution/spring.xml
runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/BasicExecutionFlowTest.java
runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionContext.java
runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStack.java [new file with mode: 0644]
runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStackLevel.java [new file with mode: 0644]
runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/OsgiExecutionModulesManager.java

index 497e6520e86177a7b1bf79748b1f1bb11298fb33..7fd07fe770ff32c1d28a94be1c21500cd067be4d 100644 (file)
@@ -15,13 +15,10 @@ import org.argeo.slc.structure.StructureAware;
 import org.argeo.slc.structure.StructureRegistry;
 import org.springframework.beans.factory.BeanNameAware;
 import org.springframework.beans.factory.InitializingBean;
-import org.springframework.context.ResourceLoaderAware;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.ResourceLoader;
 import org.springframework.validation.MapBindingResult;
 
 public class DefaultExecutionFlow implements ExecutionFlow, InitializingBean,
-               BeanNameAware, StructureAware<TreeSPath>, ResourceLoaderAware {
+               BeanNameAware, StructureAware<TreeSPath> {
 
        private final ExecutionSpec executionSpec;
        private String name = null;
@@ -31,8 +28,6 @@ public class DefaultExecutionFlow implements ExecutionFlow, InitializingBean,
        private String path;
        private StructureRegistry<TreeSPath> registry = new TreeSRegistry();
 
-       private ResourceLoader resourceLoader = null;
-
        public DefaultExecutionFlow() {
                this.executionSpec = new DefaultExecutionSpec();
        }
@@ -93,6 +88,7 @@ public class DefaultExecutionFlow implements ExecutionFlow, InitializingBean,
                }
        }
 
+       @SuppressWarnings(value = { "unchecked" })
        public void afterPropertiesSet() throws Exception {
                if (path != null) {
                        for (Runnable executable : executables) {
@@ -179,8 +175,4 @@ public class DefaultExecutionFlow implements ExecutionFlow, InitializingBean,
                }
        }
 
-       public void setResourceLoader(ResourceLoader resourceLoader) {
-               this.resourceLoader = resourceLoader;
-       }
-
 }
diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionStack.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionStack.java
new file mode 100644 (file)
index 0000000..9bdf31a
--- /dev/null
@@ -0,0 +1,128 @@
+package org.argeo.slc.core.execution;
+
+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;
+
+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;
+               }
+
+       }
+}
index 29942817d4e2343808d6a010a491def5e47bc829..0f091fcb8db2fb98eedfea434a3b717c81518f04 100644 (file)
@@ -1,59 +1,84 @@
 package org.argeo.slc.core.execution;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.argeo.slc.execution.ExecutionContext;
 import org.argeo.slc.execution.ExecutionFlow;
-import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.annotation.After;
+import org.argeo.slc.execution.ExecutionStack;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
 import org.aspectj.lang.annotation.Pointcut;
 
 @Aspect
 public class ExecutionAspect {
-       static ThreadLocal<Boolean> inModuleExecution = new ThreadLocal<Boolean>() {
-               protected Boolean initialValue() {
-                       return false;
-               }
-       };
+       private final static Log log = LogFactory.getLog(ExecutionAspect.class);
 
+       private ExecutionStack executionStack;
        private ExecutionContext executionContext;
 
-       public ExecutionContext getExecutionContext() {
-               return executionContext;
+       @Around("flowExecution()")
+       public void aroundFlow(ProceedingJoinPoint pjp) throws Throwable {
+               // IMPORTANT: Make sure that the execution context is called before the execution stack
+               executionContext.getUuid();
+               
+               ExecutionFlow executionFlow = (ExecutionFlow) pjp.getTarget();
+               executionStack.enterFlow(executionFlow);
+               executionContext.setVariable(ExecutionContext.VAR_FLOW_ID,
+                               executionStack.getCurrentStackLevelUuid());
+               executionContext.setVariable(ExecutionContext.VAR_FLOW_NAME,
+                               executionFlow.getName());
+
+               if (log.isDebugEnabled())
+                       logStackEvent("=> ", executionFlow);
+               // Actually execute the flow
+               pjp.proceed();
+               if (log.isDebugEnabled())
+                       logStackEvent("<= ", executionFlow);
+
+               executionStack.leaveFlow(executionFlow);
        }
 
-       public void setExecutionContext(ExecutionContext executionContext) {
-               this.executionContext = executionContext;
+       @Around("getVariable()")
+       public Object aroundGetVariable(ProceedingJoinPoint pjp) throws Throwable {
+               Object obj = pjp.proceed();
+               // if the variable was not found, look in the stack starting at the
+               // upper flows
+               if (obj == null) {
+                       String key = pjp.getArgs()[0].toString();
+                       obj = executionStack.findLocalVariable(key);
+               }
+               return obj;
        }
 
-       @Before("flowExecution()")
-       public void beforeFlow(JoinPoint jp) throws Throwable {
-               ExecutionFlow executionFlow = (ExecutionFlow) jp.getTarget();
-               executionContext.enterFlow(executionFlow);
+       @Pointcut("execution(void org.argeo.slc.execution.ExecutionFlow.run())")
+       public void flowExecution() {
        }
 
-       @After("flowExecution()")
-       public void afterFlow(JoinPoint jp) throws Throwable {
-               ExecutionFlow executionFlow = (ExecutionFlow) jp.getTarget();
-               executionContext.leaveFlow(executionFlow);
+       @Pointcut("execution(* org.argeo.slc.execution.ExecutionContext.getVariable(..))")
+       public void getVariable() {
        }
 
-       @Before("moduleExecution()")
-       public void beforeModuleExecution(JoinPoint jp) throws Throwable {
-               inModuleExecution.set(true);
+       public void setExecutionStack(ExecutionStack executionStack) {
+               this.executionStack = executionStack;
        }
 
-       @After("moduleExecution()")
-       public void afterModuleExecution(JoinPoint jp) throws Throwable {
-               inModuleExecution.set(false);
+       public void setExecutionContext(ExecutionContext executionContext) {
+               this.executionContext = executionContext;
        }
 
-       @Pointcut("execution(void org.argeo.slc.execution.ExecutionFlow.run())")
-       public void flowExecution() {
+       protected void logStackEvent(String symbol, ExecutionFlow executionFlow) {
+               Integer stackSize = executionStack.getStackSize();
+               log.debug(depthSpaces(stackSize) + symbol + executionFlow + " #"
+                               + executionStack.getCurrentStackLevelUuid() + ", depth="
+                               + stackSize);
        }
 
-       @Pointcut("execution(void org.argeo.slc.execution.ExecutionModule.execute(..))")
-       public void moduleExecution() {
+       private String depthSpaces(int depth) {
+               StringBuffer buf = new StringBuffer(depth * 2);
+               for (int i = 0; i < depth; i++)
+                       buf.append("  ");
+               return buf.toString();
        }
 
 }
diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionFinishedEvent.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionFinishedEvent.java
deleted file mode 100644 (file)
index fac5b5c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.argeo.slc.core.execution;
-
-import org.argeo.slc.execution.ExecutionContext;
-import org.springframework.context.ApplicationEvent;
-
-public class ExecutionFinishedEvent extends ApplicationEvent {
-       static final long serialVersionUID = 012;
-
-       private final ExecutionContext executionContext;
-
-       public ExecutionFinishedEvent(Object source, ExecutionContext executionContext) {
-               super(source);
-               this.executionContext = executionContext;
-       }
-
-       public ExecutionContext getExecutionContext() {
-               return executionContext;
-       }
-
-}
index 1bdd4f29a6d46a984443be4b213e7100bffbfda6..5b28534ba43063ceedf61849c9a1f836ecc5ef17 100644 (file)
@@ -5,57 +5,34 @@ import java.util.HashSet;
 import java.util.Iterator;\r
 import java.util.List;\r
 import java.util.Map;\r
-import java.util.Properties;\r
 import java.util.Set;\r
 \r
 import org.apache.commons.logging.Log;\r
 import org.apache.commons.logging.LogFactory;\r
 import org.argeo.slc.SlcException;\r
 import org.argeo.slc.execution.ExecutionContext;\r
+import org.argeo.slc.execution.ExecutionFlow;\r
 import org.springframework.beans.BeansException;\r
 import org.springframework.beans.MutablePropertyValues;\r
 import org.springframework.beans.PropertyValue;\r
 import org.springframework.beans.PropertyValues;\r
+import org.springframework.beans.factory.BeanDefinitionStoreException;\r
 import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;\r
-import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;\r
 import org.springframework.beans.factory.config.TypedStringValue;\r
 import org.springframework.beans.factory.support.ManagedList;\r
 import org.springframework.beans.factory.support.ManagedMap;\r
 import org.springframework.beans.factory.support.ManagedSet;\r
 import org.springframework.util.ObjectUtils;\r
+import org.springframework.util.StringUtils;\r
 \r
 public class ExecutionParameterPostProcessor extends\r
                InstantiationAwareBeanPostProcessorAdapter {\r
 \r
        private final static Log log = LogFactory\r
                        .getLog(ExecutionParameterPostProcessor.class);\r
-       \r
-       private ExecutionContext executionContext;\r
-\r
-       private ExecutionScope executionScope;\r
 \r
+       private ExecutionContext executionContext;\r
        private InstantiationManager instantiationManager;\r
-       \r
-       public InstantiationManager getInstantiationManager() {\r
-               return instantiationManager;\r
-       }\r
-\r
-       public void setInstantiationManager(\r
-                       InstantiationManager instantiationManager) {\r
-               this.instantiationManager = instantiationManager;\r
-       }\r
-\r
-       public void setExecutionScope(ExecutionScope executionScope) {\r
-               this.executionScope = executionScope;\r
-       }\r
-\r
-       public ExecutionContext getExecutionContext() {\r
-               return executionContext;\r
-       }\r
-\r
-       public void setExecutionContext(ExecutionContext executionContext) {\r
-               this.executionContext = executionContext;\r
-       }\r
 \r
        private String placeholderPrefix = "@{";\r
        private String placeholderSuffix = "}";\r
@@ -66,26 +43,138 @@ public class ExecutionParameterPostProcessor extends
                        PropertyDescriptor[] pds, Object bean, String beanName)\r
                        throws BeansException {\r
 \r
-               //TODO: resolve at execution only if scope is execution\r
-               //TODO: deal with placeholders in RuntimeBeanReference and RuntimeBeanNameReference\r
-                                       \r
+               // TODO: resolve at execution only if scope is execution\r
+               // TODO: deal with placeholders in RuntimeBeanReference and\r
+               // RuntimeBeanNameReference\r
+\r
                MutablePropertyValues newPvs = new MutablePropertyValues();\r
-               \r
+\r
                boolean changesOccured = false;\r
-                               \r
-               CustomPpc ppc = new CustomPpc(beanName);\r
-               \r
-               for(PropertyValue pv : pvs.getPropertyValues()) {\r
-                       Object convertedValue = ppc.resolveValue(pv.getValue());\r
+\r
+               for (PropertyValue pv : pvs.getPropertyValues()) {\r
+                       Object convertedValue = resolveValue(beanName, bean, pv.getValue());\r
                        newPvs.addPropertyValue(new PropertyValue(pv, convertedValue));\r
-                       if(convertedValue != pv.getValue()) {\r
+                       if (convertedValue != pv.getValue()) {\r
                                changesOccured = true;\r
                        }\r
                }\r
-               \r
+\r
                return changesOccured ? newPvs : pvs;\r
        }\r
 \r
+       @Override\r
+       public boolean postProcessAfterInstantiation(Object bean, String beanName)\r
+                       throws BeansException {\r
+               if (bean instanceof ExecutionFlow)\r
+                       instantiationManager.flowInitializationStarted(\r
+                                       (ExecutionFlow) bean, beanName);\r
+               return true;\r
+       }\r
+\r
+       @Override\r
+       public Object postProcessAfterInitialization(Object bean, String beanName)\r
+                       throws BeansException {\r
+               if (bean instanceof ExecutionFlow)\r
+                       instantiationManager.flowInitializationFinished(\r
+                                       (ExecutionFlow) bean, beanName);\r
+               return bean;\r
+       }\r
+\r
+       protected String resolvePlaceholder(Object bean, String placeholder) {\r
+               if (instantiationManager.isInFlowInitialization())\r
+                       return instantiationManager.getInitializingFlowParameter(\r
+                                       placeholder).toString();\r
+\r
+               else {// execution\r
+                       log.debug("Bean class: " + bean.getClass());\r
+                       // next call fail if no execution context available\r
+                       Object obj = executionContext.getVariable(placeholder);\r
+                       if (obj != null) {\r
+                               return obj.toString();\r
+                       }\r
+               }\r
+\r
+               return null;\r
+       }\r
+\r
+       @SuppressWarnings(value = { "unchecked" })\r
+       public Object resolveValue(String beanName, Object bean, Object value) {\r
+               if (value instanceof TypedStringValue) {\r
+                       TypedStringValue tsv = (TypedStringValue) value;\r
+                       String originalValue = tsv.getValue();\r
+\r
+                       String convertedValue = resolveString(beanName, bean, originalValue);\r
+                       return convertedValue.equals(originalValue) ? value\r
+                                       : new TypedStringValue(convertedValue);\r
+               } else if (value instanceof String) {\r
+                       String originalValue = value.toString();\r
+                       String convertedValue = resolveString(beanName, bean, originalValue);\r
+                       return convertedValue.equals(originalValue) ? value\r
+                                       : convertedValue;\r
+               } else if (value instanceof ManagedMap) {\r
+                       Map mapVal = (Map) value;\r
+\r
+                       Map newContent = new ManagedMap();\r
+                       boolean entriesModified = false;\r
+                       for (Iterator it = mapVal.entrySet().iterator(); it.hasNext();) {\r
+                               Map.Entry entry = (Map.Entry) it.next();\r
+                               Object key = entry.getKey();\r
+                               int keyHash = (key != null ? key.hashCode() : 0);\r
+                               Object newKey = resolveValue(beanName, bean, key);\r
+                               int newKeyHash = (newKey != null ? newKey.hashCode() : 0);\r
+                               Object val = entry.getValue();\r
+                               Object newVal = resolveValue(beanName, bean, val);\r
+                               newContent.put(newKey, newVal);\r
+                               entriesModified = entriesModified\r
+                                               || (newVal != val || newKey != key || newKeyHash != keyHash);\r
+                       }\r
+\r
+                       return entriesModified ? newContent : value;\r
+               } else if (value instanceof ManagedList) {\r
+                       List listVal = (List) value;\r
+                       List newContent = new ManagedList();\r
+                       boolean valueModified = false;\r
+\r
+                       for (int i = 0; i < listVal.size(); i++) {\r
+                               Object elem = listVal.get(i);\r
+                               Object newVal = resolveValue(beanName, bean, elem);\r
+                               newContent.add(newVal);\r
+                               if (!ObjectUtils.nullSafeEquals(newVal, elem)) {\r
+                                       valueModified = true;\r
+                               }\r
+                       }\r
+                       return valueModified ? newContent : value;\r
+               } else if (value instanceof ManagedSet) {\r
+                       Set setVal = (Set) value;\r
+                       Set newContent = new ManagedSet();\r
+                       boolean entriesModified = false;\r
+                       for (Iterator it = setVal.iterator(); it.hasNext();) {\r
+                               Object elem = it.next();\r
+                               int elemHash = (elem != null ? elem.hashCode() : 0);\r
+                               Object newVal = resolveValue(beanName, bean, elem);\r
+                               int newValHash = (newVal != null ? newVal.hashCode() : 0);\r
+                               newContent.add(newVal);\r
+                               entriesModified = entriesModified\r
+                                               || (newVal != elem || newValHash != elemHash);\r
+                       }\r
+                       return entriesModified ? newContent : value;\r
+               } else {\r
+                       //log.debug(beanName + ": " + value.getClass() + " : " + value);\r
+                       return value;\r
+               }\r
+\r
+       }\r
+\r
+       private String resolveString(String beanName, Object bean, String strVal) {\r
+               String value = parseStringValue(bean, strVal, new HashSet<String>());\r
+\r
+               if (value == null)\r
+                       throw new SlcException("Could not resolve placeholder '" + strVal\r
+                                       + "' in bean '" + beanName + "'");\r
+\r
+               return (value.equals(nullValue) ? null : value);\r
+       }\r
+\r
        public void setPlaceholderPrefix(String placeholderPrefix) {\r
                this.placeholderPrefix = placeholderPrefix;\r
        }\r
@@ -97,108 +186,91 @@ public class ExecutionParameterPostProcessor extends
        public void setNullValue(String nullValue) {\r
                this.nullValue = nullValue;\r
        }\r
-       \r
-       private class CustomPpc extends PropertyPlaceholderConfigurer {\r
-               private final Properties props;\r
-               String beanName;\r
-               \r
-               public CustomPpc(String beanName) {\r
-                       super();\r
-                       this.props = new Properties();\r
-                       this.beanName = beanName;\r
-                       setPlaceholderPrefix(placeholderPrefix);\r
-                       setPlaceholderSuffix(placeholderSuffix);\r
-                       setSystemPropertiesMode(SYSTEM_PROPERTIES_MODE_NEVER);\r
-               }\r
 \r
-               /** Public access to the internals of PropertyPlaceholderConfigurer*/\r
-               public String resolveString(String strVal) {\r
-                       String value = parseStringValue(strVal, this.props,\r
-                                       new HashSet<String>());\r
-                       return (value.equals(nullValue) ? null : value);\r
-               }\r
-               \r
-               public Object resolveValue(Object value) {\r
-                       if (value instanceof TypedStringValue) {\r
-                               TypedStringValue tsv = (TypedStringValue) value;\r
-                               String originalValue = tsv.getValue();\r
-\r
-                               String convertedValue = resolveString(originalValue);\r
-                               return convertedValue.equals(originalValue) ? value : new TypedStringValue(convertedValue);\r
-                       }\r
-                       else if (value instanceof String) {\r
-                               String originalValue = value.toString();                        \r
-                               String convertedValue = resolveString(originalValue);\r
-                               return convertedValue.equals(originalValue) ? value : convertedValue;\r
-                       }               \r
-                       else if (value instanceof ManagedMap) {\r
-                               Map mapVal = (Map) value;\r
-                               \r
-                               Map newContent = new ManagedMap();\r
-                               boolean entriesModified = false;\r
-                               for (Iterator it = mapVal.entrySet().iterator(); it.hasNext();) {\r
-                                       Map.Entry entry = (Map.Entry) it.next();\r
-                                       Object key = entry.getKey();\r
-                                       int keyHash = (key != null ? key.hashCode() : 0);\r
-                                       Object newKey = resolveValue(key);\r
-                                       int newKeyHash = (newKey != null ? newKey.hashCode() : 0);\r
-                                       Object val = entry.getValue();\r
-                                       Object newVal = resolveValue(val);\r
-                                       newContent.put(newKey, newVal);\r
-                                       entriesModified = entriesModified || (newVal != val || newKey != key || newKeyHash != keyHash);\r
+       public void setInstantiationManager(\r
+                       InstantiationManager instantiationManager) {\r
+               this.instantiationManager = instantiationManager;\r
+       }\r
+\r
+       public void setExecutionContext(ExecutionContext executionContext) {\r
+               this.executionContext = executionContext;\r
+       }\r
+\r
+       //\r
+       // Following methods hacked from the internals of\r
+       // PropertyPlaceholderConfigurer\r
+       //\r
+\r
+       protected String parseStringValue(Object bean, String strVal,\r
+                       Set<String> visitedPlaceholders)\r
+                       throws BeanDefinitionStoreException {\r
+\r
+               StringBuffer buf = new StringBuffer(strVal);\r
+\r
+               int startIndex = strVal.indexOf(placeholderPrefix);\r
+               while (startIndex != -1) {\r
+                       int endIndex = findPlaceholderEndIndex(buf, startIndex);\r
+                       if (endIndex != -1) {\r
+                               String placeholder = buf.substring(startIndex\r
+                                               + placeholderPrefix.length(), endIndex);\r
+                               if (!visitedPlaceholders.add(placeholder)) {\r
+                                       throw new BeanDefinitionStoreException(\r
+                                                       "Circular placeholder reference '" + placeholder\r
+                                                                       + "' in property definitions");\r
                                }\r
-                               \r
-                               return entriesModified ? newContent : value;\r
-                       }\r
-                       else if (value instanceof ManagedList) {\r
-                               List listVal = (List) value;\r
-                               List newContent = new ManagedList();\r
-                               boolean valueModified = false;\r
-                               \r
-                               for (int i = 0; i < listVal.size(); i++) {\r
-                                       Object elem = listVal.get(i);\r
-                                       Object newVal = resolveValue(elem);\r
-                                       newContent.add(newVal);\r
-                                       if (!ObjectUtils.nullSafeEquals(newVal, elem)) {\r
-                                               valueModified = true;\r
+                               // Recursive invocation, parsing placeholders contained in\r
+                               // the placeholder key.\r
+                               placeholder = parseStringValue(bean, placeholder,\r
+                                               visitedPlaceholders);\r
+                               // Now obtain the value for the fully resolved key...\r
+                               String propVal = resolvePlaceholder(bean, placeholder);\r
+                               if (propVal != null) {\r
+                                       // Recursive invocation, parsing placeholders contained\r
+                                       // in the\r
+                                       // previously resolved placeholder value.\r
+                                       propVal = parseStringValue(bean, propVal,\r
+                                                       visitedPlaceholders);\r
+                                       buf.replace(startIndex, endIndex\r
+                                                       + placeholderSuffix.length(), propVal);\r
+                                       if (log.isTraceEnabled()) {\r
+                                               log.trace("Resolved placeholder '" + placeholder + "'");\r
                                        }\r
-                               }                       \r
-                               return valueModified ? newContent : value;\r
-                       }\r
-                       else if (value instanceof ManagedSet) {\r
-                               Set setVal = (Set) value;\r
-                               Set newContent = new ManagedSet();\r
-                               boolean entriesModified = false;\r
-                               for (Iterator it = setVal.iterator(); it.hasNext();) {\r
-                                       Object elem = it.next();\r
-                                       int elemHash = (elem != null ? elem.hashCode() : 0);\r
-                                       Object newVal = resolveValue(elem);\r
-                                       int newValHash = (newVal != null ? newVal.hashCode() : 0);\r
-                                       newContent.add(newVal);\r
-                                       entriesModified = entriesModified || (newVal != elem || newValHash != elemHash);\r
-                               }       \r
-                               return entriesModified ? newContent : value;\r
+                                       startIndex = buf.indexOf(placeholderPrefix, startIndex\r
+                                                       + propVal.length());\r
+                               } else {\r
+                                       throw new BeanDefinitionStoreException(\r
+                                                       "Could not resolve placeholder '" + placeholder\r
+                                                                       + "'");\r
+                               }\r
+                               visitedPlaceholders.remove(placeholder);\r
+                       } else {\r
+                               startIndex = -1;\r
                        }\r
-                       else {\r
-                               return value;\r
-                       }                       \r
                }\r
 \r
-               @Override\r
-               protected String resolvePlaceholder(String placeholder, Properties props) {                                             \r
-                       if ((executionScope != null)\r
-                                       && (executionScope.hasExecutionContext())) {\r
-                               Object obj = executionContext.findVariable(placeholder);\r
-                               if(obj != null) {\r
-                                       return obj.toString();\r
+               return buf.toString();\r
+       }\r
+\r
+       private int findPlaceholderEndIndex(CharSequence buf, int startIndex) {\r
+               int index = startIndex + placeholderPrefix.length();\r
+               int withinNestedPlaceholder = 0;\r
+               while (index < buf.length()) {\r
+                       if (StringUtils.substringMatch(buf, index, placeholderSuffix)) {\r
+                               if (withinNestedPlaceholder > 0) {\r
+                                       withinNestedPlaceholder--;\r
+                                       index = index + placeholderSuffix.length();\r
+                               } else {\r
+                                       return index;\r
                                }\r
+                       } else if (StringUtils\r
+                                       .substringMatch(buf, index, placeholderPrefix)) {\r
+                               withinNestedPlaceholder++;\r
+                               index = index + placeholderPrefix.length();\r
+                       } else {\r
+                               index++;\r
                        }\r
-                       if (instantiationManager.isInFlowInitialization())\r
-                               return instantiationManager.getInitializingFlowParameter(\r
-                                               placeholder).toString();\r
-                       else\r
-                               throw new SlcException("Could not resolve placeholder '" \r
-                                               + placeholder + "' in bean '" + beanName + "'");\r
                }\r
+               return -1;\r
        }\r
+\r
 }\r
index a24046a99869a443f4fb024de4a5aff5875599e3..2cbd70897b93a39d4f68a8e21e745d4226d32ed6 100644 (file)
 package org.argeo.slc.core.execution;
 
-import java.util.HashMap;
-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.UnsupportedException;
 import org.argeo.slc.execution.ExecutionContext;
+import org.argeo.slc.execution.ExecutionFlow;
+import org.argeo.slc.execution.ExecutionSpec;
+import org.argeo.slc.execution.ExecutionStack;
 import org.springframework.beans.factory.ObjectFactory;
 import org.springframework.beans.factory.config.Scope;
 
 public class ExecutionScope implements Scope {
        private final static Log log = LogFactory.getLog(ExecutionScope.class);
 
-       private final ThreadLocal<ExecutionContext> executionContext = new ThreadLocal<ExecutionContext>();
+       private final ThreadLocal<ExecutionStack> executionStack = new ThreadLocal<ExecutionStack>();
+       public final ThreadLocal<String> executionStackBeanName = new ThreadLocal<String>();
 
-       public final ThreadLocal<String> executionContextBeanName = new ThreadLocal<String>();
+       private final ThreadLocal<ExecutionContext> executionContext = new ThreadLocal<ExecutionContext>();
+       private final ThreadLocal<String> executionContextBeanName = new ThreadLocal<String>();
 
        public Object get(String name, ObjectFactory objectFactory) {
-
                if (log.isTraceEnabled())
-                       log.trace("Getting scoped bean " + name);
+                       log.debug("Get execution scoped bean " + name);
+
+               // shortcuts
+               if (executionStackBeanName.get() != null
+                               && name.equals(executionStackBeanName.get())) {
+                       return executionStack.get();
+               }
+
+               if (executionContextBeanName.get() != null
+                               && name.equals(executionContextBeanName.get())) {
+                       return executionContext.get();
+               }
 
-               // check if an execution context is defined for this thread
+               // execution context must be defined first
                if (executionContext.get() == null) {
-                       // if not, we expect objectFactory to produce an ExecutionContext
                        Object obj = objectFactory.getObject();
                        if (obj instanceof ExecutionContext) {
-                               // Check whether we are in an execution
-                               // FIXME: do it more properly (not static)
-                               // see https://www.argeo.org/bugzilla/show_bug.cgi?id=82
-                               if (!ExecutionAspect.inModuleExecution.get()) {
-                                       log
-                                                       .error("An execution context is being instantiated outside a module execution."
-                                                                       + " Please check your references to execution contexts."
-                                                                       + " This may lead to unexpected behaviour and will be rejected in the future.");
-                                       //Thread.dumpStack();
-                               }
-
-                               // store the ExecutionContext in the ThreadLocal
-                               executionContext.set((ExecutionContext) obj);
-                               executionContextBeanName.set(name);
-                               if (log.isDebugEnabled()) {
-                                       log.debug("Execution context #"
-                                                       + executionContext.get().getUuid()
-                                                       + " instantiated. (beanName="
-                                                       + executionContextBeanName.get() + ")");
-                                       // Thread.dumpStack();
-                               }
-                               return obj;
+                               return dealWithSpecialScopedObject(name, executionContext,
+                                               executionContextBeanName, (ExecutionContext) obj);
                        } else {
-                               throw new SlcException(
-                                               "Expected an ExecutionContext, got an object of class "
-                                                               + obj.getClass()
-                                                               + " for bean "
-                                                               + name
-                                                               + ": make sure that you have porperly set scope=\"execution\" where required");
+                               // TODO: use execution context wrapper
+                               throw new SlcException("No execution context has been defined.");
                        }
                }
 
-               if (name.equals(executionContextBeanName.get())) {
-                       return executionContext.get();
-               } else {
-                       // see if the executionContext already knows the object
-                       Object obj = executionContext.get().findScopedObject(name);
-                       if (obj == null) {
-                               obj = objectFactory.getObject();
-                               if (!(obj instanceof ExecutionContext)) {
-                                       executionContext.get().addScopedObject(name, obj);
-                               } else {
-                                       throw new SlcException(
-                                                       "Only one ExecutionContext can be defined per Thread");
-                               }
+               // for other scoped objects, an executions stack must be available
+               if (executionStack.get() == null) {
+                       Object obj = objectFactory.getObject();
+                       if (obj instanceof ExecutionStack) {
+                               return dealWithSpecialScopedObject(name, executionStack,
+                                               executionStackBeanName, (ExecutionStack) obj);
+                       } else {
+                               throw new SlcException("No execution stack has been defined.");
                        }
-                       return obj;
                }
 
-               // if (ExecutionContext.getScopedObjects().containsKey(name)) {
-               // // returns cached instance
-               // Object obj = ExecutionContext.getScopedObjects().get(name);
-               // if (log.isTraceEnabled())
-               // log.trace("Return cached scoped object " + obj);
-               // return obj;
-               // } else {
-               // // creates instance
-               // Object obj = objectFactory.getObject();
-               // ExecutionContext.getScopedObjects().put(name, obj);
-               // if (log.isTraceEnabled())
-               // log.trace("Created regular scoped object " + obj);
-               // return obj;
-               // }
+               // see if the execution stack already knows the object
+               Object obj = executionStack.get().findScopedObject(name);
+               if (obj == null) {
+                       obj = objectFactory.getObject();
+                       if (obj instanceof ExecutionContext)
+                               throw new SlcException(
+                                               "Only one execution context can be defined per thread");
+                       if (obj instanceof ExecutionStack)
+                               throw new SlcException(
+                                               "Only one execution stack can be defined per thread");
+
+                       checkForbiddenClasses(obj);
+
+                       executionStack.get().addScopedObject(name, obj);
+               }
+               return obj;
+
        }
 
-       public String getConversationId() {
+       protected <T> T dealWithSpecialScopedObject(String name,
+                       ThreadLocal<T> threadLocal,
+                       ThreadLocal<String> threadLocalBeanName, T newObj) {
+
+               T obj = threadLocal.get();
+               if (obj == null) {
+                       obj = newObj;
+                       threadLocal.set(obj);
+                       threadLocalBeanName.set(name);
+                       if (log.isDebugEnabled()) {
+                               log.debug(obj.getClass() + " instantiated. (beanName=" + name
+                                               + ")");
+                       }
+                       return obj;
+               } else {
+                       throw new SlcException("Only one scoped " + obj.getClass()
+                                       + " can be defined per thread");
+               }
 
-               return executionContext.get().getUuid();
        }
 
-       public Boolean hasExecutionContext() {
-               return executionContext.get() != null;
+       protected void checkForbiddenClasses(Object obj) {
+               Class<?> clss = obj.getClass();
+               if (ExecutionFlow.class.isAssignableFrom(clss)
+                               || ExecutionSpec.class.isAssignableFrom(clss)) {
+                       throw new UnsupportedException("Execution scoped object", clss);
+               }
+       }
+
+       public String getConversationId() {
+               // TODO: is it the most relevant?
+               return executionContext.get().getUuid();
        }
 
        public void registerDestructionCallback(String name, Runnable callback) {
@@ -107,7 +117,8 @@ public class ExecutionScope implements Scope {
        }
 
        public Object remove(String name) {
-               log.debug("Remove object " + name);
+               if (log.isDebugEnabled())
+                       log.debug("Remove object " + name);
                throw new UnsupportedOperationException();
        }
 
diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/Executor.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/Executor.java
deleted file mode 100644 (file)
index cc46fd9..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.argeo.slc.core.execution;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.slc.execution.ExecutionContext;
-import org.argeo.slc.execution.ExecutionFlow;
-import org.argeo.slc.process.SlcExecution;
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.context.ApplicationEvent;
-import org.springframework.context.ApplicationListener;
-
-public class Executor implements ApplicationListener, ApplicationContextAware {
-       private final static Log log = LogFactory.getLog(Executor.class);
-
-       private ApplicationContext applicationContext;
-
-       public void onApplicationEvent(ApplicationEvent event) {
-               if (event instanceof NewExecutionEvent) {
-                       SlcExecution slcExecution = ((NewExecutionEvent) event)
-                                       .getSlcExecution();
-                       MapExecutionContext executionContext = new MapExecutionContext();
-                       ExecutionThread thread = new ExecutionThread(executionContext,
-                                       slcExecution);
-                       thread.start();
-               }
-
-       }
-
-       public void setApplicationContext(ApplicationContext applicationContext)
-                       throws BeansException {
-               this.applicationContext = applicationContext;
-       }
-
-       private class ExecutionThread extends Thread {
-               private final SlcExecution slcExecution;
-               private final ExecutionContext executionContext;
-
-               public ExecutionThread(MapExecutionContext executionContext,
-                               SlcExecution slcExecution) {
-                       super("SLC Execution #" + executionContext.getUuid());
-                       this.slcExecution = slcExecution;
-                       this.executionContext = executionContext;
-               }
-
-               public void run() {/*
-                       // Initialize from SlcExecution
-                       MapExecutionContext.registerExecutionContext(executionContext);
-                       MapExecutionContext.getVariables()
-                                       .putAll(slcExecution.getAttributes());
-
-                       try {
-                               log.info("Start execution #"
-                                               + MapExecutionContext.getExecutionUuid());
-                               String executionBean = slcExecution.getAttributes().get(
-                                               "slc.flows");
-                               ExecutionFlow main = (ExecutionFlow) applicationContext
-                                               .getBean(executionBean);
-                               main.execute();
-                       } catch (Exception e) {
-                               log.error("Execution " + executionContext.getUuid()
-                                               + " failed.", e);
-                       } finally {
-                               applicationContext.publishEvent(new ExecutionFinishedEvent(
-                                               this, executionContext));
-                       }
-*/
-               }
-       }
-
-}
index 361cede76ee3e17979433316a748e0495e056ef6..0debe45fbd857da89c54fdf61c8f79b21935c4f4 100644 (file)
@@ -120,8 +120,12 @@ public class FileExecutionResources implements ExecutionResources {
 
                if (withExecutionSubdirectory) {
                        Assert.notNull(executionContext, "execution context is null");
-                       String path = baseDir.getPath() + File.separator
-                                       + sdf().format(executionContext.getCreationDate())
+                       String path = baseDir.getPath()
+                                       + File.separator
+                                       + sdf()
+                                                       .format(
+                                                                       executionContext
+                                                                                       .getVariable(ExecutionContext.VAR_EXECUTION_CONTEXT_CREATION_DATE))
                                        + executionContext.getUuid();
                        File executionDir = new File(path);
 
index 2598dd73feb9feeffa4b23269d7aefc87f3e46fb..f9c5836c996146f84c40a716e3ce649227e4c46d 100644 (file)
@@ -30,12 +30,6 @@ public class InstantiationPostProcessor extends
                return true;
        }
 
-       @Override
-       public Object postProcessBeforeInitialization(Object bean, String beanName)
-                       throws BeansException {
-               return bean;
-       }
-
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName)
                        throws BeansException {
index 2dc9b867c01595d5aa90b69dce60f3a48b3bead2..564acab2219b26357558150013456cfb0fffb019 100644 (file)
 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);
-
-       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 {
+       private final Map<String, Object> variables = Collections
+                       .synchronizedMap(new HashMap<String, Object>());
 
        private final String uuid;
 
-       private final Date creationDate = new Date();
-
        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) {
+               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;
-                               }
-                       }
-               }
-
-               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;
-       }
-
-       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;
-               }
-
-       }
 }
diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/NewExecutionEvent.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/NewExecutionEvent.java
deleted file mode 100644 (file)
index ce37fe8..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.argeo.slc.core.execution;
-
-import org.argeo.slc.process.SlcExecution;
-import org.springframework.context.ApplicationEvent;
-
-public class NewExecutionEvent extends ApplicationEvent {
-       static final long serialVersionUID = 012;
-
-       private final SlcExecution slcExecution;
-
-       public NewExecutionEvent(Object source, SlcExecution slcExecution) {
-               super(source);
-               this.slcExecution = slcExecution;
-       }
-
-       public SlcExecution getSlcExecution() {
-               return slcExecution;
-       }
-
-}
index a21f302463f50cca43d6f5f8baeea5c5d8f1ce48..8b3f6dbba4d742b269713c860522998a123d1b8f 100644 (file)
                scope="execution">
                <aop:scoped-proxy />
        </bean>
+       <bean id="executionStack" class="org.argeo.slc.core.execution.DefaultExecutionStack"
+               scope="execution">
+               <aop:scoped-proxy />
+       </bean>
 
        <bean id="instantiationManager" class="org.argeo.slc.core.execution.InstantiationManager" />
 
 
        <bean class="org.argeo.slc.core.execution.ExecutionParameterPostProcessor">
                <property name="executionContext" ref="executionContext" />
-               <property name="executionScope" ref="executionScope" />
-               <property name="instantiationManager" ref="instantiationManager" />
-       </bean>
-
-       <bean class="org.argeo.slc.core.execution.InstantiationPostProcessor">
                <property name="instantiationManager" ref="instantiationManager" />
        </bean>
 
        <bean class="org.argeo.slc.core.execution.ExecutionAspect">
+               <property name="executionStack" ref="executionStack" />
                <property name="executionContext" ref="executionContext" />
        </bean>
 
index ae0a1fd581f6dbd3147811142ee826446a7f5bf9..67aad4de5b44979eda3d5b80063fe98d700fdb99 100644 (file)
@@ -78,7 +78,7 @@ public class BasicExecutionFlowTest extends AbstractExecutionFlowTestCase {
                executionParameters.put("p6", "e6");\r
                executionParameters.put("p7", "e7");\r
                executionParameters.put("p8", "e8");\r
-               executionContext.addVariables(executionParameters);\r
+               addVariables(executionContext, executionParameters);\r
 \r
                ((ExecutionFlow) applicationContext.getBean("flowA")).run();\r
                validateTestResult((SimpleTestResult) applicationContext\r
@@ -98,7 +98,7 @@ public class BasicExecutionFlowTest extends AbstractExecutionFlowTestCase {
                executionParameters.put("p4", "e4");\r
                executionParameters.put("p5", "e5");\r
                executionParameters.put("p6", "e6");\r
-               executionContext.addVariables(executionParameters);\r
+               addVariables(executionContext, executionParameters);\r
 \r
                ((ExecutionFlow) applicationContext.getBean("flowA")).run();\r
                validateTestResult((SimpleTestResult) applicationContext\r
@@ -161,4 +161,10 @@ public class BasicExecutionFlowTest extends AbstractExecutionFlowTestCase {
                validateTestResult(res, TestStatus.FAILED);\r
                applicationContext.close();\r
        }\r
+\r
+       protected void addVariables(ExecutionContext executionContext,\r
+                       Map<String, String> vars) {\r
+               for (String key : vars.keySet())\r
+                       executionContext.setVariable(key, vars.get(key));\r
+       }\r
 }\r
index c23fc363ceaf975f6a77961ae5d903587f23ad49..cc77aacfea0e974e5da466bdcc1296ab87ab7388 100644 (file)
@@ -1,35 +1,15 @@
 package org.argeo.slc.execution;\r
 \r
-import java.util.Date;\r
-import java.util.Map;\r
-\r
 public interface ExecutionContext {\r
-       public final static String VAR_PROCESS_ID = "slcVar.process.id";\r
        public final static String VAR_EXECUTION_CONTEXT_ID = "slcVar.executionContext.id";\r
+       public final static String VAR_EXECUTION_CONTEXT_CREATION_DATE = "slcVar.executionContext.creationDate";\r
        public final static String VAR_FLOW_ID = "slcVar.flow.id";\r
        public final static String VAR_FLOW_NAME = "slcVar.flow.name";\r
 \r
-       /**\r
-        * @param name\r
-        * @return null if no object is found\r
-        */\r
-       public Object findScopedObject(String name);\r
-\r
-       public void addScopedObject(String name, Object obj);\r
-\r
        public String getUuid();\r
 \r
-       public void enterFlow(ExecutionFlow executionFlow);\r
-\r
-       public void leaveFlow(ExecutionFlow executionFlow);\r
-\r
+       /** @return the variable value, or <code>null</code> if not found. */\r
        public Object getVariable(String key);\r
 \r
-       public Object findVariable(String key);\r
-\r
-       // TODO: replace with setVariable(String Key, Object value)\r
-       public void addVariables(\r
-                       Map<? extends String, ? extends Object> variablesToAdd);\r
-\r
-       public Date getCreationDate();\r
+       public void setVariable(String key, Object value);\r
 }\r
diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStack.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStack.java
new file mode 100644 (file)
index 0000000..48c7a94
--- /dev/null
@@ -0,0 +1,22 @@
+package org.argeo.slc.execution;
+
+public interface ExecutionStack {
+       /**
+        * @param name
+        * @return null if no object is found
+        */
+       public Object findScopedObject(String name);
+
+       public void addScopedObject(String name, Object obj);
+
+       public void enterFlow(ExecutionFlow executionFlow);
+
+       /** @return internal stack level UUID. */
+       public String getCurrentStackLevelUuid();
+
+       public Integer getStackSize();
+
+       public void leaveFlow(ExecutionFlow executionFlow);
+
+       Object findLocalVariable(String key);
+}
diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStackLevel.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStackLevel.java
new file mode 100644 (file)
index 0000000..790404b
--- /dev/null
@@ -0,0 +1,14 @@
+package org.argeo.slc.execution;
+
+import java.util.Map;
+
+public interface ExecutionStackLevel {
+       public ExecutionFlow getExecutionFlow();
+
+       public Map<String, Object> getScopedObjects();
+
+       public String getUuid();
+
+       public Map<String, Object> getLocalVariables();
+
+}
index 1dde56029ff2f38878a676b731fb86711f014dea..2d3ce046522023ecee79841ade540b5aadf0b603 100644 (file)
@@ -22,9 +22,11 @@ import org.osgi.util.tracker.ServiceTracker;
 import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.InitializingBean;
 
-public class OsgiExecutionModulesManager extends AbstractExecutionModulesManager implements
-               InitializingBean, DisposableBean {
-       private final static Log log = LogFactory.getLog(OsgiExecutionModulesManager.class);
+public class OsgiExecutionModulesManager extends
+               AbstractExecutionModulesManager implements InitializingBean,
+               DisposableBean {
+       private final static Log log = LogFactory
+                       .getLog(OsgiExecutionModulesManager.class);
 
        private BundlesManager bundlesManager;
        private ServiceTracker executionContexts;
@@ -169,9 +171,6 @@ public class OsgiExecutionModulesManager extends AbstractExecutionModulesManager
                String moduleName = realizedFlow.getModuleName();
                String moduleVersion = realizedFlow.getModuleVersion();
 
-               ExecutionContext executionContext = findExecutionContext(moduleName,
-                               moduleVersion);
-
                // Check whether a descriptor converter is published by this module
                ExecutionFlowDescriptorConverter descriptorConverter = findExecutionFlowDescriptorConverter(
                                moduleName, moduleVersion);
@@ -184,7 +183,10 @@ public class OsgiExecutionModulesManager extends AbstractExecutionModulesManager
                        variablesToAdd = defaultDescriptorConverter
                                        .convertValues(realizedFlow.getFlowDescriptor());
 
-               executionContext.addVariables(variablesToAdd);
+               ExecutionContext executionContext = findExecutionContext(moduleName,
+                               moduleVersion);
+               for (String key : variablesToAdd.keySet())
+                       executionContext.setVariable(key, variablesToAdd.get(key));
 
                ExecutionFlow flow = findExecutionFlow(moduleName, moduleVersion,
                                realizedFlow.getFlowDescriptor().getName());