viewRendering listener callbacks

flow model registry polishing
This commit is contained in:
Keith Donald
2008-04-11 18:55:48 +00:00
parent f235bb2011
commit e7a0e22bb5
20 changed files with 178 additions and 167 deletions

View File

@@ -162,8 +162,8 @@ class FlowRegistryFactoryBean implements FactoryBean, InitializingBean {
}
private FlowModelHolder createFlowModelHolder(FlowDefinitionResource resource) {
FlowModelHolder modelHolder = new DefaultFlowModelHolder(createFlowModelBuilder(resource), resource.getId());
flowModelRegistry.registerFlowModel(modelHolder);
FlowModelHolder modelHolder = new DefaultFlowModelHolder(createFlowModelBuilder(resource));
flowModelRegistry.registerFlowModel(resource.getId(), modelHolder);
return modelHolder;
}

View File

@@ -23,7 +23,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
import org.springframework.webflow.definition.FlowDefinition;
import org.springframework.webflow.engine.model.registry.FlowModelConstructionException;
/**
* A generic registry implementation for housing one or more flow definitions.
@@ -54,11 +53,8 @@ public class FlowDefinitionRegistryImpl implements FlowDefinitionRegistry {
public FlowDefinition getFlowDefinition(String id) throws NoSuchFlowDefinitionException,
FlowDefinitionConstructionException {
try {
if (id == null) {
throw new IllegalArgumentException("The id of the flow to lookup is required");
}
if (logger.isDebugEnabled()) {
logger.debug("Getting flow definition with id '" + id + "'");
logger.debug("Getting FlowDefinition with id '" + id + "'");
}
return getFlowDefinitionHolder(id).getFlowDefinition();
} catch (NoSuchFlowDefinitionException e) {
@@ -67,8 +63,6 @@ public class FlowDefinitionRegistryImpl implements FlowDefinitionRegistry {
return parent.getFlowDefinition(id);
}
throw e;
} catch (FlowModelConstructionException e) {
throw new FlowDefinitionConstructionException(e.getMessage(), e);
}
}

View File

@@ -83,6 +83,7 @@ import org.springframework.webflow.engine.model.SubflowStateModel;
import org.springframework.webflow.engine.model.TransitionModel;
import org.springframework.webflow.engine.model.VarModel;
import org.springframework.webflow.engine.model.ViewStateModel;
import org.springframework.webflow.engine.model.builder.FlowModelBuilderException;
import org.springframework.webflow.engine.model.registry.FlowModelHolder;
import org.springframework.webflow.engine.support.ActionExecutingViewFactory;
import org.springframework.webflow.engine.support.BeanFactoryVariableValueFactory;
@@ -122,7 +123,11 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder {
* @throws FlowBuilderException an exception occurred building the flow
*/
protected void doInit() throws FlowBuilderException {
flowModel = flowModelHolder.getFlowModel();
try {
flowModel = flowModelHolder.getFlowModel();
} catch (FlowModelBuilderException e) {
throw new FlowBuilderException("Unable to get the model for this flow", e);
}
if ("true".equals(flowModel.getAbstract())) {
throw new FlowBuilderException("Abstract flow models cannot be instantiated.");
}

View File

@@ -103,7 +103,7 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
document = documentLoader.loadDocument(resource);
lastModifiedTimestamp = resource.getFile().lastModified();
} catch (IOException e) {
throw new FlowModelBuilderException("Could not access the XML flow definition resource at " + resource, e);
throw new FlowModelBuilderException("Could not access the XML flow definition at " + resource, e);
} catch (ParserConfigurationException e) {
throw new FlowModelBuilderException("Could not configure the parser to parse the XML flow definition at "
+ resource, e);

View File

@@ -16,6 +16,8 @@
package org.springframework.webflow.engine.model.registry;
import org.springframework.core.io.Resource;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
import org.springframework.webflow.engine.model.FlowModel;
import org.springframework.webflow.engine.model.builder.FlowModelBuilder;
import org.springframework.webflow.engine.model.builder.FlowModelBuilderException;
@@ -40,11 +42,6 @@ public class DefaultFlowModelHolder implements FlowModelHolder {
*/
private FlowModel flowModel;
/**
* The flow mode identifier
*/
private String flowModelId;
/**
* The flow model builder.
*/
@@ -54,18 +51,13 @@ public class DefaultFlowModelHolder implements FlowModelHolder {
* Creates a new refreshable flow model holder that uses the configured assembler (GOF director) to drive flow
* assembly, on initial use and on any resource change or refresh.
* @param flowModelBuilder the flow model builder to use
* @param flowModelId the identifier of the flow model
*/
public DefaultFlowModelHolder(FlowModelBuilder flowModelBuilder, String flowModelId) {
public DefaultFlowModelHolder(FlowModelBuilder flowModelBuilder) {
Assert.notNull(flowModelBuilder, "The flow model builder is required");
this.flowModelBuilder = flowModelBuilder;
this.flowModelId = flowModelId;
}
public String getFlowModelId() {
return flowModelId;
}
public synchronized FlowModel getFlowModel() throws FlowModelConstructionException {
public synchronized FlowModel getFlowModel() {
if (flowModel == null) {
assembleFlowModel();
} else {
@@ -84,26 +76,23 @@ public class DefaultFlowModelHolder implements FlowModelHolder {
return flowModelBuilder.hasFlowModelChanged();
}
public synchronized void refresh() throws FlowModelConstructionException {
public synchronized void refresh() {
assembleFlowModel();
}
// internal helpers
private void assembleFlowModel() throws FlowModelConstructionException {
private void assembleFlowModel() throws FlowModelBuilderException {
try {
flowModelBuilder.init();
flowModelBuilder.build();
flowModel = flowModelBuilder.getFlowModel();
} catch (FlowModelBuilderException e) {
throw new FlowModelConstructionException(flowModelId, e);
} finally {
flowModelBuilder.dispose();
}
}
public String toString() {
return "'" + getFlowModelId() + "'";
return new ToStringCreator(this).append("flowModelBuilder", flowModelBuilder).toString();
}
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright 2004-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.webflow.engine.model.registry;
import org.springframework.webflow.core.FlowException;
/**
* Thrown when a flow model was found during a lookup operation but could not be constructed.
*
* @author Keith Donald
* @author Erwin Vervaet
* @author Scott Andrews
*/
public class FlowModelConstructionException extends FlowException {
/**
* The id of the flow that could not be constructed.
*/
private String flowModelId;
/**
* Creates an exception indicating a flow model could not be constructed.
* @param flowModelId the flow model identifier
* @param cause the underlying cause of the exception
*/
public FlowModelConstructionException(String flowModelId, Throwable cause) {
super("An exception occurred constructing the flow '" + flowModelId + "'", cause);
this.flowModelId = flowModelId;
}
/**
* Returns the id of the flow model that could not be constructed.
* @return the flow id
*/
public String getFlowModelId() {
return flowModelId;
}
}

View File

@@ -17,12 +17,13 @@ package org.springframework.webflow.engine.model.registry;
import org.springframework.core.io.Resource;
import org.springframework.webflow.engine.model.FlowModel;
import org.springframework.webflow.engine.model.builder.FlowModelBuilderException;
/**
* A holder holding a reference to a Flow model. Provides a layer of indirection, enabling things like "hot-reloadable"
* flow models.
*
* @see FlowModelRegistry#registerFlowModel(FlowModelHolder)
* @see FlowModelRegistry#registerFlowModel(String, FlowModelHolder)
*
* @author Keith Donald
* @author Scott Andrews
@@ -30,18 +31,10 @@ import org.springframework.webflow.engine.model.FlowModel;
public interface FlowModelHolder {
/**
* Returns the <code>id</code> of the flow model held by this holder. This is a <i>lightweight</i> method callers
* may call to obtain the id of the flow without triggering full flow definition assembly (which may be an expensive
* operation).
* Returns the flow model held by this holder. Calling this method the first time may trigger flow model assembly.
* @throws FlowModelBuilderException if an exception occurred building the flow model
*/
public String getFlowModelId();
/**
* Returns the flow model held by this holder. Calling this method the first time may trigger flow assembly (which
* may be expensive).
* @throws FlowModelConstructionException if there is a problem constructing the target flow model
*/
public FlowModel getFlowModel() throws FlowModelConstructionException;
public FlowModel getFlowModel() throws FlowModelBuilderException;
/**
* Has the underlying flow model changed since it was last accessed via a call to {@link #getFlowModel()}.
@@ -59,8 +52,8 @@ public interface FlowModelHolder {
/**
* Refresh the flow model held by this holder. Calling this method typically triggers flow re-assembly, which may
* include a refresh from an externalized resource such as a file.
* @throws FlowModelConstructionException if there is a problem constructing the target flow model
* @throws FlowModelBuilderException if an exception occurred building the flow model
*/
public void refresh() throws FlowModelConstructionException;
public void refresh() throws FlowModelBuilderException;
}

View File

@@ -32,7 +32,6 @@ public interface FlowModelLocator {
* @param id the flow model identifier
* @return the flow mode
* @throws NoSuchFlowModelException when the flow model with the specified id does not exist
* @throws FlowModelConstructionException if there is a problem constructing the identified flow model
*/
public FlowModel getFlowModel(String id) throws NoSuchFlowModelException, FlowModelConstructionException;
public FlowModel getFlowModel(String id) throws NoSuchFlowModelException;
}

View File

@@ -38,8 +38,9 @@ public interface FlowModelRegistry extends FlowModelLocator {
* Register a flow model in this registry. Registers a "holder", not the Flow model itself. This allows the actual
* Flow model to be loaded lazily only when needed, and also rebuilt at runtime when its underlying resource changes
* without re-deploy.
* @param id the id to register the flow model under
* @param modelHolder a holder holding the flow model to register
*/
public void registerFlowModel(FlowModelHolder modelHolder);
public void registerFlowModel(String id, FlowModelHolder modelHolder);
}

View File

@@ -50,13 +50,10 @@ public class FlowModelRegistryImpl implements FlowModelRegistry {
// implementing FlowModelLocator
public FlowModel getFlowModel(String id) throws NoSuchFlowModelException, FlowModelConstructionException {
public FlowModel getFlowModel(String id) throws NoSuchFlowModelException {
try {
if (id == null) {
throw new IllegalArgumentException("The id of the flow to lookup is required");
}
if (logger.isDebugEnabled()) {
logger.debug("Getting flow model with id '" + id + "'");
logger.debug("Getting FlowModel with id '" + id + "'");
}
return getFlowModelHolder(id).getFlowModel();
@@ -75,12 +72,12 @@ public class FlowModelRegistryImpl implements FlowModelRegistry {
this.parent = parent;
}
public void registerFlowModel(FlowModelHolder modelHolder) {
public void registerFlowModel(String id, FlowModelHolder modelHolder) {
Assert.notNull(modelHolder, "The holder of the flow model to register is required");
if (logger.isDebugEnabled()) {
logger.debug("Registering flow model " + modelHolder);
}
flowModels.put(modelHolder.getFlowModelId(), modelHolder);
flowModels.put(id, modelHolder);
}
// internal helpers

View File

@@ -113,6 +113,22 @@ public interface FlowExecutionListener {
*/
public void stateEntering(RequestContext context, StateDefinition state) throws EnterStateVetoException;
/**
* Called when a view is about to render in a view-state, before any render actions are executed.
* @param context the current request context
* @param view the view that is about to render
* @param viewState the current view state
*/
public void viewRendering(RequestContext context, View view, StateDefinition viewState);
/**
* Called after a view has completed rendering.
* @param context the current request context
* @param view the view that rendered
* @param viewState the current view state
*/
public void viewRendered(RequestContext context, View view, StateDefinition viewState);
/**
* Called when a state transitions, after the transition occurred.
* @param context the source of the event

View File

@@ -55,6 +55,12 @@ public abstract class FlowExecutionListenerAdapter implements FlowExecutionListe
public void stateEntering(RequestContext context, StateDefinition state) throws EnterStateVetoException {
}
public void viewRendered(RequestContext context, View view, StateDefinition viewState) {
}
public void viewRendering(RequestContext context, View view, StateDefinition viewState) {
}
public void stateEntered(RequestContext context, StateDefinition previousState, StateDefinition newState) {
}

View File

@@ -79,8 +79,8 @@ public abstract class AbstractXmlFlowExecutionTests extends AbstractExternalized
protected final FlowBuilder createFlowBuilder(FlowDefinitionResource resource) {
registerDependentFlowModels();
FlowModelBuilder modelBuilder = new XmlFlowModelBuilder(resource.getPath(), flowModelRegistry);
FlowModelHolder modelHolder = new DefaultFlowModelHolder(modelBuilder, resource.getId());
flowModelRegistry.registerFlowModel(modelHolder);
FlowModelHolder modelHolder = new DefaultFlowModelHolder(modelBuilder);
flowModelRegistry.registerFlowModel(resource.getId(), modelHolder);
return new FlowModelFlowBuilder(modelHolder) {
protected void registerFlowBeans(ConfigurableBeanFactory flowBeanFactory) {
registerMockFlowBeans(flowBeanFactory);
@@ -116,7 +116,7 @@ public abstract class AbstractXmlFlowExecutionTests extends AbstractExternalized
for (int i = 0; i < modelResources.length; i++) {
FlowDefinitionResource modelResource = modelResources[i];
FlowModelBuilder modelBuilder = new XmlFlowModelBuilder(modelResource.getPath(), flowModelRegistry);
flowModelRegistry.registerFlowModel(new DefaultFlowModelHolder(modelBuilder, modelResource.getId()));
flowModelRegistry.registerFlowModel(modelResource.getId(), new DefaultFlowModelHolder(modelBuilder));
}
}
}

View File

@@ -53,7 +53,7 @@ public class FlowRegistryBeanDefinitionParserTests extends TestCase {
try {
registry.getFlowDefinition("bogus");
} catch (FlowDefinitionConstructionException e) {
e.printStackTrace();
}
}

View File

@@ -29,7 +29,6 @@ import org.springframework.webflow.engine.model.ViewStateModel;
import org.springframework.webflow.engine.model.builder.xml.XmlFlowModelBuilder;
import org.springframework.webflow.engine.model.builder.xml.XmlFlowModelBuilderTests;
import org.springframework.webflow.engine.model.registry.DefaultFlowModelHolder;
import org.springframework.webflow.engine.model.registry.FlowModelConstructionException;
import org.springframework.webflow.engine.model.registry.FlowModelHolder;
import org.springframework.webflow.engine.model.registry.FlowModelRegistryImpl;
import org.springframework.webflow.engine.support.ActionExecutingViewFactory;
@@ -346,7 +345,7 @@ public class FlowModelFlowBuilderTests extends TestCase {
private Flow getFlow(ClassPathResource resource) {
FlowModelHolder holder = new DefaultFlowModelHolder(new XmlFlowModelBuilder(resource,
new FlowModelRegistryImpl()), "flow");
new FlowModelRegistryImpl()));
FlowModelFlowBuilder builder = new FlowModelFlowBuilder(holder);
FlowAssembler assembler = new FlowAssembler(builder, new MockFlowBuilderContext("flow"));
return assembler.assembleFlow();
@@ -360,7 +359,7 @@ public class FlowModelFlowBuilderTests extends TestCase {
this.model = model;
}
public FlowModel getFlowModel() throws FlowModelConstructionException {
public FlowModel getFlowModel() {
return model;
}
@@ -376,7 +375,7 @@ public class FlowModelFlowBuilderTests extends TestCase {
return false;
}
public void refresh() throws FlowModelConstructionException {
public void refresh() {
}
}

View File

@@ -4,6 +4,12 @@ import junit.framework.TestCase;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.validation.BindingResult;
import org.springframework.webflow.definition.StateDefinition;
import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.engine.builder.FlowAssembler;
import org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder;
import org.springframework.webflow.engine.impl.FlowExecutionImplFactory;
import org.springframework.webflow.engine.model.AbstractStateModel;
import org.springframework.webflow.engine.model.AttributeModel;
import org.springframework.webflow.engine.model.FlowModel;
@@ -12,10 +18,17 @@ import org.springframework.webflow.engine.model.TransitionModel;
import org.springframework.webflow.engine.model.VarModel;
import org.springframework.webflow.engine.model.ViewStateModel;
import org.springframework.webflow.engine.model.builder.FlowModelBuilder;
import org.springframework.webflow.engine.model.builder.FlowModelBuilderException;
import org.springframework.webflow.engine.model.registry.DefaultFlowModelHolder;
import org.springframework.webflow.engine.model.registry.FlowModelConstructionException;
import org.springframework.webflow.engine.model.registry.FlowModelRegistry;
import org.springframework.webflow.engine.model.registry.FlowModelRegistryImpl;
import org.springframework.webflow.execution.FlowExecution;
import org.springframework.webflow.execution.FlowExecutionListenerAdapter;
import org.springframework.webflow.execution.RequestContext;
import org.springframework.webflow.execution.View;
import org.springframework.webflow.execution.factory.StaticFlowExecutionListenerLoader;
import org.springframework.webflow.test.MockExternalContext;
import org.springframework.webflow.test.MockFlowBuilderContext;
public class XmlFlowModelBuilderTests extends TestCase {
@@ -148,10 +161,10 @@ public class XmlFlowModelBuilderTests extends TestCase {
public void testMerge() {
ClassPathResource resourceChild = new ClassPathResource("flow-inheritance-child.xml", getClass());
ClassPathResource resourceParent = new ClassPathResource("flow-inheritance-parent.xml", getClass());
registry
.registerFlowModel(new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry), "child"));
registry.registerFlowModel(new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceParent, registry),
"parent"));
registry.registerFlowModel("child",
new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry)));
registry.registerFlowModel("parent", new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceParent,
registry)));
FlowModel flow = registry.getFlowModel("child");
assertEquals(1, flow.getGlobalTransitions().size());
assertEquals(2, flow.getStates().size());
@@ -161,14 +174,14 @@ public class XmlFlowModelBuilderTests extends TestCase {
public void testMergeParentNotFound() {
ClassPathResource resourceChild = new ClassPathResource("flow-inheritance-child.xml", getClass());
ClassPathResource resourceParent = new ClassPathResource("flow-inheritance-parent.xml", getClass());
registry
.registerFlowModel(new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry), "child"));
registry.registerFlowModel(new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceParent, registry),
"parent-id-not-matching"));
registry.registerFlowModel("child",
new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry)));
registry.registerFlowModel("parent-id-not-matching", new DefaultFlowModelHolder(new XmlFlowModelBuilder(
resourceParent, registry)));
try {
registry.getFlowModel("child");
fail("A FlowModelConstructionException was expected");
} catch (FlowModelConstructionException e) {
fail("A FlowModelBuilderException was expected");
} catch (FlowModelBuilderException e) {
// we want this
}
}
@@ -185,10 +198,10 @@ public class XmlFlowModelBuilderTests extends TestCase {
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"));
registry.registerFlowModel("child",
new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry)));
registry.registerFlowModel("parent", new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceParent,
registry)));
FlowModel flow = registry.getFlowModel("child");
assertEquals(1, flow.getStates().size());
assertEquals("otherview", ((ViewStateModel) flow.getStates().get(0)).getView());
@@ -198,14 +211,14 @@ public class XmlFlowModelBuilderTests extends TestCase {
ClassPathResource resourceChild = new ClassPathResource("flow-inheritance-state-invalid-parent-syntax.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"));
registry.registerFlowModel("child",
new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry)));
registry.registerFlowModel("parent", new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceParent,
registry)));
try {
registry.getFlowModel("child");
fail("A FlowModelConstructionException was expected");
} catch (FlowModelConstructionException e) {
} catch (FlowModelBuilderException e) {
// we want this
}
}
@@ -213,14 +226,14 @@ public class XmlFlowModelBuilderTests extends TestCase {
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"));
registry.registerFlowModel("child",
new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry)));
registry.registerFlowModel("parent-id-not-matching", new DefaultFlowModelHolder(new XmlFlowModelBuilder(
resourceParent, registry)));
try {
registry.getFlowModel("child");
fail("A FlowModelConstructionException was expected");
} catch (FlowModelConstructionException e) {
fail("A FlowModelBuilderException was expected");
} catch (FlowModelBuilderException e) {
// we want this
}
}
@@ -228,14 +241,14 @@ public class XmlFlowModelBuilderTests extends TestCase {
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"));
registry.registerFlowModel("child",
new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry)));
registry.registerFlowModel("parent", new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceParent,
registry)));
try {
registry.getFlowModel("child");
fail("A FlowModelConstructionException was expected");
} catch (FlowModelConstructionException e) {
fail("A FlowModelBuilderException was expected");
} catch (FlowModelBuilderException e) {
// we want this
}
}
@@ -243,16 +256,37 @@ public class XmlFlowModelBuilderTests extends TestCase {
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"));
registry.registerFlowModel("child",
new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry)));
registry.registerFlowModel("parent", new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceParent,
registry)));
try {
registry.getFlowModel("child");
fail("A FlowModelConstructionException was expected");
} catch (FlowModelConstructionException e) {
fail("A FlowModelBuilderException was expected");
} catch (FlowModelBuilderException e) {
// we want this
}
}
public void testFormActionValidatorMethod() {
ClassPathResource resource = new ClassPathResource("flow-formaction-validatormethod.xml", getClass());
XmlFlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
DefaultFlowModelHolder holder = new DefaultFlowModelHolder(builder);
FlowModelFlowBuilder flowBuilder = new FlowModelFlowBuilder(holder);
FlowAssembler assembler = new FlowAssembler(flowBuilder, new MockFlowBuilderContext("flow"));
Flow flow = assembler.assembleFlow();
FlowExecutionImplFactory factory = new FlowExecutionImplFactory();
factory.setExecutionListenerLoader(new StaticFlowExecutionListenerLoader(new FlowExecutionListenerAdapter() {
public void viewRendering(RequestContext context, View view, StateDefinition viewState) {
BindingResult result = (BindingResult) context.getFlashScope().get(
"org.springframework.validation.BindingResult.formBean");
assertEquals(1, result.getErrorCount());
}
}));
FlowExecution execution = factory.createFlowExecution(flow);
execution.start(null, new MockExternalContext());
MockExternalContext context = new MockExternalContext();
context.setEventId("submit");
execution.resume(context);
}
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="formAction" class="org.springframework.webflow.action.FormAction">
<property name="formObjectName" value="formBean"/>
<property name="validator">
<bean class="org.springframework.webflow.action.FormActionTests$TestBeanValidator"/>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,22 @@
<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">
<var name="formBean" class="org.springframework.webflow.action.FormActionTests$TestBean"/>
<view-state id="view">
<on-entry>
<evaluate expression="formAction.setupForm"/>
</on-entry>
<transition on="submit" to="finish">
<evaluate expression="formAction.bindAndValidate">
<attribute name="validatorMethod" value="validateTestBean"/>
</evaluate>
</transition>
</view-state>
<view-state id="finish"/>
<bean-import resource="flow-formaction-validatormethod-beans.xml"/>
</flow>

View File

@@ -17,7 +17,7 @@ public class DefaultFlowModelHolderTests extends TestCase {
protected void setUp() {
builder = new SimpleFlowBuilder();
holder = new DefaultFlowModelHolder(builder, "flowId");
holder = new DefaultFlowModelHolder(builder);
}
public void testGetFlowDefinition() {

View File

@@ -28,20 +28,20 @@ public class FlowModelRegistryImplTests extends TestCase {
}
public void testRegisterFlow() {
registry.registerFlowModel(new StaticFlowModelHolder(fooFlow, "foo"));
registry.registerFlowModel("foo", new StaticFlowModelHolder(fooFlow));
assertEquals(fooFlow, registry.getFlowModel("foo"));
}
public void testRegisterFlowSameIds() {
registry.registerFlowModel(new StaticFlowModelHolder(fooFlow, "foo"));
registry.registerFlowModel("foo", new StaticFlowModelHolder(fooFlow));
FlowModel newFlow = new FlowModel();
registry.registerFlowModel(new StaticFlowModelHolder(newFlow, "foo"));
registry.registerFlowModel("foo", new StaticFlowModelHolder(newFlow));
assertSame(newFlow, registry.getFlowModel("foo"));
}
public void testRegisterMultipleFlows() {
registry.registerFlowModel(new StaticFlowModelHolder(fooFlow, "foo"));
registry.registerFlowModel(new StaticFlowModelHolder(barFlow, "bar"));
registry.registerFlowModel("foo", new StaticFlowModelHolder(fooFlow));
registry.registerFlowModel("bar", new StaticFlowModelHolder(barFlow));
assertEquals(fooFlow, registry.getFlowModel("foo"));
assertEquals(barFlow, registry.getFlowModel("bar"));
}
@@ -51,7 +51,7 @@ public class FlowModelRegistryImplTests extends TestCase {
FlowModelRegistryImpl child = new FlowModelRegistryImpl();
child.setParent(registry);
FlowModel fooFlow = new FlowModel();
child.registerFlowModel(new StaticFlowModelHolder(fooFlow, "foo"));
child.registerFlowModel("foo", new StaticFlowModelHolder(fooFlow));
assertSame(fooFlow, child.getFlowModel("foo"));
assertEquals(barFlow, child.getFlowModel("bar"));
}
@@ -59,21 +59,15 @@ public class FlowModelRegistryImplTests extends TestCase {
private static class StaticFlowModelHolder implements FlowModelHolder {
private FlowModel model;
private String id;
public StaticFlowModelHolder(FlowModel model, String id) {
public StaticFlowModelHolder(FlowModel model) {
this.model = model;
this.id = id;
}
public FlowModel getFlowModel() throws FlowModelConstructionException {
public FlowModel getFlowModel() {
return model;
}
public String getFlowModelId() {
return id;
}
public Resource getFlowModelResource() {
return null;
}
@@ -82,7 +76,7 @@ public class FlowModelRegistryImplTests extends TestCase {
return false;
}
public void refresh() throws FlowModelConstructionException {
public void refresh() {
}
}