Change the way parameterRef is implemented
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 24 Jul 2009 12:32:09 +0000 (12:32 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 24 Jul 2009 12:32:09 +0000 (12:32 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@2750 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/InstantiationManager.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ParameterRef.java [new file with mode: 0644]
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/PrimitiveSpecAttribute.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/Echo.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/test/context/ContextUtils.java
runtime/org.argeo.slc.core/src/main/resources/org/argeo/slc/core/execution/simple.xml
runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/ExceptionIfInitCalledTwice.java [new file with mode: 0644]
runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/ParameterRefTest.java [new file with mode: 0644]
runtime/org.argeo.slc.core/src/test/resources/org/argeo/slc/core/execution/parameterRef.xml [new file with mode: 0644]

index c3d844c46c54c01bd267792e6ec1af8d23057d64..1f1ff73d21cae9642ab887cf9f044c4f599705c1 100644 (file)
@@ -6,36 +6,38 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;\r
 import org.argeo.slc.SlcException;\r
 import org.argeo.slc.execution.ExecutionFlow;\r
+import org.argeo.slc.execution.ExecutionSpecAttribute;\r
 \r
 public class InstantiationManager {\r
 \r
-       private final static Log log = LogFactory.getLog(InstantiationManager.class);\r
-       \r
-       private ThreadLocal<Stack<ExecutionFlow> > flowStack = new ThreadLocal<Stack<ExecutionFlow> >();\r
-       \r
+       private final static Log log = LogFactory\r
+                       .getLog(InstantiationManager.class);\r
+\r
+       private ThreadLocal<Stack<ExecutionFlow>> flowStack = new ThreadLocal<Stack<ExecutionFlow>>();\r
+\r
        public Object createRef(String name) {\r
-               \r
-               if((flowStack.get() == null) ||  flowStack.get().empty()) {\r
+\r
+               if ((flowStack.get() == null) || flowStack.get().empty()) {\r
                        throw new SlcException("No flow is currently initializing."\r
                                        + " Declare ParameterRef as inner beans or prototypes.");\r
                }\r
-               \r
+\r
                return getInitializingFlowParameter(name);\r
-       }       \r
-       \r
+       }\r
+\r
        public void flowInitializationStarted(ExecutionFlow flow, String flowName) {\r
                if (log.isTraceEnabled())\r
                        log.trace("Start initialization of " + flow.hashCode() + " ("\r
                                        + flow + " - " + flow.getClass() + ")");\r
-               \r
+\r
                // set the flow name if it is DefaultExecutionFlow\r
-               if(flow instanceof DefaultExecutionFlow) {\r
+               if (flow instanceof DefaultExecutionFlow) {\r
                        ((DefaultExecutionFlow) flow).setBeanName(flowName);\r
                }\r
-               \r
-//             log.info("# flowInitializationStarted " + flowName);\r
+\r
+               // log.info("# flowInitializationStarted " + flowName);\r
                // create a stack for this thread if there is none\r
-               if(flowStack.get() == null) {\r
+               if (flowStack.get() == null) {\r
                        flowStack.set(new Stack<ExecutionFlow>());\r
                }\r
                flowStack.get().push(flow);\r
@@ -49,26 +51,43 @@ public class InstantiationManager {
                if (registeredFlow != null) {\r
                        if (!flow.getName().equals(registeredFlow.getName()))\r
                                throw new SlcException("Current flow is " + flow);\r
-//                     log.info("# flowInitializationFinished " + flowName);\r
-//                     initializingFlow.set(null);\r
+                       // log.info("# flowInitializationFinished " + flowName);\r
+                       // initializingFlow.set(null);\r
                }\r
-       }       \r
-       \r
-       public Object getInitializingFlowParameter(String key) {\r
+       }\r
+\r
+       protected ExecutionFlow findInitializingFlowWithParameter(String key) {\r
                if ((flowStack.get() == null) || flowStack.get().empty())\r
                        throw new SlcException("No initializing flow available.");\r
-               \r
+\r
                // first look in the outer flow (that may override parameters)\r
-               for(int i = 0; i < flowStack.get().size(); i++) {\r
-                       if(flowStack.get().elementAt(i).isSetAsParameter(key)) {\r
-                               return flowStack.get().elementAt(i).getParameter(key);\r
+               for (int i = 0; i < flowStack.get().size(); i++) {\r
+                       if (flowStack.get().elementAt(i).isSetAsParameter(key)) {\r
+                               return flowStack.get().elementAt(i);\r
                        }\r
                }\r
                throw new SlcException("Key " + key + " is not set as parameter in "\r
-                               + flowStack.get().firstElement().toString() + " (stack size="+flowStack.get().size()+")");              \r
+                               + flowStack.get().firstElement().toString() + " (stack size="\r
+                               + flowStack.get().size() + ")");\r
+\r
+       }\r
+\r
+       public Object getInitializingFlowParameter(String key) {\r
+               return findInitializingFlowWithParameter(key).getParameter(key);\r
+       }\r
+\r
+       public Class<?> getInitializingFlowParameterClass(String key) {\r
+               ExecutionSpecAttribute attr = findInitializingFlowWithParameter(key)\r
+                               .getExecutionSpec().getAttributes().get(key);\r
+               if (attr instanceof RefSpecAttribute)\r
+                       return ((RefSpecAttribute) attr).getTargetClass();\r
+               else if (attr instanceof PrimitiveSpecAttribute)\r
+                       return ((PrimitiveSpecAttribute) attr).getTypeAsClass();\r
+               else\r
+                       return null;\r
        }\r
 \r
        public Boolean isInFlowInitialization() {\r
                return (flowStack.get() != null) && !flowStack.get().empty();\r
-       }       \r
+       }\r
 }\r
diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ParameterRef.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ParameterRef.java
new file mode 100644 (file)
index 0000000..d86af02
--- /dev/null
@@ -0,0 +1,53 @@
+package org.argeo.slc.core.execution;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.FactoryBean;
+
+public class ParameterRef implements FactoryBean {
+       private final static Log log = LogFactory.getLog(ParameterRef.class);
+
+       private InstantiationManager instantiationManager;
+       private String name;
+
+       /** Cached object. */
+       private Object object;
+
+       public ParameterRef() {
+       }
+
+       /** @deprecated for backward compatibility with pre v0.11.4 approach. */
+       public ParameterRef(String name) {
+               this.name = name;
+       }
+
+       public Object getObject() throws Exception {
+               if (log.isTraceEnabled())
+                       log.debug("Parameter ref called for " + name);
+
+               if (object == null)
+                       object = instantiationManager.getInitializingFlowParameter(name);
+               return object;
+       }
+
+       public Class<?> getObjectType() {
+               if (object == null)
+                       return instantiationManager.getInitializingFlowParameterClass(name);
+               else
+                       return object.getClass();
+       }
+
+       public boolean isSingleton() {
+               return true;
+       }
+
+       public void setInstantiationManager(
+                       InstantiationManager instantiationManager) {
+               this.instantiationManager = instantiationManager;
+       }
+
+       public void setName(String name) {
+               this.name = name;
+       }
+
+}
index 27910bf905229eac0b91a5ff55874a5f314c6cd9..0186a1c3cb584be1a04c4eabdf299bed1b425fc8 100644 (file)
@@ -1,5 +1,6 @@
 package org.argeo.slc.core.execution;
 
+import org.argeo.slc.SlcException;
 
 public class PrimitiveSpecAttribute extends AbstractSpecAttribute implements
                PrimitiveAccessor {
@@ -29,8 +30,33 @@ public class PrimitiveSpecAttribute extends AbstractSpecAttribute implements
                return type;
        }
 
+       public Class<?> getTypeAsClass() {
+               return typeAsClass(type);
+       }
+
        public void setType(String type) {
                this.type = type;
+
+               // check whether type is recognized.
+               // TODO: make validation cleaner
+               typeAsClass(type);
+       }
+
+       public static Class<?> typeAsClass(String type) {
+               if (TYPE_STRING.equals(type))
+                       return String.class;
+               else if (TYPE_INTEGER.equals(type))
+                       return Integer.class;
+               else if (TYPE_LONG.equals(type))
+                       return Long.class;
+               else if (TYPE_FLOAT.equals(type))
+                       return Float.class;
+               else if (TYPE_DOUBLE.equals(type))
+                       return Double.class;
+               else if (TYPE_BOOLEAN.equals(type))
+                       return Boolean.class;
+               else
+                       throw new SlcException("Unrecognized type " + type);
        }
 
 }
index 52195903cb4fc79152f235d936b9268752b3005f..87140246ff87f11c1ba51b03f48085377c6faa3f 100644 (file)
@@ -14,7 +14,7 @@ public class Echo implements Runnable {
        private Resource writeTo = null;
 
        private Log log;
-       private String message;
+       private Object message;
 
        public void run() {
                log().info(message);
@@ -24,7 +24,8 @@ public class Echo implements Runnable {
                                File file = writeTo.getFile();
                                if (log().isDebugEnabled())
                                        log().debug("Write to " + file);
-                               FileUtils.writeStringToFile(file, message);
+                               if (message != null)
+                                       FileUtils.writeStringToFile(file, message.toString());
                        } catch (IOException e) {
                                throw new SlcException("Could not write to " + writeTo, e);
                        }
@@ -35,7 +36,7 @@ public class Echo implements Runnable {
                return log != null ? log : defaultLog;
        }
 
-       public void setMessage(String message) {
+       public void setMessage(Object message) {
                this.message = message;
        }
 
index 8d795405c99946aa6fd9c82596ed722e8e97b7d9..ff3b1095f9b7fb2cfbc98097834dc64f0ee82d7e 100644 (file)
@@ -107,7 +107,7 @@ public class ContextUtils {
                                parent.getExpectedValues());\r
                synchronize(parent, expectedValuesCommon);\r
                if (log.isDebugEnabled())\r
-                       log.debug("Synchonized context " + parent);\r
+                       log.debug("Synchronized context " + parent);\r
 \r
        }\r
 \r
index a6887e3d99575f437afaca637ae4d37587c03820..d4db7a3c01124dc4f38816615a27cc6668d0c955 100644 (file)
                <property name="ignoreUnresolvablePlaceholders" value="true" />
        </bean>
 
-       <bean id="parameterRef" factory-bean="instantiationManager"
+       <bean id="parameterRef" class="org.argeo.slc.core.execution.ParameterRef"
+               abstract="true">
+               <property name="instantiationManager" ref="instantiationManager" />
+       </bean>
+       <!--
+               <bean id="parameterRef" factory-bean="instantiationManager"
                factory-method="createRef" abstract="true" />
-
+       -->
 </beans>
\ No newline at end of file
diff --git a/runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/ExceptionIfInitCalledTwice.java b/runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/ExceptionIfInitCalledTwice.java
new file mode 100644 (file)
index 0000000..7ba7c82
--- /dev/null
@@ -0,0 +1,27 @@
+package org.argeo.slc.core.execution;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.slc.SlcException;
+import org.springframework.beans.factory.InitializingBean;
+
+public class ExceptionIfInitCalledTwice implements Runnable, InitializingBean {
+       private final static Log log = LogFactory
+                       .getLog(ExceptionIfInitCalledTwice.class);
+
+       private Boolean calledOnce = false;
+
+       public void run() {
+               log.info(getClass().getSimpleName() + " ran properly");
+       }
+
+       public void afterPropertiesSet() throws Exception {
+               log.info(getClass().getSimpleName() + " init method called");
+
+               if (calledOnce)
+                       throw new SlcException(getClass().getSimpleName()
+                                       + "init method called twice.");
+               else
+                       calledOnce = true;
+       }
+}
diff --git a/runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/ParameterRefTest.java b/runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/ParameterRefTest.java
new file mode 100644 (file)
index 0000000..4d9c922
--- /dev/null
@@ -0,0 +1,21 @@
+package org.argeo.slc.core.execution;
+
+import org.argeo.slc.core.test.SimpleTestResult;
+import org.argeo.slc.execution.ExecutionFlow;
+import org.argeo.slc.test.TestStatus;
+import org.springframework.context.ConfigurableApplicationContext;
+
+public class ParameterRefTest extends AbstractExecutionFlowTestCase {
+       public void test001() throws Exception {
+               ConfigurableApplicationContext applicationContext = createApplicationContext("parameterRef.xml");
+               ((ExecutionFlow) applicationContext.getBean("parameterRef.001")).run();
+
+               SimpleTestResult res = (SimpleTestResult) applicationContext
+                               .getBean("parameterRef.testResult");
+               assertEquals(res.getParts().get(0).getStatus(), TestStatus.PASSED);
+               assertEquals(res.getParts().get(1).getStatus(), TestStatus.FAILED);
+
+               applicationContext.close();
+       }
+
+}
diff --git a/runtime/org.argeo.slc.core/src/test/resources/org/argeo/slc/core/execution/parameterRef.xml b/runtime/org.argeo.slc.core/src/test/resources/org/argeo/slc/core/execution/parameterRef.xml
new file mode 100644 (file)
index 0000000..9f45453
--- /dev/null
@@ -0,0 +1,109 @@
+<?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="imports.xml" />\r
+\r
+       <!-- DEFINITIONS -->\r
+       <bean id="parameterRef.spec" parent="slcTemplate.simpleSpec">\r
+               <property name="attributes">\r
+                       <map>\r
+                               <entry key="exceptionIfInitCalledTwice">\r
+                                       <bean parent="specAttr.ref"\r
+                                               p:targetClass="org.argeo.slc.core.execution.ExceptionIfInitCalledTwice"\r
+                                               p:isParameter="true" p:isFrozen="true" />\r
+                               </entry>\r
+                               <entry key="testData1">\r
+                                       <bean parent="specAttr.ref" p:targetClass="org.argeo.slc.core.test.BasicTestData"\r
+                                               p:isParameter="true" p:isFrozen="true" />\r
+                               </entry>\r
+                               <entry key="testData2">\r
+                                       <bean parent="specAttr.ref" p:targetClass="org.argeo.slc.core.test.BasicTestData"\r
+                                               p:isParameter="true" p:isFrozen="true" />\r
+                               </entry>\r
+                               <entry key="testedComponentId">\r
+                                       <bean parent="specAttr.primitive" p:value="100" p:isParameter="true"\r
+                                               p:type="integer" />\r
+                               </entry>\r
+                       </map>\r
+               </property>\r
+       </bean>\r
+\r
+       <bean id="parameterRef.flowTemplate" parent="slcTemplate.simpleFlow"\r
+               abstract="true">\r
+               <constructor-arg ref="parameterRef.spec" />\r
+               <property name="executables">\r
+                       <list>\r
+                               <!-- Primitive -->\r
+                               <bean parent="task.echo" scope="execution">\r
+                                       <property name="message" value="testedComponentId=@{testedComponentId}" />\r
+                               </bean>\r
+\r
+                               <!-- Exception if init called twice -->\r
+                               <bean parent="parameterRef">\r
+                                       <constructor-arg value="exceptionIfInitCalledTwice" />\r
+                               </bean>\r
+                               <bean parent="parameterRef">\r
+                                       <property name="name" value="exceptionIfInitCalledTwice" />\r
+                               </bean>\r
+\r
+                               <!-- Basic tests -->\r
+                               <bean parent="parameterRef.testRun">\r
+                                       <property name="testData">\r
+                                               <bean parent="parameterRef">\r
+                                                       <constructor-arg value="testData1" />\r
+                                               </bean>\r
+                                       </property>\r
+                               </bean>\r
+                               <bean parent="parameterRef.testRun">\r
+                                       <property name="testData" ref="ref1" />\r
+                               </bean>\r
+                       </list>\r
+               </property>\r
+       </bean>\r
+\r
+       <!-- TEST CASES -->\r
+       <bean id="parameterRef.001" parent="parameterRef.flowTemplate">\r
+               <constructor-arg>\r
+                       <map>\r
+                               <entry key="exceptionIfInitCalledTwice">\r
+                                       <bean class="org.argeo.slc.core.execution.ExceptionIfInitCalledTwice" />\r
+                               </entry>\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
+               </constructor-arg>\r
+       </bean>\r
+\r
+       <!-- UTILITIES -->\r
+\r
+       <bean id="ref1" parent="parameterRef">\r
+               <constructor-arg value="testData2" />\r
+       </bean>\r
+\r
+       <bean id="parameterRef.testResult" class="org.argeo.slc.core.test.SimpleTestResult" />\r
+\r
+       <bean id="parameterRef.testRun" class="org.argeo.slc.core.test.SimpleTestRun"\r
+               abstract="true">\r
+               <property name="testResult" ref="parameterRef.testResult" />\r
+               <property name="testDefinition">\r
+                       <bean class="org.argeo.slc.core.test.BasicTestDefinition" />\r
+               </property>\r
+       </bean>\r
+\r
+</beans>
\ No newline at end of file