Added setFlowAttributes method to XmlFlowRegistryFactoryBean to make it easier to configure externally defined flow definition attributes (SWF-200)
This commit is contained in:
@@ -49,6 +49,8 @@ Package org.springframework.webflow.engine
|
||||
* TransitionExecutingStateExceptionHandler now does full logging of the exceptions that it handles.
|
||||
* Fixed bug in BaseFlowServiceLocator where it was not allowing user to override the default web flow
|
||||
converters (SWF-220).
|
||||
* Added setFlowAttributes method to XmlFlowRegistryFactoryBean to make it easier to configure
|
||||
externally defined flow definition attributes (SWF-200).
|
||||
|
||||
Package org.springframework.webflow.execution.factory
|
||||
* The getHolder method on ConditionalFlowExecutionListenerLoader is now private. It has a package
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
package org.springframework.webflow.engine.builder.xml;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.webflow.core.collection.AttributeMap;
|
||||
import org.springframework.webflow.core.collection.LocalAttributeMap;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionResource;
|
||||
import org.springframework.webflow.engine.builder.AbstractFlowBuildingFlowRegistryFactoryBean;
|
||||
@@ -29,14 +29,14 @@ import org.springframework.webflow.engine.builder.DefaultFlowServiceLocator;
|
||||
import org.springframework.webflow.engine.builder.FlowServiceLocator;
|
||||
|
||||
/**
|
||||
* A factory bean that produces a populated flow registry using a
|
||||
* A factory bean that produces a populated flow registry using an
|
||||
* {@link XmlFlowRegistrar}. This is the simplest implementation to use when
|
||||
* using a Spring BeanFactory to deploy an explicit registry of XML-based Flow
|
||||
* definitions for execution.
|
||||
* <p>
|
||||
* By default, a configured flow definition will be assigned a registry
|
||||
* identifier equal to the filename of the underlying definition resource, minus
|
||||
* the filename extension. For example, a XML-based flow definition defined in
|
||||
* the filename extension. For example, an XML-based flow definition defined in
|
||||
* the file <code>flow1.xml</code> will be identified as <code>flow1</code>
|
||||
* in the registry created by this factory bean.
|
||||
* <p>
|
||||
@@ -66,11 +66,21 @@ public class XmlFlowRegistryFactoryBean extends AbstractFlowBuildingFlowRegistry
|
||||
* The flow registrar that will perform the definition registrations.
|
||||
*/
|
||||
private XmlFlowRegistrar flowRegistrar = new XmlFlowRegistrar();
|
||||
|
||||
/**
|
||||
* Temporary holder for flow definition locations.
|
||||
*/
|
||||
private Resource[] locations;
|
||||
|
||||
/**
|
||||
* Temporary holder for flow definitions configured using a property map.
|
||||
*/
|
||||
private Properties flowDefinitions;
|
||||
|
||||
/**
|
||||
* A map that contains a map (java.util.Map) of flow attributes keyed by flow id (String).
|
||||
*/
|
||||
private Map flowAttributes;
|
||||
|
||||
/**
|
||||
* Returns the configured externalized XML flow registrar.
|
||||
@@ -108,7 +118,7 @@ public class XmlFlowRegistryFactoryBean extends AbstractFlowBuildingFlowRegistry
|
||||
* @param locations the resource locations
|
||||
*/
|
||||
public void setFlowLocations(Resource[] locations) {
|
||||
getXmlFlowRegistrar().setLocations(locations);
|
||||
this.locations = locations;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,7 +132,7 @@ public class XmlFlowRegistryFactoryBean extends AbstractFlowBuildingFlowRegistry
|
||||
* Here is the exact format:
|
||||
*
|
||||
* <pre>
|
||||
* flow id=resource
|
||||
* flowId=resource
|
||||
* </pre>
|
||||
*
|
||||
* For example:
|
||||
@@ -143,6 +153,20 @@ public class XmlFlowRegistryFactoryBean extends AbstractFlowBuildingFlowRegistry
|
||||
public void setFlowDefinitions(Properties flowDefinitions) {
|
||||
this.flowDefinitions = flowDefinitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets flow attributes from an externalized <code>java.util.Map</code>. The keys in the
|
||||
* map are String flow ids. The corresponding values should be <code>java.util.Map</code>
|
||||
* maps containing flow attributes to be assigned to the flow. A flow with an id not
|
||||
* contained in the provided map will get not externally defined flow attributes assigned.
|
||||
* <p>
|
||||
* Can be used in conjunction with both {@link #setFlowLocations(Resource[])}
|
||||
* and {@link #setFlowDefinitions(Properties)}.
|
||||
* @param flowAttributes the flow attributes, keyed by flow id
|
||||
*/
|
||||
public void setFlowAttributes(Map flowAttributes) {
|
||||
this.flowAttributes = flowAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the loader to load XML-based flow definition documents during flow
|
||||
@@ -160,29 +184,54 @@ public class XmlFlowRegistryFactoryBean extends AbstractFlowBuildingFlowRegistry
|
||||
}
|
||||
|
||||
protected void doPopulate(FlowDefinitionRegistry registry) {
|
||||
addFlowDefinitionLocations();
|
||||
addFlowDefinitionsFromProperties();
|
||||
getXmlFlowRegistrar().registerFlowDefinitions(registry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add configured flow definition locations to the flow definition
|
||||
* registrar.
|
||||
*/
|
||||
private void addFlowDefinitionLocations() {
|
||||
if (locations != null) {
|
||||
for (int i = 0; i < locations.length; i++) {
|
||||
String flowId = FlowDefinitionResource.conventionalFlowId(locations[i]);
|
||||
getXmlFlowRegistrar().addResource(
|
||||
new FlowDefinitionResource(flowId, locations[i], getFlowAttributes(flowId)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add flow definitions configured using a property map to
|
||||
* the flow definition registrar.
|
||||
*/
|
||||
private void addFlowDefinitionsFromProperties() {
|
||||
if (flowDefinitions != null && flowDefinitions.size() > 0) {
|
||||
List flows = new ArrayList(flowDefinitions.size());
|
||||
if (flowDefinitions != null) {
|
||||
Iterator it = flowDefinitions.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry)it.next();
|
||||
String flowId = (String)entry.getKey();
|
||||
String location = (String)entry.getValue();
|
||||
Resource resource = getFlowServiceLocator().getResourceLoader().getResource(location);
|
||||
flows.add(new FlowDefinitionResource(flowId, resource));
|
||||
getXmlFlowRegistrar().addResource(
|
||||
new FlowDefinitionResource(flowId, resource, getFlowAttributes(flowId)));
|
||||
}
|
||||
getXmlFlowRegistrar().addResources(
|
||||
(FlowDefinitionResource[])flows.toArray(new FlowDefinitionResource[flows.size()]));
|
||||
// cleanup
|
||||
flowDefinitions = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flow attributes to be assigned to the flow with given id. Returns
|
||||
* null if no attributes should be assigned.
|
||||
*/
|
||||
private AttributeMap getFlowAttributes(String flowId) {
|
||||
if (flowAttributes != null) {
|
||||
Map attributes = (Map)flowAttributes.get(flowId);
|
||||
if (attributes != null) {
|
||||
return new LocalAttributeMap(attributes);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@ package org.springframework.webflow.engine.builder;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.beans.factory.support.StaticListableBeanFactory;
|
||||
import org.springframework.webflow.action.AbstractAction;
|
||||
import org.springframework.webflow.core.collection.AttributeMap;
|
||||
import org.springframework.webflow.core.collection.LocalAttributeMap;
|
||||
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
@@ -26,8 +25,6 @@ import org.springframework.webflow.definition.FlowDefinition;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
|
||||
import org.springframework.webflow.definition.registry.StaticFlowDefinitionHolder;
|
||||
import org.springframework.webflow.engine.Flow;
|
||||
import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
import org.springframework.webflow.execution.support.ApplicationView;
|
||||
import org.springframework.webflow.test.MockRequestControlContext;
|
||||
@@ -45,7 +42,7 @@ public class AbstractFlowBuilderParameterizationTests extends TestCase {
|
||||
protected void setUp() throws Exception {
|
||||
TestFlowRegistryFactoryBean registryFactory = new TestFlowRegistryFactoryBean();
|
||||
StaticListableBeanFactory beanFactory = new StaticListableBeanFactory();
|
||||
beanFactory.addBean("testAction", new TestAction());
|
||||
beanFactory.addBean("testAction", new ParameterizationTestAction());
|
||||
registryFactory.setBeanFactory(beanFactory);
|
||||
registryFactory.afterPropertiesSet();
|
||||
registry = registryFactory.getRegistry();
|
||||
@@ -90,30 +87,6 @@ public class AbstractFlowBuilderParameterizationTests extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public class TestAction extends AbstractAction {
|
||||
|
||||
protected Event doExecute(RequestContext context) throws Exception {
|
||||
if ("flowA".equals(context.getActiveFlow().getId())) {
|
||||
Flow flowA = (Flow)context.getActiveFlow();
|
||||
assertEquals(2, flowA.getAttributes().size());
|
||||
assertEquals("A", flowA.getAttributes().get("name"));
|
||||
assertEquals("someValue", flowA.getAttributes().get("someKey"));
|
||||
assertNull(flowA.getAttributes().get("someOtherKey"));
|
||||
}
|
||||
else if ("flowB".equals(context.getActiveFlow().getId())) {
|
||||
Flow flowB = (Flow)context.getActiveFlow();
|
||||
assertEquals(2, flowB.getAttributes().size());
|
||||
assertEquals("B", flowB.getAttributes().get("name"));
|
||||
assertEquals("someOtherValue", flowB.getAttributes().get("someOtherKey"));
|
||||
assertNull(flowB.getAttributes().get("someKey"));
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return success();
|
||||
}
|
||||
}
|
||||
|
||||
public class TestFlowRegistryFactoryBean extends AbstractFlowBuildingFlowRegistryFactoryBean {
|
||||
|
||||
protected void doPopulate(FlowDefinitionRegistry registry) {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2002-2006 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.builder;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.springframework.webflow.action.AbstractAction;
|
||||
import org.springframework.webflow.engine.Flow;
|
||||
import org.springframework.webflow.execution.Event;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
/**
|
||||
* Test action used by some unit tests.
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public class ParameterizationTestAction extends AbstractAction {
|
||||
|
||||
protected Event doExecute(RequestContext context) throws Exception {
|
||||
if ("flowA".equals(context.getActiveFlow().getId())) {
|
||||
Flow flowA = (Flow)context.getActiveFlow();
|
||||
Assert.assertEquals(2, flowA.getAttributes().size());
|
||||
Assert.assertEquals("A", flowA.getAttributes().get("name"));
|
||||
Assert.assertEquals("someValue", flowA.getAttributes().get("someKey"));
|
||||
Assert.assertNull(flowA.getAttributes().get("someOtherKey"));
|
||||
}
|
||||
else if ("flowB".equals(context.getActiveFlow().getId())) {
|
||||
Flow flowB = (Flow)context.getActiveFlow();
|
||||
Assert.assertEquals(2, flowB.getAttributes().size());
|
||||
Assert.assertEquals("B", flowB.getAttributes().get("name"));
|
||||
Assert.assertEquals("someOtherValue", flowB.getAttributes().get("someOtherKey"));
|
||||
Assert.assertNull(flowB.getAttributes().get("someKey"));
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2002-2006 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.builder.xml;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
|
||||
import org.springframework.webflow.engine.Flow;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
import org.springframework.webflow.execution.support.ApplicationView;
|
||||
import org.springframework.webflow.test.MockRequestControlContext;
|
||||
|
||||
/**
|
||||
* Test flow parameterization using the XmlFlowRegistryFactoryBean.
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public class XmlFlowRegistryFactoryBeanParameterizationTests extends TestCase {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
applicationContext = new ClassPathXmlApplicationContext("parameterizedFlowContext.xml", getClass());
|
||||
}
|
||||
|
||||
public void testNoFlowParameterization() {
|
||||
FlowDefinitionRegistry registry = (FlowDefinitionRegistry)applicationContext.getBean("flowRegistry0");
|
||||
assertEquals(1, registry.getFlowDefinitionCount());
|
||||
assertTrue(registry.containsFlowDefinition("parameterizedFlow"));
|
||||
Flow parameterizedFlow = (Flow)registry.getFlowDefinition("parameterizedFlow");
|
||||
assertEquals(0, parameterizedFlow.getAttributes().size());
|
||||
assertNull(parameterizedFlow.getAttributes().get("foo"));
|
||||
}
|
||||
|
||||
public void testSimpleFlowParameterization() {
|
||||
FlowDefinitionRegistry registry = (FlowDefinitionRegistry)applicationContext.getBean("flowRegistry1");
|
||||
assertEquals(1, registry.getFlowDefinitionCount());
|
||||
assertTrue(registry.containsFlowDefinition("parameterizedFlow"));
|
||||
Flow parameterizedFlow = (Flow)registry.getFlowDefinition("parameterizedFlow");
|
||||
assertEquals(1, parameterizedFlow.getAttributes().size());
|
||||
assertEquals("bar", parameterizedFlow.getAttributes().get("foo"));
|
||||
}
|
||||
|
||||
public void testAdvancedParameterization() {
|
||||
FlowDefinitionRegistry registry = (FlowDefinitionRegistry)applicationContext.getBean("flowRegistry2");
|
||||
|
||||
assertEquals(2, registry.getFlowDefinitionCount());
|
||||
assertTrue(registry.containsFlowDefinition("flowA"));
|
||||
Flow flowA = (Flow)registry.getFlowDefinition("flowA");
|
||||
assertEquals(2, flowA.getAttributes().size());
|
||||
assertEquals("A", flowA.getAttributes().get("name"));
|
||||
assertEquals("someValue", flowA.getAttributes().get("someKey"));
|
||||
assertNull(flowA.getAttributes().get("someOtherKey"));
|
||||
|
||||
assertTrue(registry.containsFlowDefinition("flowB"));
|
||||
Flow flowB = (Flow)registry.getFlowDefinition("flowB");
|
||||
assertEquals(2, flowB.getAttributes().size());
|
||||
assertEquals("B", flowB.getAttributes().get("name"));
|
||||
assertEquals("someOtherValue", flowB.getAttributes().get("someOtherKey"));
|
||||
assertNull(flowB.getAttributes().get("someKey"));
|
||||
}
|
||||
|
||||
public void testAdvancedParameterizationAtRuntime() {
|
||||
FlowDefinitionRegistry registry = (FlowDefinitionRegistry)applicationContext.getBean("flowRegistry2");
|
||||
|
||||
Flow flowA = (Flow)registry.getFlowDefinition("flowA");
|
||||
ViewSelection viewSelection = flowA.start(new MockRequestControlContext(flowA), null);
|
||||
assertEquals("A", ((ApplicationView)viewSelection).getViewName());
|
||||
|
||||
Flow flowB = (Flow)registry.getFlowDefinition("flowB");
|
||||
viewSelection = flowB.start(new MockRequestControlContext(flowB), null);
|
||||
assertEquals("B", ((ApplicationView)viewSelection).getViewName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-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-1.0.xsd">
|
||||
|
||||
<start-state idref="test" />
|
||||
|
||||
<action-state id="test">
|
||||
<action bean="testAction" />
|
||||
<transition on="success" to="finish" />
|
||||
</action-state>
|
||||
|
||||
<end-state id="finish" view="${activeFlow.attributes['name']}"/>
|
||||
</flow>
|
||||
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
<bean id="flowRegistry0"
|
||||
class="org.springframework.webflow.engine.builder.xml.XmlFlowRegistryFactoryBean">
|
||||
<property name="flowLocations" value="classpath:org/springframework/webflow/engine/builder/xml/parameterizedFlow.xml"/>
|
||||
</bean>
|
||||
|
||||
<bean id="flowRegistry1"
|
||||
class="org.springframework.webflow.engine.builder.xml.XmlFlowRegistryFactoryBean">
|
||||
<property name="flowLocations" value="classpath:org/springframework/webflow/engine/builder/xml/parameterizedFlow.xml"/>
|
||||
<property name="flowAttributes">
|
||||
<map>
|
||||
<entry key="parameterizedFlow">
|
||||
<map>
|
||||
<entry key="foo" value="bar"/>
|
||||
</map>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="flowRegistry2"
|
||||
class="org.springframework.webflow.engine.builder.xml.XmlFlowRegistryFactoryBean">
|
||||
<property name="flowDefinitions">
|
||||
<value>
|
||||
flowA=classpath:org/springframework/webflow/engine/builder/xml/parameterizedFlow.xml
|
||||
flowB=classpath:org/springframework/webflow/engine/builder/xml/parameterizedFlow.xml
|
||||
</value>
|
||||
</property>
|
||||
<property name="flowAttributes">
|
||||
<map>
|
||||
<entry key="flowA">
|
||||
<map>
|
||||
<entry key="name" value="A"/>
|
||||
<entry key="someKey" value="someValue"/>
|
||||
</map>
|
||||
</entry>
|
||||
<entry key="flowB">
|
||||
<map>
|
||||
<entry key="name" value="B"/>
|
||||
<entry key="someOtherKey" value="someOtherValue"/>
|
||||
</map>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="testAction"
|
||||
class="org.springframework.webflow.engine.builder.ParameterizationTestAction" />
|
||||
</beans>
|
||||
Reference in New Issue
Block a user