Monday Jan 28, 2013

JSF 2.2 Faces Flow - @FlowScoped, #{flowScope}, @FlowDefinition (TOTD #198)

JavaServer Faces 2.2 is more evolutionary than it is revolutionary. This is by design as JSF 2.0 added a whole bunch of new features as part of the Java EE 6 platform. The Preface 1 from the JSF 2.2 Public Review specification provides a list of changes between JSF 2.1 and 2.2. There are several changes coming in JSF 2.2 but the big ticket items are:
  • Faces Flow
  • Resource Library Contract
  • HTML5 Friendly Markup
This Tip Of The Day (TOTD) will explain Faces Flow. Section 7.5 and 11.4.3 in the specification introduce the feature.

Faces Flow provides an encapsulation of related views/pages with an application defined entry and exit points. For example, a check out cart can consist of cart page, credit card details page, shipping address page, and confirmation page. All these pages, along with required resources and beans, can be packaged together as a module which can then be reused in other applications.

Each flow has a well-defined entry and exit point that have been assigned some application specific meaning by the developer. Usually the objects in a faces flow are designed to allow the user to accomplish a task that requires input over a number of different views. In our case, the navigation between pages for selecting items, entering shipping address, credit card details, and confirmation page would make a flow. All the pages and objects that deal with the checking out process can be composed as modules. An application thus become a collection of flows instead of just views.

It takes the best part of other flow-based technologies such as ADF Task Flow, Spring Web Flow, and Apace MyFaces CODI and standardizes in JSF 2.2.

What is the need ?

Imagine a multi-page shopping cart with one page for selecting the items, a second page for shipping options, a third page for entering credit card details, and a fourth page for final confirmation. Managed Beans can be used to capture the data, session scope variables pass information between pages, button clicks can be used to invoke the business logic in backing EJBs, and (conditional) navigation rules can be defined to go from one page to another. There are a few issues with this approach:
  • This flow of sequence will typically be part of a bigger application. However an application, typically with several pages, is one large flow and everything is visible with no logical partitioning.
  • The flow of pages or views cannot be encapsulated as a logical unit and thus cannot be reused, e.g. incorporated into another bigger flow easily.
  • The lowest logical granularity is a page. The only way to invoke application logic is to tie it to a UI component activated by the user in a page. Business logic cannot be invoked without any user initiated action.
  • Same flow cannot be opened in multiple windows because session scoped variables are used to pass information between pages. CDI defines @ConversationScoped but that is only part of the solution.
  • There is no scope defined that can span multiple pages but less than a session.
Faces Flow provide a solution to the issues mentioned above.

What's new in JSF 2.2 for flows ?

The flow of application is no longer restricted to flow between pages but instead defined as flow between "nodes". There are five different types of nodes:
  • View: Any JSF page in the application
  • Method Call: Invoke application logic from flow graph via an EL
  • Switch: Navigation decisions in the flow graph based on boolean EL
  • Flow Call: Call another flow with parameters and receive return values
  • Flow Return: Return to the calling flow
The nodes define the entry and exit points of a flow.

Two new annotations are introduced:
  • @FlowScoped is a CDI scope that defines the scope of bean in the specified flow. This enables automatic activation/passivation of the bean when the scope is entered/exited.
  • @FlowDefinition is a class level annotation that allows the flow definition to be defined using the fluent FlowBuilder API.
A new EL object, #{flowScope}, for flow local storage is also introduced. This maps to facesContext.getApplication().getFlowHandler().getCurrentFlowScope().

How are flows packaged ?

Flows can be packaged in JAR files or in directories.

JAR packaging requires flows to be explicitly declared in META-INF/faces-config.xml in the JAR file. Flow nodes are packaged in META-INF/flows/<flowname> where <flowname> is a JAR directory entry whose name is identical to that of a flow id in the corresponding faces-config.xml. @FlowScoped and @FlowDefinition beans must be packaged in the JAR file and accompanied by META-INF/beans.xml.

A sample JAR file looks like:

Flows packaged in directories use convention-over-configuration. The conventions are:
  • Every View Declaration Language file in that directory is a view node of that flow.
  • The start node of the flow is the view whose name is the same as the name of the flow.
  • Navigation among any of the views in the directory is considered to be within the flow.
  • Navigation to a view outside of that directory is considered to be an exit of the flow.
  • Optional <flowname>-flow.xml that represents the flow definition. The rules in this file overrides the conventions described above.

A sample directory looks like:

Show me the code!

Lets try a sample now!

The source code for the two samples explained below can be downloaded here. A complete explanation of the sample including the code walk-through is shown in the video:

This will run on GlassFish 4.0 b72. For now, you'll need to replace glassfish/modules/javax.faces.jar with javax.faces-2.2.0-SNAPSHOT.jar and replacing glassfish/modules/javax.el.jar with javax-el-3.0-b03.jar. This JARs will soon be integrated in the GlassFish build. Ah, the joys of bleeding edge development!

profile image
Arun Gupta is a technology enthusiast, a passionate runner, author, and a community guy who works for Oracle Corp.

Java EE 7 Samples

Stay Connected


« January 2013 »