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
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());
}
}
<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">
<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
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;
((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"));
+ }
}
<?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
--- /dev/null
+<?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