package org.springframework.webflow.engine.model.builder.xml;
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.action.FormAction;
import org.springframework.webflow.action.FormActionTests.TestBeanValidator;
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.FlowModel;
import org.springframework.webflow.engine.model.SecuredModel;
import org.springframework.webflow.engine.model.TransitionModel;
import org.springframework.webflow.engine.model.ViewStateModel;
import org.springframework.webflow.engine.model.builder.DefaultFlowModelHolder;
import org.springframework.webflow.engine.model.builder.FlowModelBuilder;
import org.springframework.webflow.engine.model.builder.FlowModelBuilderException;
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 {
private FlowModelRegistry registry;
protected void setUp() {
StaticListableBeanFactory beanFactory = new StaticListableBeanFactory();
beanFactory.addBean("bean", new Object());
registry = new FlowModelRegistryImpl();
}
public void testBuildFlowWithEndState() {
ClassPathResource resource = new ClassPathResource("flow-endstate.xml", getClass());
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
builder.init();
builder.build();
FlowModel flow = builder.getFlowModel();
assertNull(flow.getStartStateId());
assertEquals("end", flow.getStates().get(0).getId());
}
public void testBuildFlowWithDefaultStartState() {
ClassPathResource resource = new ClassPathResource("flow-startstate-default.xml", getClass());
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
builder.init();
builder.build();
FlowModel flow = builder.getFlowModel();
assertNull(flow.getStartStateId());
assertEquals("end", flow.getStates().get(0).getId());
}
public void testBuildFlowWithStartStateAttribute() {
ClassPathResource resource = new ClassPathResource("flow-startstate-attribute.xml", getClass());
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
builder.init();
builder.build();
FlowModel flow = builder.getFlowModel();
assertEquals("end", flow.getStartStateId());
}
public void testCustomFlowAttribute() {
ClassPathResource resource = new ClassPathResource("flow-custom-attribute.xml", getClass());
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
builder.init();
builder.build();
FlowModel flow = builder.getFlowModel();
assertEquals("bar", flow.getAttributes().get(0).getValue());
assertEquals("number", flow.getAttributes().get(1).getName());
}
public void testPersistenceContextFlow() {
ClassPathResource resource = new ClassPathResource("flow-persistencecontext.xml", getClass());
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
builder.init();
builder.build();
FlowModel flow = builder.getFlowModel();
assertNotNull(flow.getPersistenceContext());
}
public void testFlowSecured() {
ClassPathResource resource = new ClassPathResource("flow-secured.xml", getClass());
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
builder.init();
builder.build();
FlowModel flow = builder.getFlowModel();
SecuredModel secured = flow.getSecured();
assertNotNull(secured);
assertEquals("ROLE_USER", secured.getAttributes());
}
public void testFlowSecuredState() {
ClassPathResource resource = new ClassPathResource("flow-secured-state.xml", getClass());
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
builder.init();
builder.build();
FlowModel flow = builder.getFlowModel();
SecuredModel secured = flow.getStates().get(0).getSecured();
assertNotNull(secured);
assertEquals("ROLE_USER", secured.getAttributes());
}
public void testFlowSecuredTransition() {
ClassPathResource resource = new ClassPathResource("flow-secured-transition.xml", getClass());
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
builder.init();
builder.build();
FlowModel flow = builder.getFlowModel();
SecuredModel secured = flow.getGlobalTransitions().get(0).getSecured();
assertNotNull(secured);
assertEquals("ROLE_USER", secured.getAttributes());
}
public void testFlowVariable() {
ClassPathResource resource = new ClassPathResource("flow-var.xml", getClass());
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
builder.init();
builder.build();
FlowModel flow = builder.getFlowModel();
assertEquals("flow-foo", flow.getVars().get(0).getName());
assertEquals("conversation-foo", flow.getVars().get(1).getName());
}
public void testViewStateVariable() {
ClassPathResource resource = new ClassPathResource("flow-viewstate-var.xml", getClass());
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
builder.init();
builder.build();
FlowModel flow = builder.getFlowModel();
assertEquals("foo", ((ViewStateModel) flow.getStates().get(0)).getVars().get(0).getName());
}
public void testViewStateModelBinding() {
ClassPathResource resource = new ClassPathResource("flow-viewstate-model-binding.xml", getClass());
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
builder.init();
builder.build();
FlowModel flow = builder.getFlowModel();
ViewStateModel model = (ViewStateModel) flow.getStates().get(0);
assertEquals("formObject", model.getModel());
assertEquals("foo,bar", model.getValidationHints());
assertEquals("objectProperty", model.getBinder().getBindings().get(0).getProperty());
assertEquals("customConverter", model.getBinder().getBindings().get(0).getConverter());
}
public void testViewStateRedirect() {
ClassPathResource resource = new ClassPathResource("flow-viewstate-redirect.xml", getClass());
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
builder.init();
builder.build();
FlowModel flow = builder.getFlowModel();
assertEquals("true", ((ViewStateModel) flow.getStates().get(0)).getRedirect());
}
public void testViewStatePopup() {
ClassPathResource resource = new ClassPathResource("flow-viewstate-popup.xml", getClass());
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
builder.init();
builder.build();
FlowModel flow = builder.getFlowModel();
assertEquals("true", ((ViewStateModel) flow.getStates().get(0)).getPopup());
}
public void testMerge() {
ClassPathResource resourceChild = new ClassPathResource("flow-inheritance-child.xml", getClass());
ClassPathResource resourceParent = new ClassPathResource("flow-inheritance-parent.xml", getClass());
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());
assertEquals("view", flow.getStates().get(0).getId());
}
public void testMergeParentNotFound() {
ClassPathResource resourceChild = new ClassPathResource("flow-inheritance-child.xml", getClass());
ClassPathResource resourceParent = new ClassPathResource("flow-inheritance-parent.xml", getClass());
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 FlowModelBuilderException was expected");
} catch (FlowModelBuilderException e) {
// we want this
}
}
public void testEvaluateAction() {
ClassPathResource resource = new ClassPathResource("flow-action-evaluate-action.xml", getClass());
FlowModelBuilder builder = new XmlFlowModelBuilder(resource, registry);
builder.init();
builder.build();
FlowModel flow = builder.getFlowModel();
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("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());
}
public void testStateMergeInvalidParentSyntax() {
ClassPathResource resourceChild = new ClassPathResource("flow-inheritance-state-invalid-parent-syntax.xml",
getClass());
ClassPathResource resourceParent = new ClassPathResource("flow-inheritance-state-parent.xml", getClass());
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 (FlowModelBuilderException e) {
// we want this
}
}
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("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 FlowModelBuilderException was expected");
} catch (FlowModelBuilderException 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("child",
new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry)));
registry.registerFlowModel("parent", new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceParent,
registry)));
try {
registry.getFlowModel("child");
fail("A FlowModelBuilderException was expected");
} catch (FlowModelBuilderException 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("child",
new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceChild, registry)));
registry.registerFlowModel("parent", new DefaultFlowModelHolder(new XmlFlowModelBuilder(resourceParent,
registry)));
try {
registry.getFlowModel("child");
fail("A FlowModelBuilderException was expected");
} catch (FlowModelBuilderException e) {
// we want this
}
}
public void testParseFlowExceptionHandler() {
ClassPathResource res = new ClassPathResource("flow-exception-handler.xml", getClass());
XmlFlowModelBuilder builder = new XmlFlowModelBuilder(res);
DefaultFlowModelHolder holder = new DefaultFlowModelHolder(builder);
FlowModel model = holder.getFlowModel();
assertEquals("foo1", model.getExceptionHandlers().get(0).getBean());
assertEquals("foo2", model.getStateById("state1").getExceptionHandlers().get(0).getBean());
assertEquals("foo3", model.getStateById("state2").getExceptionHandlers().get(0).getBean());
assertEquals("foo4", model.getStateById("state3").getExceptionHandlers().get(0).getBean());
assertEquals("foo5", model.getStateById("state4").getExceptionHandlers().get(0).getBean());
assertEquals("foo6", model.getStateById("state5").getExceptionHandlers().get(0).getBean());
}
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) {
if (context.getCurrentEvent() != null && context.getCurrentEvent().getId().equals("submit")) {
BindingResult result = (BindingResult) context.getFlashScope().get(
"org.springframework.validation.BindingResult.formBean");
assertEquals(1, result.getErrorCount());
}
}
public void viewRendered(RequestContext context, View view, StateDefinition viewState) {
if (context.getCurrentEvent() != null && context.getCurrentEvent().getId().equals("submit")) {
BindingResult result = (BindingResult) context.getFlashScope().get(
"org.springframework.validation.BindingResult.formBean");
assertNull(result);
}
}
}));
FlowExecution execution = factory.createFlowExecution(flow);
FormAction action = (FormAction) flow.getApplicationContext().getBean("formAction");
assertFalse(((TestBeanValidator) action.getValidator()).getInvoked());
execution.start(null, new MockExternalContext());
MockExternalContext context = new MockExternalContext();
context.setEventId("submit");
execution.resume(context);
assertTrue(((TestBeanValidator) action.getValidator()).getInvoked());
}
public void testParsedFlowValidationHints() {
ClassPathResource res = new ClassPathResource("flow-validation-hints.xml", getClass());
XmlFlowModelBuilder builder = new XmlFlowModelBuilder(res);
DefaultFlowModelHolder holder = new DefaultFlowModelHolder(builder);
FlowModel model = holder.getFlowModel();
ViewStateModel state = (ViewStateModel) model.getStateById("state1");
assertEquals("foo,bar", state.getValidationHints());
TransitionModel transition = state.getTransitions().get(0);
assertEquals("baz", transition.getValidationHints());
state = (ViewStateModel) model.getStateById("state2");
assertNull(state.getValidationHints());
}
}