]> git.argeo.org Git - gpl/argeo-slc.git/commitdiff
Move SLC Execution to runtime
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 21 Feb 2009 13:03:28 +0000 (13:03 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 21 Feb 2009 13:03:28 +0000 (13:03 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@2159 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

35 files changed:
runtime/org.argeo.slc.execution/.classpath [new file with mode: 0644]
runtime/org.argeo.slc.execution/.project [new file with mode: 0644]
runtime/org.argeo.slc.execution/.springBeans [new file with mode: 0644]
runtime/org.argeo.slc.execution/pom.xml [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/AbstractSpecAttribute.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ConsoleContextDescriber.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ContextDescriber.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/EfLauncher.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionAspect.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionContext.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionFinishedEvent.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionFlow.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionFlowFactory.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionParameterPostProcessor.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionRegister.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionScope.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionSpec.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionSpecAttribute.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionTargetSource.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/Executor.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/InstantiationPostProcessor.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/NewExecutionEvent.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/RefSpecAttribute.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/SimpleExecutionFlow.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/SimpleExecutionSpec.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/SimpleSpecAttribute.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/tasks/Echo.java [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/slc/conf/BasicExecutionFlow.groovy [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/slc/conf/basic.xml [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/slc/conf/common.xml [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/slc/conf/main.xml [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/slc/conf/slc.properties [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/slc/conf/test.xml [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/slc/conf/testCases/basic-001.xml [new file with mode: 0644]
runtime/org.argeo.slc.execution/src/slc/conf/testCases/basic-002.xml [new file with mode: 0644]

diff --git a/runtime/org.argeo.slc.execution/.classpath b/runtime/org.argeo.slc.execution/.classpath
new file mode 100644 (file)
index 0000000..16f01e2
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" output="target/classes" path="src/main/java"/>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+       <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+       <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/runtime/org.argeo.slc.execution/.project b/runtime/org.argeo.slc.execution/.project
new file mode 100644 (file)
index 0000000..63e0d74
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>argeo.slc.executionflow</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.maven.ide.eclipse.maven2Builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.springframework.ide.eclipse.core.springbuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.springframework.ide.eclipse.core.springnature</nature>
+               <nature>org.maven.ide.eclipse.maven2Nature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/runtime/org.argeo.slc.execution/.springBeans b/runtime/org.argeo.slc.execution/.springBeans
new file mode 100644 (file)
index 0000000..07dddcb
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beansProjectDescription>
+       <version>1</version>
+       <pluginVersion><![CDATA[2.2.1.v200811281800]]></pluginVersion>
+       <configSuffixes>
+               <configSuffix><![CDATA[xml]]></configSuffix>
+       </configSuffixes>
+       <enableImports><![CDATA[true]]></enableImports>
+       <configs>
+               <config>src/slc/conf/main.xml</config>
+               <config>src/slc/conf/testCases/basic-001.xml</config>
+               <config>src/slc/conf/testCases/basic-002.xml</config>
+               <config>src/slc/conf/basic.xml</config>
+               <config>src/slc/conf/common.xml</config>
+               <config>src/slc/conf/test.xml</config>
+       </configs>
+       <configSets>
+       </configSets>
+</beansProjectDescription>
diff --git a/runtime/org.argeo.slc.execution/pom.xml b/runtime/org.argeo.slc.execution/pom.xml
new file mode 100644 (file)
index 0000000..1025a48
--- /dev/null
@@ -0,0 +1,56 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.argeo.slc</groupId>
+               <artifactId>argeo-slc</artifactId>
+               <version>0.11.3-SNAPSHOT</version>
+               <relativePath>../../org.argeo.slc</relativePath>
+       </parent>
+       <groupId>org.argeo.slc.sandbox</groupId>
+       <artifactId>org.argeo.slc.sandbox.executionflow</artifactId>
+       <name>SLC Sandbox Execution Flow</name>
+       <packaging>jar</packaging>
+       <properties></properties>
+       <build>
+               <plugins>
+                       <plugin>
+                               <artifactId>maven-jar-plugin</artifactId>
+                       </plugin>
+               </plugins>
+       </build>
+       <dependencies>
+
+
+               <dependency>
+                       <groupId>org.argeo.slc.runtime</groupId>
+                       <artifactId>org.argeo.slc.support.simple</artifactId>
+               </dependency>
+
+               <dependency>
+                       <groupId>org.aspectj</groupId>
+                       <artifactId>com.springsource.org.aspectj.runtime</artifactId>
+                       <version>1.6.2.RELEASE</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.aspectj</groupId>
+                       <artifactId>com.springsource.org.aspectj.weaver</artifactId>
+                       <version>1.6.2.RELEASE</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.codehaus.groovy</groupId>
+                       <artifactId>com.springsource.org.codehaus.groovy</artifactId>
+                       <version>1.5.7</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.beanshell</groupId>
+                       <artifactId>com.springsource.bsh</artifactId>
+                       <version>2.0.0.b4</version>
+               </dependency>
+               <dependency>
+                       <groupId>net.sourceforge.cglib</groupId>
+                       <artifactId>com.springsource.net.sf.cglib</artifactId>
+                       <version>2.1.3</version>
+               </dependency>
+       </dependencies>
+</project>
\ No newline at end of file
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/AbstractSpecAttribute.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/AbstractSpecAttribute.java
new file mode 100644 (file)
index 0000000..74c2a6b
--- /dev/null
@@ -0,0 +1,14 @@
+package org.argeo.slc.execution;
+
+public abstract class AbstractSpecAttribute implements ExecutionSpecAttribute {
+       private Boolean isParameter = true;
+
+       public Boolean getIsParameter() {
+               return isParameter;
+       }
+
+       public void setIsParameter(Boolean isParameter) {
+               this.isParameter = isParameter;
+       }
+
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ConsoleContextDescriber.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ConsoleContextDescriber.java
new file mode 100644 (file)
index 0000000..43f5443
--- /dev/null
@@ -0,0 +1,39 @@
+package org.argeo.slc.execution;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.PropertyValue;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+
+public class ConsoleContextDescriber implements ContextDescriber {
+       private final static Log log = LogFactory
+                       .getLog(ConsoleContextDescriber.class);
+
+       public void describeContext(BeanDefinitionRegistry registry) {
+               String[] beanNames = registry.getBeanDefinitionNames();
+               for (String beanName : beanNames) {
+                       log("\n## BEAN: " + beanName);
+                       describeBean(registry.getBeanDefinition(beanName));
+               }
+       }
+
+       public void describeBean(BeanDefinition beanDefinition) {
+               log("BeanDefinition class: "+beanDefinition.getClass());
+               log("# ATTRIBUTES");
+               for(String attr:beanDefinition.attributeNames()){
+                       log(attr+"="+beanDefinition.getAttribute(attr));
+               }
+               log("# PROPERTIES");
+               MutablePropertyValues pValues = beanDefinition.getPropertyValues();
+               for (PropertyValue pv : pValues.getPropertyValues()) {
+                       log(pv.getName() + "= (" + pv.getValue().getClass() + ") "
+                                       + pv.getValue());
+               }
+       }
+
+       protected void log(Object obj){
+               System.out.println(obj);
+       }
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ContextDescriber.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ContextDescriber.java
new file mode 100644 (file)
index 0000000..289a537
--- /dev/null
@@ -0,0 +1,9 @@
+package org.argeo.slc.execution;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+
+public interface ContextDescriber {
+       public void describeContext(BeanDefinitionRegistry registry);
+       public void describeBean(BeanDefinition bd);
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/EfLauncher.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/EfLauncher.java
new file mode 100644 (file)
index 0000000..56d89ec
--- /dev/null
@@ -0,0 +1,120 @@
+package org.argeo.slc.execution;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.slc.logging.Log4jUtils;
+import org.argeo.slc.process.SlcExecution;
+import org.springframework.beans.MutablePropertyValues;
+import org.springframework.beans.PropertyValue;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
+import org.springframework.beans.factory.xml.XmlBeanDefinitionParser;
+import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.support.FileSystemXmlApplicationContext;
+import org.springframework.context.support.GenericApplicationContext;
+
+public class EfLauncher implements ApplicationListener {
+       private final Log log;
+
+       private boolean running = false;
+
+       public EfLauncher() {
+               Properties userProperties = new Properties();
+               FileInputStream in = null;
+               try {
+                       in = new FileInputStream("src/slc/conf/slc.properties");
+                       userProperties.load(in);
+               } catch (Exception e) {
+                       e.printStackTrace();
+               } finally {
+                       IOUtils.closeQuietly(in);
+               }
+
+               // Set as System properties
+               for (Object obj : userProperties.keySet()) {
+                       String key = obj.toString();
+                       System.setProperty(key, userProperties.getProperty(key));
+               }
+
+               // Logging
+               System.setProperty("log4j.defaultInitOverride", "true");
+
+               Log4jUtils.initLog4j(null);
+               log = LogFactory.getLog(EfLauncher.class);
+       }
+
+       public void launch(String script) {
+               // describe(script);
+
+               GenericApplicationContext context = new GenericApplicationContext();
+               XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
+               reader.loadBeanDefinitions(script);
+               // FileSystemXmlApplicationContext context = new
+               // FileSystemXmlApplicationContext(
+               // script);
+               context.addApplicationListener(this);
+               context.refresh();
+               context.start();
+               log.debug("Context initialized");
+
+               SlcExecution slcExecution = new SlcExecution();
+               slcExecution.getAttributes().put("slc.flows", "main");
+
+               running = true;
+               context.publishEvent(new NewExecutionEvent(this, slcExecution));
+
+               synchronized (this) {
+                       while (running)
+                               try {
+                                       wait();
+                               } catch (InterruptedException e) {
+                                       // silent
+                               }
+               }
+       }
+
+       public synchronized boolean isRunning() {
+               return running;
+       }
+
+       public synchronized void setRunning(boolean running) {
+               this.running = running;
+       }
+
+       public void onApplicationEvent(ApplicationEvent event) {
+               if (event instanceof ExecutionFinishedEvent) {
+                       ExecutionContext executionContext = ((ExecutionFinishedEvent) event)
+                                       .getExecutionContext();
+                       log.debug("Execution " + executionContext.getUuid()
+                                       + " finished, stopping launcher...");
+                       synchronized (this) {
+                               running = false;
+                               notifyAll();
+                       }
+               }
+
+       }
+
+       public static void main(String[] args) {
+               String script = "file:src/slc/conf/main.xml";
+               new EfLauncher().launch(script);
+       }
+
+       private static void describe(String script) {
+               SimpleBeanDefinitionRegistry registry = new SimpleBeanDefinitionRegistry();
+               XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
+               reader.loadBeanDefinitions(script);
+               new ConsoleContextDescriber().describeContext(registry);
+       }
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionAspect.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionAspect.java
new file mode 100644 (file)
index 0000000..5a366cf
--- /dev/null
@@ -0,0 +1,37 @@
+package org.argeo.slc.execution;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.After;
+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 {
+       private static Log log = LogFactory.getLog(ExecutionAspect.class);
+
+       @Before("flowExecution()")
+       public void beforeFlow(JoinPoint jp) throws Throwable {
+               //log.debug("this " + jp.getThis().getClass());
+               //log.debug("target " + jp.getTarget().getClass());
+               // Thread.dumpStack();
+               ExecutionFlow executionFlow = (ExecutionFlow) jp.getTarget();
+               ExecutionContext.enterFlow(executionFlow);
+       }
+
+       @After("flowExecution()")
+       public void afterFlow(JoinPoint jp) throws Throwable {
+               //log.debug("this " + jp.getThis().getClass());
+               //log.debug("target " + jp.getTarget().getClass());
+               ExecutionFlow executionFlow = (ExecutionFlow) jp.getTarget();
+               ExecutionContext.leaveFlow(executionFlow);
+       }
+
+       @Pointcut("execution(void org.argeo.slc.execution.ExecutionFlow.execute())")
+       public void flowExecution() {
+       }
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionContext.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionContext.java
new file mode 100644 (file)
index 0000000..db8af23
--- /dev/null
@@ -0,0 +1,195 @@
+package org.argeo.slc.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.process.SlcExecution;
+import org.springframework.beans.factory.ObjectFactory;
+
+public class ExecutionContext {
+       private final static Log log = LogFactory.getLog(ExecutionContext.class);
+
+       private final static ThreadLocal<ExecutionContext> executionContext = new ThreadLocal<ExecutionContext>();
+
+       private final Stack<ExecutionFlowRuntime> stack = new Stack<ExecutionFlowRuntime>();
+
+       // TODO: make it thread safe?
+       private final Map<String, Object> variables = new HashMap<String, Object>();
+
+       private final String uuid = UUID.randomUUID().toString();
+
+       public static Map<String, Object> getVariables() {
+               if (executionContext.get() == null)
+                       return null;
+               return executionContext.get().variables;
+       }
+
+       public static ExecutionContext getCurrent() {
+               return executionContext.get();
+       }
+
+       public static String getExecutionUuid() {
+               if (executionContext.get() == null)
+                       return null;
+               return executionContext.get().getUuid();
+       }
+
+       public static void registerExecutionContext(ExecutionContext context) {
+               if (executionContext.get() != null)
+                       throw new SlcException("Context #" + executionContext.get().uuid
+                                       + " already registered.");
+               executionContext.set(context);
+       }
+
+       public static void enterFlow(ExecutionFlow executionFlow) {
+               Stack<ExecutionFlowRuntime> stack = executionContext.get().stack;
+
+               ExecutionFlowRuntime runtime = new ExecutionFlowRuntime(executionFlow);
+               stack.push(runtime);
+
+               if (log.isTraceEnabled())
+                       log.debug(depthSpaces(stack.size()) + "=> " + executionFlow + " #"
+                                       + getCurrentStackUuid() + ", depth=" + stack.size());
+
+               Map<String, ExecutionSpecAttribute> specAttrs = executionFlow
+                               .getExecutionSpec().getAttributes();
+               for (String key : specAttrs.keySet()) {
+                       ExecutionSpecAttribute esa = specAttrs.get(key);
+                       if (esa.getIsParameter()) {
+                               runtime.getLocalVariables().put(key,
+                                               executionFlow.getParameter(key));
+                               if (log.isTraceEnabled())
+                                       log.trace(depthSpaces(stack.size()) + "Add '" + key
+                                                       + "' as local variable.");
+                       }
+               }
+
+       }
+
+       public static Object getVariable(String key) {
+               Object obj = getWithCheck().findVariable(key);
+               if (obj == null)
+                       throw new SlcException("Variable '" + key + "' not found.");
+               return obj;
+       }
+
+       protected Object findVariable(String key) {
+               Object obj = null;
+               for (int i = stack.size() - 1; i >= 0; i--) {
+                       if (stack.get(i).getLocalVariables().containsKey(key)) {
+                               obj = stack.get(i).getLocalVariables().get(key);
+                               break;
+                       }
+               }
+
+               // Look into global execution variables
+               if (obj == null) {
+                       if (variables.containsKey(key))
+                               obj = variables.get(key);
+               }
+
+               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 static void leaveFlow(ExecutionFlow executionFlow) {
+               Stack<ExecutionFlowRuntime> stack = executionContext.get().stack;
+               if (log.isTraceEnabled())
+                       log.debug(depthSpaces(stack.size()) + "<= " + executionFlow + " #"
+                                       + getCurrentStackUuid() + ", depth=" + stack.size());
+
+               ExecutionFlowRuntime leftEf = stack.pop();
+               if (!leftEf.getExecutionFlow().getUuid()
+                               .equals(executionFlow.getUuid()))
+                       throw new SlcException("Asked to leave " + executionFlow
+                                       + " but last is " + leftEf);
+
+               leftEf.getScopedObjects().clear();
+               leftEf.getLocalVariables().clear();
+
+       }
+
+       public static String getCurrentStackUuid() {
+               return getWithCheck().stack.peek().uuid;
+       }
+
+       // public static ExecutionFlow getCurrentFlow() {
+       // return getWithCheck().stack.peek().executionFlow;
+       // }
+
+       public static Boolean isExecuting() {
+               return executionContext.get() != null;
+       }
+
+       protected static ExecutionContext getWithCheck() {
+               if (executionContext.get() == null)
+                       throw new SlcException("No execution context");
+               return executionContext.get();
+       }
+
+       public static Object findOrAddScopedObject(String name,
+                       ObjectFactory objectFactory) {
+               ExecutionContext executionContext = getWithCheck();
+               Object obj = executionContext.findScopedObject(name);
+               if (obj == null) {
+                       obj = objectFactory.getObject();
+                       executionContext.stack.peek().getScopedObjects().put(name, obj);
+               }
+               return obj;
+       }
+
+       /** return null if not found */
+       protected Object findScopedObject(String key) {
+               Object obj = null;
+               for (int i = stack.size() - 1; i >= 0; i--) {
+                       if (stack.get(i).getScopedObjects().containsKey(key)) {
+                               obj = stack.get(i).getScopedObjects().get(key);
+                               break;
+                       }
+               }
+               return obj;
+       }
+
+       public String getUuid() {
+               return uuid;
+       }
+
+       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.execution/src/main/java/org/argeo/slc/execution/ExecutionFinishedEvent.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionFinishedEvent.java
new file mode 100644 (file)
index 0000000..7aacd50
--- /dev/null
@@ -0,0 +1,19 @@
+package org.argeo.slc.execution;
+
+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.execution/src/main/java/org/argeo/slc/execution/ExecutionFlow.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionFlow.java
new file mode 100644 (file)
index 0000000..b0075bf
--- /dev/null
@@ -0,0 +1,11 @@
+package org.argeo.slc.execution;
+
+import java.util.Map;
+
+import org.argeo.slc.process.Executable;
+
+public interface ExecutionFlow extends Executable{
+       public Object getParameter(String name);
+       public ExecutionSpec getExecutionSpec();
+       public String getUuid();
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionFlowFactory.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionFlowFactory.java
new file mode 100644 (file)
index 0000000..8631ac7
--- /dev/null
@@ -0,0 +1,25 @@
+package org.argeo.slc.execution;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.argeo.slc.process.Executable;
+
+public class ExecutionFlowFactory {
+       private List<Executable> executables = new ArrayList<Executable>();
+
+       
+       public ExecutionFlow createExecutionFlow(Map<String, Object> attributes){
+               SimpleExecutionFlow executionFlow = new SimpleExecutionFlow();
+               executionFlow.setExecutables(executables);
+               return executionFlow;
+       }
+
+
+       public void setExecutables(List<Executable> executables) {
+               this.executables = executables;
+       }
+       
+       
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionParameterPostProcessor.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionParameterPostProcessor.java
new file mode 100644 (file)
index 0000000..3f741d9
--- /dev/null
@@ -0,0 +1,120 @@
+package org.argeo.slc.execution;
+
+import java.beans.PropertyDescriptor;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.slc.SlcException;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.PropertyValue;
+import org.springframework.beans.PropertyValues;
+import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
+import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
+import org.springframework.beans.factory.config.TypedStringValue;
+
+public class ExecutionParameterPostProcessor extends
+               InstantiationAwareBeanPostProcessorAdapter {
+       private final static Log log = LogFactory
+                       .getLog(ExecutionParameterPostProcessor.class);
+
+       private String placeholderPrefix = "@{";
+       private String placeholderSuffix = "}";
+       private String nullValue;
+
+       @Override
+       public PropertyValues postProcessPropertyValues(PropertyValues pvs,
+                       PropertyDescriptor[] pds, Object bean, String beanName)
+                       throws BeansException {
+               if (!ExecutionContext.isExecuting())
+                       return pvs;
+
+//             ExecutionFlow currentFlow = ExecutionContext.getCurrentFlow();
+//
+//             Properties props = new Properties();
+//             Map<String, Object> attributes = currentFlow.getAttributes();
+//             Map<String, ExecutionSpecAttribute> specAttributes = currentFlow
+//                             .getExecutionSpec().getAttributes();
+//
+//             for (String key : specAttributes.keySet()) {
+//                     ExecutionSpecAttribute obj = specAttributes.get(key);
+//                     if (!(obj instanceof RefSpecAttribute)) {
+//                             if (!attributes.containsKey(key))
+//                                     throw new SlcException("Specified attribute " + key
+//                                                     + " is not set in " + currentFlow);
+//
+//                             props.setProperty(key, attributes.get(key).toString());
+//                             // if (log.isTraceEnabled())
+//                             // log.trace("Use attribute " + key);
+//                     }
+//             }
+
+               Properties props = new Properties();
+               CustomPpc ppc = new CustomPpc(props);
+
+               for (PropertyValue pv : pvs.getPropertyValues()) {
+                       if (pv.getValue() instanceof TypedStringValue) {
+                               TypedStringValue tsv = (TypedStringValue) pv.getValue();
+                               String originalValue = tsv.getValue();
+                               String convertedValue = ppc.process(originalValue);
+                               tsv.setValue(convertedValue);
+                               if (log.isTraceEnabled()) {
+                                       if (!originalValue.equals(convertedValue))
+                                               log.trace("Converted field '" + pv.getName() + "': '"
+                                                               + originalValue + "' to '" + convertedValue
+                                                               + "' in bean " + beanName);
+                               }
+                       } else {
+                               // if (log.isTraceEnabled())
+                               // log.trace(beanName + "[" + pv.getName() + "]: "
+                               // + pv.getValue().getClass());
+                       }
+               }
+
+               return pvs;
+       }
+
+       public void setPlaceholderPrefix(String placeholderPrefix) {
+               this.placeholderPrefix = placeholderPrefix;
+       }
+
+       public void setPlaceholderSuffix(String placeholderSuffix) {
+               this.placeholderSuffix = placeholderSuffix;
+       }
+
+       public void setNullValue(String nullValue) {
+               this.nullValue = nullValue;
+       }
+
+       private class CustomPpc extends PropertyPlaceholderConfigurer {
+               private final Properties props;
+
+               public CustomPpc(Properties props) {
+                       super();
+                       this.props = props;
+                       setPlaceholderPrefix(placeholderPrefix);
+                       setPlaceholderSuffix(placeholderSuffix);
+                       setSystemPropertiesMode(SYSTEM_PROPERTIES_MODE_NEVER);
+               }
+
+               public String process(String strVal) {
+                       String value = parseStringValue(strVal, this.props,
+                                       new HashSet<String>());
+                       return (value.equals(nullValue) ? null : value);
+               }
+
+               @Override
+               protected String resolvePlaceholder(String placeholder, Properties props) {
+                       if (ExecutionContext.isExecuting())
+                               return ExecutionContext.getVariable(placeholder).toString();
+                       else if (SimpleExecutionSpec.isInFlowInitialization())
+                               return SimpleExecutionSpec.getInitializingFlowParameter(
+                                               placeholder).toString();
+                       else
+                               return super.resolvePlaceholder(placeholder, props);
+               }
+
+       }
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionRegister.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionRegister.java
new file mode 100644 (file)
index 0000000..c4f958e
--- /dev/null
@@ -0,0 +1,47 @@
+package org.argeo.slc.execution;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class ExecutionRegister implements InitializingBean {
+       private final static Log log = LogFactory.getLog(ExecutionRegister.class);
+
+       @Autowired
+       private Set<ExecutionFlow> executionFlows;
+
+       @Autowired
+       private Set<ExecutionSpec> executionSpecs;
+
+       public void afterPropertiesSet() throws Exception {
+               log.debug("Register: " + executionSpecs.size() + " specs");
+               for (ExecutionSpec spec : executionSpecs) {
+                       log.debug(spec);
+                       Map<String, ExecutionSpecAttribute> attributes = spec
+                                       .getAttributes();
+                       log.debug("Spec attributes: ");
+                       for (String key : attributes.keySet()) {
+                               log.debug(" " + key + "\t" + attributes.get(key));
+                       }
+               }
+
+               log.debug("Register: " + executionFlows.size() + " flows");
+               for (ExecutionFlow flow : executionFlows) {
+                       log.debug(flow);
+//                     Map<String, Object> attributes = flow.getAttributes();
+//                     log.debug("Specified parameters: ");
+//                     for (String key : flow.getExecutionSpec().getAttributes().keySet()) {
+//                             log.debug(" "
+//                                             + key
+//                                             + "\t"
+//                                             + (attributes.containsKey(key) ? "SPECIFIED"
+//                                                             : "TO SPECIFY"));
+//                     }
+               }
+
+       }
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionScope.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionScope.java
new file mode 100644 (file)
index 0000000..0970ac8
--- /dev/null
@@ -0,0 +1,47 @@
+package org.argeo.slc.execution;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.slc.SlcException;
+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);
+
+       public Object get(String name, ObjectFactory objectFactory) {
+
+               if (log.isTraceEnabled())
+                       log.trace("Getting scoped bean " + name);
+               return ExecutionContext.findOrAddScopedObject(name, objectFactory);
+
+               // 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;
+               // }
+       }
+
+       public String getConversationId() {
+               return ExecutionContext.getCurrentStackUuid();
+       }
+
+       public void registerDestructionCallback(String name, Runnable callback) {
+               throw new UnsupportedOperationException();
+       }
+
+       public Object remove(String name) {
+               log.debug("Remove object " + name);
+               throw new UnsupportedOperationException();
+       }
+
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionSpec.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionSpec.java
new file mode 100644 (file)
index 0000000..24a3c83
--- /dev/null
@@ -0,0 +1,7 @@
+package org.argeo.slc.execution;
+
+import java.util.Map;
+
+public interface ExecutionSpec {
+       public Map<String, ExecutionSpecAttribute> getAttributes();
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionSpecAttribute.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionSpecAttribute.java
new file mode 100644 (file)
index 0000000..582cef9
--- /dev/null
@@ -0,0 +1,6 @@
+package org.argeo.slc.execution;
+
+public interface ExecutionSpecAttribute {
+       public Object getValue();
+       public Boolean getIsParameter();
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionTargetSource.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/ExecutionTargetSource.java
new file mode 100644 (file)
index 0000000..422abec
--- /dev/null
@@ -0,0 +1,44 @@
+package org.argeo.slc.execution;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.aop.TargetSource;
+
+public class ExecutionTargetSource implements TargetSource {
+       private final static Log log = LogFactory
+                       .getLog(ExecutionTargetSource.class);
+
+       private final String name;
+       private final Class<?> targetClass;
+       private final ExecutionFlow executionFlow;
+
+       public ExecutionTargetSource(ExecutionFlow executionFlow,
+                       Class<?> targetClass, String name) {
+               this.executionFlow = executionFlow;
+               this.targetClass = targetClass;
+               this.name = name;
+       }
+
+       public Object getTarget() throws Exception {
+               if (log.isTraceEnabled())
+                       log.trace("Getting object " + name);
+               Object obj = executionFlow.getParameter(name);
+               if (log.isTraceEnabled())
+                       log.trace("Target object " + obj);
+               return obj;
+       }
+
+       public Class getTargetClass() {
+               return targetClass;
+       }
+
+       public boolean isStatic() {
+               return false;
+       }
+
+       public void releaseTarget(Object target) throws Exception {
+               // TODO Auto-generated method stub
+
+       }
+
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/Executor.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/Executor.java
new file mode 100644 (file)
index 0000000..a394803
--- /dev/null
@@ -0,0 +1,70 @@
+package org.argeo.slc.execution;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+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();
+                       ExecutionContext executionContext = new ExecutionContext();
+                       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(ExecutionContext executionContext,
+                               SlcExecution slcExecution) {
+                       super("SLC Execution #" + executionContext.getUuid());
+                       this.slcExecution = slcExecution;
+                       this.executionContext = executionContext;
+               }
+
+               public void run() {
+                       // Initialize from SlcExecution
+                       ExecutionContext.registerExecutionContext(executionContext);
+                       ExecutionContext.getVariables()
+                                       .putAll(slcExecution.getAttributes());
+
+                       try {
+                               log.info("Start execution #"
+                                               + ExecutionContext.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.execution/src/main/java/org/argeo/slc/execution/InstantiationPostProcessor.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/InstantiationPostProcessor.java
new file mode 100644 (file)
index 0000000..4873c56
--- /dev/null
@@ -0,0 +1,29 @@
+package org.argeo.slc.execution;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
+
+public class InstantiationPostProcessor extends
+               InstantiationAwareBeanPostProcessorAdapter {
+       private final static Log log = LogFactory
+                       .getLog(InstantiationPostProcessor.class);
+
+       @Override
+       public boolean postProcessAfterInstantiation(Object bean, String beanName)
+                       throws BeansException {
+               if (bean instanceof ExecutionFlow)
+                       SimpleExecutionSpec.flowInitializationStarted((ExecutionFlow) bean);
+               return true;
+       }
+
+       @Override
+       public Object postProcessBeforeInitialization(Object bean, String beanName)
+                       throws BeansException {
+               if (bean instanceof ExecutionFlow)
+                       SimpleExecutionSpec
+                                       .flowInitializationFinished((ExecutionFlow) bean);
+               return bean;
+       }
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/NewExecutionEvent.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/NewExecutionEvent.java
new file mode 100644 (file)
index 0000000..ced38a8
--- /dev/null
@@ -0,0 +1,20 @@
+package org.argeo.slc.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.execution/src/main/java/org/argeo/slc/execution/RefSpecAttribute.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/RefSpecAttribute.java
new file mode 100644 (file)
index 0000000..9b0ea6d
--- /dev/null
@@ -0,0 +1,23 @@
+package org.argeo.slc.execution;
+
+public class RefSpecAttribute  extends AbstractSpecAttribute {
+       private Class targetClass;
+       private Object value = null;
+
+       public Object getValue() {
+               return value;
+       }
+
+       public void setValue(Object value) {
+               this.value = value;
+       }
+
+       public Class getTargetClass() {
+               return targetClass;
+       }
+
+       public void setTargetClass(Class targetClass) {
+               this.targetClass = targetClass;
+       }
+
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/SimpleExecutionFlow.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/SimpleExecutionFlow.java
new file mode 100644 (file)
index 0000000..34018ee
--- /dev/null
@@ -0,0 +1,114 @@
+package org.argeo.slc.execution;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.commons.lang.math.RandomUtils;
+import org.argeo.slc.SlcException;
+import org.argeo.slc.process.Executable;
+import org.argeo.slc.test.ExecutableTestRun;
+import org.springframework.beans.factory.BeanNameAware;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.validation.MapBindingResult;
+
+public class SimpleExecutionFlow implements ExecutionFlow, InitializingBean,
+               BeanNameAware {
+       private ExecutionSpec executionSpec = new SimpleExecutionSpec();
+       private String name = null;
+       private Map<String, Object> parameters = new HashMap<String, Object>();
+       private List<Executable> executables = new ArrayList<Executable>();
+
+       private final String uuid = UUID.randomUUID().toString();
+
+       public void execute() {
+               for (Executable executable : executables) {
+                       executable.execute();
+               }
+       }
+
+       public void afterPropertiesSet() throws Exception {
+               // Validate execution specs
+               if (executionSpec == null)
+                       return;
+
+               MapBindingResult errors = new MapBindingResult(parameters, "execution#"
+                               + getUuid());
+               for (String key : executionSpec.getAttributes().keySet()) {
+                       ExecutionSpecAttribute executionSpecAttr = executionSpec
+                                       .getAttributes().get(key);
+                       if (!parameters.containsKey(key)) {
+                               Object defaultValue = executionSpecAttr.getValue();
+                               if (defaultValue == null)
+                                       errors.rejectValue(key, "Not set and no default value");
+                               else
+                                       parameters.put(key, defaultValue);
+                       } else {// contains key
+                               Object obj = parameters.get(key);
+                               if (executionSpecAttr instanceof RefSpecAttribute) {
+                                       RefSpecAttribute rsa = (RefSpecAttribute) executionSpecAttr;
+                                       Class targetClass = rsa.getTargetClass();
+                                       if (!targetClass.isAssignableFrom(obj.getClass())) {
+                                               errors.reject(key
+                                                               + " not compatible with target class "
+                                                               + targetClass);
+                                       }
+                               }
+                       }
+               }
+
+               if (errors.hasErrors())
+                       throw new SlcException("Could not prepare execution flow: "
+                                       + errors.toString());
+       }
+
+       public void setBeanName(String name) {
+               this.name = name;
+       }
+
+       public void setExecutables(List<Executable> executables) {
+               this.executables = executables;
+       }
+
+       public void setExecutionSpec(ExecutionSpec executionSpec) {
+               this.executionSpec = executionSpec;
+       }
+
+       public void setParameters(Map<String, Object> attributes) {
+               this.parameters = attributes;
+       }
+
+       public String getUuid() {
+               return uuid;
+       }
+
+       public ExecutionSpec getExecutionSpec() {
+               return executionSpec;
+       }
+
+       public Object getParameter(String name) {
+               if (parameters.containsKey(name)) {
+                       return parameters.get(name);
+               } else {
+                       if (executionSpec.getAttributes().containsKey(name)) {
+                               ExecutionSpecAttribute esa = executionSpec.getAttributes().get(
+                                               name);
+                               if (esa.getValue() != null)
+                                       return esa.getValue();
+                       } else {
+                               throw new SlcException("Key " + name
+                                               + " is not define in the specifications of "
+                                               + toString());
+                       }
+               }
+               throw new SlcException("Key " + name + " is not set as parameter in "
+                               + toString());
+       }
+
+       public String toString() {
+               return new StringBuffer("Flow ").append(name).toString();// .append(" [#")
+               // .append(uuid).append(']').toString();
+       }
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/SimpleExecutionSpec.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/SimpleExecutionSpec.java
new file mode 100644 (file)
index 0000000..8d460ff
--- /dev/null
@@ -0,0 +1,74 @@
+package org.argeo.slc.execution;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.argeo.slc.SlcException;
+import org.springframework.aop.framework.ProxyFactory;
+import org.springframework.beans.factory.BeanNameAware;
+
+public class SimpleExecutionSpec implements ExecutionSpec, BeanNameAware {
+       private final static ThreadLocal<ExecutionFlow> initializingFlow = new ThreadLocal<ExecutionFlow>();
+
+       private Map<String, ExecutionSpecAttribute> attributes = new HashMap<String, ExecutionSpecAttribute>();
+
+       private String name = null;
+
+       public Map<String, ExecutionSpecAttribute> getAttributes() {
+               return attributes;
+       }
+
+       public void setAttributes(Map<String, ExecutionSpecAttribute> attributes) {
+               this.attributes = attributes;
+       }
+
+       public Object createRef(String name) {
+               ExecutionFlow flow = initializingFlow.get();
+               if (flow == null)
+                       throw new SlcException("No flow is currently initializing."
+                                       + " Declare flow refs as inner beans or prototypes.");
+
+               RefSpecAttribute refSpecAttribute = (RefSpecAttribute) attributes
+                               .get(name);
+               Class<?> targetClass = refSpecAttribute.getTargetClass();
+               ExecutionTargetSource targetSource = new ExecutionTargetSource(flow,
+                               targetClass, name);
+               ProxyFactory proxyFactory = new ProxyFactory();
+               proxyFactory.setTargetClass(targetClass);
+               proxyFactory.setProxyTargetClass(true);
+               proxyFactory.setTargetSource(targetSource);
+
+               return proxyFactory.getProxy();
+       }
+
+       public void setBeanName(String name) {
+               this.name = name;
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public static void flowInitializationStarted(ExecutionFlow flow) {
+               initializingFlow.set(flow);
+       }
+
+       public static void flowInitializationFinished(ExecutionFlow flow) {
+               ExecutionFlow registeredFlow = initializingFlow.get();
+               if (registeredFlow == null)
+                       throw new SlcException("No flow registered");
+               if (!flow.getUuid().equals(registeredFlow.getUuid()))
+                       throw new SlcException("Current flow is " + flow);
+               initializingFlow.set(null);
+       }
+
+       public static Object getInitializingFlowParameter(String key) {
+               if (initializingFlow.get() == null)
+                       throw new SlcException("No initializing flow available.");
+               return initializingFlow.get().getParameter(key);
+       }
+
+       public static Boolean isInFlowInitialization() {
+               return initializingFlow.get() != null;
+       }
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/SimpleSpecAttribute.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/SimpleSpecAttribute.java
new file mode 100644 (file)
index 0000000..75019cb
--- /dev/null
@@ -0,0 +1,13 @@
+package org.argeo.slc.execution;
+
+public class SimpleSpecAttribute extends AbstractSpecAttribute {
+       private Object value = null;
+
+       public Object getValue() {
+               return value;
+       }
+
+       public void setValue(Object value) {
+               this.value = value;
+       }
+}
diff --git a/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/tasks/Echo.java b/runtime/org.argeo.slc.execution/src/main/java/org/argeo/slc/execution/tasks/Echo.java
new file mode 100644 (file)
index 0000000..e904153
--- /dev/null
@@ -0,0 +1,29 @@
+package org.argeo.slc.execution.tasks;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.slc.process.Executable;
+
+public class Echo implements Executable {
+       private final static Log defaultLog = LogFactory.getLog(Echo.class);
+
+       private Log log;
+       private String message;
+
+       public void execute() {
+               log().info(message);
+       }
+
+       protected Log log() {
+               return log != null ? log : defaultLog;
+       }
+
+       public void setLog(Log log) {
+               this.log = log;
+       }
+
+       public void setMessage(String message) {
+               this.message = message;
+       }
+
+}
diff --git a/runtime/org.argeo.slc.execution/src/slc/conf/BasicExecutionFlow.groovy b/runtime/org.argeo.slc.execution/src/slc/conf/BasicExecutionFlow.groovy
new file mode 100644 (file)
index 0000000..da3926e
--- /dev/null
@@ -0,0 +1,12 @@
+import org.argeo.slc.test.*;
+
+public class BasicExecutionFlow implements org.argeo.slc.executionflow.ExecutionFlow {
+
+       ExecutableTestRun firstSubTest = null;
+       ExecutableTestRun secondSubTest = null;
+
+       void execute(){
+               firstSubTest?.execute();
+               secondSubTest?.execute();
+       }
+}
diff --git a/runtime/org.argeo.slc.execution/src/slc/conf/basic.xml b/runtime/org.argeo.slc.execution/src/slc/conf/basic.xml
new file mode 100644 (file)
index 0000000..5e1c46e
--- /dev/null
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<beans xmlns="http://www.springframework.org/schema/beans"\r
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"\r
+       xmlns:aop="http://www.springframework.org/schema/aop"\r
+       xsi:schemaLocation="\r
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\r
+       http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd\r
+       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">\r
+\r
+       <import resource="common.xml" />\r
+\r
+       <bean id="basic.executionSpec" class="org.argeo.slc.execution.SimpleExecutionSpec">\r
+               <property name="attributes">\r
+                       <map>\r
+                               <entry key="testedComponentId">\r
+                                       <bean parent="specAttribute" p:value="100" />\r
+                               </entry>\r
+                               <entry key="testData1">\r
+                                       <bean parent="refAttribute" p:targetClass="org.argeo.slc.core.test.BasicTestData" />\r
+                               </entry>\r
+                               <entry key="testData2">\r
+                                       <bean parent="refAttribute" p:targetClass="org.argeo.slc.core.test.BasicTestData" />\r
+                               </entry>\r
+                       </map>\r
+               </property>\r
+       </bean>\r
+\r
+       <bean id="basic.ref" factory-bean="basic.executionSpec"\r
+               factory-method="createRef" abstract="true" />\r
+\r
+       <bean id="basic.executionFlowTemplate" class="org.argeo.slc.execution.SimpleExecutionFlow"\r
+               abstract="true">\r
+               <property name="executionSpec" ref="basic.executionSpec" />\r
+               <property name="executables">\r
+                       <list>\r
+                               <ref bean="echo1" />\r
+                               <bean parent="testRun">\r
+                                       <property name="testDefinition" ref="testDef" />\r
+                                       <property name="testData">\r
+                                               <bean parent="basic.ref">\r
+                                                       <constructor-arg value="testData1" />\r
+                                               </bean>\r
+                                       </property>\r
+                               </bean>\r
+                               <bean parent="testRun">\r
+                                       <property name="testDefinition" ref="testDef" />\r
+                                       <property name="testData" ref="ref1" />\r
+                               </bean>\r
+                       </list>\r
+               </property>\r
+       </bean>\r
+\r
+       <bean id="ref1" parent="basic.ref" scope="prototype">\r
+               <constructor-arg value="testData2" />\r
+       </bean>\r
+\r
+       <bean id="testDef" class="org.argeo.slc.core.test.BasicTestDefinition"\r
+               scope="prototype" />\r
+\r
+       <bean id="testResult" parent="slcDefault.test.basicSimpleTestResult" />\r
+\r
+       <bean id="testRun" class="org.argeo.slc.core.test.SimpleTestRun"\r
+               abstract="true">\r
+               <property name="testResult" ref="testResult" />\r
+       </bean>\r
+\r
+       <!--\r
+               <bean class="org.springframework.aop.framework.ProxyFactoryBean">\r
+               <property name="targetClass"\r
+               value="org.argeo.slc.core.test.BasicTestData" /> <property\r
+               name="targetSource"> <bean\r
+               class="org.argeo.slc.executionflow.ExecutionTargetSource"> <property\r
+               name="name" value="testData" /> <property name="targetClass"\r
+               value="org.argeo.slc.core.test.BasicTestData" /> </bean> </property>\r
+               <property name="proxyTargetClass" value="true" /> </bean>\r
+       -->\r
+\r
+</beans>
\ No newline at end of file
diff --git a/runtime/org.argeo.slc.execution/src/slc/conf/common.xml b/runtime/org.argeo.slc.execution/src/slc/conf/common.xml
new file mode 100644 (file)
index 0000000..4495b2f
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<beans xmlns="http://www.springframework.org/schema/beans"\r
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"\r
+       xmlns:aop="http://www.springframework.org/schema/aop"\r
+       xsi:schemaLocation="\r
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\r
+       http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd\r
+       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">\r
+\r
+       <import\r
+               resource="classpath:/org/argeo/slc/core/test/spring/applicationContext.xml" />\r
+\r
+       <bean id="specAttribute" class="org.argeo.slc.execution.SimpleSpecAttribute"\r
+               abstract="true" />\r
+\r
+       <bean id="refAttribute" class="org.argeo.slc.execution.RefSpecAttribute"\r
+               abstract="true" />\r
+\r
+</beans>
\ No newline at end of file
diff --git a/runtime/org.argeo.slc.execution/src/slc/conf/main.xml b/runtime/org.argeo.slc.execution/src/slc/conf/main.xml
new file mode 100644 (file)
index 0000000..829e6ee
--- /dev/null
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<beans xmlns="http://www.springframework.org/schema/beans"\r
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"\r
+       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"\r
+       xsi:schemaLocation="\r
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\r
+       http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd\r
+       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\r
+       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">\r
+\r
+       <import resource="testCases/basic-001.xml" />\r
+       <import resource="testCases/basic-002.xml" />\r
+\r
+       <bean id="main" class="org.argeo.slc.execution.SimpleExecutionFlow">\r
+               <property name="executionSpec">\r
+                       <bean class="org.argeo.slc.execution.SimpleExecutionSpec">\r
+                               <property name="attributes">\r
+                                       <map>\r
+                                               <entry key="testKey">\r
+                                                       <bean parent="specAttribute" p:value="660" />\r
+                                               </entry>\r
+                                       </map>\r
+                               </property>\r
+                       </bean>\r
+               </property>\r
+               <property name="executables">\r
+                       <list>\r
+                               <ref local="echo1" />\r
+                               <ref bean="basic.001" />\r
+                               <ref bean="basic.001" />\r
+                               <ref bean="basic.002" />\r
+                       </list>\r
+               </property>\r
+       </bean>\r
+\r
+       <bean id="echo1" parent="echoTemplate" scope="execution">\r
+               <property name="message" value="From main! @{testKey}, slc.flows=@{slc.flows}" />\r
+               <aop:scoped-proxy />\r
+       </bean>\r
+\r
+       <bean id="echoTemplate" class="org.argeo.slc.execution.tasks.Echo"\r
+               abstract="true">\r
+       </bean>\r
+\r
+       <context:annotation-config />\r
+       <bean class="org.argeo.slc.execution.ExecutionRegister" />\r
+\r
+\r
+       <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">\r
+               <property name="scopes">\r
+                       <map>\r
+                               <entry key="execution">\r
+                                       <bean class="org.argeo.slc.execution.ExecutionScope" />\r
+                               </entry>\r
+                       </map>\r
+               </property>\r
+       </bean>\r
+\r
+       <bean\r
+               class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />\r
+       <bean class="org.argeo.slc.execution.ExecutionParameterPostProcessor" />\r
+       <bean class="org.argeo.slc.execution.InstantiationPostProcessor" />\r
+       <bean class="org.argeo.slc.execution.Executor" />\r
+\r
+       <bean class="org.argeo.slc.execution.ExecutionAspect"></bean>\r
+       <aop:aspectj-autoproxy />\r
+\r
+</beans>
\ No newline at end of file
diff --git a/runtime/org.argeo.slc.execution/src/slc/conf/slc.properties b/runtime/org.argeo.slc.execution/src/slc/conf/slc.properties
new file mode 100644 (file)
index 0000000..b18dce1
--- /dev/null
@@ -0,0 +1,16 @@
+log4j.rootLogger=WARN, console
+
+## Levels
+log4j.logger.org.argeo=DEBUG
+log4j.logger.org.argeo.slc.executionflow.ExecutionParameterPostProcessor=TRACE
+log4j.logger.org.argeo.slc.executionflow.ExecutionContext=TRACE
+
+## Appenders
+# console is set to be a ConsoleAppender.
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+
+# console uses PatternLayout.
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern= %-5p %d{ISO8601} %m - %c%n
+
+testCase=002
\ No newline at end of file
diff --git a/runtime/org.argeo.slc.execution/src/slc/conf/test.xml b/runtime/org.argeo.slc.execution/src/slc/conf/test.xml
new file mode 100644 (file)
index 0000000..6cc40e8
--- /dev/null
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<beans xmlns="http://www.springframework.org/schema/beans"\r
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"\r
+       xmlns:lang="http://www.springframework.org/schema/lang"\r
+       xsi:schemaLocation="\r
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\r
+       http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd\r
+       ">\r
+\r
+       <import\r
+               resource="classpath:/org/argeo/slc/core/test/spring/applicationContext.xml" />\r
+\r
+       <import resource="testCases/basic-001.xml" />\r
+       <import resource="testCases/basic-002.xml" />\r
+\r
+       <bean id="executionFlow.basic1" class="org.argeo.slc.executionflow.SimpleExecutionFlow">\r
+               <meta key="meta1" value="mata1Value" />\r
+               <qualifier>\r
+                       <attribute key="qual1" value="qual1value" />\r
+               </qualifier>\r
+               <property name="executables">\r
+                       <list>\r
+                               <ref local="testGroovyImpl" />\r
+                               <ref local="testBshImpl" />\r
+                               <bean parent="testRun" p:testDefinition-ref="testDef"\r
+                                       p:testData-ref="testData-${testCase}" />\r
+                               <bean parent="testRun" p:testDefinition-ref="testDef"\r
+                                       p:testData-ref="testData-${testCase}" />\r
+                       </list>\r
+               </property>\r
+       </bean>\r
+\r
+       <lang:groovy id="executionFlow.groovy1" script-source="src/slc/conf/BasicExecutionFlow.groovy">\r
+               <lang:property name="firstSubTest">\r
+                       <bean parent="testRun" p:testDefinition-ref="testDef"\r
+                               p:testData-ref="testData-${testCase}" />\r
+               </lang:property>\r
+       </lang:groovy>\r
+\r
+       <bean id="testGroovyImpl" parent="testGroovy">\r
+               <property name="message" value="Hello World! Groovy" />\r
+       </bean>\r
+       <bean id="testBshImpl" parent="testBsh">\r
+               <property name="message" value="Hello World! Beanshell" />\r
+       </bean>\r
+\r
+       <bean id="testDef" class="org.argeo.slc.core.test.BasicTestDefinition"\r
+               scope="prototype" />\r
+\r
+       <bean\r
+               class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />\r
+\r
+       <bean id="testResult" parent="slcDefault.test.basicSimpleTestResult">\r
+       </bean>\r
+\r
+       <bean id="testRun" class="org.argeo.slc.core.test.SimpleTestRun"\r
+               abstract="true">\r
+               <property name="testResult" ref="testResult" />\r
+       </bean>\r
+\r
+       <lang:groovy id="testGroovyBean">\r
+               <lang:inline-script><![CDATA[\r
+               class Message {\r
+               String message = 'test'\r
+               \r
+               public String getMessage(){\r
+                       return message;\r
+               }\r
+               }\r
+               ]]></lang:inline-script>\r
+       </lang:groovy>\r
+\r
+       <lang:groovy id="testGroovy">\r
+               <lang:inline-script><![CDATA[\r
+               class GroovyMessenger extends org.argeo.slc.core.test.SimpleTestRun {\r
+       \r
+               String message = 'test'\r
+       \r
+                       void execute(){\r
+                               println(message);\r
+                       }\r
+               }\r
+               ]]></lang:inline-script>\r
+       </lang:groovy>\r
+\r
+       <lang:bsh id="testBsh" script-interfaces="org.argeo.slc.test.ExecutableTestRun">\r
+               <lang:inline-script><![CDATA[\r
+               setStrictJava(true);\r
+\r
+               class BshMessenger extends org.argeo.slc.core.test.SimpleTestRun {\r
+\r
+                       String message = "test";\r
+\r
+                       public void execute(){\r
+                               System.out.println(message);\r
+                       }\r
+                       \r
+                       public void setMessage(String message){\r
+                               this.message = message;\r
+                       }\r
+               }\r
+               ]]></lang:inline-script>\r
+       </lang:bsh>\r
+\r
+</beans>
\ No newline at end of file
diff --git a/runtime/org.argeo.slc.execution/src/slc/conf/testCases/basic-001.xml b/runtime/org.argeo.slc.execution/src/slc/conf/testCases/basic-001.xml
new file mode 100644 (file)
index 0000000..0131cc2
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<beans xmlns="http://www.springframework.org/schema/beans"\r
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"\r
+       xmlns:aop="http://www.springframework.org/schema/aop"\r
+       xsi:schemaLocation="\r
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\r
+       http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd\r
+       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">\r
+\r
+       <import resource="../basic.xml" />\r
+\r
+       <bean id="basic.001" parent="basic.executionFlowTemplate">\r
+               <property name="parameters">\r
+                       <map>\r
+                               <entry key="testData1" value-ref="basic.001.testData" />\r
+                               <entry key="testData2">\r
+                                       <bean class="org.argeo.slc.core.test.BasicTestData" scope="execution">\r
+                                               <aop:scoped-proxy />\r
+                                               <property name="expected" value="tata101" />\r
+                                               <property name="reached" value="tata@{testKey}" />\r
+                                       </bean>\r
+                               </entry>\r
+                       </map>\r
+               </property>\r
+       </bean>\r
+\r
+       <bean id="basic.001.testData" class="org.argeo.slc.core.test.BasicTestData"\r
+               scope="execution">\r
+               <aop:scoped-proxy />\r
+               <property name="expected" value="tata100" />\r
+               <property name="reached" value="tata@{testedComponentId}" />\r
+       </bean>\r
+\r
+       <bean id="basic.001.testData2" class="org.argeo.slc.core.test.context.DefaultContextTestData">\r
+       </bean>\r
+\r
+</beans>
\ No newline at end of file
diff --git a/runtime/org.argeo.slc.execution/src/slc/conf/testCases/basic-002.xml b/runtime/org.argeo.slc.execution/src/slc/conf/testCases/basic-002.xml
new file mode 100644 (file)
index 0000000..fc52a03
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<beans xmlns="http://www.springframework.org/schema/beans"\r
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"\r
+\r
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">\r
+\r
+       <import resource="../basic.xml" />\r
+\r
+       <bean id="basic.002" parent="basic.executionFlowTemplate">\r
+               <property name="parameters">\r
+                       <map>\r
+                               <entry key="testData1">\r
+                                       <bean class="org.argeo.slc.core.test.BasicTestData">\r
+                                               <property name="expected" value="toto" />\r
+                                               <property name="reached" value="toto" />\r
+                                       </bean>\r
+                               </entry>\r
+                               <entry key="testData2">\r
+                                       <bean class="org.argeo.slc.core.test.BasicTestData">\r
+                                               <property name="expected" value="tata" />\r
+                                               <property name="reached" value="toto" />\r
+                                       </bean>\r
+                               </entry>\r
+                       </map>\r
+               </property>\r
+       </bean>\r
+</beans>
\ No newline at end of file