}\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
// set the flow name if it is DefaultExecutionFlow\r
if (flow instanceof DefaultExecutionFlow) {\r
((DefaultExecutionFlow) flow).setBeanName(flowName);\r
}\r
+ \r
+ if (log.isTraceEnabled())\r
+ log.trace("Start initialization of " + flow.hashCode() + " ("\r
+ + flow + " - " + flow.getClass() + ")");\r
\r
// log.info("# flowInitializationStarted " + flowName);\r
// create a stack for this thread if there is none\r
if (log.isTraceEnabled())\r
log.trace("Finish initialization of " + flow.hashCode() + " ("\r
+ flow + " - " + flow.getClass() + ")");\r
- ExecutionFlow registeredFlow = flowStack.get().pop();\r
- 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
+ \r
+ if(flowStack.get() != null) {\r
+ ExecutionFlow registeredFlow = flowStack.get().pop();\r
+ 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
+ }\r
+ }\r
+ else {\r
+ // happens for flows imported as services\r
+ log.warn("flowInitializationFinished - Flow Stack is null");\r
}\r
}\r
\r
--- /dev/null
+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.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
+ */\r
+public class ExecutionScopeDecorator implements BeanDefinitionDecorator {\r
+ private Log log = LogFactory.getLog(ExecutionScopeDecorator.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
+ }\r
+ }\r
+}\r
if (StringUtils.hasText(parent))
builder.setParentName(parent);
+
+ builder.getBeanDefinition().setDescription(DomUtils.getChildElementValueByTagName(element,
+ "description"));
+
List<Element> execElems = new ArrayList<Element>();
List<Element> argsElems = new ArrayList<Element>();
NodeList nodeList = element.getChildNodes();
if (node instanceof Element) {
if (DomUtils.nodeNameEquals(node, "arg"))
argsElems.add((Element) node);
- else
+ else if(!DomUtils.nodeNameEquals(node, "description"))
execElems.add((Element) node);
}
}
// Executables
if (execElems.size() != 0) {
ManagedList executables = new ManagedList(execElems.size());
- for (int i = 0; i < execElems.size(); i++) {
- Element child = execElems.get(i);
- String name = child.getLocalName();
- if (DomUtils.nodeNameEquals(child, "bean")
- || DomUtils.nodeNameEquals(child, "ref")) {
- // Object target = parseBeanReference((Element) child,
- // parserContext, builder);
- executables.add(NamespaceUtils.parseBeanOrReference(child,
- parserContext, builder.getBeanDefinition()));
- } else if (DomUtils.nodeNameEquals(child, "flow")) {
- throw new SlcException(
- "Nested flows are not yet supported, use a standard ref to another flow.");
- } else {
- throw new SlcException("Unsupported child '" + name + "'");
- }
+ for(Element child : execElems) {
+ // child validity check is performed in xsd
+ executables.add(NamespaceUtils.parseBeanOrReference(child,
+ parserContext, builder.getBeanDefinition()));
}
builder.addPropertyValue("executables", executables);
}
registerBeanDefinitionDecoratorForAttribute("as-flow",
new AsFlowDecorator());
registerBeanDefinitionParser("param", new ParamDecorator());
+// registerBeanDefinitionDecoratorForAttribute("var", new ExecutionScopeDecorator());
}
}
@Override
protected void doParse(Element element, ParserContext parserContext,
BeanDefinitionBuilder builder) {
+ builder.getBeanDefinition().setDescription(DomUtils.getChildElementValueByTagName(element,
+ "description"));
+
ManagedMap attributes = new ManagedMap();
// Primitives
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:sequence>
+ <xsd:element ref="beans:description" minOccurs="0"/>
<xsd:sequence>
<xsd:element name="arg" minOccurs="0" maxOccurs="unbounded"
type="flow:argType">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element ref="beans:bean" />
<xsd:element ref="beans:ref" />
+ <xsd:element ref="flow:flow" />
</xsd:choice>
<!--
<xsd:any namespace="##other" processContents="strict"
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:sequence>
+ <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="0" maxOccurs="1">
<xsd:element ref="beans:bean" />
<xsd:element ref="beans:ref" />
+ <xsd:element ref="flow:param" />
</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:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
+-->
<xsd:element name="param">
<xsd:annotation>
<xsd:documentation><![CDATA[
</xsd:complexType>
</xsd:element>
+ <!-- for description tags, beans or current namespace are valid -->
+ <xsd:element name="description" substitutionGroup="beans:description"/>
+
</xsd:schema>
\ No newline at end of file
((ExecutionFlow) applicationContext.getBean("canonic-ns.001")).run();
((ExecutionFlow) applicationContext.getBean("canonic-ns.002")).run();
}
+
+ public void testAdvanced() throws Exception {
+ ConfigurableApplicationContext applicationContext = createApplicationContext("advanced.xml");
+ ((ExecutionFlow) applicationContext.getBean("flow1")).run();
+ ((ExecutionFlow) applicationContext.getBean("flow2")).run();
+ ((ExecutionFlow) applicationContext.getBean("flow3")).run();
+ }
}
--- /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:aop="http://www.springframework.org/schema/aop" 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
+ <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: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> \r
+ <flow:flow>\r
+ <bean parent="task.echo" p:message="Flow in Flow - param1=@{param1}" />\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
+ <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>\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>\r
+ <flow:flow parent="advanced.flowTemplate">\r
+ <flow:arg name="param1" value="@{param1}"/>\r
+ <flow:arg name="param2">\r
+ <!-- flow:param in flow:arg -->\r
+ <flow:param name="param2" />\r
+ </flow:arg>\r
+ </flow:flow>\r
+ </flow:flow>\r
+\r
+ \r
+ <flow:flow id="flow1" parent="advanced.flowTemplate">\r
+ <flow:arg name="param1" 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: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:flow>\r
+\r
+</beans>
\ No newline at end of file