From 08aa02f96eb32a6e1f0cc001113df9311a618eb9 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Tue, 30 Jun 2009 14:16:48 +0000 Subject: [PATCH] Refactor runtime git-svn-id: https://svn.argeo.org/slc/trunk@2631 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../core/execution/DefaultExecutionFlow.java | 12 +- .../core/execution/DefaultExecutionStack.java | 128 +++++++ .../slc/core/execution/ExecutionAspect.java | 85 +++-- .../execution/ExecutionFinishedEvent.java | 20 -- .../ExecutionParameterPostProcessor.java | 336 +++++++++++------- .../slc/core/execution/ExecutionScope.java | 151 ++++---- .../argeo/slc/core/execution/Executor.java | 72 ---- .../execution/FileExecutionResources.java | 8 +- .../execution/InstantiationPostProcessor.java | 6 - .../core/execution/MapExecutionContext.java | 151 +------- .../slc/core/execution/NewExecutionEvent.java | 20 -- .../org/argeo/slc/core/execution/spring.xml | 10 +- .../execution/BasicExecutionFlowTest.java | 10 +- .../argeo/slc/execution/ExecutionContext.java | 26 +- .../argeo/slc/execution/ExecutionStack.java | 22 ++ .../slc/execution/ExecutionStackLevel.java | 14 + .../slc/osgi/OsgiExecutionModulesManager.java | 16 +- 17 files changed, 546 insertions(+), 541 deletions(-) create mode 100644 runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionStack.java delete mode 100644 runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionFinishedEvent.java delete mode 100644 runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/Executor.java delete mode 100644 runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/NewExecutionEvent.java create mode 100644 runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStack.java create mode 100644 runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStackLevel.java diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlow.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlow.java index 497e6520e..7fd07fe77 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlow.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionFlow.java @@ -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, ResourceLoaderAware { + BeanNameAware, StructureAware { private final ExecutionSpec executionSpec; private String name = null; @@ -31,8 +28,6 @@ public class DefaultExecutionFlow implements ExecutionFlow, InitializingBean, private String path; private StructureRegistry 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 index 000000000..9bdf31af1 --- /dev/null +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionStack.java @@ -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 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; + } + + } +} diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionAspect.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionAspect.java index 29942817d..0f091fcb8 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionAspect.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionAspect.java @@ -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 inModuleExecution = new ThreadLocal() { - 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 index fac5b5c66..000000000 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionFinishedEvent.java +++ /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; - } - -} diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java index 1bdd4f29a..5b28534ba 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java @@ -5,57 +5,34 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Properties; import java.util.Set; 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.springframework.beans.BeansException; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyValue; import org.springframework.beans.PropertyValues; +import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; -import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import org.springframework.beans.factory.config.TypedStringValue; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.support.ManagedSet; import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; public class ExecutionParameterPostProcessor extends InstantiationAwareBeanPostProcessorAdapter { private final static Log log = LogFactory .getLog(ExecutionParameterPostProcessor.class); - - private ExecutionContext executionContext; - - private ExecutionScope executionScope; + private ExecutionContext executionContext; private InstantiationManager instantiationManager; - - public InstantiationManager getInstantiationManager() { - return instantiationManager; - } - - public void setInstantiationManager( - InstantiationManager instantiationManager) { - this.instantiationManager = instantiationManager; - } - - public void setExecutionScope(ExecutionScope executionScope) { - this.executionScope = executionScope; - } - - public ExecutionContext getExecutionContext() { - return executionContext; - } - - public void setExecutionContext(ExecutionContext executionContext) { - this.executionContext = executionContext; - } private String placeholderPrefix = "@{"; private String placeholderSuffix = "}"; @@ -66,26 +43,138 @@ public class ExecutionParameterPostProcessor extends PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { - //TODO: resolve at execution only if scope is execution - //TODO: deal with placeholders in RuntimeBeanReference and RuntimeBeanNameReference - + // TODO: resolve at execution only if scope is execution + // TODO: deal with placeholders in RuntimeBeanReference and + // RuntimeBeanNameReference + MutablePropertyValues newPvs = new MutablePropertyValues(); - + boolean changesOccured = false; - - CustomPpc ppc = new CustomPpc(beanName); - - for(PropertyValue pv : pvs.getPropertyValues()) { - Object convertedValue = ppc.resolveValue(pv.getValue()); + + for (PropertyValue pv : pvs.getPropertyValues()) { + Object convertedValue = resolveValue(beanName, bean, pv.getValue()); newPvs.addPropertyValue(new PropertyValue(pv, convertedValue)); - if(convertedValue != pv.getValue()) { + if (convertedValue != pv.getValue()) { changesOccured = true; } } - + return changesOccured ? newPvs : pvs; } + @Override + public boolean postProcessAfterInstantiation(Object bean, String beanName) + throws BeansException { + if (bean instanceof ExecutionFlow) + instantiationManager.flowInitializationStarted( + (ExecutionFlow) bean, beanName); + return true; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + if (bean instanceof ExecutionFlow) + instantiationManager.flowInitializationFinished( + (ExecutionFlow) bean, beanName); + return bean; + } + + protected String resolvePlaceholder(Object bean, String placeholder) { + if (instantiationManager.isInFlowInitialization()) + return instantiationManager.getInitializingFlowParameter( + placeholder).toString(); + + else {// execution + log.debug("Bean class: " + bean.getClass()); + // next call fail if no execution context available + Object obj = executionContext.getVariable(placeholder); + if (obj != null) { + return obj.toString(); + } + } + + return null; + } + + @SuppressWarnings(value = { "unchecked" }) + public Object resolveValue(String beanName, Object bean, Object value) { + if (value instanceof TypedStringValue) { + TypedStringValue tsv = (TypedStringValue) value; + String originalValue = tsv.getValue(); + + String convertedValue = resolveString(beanName, bean, originalValue); + return convertedValue.equals(originalValue) ? value + : new TypedStringValue(convertedValue); + } else if (value instanceof String) { + String originalValue = value.toString(); + String convertedValue = resolveString(beanName, bean, originalValue); + return convertedValue.equals(originalValue) ? value + : convertedValue; + } else if (value instanceof ManagedMap) { + Map mapVal = (Map) value; + + Map newContent = new ManagedMap(); + boolean entriesModified = false; + for (Iterator it = mapVal.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + Object key = entry.getKey(); + int keyHash = (key != null ? key.hashCode() : 0); + Object newKey = resolveValue(beanName, bean, key); + int newKeyHash = (newKey != null ? newKey.hashCode() : 0); + Object val = entry.getValue(); + Object newVal = resolveValue(beanName, bean, val); + newContent.put(newKey, newVal); + entriesModified = entriesModified + || (newVal != val || newKey != key || newKeyHash != keyHash); + } + + return entriesModified ? newContent : value; + } else if (value instanceof ManagedList) { + List listVal = (List) value; + List newContent = new ManagedList(); + boolean valueModified = false; + + for (int i = 0; i < listVal.size(); i++) { + Object elem = listVal.get(i); + Object newVal = resolveValue(beanName, bean, elem); + newContent.add(newVal); + if (!ObjectUtils.nullSafeEquals(newVal, elem)) { + valueModified = true; + } + } + return valueModified ? newContent : value; + } else if (value instanceof ManagedSet) { + Set setVal = (Set) value; + Set newContent = new ManagedSet(); + boolean entriesModified = false; + for (Iterator it = setVal.iterator(); it.hasNext();) { + Object elem = it.next(); + int elemHash = (elem != null ? elem.hashCode() : 0); + Object newVal = resolveValue(beanName, bean, elem); + int newValHash = (newVal != null ? newVal.hashCode() : 0); + newContent.add(newVal); + entriesModified = entriesModified + || (newVal != elem || newValHash != elemHash); + } + return entriesModified ? newContent : value; + } else { + //log.debug(beanName + ": " + value.getClass() + " : " + value); + return value; + } + + } + + private String resolveString(String beanName, Object bean, String strVal) { + String value = parseStringValue(bean, strVal, new HashSet()); + + if (value == null) + throw new SlcException("Could not resolve placeholder '" + strVal + + "' in bean '" + beanName + "'"); + + return (value.equals(nullValue) ? null : value); + } + public void setPlaceholderPrefix(String placeholderPrefix) { this.placeholderPrefix = placeholderPrefix; } @@ -97,108 +186,91 @@ public class ExecutionParameterPostProcessor extends public void setNullValue(String nullValue) { this.nullValue = nullValue; } - - private class CustomPpc extends PropertyPlaceholderConfigurer { - private final Properties props; - String beanName; - - public CustomPpc(String beanName) { - super(); - this.props = new Properties(); - this.beanName = beanName; - setPlaceholderPrefix(placeholderPrefix); - setPlaceholderSuffix(placeholderSuffix); - setSystemPropertiesMode(SYSTEM_PROPERTIES_MODE_NEVER); - } - /** Public access to the internals of PropertyPlaceholderConfigurer*/ - public String resolveString(String strVal) { - String value = parseStringValue(strVal, this.props, - new HashSet()); - return (value.equals(nullValue) ? null : value); - } - - public Object resolveValue(Object value) { - if (value instanceof TypedStringValue) { - TypedStringValue tsv = (TypedStringValue) value; - String originalValue = tsv.getValue(); - - String convertedValue = resolveString(originalValue); - return convertedValue.equals(originalValue) ? value : new TypedStringValue(convertedValue); - } - else if (value instanceof String) { - String originalValue = value.toString(); - String convertedValue = resolveString(originalValue); - return convertedValue.equals(originalValue) ? value : convertedValue; - } - else if (value instanceof ManagedMap) { - Map mapVal = (Map) value; - - Map newContent = new ManagedMap(); - boolean entriesModified = false; - for (Iterator it = mapVal.entrySet().iterator(); it.hasNext();) { - Map.Entry entry = (Map.Entry) it.next(); - Object key = entry.getKey(); - int keyHash = (key != null ? key.hashCode() : 0); - Object newKey = resolveValue(key); - int newKeyHash = (newKey != null ? newKey.hashCode() : 0); - Object val = entry.getValue(); - Object newVal = resolveValue(val); - newContent.put(newKey, newVal); - entriesModified = entriesModified || (newVal != val || newKey != key || newKeyHash != keyHash); + public void setInstantiationManager( + InstantiationManager instantiationManager) { + this.instantiationManager = instantiationManager; + } + + public void setExecutionContext(ExecutionContext executionContext) { + this.executionContext = executionContext; + } + + // + // Following methods hacked from the internals of + // PropertyPlaceholderConfigurer + // + + protected String parseStringValue(Object bean, String strVal, + Set visitedPlaceholders) + throws BeanDefinitionStoreException { + + StringBuffer buf = new StringBuffer(strVal); + + int startIndex = strVal.indexOf(placeholderPrefix); + while (startIndex != -1) { + int endIndex = findPlaceholderEndIndex(buf, startIndex); + if (endIndex != -1) { + String placeholder = buf.substring(startIndex + + placeholderPrefix.length(), endIndex); + if (!visitedPlaceholders.add(placeholder)) { + throw new BeanDefinitionStoreException( + "Circular placeholder reference '" + placeholder + + "' in property definitions"); } - - return entriesModified ? newContent : value; - } - else if (value instanceof ManagedList) { - List listVal = (List) value; - List newContent = new ManagedList(); - boolean valueModified = false; - - for (int i = 0; i < listVal.size(); i++) { - Object elem = listVal.get(i); - Object newVal = resolveValue(elem); - newContent.add(newVal); - if (!ObjectUtils.nullSafeEquals(newVal, elem)) { - valueModified = true; + // Recursive invocation, parsing placeholders contained in + // the placeholder key. + placeholder = parseStringValue(bean, placeholder, + visitedPlaceholders); + // Now obtain the value for the fully resolved key... + String propVal = resolvePlaceholder(bean, placeholder); + if (propVal != null) { + // Recursive invocation, parsing placeholders contained + // in the + // previously resolved placeholder value. + propVal = parseStringValue(bean, propVal, + visitedPlaceholders); + buf.replace(startIndex, endIndex + + placeholderSuffix.length(), propVal); + if (log.isTraceEnabled()) { + log.trace("Resolved placeholder '" + placeholder + "'"); } - } - return valueModified ? newContent : value; - } - else if (value instanceof ManagedSet) { - Set setVal = (Set) value; - Set newContent = new ManagedSet(); - boolean entriesModified = false; - for (Iterator it = setVal.iterator(); it.hasNext();) { - Object elem = it.next(); - int elemHash = (elem != null ? elem.hashCode() : 0); - Object newVal = resolveValue(elem); - int newValHash = (newVal != null ? newVal.hashCode() : 0); - newContent.add(newVal); - entriesModified = entriesModified || (newVal != elem || newValHash != elemHash); - } - return entriesModified ? newContent : value; + startIndex = buf.indexOf(placeholderPrefix, startIndex + + propVal.length()); + } else { + throw new BeanDefinitionStoreException( + "Could not resolve placeholder '" + placeholder + + "'"); + } + visitedPlaceholders.remove(placeholder); + } else { + startIndex = -1; } - else { - return value; - } } - @Override - protected String resolvePlaceholder(String placeholder, Properties props) { - if ((executionScope != null) - && (executionScope.hasExecutionContext())) { - Object obj = executionContext.findVariable(placeholder); - if(obj != null) { - return obj.toString(); + return buf.toString(); + } + + private int findPlaceholderEndIndex(CharSequence buf, int startIndex) { + int index = startIndex + placeholderPrefix.length(); + int withinNestedPlaceholder = 0; + while (index < buf.length()) { + if (StringUtils.substringMatch(buf, index, placeholderSuffix)) { + if (withinNestedPlaceholder > 0) { + withinNestedPlaceholder--; + index = index + placeholderSuffix.length(); + } else { + return index; } + } else if (StringUtils + .substringMatch(buf, index, placeholderPrefix)) { + withinNestedPlaceholder++; + index = index + placeholderPrefix.length(); + } else { + index++; } - if (instantiationManager.isInFlowInitialization()) - return instantiationManager.getInitializingFlowParameter( - placeholder).toString(); - else - throw new SlcException("Could not resolve placeholder '" - + placeholder + "' in bean '" + beanName + "'"); } + return -1; } + } diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionScope.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionScope.java index a24046a99..2cbd70897 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionScope.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionScope.java @@ -1,104 +1,114 @@ 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 = new ThreadLocal(); + private final ThreadLocal executionStack = new ThreadLocal(); + public final ThreadLocal executionStackBeanName = new ThreadLocal(); - public final ThreadLocal executionContextBeanName = new ThreadLocal(); + private final ThreadLocal executionContext = new ThreadLocal(); + private final ThreadLocal executionContextBeanName = new ThreadLocal(); 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 dealWithSpecialScopedObject(String name, + ThreadLocal threadLocal, + ThreadLocal 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 index cc46fd97c..000000000 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/Executor.java +++ /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)); - } -*/ - } - } - -} diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/FileExecutionResources.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/FileExecutionResources.java index 361cede76..0debe45fb 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/FileExecutionResources.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/FileExecutionResources.java @@ -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); diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/InstantiationPostProcessor.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/InstantiationPostProcessor.java index 2598dd73f..f9c5836c9 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/InstantiationPostProcessor.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/InstantiationPostProcessor.java @@ -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 { diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/MapExecutionContext.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/MapExecutionContext.java index 2dc9b867c..564acab22 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/MapExecutionContext.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/MapExecutionContext.java @@ -1,168 +1,35 @@ 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 stack = new Stack(); - - // TODO: make it thread safe? - private final Map variables = new HashMap(); +public class MapExecutionContext implements + ExecutionContext { + private final Map variables = Collections + .synchronizedMap(new HashMap()); 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 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 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 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; - } - - } } 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 index ce37fe852..000000000 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/NewExecutionEvent.java +++ /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; - } - -} diff --git a/runtime/org.argeo.slc.core/src/main/resources/org/argeo/slc/core/execution/spring.xml b/runtime/org.argeo.slc.core/src/main/resources/org/argeo/slc/core/execution/spring.xml index a21f30246..8b3f6dbba 100644 --- a/runtime/org.argeo.slc.core/src/main/resources/org/argeo/slc/core/execution/spring.xml +++ b/runtime/org.argeo.slc.core/src/main/resources/org/argeo/slc/core/execution/spring.xml @@ -35,6 +35,10 @@ scope="execution"> + + + @@ -43,15 +47,11 @@ - - - - - + diff --git a/runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/BasicExecutionFlowTest.java b/runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/BasicExecutionFlowTest.java index ae0a1fd58..67aad4de5 100644 --- a/runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/BasicExecutionFlowTest.java +++ b/runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/BasicExecutionFlowTest.java @@ -78,7 +78,7 @@ public class BasicExecutionFlowTest extends AbstractExecutionFlowTestCase { executionParameters.put("p6", "e6"); executionParameters.put("p7", "e7"); executionParameters.put("p8", "e8"); - executionContext.addVariables(executionParameters); + addVariables(executionContext, executionParameters); ((ExecutionFlow) applicationContext.getBean("flowA")).run(); validateTestResult((SimpleTestResult) applicationContext @@ -98,7 +98,7 @@ public class BasicExecutionFlowTest extends AbstractExecutionFlowTestCase { executionParameters.put("p4", "e4"); executionParameters.put("p5", "e5"); executionParameters.put("p6", "e6"); - executionContext.addVariables(executionParameters); + addVariables(executionContext, executionParameters); ((ExecutionFlow) applicationContext.getBean("flowA")).run(); validateTestResult((SimpleTestResult) applicationContext @@ -161,4 +161,10 @@ public class BasicExecutionFlowTest extends AbstractExecutionFlowTestCase { validateTestResult(res, TestStatus.FAILED); applicationContext.close(); } + + protected void addVariables(ExecutionContext executionContext, + Map vars) { + for (String key : vars.keySet()) + executionContext.setVariable(key, vars.get(key)); + } } diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionContext.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionContext.java index c23fc363c..cc77aacfe 100644 --- a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionContext.java +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionContext.java @@ -1,35 +1,15 @@ package org.argeo.slc.execution; -import java.util.Date; -import java.util.Map; - public interface ExecutionContext { - public final static String VAR_PROCESS_ID = "slcVar.process.id"; public final static String VAR_EXECUTION_CONTEXT_ID = "slcVar.executionContext.id"; + public final static String VAR_EXECUTION_CONTEXT_CREATION_DATE = "slcVar.executionContext.creationDate"; public final static String VAR_FLOW_ID = "slcVar.flow.id"; public final static String VAR_FLOW_NAME = "slcVar.flow.name"; - /** - * @param name - * @return null if no object is found - */ - public Object findScopedObject(String name); - - public void addScopedObject(String name, Object obj); - public String getUuid(); - public void enterFlow(ExecutionFlow executionFlow); - - public void leaveFlow(ExecutionFlow executionFlow); - + /** @return the variable value, or null if not found. */ public Object getVariable(String key); - public Object findVariable(String key); - - // TODO: replace with setVariable(String Key, Object value) - public void addVariables( - Map variablesToAdd); - - public Date getCreationDate(); + public void setVariable(String key, Object value); } 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 index 000000000..48c7a94a4 --- /dev/null +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStack.java @@ -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 index 000000000..790404b58 --- /dev/null +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStackLevel.java @@ -0,0 +1,14 @@ +package org.argeo.slc.execution; + +import java.util.Map; + +public interface ExecutionStackLevel { + public ExecutionFlow getExecutionFlow(); + + public Map getScopedObjects(); + + public String getUuid(); + + public Map getLocalVariables(); + +} diff --git a/runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/OsgiExecutionModulesManager.java b/runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/OsgiExecutionModulesManager.java index 1dde56029..2d3ce0465 100644 --- a/runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/OsgiExecutionModulesManager.java +++ b/runtime/org.argeo.slc.support.osgi/src/main/java/org/argeo/slc/osgi/OsgiExecutionModulesManager.java @@ -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()); -- 2.39.2