exception handler fix and tests

This commit is contained in:
Keith Donald
2008-04-18 14:48:53 +00:00
parent ed4a72a4f9
commit a0c26d52d3
7 changed files with 105 additions and 36 deletions

View File

@@ -745,7 +745,7 @@ public class FlowModelFlowBuilder extends AbstractFlowBuilder {
private FlowExecutionExceptionHandler parseCustomExceptionHandler(ExceptionHandlerModel exceptionHandler) {
return (FlowExecutionExceptionHandler) getLocalContext().getApplicationContext().getBean(
exceptionHandler.getBeanName(), FlowExecutionExceptionHandler.class);
exceptionHandler.getBean(), FlowExecutionExceptionHandler.class);
}
private Transition[] parseTransitions(List transitionModels) {

View File

@@ -25,14 +25,15 @@ import org.springframework.util.StringUtils;
* @author Scott Andrews
*/
public class ExceptionHandlerModel extends AbstractModel {
private String beanName;
private String bean;
/**
* Create an exception handler model
* @param beanName the name of the bean to handle exceptions
* @param bean the name of the bean to handle exceptions
*/
public ExceptionHandlerModel(String beanName) {
setBeanName(beanName);
public ExceptionHandlerModel(String bean) {
setBean(bean);
}
public boolean isMergeableWith(Model model) {
@@ -42,21 +43,15 @@ public class ExceptionHandlerModel extends AbstractModel {
public void merge(Model model) {
}
/**
* @return the bean name
*/
public String getBeanName() {
return beanName;
public String getBean() {
return bean;
}
/**
* @param beanName the bean name to set
*/
public void setBeanName(String beanName) {
if (StringUtils.hasText(beanName)) {
this.beanName = beanName;
public void setBean(String bean) {
if (StringUtils.hasText(bean)) {
this.bean = bean;
} else {
this.beanName = null;
this.bean = null;
}
}
}

View File

@@ -80,12 +80,20 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
/**
* 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.
* @param resource the path to the XML flow definition (required)
*/
public XmlFlowModelBuilder(Resource resource) {
init(resource, null);
}
/**
* 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.
* @param resource the path to the XML flow definition (required)
* @param modelLocator a locator for parent flow models to support flow inheritance
*/
public XmlFlowModelBuilder(Resource resource, FlowModelLocator modelLocator) {
Assert.notNull(resource, "The location of the XML-based flow definition is required");
Assert.notNull(modelLocator, "The model locator for accessing other flow models for merging is required");
this.resource = resource;
this.modelLocator = modelLocator;
init(resource, modelLocator);
}
/**
@@ -214,6 +222,12 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
return document != null ? document.getDocumentElement() : null;
}
private void init(Resource resource, FlowModelLocator modelLocator) {
Assert.notNull(resource, "The location of the XML-based flow definition is required");
this.resource = resource;
this.modelLocator = modelLocator;
}
private FlowModel parseFlow(Element element) {
FlowModel flow = new FlowModel();
flow.setAbstract(element.getAttribute("abstract"));
@@ -462,7 +476,7 @@ public class XmlFlowModelBuilder implements FlowModelBuilder {
}
private ExceptionHandlerModel parseExceptionHandler(Element element) {
return new ExceptionHandlerModel(element.getAttribute("bean-name"));
return new ExceptionHandlerModel(element.getAttribute("bean"));
}
private BeanImportModel parseBeanImport(Element element) {

View File

@@ -202,7 +202,7 @@ Actions to execute when this state is entered.
<xsd:group ref="actionTypes" maxOccurs="unbounded" />
</xsd:complexType>
</xsd:element>
<xsd:group ref="actionTypes" maxOccurs="unbounded" />
<xsd:group ref="actionTypes" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="transition" type="transition" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>
@@ -1438,20 +1438,10 @@ The bean id of the custom exception handler.
<xsd:documentation>
<![CDATA[
Secures this flow definition element.
The user invoking this element must meet the required attributes otherwise access to the element will be denied.
The current user invoking this element must have the required security attributes otherwise access to the element will be denied.
<br>
WARNING: This element will only configure a security attribute in the definition. The flow execution must also be secured with a SecurityFlowExecutionListener.
<br>
For example:
<pre>
&lt;web:flow-executor id="flowExecutor" flow-registry="flowRegistry"&gt;
&lt;web:flow-execution-listeners&gt;
&lt;web:listener ref="securityFlowExecutionListener" /&gt;
&lt;/web:flow-execution-listeners&gt;
&lt;/web:flow-executor&gt;
&lt;bean id="securityFlowExecutionListener" class="org.springframework.webflow.security.SecurityFlowExecutionListener" /&gt;
</pre>
Note: This element configures a meta-attribute.
For the attribute to be enforced, the flow execution must be observed by a SecurityFlowExecutionListener.
]]>
</xsd:documentation>
</xsd:annotation>

View File

@@ -10,14 +10,17 @@ import org.springframework.webflow.action.FlowDefinitionRedirectAction;
import org.springframework.webflow.core.collection.LocalAttributeMap;
import org.springframework.webflow.core.collection.MutableAttributeMap;
import org.springframework.webflow.engine.Flow;
import org.springframework.webflow.engine.FlowExecutionExceptionHandler;
import org.springframework.webflow.engine.FlowInputMappingException;
import org.springframework.webflow.engine.FlowOutputMappingException;
import org.springframework.webflow.engine.RequestControlContext;
import org.springframework.webflow.engine.ViewState;
import org.springframework.webflow.engine.builder.FlowAssembler;
import org.springframework.webflow.engine.builder.FlowBuilderException;
import org.springframework.webflow.engine.impl.FlowExecutionImplFactory;
import org.springframework.webflow.engine.model.AttributeModel;
import org.springframework.webflow.engine.model.EndStateModel;
import org.springframework.webflow.engine.model.ExceptionHandlerModel;
import org.springframework.webflow.engine.model.FlowModel;
import org.springframework.webflow.engine.model.InputModel;
import org.springframework.webflow.engine.model.OutputModel;
@@ -34,6 +37,7 @@ import org.springframework.webflow.engine.model.registry.FlowModelRegistryImpl;
import org.springframework.webflow.engine.support.ActionExecutingViewFactory;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.FlowExecution;
import org.springframework.webflow.execution.FlowExecutionException;
import org.springframework.webflow.execution.ViewFactory;
import org.springframework.webflow.security.SecurityRule;
import org.springframework.webflow.test.MockExternalContext;
@@ -336,6 +340,26 @@ public class FlowModelFlowBuilderTests extends TestCase {
}
}
public void testExceptionHandlers() {
FlowModel model = new FlowModel();
model.addState(new EndStateModel("state"));
model.addExceptionHandler(new ExceptionHandlerModel("exceptionHandler"));
FlowExecutionExceptionHandler handler = new FlowExecutionExceptionHandler() {
public boolean canHandle(FlowExecutionException exception) {
return true;
}
public void handle(FlowExecutionException exception, RequestControlContext context) {
}
};
FlowModelFlowBuilder builder = new FlowModelFlowBuilder(new StaticFlowModelHolder(model));
MockFlowBuilderContext context = new MockFlowBuilderContext("foo");
context.registerBean("exceptionHandler", handler);
FlowAssembler assembler = new FlowAssembler(builder, context);
Flow flow = assembler.assembleFlow();
assertEquals(1, flow.getExceptionHandlerSet().size());
}
private Flow getFlow(FlowModel model) {
FlowModelHolder holder = new StaticFlowModelHolder(model);
FlowModelFlowBuilder builder = new FlowModelFlowBuilder(holder);

View File

@@ -12,6 +12,7 @@ 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.ExceptionHandlerModel;
import org.springframework.webflow.engine.model.FlowModel;
import org.springframework.webflow.engine.model.SecuredModel;
import org.springframework.webflow.engine.model.TransitionModel;
@@ -268,6 +269,24 @@ public class XmlFlowModelBuilderTests extends TestCase {
}
}
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", ((ExceptionHandlerModel) model.getExceptionHandlers().get(0)).getBean());
assertEquals("foo2", ((ExceptionHandlerModel) model.getStateById("state1").getExceptionHandlers().get(0))
.getBean());
assertEquals("foo3", ((ExceptionHandlerModel) model.getStateById("state2").getExceptionHandlers().get(0))
.getBean());
assertEquals("foo4", ((ExceptionHandlerModel) model.getStateById("state3").getExceptionHandlers().get(0))
.getBean());
assertEquals("foo5", ((ExceptionHandlerModel) model.getStateById("state4").getExceptionHandlers().get(0))
.getBean());
assertEquals("foo6", ((ExceptionHandlerModel) 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);

View File

@@ -0,0 +1,27 @@
<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="state1">
<exception-handler bean="foo2"/>
</view-state>
<action-state id="state2">
<exception-handler bean="foo3"/>
</action-state>
<subflow-state id="state3">
<exception-handler bean="foo4"/>
</subflow-state>
<decision-state id="state4">
<exception-handler bean="foo5"/>
</decision-state>
<end-state id="state5">
<exception-handler bean="foo6"/>
</end-state>
<exception-handler bean="foo1"/>
</flow>