18. System Setup
This chapter shows you how to set up the Web Flow system for use in any web environment.
18.1. Java Configuration and the XML Namespace
Web Flow provides dedicated configuration support for both Java- and XML-based configuration.
To get started with XML based configuration, declare the webflow
config XML namespace, as follows:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/webflow-config
https://www.springframework.org/schema/webflow-config/spring-webflow-config.xsd">
<!-- Setup Web Flow here -->
</beans>
To get started with Java configuration extend AbstractFlowConfiguration
in an @Configuration
class, as follows:
@Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
}
18.2. Basic System Configuration
The next two sections show the minimal configuration required to set up the Web Flow system in your application:
18.2.1. Registering a FlowRegistry
You can register your flows in a FlowRegistry
in XML, as follows:
<webflow:flow-registry id="flowRegistry">
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />
</webflow:flow-registry>
You can register your flows in a FlowRegistry
in Java, as follows:
@Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder()
.addFlowLocation("/WEB-INF/flows/booking/booking.xml")
.build();
}
18.2.2. Deploying a FlowExecutor
You can deploy a FlowExecutor
, the central service for executing flows in XML, as follows:
<webflow:flow-executor id="flowExecutor" />
You can deploy a FlowExecutor
, the central service for executing flows in Java:
@Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry()).build();
}
See the Spring MVC Integration and JSF Integration sections of this guide on how to integrate the Web Flow system with the MVC and JSF environment, respectively.
18.3. flow-registry
options
This section explores flow-registry configuration options.
18.3.1. Specifying Flow Locations
You can use the location
element to specify paths to flow definitions that you want to register.
By default, flows are assigned registry identifiers equal to their filenames minus the file extension, unless a registry base path is defined (see Flow Location Base Path).
The following example specifies a flow location in XML:
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />
The following example specifies a flow location in Java:
return getFlowDefinitionRegistryBuilder()
.addFlowLocation("/WEB-INF/flows/booking/booking.xml")
.build();
18.3.2. Assigning Custom Flow Identifiers
You can specify an ID to assign a custom registry identifier to a flow.
The following example shows how to assign custom flow identifiers in XML:
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" id="bookHotel" />
The following example shows how to assign custom flow identifiers in Java:
return getFlowDefinitionRegistryBuilder()
.addFlowLocation("/WEB-INF/flows/booking/booking.xml", "bookHotel")
.build();
18.3.3. Assigning Flow Meta-attributes
You can use the flow-definition-attributes
element to assign custom meta-attributes to a registered flow.
The following example shows how to assign flow meta-attributes in XML:
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml">
<webflow:flow-definition-attributes>
<webflow:attribute name="caption" value="Books a hotel" />
</webflow:flow-definition-attributes>
</webflow:flow-location>
The following example shows how to assign flow meta-attributes in Java:
Map<String, Object> attrs = ... ;
return getFlowDefinitionRegistryBuilder()
.addFlowLocation("/WEB-INF/flows/booking/booking.xml", null, attrs)
.build();
18.3.4. Registering Flows by Using a Location Pattern
You can use the flow-location-patterns
element to register flows that match a specific resource location pattern.
The following example shows how to register a flow in XML:
<webflow:flow-location-pattern value="/WEB-INF/flows/**/*-flow.xml" />
The following example shows how to register a flow in Java:
return getFlowDefinitionRegistryBuilder()
.addFlowLocationPattern("/WEB-INF/flows...
.build();
18.3.5. Flow Location Base Path
You can use the base-path
attribute to define a base location for all flows in the application.
All flow locations are then relative to the base path.
The base path can be a resource path (such as /WEB-INF
) or a location on the classpath (such as classpath:org/springframework/webflow/samples
).
The following example shows how to set the base path in XML:
<webflow:flow-registry id="flowRegistry" base-path="/WEB-INF">
<webflow:flow-location path="/hotels/booking/booking.xml" />
</webflow:flow-registry>
The following example shows how to set the base path in Java:
return getFlowDefinitionRegistryBuilder()
.setBasePath("/WEB-INF")
.addFlowLocationPattern("/hotels/booking/booking.xml")
.build();
With a base path defined, the algorithm that assigns flow identifiers changes slightly.
Flows are now assigned registry identifiers equal to the the path segment between their base path and their file name.
For example, if a flow definition is located at /WEB-INF/hotels/booking/booking-flow.xml
and the base path is /WEB-INF
, the remaining path to this flow is hotels/booking
, which becomes the flow ID.
A directory for each flow definition
It is a best practice to package each flow definition in a unique directory.
This improves modularity, letting dependent resources be packaged with the flow definition.
It also prevents two flows from having the same identifiers when using the convention.
|
If no base path is not specified or if the flow definition is directly on the base path, flow ID assignment from the filename (minus the extension) is used.
For example, if a flow definition file is booking.xml
, the flow identifier is simply booking
.
Location patterns are particularly powerful when combined with a registry base path.
Instead of the flow identifiers becoming *-flow
, they are based on the directory path.
The following example combines a base path with a flow location pattern in XML:
<webflow:flow-registry id="flowRegistry" base-path="/WEB-INF">
<webflow:flow-location-pattern value="/**/*-flow.xml" />
</webflow:flow-registry>
The following example combines a base path with a flow location pattern in Java:
return getFlowDefinitionRegistryBuilder()
.setBasePath("/WEB-INF")
.addFlowLocationPattern("...
.build();
In the preceding example, suppose you had flows located in the /user/login
, /user/registration
, /hotels/booking
, and /flights/booking
directories within WEB-INF
.
You would end up with flow IDs of user/login
, user/registration
, hotels/booking
, and flights/booking
, respectively.
18.3.6. Configuring FlowRegistry
Hierarchies
You can use the parent
attribute to link two flow registries together in a hierarchy.
When the child registry is queried, if it cannot find the requested flow, it delegates to its parent.
The following example establishes a parent relationship for two flow registries in XML:
<!-- my-system-config.xml -->
<webflow:flow-registry id="flowRegistry" parent="sharedFlowRegistry">
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />
</webflow:flow-registry>
<!-- shared-config.xml -->
<webflow:flow-registry id="sharedFlowRegistry">
<!-- Global flows shared by several applications -->
</webflow:flow-registry>
The following example establishes a parent relationship for two flow registries in Java:
@Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
@Autowired
private SharedConfig sharedConfig;
@Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder()
.setParent(this.sharedConfig.sharedFlowRegistry())
.addFlowLocation("/WEB-INF/flows/booking/booking.xml")
.build();
}
}
@Configuration
public class SharedConfig extends AbstractFlowConfiguration {
@Bean
public FlowDefinitionRegistry sharedFlowRegistry() {
return getFlowDefinitionRegistryBuilder()
.addFlowLocation("/WEB-INF/flows/shared.xml")
.build();
}
}
18.3.7. Configuring Custom FlowBuilder
Services
You can use the flow-builder-services
attribute (in XML) or the FlowBuilderServices
object (in Java) to customize the services and settings used to build flows in a flow-registry.
If no flow-builder-services
element is specified, the default service implementations are used.
When the element is specified, you need only reference the services you want to customize.
The following example shows how to create a custom flow builder service in XML:
<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />
</webflow:flow-registry>
<webflow:flow-builder-services id="flowBuilderServices" />
The following example shows how to create a custom flow builder service in Java:
@Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder(flowBuilderServices())
.addFlowLocation("/WEB-INF/flows/booking/booking.xml")
.build();
}
@Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder().build();
}
The configurable services are the conversion-service
, expression-parser
, and view-factory-creator
elements (in XML) and the ConversionService
, ExpressionParser
, and ViewFactoryCreator
interfaces (in Java).
These services are configured by referencing custom beans that you must define.
The following example shows how to define the configurable services in XML:
<webflow:flow-builder-services id="flowBuilderServices"
conversion-service="conversionService"
expression-parser="expressionParser"
view-factory-creator="viewFactoryCreator" />
<bean id="conversionService" class="..." />
<bean id="expressionParser" class="..." />
<bean id="viewFactoryCreator" class="..." />
The following example shows how to define the configurable services in Java:
@Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setConversionService(conversionService())
.setExpressionParser(expressionParser)
.setViewFactoryCreator(mvcViewFactoryCreator())
.build();
}
@Bean
public ConversionService conversionService() {
// ...
}
@Bean
public ExpressionParser expressionParser() {
// ...
}
@Bean
public ViewFactoryCreator viewFactoryCreator() {
// ...
}
Using the Conversion Service
You can use the conversion-service
attribute (in XML) or the ConversionService
interface (in Java) to customize the ConversionService
used by the Web Flow system.
Type conversion is used to convert from one type to another when required during flow execution, such as when processing request parameters, invoking actions, and so on.
Many common object types (such as numbers, classes, and enums) are supported.
However, you probably need to provide your own type conversion and formatting logic for custom data types.
See Performing Type Conversion for important information on how to provide custom type conversion logic.
Using the Expression Parser
You can use the expression-parser
attribute (in XML) or the ExpressionParser
interface (in Java) to customize the ExpressionParser
used by the Web Flow system.
The default ExpressionParser
uses the Unified Expression Language if available on the classpath.
Otherwise, it uses the Spring Expression Language.
Using the View Factory Creator
You can use the view-factory-creator
attribute (in XML) or the ViewFactoryCreator
interface (in Java) to customize the ViewFactoryCreator
used by the Web Flow system.
The default ViewFactoryCreator
produces Spring MVC view factories capable of rendering JSP, Velocity, and Freemarker views.
The configurable settings are development
.
These settings are global configuration attributes that you can apply during the flow construction process.
Enabling Development Mode
When you create a flow builder services object, you can turn on development mode. Development mode switches on hot-reloading of flow definition changes, including changes to dependent flow resources such as message bundles.
To turn on development mode in XML, set the development
attribute on the flow-builder-services
element to true
.
To turn on development mode in Java, use setDevelopment(true)
on the FlowBuilderServices
object.
18.4. Setting Flow Executor options
This section explores Flow Executor configuration options.
18.4.1. Attaching Flow Execution Listeners
You can use the flow-execution-listeners
element (in XML) or the addFlowExecutionListener
method (in Java) to register listeners that observe the lifecycle of flow executions.
The following example shows how to create flow execution listeners in XML:
<webflow:flow-execution-listeners>
<webflow:listener ref="securityListener"/>
<webflow:listener ref="persistenceListener"/>
</webflow:flow-execution-listeners>
The folloiwng example shows how to create flow execution listeners in Java:
@Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry())
.addFlowExecutionListener(securityListener())
.addFlowExecutionListener(persistenceListener())
.build();
}
You can also configure a listener to observe only certain flows.
The following example shows how to configure a listener to monitor only two flows in XML:
<webflow:listener ref="securityListener" criteria="securedFlow1,securedFlow2"/>
The following example shows how to configure a listener to monitor only two flows in Java:
@Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry())
.addFlowExecutionListener(securityListener(), "securedFlow1,securedFlow2")
.build();
}
18.4.2. Tuning Flow Execution Persistence
You can use the flow-execution-repository
element (in XML) or the FlowExecutor
interface (in Java) to tune flow execution persistence settings.
The following example tunes flow execution in XML:
<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
<webflow:flow-execution-repository max-executions="5" max-execution-snapshots="30" />
</webflow:flow-executor>
The following example tunes flow execution in Java:
@Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry())
.setMaxFlowExecutions(5)
.setMaxFlowExecutionSnapshots(30)
.build();
}
Tuning max-executions
You can tune the max-executions
attribute (in XML) to place a cap on the number of flow executions that can be created per user session.
When the maximum number of executions is exceeded, the oldest execution is removed.
The max-executions attribute is per user session.
That is, it works across instances of any flow definition.
|
Tuning max-execution-snapshots
You can tune the max-execution-snapshots
attribute to place a cap on the number of history snapshots that can be taken per flow execution.
To disable snapshotting, set this value to 0.
To enable an unlimited number of snapshots, set this value to -1.
History snapshots enable browser back button support. When snapshotting is disabled, pressing the browser back button does not work. Doing so results in using an execution key that points to a snapshot that has not been recorded. |