Skip to main content

Source code revision


revision: 11954
author: edburns
date: 2013-05-09 19:56:02 UTC (3 years)

- Kim Haase uncovered a new corner case.

Consider this flow definition.




index.xhtml calls flow1.

flow1 calls flow2

user clicks button on flow2.xhtml that activates the "exit2" node.

"exit2" returns returnFromFlow2 to flow1.

This activates the "returnFromFlow2" node in flow1.

This causes navigation to the /index.xhtml page in the web-app root, and
does so outside the scope of any flow. In other words, activating
"exit2" in flow2 ultimately causes the entire stack to be popped.

Unfortunately, without this fix, the popping did not happen.

SECTION: Modified Files
M jsf-ri/src/main/java/com/sun/faces/application/

- Unrelated change: remove PENDING comment about flows not working with
redirect. They do.

M jsf-ri/src/main/java/com/sun/faces/flow/

- in getCurrentFlow(), present ArrayIndexOutOfBoundsException in the
event of more pops then depth allows.

- This change must be brought to the EG.

When processing a , it is necessary to keep track of the
number of pop operations which must be performed on the flow stack.
This quantity is called the "pop-depth". Prior to this change, a
only caused *one* pop off the flow stack, regardless of
the number of levels between the current flow and the flow to which
control will ultimately be returned (or the unbounded flow, if the
goes all the way out). This change introduces the
necessary logic to keep track of the pop-depth in both the case of
normal POSTback based navigation, and in the case of GET based

First, let's explain at what point the pop-depth is determined.

When processing nodes, the method pushReturnMode() is
specified to be called whenever another level of the flow stack is to
be popped. When this process has completed and a navigation target
has been identified as a result of the processing of however many
levels of are encountered, pushReturnMode() will have
been called a number of times equal to the pop depth.

Once the pop-depth has been determined, we must explain at what point
it is used. As with all navigation related concerns since JSF 2.0,
two cases must be considered. 1. POSTback based navigation. 2. GET
based navigation. In both cases, there are two points of interest:

a. finding the destination of the (and thus determining
the pop-depth)

b. the subsequent flow stack popping.

CASE 1: POSTback based navigation.

Both a. and b. happen in a single invocation of the call stack of

Part a. happens during processing of the node during the
invokeApplication phase of the lifecycle as a result of a UICommand
component being activated. In CASE 1, there is only 1 occurrence of
part a.

Part b. happens in FlowHandler.transition(). It is within
FlowHandler.transition() that we must use the pop-depth. When calling
FlowHandler.transition() in the case of a flow return, the source flow
will be the current flow and the destination flow will be null. Prior
to this change, the runtime would do a single pop if the destination
flow was null. After this change, instead of just one pop, pop-depth
pops are performed.

CASE 2: GET based navigation.

Part a. happens when rendering the button or link that, when clicked,
would cause the navigation. The pop-depth must be encoded into the
rendering of the component. In CASE 2, there can be multiple such
components on a page, each with its own pop-depth depending on how the
navigation plays out, and each such component is an occurrence of part
a. Thus we need to clear the pop-depth each time it is used.

Part b. happens when the GET request from the previously rendered
component is submitted by the browser. This happens in
FlowHandler.clientWindowTransition(), during RestoreViewPhase.

- Add method getAndClearReturnModeDepth(). This allows part b to

- Modified FlowDeque.pushReturnMode() to fulfill part a.

- In performPops(), which is called from transition() (and therefore
from clientWindowTransition(), perform pop-depth number of pops.

- In clientWindowTransition(), call flowStack.setMaxReturnDepth() with
the decoded return depth.

- Define constant for FLOW_RETURN_DEPTH_PARAM_NAME.

M jsf-ri/src/main/java/com/sun/faces/renderkit/html_basic/

- In addNavigationParams(), encode the pop-depth, obtained from
FlowHandlerImpl.getAndClearReturnModeDepth() in url param.

Change Path Actions
M branches/MOJARRA_2_2X_ROLLING/jsf-ri/src/main/java/com/sun/faces/application/
M branches/MOJARRA_2_2X_ROLLING/jsf-ri/src/main/java/com/sun/faces/flow/
M branches/MOJARRA_2_2X_ROLLING/jsf-ri/src/main/java/com/sun/faces/renderkit/html_basic/
M branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/pom.xml
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/nbactions.xml
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/pom.xml
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main/java
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main/resources
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main/webapp
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main/webapp/WEB-INF
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main/webapp/WEB-INF/beans.xml
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main/webapp/WEB-INF/faces-config.xml
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main/webapp/WEB-INF/glassfish-web.xml
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main/webapp/WEB-INF/web.xml
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main/webapp/flow1
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main/webapp/flow1/flow1.xhtml
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main/webapp/flow1/return2.xhtml
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main/webapp/flow2
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main/webapp/flow2/flow2.xhtml
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/main/webapp/index.xhtml
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/test
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/test/java
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/test/java/com
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/test/java/com/sun
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/test/java/com/sun/faces
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/test/java/com/sun/faces/test
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/test/java/com/sun/faces/test/webprofile
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/test/java/com/sun/faces/test/webprofile/flow
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/test/java/com/sun/faces/test/webprofile/flow/return_from_depth
A branches/MOJARRA_2_2X_ROLLING/test/web-profile/flow/return_from_depth/src/test/java/com/sun/faces/test/webprofile/flow/return_from_depth/
Please Confirm