diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/DefaultFlowModelHolder.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/DefaultFlowModelHolder.java index 420c6d20..f03480ba 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/DefaultFlowModelHolder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/DefaultFlowModelHolder.java @@ -60,7 +60,7 @@ public class DefaultFlowModelHolder implements FlowModelHolder { if (flowModel == null) { assembleFlowModel(); } else { - if (flowModelBuilder.hasFlowModelChanged()) { + if (flowModelBuilder.hasFlowModelResourceChanged()) { assembleFlowModel(); } } @@ -72,7 +72,7 @@ public class DefaultFlowModelHolder implements FlowModelHolder { } public boolean hasFlowModelChanged() { - return flowModelBuilder.hasFlowModelChanged(); + return flowModelBuilder.hasFlowModelResourceChanged(); } public synchronized void refresh() { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/FlowModelBuilder.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/FlowModelBuilder.java index c66526cf..32633e0b 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/FlowModelBuilder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/FlowModelBuilder.java @@ -69,16 +69,18 @@ public interface FlowModelBuilder { */ public void dispose() throws FlowModelBuilderException; - /** - * Returns true if the underlying flow model has changed since the last call to {@link #init()}. - * @return true if the flow model has changed - */ - public boolean hasFlowModelChanged(); - /** * Get the underlying flow model resource accessed to build this flow model. Returns null if this builder does not * construct the flow model from a resource. * @return the flow model resource */ public Resource getFlowModelResource(); + + /** + * Returns true if the underlying flow model resource has changed since the last call to {@link #init()}. Always + * returns false if the flow model is not build from a resource. + * @return true if the resource backing the flow model has changed + */ + public boolean hasFlowModelResourceChanged(); + } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/xml/XmlFlowModelBuilder.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/xml/XmlFlowModelBuilder.java index 1ba45d21..27b152df 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/xml/XmlFlowModelBuilder.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/model/builder/xml/XmlFlowModelBuilder.java @@ -75,10 +75,10 @@ public class XmlFlowModelBuilder implements FlowModelBuilder { private Document document; - private FlowModel flowModel; - private long lastModifiedTimestamp; + private FlowModel flowModel; + /** * Create a new XML flow model builder that will parse the XML document at the specified resource location and use * the provided locator to access parent flow models. @@ -111,7 +111,7 @@ public class XmlFlowModelBuilder implements FlowModelBuilder { public void init() throws FlowModelBuilderException { try { document = documentLoader.loadDocument(resource); - lastModifiedTimestamp = resource.lastModified(); + initLastModifiedTimestamp(); } catch (IOException e) { throw new FlowModelBuilderException("Could not access the XML flow definition at " + resource, e); } catch (ParserConfigurationException e) { @@ -132,59 +132,11 @@ public class XmlFlowModelBuilder implements FlowModelBuilder { mergeStates(); } - protected void mergeFlows() { - if (flowModel.getParent() != null) { - List parents = Arrays.asList(StringUtils.trimArrayElements(flowModel.getParent().split(","))); - for (Iterator it = parents.iterator(); it.hasNext();) { - String parentFlowId = (String) it.next(); - if (StringUtils.hasText(parentFlowId)) { - try { - flowModel.merge(modelLocator.getFlowModel(parentFlowId)); - } catch (NoSuchFlowModelException e) { - throw new FlowModelBuilderException("Unable to find flow '" + parentFlowId - + "' to inherit from", e); - } - } - } - } - } - - 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("#")) { - throw new FlowModelBuilderException("Invalid parent syntax '" + parent - + "', should take form 'flowId#stateId'"); - } - flowId = parent.substring(0, parent.indexOf("#")).trim(); - stateId = parent.substring(parent.indexOf("#") + 1).trim(); - 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 { + if (flowModel == null) { + throw new FlowModelBuilderException( + "The FlowModel must be built first -- called init() and build() before calling getFlowModel()"); + } return flowModel; } @@ -197,7 +149,10 @@ public class XmlFlowModelBuilder implements FlowModelBuilder { return resource; } - public boolean hasFlowModelChanged() { + public boolean hasFlowModelResourceChanged() { + if (lastModifiedTimestamp == -1) { + return false; + } try { long lastModified = resource.lastModified(); if (lastModified > lastModifiedTimestamp) { @@ -230,6 +185,14 @@ public class XmlFlowModelBuilder implements FlowModelBuilder { this.modelLocator = modelLocator; } + private void initLastModifiedTimestamp() { + try { + lastModifiedTimestamp = resource.lastModified(); + } catch (IOException e) { + lastModifiedTimestamp = -1; + } + } + private FlowModel parseFlow(Element element) { FlowModel flow = new FlowModel(); flow.setAbstract(element.getAttribute("abstract")); @@ -659,6 +622,58 @@ public class XmlFlowModelBuilder implements FlowModelBuilder { return state; } + private void mergeFlows() { + if (flowModel.getParent() != null) { + List parents = Arrays.asList(StringUtils.trimArrayElements(flowModel.getParent().split(","))); + for (Iterator it = parents.iterator(); it.hasNext();) { + String parentFlowId = (String) it.next(); + if (StringUtils.hasText(parentFlowId)) { + try { + flowModel.merge(modelLocator.getFlowModel(parentFlowId)); + } catch (NoSuchFlowModelException e) { + throw new FlowModelBuilderException("Unable to find flow '" + parentFlowId + + "' to inherit from", e); + } + } + } + } + } + + private 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("#")) { + throw new FlowModelBuilderException("Invalid parent syntax '" + parent + + "', should take form 'flowId#stateId'"); + } + flowId = parent.substring(0, parent.indexOf("#")).trim(); + stateId = parent.substring(parent.indexOf("#") + 1).trim(); + 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 String toString() { return new ToStringCreator(this).append("resource", resource).toString(); } diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/model/registry/DefaultFlowModelHolderTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/model/registry/DefaultFlowModelHolderTests.java index fe79b230..d3c87055 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/engine/model/registry/DefaultFlowModelHolderTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/model/registry/DefaultFlowModelHolderTests.java @@ -61,7 +61,7 @@ public class DefaultFlowModelHolderTests extends TestCase { return null; } - public boolean hasFlowModelChanged() { + public boolean hasFlowModelResourceChanged() { return false; }