Files
spring-webflow/src/reference/system-setup.xml
2014-03-31 15:03:11 -04:00

517 lines
19 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<chapter xml:id="system-setup"
xmlns="http://docbook.org/ns/docbook" version="5.0"
xmlns:xl="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://docbook.org/ns/docbook http://www.docbook.org/xml/5.0/xsd/docbook.xsd
http://www.w3.org/1999/xlink http://www.docbook.org/xml/5.0/xsd/xlink.xsd">
<title>System Setup</title>
<sect1 xml:id="system-setup-introduction">
<title>Introduction</title>
<para>
This chapter shows you how to setup the Web Flow system for use in any web environment.
</para>
</sect1>
<sect1 xml:id="system-config-options">
<title>Java Config and XML Namespace</title>
<para>
Web Flow provides dedicated configuration support for both Java and
XML-based configuration.
</para>
<para>
To get started with XML based configuration declare the webflow config XML namespace:
</para>
<programlisting language="xml"><![CDATA[
<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
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/webflow-config
http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.4.xsd">
<!-- Setup Web Flow here -->
</beans>]]>
</programlisting>
<para>
To get started with Java configuration extend
<classname>AbstractFlowConfiguration</classname> in an
<classname>@Configuration</classname> class:
</para>
<programlisting language="java"><![CDATA[
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
}]]>
</programlisting>
</sect1>
<sect1 xml:id="system-config-basic">
<title>Basic system configuration</title>
<para>
The next section shows the minimal configuration required to set up the Web Flow system in your application.
</para>
<sect2 xml:id="basic-setup-flow-registry">
<title>FlowRegistry</title>
<para>
Register your flows in a <code>FlowRegistry</code> in XML:
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-registry id="flowRegistry">
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />
</webflow:flow-registry>]]>
</programlisting>
<para>
Register your flows in a <code>FlowRegistry</code> in Java:
</para>
<programlisting language="java"><![CDATA[
@Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder()
.addFlowLocation("/WEB-INF/flows/booking/booking.xml")
.build();
}]]>
</programlisting>
</sect2>
<sect2 xml:id="basic-setup-flow-executor">
<title>FlowExecutor</title>
<para>
Deploy a FlowExecutor, the central service for executing flows in XML:
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-executor id="flowExecutor" />]]>
</programlisting>
<para>
Deploy a FlowExecutor, the central service for executing flows in Java:
</para>
<programlisting language="java"><![CDATA[
@Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry()).build();
}]]>
</programlisting>
<para>
See the Spring MVC and Spring Faces sections of this guide on how to integrate the Web Flow system with the MVC and JSF environment, respectively.
</para>
</sect2>
</sect1>
<sect1 xml:id="flow-registry">
<title>flow-registry options</title>
<para>
This section explores flow-registry configuration options.
</para>
<sect2 xml:id="flow-registry-location">
<title>Specifying flow locations</title>
<para>
Use the <code>location</code> element to specify paths to flow definitions to register.
By default, flows will be assigned registry identifiers equal to their filenames minus
the file extension, unless a registry bath path is defined.
</para>
<para>
In XML:
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" />]]>
</programlisting>
<para>
In Java:
</para>
<programlisting language="java"><![CDATA[
return getFlowDefinitionRegistryBuilder()
.addFlowLocation("/WEB-INF/flows/booking/booking.xml")
.build();]]>
</programlisting>
</sect2>
<sect2 xml:id="flow-registry-location-id">
<title>Assigning custom flow identifiers</title>
<para>
Specify an id to assign a custom registry identifier to a flow in XML:
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-location path="/WEB-INF/flows/booking/booking.xml" id="bookHotel" />]]>
</programlisting>
<para>
Specify an id to assign a custom registry identifier to a flow in Java:
</para>
<programlisting language="java"><![CDATA[
return getFlowDefinitionRegistryBuilder()
.addFlowLocation("/WEB-INF/flows/booking/booking.xml", "bookHotel")
.build();]]>
</programlisting>
</sect2>
<sect2 xml:id="flow-registry-location-attributes">
<title>Assigning flow meta-attributes</title>
<para>
Use the <code>flow-definition-attributes</code> element to assign custom meta-attributes to a registered flow.
</para>
<para>
In XML:
</para>
<programlisting language="xml"><![CDATA[
<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>]]>
</programlisting>
<para>
In Java:
</para>
<programlisting language="java"><![CDATA[
Map<String, Object> attrs = ... ;
return getFlowDefinitionRegistryBuilder()
.addFlowLocation("/WEB-INF/flows/booking/booking.xml", null, attrs)
.build();]]>
</programlisting>
</sect2>
<sect2 xml:id="flow-registry-patterns">
<title>Registering flows using a location pattern</title>
<para>
Use the <code>flow-location-patterns</code> element to register flows that match a specific resource location pattern:
</para>
<para>
In XML:
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-location-pattern value="/WEB-INF/flows/**/*-flow.xml" />]]>
</programlisting>
<para>
In Java:
</para>
<programlisting language="java"><![CDATA[
return getFlowDefinitionRegistryBuilder()
.addFlowLocationPattern("/WEB-INF/flows/**/*-flow.xml")
.build();]]>
</programlisting>
</sect2>
<sect2 xml:id="flow-registry-base-path">
<title>Flow location base path</title>
<para>
Use the <code>base-path</code> 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 like 'classpath:org/springframework/webflow/samples'.
</para>
<para>
In XML:
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-registry id="flowRegistry" base-path="/WEB-INF">
<webflow:flow-location path="/hotels/booking/booking.xml" />
</webflow:flow-registry>]]>
</programlisting>
<para>
In Java:
</para>
<programlisting language="java"><![CDATA[
return getFlowDefinitionRegistryBuilder()
.setBasePath("/WEB-INF")
.addFlowLocationPattern("/hotels/booking/booking.xml")
.build();]]>
</programlisting>
<para>
With a base path defined, the algorithm that assigns flow identifiers changes slightly.
Flows will now be assigned registry identifiers equal to the the path segment between their base path and 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.
</para>
<tip>
<title>Directory per flow definition</title>
<para>
Recall it is a best practice to package each flow definition in a unique directory.
This improves modularity, allowing dependent resources to be packaged with the flow definition.
It also prevents two flows from having the same identifiers when using the convention.
</para>
</tip>
<para>
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'.
</para>
<para>
Location patterns are particularly powerful when combined with a registry base path.
Instead of the flow identifiers becoming '*-flow', they will be based on the directory path.
For example in XML:
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-registry id="flowRegistry" base-path="/WEB-INF">
<webflow:flow-location-pattern value="/**/*-flow.xml" />
</webflow:flow-registry>]]>
</programlisting>
<para>
In Java:
</para>
<programlisting language="java"><![CDATA[
return getFlowDefinitionRegistryBuilder()
.setBasePath("/WEB-INF")
.addFlowLocationPattern("/**/*-flow.xml")
.build();]]>
</programlisting>
<para>
In the above example, suppose you had flows located in <code>/user/login</code>, <code>/user/registration</code>, <code>/hotels/booking</code>, and <code>/flights/booking</code> directories within <code>WEB-INF</code>,
you'd end up with flow ids of <code>user/login</code>, <code>user/registration</code>, <code>hotels/booking</code>, and <code>flights/booking</code>, respectively.
</para>
</sect2>
<sect2 xml:id="flow-registry-parent">
<title>Configuring FlowRegistry hierarchies</title>
<para>
Use the <code>parent</code> attribute to link two flow registries together in a hierarchy.
When the child registry is queried, if it cannot find the requested flow it will delegate to its parent.
</para>
<para>
In XML:
</para>
<programlisting language="xml"><![CDATA[
<!-- 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>]]>
</programlisting>
<para>
In Java:
</para>
<programlisting language="java"><![CDATA[
@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();
}
}]]>
</programlisting>
</sect2>
<sect2 xml:id="flow-registry-builder-services">
<title>Configuring custom FlowBuilder services</title>
<para>
Use the <code>flow-builder-services</code> attribute to customize the services and settings used to build flows in a flow-registry.
If no flow-builder-services tag is specified, the default service implementations are used.
When the tag is defined, you only need to reference the services you want to customize.
</para>
<para>In XML:</para>
<programlisting language="xml"><![CDATA[
<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" />]]>
</programlisting>
<para>In Java:</para>
<programlisting language="java"><![CDATA[
@Bean
public FlowDefinitionRegistry flowRegistry() {
return getFlowDefinitionRegistryBuilder(flowBuilderServices())
.addFlowLocation("/WEB-INF/flows/booking/booking.xml")
.build();
}
@Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder().build();
}]]>
</programlisting>
<para>
The configurable services are the <code>conversion-service</code>, <code>expression-parser</code>, and <code>view-factory-creator</code>.
These services are configured by referencing custom beans you define.
</para>
<para>
For example in XML:
</para>
<programlisting language="xml"><![CDATA[
<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="..." />]]>
</programlisting>
<para>In Java:</para>
<programlisting language="java"><![CDATA[
@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() {
// ...
}]]>
</programlisting>
<sect3 xml:id="builder-service-conversion">
<title>conversion-service</title>
<para>
Use the <code>conversion-service</code> attribute to customize the <code>ConversionService</code> 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'll probably need to provide your own type conversion and formatting logic for custom data types.
Please read <xref linkend="view-type-conversion"/> for important information on how to provide custom type conversion logic.
</para>
</sect3>
<sect3 xml:id="builder-service-expression-parser">
<title>expression-parser</title>
<para>
Use the <code>expression-parser</code> attribute to customize the <code>ExpressionParser</code> used by the Web Flow system.
The default ExpressionParser uses the Unified EL if available on the classpath, otherwise OGNL is used.
</para>
</sect3>
<sect3 xml:id="builder-service-view-factory-creator">
<title>view-factory-creator</title>
<para>
Use the <code>view-factory-creator</code> attribute to customize the <code>ViewFactoryCreator</code> used by the Web Flow system.
The default ViewFactoryCreator produces Spring MVC ViewFactories capable of rendering JSP, Velocity, and Freemarker views.
</para>
<para>
The configurable settings are <code>development</code>.
These settings are global configuration attributes that can be applied during the flow construction process.
</para>
</sect3>
<sect3 xml:id="builder-development">
<title>development</title>
<para>
Set this to <code>true</code> to switch on flow <emphasis>development mode</emphasis>.
Development mode switches on hot-reloading of flow definition changes, including changes to dependent flow resources such as message bundles.
</para>
</sect3>
</sect2>
</sect1>
<sect1 xml:id="flow-executor">
<title>flow-executor options</title>
<para>
This section explores flow-executor configuration options.
</para>
<sect2 xml:id="flow-executor-execution-listeners">
<title>Attaching flow execution listeners</title>
<para>
Use the <code>flow-execution-listeners</code> element to register listeners that observe the lifecycle
of flow executions. For example in XML:
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-execution-listeners>
<webflow:listener ref="securityListener"/>
<webflow:listener ref="persistenceListener"/>
</webflow:flow-execution-listeners>]]>
</programlisting>
<para>
In Java:
</para>
<programlisting language="java"><![CDATA[
@Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry())
.addFlowExecutionListener(securityListener())
.addFlowExecutionListener(persistenceListener())
.build();
}]]>
</programlisting>
<para>
You may also configure a listener to observe only certain flows. For example in XML:
</para>
<programlisting language="xml"><![CDATA[
<webflow:listener ref="securityListener" criteria="securedFlow1,securedFlow2"/>]]>
</programlisting>
<para>
In Java:
</para>
<programlisting language="java"><![CDATA[
@Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry())
.addFlowExecutionListener(securityListener(), "securedFlow1,securedFlow2")
.build();
}]]>
</programlisting>
</sect2>
<sect2 xml:id="tuning-flow-execution-repository">
<title>Tuning FlowExecution persistence</title>
<para>
Use the <code>flow-execution-repository</code> element to tune flow execution persistence settings.
For example in XML:
</para>
<programlisting language="xml"><![CDATA[
<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
<webflow:flow-execution-repository max-executions="5" max-execution-snapshots="30" />
</webflow:flow-executor>]]>
</programlisting>
<para>
In Java:
</para>
<programlisting language="java"><![CDATA[
@Bean
public FlowExecutor flowExecutor() {
return getFlowExecutorBuilder(flowRegistry())
.setMaxFlowExecutions(5)
.setMaxFlowExecutionSnapshots(30)
.build();
}]]>
</programlisting>
<sect3 xml:id="repository-max-executions">
<title>max-executions</title>
<para>
Tune the <code>max-executions</code> attribute 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.
<note>
<para>
The <code>max-executions</code> attribute is per user session, i.e. it works across instances of any flow definition.
</para>
</note>
</para>
</sect3>
<sect3 xml:id="repository-max-snapshots">
<title>max-execution-snapshots</title>
<para>
Tune the <code>max-execution-snapshots</code> 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.
<note>
<para>
History snapshots enable browser back button support.
When snapshotting is disabled pressing the browser back button will not work.
It will result in using an execution key that points to a snapshot that has not be recorded.
</para>
</note>
</para>
</sect3>
</sect2>
</sect1>
</chapter>