jsr344-experts@javaserverfaces-spec-public.java.net

[jsr344-experts] [730-Flows] Return node handling

From: Edward Burns <edward.burns_at_oracle.com>
Date: Wed, 27 Feb 2013 05:30:59 -0800

Hello Volunteers,

Leonardo brought up a great point about flow returns. When performing a
flow return the destination node must be determined with respect to the
calling flow.

I asked EG member David Schneider about it and here's what he said:

On 02/25/2013 09:22 PM, Edward Burns wrote:

EB> Let's say we are a few flows deep. Does ADF always allow accessing the
EB> nav rules of the unbounded task flow, as the target of a return node?

>>>>> David Schneider answered:

DS> Hi Ed,

DS> No, ADF does not consult the unbounded flow unless that's the flow the
DS> application is returning too. When executing a flow return ADF moves
DS> back to the previous flow (i.e. the one that called the flow that's
DS> returning) and attempts to navigate from the flow call node using the
DS> outcome returned from the flow.

DS> Another thing ADF does is record the last viewId that was displayed in
DS> the calling flow *before* the flow was called. Then, when returning,
DS> that viewId is displayed again if and only if navigation from the flow
DS> call using the returned outcome does not produce a new viewId. That's
DS> done to ensure a viewId from the now current (top of call stack) flow is
DS> displayed.

This changebundle does the following:

* It implicit navigation can only "see" pages in the current flow.

* Adds API that allows navigation to happen in the scope of the
  preceding flow, if present.

* Adds API that saves the last displayed viewId of the current flow, as
  the flows are being navigated.

SECTION: API changes
--------------------

M jsf-api/src/main/java/javax/faces/lifecycle/Lifecycle.java

- Revert revision 11649, which introduced the requirement to call
  FlowHandler.clientWindowTransition() to Lifecycle.attachWindow().
  This is now handled in RestoreViewPhase.

M requestProcessingLifecycle.fm

- In section 2.2.1 RestoreViewPhase, call clientWindowTransition().

M applicationIntegration.fm

- In section 7.4.2.1, Requirements for Explicit Navigation in Faces Flow
  Call Nodes other than ViewNodes, here is the new text regarding return
  nodes.

  If the node is a ReturnNode obtain its navigation case and call
  FlowHandler.setReturnMode(true). This enables the navigation to
  proceed with respect to the calling flow's navigation rules, or the
  application's navigation rules if there is no calling flow. Start the
  navigation algorithm over using it as the basis but pass the value of
  the symbolic constant javax.faces.flow.FlowHandler.NULL_FLOW as the
  value of the toFlowDocumentId argument. If this does not yield a
  navigation case, call FlowHandler.getLastDisplayedViewId(), which will
  return the last displayed view id of the calling flow, or null if
  there is no such flow. In a finally block, when the re-invocation of
  the navigation algorithms completes, call
  FlowHandler.setReturnMode(false).


M jsf-api/src/main/java/javax/faces/flow/FlowHandler.java

- In getCurrentFlow(), document how return mode works.

+ *
+ * <div class="changed_added_2_2">
+ *
+ * <p>If {_at_link #setReturnMode} had been called with {_at_code true} as the
+ * argument before invoking this method, return the preceding flow on
+ * the stack instead of the actual current flow, or {_at_code null} if there
+ * is no preceding flow. Otherwise, return the current flow.</p>
+ *
+ * </div>

- new method getLastDisplayedViewId(),

+ * <p class="changed_added_2_2">Return the last displayed viewId for the
+ * current flow, as returned by {_at_link #getCurrentFlow(javax.faces.context.FacesContext)},
+ * or {_at_code null} if there is no current flow.</p>
+ *
+ * @param context the {_at_code FacesContext} for the current request.
+ *
+ * @throws NullPointerException if {_at_code context} is {_at_code null}
+ *
+ * @since 2.2
+ */
+
+ public abstract String getLastDisplayedViewId(FacesContext context);

- new method setReturnMode(),

+ * <p class="changed_added_2_2">Enable the correct handling of navigation
+ * when processing a return node. The default {_at_link javax.faces.application.NavigationHandler}
+ * specification requires calling this method with {_at_code true} before processing
+ * the navigation rules for the flow return, and calling this method with
+ * {_at_code false}, from a {_at_code finally} block, immediately afterward.</p>
+ *
+ * @param context the {_at_code FacesContext} for the current request.
 
+ * @param returnMode the return mode for the current flow.
+ *
+ * @throws NullPointerException if {_at_code context} is {_at_code null}.
+ *
+ * @since 2.2
+ */
+
+ public abstract void setReturnMode(FacesContext context, boolean returnMode);
+

- New "toViewId" argument to transition().

+ * @param toViewId the viewId of the view being displayed as a result of
+ * this transition. This parameter makes it possible to implement {_at_link #getLastDisplayedViewId}.
+ *

M jsf-api/src/main/java/javax/faces/flow/Flow.java

- Fix spelling error.


SECTION: Modified Files
-----------------------
M jsf-ri/src/main/java/com/sun/faces/lifecycle/RestoreViewPhase.java

- Because we need the viewId to invoke FlowHandler.transition(), we now
  need to call clientWindowTransition() from RestoreViewPhase instead of
  Lifecycle.attachWindow().

M jsf-ri/src/main/java/com/sun/faces/lifecycle/LifecycleImpl.java

- No longer call clientWindowTransition().

M jsf-ri/src/main/java/com/sun/faces/application/NavigationHandlerImpl.java

- In getNavigationMap(), return the empty map if we are in a flow but the flow has no
  explicitly defined navigation rules.

- In findImplicitMatch(), make it so the navigation can only "see" views
  within the current flow.

- In both places where return nodes are handled, do the right thing with
  respect to the re-invocation of the navigation rules so they operate
  in the context of the calling flow. Also, do the right thing with
  respect to getLastDisplayedViewId().

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

- Implement API changes

M test/web-profile/flow/basic-multi-page-fdl-in-web-inf/src/test/java/com/sun/faces/test/webprofile/flow/basic_in_web_inf/BasicInWebInfFlowEntryExitIT.java
M test/web-profile/flow/multi-page-from-jar/app/src/test/java/com/sun/faces/test/webprofile/flow/basic_multi_page_flow_in_jar/BasicMultiPageFlowInJarEntryExitIT.java
M test/web-profile/flow/basic-multi-page/src/test/java/com/sun/faces/test/webprofile/flow/basic_multi_page/BasicMultiPageFlowEntryExitIT.java
M test/web-profile/flow/basic_faces_flow_call/src/test/java/com/sun/faces/test/webprofile/flow/basic_faces_flow_call/FlowACallsFlowBIT.java
M test/web-profile/flow/basic-implicit/src/test/java/com/sun/faces/test/webprofile/flow/basic_implicit/BasicFlowEntryExitIT.java
D test/web-profile/flow/basic-multi-page-fdl-in-web-inf/src/main/webapp/nonFlow.xhtml
D test/web-profile/flow/multi-page-from-jar/app/src/main/webapp/nonFlow.xhtml
D test/web-profile/flow/basic-multi-page/src/main/webapp/nonFlow.xhtml
D test/web-profile/flow/basic-implicit/src/main/webapp/nonFlow.xhtml

- Test changes.

--