IN PROGRESS - issue SWF-545: Add support for merging a state in one flow model with a state in another
http://jira.springframework.org/browse/SWF-545
This commit is contained in:
@@ -26,6 +26,7 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public abstract class AbstractStateModel extends AbstractModel {
|
||||
private String id;
|
||||
private String parent;
|
||||
private LinkedList attributes;
|
||||
private SecuredModel secured;
|
||||
private LinkedList onEntryActions;
|
||||
@@ -49,6 +50,24 @@ public abstract class AbstractStateModel extends AbstractModel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the parent
|
||||
*/
|
||||
public String getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param parent the parent to set
|
||||
*/
|
||||
public void setParent(String parent) {
|
||||
if (StringUtils.hasText(parent)) {
|
||||
this.parent = parent;
|
||||
} else {
|
||||
this.parent = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the attributes
|
||||
*/
|
||||
|
||||
@@ -44,6 +44,7 @@ public class ActionStateModel extends AbstractTransitionableStateModel {
|
||||
|
||||
public void merge(Model model) {
|
||||
ActionStateModel state = (ActionStateModel) model;
|
||||
setParent(null);
|
||||
setAttributes(merge(getAttributes(), state.getAttributes()));
|
||||
setSecured((SecuredModel) merge(getSecured(), state.getSecured()));
|
||||
setOnEntryActions(merge(getOnEntryActions(), state.getOnEntryActions(), false));
|
||||
|
||||
@@ -45,12 +45,12 @@ public class AttributeModel extends AbstractModel {
|
||||
return false;
|
||||
}
|
||||
AttributeModel attribute = (AttributeModel) model;
|
||||
return ObjectUtils.nullSafeEquals(getName(), attribute.getName())
|
||||
&& ObjectUtils.nullSafeEquals(getValue(), attribute.getValue());
|
||||
return ObjectUtils.nullSafeEquals(getName(), attribute.getName());
|
||||
}
|
||||
|
||||
public void merge(Model model) {
|
||||
AttributeModel attribute = (AttributeModel) model;
|
||||
setValue(merge(getValue(), attribute.getValue()));
|
||||
setType(merge(getType(), attribute.getType()));
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ public class DecisionStateModel extends AbstractStateModel {
|
||||
|
||||
public void merge(Model model) {
|
||||
DecisionStateModel state = (DecisionStateModel) model;
|
||||
setParent(null);
|
||||
setAttributes(merge(getAttributes(), state.getAttributes()));
|
||||
setSecured((SecuredModel) merge(getSecured(), state.getSecured()));
|
||||
setOnEntryActions(merge(getOnEntryActions(), state.getOnEntryActions(), false));
|
||||
|
||||
@@ -47,6 +47,7 @@ public class EndStateModel extends AbstractStateModel {
|
||||
|
||||
public void merge(Model model) {
|
||||
EndStateModel state = (EndStateModel) model;
|
||||
setParent(null);
|
||||
setAttributes(merge(getAttributes(), state.getAttributes()));
|
||||
setSecured((SecuredModel) merge(getSecured(), state.getSecured()));
|
||||
setOnEntryActions(merge(getOnEntryActions(), state.getOnEntryActions(), false));
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.webflow.engine.model;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -371,6 +372,23 @@ public class FlowModel extends AbstractModel {
|
||||
return states;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state model for an identifier
|
||||
* @param id the state identifier to find
|
||||
* @return the state or null if the identifier was not found
|
||||
*/
|
||||
public AbstractStateModel getStateById(String id) {
|
||||
if (states != null) {
|
||||
for (Iterator it = states.iterator(); it.hasNext();) {
|
||||
AbstractStateModel state = (AbstractStateModel) it.next();
|
||||
if (id.equals(state.getId())) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param states the states to set
|
||||
*/
|
||||
|
||||
@@ -50,6 +50,7 @@ public class SubflowStateModel extends AbstractTransitionableStateModel {
|
||||
|
||||
public void merge(Model model) {
|
||||
SubflowStateModel state = (SubflowStateModel) model;
|
||||
setParent(null);
|
||||
setAttributes(merge(getAttributes(), state.getAttributes()));
|
||||
setSecured((SecuredModel) merge(getSecured(), state.getSecured()));
|
||||
setOnEntryActions(merge(getOnEntryActions(), state.getOnEntryActions(), false));
|
||||
|
||||
@@ -51,6 +51,7 @@ public class ViewStateModel extends AbstractTransitionableStateModel {
|
||||
|
||||
public void merge(Model model) {
|
||||
ViewStateModel state = (ViewStateModel) model;
|
||||
setParent(null);
|
||||
setAttributes(merge(getAttributes(), state.getAttributes()));
|
||||
setSecured((SecuredModel) merge(getSecured(), state.getSecured()));
|
||||
setOnEntryActions(merge(getOnEntryActions(), state.getOnEntryActions(), false));
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.webflow.engine.model.builder.xml;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -121,6 +122,11 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
|
||||
"The FlowModelBuilder must be initialized first -- called init() before calling build()");
|
||||
}
|
||||
flowModel = parseFlow(getDocumentElement());
|
||||
mergeFlows();
|
||||
mergeStates();
|
||||
}
|
||||
|
||||
protected void mergeFlows() {
|
||||
if (flowModel.getParent() != null) {
|
||||
List parents = Arrays.asList(StringUtils.trimArrayElements(flowModel.getParent().split(",")));
|
||||
for (Iterator it = parents.iterator(); it.hasNext();) {
|
||||
@@ -137,6 +143,42 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
protected void mergeStates() {
|
||||
if (flowModel.getStates() == null) {
|
||||
return;
|
||||
}
|
||||
for (Iterator it = flowModel.getStates().iterator(); it.hasNext();) {
|
||||
AbstractStateModel childState = (AbstractStateModel) it.next();
|
||||
String parent = childState.getParent();
|
||||
if (childState.getParent() != null) {
|
||||
String flowId;
|
||||
String stateId;
|
||||
AbstractStateModel parentState = null;
|
||||
if (parent.contains("#")) {
|
||||
flowId = parent.substring(0, parent.indexOf("#")).trim();
|
||||
stateId = parent.substring(parent.indexOf("#") + 1).trim();
|
||||
} else {
|
||||
flowId = parent.trim();
|
||||
stateId = childState.getId();
|
||||
}
|
||||
try {
|
||||
parentState = modelLocator.getFlowModel(flowId).getStateById(stateId);
|
||||
if (parentState == null) {
|
||||
throw new FlowModelBuilderException("Unable to find state '" + stateId + "' in flow '" + flowId
|
||||
+ "'");
|
||||
}
|
||||
childState.merge(parentState);
|
||||
} catch (NoSuchFlowModelException e) {
|
||||
throw new FlowModelBuilderException("Unable to find flow '" + flowId + "' to inherit from", e);
|
||||
} catch (ClassCastException e) {
|
||||
throw new FlowModelBuilderException("Parent state type '" + parentState.getClass().getName()
|
||||
+ "' cannot be merged with state type '" + childState.getClass().getName() + "'", e);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FlowModel getFlowModel() throws FlowModelBuilderException {
|
||||
return flowModel;
|
||||
}
|
||||
@@ -245,7 +287,8 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
|
||||
}
|
||||
|
||||
private LinkedList parseActions(Element element) {
|
||||
List actionElements = getChildElementsByTagNames(element, new String[] { "evaluate", "render", "set" });
|
||||
List actionElements = getChildElementsByTagNames(element, Arrays.asList(new String[] { "evaluate", "render",
|
||||
"set" }));
|
||||
if (actionElements.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@@ -257,8 +300,8 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
|
||||
}
|
||||
|
||||
private LinkedList parseStates(Element element) {
|
||||
List stateElements = getChildElementsByTagNames(element, new String[] { "view-state", "action-state",
|
||||
"decision-state", "subflow-state", "end-state" });
|
||||
List stateElements = getChildElementsByTagNames(element, Arrays.asList(new String[] { "view-state",
|
||||
"action-state", "decision-state", "subflow-state", "end-state" }));
|
||||
if (stateElements.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@@ -503,6 +546,7 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
|
||||
|
||||
private ActionStateModel parseActionState(Element element) {
|
||||
ActionStateModel state = new ActionStateModel(element.getAttribute("id"));
|
||||
state.setParent(element.getAttribute("parent"));
|
||||
state.setAttributes(parseAttributes(element));
|
||||
state.setSecured(parseSecured(element));
|
||||
state.setOnEntryActions(parseOnEntryActions(element));
|
||||
@@ -515,6 +559,7 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
|
||||
|
||||
private ViewStateModel parseViewState(Element element) {
|
||||
ViewStateModel state = new ViewStateModel(element.getAttribute("id"));
|
||||
state.setParent(element.getAttribute("parent"));
|
||||
state.setView(element.getAttribute("view"));
|
||||
state.setRedirect(element.getAttribute("redirect"));
|
||||
state.setPopup(element.getAttribute("popup"));
|
||||
@@ -532,6 +577,7 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
|
||||
|
||||
private DecisionStateModel parseDecisionState(Element element) {
|
||||
DecisionStateModel state = new DecisionStateModel(element.getAttribute("id"));
|
||||
state.setParent(element.getAttribute("parent"));
|
||||
state.setIfs(parseIfs(element));
|
||||
state.setOnExitActions(parseOnExitActions(element));
|
||||
state.setAttributes(parseAttributes(element));
|
||||
@@ -543,6 +589,7 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
|
||||
|
||||
private SubflowStateModel parseSubflowState(Element element) {
|
||||
SubflowStateModel state = new SubflowStateModel(element.getAttribute("id"), element.getAttribute("subflow"));
|
||||
state.setParent(element.getAttribute("parent"));
|
||||
state.setSubflowAttributeMapper(element.getAttribute("subflow-attribute-mapper"));
|
||||
state.setInputs(parseInputs(element));
|
||||
state.setOutputs(parseOutputs(element));
|
||||
@@ -557,6 +604,7 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
|
||||
|
||||
private EndStateModel parseEndState(Element element) {
|
||||
EndStateModel state = new EndStateModel(element.getAttribute("id"));
|
||||
state.setParent(element.getAttribute("parent"));
|
||||
state.setView(element.getAttribute("view"));
|
||||
state.setCommit(element.getAttribute("commit"));
|
||||
state.setOutputs(parseOutputs(element));
|
||||
@@ -567,18 +615,23 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
|
||||
return state;
|
||||
}
|
||||
|
||||
// TODO: submit this to DomUtils in spring-core then remove here
|
||||
private static List getChildElementsByTagNames(Element element, String[] childElementNames) {
|
||||
List names = Arrays.asList(childElementNames);
|
||||
NodeList nodeList = element.getChildNodes();
|
||||
List childElements = new ArrayList();
|
||||
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||
Node node = nodeList.item(i);
|
||||
if (node instanceof Element && (names.contains(node.getLocalName()) || names.contains(node.getNodeName()))) {
|
||||
childElements.add(node);
|
||||
// TODO: submited to DomUtils in spring-core will be available in 2.5.3
|
||||
public static List getChildElementsByTagNames(Element ele, Collection childEleNames) {
|
||||
Assert.notNull(ele, "Element must not be null");
|
||||
Assert.notNull(childEleNames, "Element names collection must not be null");
|
||||
NodeList nl = ele.getChildNodes();
|
||||
List childEles = new ArrayList();
|
||||
for (int i = 0; i < nl.getLength(); i++) {
|
||||
Node node = nl.item(i);
|
||||
if (node instanceof Element && nodeNameMatch(node, childEleNames)) {
|
||||
childEles.add(node);
|
||||
}
|
||||
}
|
||||
return childElements;
|
||||
return childEles;
|
||||
}
|
||||
|
||||
private static boolean nodeNameMatch(Node node, Collection desiredNames) {
|
||||
return (desiredNames.contains(node.getNodeName()) || desiredNames.contains(node.getLocalName()));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
||||
@@ -206,7 +206,7 @@ A transition out of this state is driven by the result of action execution.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:sequence minOccurs="0">
|
||||
<xsd:element name="attribute" type="attribute" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
@@ -276,6 +276,19 @@ Handles exceptions that occur within this state.
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The unique identifier of this state; must be unique to this flow.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="parent" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Flow identifier to inherit from for this state only. By default, the inherited flow's state identifer will match this state's identifier.
|
||||
<p>
|
||||
For example <pre><state id="state" parent="flow"></pre> defaults to <pre><state id="state" parent="flow#state"></pre>.
|
||||
To inherit from a different identifier <pre><state id="state" parent="flow#other"></pre>
|
||||
</ul>
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
@@ -428,6 +441,19 @@ Handles exceptions that occur within this state.
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The unique identifier of this state; must be unique to this flow.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="parent" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Flow identifier to inherit from for this state only. By default, the inherited flow's state identifer will match this state's identifier.
|
||||
<p>
|
||||
For example <pre><state id="state" parent="flow"></pre> defaults to <pre><state id="state" parent="flow#state"></pre>.
|
||||
To inherit from a different identifier <pre><state id="state" parent="flow#other"></pre>
|
||||
</ul>
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
@@ -617,6 +643,19 @@ Handles exceptions that occur within this state.
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The unique identifier of this state; must be unique to this flow.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="parent" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Flow identifier to inherit from for this state only. By default, the inherited flow's state identifer will match this state's identifier.
|
||||
<p>
|
||||
For example <pre><state id="state" parent="flow"></pre> defaults to <pre><state id="state" parent="flow#state"></pre>.
|
||||
To inherit from a different identifier <pre><state id="state" parent="flow#other"></pre>
|
||||
</ul>
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
@@ -636,7 +675,7 @@ A transition is triggered by the subflow outcome that was reached.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:sequence minOccurs="0" >
|
||||
<xsd:element name="attribute" type="attribute" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
@@ -727,7 +766,20 @@ The unique identifier of this state; must be unique to this flow.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="subflow" type="flowId" use="required">
|
||||
<xsd:attribute name="parent" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Flow identifier to inherit from for this state only. By default, the inherited flow's state identifer will match this state's identifier.
|
||||
<p>
|
||||
For example <pre><state id="state" parent="flow"></pre> defaults to <pre><state id="state" parent="flow#state"></pre>.
|
||||
To inherit from a different identifier <pre><state id="state" parent="flow#other"></pre>
|
||||
</ul>
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="subflow" type="flowId">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
@@ -818,6 +870,19 @@ Handles exceptions that occur in this state.
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The unique identifier of this state; must be unique to this flow.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="parent" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Flow identifier to inherit from for this state only. By default, the inherited flow's state identifer will match this state's identifier.
|
||||
<p>
|
||||
For example <pre><state id="state" parent="flow"></pre> defaults to <pre><state id="state" parent="flow#state"></pre>.
|
||||
To inherit from a different identifier <pre><state id="state" parent="flow#other"></pre>
|
||||
</ul>
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
@@ -172,6 +172,7 @@ public class XmlFlowModelBuilderTests extends TestCase {
|
||||
fail("A FlowModelConstructionException was expected");
|
||||
} catch (FlowModelConstructionException e) {
|
||||
// we want this
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,4 +185,73 @@ public class XmlFlowModelBuilderTests extends TestCase {
|
||||
assertEquals(4, flow.getOnStartActions().size());
|
||||
}
|
||||
|
||||
public void testStateMerge() {
|
||||
ClassPathResource resourceChild = new ClassPathResource("flow-inheritance-state-child.xml", getClass());
|
||||
ClassPathResource resourceParent = new ClassPathResource("flow-inheritance-state-parent.xml", getClass());
|
||||
registry
|
||||
.registerFlowModel(new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry), "child"));
|
||||
registry.registerFlowModel(new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceParent, registry),
|
||||
"parent"));
|
||||
FlowModel flow = registry.getFlowModel("child");
|
||||
assertEquals(1, flow.getStates().size());
|
||||
assertEquals("otherview", ((ViewStateModel) flow.getStates().get(0)).getView());
|
||||
}
|
||||
|
||||
public void testStateMergeDefault() {
|
||||
ClassPathResource resourceChild = new ClassPathResource("flow-inheritance-state-child-default.xml", getClass());
|
||||
ClassPathResource resourceParent = new ClassPathResource("flow-inheritance-state-parent.xml", getClass());
|
||||
registry
|
||||
.registerFlowModel(new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry), "child"));
|
||||
registry.registerFlowModel(new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceParent, registry),
|
||||
"parent"));
|
||||
FlowModel flow = registry.getFlowModel("child");
|
||||
assertEquals(1, flow.getStates().size());
|
||||
assertEquals("mainview", ((ViewStateModel) flow.getStates().get(0)).getView());
|
||||
}
|
||||
|
||||
public void testStateMergeParentFlowNotFound() {
|
||||
ClassPathResource resourceChild = new ClassPathResource("flow-inheritance-state-child.xml", getClass());
|
||||
ClassPathResource resourceParent = new ClassPathResource("flow-inheritance-state-parent.xml", getClass());
|
||||
registry
|
||||
.registerFlowModel(new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry), "child"));
|
||||
registry.registerFlowModel(new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceParent, registry),
|
||||
"parent-id-not-matching"));
|
||||
try {
|
||||
registry.getFlowModel("child");
|
||||
fail("A FlowModelConstructionException was expected");
|
||||
} catch (FlowModelConstructionException e) {
|
||||
// we want this
|
||||
}
|
||||
}
|
||||
|
||||
public void testStateMergeParentStateNotFound() {
|
||||
ClassPathResource resourceChild = new ClassPathResource("flow-inheritance-state-child.xml", getClass());
|
||||
ClassPathResource resourceParent = new ClassPathResource("flow-empty.xml", getClass());
|
||||
registry
|
||||
.registerFlowModel(new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry), "child"));
|
||||
registry.registerFlowModel(new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceParent, registry),
|
||||
"parent"));
|
||||
try {
|
||||
registry.getFlowModel("child");
|
||||
fail("A FlowModelConstructionException was expected");
|
||||
} catch (FlowModelConstructionException e) {
|
||||
// we want this
|
||||
}
|
||||
}
|
||||
|
||||
public void testStateMergeParentStateIncompatable() {
|
||||
ClassPathResource resourceChild = new ClassPathResource("flow-inheritance-state-child-alt.xml", getClass());
|
||||
ClassPathResource resourceParent = new ClassPathResource("flow-inheritance-state-parent.xml", getClass());
|
||||
registry
|
||||
.registerFlowModel(new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry), "child"));
|
||||
registry.registerFlowModel(new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceParent, registry),
|
||||
"parent"));
|
||||
try {
|
||||
registry.getFlowModel("child");
|
||||
fail("A FlowModelConstructionException was expected");
|
||||
} catch (FlowModelConstructionException e) {
|
||||
// we want this
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +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">
|
||||
|
||||
</flow>
|
||||
@@ -0,0 +1,7 @@
|
||||
<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">
|
||||
|
||||
<action-state id="view" parent="parent" />
|
||||
|
||||
</flow>
|
||||
@@ -0,0 +1,7 @@
|
||||
<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">
|
||||
|
||||
<view-state id="view" parent="parent" />
|
||||
|
||||
</flow>
|
||||
@@ -0,0 +1,7 @@
|
||||
<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">
|
||||
|
||||
<view-state id="view" parent="parent#other" />
|
||||
|
||||
</flow>
|
||||
@@ -0,0 +1,8 @@
|
||||
<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">
|
||||
|
||||
<view-state id="view" view="mainview"/>
|
||||
<view-state id="other" view="otherview"/>
|
||||
|
||||
</flow>
|
||||
Reference in New Issue
Block a user