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
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.
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
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 fluentFlowBuilder
API.
#{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:
META-INF/faces-config.xml META-INF/flows/flow1/entry.xhtml META-INF/flows/flow1/next.xhtml META-INF/flows/flow1/end.xhtml META-INF/flows/flow2/start.xhtml META-INF/flows/flow2/next.xhtml META-INF/flows/flow2/end.xhtml META-INF/beans.xml org/glassfish/sample/MyFlow1Bean.class org/glassfish/sample/MyFlow2Bean.class org/glassfish/sample/MyFlowDefintion.classFlows 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:
flow1/flow1.xhtmlShow me the code!
flow1/flow1a.xhtml
flow1/flow1b.xhtml
flow2/flow2-flow.xml
flow2/flow2.xhtml
flow2/flow2a.xhtml
flow2/flow2b.xhtml
WEB-INF/...
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!