slc flow namespace extended (flow:variables, list, map, etc. in flow:arg and spec...
authorOlivier Capillon <olivier.capillon@gmail.com>
Fri, 21 May 2010 11:01:47 +0000 (11:01 +0000)
committerOlivier Capillon <olivier.capillon@gmail.com>
Fri, 21 May 2010 11:01:47 +0000 (11:01 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@3585 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/xml/ExecutionScopeDecorator.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/xml/FlowNamespaceHandler.java
runtime/org.argeo.slc.core/src/main/resources/org/argeo/slc/core/execution/xml/slc-flow-0.12.xsd
runtime/org.argeo.slc.core/src/test/java/org/argeo/slc/core/execution/xml/FlowNamespaceTest.java
runtime/org.argeo.slc.core/src/test/resources/org/argeo/slc/core/execution/xml/advanced.xml
runtime/org.argeo.slc.core/src/test/resources/org/argeo/slc/core/execution/xml/containers.xml [new file with mode: 0644]

index e5738b16878d30c9efb8956e77ac156c5cbc94a5..726f342302ae9e257527e93b057cf97f8963cc05 100644 (file)
@@ -1,44 +1,36 @@
 package org.argeo.slc.core.execution.xml;\r
 \r
-import org.apache.commons.logging.Log;\r
-import org.apache.commons.logging.LogFactory;\r
 import org.springframework.aop.scope.ScopedProxyUtils;\r
 import org.springframework.beans.factory.config.BeanDefinitionHolder;\r
 import org.springframework.beans.factory.parsing.BeanComponentDefinition;\r
 import org.springframework.beans.factory.xml.BeanDefinitionDecorator;\r
 import org.springframework.beans.factory.xml.ParserContext;\r
+import org.w3c.dom.Element;\r
 import org.w3c.dom.Node;\r
 \r
 /**\r
- * Inspired by org.springframework.aop.config.AopNamespaceHandler\r
- * Conceived to replace Element "aop:scoped-proxy" by an attribute.\r
- * Does not work correctly with other attribute decorators (e.g. \r
- * p namespace) since this decorator needs to be called after all\r
- * properties have been set on target bean. \r
+ * Inspired by org.springframework.aop.config.ScopedProxyBeanDefinitionDecorator\r
  */\r
-public class ExecutionScopeDecorator implements BeanDefinitionDecorator {\r
-       private Log log = LogFactory.getLog(ExecutionScopeDecorator.class);\r
+public class ExecutionScopeDecorator implements BeanDefinitionDecorator {      \r
+       private static final String PROXY_TARGET_CLASS = "proxy-target-class";  \r
        \r
        public BeanDefinitionHolder decorate(Node node,\r
                        BeanDefinitionHolder definition, ParserContext parserContext) {\r
                \r
-               Boolean isVar = Boolean.valueOf(node.getNodeValue());\r
-                               \r
-               if(isVar) {\r
-                       definition.getBeanDefinition().setScope("execution");\r
-                       \r
-                       boolean proxyTargetClass = true;\r
-                       \r
-                       // Register the original bean definition as it will be referenced by the scoped proxy and is relevant for tooling (validation, navigation).\r
-                       String targetBeanName = ScopedProxyUtils.getTargetBeanName(definition.getBeanName());\r
-                       parserContext.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(definition.getBeanDefinition(), targetBeanName));\r
-                       \r
-                       log.debug("Decorating bean " + definition.getBeanName());\r
-                       \r
-                       return ScopedProxyUtils.createScopedProxy(definition, parserContext.getRegistry(), proxyTargetClass);           \r
-               }\r
-               else {\r
-                       return definition;\r
+               definition.getBeanDefinition().setScope("execution");\r
+               \r
+               boolean proxyTargetClass = true;\r
+               if (node instanceof Element) {\r
+                       Element ele = (Element) node;\r
+                       if (ele.hasAttribute(PROXY_TARGET_CLASS)) {\r
+                               proxyTargetClass = Boolean.valueOf(ele.getAttribute(PROXY_TARGET_CLASS)).booleanValue();\r
+                       }\r
                }\r
+               \r
+               // Register the original bean definition as it will be referenced by the scoped proxy and is relevant for tooling (validation, navigation).\r
+               String targetBeanName = ScopedProxyUtils.getTargetBeanName(definition.getBeanName());\r
+               parserContext.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(definition.getBeanDefinition(), targetBeanName));\r
+               \r
+               return ScopedProxyUtils.createScopedProxy(definition, parserContext.getRegistry(), proxyTargetClass);           \r
        }\r
 }\r
index f092bb1ac14649647d6ff7d47c3c26e317d535a9..a1d6912aa9328278591580d1e855175400ecb552 100644 (file)
@@ -10,7 +10,17 @@ public class FlowNamespaceHandler extends NamespaceHandlerSupport {
                registerBeanDefinitionDecoratorForAttribute("as-flow",
                                new AsFlowDecorator());
                registerBeanDefinitionParser("param", new ParamDecorator());
-//             registerBeanDefinitionDecoratorForAttribute("var", new ExecutionScopeDecorator());
+                
+               // The objective was to replace
+               // - attribute scope="execution"
+               // - and element "aop:scoped-proxy" 
+               // by a single attribute, using an attribute decorator 
+               // this does not work correctly with other attribute decorators (e.g. 
+               // p namespace) since this decorator needs to be called after all
+               // properties have been set on target bean. 
+               // It works properly with element decorators (called after all attribute
+               // decorators
+               registerBeanDefinitionDecorator("variable", new ExecutionScopeDecorator());
        }
 
 }
index 884faaa2125de08634a3a7c879fa04eb12ac9d84..7af852fe95258497a7819a71d52b7e818adb507f 100644 (file)
@@ -26,7 +26,7 @@
                        <xsd:complexContent>
                                <xsd:extension base="beans:identifiedType">
                                        <xsd:sequence>
-                                               <xsd:element ref="beans:description" minOccurs="0"/>
+                                               <xsd:element ref="beans:description" minOccurs="0" />
                                                <xsd:sequence>
                                                        <xsd:element name="arg" minOccurs="0" maxOccurs="unbounded"
                                                                type="flow:argType">
@@ -96,7 +96,7 @@
                        <xsd:complexContent>
                                <xsd:extension base="beans:identifiedType">
                                        <xsd:sequence>
-                                               <xsd:element ref="beans:description" minOccurs="0"/>
+                                               <xsd:element ref="beans:description" minOccurs="0" />
                                                <xsd:choice minOccurs="0" maxOccurs="unbounded">
                                                        <xsd:element name="primitive" type="flow:primitiveSpecAttributeType"
                                                                minOccurs="0" maxOccurs="unbounded">
                                        <xsd:choice minOccurs="1" maxOccurs="1">
                                                <xsd:element ref="beans:bean" />
                                                <xsd:element ref="beans:ref" />
+                                               <xsd:element ref="beans:list"/>
+                                               <xsd:element ref="beans:set"/>
+                                               <xsd:element ref="beans:map"/>
+                                               <xsd:element ref="beans:props"/>                                                        
                                        </xsd:choice>
                                </xsd:complexType>
                        </xsd:element>
                        <xsd:element ref="beans:bean" />
                        <xsd:element ref="beans:ref" />
                        <xsd:element ref="flow:param" />
+                       <xsd:element ref="beans:list"/>
+                       <xsd:element ref="beans:set"/>
+                       <xsd:element ref="beans:map"/>
+                       <xsd:element ref="beans:props"/>                        
                </xsd:choice>
                <xsd:attribute name="name" use="required" type="xsd:string">
                        <xsd:annotation>
                        ]]></xsd:documentation>
                </xsd:annotation>
        </xsd:attribute>
-<!--
-       <xsd:attribute name="var" type="xsd:boolean">
-               <xsd:annotation>
-                       <xsd:documentation><![CDATA[
-       If true, the decorated bean is set to scope execution and proxied.
+       <!--
+               <xsd:attribute name="var" type="xsd:boolean"> <xsd:annotation>
+               <xsd:documentation><![CDATA[ If true, the decorated bean is set to
+               scope execution and proxied. ]]></xsd:documentation> </xsd:annotation>
+               </xsd:attribute>
+       -->
+
+       <xsd:element name="variable">
+               <xsd:complexType>
+                       <xsd:annotation>
+                               <xsd:documentation><![CDATA[
+       Marks a bean definition as being variable, i.e. a scoped proxy of scope execution 
                        ]]></xsd:documentation>
-               </xsd:annotation>
-       </xsd:attribute>
--->
+                       </xsd:annotation>
+                       <xsd:attribute name="proxy-target-class" type="xsd:boolean"
+                               default="true">
+                               <xsd:annotation>
+                                       <xsd:documentation><![CDATA[
+                                               Are class-based (CGLIB) proxies to be created?
+                                               This is the default;
+                                               in order to switch to standard Java
+                                               interface-based proxies, turn this flag to
+                                               "false".
+                                       ]]></xsd:documentation>
+                               </xsd:annotation>
+                       </xsd:attribute>
+               </xsd:complexType>
+       </xsd:element>
+       
        <xsd:element name="param">
                <xsd:annotation>
                        <xsd:documentation><![CDATA[
        </xsd:element>
 
        <!-- for description tags, beans or current namespace are valid -->
-       <xsd:element name="description" substitutionGroup="beans:description"/>
+       <xsd:element name="description" substitutionGroup="beans:description" />
 
 </xsd:schema>
\ No newline at end of file
index b9f035db1bed9651ad30d389af23f03d91594d6e..6f7a22206ce2f12878596d6030a90ee89b7532a0 100644 (file)
@@ -1,6 +1,8 @@
 package org.argeo.slc.core.execution.xml;
 
 import org.argeo.slc.core.execution.AbstractExecutionFlowTestCase;
+import org.argeo.slc.core.test.SimpleTestResult;
+import org.argeo.slc.execution.ExecutionContext;
 import org.argeo.slc.execution.ExecutionFlow;
 import org.springframework.context.ConfigurableApplicationContext;
 
@@ -16,5 +18,30 @@ public class FlowNamespaceTest extends AbstractExecutionFlowTestCase {
                ((ExecutionFlow) applicationContext.getBean("flow1")).run();
                ((ExecutionFlow) applicationContext.getBean("flow2")).run();
                ((ExecutionFlow) applicationContext.getBean("flow3")).run();
+               
+               validateTestResult((SimpleTestResult) applicationContext
+                               .getBean("testResult"));                
        }       
+       
+       public void testAdvancedExecution() throws Exception {
+               ConfigurableApplicationContext applicationContext = createApplicationContext("advanced.xml");
+               
+               ExecutionContext executionContext = (ExecutionContext) applicationContext
+               .getBean("executionContext");
+               executionContext.setVariable("param2", 4);
+               
+               ((ExecutionFlow) applicationContext.getBean("flow4")).run();
+               
+               validateTestResult((SimpleTestResult) applicationContext
+                               .getBean("testResult"));                
+       }       
+       
+       public void testContainers() throws Exception {
+               ConfigurableApplicationContext applicationContext = createApplicationContext("containers.xml");
+               ((ExecutionFlow) applicationContext.getBean("test.list.flow1")).run();
+               ((ExecutionFlow) applicationContext.getBean("test.list.flow2")).run();
+               
+               validateTestResult((SimpleTestResult) applicationContext
+                               .getBean("testResult"));                        
+       }
 }
index 4745a10c1c4b015c313b407f55267ac786bfd269..41164516afd6bed775f14ffe831845c8ed6ad2b0 100644 (file)
@@ -1,72 +1,60 @@
 <?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:flow="http://www.argeo.org/schema/slc-flow"\r
+       xmlns:flow="http://www.argeo.org/schema/slc-flow"\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
        http://www.argeo.org/schema/slc-flow http://www.argeo.org/schema/slc-flow-0.12.xsd">\r
 \r
        <import resource="classpath:org/argeo/slc/core/execution/spring.xml" />\r
        <import resource="classpath:/org/argeo/slc/core/test/spring.xml" />\r
 \r
+       <bean id="testResult" class="org.argeo.slc.core.test.SimpleTestResult" />\r
+\r
+       <bean id="testDef" class="org.argeo.slc.core.test.BasicTestDefinition" />\r
+\r
+       <bean id="testRunTemplate" class="org.argeo.slc.core.test.SimpleTestRun" abstract="true">\r
+               <property name="testDefinition" ref="testDef" />\r
+               <property name="testResult" ref="testResult"/>\r
+       </bean> \r
+\r
        <flow:spec id="advanced.spec">\r
                <flow:description>spec description</flow:description>\r
                <flow:primitive name="param1" isParameter="true"\r
                        type="integer" />\r
-               <flow:ref name="param2" targetClass="org.argeo.slc.core.test.BasicTestData"\r
-                       isParameter="true">\r
-                       <flow:value>\r
-                               <bean class="org.argeo.slc.core.test.BasicTestData">\r
-                                       <property name="expected" value="tata" />\r
-                                       <property name="reached" value="tata" />\r
-                               </bean>                         \r
-                       </flow:value>\r
-               </flow:ref>     \r
+               <flow:primitive name="param2" isParameter="true"\r
+                       type="integer" />                       \r
        </flow:spec>\r
 \r
 \r
        <flow:flow id="advanced.flowTemplate" abstract="true" spec="advanced.spec"\r
                path="/path">\r
                <description>flow description</description>\r
-               <bean parent="task.echo"\r
-                       scope="execution">\r
-                       <property name="message" value="Advanced: param1=@{param1}" />\r
-                       <aop:scoped-proxy/>\r
+               <bean parent="task.echo">\r
+                       <property name="message" value="Advanced: param1=@{param1}, param2=@{param2}" />\r
+                       <flow:variable/>\r
                </bean> \r
                <flow:flow>\r
-                       <bean parent="task.echo" p:message="Flow in Flow - param1=@{param1}" />\r
+                       <bean parent="task.echo" p:message="Flow in Flow - param1=@{param1}, param2=@{param2} [Not variable]" />\r
                </flow:flow>\r
  \r
-               <bean class="org.argeo.slc.core.test.SimpleTestRun">\r
-                       <property name="testDefinition">\r
-                               <bean class="org.argeo.slc.core.test.BasicTestDefinition" />\r
-                       </property>\r
+               <bean parent="testRunTemplate">\r
                        <property name="testData">\r
-                               <flow:param name="param2" />\r
-                       </property>\r
-\r
-                       <property name="testResult">\r
-                               <bean parent="slcDefault.test.basicTreeTestResult" scope="execution">\r
-                                       <property name="attributes">\r
-                                               <map>\r
-                                                       <entry key="param1" value="@{param1}" />\r
-                                               </map>\r
-                                       </property>\r
-                                       <aop:scoped-proxy />\r
+                               <bean class="org.argeo.slc.core.test.BasicTestData">\r
+                                       <flow:variable/>\r
+                                       <property name="expected" value="@{param1}" />\r
+                                       <property name="reached" value="@{param2}" />\r
                                </bean>\r
-                       </property>\r
+                       </property>                                     \r
                </bean>\r
  \r
        </flow:flow>\r
 \r
        <flow:flow id="advanced.flowTemplate2" abstract="true" spec="advanced.spec"\r
                path="/path">\r
-               <bean parent="task.echo"\r
-                       scope="execution">\r
-                       <property name="message" value="Advanced2: param1=@{param1}" />\r
-                       <aop:scoped-proxy/>\r
+               <bean parent="task.echo" p:message="Advanced2: param1=@{param1}, param2=@{param2}">\r
+                       <flow:variable/>\r
                </bean>\r
                <flow:flow parent="advanced.flowTemplate">\r
                        <flow:arg name="param1" value="@{param1}"/>\r
        \r
        <flow:flow id="flow1" parent="advanced.flowTemplate">\r
                <flow:arg name="param1" value="1" />\r
+               <flow:arg name="param2" value="1" />\r
        </flow:flow>\r
        \r
        <flow:flow id="flow2">\r
                <flow:flow parent="advanced.flowTemplate">\r
                        <flow:arg name="param1" value="2" />\r
+                       <flow:arg name="param2" value="2" />\r
                </flow:flow>\r
        </flow:flow>\r
 \r
        <flow:flow id="flow3" parent="advanced.flowTemplate2">\r
                <flow:arg name="param1" value="3" />\r
-               <flow:arg name="param2">\r
-                       <bean class="org.argeo.slc.core.test.BasicTestData">\r
-                               <property name="expected" value="tata" />\r
-                               <property name="reached" value="toto" />\r
-                       </bean>         \r
-               </flow:arg>\r
+               <flow:arg name="param2" value="3" />\r
        </flow:flow>\r
+       \r
+       <flow:flow id="flow4" parent="advanced.flowTemplate">\r
+               <description>Would fail if param 2 is not changed at execution</description>\r
+               <flow:arg name="param1" value="4" />\r
+               <flow:arg name="param2" value="3" />\r
+       </flow:flow>    \r
+\r
 \r
 </beans>
\ No newline at end of file
diff --git a/runtime/org.argeo.slc.core/src/test/resources/org/argeo/slc/core/execution/xml/containers.xml b/runtime/org.argeo.slc.core/src/test/resources/org/argeo/slc/core/execution/xml/containers.xml
new file mode 100644 (file)
index 0000000..d727508
--- /dev/null
@@ -0,0 +1,112 @@
+<?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:flow="http://www.argeo.org/schema/slc-flow" 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
+       http://www.argeo.org/schema/slc-flow http://www.argeo.org/schema/slc-flow-0.12.xsd">\r
+\r
+       <import resource="classpath:org/argeo/slc/core/execution/spring.xml" />\r
+       <import resource="classpath:/org/argeo/slc/core/test/spring.xml" />\r
+\r
+       <bean id="testResult" class="org.argeo.slc.core.test.SimpleTestResult" />\r
+\r
+       <bean id="testDef" class="org.argeo.slc.core.test.BasicTestDefinition" />\r
+\r
+       <bean id="testRunTemplate" class="org.argeo.slc.core.test.SimpleTestRun" abstract="true">\r
+               <property name="testDefinition" ref="testDef" />\r
+               <property name="testResult" ref="testResult"/>\r
+       </bean> \r
+\r
+       <flow:spec id="test.list.spec">\r
+               <flow:ref name="list1" targetClass="java.util.List">\r
+                       <flow:value>\r
+                               <!-- a list element can be used directly as default value-->\r
+                               <list>\r
+                                       <value>val1</value>\r
+                               </list>\r
+                       </flow:value>\r
+               </flow:ref>\r
+               <flow:ref name="list2" targetClass="java.util.List" />\r
+               <!-- following parameters are not used in flow -->\r
+               <flow:ref name="dummyMap" targetClass="java.util.Map">\r
+                       <flow:value>\r
+                               <map></map>\r
+                       </flow:value>\r
+               </flow:ref>\r
+               <flow:ref name="dummySet" targetClass="java.util.Set">\r
+                       <flow:value>\r
+                               <set></set>\r
+                       </flow:value>\r
+               </flow:ref>\r
+               <flow:ref name="dummyProperties" targetClass="java.util.Properties">\r
+                       <flow:value>\r
+                               <props></props>\r
+                       </flow:value>\r
+               </flow:ref>\r
+               \r
+       </flow:spec>\r
+\r
+\r
+       <flow:flow id="test.list.flowTemplate" abstract="true" spec="test.list.spec"\r
+               path="/path">\r
+               <bean parent="task.echo">\r
+                       <property name="message" value="list1=@{list1}, list2=@{list2}" />\r
+                       <flow:variable/>\r
+               </bean> \r
+\r
+               <bean parent="testRunTemplate">\r
+                       <property name="testData">\r
+                               <bean class="org.argeo.slc.core.test.BasicTestData">\r
+                                       <property name="expected">\r
+                                               <flow:param name="list1"/>\r
+                                       </property>\r
+                                       <property name="reached">\r
+                                               <flow:param name="list2"/>\r
+                                       </property>\r
+                               </bean>\r
+                       </property>                                     \r
+               </bean>\r
\r
+       </flow:flow>\r
+\r
+       <flow:flow id="test.list.flow1" parent="test.list.flowTemplate">\r
+               <flow:arg name="list1">\r
+                       <list>\r
+                               <value>val1</value>\r
+                               <value>val2</value>                     \r
+                       </list>\r
+               </flow:arg>\r
+               <flow:arg name="list2">\r
+                       <list>\r
+                               <value>val1</value>\r
+                               <value>val2</value>                     \r
+                       </list>\r
+               </flow:arg>\r
+               \r
+               <!-- not used in flow (just to test that the syntax is accepted): -->\r
+               <flow:arg name="dummyMap">\r
+                       <map></map>\r
+               </flow:arg>\r
+               <flow:arg name="dummySet">\r
+                       <set></set>\r
+               </flow:arg>\r
+               <flow:arg name="dummyProperties">\r
+                       <props></props>\r
+               </flow:arg>             \r
+               \r
+       </flow:flow>\r
+       \r
+       <flow:flow id="test.list.flow2" parent="test.list.flowTemplate">\r
+               <description>use default value for parameter "list1"</description>\r
+               <flow:arg name="list2">\r
+                       <list>\r
+                               <value>val1</value>\r
+                       </list>\r
+               </flow:arg>\r
+       </flow:flow>\r
+\r
+\r
+</beans>
\ No newline at end of file