diff --git a/spring-webflow/docs/reference/src/flow-executor.xml b/spring-webflow/docs/reference/src/flow-executor.xml index ed8089e7..59b0b764 100644 --- a/spring-webflow/docs/reference/src/flow-executor.xml +++ b/spring-webflow/docs/reference/src/flow-executor.xml @@ -521,74 +521,28 @@ Java Server Faces (JSF) integration - Spring Web Flow integrates with JSF. The JSF integration relies on custom implementations of - core JSF artifacts such as navigation handler and phase listener to drive the - execution of flows. In addition, it relies on custom Variable and Property Resolvers to - access flow execution variables from JSF components. + Spring Web Flow provides strong integration with Java Server Faces (JSF). When used with JSF, Spring Web Flow + takes responsibility for view navigation handling and managing model state, adding power and + simplicity to JSF's default navigation system and object scopes. Plain JSF views and components continue to work just as before, + and are able to participate in flows with full access to flow state. In addition, other view technologies + such as Facelets and Ajax4JSF continue to plug-in normally. + + + The JSF integration relies on custom implementations of core JSF artifacts such as the PhaseListener + and NavigationHandler to drive the execution of flows. In addition, it relies on a custom VariableResolver to + access flow execution attributes from JSF components. - A typical faces-config.xml file - -<faces-config> - <application> - <navigation-handler> - org.springframework.webflow.executor.jsf.FlowNavigationHandler - </navigation-handler> - <variable-resolver> - org.springframework.webflow.executor.jsf.FlowExecutionVariableResolver - </variable-resolver> - <property-resolver> - org.springframework.webflow.executor.jsf.FlowExecutionPropertyResolver - </property-resolver> - </application> - - <lifecycle> - <phase-listener>org.springframework.webflow.executor.jsf.FlowPhaseListener</phase-listener> - </lifecycle> -</faces-config> - - - - Launching a flow execution - command link - - <h:commandLink value="Go" action="flowId:myflow"/> - - - - Resuming a flow execution - form bound to flow execution variables - - <h:form id="form"> - ... - <h:inputText id="propertyName" value="#{flowExecution.flashScope.aFlashScopeAttribute}"/> - <h:inputText id="propertyName" value="#{flowExecution.flowScope.aFlowScopeAttribute}"/> - <h:inputText id="propertyName" value="#{flowExecution.conversationScope.aConversationScopeAttribute}"/> - - <h:inputText id="propertyName" value="#{flowExecution.anAttributeToSearchForAcrossAllScopes}"/> - ... - <input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}"> - <h:commandButton type="submit" value="Next" action="submit"/> - </h:form> - - - - A pre Spring Web Flow 1.0.2 faces-config.xml file + A minimal faces-config.xml file - Before Spring Web Flow 1.0.2 Spring Web Flow only supported resolving variables in flow scope - (and not the other scopes such as flash and conversation shown above). This configuration is still supported - for backwards compatibility reasons and follows: + Using Spring Web Flow in a JSF environment requires adding these custom artifacts to the application's + faces-config.xml file: <faces-config> <application> - <navigation-handler> - org.springframework.webflow.executor.jsf.FlowNavigationHandler - </navigation-handler> - <variable-resolver> - org.springframework.webflow.executor.jsf.FlowVariableResolver - </variable-resolver> - <property-resolver> - org.springframework.webflow.executor.jsf.FlowPropertyResolver - </property-resolver> + <navigation-handler>org.springframework.webflow.executor.jsf.FlowNavigationHandler</navigation-handler> + <variable-resolver>org.springframework.webflow.executor.jsf.DelegatingFlowVariableResolver</variable-resolver> </application> <lifecycle> @@ -596,10 +550,158 @@ </lifecycle> </faces-config> + + The FlowPhaseListener is required to manage the overall flow execution lifecycle in a JSF environment. It handles launching new + flows accessed by browsers via direct URLs, and also handles restoring flow executions on postback and browser refreshes. + + + The FlowNavigationHandler is required to continue a flow on an action outcome from a JSF view + participating in the flow. Outcome strings are treated as events signaled against the current view state + of the flow execution automatically. + + + The DelegatingFlowVariableResolver resolves JSF a value binding expression like {#someBean.someProperty} + to a flow execution attribute. This resolver searches flash, flow, and conversation scope in that order until + it finds a match. If no match is found this resolver delegates to the next resolver in the chain. + + + + Launching a flow execution - JSF command link component + + Flows can be launched by firing JSF action outcomes that adhere to a special format: + + + <h:commandLink value="Go" action="flowId:myflow"/> + + + The command link above says launch 'myflow' when clicked. + By default, an action outcome prefixed with flowId: will treated as a flow definition identifier. + The FlowNavigationHandler will launch a new execution of that flow definition. + + + The flow id prefix respected by the FlowNavigationHandler is configurable. See the API documentation for + more information. + + + + Launching a flow execution - normal HTML anchor + + Flows can also be launched simply by accessing flow definition URLs directly using a bookmark or normal HTML link: + + + <a href="app.faces?flowId=myflow">Go</a> + + + This example link assumes *.faces has been mapped to the FacesServlet defined within web.xml. + The format of a flow definition URL is configurable on the FlowPhaseListener. + + + + Sample flow in a JSF environment + + Flow definitions in a JSF environment are just plain Spring Web Flow definitions: + + +<?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"> + + <var name="bean" class="example.ManagedBeanImpl" scope="conversation" /> + + <start-state idref="displayView" /> + + <view-state id="displayView" view="/myview.jsp"> + <transition on="submit" to="displayNextView"/> + </view-state> + + <view-state id="displayNextView" view="/nextview.jsp" /> + +</flow> + + + A benefit of using JSF is UI components typically handle data binding and validation, so the actual flow + definition logic is often simpler and more focused. In general, it is recommended views selected by + view states follow the standard JSF view identifier format, which requires a leading forward-slash + and ends in a prefix. + + + How Spring Web Flow view names are mapped to JSF view ids is configurable. See the + FlowPhaseListener API documentation for more information. + + + + Resuming a flow execution - form bound to flow execution variables + + Views participating in flows are just plain JSF views. They may also incorporate other + JSF view technologies such as Facelets and Ajax4JSF. + + +<f:view> + <h:form id="form"> + ... + <h:inputText id="propertyName" value="#{someBean.someProperty}"/> + ... + <h:commandButton type="submit" value="Next" action="submit"/> + </h:form> +</f:view> + + + As shown above, there is nothing Spring Web Flow specific here. The flow execution + key is automatically tracked by a special UI component in the view root, so there is no need to + track it manually. Action outcomes are automatically mapped to Spring Web Flow event identifiers + signaled against the current state. + + + + Spring Web Flow JSF Integration Samples + + See the sellitem-jsf sample that illustrates Spring Web Flow operating in + a JSF environment. + + + + A pre Spring Web Flow 1.0.2 faces-config.xml file + + This section applies to those using Spring Web Flow's JSF integration before release 1.0.2. + + + Before release 1.0.2, Spring Web Flow only supported resolving variables in flow scope + (and not the other scopes such as flash and conversation shown above). This configuration is still supported + for backwards compatibility reasons: + + +<faces-config> + <application> + <navigation-handler>org.springframework.webflow.executor.jsf.FlowNavigationHandler</navigation-handler> + <variable-resolver>org.springframework.webflow.executor.jsf.FlowVariableResolver</variable-resolver> + <property-resolver>org.springframework.webflow.executor.jsf.FlowPropertyResolver</property-resolver> + </application> + + <lifecycle> + <phase-listener>org.springframework.webflow.executor.jsf.FlowPhaseListener</phase-listener> + </lifecycle> +</faces-config> + + + + With 1.0.2 DelegatingFlowVariableResolver is now the recommended default resolver, + as it allows full access to all flow execution scopes transparently from the point of view of the + JSF view developer. + + - Resuming a flow execution - pre 1.0.2 form bound to flow scope variables + Resuming a flow execution - pre Spring Web Flow 1.0.2 + + Before release 1.0.2, the flow execution key had to be tracked manually in JSF views participating + in a flow execution. This configuration is still supported for backwards compatibility reasons. + However, it is highly recommended that existing users of Spring Web Flow's JSF integration + update their views to be just plain JSF. + +<f:view> <h:form id="form"> ... <h:inputText id="propertyName" value="#{flowScope.aFlowScopeAttribute}"/> @@ -607,7 +709,12 @@ <input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}"> <h:commandButton type="submit" value="Next" action="submit"/> </h:form> +</f:view> + + The hidden form field above can now be safely removed. In addition, the new variable resolver + can be plugged in to gain access to other scopes such as flash and conversation. + \ No newline at end of file diff --git a/spring-webflow/docs/reference/src/practical.xml b/spring-webflow/docs/reference/src/practical.xml index 76db2c50..090c9995 100644 --- a/spring-webflow/docs/reference/src/practical.xml +++ b/spring-webflow/docs/reference/src/practical.xml @@ -1766,8 +1766,8 @@ public void registerCustomEditors(PropertyEditorRegistry registry) { Overview The Sellitem-JSF example uses Web Flow and JSF to build a shopping - cart wizard. Navigation logic and supporting "flow" scoped beans - are supplied through Spring and Spring Web Flow while JSP's and + cart wizard. Navigation logic and supporting managed beans + are supplied by Spring Web Flow while UI views and overall servlet processing is based on JSF technology. @@ -1785,7 +1785,7 @@ public void registerCustomEditors(PropertyEditorRegistry registry) { Web.xml The web.xml contains standard JSF configuration including mappings for - the JSF front servlet: it handles all requests ending with "*.jsf": + the JSF front servlet: it handles all requests ending with "*.faces": <!-- Faces Servlet --> <servlet> @@ -1796,13 +1796,13 @@ public void registerCustomEditors(PropertyEditorRegistry registry) { <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> - <url-pattern>*.jsf</url-pattern> + <url-pattern>*.faces</url-pattern> </servlet-mapping> - In addition the web.xml loads to Spring contexts with the - ContextLoaderListener: + In addition the web.xml loads a Spring root web application context containing the services + used by the application: <context-param> <param-name>contextConfigLocation</param-name> @@ -1819,29 +1819,23 @@ public void registerCustomEditors(PropertyEditorRegistry registry) { The services-config.xml contains POJO beans required for the services and data access layers of the application. These declarations are very similar to the Sellitem example (and explained in more detail there). - The webflow-config.xml context contains Web Flow related bean + The webflow-config.xml contains Web Flow related bean definitions. These definitions will be explained a little bit further on in the context of how they fit into the JSF phases lifecycle. - JSF Setup in faces-config.xml + Web Flow JSF Setup in faces-config.xml - The Spring framework has several classes to help JSF applications - to use Spring beans as JSF managed beans and to do dependency injection - on a navigation handler or a phase listener using Spring. + To plug in Web Flow a few things must be added once to faces-config.xml. This is demonstrated in the faces-config.xml of Sellitem-JSF: <application> - <!-- Navigation handler proxy for a Spring-managed bean that is the Web Flow Navigation Handler --> - <navigation-handler> - org.springframework.webflow.executor.jsf.FlowNavigationHandler - </navigation-handler> - <variable-resolver> - org.springframework.webflow.executor.jsf.DelegatingFlowVariableResolver - </variable-resolver> + <navigation-handler>org.springframework.webflow.executor.jsf.FlowNavigationHandler</navigation-handler> + <variable-resolver>org.springframework.webflow.executor.jsf.DelegatingFlowVariableResolver</variable-resolver> </application> + <lifecycle> <phase-listener>org.springframework.webflow.executor.jsf.FlowPhaseListener</phase-listener> </lifecycle> @@ -1866,27 +1860,35 @@ public void registerCustomEditors(PropertyEditorRegistry registry) { - Web Flow Definitions + Web Flow System Setup in webflow-config.xml Examining the definitions in faces-config.xml highlighted the ability - to use Spring beans as JSF managed beans as well as plug Web Flow - definitions for JSF navigation logic. Now we can turn to the question - of how to configure specific web flow definitions. + to use plug Web Flow in as a navigation handler and as a source + for JSF managed beans. Now we can turn to the question + of how to configure the web flow system itself in a JSF environment. - The Spring web context /WEB-INF/webflow-config.xml contains the following - flow registry bean definition: + The Spring web context fragment /WEB-INF/webflow-config.xml contains the following configuration: +<!-- 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="flowDefinitionLocator"> +<flow:registry id="flowRegistry"> <flow:location path="/WEB-INF/flows/sellitem-flow.xml" /> </flow:registry> - Here the flow registry definies the path to one web flow definition - - sellitem-flow.xml. The flow registry bean with an id of "flowDefinitionLocator" - is accessed by the FlowPhaseListener, which makes the specified web flow - definitions available for use in JSF. The intro.jsp page shows how the - configured web flow sellitem-flow.xml can be invoked: + Here the flow executor is configured to support execution of a single + flow definition - sellitem-flow.xml. The executor bean has been assigned the id + "flowExecutor". This id is significant and is required for the JSF artifacts to detect + the executor and its services. + + + + Launching the sellitem-flow + + The intro.jsp page shows how the configured web flow sellitem-flow.xml can be launched using + a JSF command link component. <h:form> <h:commandLink value="Sell Item" action="flowId:sellitem-flow"/> @@ -1901,30 +1903,26 @@ public void registerCustomEditors(PropertyEditorRegistry registry) { - The JSF version of the sellitem flow definition is simpler because JSF components - care for data binding and validation. + The JSF version of the sellitem flow definition is simpler because JSF components care for data binding and validation. - In its web flow definition Sellitem-JSF uses actual - JSP names (instead of the logical view names used - in Sellitem) to be rendered by JSF. + In its web flow definition Sellitem-JSF uses actual JSP names (instead of the logical view names used in Sellitem) + to be rendered by JSF. This is consistent with normal JSF-isms. - The JSP pages in Sellitem-JSF use unified EL to - access the flowScoped Sale object - e.g. #{sale.price}. + The JSP pages in Sellitem-JSF use unified EL to access the converastion scoped Sale object - e.g. #{sale.price}. - Sellitem-JSF uses JSF tags for UI and Sellitem uses Spring form tags. + Sellitem-JSF uses JSF component tags for UI and Sellitem uses Spring form tags. - There is no need to manually track the flow execution key because it is tracked - for you in the JSF view root. + There is no need to manually track the flow execution key because it is tracked for you in the JSF view root.