# 13. JSF Integration ## 13.1. Introduction Spring Web Flow provides a JSF integration that lets you use the JSF UI Component Model with Spring Web Flow controllers. Web Flow also provides a Spring Security tag library for use in JSF environments, see [Section 13.9, “Using the Spring Security Facelets Tag Library”](spring-faces.html#spring-faces-security-taglib) for more details. Spring Web Flow 2.5 requires JSF 2.2 or higher. ## 13.2. Configuring web.xml The first step is to route requests to the`DispatcherServlet` in the `web.xml` file. In this example, we map all URLs that begin with `/spring/` to the servlet. The servlet needs to be configured. An `init-param` is used in the servlet to pass the `contextConfigLocation`. This is the location of the Spring configuration for your web application. ``` Spring MVC Dispatcher Servlet org.springframework.web.servlet.DispatcherServlet contextConfigLocation /WEB-INF/web-application-config.xml 1 Spring MVC Dispatcher Servlet /spring/* ``` In order for JSF to bootstrap correctly, the`FacesServlet` must be configured in `web.xml` as it normally would even though you generally will not need to route requests through it at all when using JSF with Spring Web Flow. ``` Faces Servlet javax.faces.webapp.FacesServlet 1 Faces Servlet *.faces ``` The use of Facelets instead of JSP typically requires this in web.xml: ``` !-- Use JSF view templates saved as *.xhtml, for use with Facelets --> javax.faces.DEFAULT_SUFFIX .xhtml ``` ## 13.3. Configuring Web Flow for use with JSF This section explains how to configure Web Flow with JSF. Both Java and XML style configuration are supported. The following is sample configuration for Web Flow and JSF in XML: ``` ``` The following is an example of the same in Java configuration: ``` import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.faces.config.*; @Configuration public class WebFlowConfig extends AbstractFacesFlowConfiguration { @Bean public FlowExecutor flowExecutor() { return getFlowExecutorBuilder(flowRegistry()) .addFlowExecutionListener(new FlowFacesContextLifecycleListener()) .build(); } @Bean public FlowDefinitionRegistry flowRegistry() { return getFlowDefinitionRegistryBuilder() .setBasePath("/WEB-INF") .addFlowLocationPattern("**/*-flow.xml").build(); } ``` The main points are the installation of a`FlowFacesContextLifecycleListener` that manages a single FacesContext for the duration of Web Flow request and the use of the`flow-builder-services` element from the `faces`custom namespace to configure rendering for a JSF environment. In a JSF environment you'll also need this Spring MVC related configuration: ``` ``` The `resources` custom namespace element delegates JSF resource requests to the JSF resource API. The`JsfFlowHandlerAdapter` is a replacement for the`FlowHandlerAdapter` normally used with Web Flow. This adapter initializes itself with a `JsfAjaxHandler` instead of the`SpringJavaSciprtAjaxHandler`. When using Java config, the `AbstractFacesFlowConfiguration`base class automatically registers `JsfResourceRequestHandler`so there is nothing further to do. ## 13.4. Replacing the JSF Managed Bean Facility When using JSF with Spring Web Flow you can completely replace the JSF managed bean facility with a combination of Web Flow managed variables and Spring managed beans. It gives you a good deal more control over the lifecycle of your managed objects with well-defined hooks for initialization and execution of your domain model. Additionally, since you are presumably already using Spring for your business layer, it reduces the conceptual overhead of having to maintain two different managed bean models. In doing pure JSF development, you will quickly find that request scope is not long-lived enough for storing conversational model objects that drive complex event-driven views. In JSF the usual option is to begin putting things into session scope, with the extra burden of needing to clean the objects up before progressing to another view or functional area of the application. What is really needed is a managed scope that is somewhere between request and session scope. JSF provides flash and view scopes that can be accessed programmatically via UIViewRoot.getViewMap(). Spring Web Flow provides access to flash, view, flow, and conversation scopes. These scopes are seamlessly integrated through JSF variable resolvers and work the same in all JSF applications. ### 13.4.1. Using Flow Variables The easiest and most natural way to declare and manage the model is through the use of [flow variables](defining-flows.html#flow-variables). You can declare these variables at the beginning of the flow: ``` ``` and then reference this variable in one of the flow's JSF view templates through EL: ``` ``` Note that you do not need to prefix the variable with its scope when referencing it from the template (though you can do so if you need to be more specific). As with standard JSF beans, all available scopes will be searched for a matching variable, so you could change the scope of the variable in your flow definition without having to modify the EL expressions that reference it. You can also define view instance variables that are scoped to the current view and get cleaned up automatically upon transitioning to another view. This is quite useful with JSF as views are often constructed to handle multiple in-page events across many requests before transitioning to another view. To define a view instance variable, you can use the`var` element inside a `view-state`definition: ``` ``` ### 13.4.2. Using Scoped Spring Beans Though defining autowired flow instance variables provides nice modularization and readability, occasions may arise where you want to utilize the other capabilities of the Spring container such as AOP. In these cases, you can define a bean in your Spring ApplicationContext and give it a specific web flow scope: ``` ``` The major difference with this approach is that the bean will not be fully initialized until it is first accessed via an EL expression. This sort of lazy instantiation via EL is quite similar to how JSF managed beans are typically allocated. ### 13.4.3. Manipulating The Model The need to initialize the model before view rendering (such as by loading persistent entities from a database) is quite common, but JSF by itself does not provide any convenient hooks for such initialization. The flow definition language provides a natural facility for this through its [Actions](defining-flows.html#flow-actions) . Spring Web Flow provides some extra conveniences for converting the outcome of an action into a JSF-specific data structure. For example: ``` ``` This will take the result of the`bookingService.findBookings` method an wrap it in a custom JSF DataModel so that the list can be used in a standard JSF DataTable component: ``` Name #{booking.hotel.name} Confirmation number #{booking.id} Action ``` ### 13.4.4. Data Model Implementations In the example above result-type="dataModel" results in the wrapping of List\ with custom`DataModel` type. The custom`DataModel` provides extra conveniences such as being serializable for storage beyond request scope as well as access to the currently selected row in EL expressions. For example, on postback from a view where the action event was fired by a component within a DataTable, you can take action on the selected row's model instance: ``` ``` Spring Web Flow provides two custom DataModel types:`OneSelectionTrackingListDataModel` and`ManySelectionTrackingListDataModel`. As the names indicate they keep track of one or multiple selected rows. This is done with the help of a`SelectionTrackingActionListener` listener, which responds to JSF action events and invokes the appopriate methods on the`SelectinAware` data models to record the currently clicked row. To understand how this is configured, keep in mind the`FacesConversionService` registers a`DataModelConverter` against the alias "dataModel" on startup. When result-type="dataModel" is used in a flow definition it causes the `DataModelConverter` to be used. The converter then wraps the given List with an instance of`OneSelectionTrackingListDataModel`. To use the`ManySelectionTrackingListDataModel` you will need to register your own custom converter. ## 13.5. Handling JSF Events With Spring Web Flow Spring Web Flow allows you to handle JSF action events in a decoupled way, requiring no direct dependencies in your Java code on JSF API's. In fact, these events can often be handled completely in the flow definiton language without requiring any custom Java action code at all. This allows for a more agile development process since the artifacts being manipulated in wiring up events (JSF view templates and SWF flow definitions) are instantly refreshable without requiring a build and re-deploy of the whole application. ### 13.5.1. Handling JSF In-page Action Events A simple but common case in JSF is the need to signal an event that causes manipulation of the model in some way and then redisplays the same view to reflect the changed state of the model. The flow definition language has special support for this in the`transition` element. A good example of this is a table of paged list results. Suppose you want to be able to load and display only a portion of a large result list, and allow the user to page through the results. The initial`view-state` definition to load and display the list would be: ``` ``` You construct a JSF DataTable that displays the current`hotels` list, and then place a "More Results" link below the table: ``` ``` This commandLink signals a "next" event from its action attribute. You can then handle the event by adding to the `view-state`definition: ``` ``` Here you handle the "next" event by incrementing the page count on the searchCriteria instance. The `on-render` action is then called again with the updated criteria, which causes the next page of results to be loaded into the DataModel. The same view is re-rendered since there was no `to` attribute on the`transition` element, and the changes in the model are reflected in the view. ### 13.5.2. Handling JSF Action Events The next logical level beyond in-page events are events that require navigation to another view, with some manipulation of the model along the way. Achieving this with pure JSF would require adding a navigation rule to faces-config.xml and likely some intermediary Java code in a JSF managed bean (both tasks requiring a re-deploy). With the flow defintion language, you can handle such a case concisely in one place in a quite similar way to how in-page events are handled. Continuing on with our use case of manipulating a paged list of results, suppose we want each row in the displayed DataTable to contain a link to a detail page for that row instance. You can add a column to the table containing the following `commandLink`component: ``` ``` This raises the "select" event which you can then handle by adding another `transition` element to the existing`view-state` : ``` ``` Here the "select" event is handled by pushing the currently selected hotel instance from the DataTable into flow scope, so that it may be referenced by the "reviewHotel" `view-state` . ### 13.5.3. Performing Model Validation JSF provides useful facilities for validating input at field-level before changes are applied to the model, but when you need to then perform more complex validation at the model-level after the updates have been applied, you are generally left with having to add more custom code to your JSF action methods in the managed bean. Validation of this sort is something that is generally a responsibility of the domain model itself, but it is difficult to get any error messages propagated back to the view without introducing an undesirable dependency on the JSF API in your domain layer. With Web Flow, you can utilize the generic and low-level`MessageContext` in your business code and any messages added there will then be available to the `FacesContext` at render time. For example, suppose you have a view where the user enters the necessary details to complete a hotel booking, and you need to ensure the Check In and Check Out dates adhere to a given set of business rules. You can invoke such model-level validation from a`transition` element: ``` ``` Here the "proceed" event is handled by invoking a model-level validation method on the booking instance, passing the generic`MessageContext` instance so that messages may be recorded. The messages can then be displayed along with any other JSF messages with the `h:messages` component, ### 13.5.4. Handling Ajax Events In JSF JSF provides built-in support for sending Ajax requests and performing partial processing and rendering on the server-side. You can specify a list of id's for partial rendering through the \ facelets tag. In Spring Web Flow you also have the option to specify the ids to use for partial rendering on the server side with the render action: ``` ``` ## 13.6. Embedding a Flow On a Page By default when a flow enters a view state, it executes a client-side redirect before rendering the view. This approach is known as POST-REDIRECT-GET. It has the advantage of separating the form processing for one view from the rendering of the next view. As a result the browser Back and Refresh buttons work seamlessly without causing any browser warnings. Normally the client-side redirect is transparent from a user's perspective. However, there are situations where POST-REDIRECT-GET may not bring the same benefits. For example sometimes it may be useful to embed a flow on a page and drive it via Ajax requests refreshing only the area of the page where the flow is rendered. Not only is it unnecessary to use client-side redirects in this case, it is also not the desired behavior with regards to keeping the surrounding content of the page intact. To indicate a flow should execute in "page embedded" mode all you need to do is pass an extra flow input attribute called "mode" with a value of "embedded". Below is an example of a top-level container flow invoking a sub-flow in an embedded mode: ``` ``` When launched in "page embedded" mode the sub-flow will not issue flow execution redirects during Ajax requests. If you'd like to see examples of an embedded flow please refer to the webflow-primefaces-showcase project. You can check out the source code locally, build it as you would a Maven project, and import it into Eclipse: ``` cd some-directory svn co https://src.springframework.org/svn/spring-samples/webflow-primefaces-showcase cd webflow-primefaces-showcase mvn package # import into Eclipse ``` The specific example you need to look at is under the "Advanced Ajax" tab and is called "Top Flow with Embedded Sub-Flow". ## 13.7. Redirect In Same State By default Web Flow does a client-side redirect even it it remains in the same view state as long as the current request is not an Ajax request. This is quite useful after form validation failures for example. If the user hits Refresh or Back they won't see any browser warnings. They would if the Web Flow didn't do a redirect. This can lead to a problem specific to JSF environments where a specific Sun Mojarra listener component caches the FacesContext assuming the same instance is available throughout the JSF lifecycle. In Web Flow however the render phase is temporarily put on hold and a client-side redirect executed. The default behavior of Web Flow is desirable and it is unlikely JSF applications will experience the issue. This is because Ajax is often enabled the default in JSF component libraries and Web Flow does not redirect during Ajax requests. However if you experience this issue you can disable client-side redirects within the same view as follows: ``` ``` ## 13.8. Handling File Uploads with JSF Most JSF component providers include some form of 'file upload' component. Generally when working with these components JSF must take complete control of parsing multi-part requests and Spring MVC's`MultipartResolver` cannot be used. Spring Web Flow has been tested with file upload components from PrimeFaces. Check the documentation of your JSF component library for other providers to see how to configure file upload. ### 13.8.1. File Uploads with PrimeFaces PrimeFaces provides a `` component for uploading files. In order to use the component you need to configure the `org.primefaces.webapp.filter.FileUploadFilter`servlet filter. The filter needs to be configured against Spring MVC's`DispatcherServlet` in your `web.xml`: ``` PrimeFaces FileUpload Filter org.primefaces.webapp.filter.FileUploadFilter PrimeFaces FileUpload Filter Spring MVC Dispatcher Servlet primefaces.UPLOADER commons ``` For more details refer to the[PrimeFaces documentation](http://primefaces.org/documentation.html). ## 13.9. Using the Spring Security Facelets Tag Library To use the library you'll need to create a `.taglib.xml`file and register it in `web.xml`. Create the file`/WEB-INF/springsecurity.taglib.xml` with the following content: ``` http://www.springframework.org/security/tags authorize org.springframework.faces.security.FaceletsAuthorizeTagHandler areAllGranted org.springframework.faces.security.FaceletsAuthorizeTagUtils boolean areAllGranted(java.lang.String) areAnyGranted org.springframework.faces.security.FaceletsAuthorizeTagUtils boolean areAnyGranted(java.lang.String) areNotGranted org.springframework.faces.security.FaceletsAuthorizeTagUtils boolean areNotGranted(java.lang.String) isAllowed org.springframework.faces.security.FaceletsAuthorizeTagUtils boolean isAllowed(java.lang.String, java.lang.String) ``` Next, register the above file taglib in web.xml: ``` javax.faces.FACELETS_LIBRARIES /WEB-INF/springsecurity.taglib.xml ``` Now you are ready to use the tag library in your views. You can use the authorize tag to include nested content conditionally: ``` Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet ``` You can also use one of several EL functions in the rendered or other attribute of any JSF component: ``` ``` ## 13.10. Third-Party Component Library Integration The Spring Web Flow JSF integration strives to be compatible with any third-party JSF component library. By honoring all of the standard semantics of the JSF specification within the SWF-driven JSF lifecycle, third-party libraries in general should "just work". The main thing to remember is that configuration in web.xml will change slightly since Web Flow requests are not routed through the standard FacesServlet. Typically, anything that is traditionally mapped to the FacesServlet should be mapped to the Spring DispatcherServlet instead. (You can also map to both if for example you are migrating a legacy JSF application page-by-page.).