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

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

From: Edward Burns <edward.burns_at_oracle.com>
Date: Tue, 12 Mar 2013 18:01:02 -0700

>>>>> On Mon, 04 Mar 2013 14:22:46 -0700, David Schneider <david.schneider_at_oracle.com> said:

DS> On 02/28/2013 07:41 AM, Leonardo Uribe wrote:
>>> In section 7.4.2.1, Requirements for Explicit Navigation in Faces Flow
EB> Call Nodes other than ViewNodes, here is the new text regarding return
EB> nodes.

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

LU> I don't get these lines. In theory flowDocumentId to use should be the
LU> parent flow flowDocumentId. So, if the node is a ReturnNode, it should
LU> take the outcome, and try to resolve it under the parent flow and if
LU> it resolves to something else the parent flowDocumentId should be
LU> used. If it founds another ReturnNode it should do the same until
LU> the top. The rules that are on top (not bound to any flow and set
LU> globally) only should be consulted if no parent flow is found, respecting
LU> encapsulation principle.

DS> I believe I agree. When exiting a flow the flow being exited should be
DS> "popped" from the flow call stack and navigation should proceed in the
DS> context of the calling flow, with navigation originating from that
DS> flow's call node, and using that flow's navigation rules.

Yes, this is what I have.

DS> The only time navigation should use the null flow is when the whole
DS> call stack has been popped.

The NULL_FLOW value for the toFlowDocumentId argument is just a flag
that means we are in the midst of a flow return and the popped flow is
the one that should be used as the context of the navigation algorithm.

DS> The existence of the return mode attribute in the interface contract
DS> seems to suggest we don't have the separation of responsibilities of the
DS> classes well thought out. It looks like we have a somewhat obtuse way
DS> of performing a push and pop of a window's flow stack using
DS> FlowHandler.transition(), FlowHandler.getCurrentFlow(), and
DS> FlowHandler.setReturnMode(). Maybe it would be more clear if the
DS> operations on the FlowHandler interface were described as stack
DS> operations such as push, pop, and peek.

As I said before, I don't want to expose the stack data structure to the
API to allow for greater flexibility in implementation choice.

>>>>> On Sun, 10 Mar 2013 18:10:55 -0500, Leonardo Uribe <lu4242_at_gmail.com> said:

LU> Thanks David for the clarification. So in this case it is better that the
LU> "global rules" only apply if the stack is clear. I agree. What's important
LU> here is ensure that the developer can nest 2, 3 or many more flows and
LU> in all cases it will work correctly. The API no matter how is done should
LU> reflect that.

Yes, of course the ability to do this nesting is essential, and we have
a working testcase that shows this ability.

LU> I totally agree with you in this case. Currently we have this:

LU> public abstract Flow getCurrentFlow(FacesContext context)
LU> public abstract void setReturnMode(FacesContext context,
LU> boolean returnMode)
LU> public abstract void transition(FacesContext context,
LU> Flow sourceFlow,
LU> Flow targetFlow,
LU> FlowCallNode outboundCallNode,
LU> String toViewId)

LU> transition() method is ok, because you can't nest the same flow twice.
LU> But trying to implement transition() method, I have found that internally
LU> this method requires a stack to do the job.

Yes, of course one needs a stack inside to do the job.

LU> We need an API that can do
LU> two things:

LU> 1. Handle transitions or when to go in/out of a flow, and apply operations
LU> like clear/init flow scope and so on.

LU> 2. Calculate the navigation case taking into account the current context,
LU> traversing the flow structure but without execute any of the steps to be
LU> done for the real navigation.

LU> The api we need is something that can do the calculation without affect
LU> the current state, because that part will be done later in

LU> NavigationHandler.handleNavigation() / FlowHandler.transition()

Yes, and I assert that those operations can be done as an implementation
detail. The important thing is to specify the behavior of the flow
nodes with respect to navigation.

Ed