diff --git a/spring-webflow/changelog.txt b/spring-webflow/changelog.txt index 3b8154c7..31792566 100644 --- a/spring-webflow/changelog.txt +++ b/spring-webflow/changelog.txt @@ -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 diff --git a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowRegistryFactoryBean.java b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowRegistryFactoryBean.java index 99f12f51..a0d5a12d 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowRegistryFactoryBean.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/engine/builder/xml/XmlFlowRegistryFactoryBean.java @@ -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. *
* 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 flow1.xml will be identified as flow1
* in the registry created by this factory bean.
*
@@ -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: * *
- * flow id=resource + * flowId=resource ** * 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
java.util.Map. The keys in the
+ * map are String flow ids. The corresponding values should be java.util.Map
+ * 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.
+ *
+ * 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;
+ }
}
\ No newline at end of file
diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/AbstractFlowBuilderParameterizationTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/AbstractFlowBuilderParameterizationTests.java
index baf96a9e..5d7bed3b 100644
--- a/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/AbstractFlowBuilderParameterizationTests.java
+++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/AbstractFlowBuilderParameterizationTests.java
@@ -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) {
diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/ParameterizationTestAction.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/ParameterizationTestAction.java
new file mode 100644
index 00000000..67c3ecc2
--- /dev/null
+++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/ParameterizationTestAction.java
@@ -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();
+ }
+
+}
diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/xml/XmlFlowRegistryFactoryBeanParameterizationTests.java b/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/xml/XmlFlowRegistryFactoryBeanParameterizationTests.java
new file mode 100644
index 00000000..ec573d20
--- /dev/null
+++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/xml/XmlFlowRegistryFactoryBeanParameterizationTests.java
@@ -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());
+ }
+}
diff --git a/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/xml/parameterizedFlow.xml b/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/xml/parameterizedFlow.xml
new file mode 100644
index 00000000..ae8367a6
--- /dev/null
+++ b/spring-webflow/src/test/java/org/springframework/webflow/engine/builder/xml/parameterizedFlow.xml
@@ -0,0 +1,13 @@
+
+