RESOLVED - issue SWF-380: Allow users to specify the namespace to register a flow in
http://opensource.atlassian.com/projects/spring/browse/SWF-380
This commit is contained in:
@@ -15,16 +15,25 @@
|
||||
*/
|
||||
package org.springframework.webflow.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.springframework.webflow.engine.builder.xml.XmlFlowRegistryFactoryBean;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionResource;
|
||||
import org.springframework.webflow.engine.builder.FlowRegistryFactoryBean;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
@@ -32,40 +41,73 @@ import org.w3c.dom.Element;
|
||||
*
|
||||
* @author Ben Hale
|
||||
*/
|
||||
class RegistryBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
// elements and attributes
|
||||
class RegistryBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
// elements
|
||||
private static final String LOCATION_ELEMENT = "location";
|
||||
|
||||
// properties
|
||||
private static final String NAMESPACE_ELEMENT = "namespace";
|
||||
|
||||
private static final String FLOW_LOCATIONS_PROPERTY = "flowLocations";
|
||||
// attributes
|
||||
private static final String ID_ATTRIBUTE = "id";
|
||||
|
||||
private static final String NAME_ATTRIBUTE = "name";
|
||||
|
||||
private static final String PATH_ATTRIBUTE = "path";
|
||||
|
||||
protected Class getBeanClass(Element element) {
|
||||
return XmlFlowRegistryFactoryBean.class;
|
||||
// Properties
|
||||
private static final String XML_NAMESPACE_FLOW_MAPPINGS_PROPERTY = "xmlNamespaceFlowMappings";
|
||||
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(FlowRegistryFactoryBean.class);
|
||||
definitionBuilder.setSource(parserContext.extractSource(element));
|
||||
parseXml(element, definitionBuilder, parserContext);
|
||||
return definitionBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
protected void doParse(Element element, BeanDefinitionBuilder definitionBuilder) {
|
||||
List locationElements = DomUtils.getChildElementsByTagName(element, LOCATION_ELEMENT);
|
||||
List locations = getLocations(locationElements);
|
||||
definitionBuilder.addPropertyValue(FLOW_LOCATIONS_PROPERTY, locations.toArray(new String[locations.size()]));
|
||||
public void parseXml(Element element, BeanDefinitionBuilder definitionBuilder, ParserContext parserContext) {
|
||||
Map xmlNamespaceFlowMappings = new HashMap();
|
||||
xmlNamespaceFlowMappings.put("", parseXmlElements(
|
||||
DomUtils.getChildElementsByTagName(element, LOCATION_ELEMENT), parserContext));
|
||||
List namespaceElements = DomUtils.getChildElementsByTagName(element, NAMESPACE_ELEMENT);
|
||||
for (Iterator it = namespaceElements.iterator(); it.hasNext();) {
|
||||
Element namespaceElement = (Element) it.next();
|
||||
String namespace = namespaceElement.getAttribute(NAME_ATTRIBUTE);
|
||||
xmlNamespaceFlowMappings.put(namespace, parseXmlElements(DomUtils.getChildElementsByTagName(
|
||||
namespaceElement, LOCATION_ELEMENT), parserContext));
|
||||
}
|
||||
definitionBuilder.addPropertyValue(XML_NAMESPACE_FLOW_MAPPINGS_PROPERTY, xmlNamespaceFlowMappings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse location definitions from given list of location elements.
|
||||
*/
|
||||
private List getLocations(List locationElements) {
|
||||
List locations = new ArrayList(locationElements.size());
|
||||
for (Iterator i = locationElements.iterator(); i.hasNext();) {
|
||||
Element locationElement = (Element) i.next();
|
||||
String path = locationElement.getAttribute(PATH_ATTRIBUTE);
|
||||
if (StringUtils.hasText(path)) {
|
||||
locations.add(path);
|
||||
private Set parseXmlElements(List locationElements, ParserContext parserContext) {
|
||||
ResourcePatternResolver resolver = ResourcePatternUtils.getResourcePatternResolver(parserContext
|
||||
.getReaderContext().getResourceLoader());
|
||||
Set resources = new HashSet();
|
||||
for (Iterator it = locationElements.iterator(); it.hasNext();) {
|
||||
Element locationElement = (Element) it.next();
|
||||
try {
|
||||
Resource[] locations = resolver.getResources(locationElement.getAttribute(PATH_ATTRIBUTE));
|
||||
if (locationElement.hasAttribute(ID_ATTRIBUTE)) {
|
||||
if (locations.length != 1) {
|
||||
parserContext.getReaderContext().error(
|
||||
"The 'path' attribute of the 'location' element must point to a single value "
|
||||
+ "flow definition if an id has been specified", locationElement);
|
||||
} else {
|
||||
resources.add(new FlowDefinitionResource(locationElement.getAttribute(ID_ATTRIBUTE),
|
||||
locations[0]));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < locations.length; i++) {
|
||||
resources.add(new FlowDefinitionResource(locations[i]));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
parserContext.getReaderContext().error(
|
||||
"The 'path' attribute of the 'location' element must point to a valid flow definition "
|
||||
+ "or definitions", locationElement);
|
||||
}
|
||||
}
|
||||
return locations;
|
||||
return resources;
|
||||
}
|
||||
}
|
||||
@@ -20,17 +20,17 @@ Provides an easy way to configure a flow executor and an XML flow definition reg
|
||||
|
||||
<xsd:import namespace="http://www.springframework.org/schema/beans"
|
||||
schemaLocation="http://www.springframework.org/schema/beans/spring-beans-2.0.xsd" />
|
||||
|
||||
<xsd:element name="enable-scopes">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Allows access to the Spring Web Flow scopes (conversation, flow, flash) from a Spring ApplicationContext.
|
||||
Only one of these elements is required per ApplicationContext.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="enable-scopes">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Allows access to the Spring Web Flow scopes (conversation, flow, flash) from a Spring ApplicationContext.
|
||||
Only one of these elements is required per ApplicationContext.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="registry">
|
||||
<xsd:annotation>
|
||||
@@ -52,7 +52,7 @@ A flow registry is used by a flow executor at runtime to launch new executions o
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="beans:identifiedType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="location" type="locationType" maxOccurs="unbounded">
|
||||
<xsd:element name="location" type="locationType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
@@ -67,6 +67,47 @@ Individual paths such as:
|
||||
<pre>
|
||||
/WEB-INF/flows/**/*-flow.xml
|
||||
</pre>
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="class" type="classType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Specifies a class containing a flow definition. The flow definition built from this
|
||||
class will be registered in this registry.
|
||||
<br>
|
||||
Classes must be declared using a fully qualified path name such as
|
||||
<pre>
|
||||
com.interface21.SellItemFlow
|
||||
</pre>
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="crud" type="crudType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Specifies a domain entity class to have crud flows built for. This will register flows for Creating, Reading, Updating,
|
||||
and Deleting the domain entity in a namespace that is equal to the short name of the class.
|
||||
<br>
|
||||
Entities must be declared using a fully qualified path name such as
|
||||
<pre>
|
||||
com.interface21.Account
|
||||
</pre>
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="namespace" type="namespaceType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Specifies a namespace to register nested flow definitions in. This namespace is a course-grained grouping for uniquely
|
||||
identifying a flow. Since some flows define a namespace implicitly (CRUD flows for example), not all flow types are
|
||||
allowed to be nested in the namespace tag.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
@@ -78,12 +119,96 @@ Individual paths such as:
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="locationType">
|
||||
<xsd:attribute name="id" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The id to the externalized flow definition resource. This only needs to be populated for explict declaration of flow
|
||||
identifiers. If not populated this id of the flow is equal to the filename of the underlying definition resource, minus
|
||||
the filename extension. This value cannot be set if an ANT-style path expression that matches multiple resources is
|
||||
used in path attribute.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="path" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The path to the externalized flow definition resource. May be a path to a single resource or
|
||||
a ANT-style path expression that matches multiple resources.
|
||||
The path to the externalized flow definition resource. May be a path to a single resource or a ANT-style path expression
|
||||
that matches multiple resources.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="classType">
|
||||
<xsd:attribute name="name" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The name of the java based flow definition.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="crudType">
|
||||
<xsd:attribute name="entity" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The name of a domain entity class to have crud flows created for.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="namespaceType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="location" type="locationType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Specifies a path to a externalized flow definition resource. The flow definition built from this
|
||||
resource will be registered in this registry.
|
||||
<br>
|
||||
Individual paths such as:
|
||||
<pre>
|
||||
/WEB-INF/flows/orderitem-flow.xml
|
||||
</pre>
|
||||
... are supported as well as wildcard paths such as:
|
||||
<pre>
|
||||
/WEB-INF/flows/**/*-flow.xml
|
||||
</pre>
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="class" type="classType" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
Specifies a class containing a flow definition. The flow definition built from this
|
||||
class will be registered in this registry.
|
||||
<br>
|
||||
Classes must be declared using a fully qualified path name such as
|
||||
<pre>
|
||||
com.interface21.SellItemFlow
|
||||
</pre>
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[
|
||||
The name of the namespace to group all child flow definitions in.
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
@@ -38,7 +38,7 @@ public interface AttributeMap extends MapAdaptable {
|
||||
|
||||
/**
|
||||
* Returns the size of this map.
|
||||
* @return the nubmer of entries in the map
|
||||
* @return the number of entries in the map
|
||||
*/
|
||||
public int size();
|
||||
|
||||
|
||||
@@ -1,97 +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.definition.registry;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* A base class for factory beans that create populated flow definition registries. Subclasses should override the
|
||||
* {@link #doPopulate(FlowDefinitionRegistry)} method to perform the registry population logic, typically delegating to
|
||||
* a {@link FlowDefinitionRegistrar} strategy to perform the population.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public abstract class AbstractFlowDefinitionRegistryFactoryBean implements FactoryBean, InitializingBean {
|
||||
|
||||
/**
|
||||
* The registry to register flow definitions in.
|
||||
*/
|
||||
private FlowDefinitionRegistry registry = createFlowDefinitionRegistry();
|
||||
|
||||
/**
|
||||
* Sets the parent registry of the registry constructed by this factory bean.
|
||||
* <p>
|
||||
* A child registry will delegate to its parent if it cannot fulfill a request to locate a flow definition itself.
|
||||
* @param parent the parent flow definition registry
|
||||
*/
|
||||
public void setParent(FlowDefinitionRegistry parent) {
|
||||
registry.setParent(parent);
|
||||
}
|
||||
|
||||
// implementing InitializingBean
|
||||
|
||||
public final void afterPropertiesSet() throws Exception {
|
||||
init();
|
||||
doPopulate(registry);
|
||||
}
|
||||
|
||||
// implementing FactoryBean
|
||||
|
||||
public Class getObjectType() {
|
||||
return FlowDefinitionRegistry.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
// the registry is populated by the time this is called
|
||||
return getRegistry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flow definition registry constructed by the factory bean.
|
||||
*/
|
||||
public FlowDefinitionRegistry getRegistry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
// subclassing hooks
|
||||
|
||||
/**
|
||||
* Create the flow definition registry to be populated in {@link #doPopulate(FlowDefinitionRegistry)}. Subclasses
|
||||
* can override this method if they want to use a custom flow definition registry implementation.
|
||||
*/
|
||||
protected FlowDefinitionRegistry createFlowDefinitionRegistry() {
|
||||
return new FlowDefinitionRegistryImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method subclasses may override to perform factory bean initialization logic before registry population.
|
||||
* Will be called before {@link #doPopulate(FlowDefinitionRegistry)}. The default implementation is empty.
|
||||
*/
|
||||
protected void init() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method subclasses must override to perform registry population.
|
||||
* @param registry the flow definition registry to populate
|
||||
*/
|
||||
protected abstract void doPopulate(FlowDefinitionRegistry registry);
|
||||
|
||||
}
|
||||
@@ -15,13 +15,15 @@
|
||||
*/
|
||||
package org.springframework.webflow.definition.registry;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.webflow.engine.builder.FlowServiceLocator;
|
||||
|
||||
/**
|
||||
* A flow definition registrar that populates a flow definition registry from flow definitions defined within
|
||||
@@ -30,167 +32,139 @@ import org.springframework.core.style.ToStringCreator;
|
||||
* <p>
|
||||
* Concrete subclasses are expected to derive from this class to provide knowledge about a particular kind of definition
|
||||
* format by implementing the abstract template methods in this class.
|
||||
* <p>
|
||||
* By default, when configuring the {@link #setLocations(Resource[]) locations} property, flow definitions at those
|
||||
* locations 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 file "flow1.xml" will be identified
|
||||
* as "flow1" when registered in a registry.
|
||||
* <p>
|
||||
* For full control over the assignment of flow identifiers and flow properties, configure formal
|
||||
* {@link org.springframework.webflow.definition.registry.FlowDefinitionResource} instances using the
|
||||
* {@link #setResources(FlowDefinitionResource[] resources)} property.
|
||||
*
|
||||
* @see org.springframework.webflow.definition.registry.FlowDefinitionResource
|
||||
* @see org.springframework.webflow.definition.registry.FlowDefinitionRegistry
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Ben Hale
|
||||
*/
|
||||
public abstract class ExternalizedFlowDefinitionRegistrar implements FlowDefinitionRegistrar {
|
||||
|
||||
/**
|
||||
* File locations of externalized flow definition resources to load. A set of {@link Resource}} objects.
|
||||
* The locator of services needed by flow definitions.
|
||||
*/
|
||||
private Set locations = new HashSet();
|
||||
private FlowServiceLocator flowServiceLocator;
|
||||
|
||||
/**
|
||||
* A set of formal externalized flow definitions to load. A set of {@link FlowDefinitionResource} objects.
|
||||
* A set of mappings between a namespace and a set of externalized flow definitions. A map of Strings to Sets
|
||||
* containing {@link FlowDefinitionResource}s
|
||||
*/
|
||||
private Set resources = new HashSet();
|
||||
private Map namespaceFlowMappings;
|
||||
|
||||
/**
|
||||
* Sets the locations (file paths) pointing to externalized flow definitions.
|
||||
* <p>
|
||||
* Flows registered from this set will be automatically assigned an id based on the filename of the flow resource.
|
||||
* @param locations the resource locations
|
||||
* The default namespace for flows registered without an explicit namespace.
|
||||
*/
|
||||
public void setLocations(Resource[] locations) {
|
||||
this.locations = new HashSet(Arrays.asList(locations));
|
||||
private String defaultNamespace = "";
|
||||
|
||||
/**
|
||||
* Creates a new registrar with an empty initial set of namespace to flow mappings.
|
||||
*/
|
||||
public ExternalizedFlowDefinitionRegistrar() {
|
||||
this(new HashMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the formal set of externalized flow definitions this registrar will register.
|
||||
* <p>
|
||||
* Use this method when you want full control over the assigned flow id and the set of properties applied to the
|
||||
* externalized flow resources.
|
||||
* @param resources the externalized flow definition specifications
|
||||
* Creates a new registrar with an initial set of namespace to flow mappings.
|
||||
* @param namespaceFlowMappings the initial set of namespace to flow mappings
|
||||
*/
|
||||
public void setResources(FlowDefinitionResource[] resources) {
|
||||
this.resources = new HashSet(Arrays.asList(resources));
|
||||
public ExternalizedFlowDefinitionRegistrar(Map namespaceFlowMappings) {
|
||||
this.namespaceFlowMappings = namespaceFlowMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a flow location pointing to an externalized flow resource.
|
||||
* <p>
|
||||
* The flow registered from this location will automatically assigned an id based on the filename of the flow
|
||||
* resource.
|
||||
* @param location the definition location
|
||||
* Sets the default namespace to register flows in. If not set the default namespace is "" (an empty string).
|
||||
* @param defaultNamespace the default namespace
|
||||
*/
|
||||
public void setDefaultNamespace(String defaultNamespace) {
|
||||
this.defaultNamespace = defaultNamespace;
|
||||
}
|
||||
|
||||
public void setFlowServiceLocator(FlowServiceLocator flowServiceLocator) {
|
||||
this.flowServiceLocator = flowServiceLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flow service locator for use by subclasses.
|
||||
*/
|
||||
protected FlowServiceLocator getFlowServiceLocator() {
|
||||
return flowServiceLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an externalized XML flow definition to be registered in the default namespace.
|
||||
* @param location the resource to register
|
||||
* @see #addLocation(Resource, String)
|
||||
* @see #setDefaultNamespace(String)
|
||||
*/
|
||||
public boolean addLocation(Resource location) {
|
||||
return locations.add(location);
|
||||
return addLocation(location, defaultNamespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the flow locations pointing to externalized flow resources.
|
||||
* <p>
|
||||
* The flow registered from this location will automatically assigned an id based on the filename of the flow
|
||||
* resource.
|
||||
* @param locations the definition locations
|
||||
* Adds an externalized XML flow definition to be registered. The resource will be assigned a registry identifier
|
||||
* equal to the filename of the resource, minus 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.
|
||||
* @param location the resource to register
|
||||
* @param namespace the namespace to register the flow definition in
|
||||
*/
|
||||
public boolean addLocations(Resource[] locations) {
|
||||
if (locations == null) {
|
||||
return false;
|
||||
}
|
||||
return this.locations.addAll(Arrays.asList(locations));
|
||||
public boolean addLocation(Resource location, String namespace) {
|
||||
return getFlows(namespace).add(new FlowDefinitionResource(location));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an externalized flow definition specification pointing to an externalized flow resource.
|
||||
* <p>
|
||||
* Use this method when you want full control over the assigned flow id and the set of properties applied to the
|
||||
* externalized flow resource.
|
||||
* @param resource the definition the definition resource
|
||||
* Adds an externalized XML flow definition resource to be registered in the default namespace.
|
||||
* @param resource the flow definition resource to be registered
|
||||
* @see #addResource(FlowDefinitionResource, String)
|
||||
* @see #setDefaultNamespace(String)
|
||||
*/
|
||||
public boolean addResource(FlowDefinitionResource resource) {
|
||||
return resources.add(resource);
|
||||
return addResource(resource, defaultNamespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the externalized flow definitions pointing to externalized flow resources.
|
||||
* <p>
|
||||
* Use this method when you want full control over the assigned flow id and the set of properties applied to the
|
||||
* externalized flow resources.
|
||||
* @param resources the definitions
|
||||
* Adds an externalized XML flow definition resource to be registered.
|
||||
* @param resource the flow definition resource to be registered
|
||||
* @param namespace the namespace to register the flow definition in
|
||||
*/
|
||||
public boolean addResources(FlowDefinitionResource[] resources) {
|
||||
if (resources == null) {
|
||||
return false;
|
||||
}
|
||||
return this.resources.addAll(Arrays.asList(resources));
|
||||
public boolean addResource(FlowDefinitionResource resource, String namespace) {
|
||||
return getFlows(namespace).add(resource);
|
||||
}
|
||||
|
||||
public void registerFlowDefinitions(FlowDefinitionRegistry registry) {
|
||||
processLocations(registry);
|
||||
processResources(registry);
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
/**
|
||||
* Register the flow definitions at the configured file locations.
|
||||
* @param registry the registry
|
||||
*/
|
||||
private void processLocations(FlowDefinitionRegistry registry) {
|
||||
Iterator it = locations.iterator();
|
||||
while (it.hasNext()) {
|
||||
Resource location = (Resource) it.next();
|
||||
if (isFlowDefinitionResource(location)) {
|
||||
FlowDefinitionResource resource = createFlowDefinitionResource(location);
|
||||
register(resource, registry);
|
||||
for (Iterator mappings = namespaceFlowMappings.entrySet().iterator(); mappings.hasNext();) {
|
||||
Map.Entry mapping = (Map.Entry) mappings.next();
|
||||
String namespace = (String) mapping.getKey();
|
||||
for (Iterator resources = ((Set) mapping.getValue()).iterator(); resources.hasNext();) {
|
||||
FlowDefinitionResource resource = (FlowDefinitionResource) resources.next();
|
||||
register(resource, namespace, registry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the flow definitions at the configured file locations.
|
||||
* Registers a flow definition resource in a given namespace.
|
||||
* @param resource the resource to register
|
||||
* @param namespace the namespace to register in
|
||||
* @param registry the registry
|
||||
*/
|
||||
private void processResources(FlowDefinitionRegistry registry) {
|
||||
Iterator it = resources.iterator();
|
||||
while (it.hasNext()) {
|
||||
FlowDefinitionResource resource = (FlowDefinitionResource) it.next();
|
||||
register(resource, registry);
|
||||
private void register(FlowDefinitionResource resource, String namespace, FlowDefinitionRegistry registry) {
|
||||
registry.registerFlowDefinition(createFlowDefinitionHolder(resource), namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of flows to be registered in a namespace.
|
||||
* @param namespace The namespace for the collection to be returned
|
||||
*/
|
||||
private Set getFlows(String namespace) {
|
||||
if (!namespaceFlowMappings.containsKey(namespace)) {
|
||||
namespaceFlowMappings.put(namespace, new HashSet());
|
||||
}
|
||||
return (Set) namespaceFlowMappings.get(namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to register the flow built from an externalized resource in the registry.
|
||||
* @param resource representation of the externalized flow definition resource
|
||||
* @param registry the flow registry to register the flow in
|
||||
*/
|
||||
protected final void register(FlowDefinitionResource resource, FlowDefinitionRegistry registry) {
|
||||
registry.registerFlowDefinition(createFlowDefinitionHolder(resource));
|
||||
}
|
||||
|
||||
// subclassing hooks
|
||||
|
||||
/**
|
||||
* Template method that calculates if the given file resource is actually a flow definition resource. Resources that
|
||||
* aren't flow definitions will be ignored. Subclasses may override; this implementation simply returns true.
|
||||
* @param resource the underlying resource
|
||||
* @return true if yes, false otherwise
|
||||
*/
|
||||
protected boolean isFlowDefinitionResource(Resource resource) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method that creates a flow definition from an externalized resource location.
|
||||
* @param location the location of the resource
|
||||
* @return the externalized flow definition pointer
|
||||
*/
|
||||
protected FlowDefinitionResource createFlowDefinitionResource(Resource location) {
|
||||
return new FlowDefinitionResource(location);
|
||||
}
|
||||
// sub-classing hooks
|
||||
|
||||
/**
|
||||
* Template factory method subclasses must override to return the holder for the flow definition to be registered
|
||||
@@ -201,6 +175,6 @@ public abstract class ExternalizedFlowDefinitionRegistrar implements FlowDefinit
|
||||
protected abstract FlowDefinitionHolder createFlowDefinitionHolder(FlowDefinitionResource resource);
|
||||
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("locations", locations).append("resources", resources).toString();
|
||||
return new ToStringCreator(this).append("namespaceFlowMappings", namespaceFlowMappings).toString();
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.webflow.definition.registry;
|
||||
|
||||
|
||||
/**
|
||||
* A strategy to use to populate a flow definition registry with one or more flow definitions.
|
||||
* <p>
|
||||
@@ -42,4 +43,5 @@ public interface FlowDefinitionRegistrar {
|
||||
* @param registry the registry to register flow definitions in
|
||||
*/
|
||||
public void registerFlowDefinitions(FlowDefinitionRegistry registry);
|
||||
|
||||
}
|
||||
@@ -1,83 +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.builder;
|
||||
|
||||
import org.springframework.webflow.core.collection.AttributeMap;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionHolder;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
|
||||
import org.springframework.webflow.definition.registry.StaticFlowDefinitionHolder;
|
||||
import org.springframework.webflow.engine.Flow;
|
||||
import org.springframework.webflow.engine.builder.AbstractFlowBuilder;
|
||||
import org.springframework.webflow.engine.builder.AbstractFlowBuildingFlowRegistryFactoryBean;
|
||||
import org.springframework.webflow.engine.builder.FlowAssembler;
|
||||
|
||||
/**
|
||||
* Base class for factory beans that create flow definition registries containing flows built using Java based
|
||||
* {@link AbstractFlowBuilder flow builders}.
|
||||
* <p>
|
||||
* Subclasses only need to define the {@link #doPopulate(FlowDefinitionRegistry)} method and use the
|
||||
* {@link #registerFlowDefinition(FlowDefinitionRegistry, String, AbstractFlowBuilder)} convenience methods provided by
|
||||
* this class to register all relevant flows:
|
||||
*
|
||||
* <pre class="code">
|
||||
* public class MyFlowRegistryFactoryBean extends AbstractFlowBuilderFlowRegistryFactoryBean {
|
||||
* protected void doPopulate(FlowDefinitionRegistry registry) {
|
||||
* registerFlowDefinition(registry, "my-flow", new MyFlowBuilder());
|
||||
* registerFlowDefinition(registry, "my-other-flow", new MyOtherFlowBuilder());
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see AbstractFlowBuilder
|
||||
*
|
||||
* @since 1.0.2
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public abstract class AbstractFlowBuilderFlowRegistryFactoryBean extends AbstractFlowBuildingFlowRegistryFactoryBean {
|
||||
|
||||
/**
|
||||
* Register the flow built by given flow builder in specified flow definition registry.
|
||||
* <p>
|
||||
* Note that this method will set the {@link #getFlowServiceLocator() flow service locator} of this class on given
|
||||
* flow builder.
|
||||
* @param registry the registry to register the flow in
|
||||
* @param flowId the flow id to assign
|
||||
* @param flowBuilder the builder used to build the flow
|
||||
*/
|
||||
protected void registerFlowDefinition(FlowDefinitionRegistry registry, String flowId,
|
||||
AbstractFlowBuilder flowBuilder) {
|
||||
registerFlowDefinition(registry, flowId, null, flowBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the flow built by given flow builder in specified flow definition registry.
|
||||
* <p>
|
||||
* Note that this method will set the {@link #getFlowServiceLocator() flow service locator} of this class on given
|
||||
* flow builder.
|
||||
* @param registry the registry to register the flow in
|
||||
* @param flowId the flow id to assign
|
||||
* @param flowAttributes externally assigned flow attributes that can affect flow construction
|
||||
* @param flowBuilder the builder used to build the flow
|
||||
*/
|
||||
protected void registerFlowDefinition(FlowDefinitionRegistry registry, String flowId, AttributeMap flowAttributes,
|
||||
AbstractFlowBuilder flowBuilder) {
|
||||
flowBuilder.setFlowServiceLocator(getFlowServiceLocator());
|
||||
Flow flow = new FlowAssembler(flowId, flowAttributes, flowBuilder).assembleFlow();
|
||||
FlowDefinitionHolder flowHolder = new StaticFlowDefinitionHolder(flow);
|
||||
registry.registerFlowDefinition(flowHolder);
|
||||
}
|
||||
}
|
||||
@@ -1,223 +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.builder;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.webflow.action.BeanInvokingActionFactory;
|
||||
import org.springframework.webflow.definition.registry.AbstractFlowDefinitionRegistryFactoryBean;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
|
||||
import org.springframework.webflow.engine.Flow;
|
||||
import org.springframework.webflow.engine.State;
|
||||
import org.springframework.webflow.execution.Action;
|
||||
|
||||
/**
|
||||
* A base class for factory beans that create populated registries of flow definitions built using a {@link FlowBuilder},
|
||||
* typically a {@link BaseFlowBuilder} subclass. This base class will setup a {@link FlowServiceLocator} for use by the
|
||||
* flow builder.
|
||||
* <p>
|
||||
* Subclasses should override the {@link #doPopulate(FlowDefinitionRegistry)} template method to perform the registry
|
||||
* population logic, typically delegating to a
|
||||
* {@link org.springframework.webflow.definition.registry.FlowDefinitionRegistrar} strategy.
|
||||
*
|
||||
* @see org.springframework.webflow.definition.registry.FlowDefinitionRegistry
|
||||
* @see org.springframework.webflow.definition.registry.FlowDefinitionRegistrar
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public abstract class AbstractFlowBuildingFlowRegistryFactoryBean extends AbstractFlowDefinitionRegistryFactoryBean
|
||||
implements BeanFactoryAware, ResourceLoaderAware {
|
||||
|
||||
/**
|
||||
* The locator of services needed by the flows built for inclusion in the registry.
|
||||
*/
|
||||
private FlowServiceLocator flowServiceLocator;
|
||||
|
||||
/**
|
||||
* The factory encapsulating the creation of central Flow artifacts such as {@link Flow flows} and
|
||||
* {@link State states}.
|
||||
*/
|
||||
private FlowArtifactFactory flowArtifactFactory;
|
||||
|
||||
/**
|
||||
* The factory encapsulating the creation of bean invoking actions, actions that adapt methods on objects to the
|
||||
* {@link Action} interface.
|
||||
*/
|
||||
private BeanInvokingActionFactory beanInvokingActionFactory;
|
||||
|
||||
/**
|
||||
* The parser for parsing expression strings into evaluatable expression objects.
|
||||
*/
|
||||
private ExpressionParser expressionParser;
|
||||
|
||||
/**
|
||||
* A conversion service that can convert between types.
|
||||
*/
|
||||
private ConversionService conversionService;
|
||||
|
||||
/**
|
||||
* A resource loader that can load resources.
|
||||
*/
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
/**
|
||||
* The Spring bean factory that manages configured flow artifacts.
|
||||
*/
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* Returns the factory encapsulating the creation of central Flow artifacts such as {@link Flow flows} and
|
||||
* {@link State states}.
|
||||
*/
|
||||
protected FlowArtifactFactory getFlowArtifactFactory() {
|
||||
return flowArtifactFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the factory encapsulating the creation of central Flow artifacts such as {@link Flow flows} and
|
||||
* {@link State states}.
|
||||
*/
|
||||
public void setFlowArtifactFactory(FlowArtifactFactory flowArtifactFactory) {
|
||||
this.flowArtifactFactory = flowArtifactFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the factory for creating bean invoking actions, actions that adapt methods on objects to the
|
||||
* {@link Action} interface.
|
||||
*/
|
||||
protected BeanInvokingActionFactory getBeanInvokingActionFactory() {
|
||||
return beanInvokingActionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the factory for creating bean invoking actions, actions that adapt methods on objects to the {@link Action}
|
||||
* interface.
|
||||
*/
|
||||
public void setBeanInvokingActionFactory(BeanInvokingActionFactory beanInvokingActionFactory) {
|
||||
this.beanInvokingActionFactory = beanInvokingActionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expression parser responsible for parsing expression strings into evaluatable expression objects.
|
||||
*/
|
||||
protected ExpressionParser getExpressionParser() {
|
||||
return expressionParser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expression parser responsible for parsing expression strings into evaluatable expression objects.
|
||||
*/
|
||||
public void setExpressionParser(ExpressionParser expressionParser) {
|
||||
this.expressionParser = expressionParser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the conversion service to use to convert between types; typically from string to a rich object type.
|
||||
*/
|
||||
protected ConversionService getConversionService() {
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the conversion service to use to convert between types; typically from string to a rich object type.
|
||||
*/
|
||||
public void setConversionService(ConversionService conversionService) {
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
// implementing ResourceLoaderAware
|
||||
|
||||
/**
|
||||
* Returns the injected resource loader.
|
||||
*/
|
||||
protected ResourceLoader getResourceLoader() {
|
||||
return resourceLoader;
|
||||
}
|
||||
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
// implementing BeanFactoryAware
|
||||
|
||||
/**
|
||||
* Returns the bean factory managing this bean.
|
||||
*/
|
||||
protected BeanFactory getBeanFactory() {
|
||||
return beanFactory;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
protected final void init() {
|
||||
flowServiceLocator = createFlowServiceLocator();
|
||||
init(flowServiceLocator);
|
||||
}
|
||||
|
||||
// subclassing hooks
|
||||
|
||||
/**
|
||||
* Factory method for creating the service locator used to locate webflow services during flow assembly. Subclasses
|
||||
* may override to customize the instantiation and configuration of the locator returned.
|
||||
* @return the service locator
|
||||
*/
|
||||
protected FlowServiceLocator createFlowServiceLocator() {
|
||||
DefaultFlowServiceLocator serviceLocator = new DefaultFlowServiceLocator(getRegistry(), beanFactory);
|
||||
if (flowArtifactFactory != null) {
|
||||
serviceLocator.setFlowArtifactFactory(flowArtifactFactory);
|
||||
}
|
||||
if (beanInvokingActionFactory != null) {
|
||||
serviceLocator.setBeanInvokingActionFactory(beanInvokingActionFactory);
|
||||
}
|
||||
if (expressionParser != null) {
|
||||
serviceLocator.setExpressionParser(expressionParser);
|
||||
}
|
||||
if (conversionService != null) {
|
||||
serviceLocator.setConversionService(conversionService);
|
||||
}
|
||||
if (resourceLoader != null) {
|
||||
serviceLocator.setResourceLoader(resourceLoader);
|
||||
}
|
||||
return serviceLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after properties have been set on the service locator, but before registry population. Subclasses may
|
||||
* override to perform custom initialization of the flow service locator.
|
||||
* @param flowServiceLocator the flow service locator to use to locate externally managed services needed during
|
||||
* flow building and assembly, typically used by a
|
||||
* {@link org.springframework.webflow.definition.registry.FlowDefinitionRegistrar}
|
||||
*/
|
||||
protected void init(FlowServiceLocator flowServiceLocator) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the strategy for locating dependent artifacts when a flow is being built. May be called by subclasses
|
||||
* during {@link #doPopulate(FlowDefinitionRegistry) registry population} to wire in the service locator needed for
|
||||
* flow assembly.
|
||||
*/
|
||||
protected FlowServiceLocator getFlowServiceLocator() {
|
||||
return flowServiceLocator;
|
||||
}
|
||||
|
||||
protected abstract void doPopulate(FlowDefinitionRegistry registry);
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.builder;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistrar;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistryImpl;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionResource;
|
||||
import org.springframework.webflow.engine.builder.xml.XmlFlowRegistrar;
|
||||
|
||||
/**
|
||||
* A factory bean that accepts an arbitrary list of {@link FlowDefinitionRegistrar}s and uses them to register flows.
|
||||
* This implementation should not be used programmatically but rather from the spring-webflow-config XML namespace.
|
||||
* <p>
|
||||
* Example Usage:
|
||||
*
|
||||
* <pre>
|
||||
* <flow:registry id="flowRegistry">
|
||||
* <flow:location path="flow1.xml"/>
|
||||
* <flow:location id="foo" path="flow2.xml"/>
|
||||
* <flow:class name="BarClass"/>
|
||||
* <flow:crud entity="Account"/>
|
||||
* <flow:namespace name="baz">
|
||||
* <flow:location path="flow3.xml"/>
|
||||
* <flow:class name="XyzClass"/>
|
||||
* </flow:namespace>
|
||||
* </flow:registry>
|
||||
* </pre>
|
||||
*
|
||||
* @author Ben Hale
|
||||
*/
|
||||
public class FlowRegistryFactoryBean implements FactoryBean, InitializingBean, BeanFactoryAware {
|
||||
|
||||
private FlowDefinitionRegistry registry;
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private FlowServiceLocator flowServiceLocator;
|
||||
|
||||
private Map xmlNamespaceFlowMappings;
|
||||
|
||||
public void setFlowServiceLocator(FlowServiceLocator flowServiceLocator) {
|
||||
this.flowServiceLocator = flowServiceLocator;
|
||||
}
|
||||
|
||||
public void setXmlNamespaceFlowMappings(Map xmlNamespaceFlowMappings) {
|
||||
this.xmlNamespaceFlowMappings = xmlNamespaceFlowMappings;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
this.registry = new FlowDefinitionRegistryImpl();
|
||||
initXml(registry);
|
||||
}
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
return registry;
|
||||
}
|
||||
|
||||
public Class getObjectType() {
|
||||
return FlowDefinitionRegistry.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
private void initXml(FlowDefinitionRegistry registry) {
|
||||
XmlFlowRegistrar registrar = new XmlFlowRegistrar(getFlowServiceLocator(registry));
|
||||
for (Iterator mappings = xmlNamespaceFlowMappings.entrySet().iterator(); mappings.hasNext();) {
|
||||
Map.Entry mapping = (Map.Entry) mappings.next();
|
||||
String namespace = (String) mapping.getKey();
|
||||
for (Iterator resources = ((Set) mapping.getValue()).iterator(); resources.hasNext();) {
|
||||
FlowDefinitionResource resource = (FlowDefinitionResource) resources.next();
|
||||
registrar.addResource(resource, namespace);
|
||||
}
|
||||
}
|
||||
registrar.registerFlowDefinitions(registry);
|
||||
}
|
||||
|
||||
private FlowServiceLocator getFlowServiceLocator(FlowDefinitionRegistry registry) {
|
||||
if (flowServiceLocator == null) {
|
||||
this.flowServiceLocator = new DefaultFlowServiceLocator(registry, beanFactory);
|
||||
}
|
||||
return flowServiceLocator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.builder;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionResource;
|
||||
import org.springframework.webflow.test.MockFlowServiceLocator;
|
||||
|
||||
/**
|
||||
* Tests that the factory bean properly creates a {@link FlowDefinitionRegistry} with the proper definitions in it.
|
||||
*/
|
||||
public class FlowRegistryFactoryBeanTests extends TestCase {
|
||||
|
||||
public void testXmlRegistrar() throws Exception {
|
||||
Set emptyNamespace = new HashSet();
|
||||
emptyNamespace.add(new FlowDefinitionResource(fromClassPath("flow1.xml")));
|
||||
Set bookingNamespace = new HashSet();
|
||||
bookingNamespace.add(new FlowDefinitionResource(fromClassPath("flow2.xml")));
|
||||
Map xmlNamespaceFlowMappings = new HashMap();
|
||||
xmlNamespaceFlowMappings.put("", emptyNamespace);
|
||||
xmlNamespaceFlowMappings.put("booking", bookingNamespace);
|
||||
FlowRegistryFactoryBean factoryBean = new FlowRegistryFactoryBean();
|
||||
factoryBean.setFlowServiceLocator(new MockFlowServiceLocator());
|
||||
factoryBean.setXmlNamespaceFlowMappings(xmlNamespaceFlowMappings);
|
||||
factoryBean.afterPropertiesSet();
|
||||
FlowDefinitionRegistry registry = (FlowDefinitionRegistry) factoryBean.getObject();
|
||||
assertEquals("Incorrect number of flows", 2, registry.getFlowDefinitionCount());
|
||||
assertTrue("Missing flow", registry.containsFlowDefinition("flow1"));
|
||||
assertTrue("Missing flow", registry.containsFlowDefinition("booking/flow2"));
|
||||
}
|
||||
|
||||
private Resource fromClassPath(String resourceName) {
|
||||
return new ClassPathResource(resourceName, getClass());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,17 +22,19 @@ import org.springframework.webflow.definition.registry.FlowDefinitionHolder;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionResource;
|
||||
import org.springframework.webflow.engine.builder.FlowAssembler;
|
||||
import org.springframework.webflow.engine.builder.FlowBuilder;
|
||||
import org.springframework.webflow.engine.builder.FlowRegistryFactoryBean;
|
||||
import org.springframework.webflow.engine.builder.FlowServiceLocator;
|
||||
import org.springframework.webflow.engine.builder.RefreshableFlowDefinitionHolder;
|
||||
|
||||
/**
|
||||
* A flow definition registrar that populates a flow definition registry with flow definitions defined in externalized
|
||||
* XML resources. Typically used in conjunction with a {@link XmlFlowRegistryFactoryBean} but may also be used
|
||||
* standalone in programmatic fashion.
|
||||
* XML resources. Typically used in conjunction with a {@link FlowRegistryFactoryBean} but may also be used stand-alone
|
||||
* in programmatic fashion.
|
||||
* <p>
|
||||
* By default, a flow definition registered by this registrar 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 file "flow1.xml" will be identified as "flow1" when registered in a registry.
|
||||
* By default, a flow definition added to this registrar with the {@link #addLocation(Resource, String)} method will be
|
||||
* 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 file "flow1.xml" will be identified as
|
||||
* "flow1" when registered in a registry.
|
||||
* <p>
|
||||
* Programmatic usage example:
|
||||
*
|
||||
@@ -43,59 +45,28 @@ import org.springframework.webflow.engine.builder.RefreshableFlowDefinitionHolde
|
||||
* new DefaultFlowServiceLocator(registry, beanFactory);
|
||||
* XmlFlowRegistrar registrar = new XmlFlowRegistrar(flowServiceLocator);
|
||||
* File parent = new File("src/webapp/WEB-INF");
|
||||
* registrar.addLocation(new FileSystemResource(new File(parent, "flow1.xml"));
|
||||
* registrar.addLocation(new FileSystemResource(new File(parent, "flow2.xml"));
|
||||
* registrar.add(new FileSystemResource(new File(parent, "flow1.xml"));
|
||||
* registrar.add(new FileSystemResource(new File(parent, "flow2.xml"));
|
||||
* registrar.registerFlowDefinitions(registry);
|
||||
* </pre>
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Ben Hale
|
||||
*/
|
||||
public class XmlFlowRegistrar extends ExternalizedFlowDefinitionRegistrar {
|
||||
|
||||
/**
|
||||
* The xml file suffix constant.
|
||||
*/
|
||||
private static final String XML_SUFFIX = ".xml";
|
||||
|
||||
/**
|
||||
* The locator of services needed by flow definitions.
|
||||
*/
|
||||
private FlowServiceLocator flowServiceLocator;
|
||||
|
||||
/**
|
||||
* The loader of XML-based flow definition documents.
|
||||
*/
|
||||
private DocumentLoader documentLoader;
|
||||
|
||||
/**
|
||||
* Creates a new XML flow registrar. Protected constructor - if used, make sure the required
|
||||
* {@link #flowServiceLocator} reference is set.
|
||||
*/
|
||||
protected XmlFlowRegistrar() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new XML flow registrar.
|
||||
* @param flowServiceLocator the locator needed to support flow definition assembly
|
||||
*/
|
||||
public XmlFlowRegistrar(FlowServiceLocator flowServiceLocator) {
|
||||
setFlowServiceLocator(flowServiceLocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flow service locator.
|
||||
* @param flowServiceLocator the flow service locator (may not be null)
|
||||
*/
|
||||
protected void setFlowServiceLocator(FlowServiceLocator flowServiceLocator) {
|
||||
Assert.notNull(flowServiceLocator, "The flow service locator is required");
|
||||
this.flowServiceLocator = flowServiceLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flow service locator.
|
||||
*/
|
||||
protected FlowServiceLocator getFlowServiceLocator() {
|
||||
return flowServiceLocator;
|
||||
setFlowServiceLocator(flowServiceLocator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,16 +78,7 @@ public class XmlFlowRegistrar extends ExternalizedFlowDefinitionRegistrar {
|
||||
this.documentLoader = documentLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the loader of XML-based flow definition documents.
|
||||
*/
|
||||
public DocumentLoader getDocumentLoader() {
|
||||
return documentLoader;
|
||||
}
|
||||
|
||||
protected boolean isFlowDefinitionResource(Resource resource) {
|
||||
return resource.getFilename().endsWith(XML_SUFFIX);
|
||||
}
|
||||
// hook methods
|
||||
|
||||
protected FlowDefinitionHolder createFlowDefinitionHolder(FlowDefinitionResource resource) {
|
||||
FlowBuilder builder = createFlowBuilder(resource.getLocation());
|
||||
@@ -124,8 +86,6 @@ public class XmlFlowRegistrar extends ExternalizedFlowDefinitionRegistrar {
|
||||
return new RefreshableFlowDefinitionHolder(assembler);
|
||||
}
|
||||
|
||||
// hook methods
|
||||
|
||||
/**
|
||||
* Factory method that creates and fully initializes the XML-based flow definition builder.
|
||||
* @param location the xml-based resource
|
||||
|
||||
@@ -1,238 +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.builder.xml;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
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;
|
||||
import org.springframework.webflow.engine.builder.DefaultFlowServiceLocator;
|
||||
import org.springframework.webflow.engine.builder.FlowServiceLocator;
|
||||
|
||||
/**
|
||||
* 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, 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>
|
||||
* This class is also <code>BeanFactoryAware</code> and when used with Spring will automatically create a configured
|
||||
* {@link DefaultFlowServiceLocator} for loading Flow artifacts like Actions from the Spring bean factory during the
|
||||
* Flow registration process.
|
||||
* <p>
|
||||
* This class is also <code>ResourceLoaderAware</code>; when an instance is created by a Spring BeanFactory the
|
||||
* factory will automatically configure the XmlFlowRegistrar with a context-relative resource loader for accessing other
|
||||
* resources during Flow assembly.
|
||||
*
|
||||
* Usage example:
|
||||
*
|
||||
* <pre>
|
||||
* <bean id="flowRegistry" class="org.springframework.webflow.engine.builder.registry.XmlFlowRegistryFactoryBean">
|
||||
* <property name="flowLocations" value="/WEB-INF/flows/*-flow.xml"/>
|
||||
* </bean>
|
||||
* </pre>
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class XmlFlowRegistryFactoryBean extends AbstractFlowBuildingFlowRegistryFactoryBean {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public XmlFlowRegistrar getXmlFlowRegistrar() {
|
||||
return flowRegistrar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the configured externalized XML flow registrar.
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public void setXmlFlowRegistrar(XmlFlowRegistrar flowRegistrar) {
|
||||
Assert.notNull(flowRegistrar, "The flowRegistrar is required");
|
||||
this.flowRegistrar = flowRegistrar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the locations (resource file paths) pointing to XML-based flow definitions.
|
||||
* <p>
|
||||
* When configuring as a Spring bean definition, ANT-style resource patterns/wildcards are also supported, taking
|
||||
* advantage of Spring's built in ResourceArrayPropertyEditor machinery.
|
||||
* <p>
|
||||
* For example:
|
||||
*
|
||||
* <pre>
|
||||
* <bean id="flowRegistry" class="org.springframework.webflow.engine.builder.xml.XmlFlowRegistryFactoryBean">
|
||||
* <property name="flowLocations" value="/WEB-INF/flows/*-flow.xml"/>
|
||||
* </bean>
|
||||
* </pre>
|
||||
*
|
||||
* Another example:
|
||||
*
|
||||
* <pre>
|
||||
* <bean id="flowRegistry" class="org.springframework.webflow.engine.builder.xml.XmlFlowRegistryFactoryBean">
|
||||
* <property name="flowLocations" value="classpath*:/example/flows/*-flow.xml"/>
|
||||
* </bean>
|
||||
* </pre>
|
||||
*
|
||||
* Flows registered from this set will be automatically assigned an id based on the filename of the matched XML
|
||||
* resource.
|
||||
* @param locations the resource locations
|
||||
*/
|
||||
public void setFlowLocations(Resource[] locations) {
|
||||
this.locations = locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for setting externalized flow definitions from a <code>java.util.Properties</code> map.
|
||||
* Allows for more control over the definition, including which <code>flowId</code> is assigned.
|
||||
* <p>
|
||||
* Each property key is the <code>flowId</code> and each property value is the string encoded location of the
|
||||
* externalized flow definition resource.
|
||||
* <p>
|
||||
* Here is the exact format:
|
||||
*
|
||||
* <pre>
|
||||
* flowId = resource
|
||||
* </pre>
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* <pre>
|
||||
* <bean id="flowRegistry" class="org.springframework.webflow.engine.builder.xml.XmlFlowRegistryFactoryBean">
|
||||
* <property name="flowDefinitions">
|
||||
* <value>
|
||||
* searchFlow=/WEB-INF/flows/search-flow.xml
|
||||
* detailFlow=/WEB-INF/flows/detail-flow.xml
|
||||
* </value>
|
||||
* </property>
|
||||
* </bean>
|
||||
* </pre>
|
||||
*
|
||||
* @param flowDefinitions the flow definitions, defined within a properties map
|
||||
*/
|
||||
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
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public void setFlowAttributes(Map flowAttributes) {
|
||||
this.flowAttributes = flowAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the loader to load XML-based flow definition documents during flow definition assembly. Allows for
|
||||
* customization over how flow definition documents are loaded. Optional.
|
||||
* @param documentLoader the document loader
|
||||
*/
|
||||
public void setDocumentLoader(DocumentLoader documentLoader) {
|
||||
getXmlFlowRegistrar().setDocumentLoader(documentLoader);
|
||||
}
|
||||
|
||||
protected void init(FlowServiceLocator flowServiceLocator) {
|
||||
// simply wire in the locator to the registrar
|
||||
getXmlFlowRegistrar().setFlowServiceLocator(flowServiceLocator);
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
getXmlFlowRegistrar().addResource(
|
||||
new FlowDefinitionResource(flowId, resource, getFlowAttributes(flowId)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.webflow.executor.mvc.FlowController;
|
||||
|
||||
/**
|
||||
* Test case that illustrates configuration of a FlowController and its associated artefacts using classic spring bean
|
||||
* Test case that illustrates configuration of a FlowController and its associated artifacts using classic spring bean
|
||||
* configuration information. This test case does not really test much but serves more as an example.
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.webflow.config;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.beans.factory.parsing.Problem;
|
||||
import org.springframework.beans.factory.parsing.ProblemReporter;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
@@ -38,17 +39,12 @@ import org.springframework.webflow.executor.FlowExecutorImpl;
|
||||
|
||||
/**
|
||||
* Unit tests for the WebFlowConfigNamespaceHandler and its BeanDefinitionParsers.
|
||||
*
|
||||
* @author Ben Hale
|
||||
* @author Erwin Vervaet
|
||||
* @author Christian Dupuis
|
||||
*/
|
||||
public class WebFlowConfigNamespaceHandlerTests extends TestCase {
|
||||
|
||||
private DefaultListableBeanFactory beanFactory;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
this.beanFactory = new DefaultListableBeanFactory();
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory);
|
||||
reader.loadBeanDefinitions(new ClassPathResource(
|
||||
@@ -58,16 +54,36 @@ public class WebFlowConfigNamespaceHandlerTests extends TestCase {
|
||||
public void testRegistryWithPath() {
|
||||
FlowDefinitionRegistry registry = (FlowDefinitionRegistry) this.beanFactory.getBean("withPath");
|
||||
assertEquals("Incorrect number of flows loaded", 1, registry.getFlowDefinitionCount());
|
||||
}
|
||||
|
||||
public void testRegistryWithoutPath() {
|
||||
FlowDefinitionRegistry registry = (FlowDefinitionRegistry) this.beanFactory.getBean("withoutPath");
|
||||
assertEquals("Incorrect number of flows loaded", 0, registry.getFlowDefinitionCount());
|
||||
assertTrue("Incorrect flow name", registry.containsFlowDefinition("/flow1"));
|
||||
}
|
||||
|
||||
public void testRegistryWithPathWithWildcards() {
|
||||
FlowDefinitionRegistry registry = (FlowDefinitionRegistry) this.beanFactory.getBean("withPathWithWildcards");
|
||||
assertEquals("Incorrect number of flows loaded", 0, registry.getFlowDefinitionCount());
|
||||
assertEquals("Incorrect number of flows loaded", 3, registry.getFlowDefinitionCount());
|
||||
assertTrue("Incorrect flow name", registry.containsFlowDefinition("/flow1"));
|
||||
assertTrue("Incorrect flow name", registry.containsFlowDefinition("/flow2"));
|
||||
}
|
||||
|
||||
public void testRegistryWithId() {
|
||||
FlowDefinitionRegistry registry = (FlowDefinitionRegistry) this.beanFactory.getBean("withId");
|
||||
assertEquals("Incorrect number of flows loaded", 1, registry.getFlowDefinitionCount());
|
||||
assertTrue("Incorrect flow name", registry.containsFlowDefinition("/foo"));
|
||||
}
|
||||
|
||||
public void testWithIdWithWildCards() {
|
||||
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory);
|
||||
try {
|
||||
reader.loadBeanDefinitions(new ClassPathResource(
|
||||
"org/springframework/webflow/config/webflow-config-namespace-bad.xml"));
|
||||
fail("Should not have allowed id with wildcards");
|
||||
} catch (BeanDefinitionParsingException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testRegistryWithNamespace() {
|
||||
FlowDefinitionRegistry registry = (FlowDefinitionRegistry) this.beanFactory.getBean("withNamespace");
|
||||
assertEquals("Incorrect number of flows loaded", 1, registry.getFlowDefinitionCount());
|
||||
assertTrue("Incorrect flow name", registry.containsFlowDefinition("namespace/flow1"));
|
||||
}
|
||||
|
||||
public void testDefaultExecutor() {
|
||||
|
||||
@@ -1,14 +1,27 @@
|
||||
<?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.0.xsd">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/util
|
||||
http://www.springframework.org/schema/util/spring-util-2.0.xsd">
|
||||
|
||||
<!-- a sample flow registry -->
|
||||
|
||||
<bean id="flowRegistry" class="org.springframework.webflow.engine.builder.xml.XmlFlowRegistryFactoryBean">
|
||||
<property name="flowLocations" value="classpath:test-flow.xml"/>
|
||||
<bean id="flowRegistry" class="org.springframework.webflow.engine.builder.FlowRegistryFactoryBean">
|
||||
<property name="xmlNamespaceFlowMappings">
|
||||
<util:map key-type="java.lang.String">
|
||||
<entry key="">
|
||||
<util:set>
|
||||
<bean class="org.springframework.webflow.definition.registry.FlowDefinitionResource">
|
||||
<constructor-arg value="classpath:test-flow.xml" />
|
||||
</bean>
|
||||
</util:set>
|
||||
</entry>
|
||||
</util:map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="flowExecutor0" class="org.springframework.webflow.config.FlowExecutorFactoryBean">
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?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="start" />
|
||||
|
||||
<view-state id="start">
|
||||
</view-state>
|
||||
|
||||
</flow>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?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="start" />
|
||||
|
||||
<view-state id="start">
|
||||
</view-state>
|
||||
|
||||
</flow>
|
||||
@@ -1,104 +1,120 @@
|
||||
<?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="
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
|
||||
<!-- a sample flow registry -->
|
||||
|
||||
<bean id="flowRegistry" class="org.springframework.webflow.engine.builder.xml.XmlFlowRegistryFactoryBean">
|
||||
<property name="flowLocations" value="classpath:test-flow.xml"/>
|
||||
</bean>
|
||||
|
||||
<!-- a sample flow execution listener and corresponding loader -->
|
||||
|
||||
<bean id="flowExecutionListener" class="org.springframework.webflow.execution.MockFlowExecutionListener"/>
|
||||
|
||||
<bean id="executionListenerLoader" class="org.springframework.webflow.execution.factory.ConditionalFlowExecutionListenerLoader">
|
||||
<property name="listeners">
|
||||
<map>
|
||||
<entry key-ref="flowExecutionListener" value="*"/>
|
||||
<entry key-ref="flowExecutionListener" value="test-flow"/>
|
||||
<entry key-ref="flowExecutionListener">
|
||||
<bean class="org.springframework.webflow.config.TestFlowExecutionListenerCriteria"/>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- a sample conversation manager -->
|
||||
|
||||
<bean id="conversationManager" class="org.springframework.webflow.conversation.impl.SessionBindingConversationManager">
|
||||
<property name="maxConversations" value="5"/>
|
||||
</bean>
|
||||
|
||||
<!-- relatively simple flow controller definition using factory beans -->
|
||||
|
||||
<bean id="flowController" class="org.springframework.webflow.executor.mvc.FlowController">
|
||||
<property name="flowExecutor" ref="flowExecutor"/>
|
||||
<property name="defaultFlowId" value="test-flow"/>
|
||||
</bean>
|
||||
|
||||
<bean id="flowExecutor" class="org.springframework.webflow.config.FlowExecutorFactoryBean">
|
||||
<property name="definitionLocator" ref="flowRegistry"/>
|
||||
<property name="executionAttributes">
|
||||
<map>
|
||||
<entry key="foo" value="bar"/>
|
||||
</map>
|
||||
</property>
|
||||
<property name="executionListenerLoader" ref="executionListenerLoader"/>
|
||||
<property name="repositoryType" value="SINGLEKEY"/>
|
||||
<property name="conversationManager" ref="conversationManager"/>
|
||||
<property name="defaults">
|
||||
<bean class="org.springframework.webflow.config.FlowSystemDefaults">
|
||||
<property name="alwaysRedirectOnPause" value="true"/>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- very elaborate flow controller definition using straight low level bean definitions -->
|
||||
|
||||
<bean id="flowController-bean" class="org.springframework.webflow.executor.mvc.FlowController">
|
||||
<property name="flowExecutor" ref="flowExecutor-bean"/>
|
||||
<property name="defaultFlowId" value="test-flow"/>
|
||||
</bean>
|
||||
|
||||
<bean id="flowExecutor-bean" class="org.springframework.webflow.executor.FlowExecutorImpl">
|
||||
<constructor-arg ref="flowRegistry"/>
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.webflow.engine.impl.FlowExecutionImplFactory">
|
||||
<property name="executionAttributesMap">
|
||||
<map>
|
||||
<entry key="foo" value="bar"/>
|
||||
<entry key="alwaysRedirectOnPause">
|
||||
<value type="java.lang.Boolean">true</value>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
<property name="executionListenerLoader" ref="executionListenerLoader"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
<constructor-arg ref="executionRepository-bean"/>
|
||||
</bean>
|
||||
|
||||
<bean id="executionRepository-bean" class="org.springframework.webflow.execution.repository.support.SimpleFlowExecutionRepository">
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.webflow.engine.impl.FlowExecutionImplStateRestorer">
|
||||
<constructor-arg ref="flowRegistry"/>
|
||||
<property name="executionAttributesMap">
|
||||
<map>
|
||||
<entry key="foo" value="bar"/>
|
||||
<entry key="alwaysRedirectOnPause">
|
||||
<value type="java.lang.Boolean">true</value>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
<property name="executionListenerLoader" ref="executionListenerLoader"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
<constructor-arg ref="conversationManager"/>
|
||||
<property name="alwaysGenerateNewNextKey" value="false"/>
|
||||
</bean>
|
||||
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/util
|
||||
http://www.springframework.org/schema/util/spring-util-2.0.xsd">
|
||||
|
||||
<!-- a sample flow registry -->
|
||||
|
||||
<bean id="flowRegistry" class="org.springframework.webflow.engine.builder.FlowRegistryFactoryBean">
|
||||
<property name="xmlNamespaceFlowMappings">
|
||||
<util:map key-type="java.lang.String">
|
||||
<entry key="">
|
||||
<util:set>
|
||||
<bean class="org.springframework.webflow.definition.registry.FlowDefinitionResource">
|
||||
<constructor-arg value="classpath:test-flow.xml" />
|
||||
</bean>
|
||||
</util:set>
|
||||
</entry>
|
||||
</util:map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- a sample flow execution listener and corresponding loader -->
|
||||
|
||||
<bean id="flowExecutionListener" class="org.springframework.webflow.execution.MockFlowExecutionListener" />
|
||||
|
||||
<bean id="executionListenerLoader"
|
||||
class="org.springframework.webflow.execution.factory.ConditionalFlowExecutionListenerLoader">
|
||||
<property name="listeners">
|
||||
<map>
|
||||
<entry key-ref="flowExecutionListener" value="*" />
|
||||
<entry key-ref="flowExecutionListener" value="test-flow" />
|
||||
<entry key-ref="flowExecutionListener">
|
||||
<bean class="org.springframework.webflow.config.TestFlowExecutionListenerCriteria" />
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- a sample conversation manager -->
|
||||
|
||||
<bean id="conversationManager"
|
||||
class="org.springframework.webflow.conversation.impl.SessionBindingConversationManager">
|
||||
<property name="maxConversations" value="5" />
|
||||
</bean>
|
||||
|
||||
<!-- relatively simple flow controller definition using factory beans -->
|
||||
|
||||
<bean id="flowController" class="org.springframework.webflow.executor.mvc.FlowController">
|
||||
<property name="flowExecutor" ref="flowExecutor" />
|
||||
<property name="defaultFlowId" value="test-flow" />
|
||||
</bean>
|
||||
|
||||
<bean id="flowExecutor" class="org.springframework.webflow.config.FlowExecutorFactoryBean">
|
||||
<property name="definitionLocator" ref="flowRegistry" />
|
||||
<property name="executionAttributes">
|
||||
<map>
|
||||
<entry key="foo" value="bar" />
|
||||
</map>
|
||||
</property>
|
||||
<property name="executionListenerLoader" ref="executionListenerLoader" />
|
||||
<property name="repositoryType" value="SINGLEKEY" />
|
||||
<property name="conversationManager" ref="conversationManager" />
|
||||
<property name="defaults">
|
||||
<bean class="org.springframework.webflow.config.FlowSystemDefaults">
|
||||
<property name="alwaysRedirectOnPause" value="true" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- very elaborate flow controller definition using straight low level bean definitions -->
|
||||
|
||||
<bean id="flowController-bean" class="org.springframework.webflow.executor.mvc.FlowController">
|
||||
<property name="flowExecutor" ref="flowExecutor-bean" />
|
||||
<property name="defaultFlowId" value="test-flow" />
|
||||
</bean>
|
||||
|
||||
<bean id="flowExecutor-bean" class="org.springframework.webflow.executor.FlowExecutorImpl">
|
||||
<constructor-arg ref="flowRegistry" />
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.webflow.engine.impl.FlowExecutionImplFactory">
|
||||
<property name="executionAttributesMap">
|
||||
<map>
|
||||
<entry key="foo" value="bar" />
|
||||
<entry key="alwaysRedirectOnPause">
|
||||
<value type="java.lang.Boolean">true</value>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
<property name="executionListenerLoader" ref="executionListenerLoader" />
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
<constructor-arg ref="executionRepository-bean" />
|
||||
</bean>
|
||||
|
||||
<bean id="executionRepository-bean"
|
||||
class="org.springframework.webflow.execution.repository.support.SimpleFlowExecutionRepository">
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.webflow.engine.impl.FlowExecutionImplStateRestorer">
|
||||
<constructor-arg ref="flowRegistry" />
|
||||
<property name="executionAttributesMap">
|
||||
<map>
|
||||
<entry key="foo" value="bar" />
|
||||
<entry key="alwaysRedirectOnPause">
|
||||
<value type="java.lang.Boolean">true</value>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
<property name="executionListenerLoader" ref="executionListenerLoader" />
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
<constructor-arg ref="conversationManager" />
|
||||
<property name="alwaysGenerateNewNextKey" value="false" />
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:flow="http://www.springframework.org/schema/webflow-config"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/webflow-config
|
||||
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd">
|
||||
|
||||
<flow:registry id="withIdWithWildcards">
|
||||
<flow:location id="foo" path="classpath*:org/springframework/webflow/config/flow*.xml"/>
|
||||
</flow:registry>
|
||||
|
||||
</beans>
|
||||
@@ -6,19 +6,24 @@
|
||||
http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/webflow-config
|
||||
http://www.springframework.org/schema/webflow-config/spring-webflow-config-1.0.xsd">
|
||||
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd">
|
||||
|
||||
<flow:registry id="withPath">
|
||||
<flow:location path="classpath:org/springframework/webflow/registry/flow1.xml" />
|
||||
</flow:registry>
|
||||
|
||||
<flow:registry id="withoutPath">
|
||||
<flow:location path="" />
|
||||
<flow:location path="classpath:org/springframework/webflow/config/flow1.xml" />
|
||||
</flow:registry>
|
||||
|
||||
<flow:registry id="withPathWithWildcards">
|
||||
<flow:location path="classpath*:org/springframework/webflow/engine/builder/registry/flow*.xml" />
|
||||
<flow:location path="classpath*:org/springframework/webflow/engine/builder/registry/flows/**/flow*.xml" />
|
||||
<flow:location path="classpath*:org/springframework/webflow/config/flow*.xml" />
|
||||
</flow:registry>
|
||||
|
||||
<flow:registry id="withId">
|
||||
<flow:location id="foo" path="classpath:org/springframework/webflow/config/flow1.xml"/>
|
||||
</flow:registry>
|
||||
|
||||
<flow:registry id="withNamespace">
|
||||
<flow:namespace name="namespace">
|
||||
<flow:location path="classpath:org/springframework/webflow/config/flow1.xml"/>
|
||||
</flow:namespace>
|
||||
</flow:registry>
|
||||
|
||||
<flow:executor id="defaultExecutor" registry-ref="withPathWithWildcards"/>
|
||||
|
||||
@@ -20,13 +20,17 @@ import java.io.ObjectOutputStream;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.beans.factory.support.StaticListableBeanFactory;
|
||||
import org.springframework.webflow.config.FlowExecutorFactoryBean;
|
||||
import org.springframework.webflow.config.RepositoryType;
|
||||
import org.springframework.webflow.core.collection.SharedAttributeMap;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionHolder;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistrar;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistryImpl;
|
||||
import org.springframework.webflow.definition.registry.StaticFlowDefinitionHolder;
|
||||
import org.springframework.webflow.engine.Flow;
|
||||
import org.springframework.webflow.engine.builder.AbstractFlowBuilder;
|
||||
import org.springframework.webflow.engine.builder.AbstractFlowBuilderFlowRegistryFactoryBean;
|
||||
import org.springframework.webflow.engine.builder.FlowAssembler;
|
||||
import org.springframework.webflow.engine.builder.FlowBuilderException;
|
||||
import org.springframework.webflow.execution.support.ApplicationView;
|
||||
import org.springframework.webflow.execution.support.FlowExecutionRedirect;
|
||||
@@ -36,19 +40,16 @@ import org.springframework.webflow.test.MockExternalContext;
|
||||
|
||||
/**
|
||||
* Test case that looks for the miminum conversation size.
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public class ConversationSizeTests extends TestCase {
|
||||
|
||||
private SessionBindingConversationManager conversationManager;
|
||||
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
AbstractFlowBuilderFlowRegistryFactoryBean flowRegistryFactory = new SizeTestFlowRegistry();
|
||||
flowRegistryFactory.setBeanFactory(new StaticListableBeanFactory());
|
||||
flowRegistryFactory.afterPropertiesSet();
|
||||
FlowDefinitionRegistry flowRegistry = flowRegistryFactory.getRegistry();
|
||||
FlowDefinitionRegistry flowRegistry = new FlowDefinitionRegistryImpl();
|
||||
new SizeTestFlowRegistrar().registerFlowDefinitions(flowRegistry);
|
||||
|
||||
conversationManager = new SessionBindingConversationManager();
|
||||
|
||||
@@ -110,9 +111,6 @@ public class ConversationSizeTests extends TestCase {
|
||||
oout.writeObject(obj);
|
||||
oout.flush();
|
||||
int objSize = bout.toByteArray().length;
|
||||
|
||||
// System.out.println(">>>> serialized size of '" + obj + "' is " + objSize);
|
||||
|
||||
return objSize;
|
||||
}
|
||||
|
||||
@@ -123,9 +121,12 @@ public class ConversationSizeTests extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
private static class SizeTestFlowRegistry extends AbstractFlowBuilderFlowRegistryFactoryBean {
|
||||
protected void doPopulate(FlowDefinitionRegistry registry) {
|
||||
registerFlowDefinition(registry, "size-test-flow", new SizeTestFlowBuilder());
|
||||
private static class SizeTestFlowRegistrar implements FlowDefinitionRegistrar {
|
||||
|
||||
public void registerFlowDefinitions(FlowDefinitionRegistry registry) {
|
||||
Flow flow = new FlowAssembler("size-test-flow", null, new SizeTestFlowBuilder()).assembleFlow();
|
||||
FlowDefinitionHolder flowHolder = new StaticFlowDefinitionHolder(flow);
|
||||
registry.registerFlowDefinition(flowHolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,32 +17,32 @@ package org.springframework.webflow.engine.builder;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.beans.factory.support.StaticListableBeanFactory;
|
||||
import org.springframework.webflow.core.collection.LocalAttributeMap;
|
||||
import org.springframework.webflow.core.collection.MutableAttributeMap;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionHolder;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistrar;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistryImpl;
|
||||
import org.springframework.webflow.definition.registry.StaticFlowDefinitionHolder;
|
||||
import org.springframework.webflow.engine.Flow;
|
||||
import org.springframework.webflow.execution.ViewSelection;
|
||||
import org.springframework.webflow.execution.support.ApplicationView;
|
||||
import org.springframework.webflow.test.MockFlowServiceLocator;
|
||||
import org.springframework.webflow.test.MockRequestControlContext;
|
||||
|
||||
/**
|
||||
* Test parameterization of flow built using an AbstractFlowBuilder when registering the flows with a
|
||||
* FlowDefinitionRegistry.
|
||||
*
|
||||
* @author Erwin Vervaet
|
||||
*/
|
||||
public class AbstractFlowBuilderParameterizationTests extends TestCase {
|
||||
|
||||
private FlowDefinitionRegistry registry;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
TestFlowRegistryFactoryBean registryFactory = new TestFlowRegistryFactoryBean();
|
||||
StaticListableBeanFactory beanFactory = new StaticListableBeanFactory();
|
||||
beanFactory.addBean("testAction", new ParameterizationTestAction());
|
||||
registryFactory.setBeanFactory(beanFactory);
|
||||
registryFactory.afterPropertiesSet();
|
||||
registry = registryFactory.getRegistry();
|
||||
registry = new FlowDefinitionRegistryImpl();
|
||||
MockFlowServiceLocator flowServiceLocator = new MockFlowServiceLocator();
|
||||
flowServiceLocator.registerBean("testAction", new ParameterizationTestAction());
|
||||
new TestFlowRegistrar(flowServiceLocator).registerFlowDefinitions(registry);
|
||||
}
|
||||
|
||||
public void testFlowParameterization() {
|
||||
@@ -74,24 +74,40 @@ public class AbstractFlowBuilderParameterizationTests extends TestCase {
|
||||
|
||||
public class TestFlowBuilder extends AbstractFlowBuilder {
|
||||
|
||||
public TestFlowBuilder(FlowServiceLocator flowServiceLocator) {
|
||||
setFlowServiceLocator(flowServiceLocator);
|
||||
}
|
||||
|
||||
public void buildStates() throws FlowBuilderException {
|
||||
addActionState("test", action("testAction"), transition(on(success()), to("finish")));
|
||||
addEndState("finish", "${activeFlow.attributes['name']}");
|
||||
}
|
||||
}
|
||||
|
||||
public class TestFlowRegistryFactoryBean extends AbstractFlowBuilderFlowRegistryFactoryBean {
|
||||
private class TestFlowRegistrar implements FlowDefinitionRegistrar {
|
||||
|
||||
protected void doPopulate(FlowDefinitionRegistry registry) {
|
||||
MutableAttributeMap attributes = new LocalAttributeMap();
|
||||
attributes.put("name", "A");
|
||||
attributes.put("someKey", "someValue");
|
||||
registerFlowDefinition(registry, "flowA", attributes, new TestFlowBuilder());
|
||||
private FlowServiceLocator flowServiceLocator;
|
||||
|
||||
attributes = new LocalAttributeMap();
|
||||
attributes.put("name", "B");
|
||||
attributes.put("someOtherKey", "someOtherValue");
|
||||
registerFlowDefinition(registry, "flowB", attributes, new TestFlowBuilder());
|
||||
public TestFlowRegistrar(FlowServiceLocator flowServiceLocator) {
|
||||
this.flowServiceLocator = flowServiceLocator;
|
||||
}
|
||||
|
||||
public void registerFlowDefinitions(FlowDefinitionRegistry registry) {
|
||||
MutableAttributeMap attributesA = new LocalAttributeMap();
|
||||
attributesA.put("name", "A");
|
||||
attributesA.put("someKey", "someValue");
|
||||
Flow flowA = new FlowAssembler("flowA", attributesA, new TestFlowBuilder(flowServiceLocator))
|
||||
.assembleFlow();
|
||||
FlowDefinitionHolder flowHolderA = new StaticFlowDefinitionHolder(flowA);
|
||||
registry.registerFlowDefinition(flowHolderA);
|
||||
|
||||
MutableAttributeMap attributesB = new LocalAttributeMap();
|
||||
attributesB.put("name", "B");
|
||||
attributesB.put("someOtherKey", "someOtherValue");
|
||||
Flow flowB = new FlowAssembler("flowB", attributesB, new TestFlowBuilder(flowServiceLocator))
|
||||
.assembleFlow();
|
||||
FlowDefinitionHolder flowHolderB = new StaticFlowDefinitionHolder(flowB);
|
||||
registry.registerFlowDefinition(flowHolderB);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,14 @@ package org.springframework.webflow.engine.builder.xml;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistryImpl;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionResource;
|
||||
import org.springframework.webflow.engine.builder.BaseFlowServiceLocator;
|
||||
|
||||
public class XmlFlowRegistrarTests extends TestCase {
|
||||
|
||||
private XmlFlowRegistrar registrar;
|
||||
|
||||
private FlowDefinitionRegistry registry = new FlowDefinitionRegistryImpl();
|
||||
@@ -33,19 +35,41 @@ public class XmlFlowRegistrarTests extends TestCase {
|
||||
registrar = new XmlFlowRegistrar(locator);
|
||||
}
|
||||
|
||||
public void testAddLocation() {
|
||||
assertEquals(0, registry.getFlowDefinitionCount());
|
||||
registrar.addLocation(new ClassPathResource("flow.xml", getClass()));
|
||||
registrar.registerFlowDefinitions(registry);
|
||||
assertEquals(1, registry.getFlowDefinitionCount());
|
||||
assertEquals("flow", registry.getFlowDefinition("flow").getId());
|
||||
}
|
||||
|
||||
public void testAddResource() {
|
||||
assertEquals(0, registry.getFlowDefinitionCount());
|
||||
registrar.addResource(new FlowDefinitionResource("foo", new ClassPathResource("flow.xml", getClass())));
|
||||
registrar.addResource(new FlowDefinitionResource("foo", fromClassPath("flow.xml")), "namespace");
|
||||
registrar.registerFlowDefinitions(registry);
|
||||
assertEquals(1, registry.getFlowDefinitionCount());
|
||||
assertEquals("foo", registry.getFlowDefinition("foo").getId());
|
||||
assertEquals("foo", registry.getFlowDefinition("namespace/foo").getId());
|
||||
}
|
||||
|
||||
public void testAddResourceDefaultNamespace() {
|
||||
assertEquals(0, registry.getFlowDefinitionCount());
|
||||
registrar.setDefaultNamespace("default");
|
||||
registrar.addResource(new FlowDefinitionResource("foo", fromClassPath("flow.xml")));
|
||||
registrar.registerFlowDefinitions(registry);
|
||||
assertEquals(1, registry.getFlowDefinitionCount());
|
||||
assertEquals("foo", registry.getFlowDefinition("default/foo").getId());
|
||||
}
|
||||
|
||||
public void testAddLocation() {
|
||||
assertEquals(0, registry.getFlowDefinitionCount());
|
||||
registrar.addLocation(fromClassPath("flow.xml"), "namespace");
|
||||
registrar.registerFlowDefinitions(registry);
|
||||
assertEquals(1, registry.getFlowDefinitionCount());
|
||||
assertEquals("flow", registry.getFlowDefinition("namespace/flow").getId());
|
||||
}
|
||||
|
||||
public void testAddLocationDefaultNamespace() {
|
||||
assertEquals(0, registry.getFlowDefinitionCount());
|
||||
registrar.setDefaultNamespace("default");
|
||||
registrar.addLocation(fromClassPath("flow.xml"));
|
||||
registrar.registerFlowDefinitions(registry);
|
||||
assertEquals(1, registry.getFlowDefinitionCount());
|
||||
assertEquals("flow", registry.getFlowDefinition("default/flow").getId());
|
||||
}
|
||||
|
||||
private Resource fromClassPath(String resourceName) {
|
||||
return new ClassPathResource(resourceName, getClass());
|
||||
}
|
||||
}
|
||||
@@ -1,89 +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.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());
|
||||
}
|
||||
}
|
||||
@@ -1,49 +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.builder.xml;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.beans.factory.support.StaticListableBeanFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
|
||||
|
||||
public class XmlFlowRegistryFactoryBeanTests extends TestCase {
|
||||
private XmlFlowRegistryFactoryBean factoryBean = new XmlFlowRegistryFactoryBean();
|
||||
|
||||
public void testCreateFromLocations() throws Exception {
|
||||
ClassPathResource[] locations = new ClassPathResource[] { new ClassPathResource("flow.xml", getClass()) };
|
||||
factoryBean.setFlowLocations(locations);
|
||||
factoryBean.setBeanFactory(new StaticListableBeanFactory());
|
||||
factoryBean.afterPropertiesSet();
|
||||
FlowDefinitionRegistry registry = (FlowDefinitionRegistry) factoryBean.getObject();
|
||||
assertEquals(1, registry.getFlowDefinitionCount());
|
||||
assertEquals("flow", registry.getFlowDefinition("flow").getId());
|
||||
}
|
||||
|
||||
public void testCreateFromDefinitions() throws Exception {
|
||||
Properties properties = new Properties();
|
||||
properties.put("foo", "classpath:/org/springframework/webflow/engine/builder/xml/flow.xml");
|
||||
factoryBean.setFlowDefinitions(properties);
|
||||
factoryBean.setBeanFactory(new StaticListableBeanFactory());
|
||||
factoryBean.afterPropertiesSet();
|
||||
FlowDefinitionRegistry registry = (FlowDefinitionRegistry) factoryBean.getObject();
|
||||
assertEquals(1, registry.getFlowDefinitionCount());
|
||||
assertEquals("foo", registry.getFlowDefinition("foo").getId());
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?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>
|
||||
@@ -1,27 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:flow="http://www.springframework.org/schema/webflow-config"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/webflow-config
|
||||
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd">
|
||||
|
||||
<bean id="executor" class="org.springframework.webflow.executor.FlowExecutorImpl">
|
||||
<bean id="executor"
|
||||
class="org.springframework.webflow.executor.FlowExecutorImpl">
|
||||
<constructor-arg ref="registry" />
|
||||
<constructor-arg ref="factory" />
|
||||
<constructor-arg ref="repository" />
|
||||
</bean>
|
||||
|
||||
<bean id="factory" class="org.springframework.webflow.engine.impl.FlowExecutionImplFactory" />
|
||||
<bean id="factory"
|
||||
class="org.springframework.webflow.engine.impl.FlowExecutionImplFactory" />
|
||||
|
||||
<bean id="stateRestorer" class="org.springframework.webflow.engine.impl.FlowExecutionImplStateRestorer">
|
||||
<bean id="stateRestorer"
|
||||
class="org.springframework.webflow.engine.impl.FlowExecutionImplStateRestorer">
|
||||
<constructor-arg>
|
||||
<ref bean="registry" />
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="registry" class="org.springframework.webflow.engine.builder.xml.XmlFlowRegistryFactoryBean">
|
||||
<property name="flowLocations" value="classpath:org/springframework/webflow/executor/flow.xml" />
|
||||
</bean>
|
||||
<flow:registry id="registry">
|
||||
<flow:location
|
||||
path="classpath:org/springframework/webflow/executor/flow.xml" />
|
||||
</flow:registry>
|
||||
|
||||
<bean id="conversationManager" class="org.springframework.webflow.conversation.impl.SessionBindingConversationManager"/>
|
||||
<bean id="conversationManager"
|
||||
class="org.springframework.webflow.conversation.impl.SessionBindingConversationManager" />
|
||||
|
||||
</beans>
|
||||
Reference in New Issue
Block a user