diff --git a/spring-webflow/docs/reference/src/index.xml b/spring-webflow/docs/reference/src/index.xml
index c5ddc11a..7e68655e 100644
--- a/spring-webflow/docs/reference/src/index.xml
+++ b/spring-webflow/docs/reference/src/index.xml
@@ -26,6 +26,10 @@
ErwinVervaet
+
+ Ross
+ Stoyanchev
+
diff --git a/spring-webflow/docs/reference/src/practical.xml b/spring-webflow/docs/reference/src/practical.xml
index 5744a8c4..dc097d50 100644
--- a/spring-webflow/docs/reference/src/practical.xml
+++ b/spring-webflow/docs/reference/src/practical.xml
@@ -29,10 +29,14 @@
NumberGuess - demonstrates use of stateful middle-tier components to carry out business logic.
- Birthdate - demonstrates Struts integration and the MultiAction.
+
+ Birthdate - demonstrates Struts integration and the MultiAction.
+
- Fileupload - demonstrates multipart file upload.
+
+ Fileupload - demonstrates multipart file upload.
+ Phonebook-Portlet - the phonebook sample in a Portlet environment (notice how the flow definitions do not change).
@@ -44,4 +48,436 @@
+
+ Running the Samples
+
+ The samples can be built from the command line and imported as Eclipse projects - all samples come
+ with Eclipse project settings. It is also possible to start by importing the samples into Eclipse
+ first and then build with Ant within Eclipse.
+
+
+ Building from the Command Line
+
+ Java 1.5 (or greater) and Ant 1.6 (or greater) are prerequisites for running the build. Ensure
+ those are present in the system path or are passed on the command line. Open a prompt, cd to the
+ directory where Spring Web Flow was unzipped and run the following:
+
+cd projects/spring-webflow/build-spring-webflow
+ant dist
+
+ This builds all samples preparing "target" areas within each sample project subdirectory
+ containing webapp structures in both exploded and WAR archive forms. The build provides targets
+ for deploying to Tomcat. However these webapp structures can be copied to any servlet container.
+
+
+
+ Deploying to Tomcat
+
+ In order to use the Ant Tomcat tasks cd to the projects/spring-webflow/build-spring-webflow
+ subdirectory (relative to where Spring Web Flow was unzipped) and add the following property
+ to the build.properties file (create it if it doesn't exist):
+
+tomcat.dir=c:/tomcat
+
+ where c:/tomcat is the location of the Tomcat installation to deploy to. When this is done run
+ "ant tomcat-copy-war" from the same directory to copy all sample applications.
+
+
+
+ Importing Projects into Eclipse
+
+ Importing the sample projects into Eclipse is easy. With a new or an existing workspace select:
+ File > Import > Existing Projects into Workspace. In the resulting dialog browse to the project
+ subdirectory where Spring Web Flow was unzipped and choose it as the root directory to import form.
+ Press OK. Here Eclipse will list all projects it found including the samples projects. Press Finish and
+ allow the build to complete.
+
+
+ If you previously did a build from the command line Eclipse will compile with no errors. If not
+ you will need to run the ant build once for these errors to clear and you can do that within
+ Eclipse. Expand the build-spring-webflow project in Eclipse, right-click build.xml and select:
+ Run As > Ant Build. This will run the default Ant target and will build all sample projects.
+ When this is done all errors in the Eclipse problems view should go away. Next you can run the
+ "tomcat-copy-war" Ant task if you didn't alread do so (see the previous section).
+
+
+
+ Other IDE's
+
+ Importing samples into other IDE's should be fairly straight-forward. If using another IDE
+ running the Ant build from the command line first may help as it will populate the lib
+ subdirectories of each sample project. Follow steps similar as those outlined for Eclipse above.
+
+
+
+
+ Fileupload Example
+
+ Overview
+
+ Fileupload is a simple one page web application for uploading files to a server. It is based
+ on Spring MVC, uses a Web Flow controller and one web flow with two states: a view state for
+ displaying the initial JSP page and an action state for processing the submit.
+
+
+
+ Web.xml
+
+ The web.xml configuration maps requests for "*.htm" to the fileupload servlet - a regular
+ Spring MVC DispatcherServlet:
+
+<servlet>
+ <servlet-name>fileupload</servlet-name>
+ <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
+</servlet>
+
+<servlet-mapping>
+ <servlet-name>fileupload</servlet-name>
+ <url-pattern>*.htm</url-pattern>
+</servlet-mapping>
+
+
+
+
+ Spring MVC Context
+
+ The Spring MVC servlet context for the fileupload servlet (WEB-INF/fileupload-servlet.xml) defines
+ one controller bean:
+
+<bean name="/admin.htm" class="org.springframework.webflow.executor.mvc.FlowController">
+ <property name="flowExecutor" ref="flowExecutor" />
+</bean>
+
+ FlowController is a Web Flow controller. It is the main point of integration between Spring MVC
+ and Spring Web Flow routing requests to one or more managed web flow executions. The
+ FlowController is injected with flowExecutor and flowRegistry beans containing one web flow
+ definition:
+
+<!-- Launches new flow executions and resumes existing executions. -->
+<flow:executor id="flowExecutor" registry-ref="flowRegistry" repository-type="singlekey"/>
+
+<!-- Creates the registry of flow definitions for this application -->
+<flow:registry id="flowRegistry">
+ <flow:location path="/WEB-INF/fileupload.xml" />
+</flow:registry>
+
+ Given the above definitions the following URI can be used to invoke the "fileupload" flow:
+
+/swf-fileupload/admin.htm?_flowId=fileupload
+
+
+
+ Both flowExecutor and flowRegistry beans are defined with Spring custom tags schema available in
+ Spring 2.0. The custom tags make configuration less verbose and more readable. Regular Spring
+ bean definitions can be used as well with earlier versions of Spring.
+
+
+ The Spring MVC context also defines a view resolver bean for resolving logical view names and a
+ multipartResolver bean for the upload component. In general Web Flow does not aim to replace the
+ flexibility of Spring MVC for view resolution. It focuses on the C in MVC.
+
+
+
+ Fileupload Web Flow
+
+ The start state for the fileupload flow (WEB-INF/fileupload.xml) is a view state:
+
+<start-state idref="selectFile"/>
+
+<view-state id="selectFile" view="fileForm">
+ <transition on="submit" to="uploadFile"/>
+</view-state>
+
+ View states allow a user to participate in a flow by presenting a suitable interface.
+ The view attribute "fileForm" is a logical view name, which the Spring MVC view resolver bean
+ will resolve to /WEB-INF/jsp/fileForm.jsp.
+
+
+ The fileForm.jsp has an html form that submits back to the same controller
+ (/swf-fileupload/admin.htm) and passes a "_flowExecutionKey" parameter.
+ The value for _flowExecutionKey is provided by the FlowController - it identifies the current
+ instance of the flow and allows Web Flow to resume flow execution, which is paused each time a
+ view is displayed.
+
+
+ The name of the form submit button "_eventId_submit" indicates the event id to use for deciding
+ where to transition to next. Given an event with id of "submit" the "selectFile" view transitions
+ to the "uploadFile" state:
+
+<action-state id="uploadFile">
+ <action bean="uploadAction" method="uploadFile"/>
+ <transition on="success" to="selectFile">
+ <set attribute="fileUploaded" scope="flash" value="true"/>
+ </transition>
+ <transition on="error" to="selectFile"/>
+</action-state>
+
+
+
+ The "uploadFile" state is an action state. Action states integrate with business application code and
+ respond to the execution of that code by deciding what state of the flow to enter next. The code for the
+ uploadFile state is in the "uploadAction" bean declared in the Spring web context (/WEB-INF/fileupload-servlet.xml):
+
+<bean id="uploadAction" class="org.springframework.webflow.samples.fileupload.FileUploadAction" />
+
+ FileUploadAction has simple logic. It picks one of two Web Flow defined events - success or error,
+ depending on whether the uploaded file size is greater than 0 or not. Both success and error
+ transition back to the "selectFile" view state. However, a success event causes an attribute named
+ "fileUploaded" to be set in flash scope
+
+
+ A flash-scoped attribute called "file" is also set programmatically in the FileUploadAction bean:
+
+context.getFlashScope().put("file", new String(file.getBytes()));
+return success();
+
+ This illustrates the choice to save attributes in one of several scopes either programatically or
+ declaratively.
+
+
+
+
+ Birthdate Example
+
+ Overview
+
+ Birthdate is a web application with 3 consequitive screens. The first two collect user input
+ to populate a form object. The third presents the results of business calculations based on
+ input provided in the first two screens.
+
+
+ Birthdate demonstrates Spring Web Flow's Struts integration as well as the use of FormAction,
+ a multi-action used to do the processing required for all three screens. The sample also uses JSTL
+ taglibs in conjunction with flows.
+
+
+
+ Web.xml
+
+ The web.xml configuration maps requests for "*.do" to a regular Struts ActionServlet:
+
+<servlet>
+ <servlet-name>action</servlet-name>
+ <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
+</servlet>
+
+<servlet-mapping>
+ <servlet-name>action</servlet-name>
+ <url-pattern>*.do</url-pattern>
+</servlet-mapping>
+
+ The web.xml also sets up the loading of a Spring context at web application startup:
+
+<context-param>
+ <param-name>contextConfigLocation</param-name>
+ <param-value>
+ /WEB-INF/webflow-config.xml
+ </param-value>
+</context-param>
+
+<listener>
+ <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+</listener>
+
+ The Spring web context contains beans to set up the Web Flow runtime environment. As will be
+ shown in the next section Struts is configured with a Web Flow action that relies on the
+ presence of a flowExecutor and a flowRegistry beans in this context.
+
+
+
+ Struts Configuration
+
+ The Struts configuration (WEB-INF/struts-config.xml) defines the following action mapping:
+
+<action-mappings>
+ <action path="/flowAction" name="actionForm" scope="request"
+ type="org.springframework.webflow.executor.struts.FlowAction"/>
+</action-mappings>
+
+ FlowAction is a Struts action acting as a front controller to the Web Flow system routing Struts
+ requests to one or more managed web flow executions. To fully configure the FlowAction a Spring
+ web context is required to define flowExecutor and flowRegistry beans (named exactly so). This is
+ an excerpt from the Spring web context (/WEB-INF/webflow-config.xml) defining these beans:
+
+<!-- Launches new flow executions and resumes existing executions. -->
+<flow:executor id="flowExecutor" registry-ref="flowRegistry"/>
+
+<!-- Creates the registry of flow definitions for this application -->
+<flow:registry id="flowRegistry">
+ <flow:location path="/WEB-INF/birthdate.xml"/>
+ <flow:location path="/WEB-INF/birthdate-alternate.xml"/>
+</flow:registry>
+
+
+
+ Based on the above, Web Flow is configured with two flows - birthdate and birthdate-alternate,
+ which can be invoked as follows:
+
+/swf-birthdate/flowAction.do?_flowId=birthdate
+/swf-birthdate/flowAction.do?_flowId=birthdate-alternate
+
+ The Struts configuration file also defines several global forwards: birthdateForm, cardForm,
+ and yourAge, which will be referenced from Web Flow definitions as logical view names
+ (and left to Struts to resolve to actual JSP pages). In general Web Flow does not aim to replace
+ view resolution capabilities of web frameworks such as Struts or Spring MVC.
+ It focuses on the C in MVC.
+
+
+
+ Birthdate Web Flow
+
+ The birthdate web flow (WEB-INF/birthdate.xml) defines the following start state:
+
+<view-state id="enterBirthdate" view="birthdateForm">
+ <render-actions>
+ <action bean="formAction" method="setupForm" />
+ </render-actions>
+ <transition on="submit" to="processBirthdateFormSubmit" />
+</view-state>
+
+ The setupForm action is called to perform initializations for the enterBirthdate view state.
+ Its action bean is defined the Spring web context WEB-INF/webflow-config.xml:
+
+<bean id="formAction" class="org.springframework.webflow.samples.birthdate.BirthDateFormAction" />
+
+ BirthDateFormAction is a FormAction - it extends Web Flow's FormAction class, which serves a
+ purpose similar to that of Spring MVC's SimpleFormController providing common form functionality
+ for data binding and validation.
+
+
+ When the BirthDateFormAction bean is instantiated it sets the name, class and scope of the form
+ object to use for loading form data upon display and collecting form data upon submit:
+
+public BirthDateFormAction() {
+ // tell the superclass about the form object and validator we want to
+ // use you could also do this in the application context XML ofcourse
+ setFormObjectName("birthDate");
+ setFormObjectClass(BirthDate.class);
+ setFormObjectScope(ScopeType.FLOW);
+ setValidator(new BirthDateValidator());
+}
+
+ The form object "birthDate" is placed in flow scope, which means it will not be re-created with
+ each request but will be obtained from flow scope instead as long as the request remains within
+ the same flow.
+
+
+ Once setupForm is done, the "birthdateForm" view will be rendered.
+ The logical view name "birthdateForm" is a global-forward in struts-config.xml resolving to
+ /WEB-INF/jsp/birthdateForm.jsp. This JSP collects data for the fields "name" and "date" bound to
+ the birthDate form object and posts back to FlowAction with a submit image named
+ "_eventId_submit". An event with the id of "submit" causes a transition to the
+ processBirthdateFormSubmit action state defined as follows:
+
+<action-state id="processBirthdateFormSubmit">
+ <action bean="formAction" method="bindAndValidate">
+ <attribute name="validatorMethod" value="validateBirthdateForm" />
+ </action>
+ <transition on="success" to="enterCardInformation" />
+ <transition on="error" to="enterBirthdate" />
+</action-state>
+
+ The processBirthDateFormSubmit action state uses the same formAction bean as the one already used
+ to setup the form. This time its bindAndValidate
+ method is used to populate and validate the html form values. Also, note the "validateMethod"
+ attribute used to specify the name of the method to invoke on the Validator object setup in the
+ constructor of the BirthDateFormAction. The use of this attribute allows partial validation of
+ complex objects populated over several consecutive screens.
+
+
+ On error the action returns to the view state it came from. On success it transitions to the
+ enterCardInformation view state:
+
+<view-state id="enterCardInformation" view="cardForm">
+ <transition on="submit" to="processCardFormSubmit" />
+</view-state>
+
+ The logical view name "cardForm" is a global-forward in struts-config.xml resolving to
+ /WEB-INF/jsp/cardForm.jsp. This JSP collects data for the remaining fields of the birthDate form
+ object - "sendCard" and "emailAddress", and posts back to FlowAction with a submit image named
+ "_eventId_submit". An event with the id of "submit" causes a transition to the
+ processCardFormSubmit action state defined as follows:
+
+<action-state id="processCardFormSubmit">
+ <action bean="formAction" method="bindAndValidate">
+ <attribute name="validatorMethod" value="validateCardForm" />
+ </action>
+ <transition on="success" to="calculateAge" />
+ <transition on="error" to="enterCardInformation" />
+</action-state>
+
+ For this action state the bindAndValidate method of the formAction bean is used to populate and
+ validate the remaining html form values. The "validateMethod" attribute specifies the name of the
+ method to invoke on the Validator object specific to the fields loaded on the current screen.
+
+
+ On error the action returns to the view state it came from. On success it transitions to another
+ action state called calculateAge:
+
+<action-state id="calculateAge">
+ <action bean="formAction" method="calculateAge" />
+ <transition on="success" to="displayAge" />
+</action-state>
+
+ The logic for the calculateAge action state is in the calculateAge method of the same formAction
+ bean used for data binding and validation. This demonstrates the flexibility Web Flow allows in
+ properly structuring control and business logic according to function.
+
+
+ The caculateAge method performs business calculations and adds a string in request scope with the
+ calculated age. Upon successful completion the calculateAge action state transitions to the end
+ view state:
+
+<end-state id="displayAge" view="yourAge" />
+
+ Once again the logical view name "yourAge" is a global-forward in struts-config.xml resolving to
+ /WEB-INF/jsp/yourAge.jsp. This JSP page retrieves the calculated age from request scope and
+ displays the results for the user.
+
+
+ The transition to the end state indicates the end of the web flow. The flow execution is cleaned up.
+ If the web flow is entered again a new flow execution will start, creating a new form
+ object named "birthDate" and placing it in flow scope.
+
+
+
+ Birthdate-alternate Web Flow
+
+ The birthdate-alternate web flow (/WEB-INF/birthdate-alternate.xml) offers an alternative way and
+ more compact way of defining the same web flow. For example the birthdate web flow defines two
+ independent states for the first screen - a view state (enterBirthdate) and an action state
+ (processBirthdateFormSubmit). In birthdate-alternate those are encapsulated in the view state
+ enterBirthdate as follows:
+
+<view-state id="enterBirthdate" view="birthdateForm">
+ <render-actions>
+ <action bean="formAction" method="setupForm" />
+ </render-actions>
+ <transition on="submit" to="enterCardInformation">
+ <action bean="formAction" method="bindAndValidate">
+ <attribute name="validatorMethod" value="validateBirthdateForm" />
+ </action>
+ </transition>
+</view-state>
+
+ Here the setupForm action state is defined as a render-action of the enterBirthdate view state
+ while the transition to the next screen uses a nested action bean invoked before the transition
+ occurs. Notice that success is implicitly required for the transition to occur. Similarly on error
+ the transition does not occur and the same view state is displayed again.
+
+
+ The second screen is also defined with a nested transition and action bean:
+
+<view-state id="enterCardInformation" view="cardForm">
+ <transition on="submit" to="calculateAge">
+ <action bean="formAction" method="bindAndValidate">
+ <attribute name="validatorMethod" value="validateCardForm" />
+ </action>
+ </transition>
+</view-state>
+
+ The remaining two states - calculateAge and displayAge are identical.
+
+
+