persistence-context element

This commit is contained in:
Keith Donald
2008-02-29 03:19:25 +00:00
parent eee96e21ff
commit eac0a2b47c
10 changed files with 72 additions and 190 deletions

View File

@@ -30,7 +30,6 @@ import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.binding.convert.ConversionException;
import org.springframework.binding.convert.ConversionExecutor;
import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.expression.EvaluationException;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.expression.support.CollectionAddingExpression;
@@ -120,8 +119,6 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
private static final String ID_ATTRIBUTE = "id";
private static final String IDREF_ATTRIBUTE = "idref";
private static final String BEAN_ATTRIBUTE = "bean";
private static final String FLOW_ELEMENT = "flow";
@@ -178,12 +175,8 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
private static final String OUTPUT_MAPPER_ELEMENT = "output-mapper";
private static final String OUTPUT_ATTRIBUTE_ELEMENT = "output-attribute";
private static final String INPUT_MAPPER_ELEMENT = "input-mapper";
private static final String INPUT_ATTRIBUTE_ELEMENT = "input-attribute";
private static final String MAPPING_ELEMENT = "mapping";
private static final String SOURCE_ATTRIBUTE = "source";
@@ -413,8 +406,16 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
}
String flowId = getLocalContext().getFlowId();
AttributeMap externallyAssignedAttributes = getLocalContext().getFlowAttributes();
AttributeMap flowAttributes = parseAttributes(flowElement).union(externallyAssignedAttributes);
return getFlowArtifactFactory().createFlow(flowId, flowAttributes);
MutableAttributeMap flowAttributes = parseAttributes(flowElement);
parseAndSetPersistenceContextAttribute(flowElement, flowAttributes);
return getFlowArtifactFactory().createFlow(flowId, flowAttributes.union(externallyAssignedAttributes));
}
private void parseAndSetPersistenceContextAttribute(Element flowElement, MutableAttributeMap flowAttributes) {
Element element = DomUtils.getChildElementByTagName(flowElement, "persistence-context");
if (element != null) {
flowAttributes.put("persistenceContext", Boolean.TRUE);
}
}
private boolean isFlowElement(Element flowElement) {
@@ -558,7 +559,7 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
} else {
Element startStateElement = DomUtils.getChildElementByTagName(element, startState);
if (startStateElement != null) {
return startStateElement.getAttribute(IDREF_ATTRIBUTE);
return startStateElement.getAttribute("idref");
} else {
return null;
}
@@ -726,16 +727,12 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
continue;
}
if (DomUtils.nodeNameEquals(childNode, ACTION_ELEMENT)) {
// parse standard action
actions.add(parseAnnotatedAction((Element) childNode));
} else if (DomUtils.nodeNameEquals(childNode, BEAN_ACTION_ELEMENT)) {
// parse bean invoking action
actions.add(parseAnnotatedBeanInvokingAction((Element) childNode));
} else if (DomUtils.nodeNameEquals(childNode, EVALUATE_ACTION_ELEMENT)) {
// parse evaluate action
actions.add(parseAnnotatedEvaluateAction((Element) childNode));
} else if (DomUtils.nodeNameEquals(childNode, SET_ELEMENT)) {
// parse set action
actions.add(parseAnnotatedSetAction((Element) childNode));
}
}
@@ -899,7 +896,7 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
}
}
private AttributeMap parseAttributes(Element element) {
private MutableAttributeMap parseAttributes(Element element) {
LocalAttributeMap attributes = new LocalAttributeMap();
List propertyElements = DomUtils.getChildElementsByTagName(element, ATTRIBUTE_ELEMENT);
for (int i = 0; i < propertyElements.size(); i++) {
@@ -982,8 +979,6 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
Element mapperElement = DomUtils.getChildElementByTagName(element, INPUT_MAPPER_ELEMENT);
if (mapperElement != null) {
DefaultAttributeMapper mapper = new DefaultAttributeMapper();
parseSimpleInputAttributeMappings(mapper, DomUtils.getChildElementsByTagName(mapperElement,
INPUT_ATTRIBUTE_ELEMENT));
parseMappings(mapper, mapperElement, MutableAttributeMap.class, RequestContext.class);
return mapper;
} else {
@@ -995,8 +990,6 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
Element mapperElement = DomUtils.getChildElementByTagName(element, INPUT_MAPPER_ELEMENT);
if (mapperElement != null) {
DefaultAttributeMapper mapper = new DefaultAttributeMapper();
parseSimpleInputAttributeMappings(mapper, DomUtils.getChildElementsByTagName(mapperElement,
INPUT_ATTRIBUTE_ELEMENT));
parseMappings(mapper, mapperElement, RequestContext.class, MutableAttributeMap.class);
return mapper;
} else {
@@ -1008,8 +1001,6 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
Element mapperElement = DomUtils.getChildElementByTagName(element, OUTPUT_MAPPER_ELEMENT);
if (mapperElement != null) {
DefaultAttributeMapper mapper = new DefaultAttributeMapper();
parseSimpleOutputAttributeMappings(mapper, DomUtils.getChildElementsByTagName(mapperElement,
OUTPUT_ATTRIBUTE_ELEMENT));
parseMappings(mapper, mapperElement, RequestContext.class, MutableAttributeMap.class);
return mapper;
} else {
@@ -1021,8 +1012,6 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
Element mapperElement = DomUtils.getChildElementByTagName(element, OUTPUT_MAPPER_ELEMENT);
if (mapperElement != null) {
DefaultAttributeMapper mapper = new DefaultAttributeMapper();
parseSimpleOutputAttributeMappings(mapper, DomUtils.getChildElementsByTagName(mapperElement,
OUTPUT_ATTRIBUTE_ELEMENT));
parseMappings(mapper, mapperElement, MutableAttributeMap.class, RequestContext.class);
return mapper;
} else {
@@ -1053,40 +1042,6 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
}
}
// this looks really complicated and possibly wrong
private void parseSimpleInputAttributeMappings(DefaultAttributeMapper mapper, List elements) {
ExpressionParser parser = getLocalContext().getExpressionParser();
for (Iterator it = elements.iterator(); it.hasNext();) {
Element element = (Element) it.next();
Expression attributeExpression = parser.parseExpression(element.getAttribute(NAME_ATTRIBUTE),
new ParserContextImpl().eval(RequestContext.class));
Expression scopedAttributeExpression = new ScopedAttributeExpression(attributeExpression, parseScope(
element, ScopeType.FLOW));
if (getRequired(element, false)) {
mapper.addMapping(new RequiredMapping(attributeExpression, scopedAttributeExpression, null));
} else {
mapper.addMapping(new Mapping(attributeExpression, scopedAttributeExpression, null));
}
}
}
// this looks really complicated and possibly wrong
private void parseSimpleOutputAttributeMappings(DefaultAttributeMapper mapper, List elements) {
ExpressionParser parser = getLocalContext().getExpressionParser();
for (Iterator it = elements.iterator(); it.hasNext();) {
Element element = (Element) it.next();
Expression attributeExpression = parser.parseExpression(element.getAttribute(NAME_ATTRIBUTE),
new ParserContextImpl().eval(RequestContext.class));
Expression scopedAttributeExpression = new ScopedAttributeExpression(attributeExpression, parseScope(
element, ScopeType.FLOW));
if (getRequired(element, false)) {
mapper.addMapping(new RequiredMapping(scopedAttributeExpression, attributeExpression, null));
} else {
mapper.addMapping(new Mapping(scopedAttributeExpression, attributeExpression, null));
}
}
}
private boolean getRequired(Element element, boolean defaultValue) {
if (StringUtils.hasText(element.getAttribute(REQUIRED_ATTRIBUTE))) {
return ((Boolean) fromStringTo(Boolean.class).execute(element.getAttribute(REQUIRED_ATTRIBUTE)))
@@ -1188,28 +1143,6 @@ public class XmlFlowBuilder extends AbstractFlowBuilder implements ResourceHolde
}
}
private static class ScopedAttributeExpression implements Expression {
private Expression scopeMapExpression;
private ScopeType scopeType;
public ScopedAttributeExpression(Expression scopeMapExpression, ScopeType scopeType) {
this.scopeMapExpression = scopeMapExpression;
this.scopeType = scopeType;
}
public Object getValue(Object target) throws EvaluationException {
MutableAttributeMap scopeMap = scopeType.getScope((RequestContext) target);
return scopeMapExpression.getValue(scopeMap);
}
public void setValue(Object target, Object value) throws EvaluationException {
MutableAttributeMap scopeMap = scopeType.getScope((RequestContext) target);
scopeMapExpression.setValue(scopeMap, value);
}
}
private static class FlowRelativeResourceLoader implements ResourceLoader {
private Resource resource;

View File

@@ -201,8 +201,11 @@ A flow may also exhibit the following characteristics:
<ul>
<li>Be annotated with attributes that define descriptive properties that may affect flow execution.
(See the &lt;attribute/&gt; element)
<li>Be a persistence context for managing persistent objects during the course of flow execution.
(See the &lt;persistence-context/&gt; element)
<li>Instantiate a set of application variables when started.
<li>Instantiate a set of instance variables when started.
(See the &lt;var/&gt; element)
<li>Map input provided by callers that start it
@@ -239,6 +242,19 @@ An attribute describing this flow.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element ref="persistence-context" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Indicates this flow manages a persistence context. The persistence context is created when a new instance of this flow starts.
The persistence context is closed when the flow instance ends. If the flow ends by reaching a "commit" end-state, changes
made to managed persistent entities during the course of flow execution are flushed to the database in a transaction.
<br>
The persistence context can be referenced from within this flow by the "entityManager" variable.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element ref="var" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
@@ -489,17 +505,6 @@ The identifier of the start state of this flow. The start state is the point wh
<xsd:element name="input-mapper">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="input-attribute" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
A rule that maps an input attribute in a source attribute map to a target attribute map.
This is a convenient form of the more flexible 'mapping' element for mapping attributes between
attribute maps.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element ref="mapping" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
@@ -580,39 +585,6 @@ evaluates to null an error will be reported.
</xsd:complexType>
</xsd:element>
<xsd:element name="input-attribute">
<xsd:complexType>
<xsd:attribute name="name" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The name of the input attribute.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="scope" type="scopeType" default="default">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The scope of the input attribute. If not specified the default scope type is used ('flow' by default).
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="required" type="xsd:boolean">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Whether or not this input attribute is required. If marked required and it evaluates to null
an error will be reported.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="attribute">
<xsd:complexType>
<xsd:sequence>
@@ -662,6 +634,9 @@ The value of this attribute; a short-cut alternative to an explicit child 'value
<xsd:choice minOccurs="0" maxOccurs="unbounded" />
</xsd:complexType>
</xsd:element>
<xsd:element name="persistence-context">
</xsd:element>
<xsd:element name="var">
<xsd:complexType>
@@ -1651,18 +1626,6 @@ For the output mapper the following mapping characteristics apply:
<li>The 'target' of each output mapping is the RequestContext, exposing access to
internal data structures of this flow such as flowScope.
</ul>
<br>
For example:
<pre>
&lt;attribute-mapper&gt;
&lt;input-mapper&gt;
&lt;input-attribute name="myFlowAttribute"/&gt;
&lt;/input-mapper&gt;
&lt;output-mapper&gt;
&lt;output-attribute name="aSubflowOutputAttribute"/&gt;
&lt;/output-mapper&gt;
&lt;/attribute-mapper&gt;
</pre>
]]>
</xsd:documentation>
</xsd:annotation>
@@ -1925,17 +1888,6 @@ and may execute one or more actions before executing.
<xsd:element name="output-mapper">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="output-attribute" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
A rule that maps an output attribute in a source attribute map to a target attribute map.
This is a convenient form of the more flexible 'mapping' element for mapping attributes between
attribute maps.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element ref="mapping" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
@@ -1951,39 +1903,6 @@ support for type conversion.
</xsd:complexType>
</xsd:element>
<xsd:element name="output-attribute">
<xsd:complexType>
<xsd:attribute name="name" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The name of the output attribute.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="scope" type="scopeType" default="default">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The scope of the output attribute. If not specified the default scope type is used ('flow' by default).
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="required" type="xsd:boolean">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
Whether or not this output attribute is required. If marked required and it evaluates to null
an error will be reported.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="exception-handler">
<xsd:complexType>
<xsd:attribute name="bean" type="xsd:string" use="required">

View File

@@ -65,4 +65,21 @@ public class XmlFlowBuilderTests extends TestCase {
assertEquals("end", flow.getStartState().getId());
}
public void testCustomFlowAttribute() {
ClassPathResource resource = new ClassPathResource("flow-custom-attribute.xml", getClass());
builder = new XmlFlowBuilder(resource);
FlowAssembler assembler = new FlowAssembler(builder, new MockFlowBuilderContext("flow"));
Flow flow = assembler.assembleFlow();
assertEquals("bar", flow.getAttributes().get("foo"));
assertEquals(new Integer(1), flow.getAttributes().get("number"));
}
public void testPersistenceContextFlow() {
ClassPathResource resource = new ClassPathResource("flow-persistencecontext.xml", getClass());
builder = new XmlFlowBuilder(resource);
FlowAssembler assembler = new FlowAssembler(builder, new MockFlowBuilderContext("flow"));
Flow flow = assembler.assembleFlow();
assertNotNull(flow.getAttributes().get("persistenceContext"));
assertTrue(((Boolean) flow.getAttributes().get("persistenceContext")).booleanValue());
}
}

View File

@@ -0,0 +1,9 @@
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<attribute name="foo" value="bar"/>
<attribute name="number" value="1" type="integer"/>
<end-state id="end"/>
</flow>

View File

@@ -1,7 +1,6 @@
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd" start-state="end">
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<end-state id="end"/>

View File

@@ -1,6 +1,5 @@
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
</flow>

View File

@@ -0,0 +1,9 @@
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<persistence-context/>
<end-state id="end"/>
</flow>

View File

@@ -1,7 +1,6 @@
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd" start-state="end">
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd" start-state="end">
<end-state id="foo"/>
<end-state id="end"/>

View File

@@ -1,7 +1,6 @@
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<end-state id="end"/>

View File

@@ -1,7 +1,6 @@
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<start-state idref="end"/>