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:

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.class
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:

flow1/flow1.xhtml
flow1/flow1a.xhtml
flow1/flow1b.xhtml
flow2/flow2-flow.xml
flow2/flow2.xhtml
flow2/flow2a.xhtml
flow2/flow2b.xhtml
WEB-INF/...
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!
Comments:

Cool. It's sad that it took such a long time to standardize such a natural thing. I've implemented this in my servlet-based framework back in 2005.

Posted by vanuatoo on January 28, 2013 at 11:58 PM PST #

I just committed a change to rename the XML element for <faces-flow-definition> to just be <flow-definition>.

Posted by Ed Burns on January 29, 2013 at 10:31 AM PST #

Another good news for Java (or Java EE 6) web-application developers
JSF 2.x is getting matured for modern web-application.
The face flow helps a lot because JSF 2.x has become one of most valued technology/web-framework. Spring/Struts/Servlets is not a good choice for modern web-apps.

Posted by Sree Ramakrishna on February 02, 2013 at 02:35 AM PST #

Vanuatoo, Nice. It would be good if you post and share to public.
It may be sad for some one, but now it is required feature in JSF 2.x to make happy many and new web developers.

Posted by SreeRama on February 02, 2013 at 02:41 AM PST #

Thanks for the great post.
I get an WELD-001303 No active contexts for scope running it on the provided environment. The constructor of Flow1Bean is invoked, after that a proxy is invoked and after that i get the exception I only changed the information which Ed Burns wrote.

Thanks in advance,

Jannis Elgner

Posted by Jannis Elgner on February 05, 2013 at 04:43 AM PST #

Great

Posted by guest on February 05, 2013 at 06:12 AM PST #

Jannie,

Are you using 2.2.0-SNAPSHOT or 2.2.0-m08 ?

Posted by Arun Gupta on February 05, 2013 at 11:58 AM PST #

I tried both in serveral combinations but now i got it working. I changed 2.2.0-SNAPSHOT to 2.2.0-20130126.094249-235 in the pom of your project-sources.

Thank you!!

Posted by Jannis Elgner on February 05, 2013 at 12:53 PM PST #

Jannis,

The APIs are evolving fast and glad you got it working!

Arun

Posted by Arun Gupta on February 06, 2013 at 03:53 AM PST #

Do you have an example of a jsf component that can drive the flow rather than a page? i.e: On a page there is a component that specifies that it would start flow1 and on that page you'd see the output that is the first page of flow1 in the area allocated to the component. Then within the component that area gets replaced with 2nd page of flow1 etc but the outer page remains the same.

Posted by guest on February 28, 2013 at 05:51 AM PST #

I've asked Ed Burns to take a look at your comment and he'll likely respond back.

Posted by Arun Gupta on March 02, 2013 at 04:52 PM PST #

Just fyi that component would have to reset to first page if any of it's inputs changed. Also first page should be driven by first action of the flow vs a page that way you get to populate the first page of the flow in the flow vs from just inputs and also based on the inputs you may chose to navigate to a different start view state in the flow.. It may already work this way but I wanted to make sure this was possible.

Posted by guest on March 02, 2013 at 05:24 PM PST #

I am unable to deploy the application in glassfish which is of version mentioned in the video.Can any one please help me in deploying.
I googled and found that i have to place the war file autodeploy folder. I tried that but it didnt work.

Posted by Aditya D G on July 02, 2013 at 11:24 PM PDT #

Hi Arun.

I deployed the application but navigation between flows is not taking place. Moreover i am getting a compiler error if @FlowDefnition is at the class level in the example, if used the specific version jars you mentioned in the example. I moved that annotation to method level and deployed the application. I am able to deploy but when clicked on any of the buttons to enter into a flow, it is not going.

Please help me.

Posted by Aditya D G on August 16, 2013 at 03:12 AM PDT #

Faces Flow is very helpful for real world project. Happy it is in feature list now

Posted by guest on August 26, 2013 at 04:44 PM PDT #

Adtiya D G

Check out completed Faces Flow sample at:

https://github.com/arun-gupta/javaee7-samples/tree/master/jsf

Let me know if they don't work on GlassFish 4.

Cheers
Arun

Posted by Arun Gupta on September 02, 2013 at 02:07 PM PDT #

Hi Arun.

Faceflow is great as it can solve real flow situation.

Do the faces flow also support subflow?

Consider below scenario:
there are 2 flows:
customer/search_customer.xhtml
customer/customer_details.xhtml

flowB/seach.xhtml
flowB/edit_details.xhtml

here is the flow order:
search_customer.xhtml --> edit customer_details.xhtml --> goto flow B (edit and then save) --> customer_details.xhtml in edit mode.

assume the result of the flowB require to pass to flowA.

The entry point of the customer flow is customer.xhtml
The entry point of the flow B flow is search.xhtml

Do I require to set 1 more flow definition to achieve the above situation?

Please help.

Posted by guest on September 09, 2013 at 04:04 AM PDT #

Post a Comment:
Comments are closed for this entry.
About

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

Search

Archives
« July 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
Today