You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2013/08/30 03:34:44 UTC

svn commit: r1518877 - in /myfaces/core/trunk/impl/src: main/java/org/apache/myfaces/application/ main/java/org/apache/myfaces/flow/ test/java/org/apache/myfaces/application/flow/ test/resources/org/apache/myfaces/application/flow/WEB-INF/ test/resourc...

Author: lu4242
Date: Fri Aug 30 01:34:44 2013
New Revision: 1518877

URL: http://svn.apache.org/r1518877
Log:
MYFACES-3764 Implement FlowHandler.getLastDisplayedViewId(FacesContext context) logic 

Added:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/_FlowContextualInfo.java   (with props)
Modified:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/FlowHandlerImpl.java
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/flow/FlowMyFacesRequestTestCase.java
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/WEB-INF/flow1-flow.xml
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow1/begin.xhtml
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow1/content.xhtml
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow2/begin.xhtml
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow2/content.xhtml

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java?rev=1518877&r1=1518876&r2=1518877&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/NavigationHandlerImpl.java Fri Aug 30 01:34:44 2013
@@ -120,7 +120,8 @@ public class NavigationHandlerImpl
     {
         //NavigationCase navigationCase = getNavigationCase(facesContext, fromAction, outcome);
         NavigationContext navigationContext = new NavigationContext();
-        NavigationCase navigationCase = getNavigationCommand(facesContext, navigationContext, fromAction, outcome);
+        NavigationCase navigationCase = getNavigationCommand(facesContext, navigationContext, fromAction, outcome,
+            toFlowDocumentId);
 
         if (navigationCase != null)
         {
@@ -340,7 +341,7 @@ public class NavigationHandlerImpl
     public NavigationCase getNavigationCase(FacesContext facesContext, String fromAction, String outcome)
     {
         NavigationContext navigationContext = new NavigationContext();
-        return getNavigationCommand(facesContext, navigationContext, fromAction, outcome);
+        return getNavigationCommand(facesContext, navigationContext, fromAction, outcome, null);
     }
     
     public NavigationCase getNavigationCommandFromGlobalNavigationCases(
@@ -388,7 +389,8 @@ public class NavigationHandlerImpl
     }
     
     public NavigationCase getNavigationCommand(
-        FacesContext facesContext, NavigationContext navigationContext, String fromAction, String outcome)
+        FacesContext facesContext, NavigationContext navigationContext, String fromAction, String outcome, 
+        String toFlowDocumentId)
     {
         String viewId = facesContext.getViewRoot() != null ? facesContext.getViewRoot().getViewId() : null;
         NavigationCase navigationCase = getNavigationCommandFromGlobalNavigationCases(
@@ -402,7 +404,11 @@ public class NavigationHandlerImpl
             // has the additional possibility of being a flow id.
             Flow targetFlow = null;
             FlowCallNode targetFlowCallNode = null;
-            if (currentFlow != null)
+            if (toFlowDocumentId != null)
+            {
+                targetFlow = flowHandler.getFlow(facesContext, toFlowDocumentId, outcome);
+            }
+            if (targetFlow == null && currentFlow != null)
             {
                 targetFlow = flowHandler.getFlow(facesContext, currentFlow.getDefiningDocumentId(), outcome);
             }
@@ -595,20 +601,35 @@ public class NavigationHandlerImpl
                                 }                                    
                                 // This is the part when the pseudo "recursive call" is done. 
                                 navigationContext.popFlow(facesContext);
-                                //getNavigationCommand(
-                                //    facesContext, navigationContext, currentFlow.getId(), fromOutcome);
-                                
-                                // TODO: add logic for exit the flow properly
                                 currentFlow = navigationContext.getCurrentFlow(facesContext);
                                 navigationContext.addTargetFlow(currentFlow, null);
                                 outcomeToGo = fromOutcome;
-                                
+                                // The part where FlowHandler.NULL_FLOW is passed as documentId causes the effect of
+                                // do not take into account the documentId of the returned flow in the command. In theory
+                                // there is no Flow with defining documentId as FlowHandler.NULL_FLOW. It has sense
+                                // because the one who specify the return rules should be the current flow after it is
+                                // returned.
                                 navigationCase = getNavigationCommand(facesContext, 
-                                        navigationContext, actionToGo, outcomeToGo);
+                                        navigationContext, actionToGo, outcomeToGo, FlowHandler.NULL_FLOW);
                                 if (navigationCase != null)
                                 {
                                     complete = true;
                                 }
+                                else
+                                {
+                                    // No navigation case
+                                    if (currentFlow != null)
+                                    {
+                                        String lastDisplayedViewId = navigationContext.getLastDisplayedViewId(facesContext, 
+                                            currentFlow);
+                                        if (lastDisplayedViewId != null)
+                                        {
+                                            navigationCase = createNavigationCase(
+                                                viewId, flowNode.getId(), lastDisplayedViewId);
+                                            complete = true;
+                                        }
+                                    }
+                                }
                                 if (currentFlow == null)
                                 {
                                     complete = true;
@@ -1356,6 +1377,7 @@ public class NavigationHandlerImpl
         private List<Flow> targetFlows;
         private List<FlowCallNode> targetFlowCallNodes;
         private List<Flow> currentFlows;
+        private Map<Flow, String> lastDisplayedViewIdMap;
 
         public NavigationContext()
         {
@@ -1418,13 +1440,16 @@ public class NavigationHandlerImpl
                 Flow curFlow = flowHandler.getCurrentFlow(facesContext);
                 // Save the top one
                 currentFlow = curFlow;
-                currentFlows = new ArrayList<Flow>();                
+                currentFlows = new ArrayList<Flow>();
                 if (curFlow != null)
                 {
+                    lastDisplayedViewIdMap = new HashMap<Flow, String>();
                     // Fill the stack
                     while (curFlow != null)
                     {
+                        String lastDisplayedViewId = flowHandler.getLastDisplayedViewId(facesContext);
                         currentFlows.add(0,curFlow);
+                        lastDisplayedViewIdMap.put(curFlow, lastDisplayedViewId);
                         flowHandler.pushReturnMode(facesContext);
                         curFlow = flowHandler.getCurrentFlow(facesContext);
                     }
@@ -1461,5 +1486,14 @@ public class NavigationHandlerImpl
         {
             currentFlows.add(flow);
         }
+        
+        public String getLastDisplayedViewId(FacesContext facesContext, Flow flow)
+        {
+            if (lastDisplayedViewIdMap != null)
+            {
+                return lastDisplayedViewIdMap.get(flow);
+            }
+            return null;
+        }
     }
 }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/FlowHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/FlowHandlerImpl.java?rev=1518877&r1=1518876&r2=1518877&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/FlowHandlerImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/FlowHandlerImpl.java Fri Aug 30 01:34:44 2013
@@ -164,14 +164,13 @@ public class FlowHandlerImpl extends Flo
         }
         
         
-        FlowReference flowReference = getCurrentFlowReference(context, clientWindow);
-        //String flowReference = getCurrentFlowReference(context, clientWindow);
-        if (flowReference == null)
+        _FlowContextualInfo info = getCurrentFlowReference(context, clientWindow);
+        if (info == null)
         {
             return null;
         }
+        FlowReference flowReference = info.getFlowReference();
         return getFlow(context, flowReference.getDocumentId(), flowReference.getId());
-        //return getFlow(context, null, flowReference);
     }
     
     @Override
@@ -202,19 +201,20 @@ public class FlowHandlerImpl extends Flo
                 targetFlow, !outboundCallNodeProcessed ? outboundCallNode : null);
             outboundCallNodeProcessed = true;
             pushFlowReference(context, clientWindow, 
-                    new FlowReference(targetFlow.getDefiningDocumentId(), targetFlow.getId()));
+                    new FlowReference(targetFlow.getDefiningDocumentId(), targetFlow.getId()), toViewId);
             doAfterEnterFlow(context, targetFlow, outboundParameters);
         }
         else if (targetFlow == null)
         {
             // Getting out of the flow, since targetFlow is null, just clear the stack
-            List<FlowReference> currentFlowStack = getCurrentFlowStack(context, clientWindow);
+            List<_FlowContextualInfo> currentFlowStack = getCurrentFlowStack(context, clientWindow);
             if (currentFlowStack != null)
             {
                 //currentFlowStack.clear();
                 for (int i = currentFlowStack.size()-1; i >= 0; i--)
                 {
-                    FlowReference fr = currentFlowStack.get(i);
+                    _FlowContextualInfo fci = currentFlowStack.get(i);
+                    FlowReference fr = fci.getFlowReference();
                     doBeforeExitFlow(context, getFlow(context, fr.getDocumentId(), fr.getId()));
                     currentFlowStack.remove(i);
                 }
@@ -225,17 +225,26 @@ public class FlowHandlerImpl extends Flo
             // Both sourceFlow and targetFlow are not null, so we need to check the direction
             // If targetFlow is on the stack, remove elements until get there.
             // If targetFlow is not there, add it to the stack.
-            List<FlowReference> currentFlowStack = getCurrentFlowStack(context, clientWindow);
+            List<_FlowContextualInfo> currentFlowStack = getCurrentFlowStack(context, clientWindow);
             if (currentFlowStack != null)
             {
                 FlowReference targetFlowReference = new FlowReference(
                         targetFlow.getDefiningDocumentId(), targetFlow.getId());
-                int targetFlowIndex = currentFlowStack.lastIndexOf(targetFlowReference);
+                int targetFlowIndex = -1;
+                for (int j = currentFlowStack.size()-1; j >= 0; j--)
+                {
+                    if (targetFlowReference.equals(currentFlowStack.get(j).getFlowReference()))
+                    {
+                        targetFlowIndex = j;
+                        break;
+                    }
+                }
                 if (targetFlowIndex >= 0)
                 {
                     for (int i = currentFlowStack.size()-1; i > targetFlowIndex; i--)
                     {
-                        FlowReference fr = currentFlowStack.get(i);
+                        _FlowContextualInfo fci = currentFlowStack.get(i);
+                        FlowReference fr = fci.getFlowReference();
                         doBeforeExitFlow(context, getFlow(context, fr.getDocumentId(), fr.getId()));
                         currentFlowStack.remove(i);
                     }
@@ -245,22 +254,22 @@ public class FlowHandlerImpl extends Flo
                     // sourceFlow should match.
                     FlowReference sourceFlowReference = new FlowReference(
                             sourceFlow.getDefiningDocumentId(), sourceFlow.getId());
-                    if ( sourceFlowReference.equals(currentFlowStack.get(currentFlowStack.size()-1)) )
+                    if ( sourceFlowReference.equals(currentFlowStack.get(currentFlowStack.size()-1).getFlowReference()) )
                     {
                         Map<String, Object> outboundParameters = doBeforeEnterFlow(context,
                             targetFlow, !outboundCallNodeProcessed ? outboundCallNode : null);
                         outboundCallNodeProcessed = true;
                         pushFlowReference(context, clientWindow, 
-                                new FlowReference(targetFlow.getDefiningDocumentId(), targetFlow.getId()));
+                                new FlowReference(targetFlow.getDefiningDocumentId(), targetFlow.getId()), toViewId);
                         doAfterEnterFlow(context, targetFlow, outboundParameters);
                     }
                     else
                     {
                         // Chain gets broken. Clear stack and start again.
-                        //currentFlowStack.clear();
                         for (int i = currentFlowStack.size()-1; i >= 0; i--)
                         {
-                            FlowReference fr = currentFlowStack.get(i);
+                            _FlowContextualInfo fci = currentFlowStack.get(i);
+                            FlowReference fr = fci.getFlowReference();
                             doBeforeExitFlow(context, getFlow(context, fr.getDocumentId(), fr.getId()));
                             currentFlowStack.remove(i);
                         }
@@ -269,7 +278,7 @@ public class FlowHandlerImpl extends Flo
                             targetFlow, !outboundCallNodeProcessed ? outboundCallNode : null);
                         outboundCallNodeProcessed = true;
                         pushFlowReference(context, clientWindow, 
-                                new FlowReference(targetFlow.getDefiningDocumentId(), targetFlow.getId()));
+                                new FlowReference(targetFlow.getDefiningDocumentId(), targetFlow.getId()), toViewId);
                         doAfterEnterFlow(context, targetFlow, outboundParameters);
                     }
                 }
@@ -280,7 +289,7 @@ public class FlowHandlerImpl extends Flo
                     targetFlow, !outboundCallNodeProcessed ? outboundCallNode : null);
                 outboundCallNodeProcessed = true;
                 pushFlowReference(context, clientWindow, 
-                        new FlowReference(targetFlow.getDefiningDocumentId(), targetFlow.getId()));
+                        new FlowReference(targetFlow.getDefiningDocumentId(), targetFlow.getId()), toViewId);
                 doAfterEnterFlow(context, targetFlow, outboundParameters);
             }
         }
@@ -369,15 +378,19 @@ public class FlowHandlerImpl extends Flo
         Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
         String currentFlowMapKey = CURRENT_FLOW_STACK + clientWindow.getId();
 
-        List<FlowReference> currentFlowStack = (List<FlowReference>) sessionMap.get(currentFlowMapKey);
+        List<_FlowContextualInfo> currentFlowStack = (List<_FlowContextualInfo>) sessionMap.get(currentFlowMapKey);
         if (currentFlowStack == null)
         {
             return false;
         }
         FlowReference reference = new FlowReference(definingDocumentId, id);
-        if (currentFlowStack.contains(reference))
+        
+        for (_FlowContextualInfo info : currentFlowStack)
         {
-            return true;
+            if (reference.equals(info.getFlowReference()))
+            {
+                return true;
+            }
         }
         return false;
     }
@@ -395,43 +408,6 @@ public class FlowHandlerImpl extends Flo
         // throw new UnsupportedOperationException("Not supported yet.");
     }
 
-    /**
-     * TODO: Something like this should be included in the spec.
-     * 
-     * @param context
-     * @return 
-     */
-    private List<Flow> getFlowStack(FacesContext context)
-    {
-        Object session = context.getExternalContext().getSession(false);
-        if (session != null)
-        {
-            return Collections.emptyList();
-        }
-        ClientWindow clientWindow = context.getExternalContext().getClientWindow();
-        if (clientWindow == null)
-        {
-            return Collections.emptyList();
-        }
-        
-        Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
-        String currentFlowMapKey = CURRENT_FLOW_STACK + clientWindow.getId();
-        //LinkedList<FlowReference> currentFlowStack = (LinkedList<FlowReference>) sessionMap.get(currentFlowMapKey);
-        List<FlowReference> currentFlowStack = (List<FlowReference>) sessionMap.get(currentFlowMapKey);
-        if (currentFlowStack == null)
-        {
-            return Collections.emptyList();
-        }
-
-        // Convert flowReference list into Flow list
-        List<Flow> flowList = new ArrayList<Flow>(currentFlowStack.size());
-        for (FlowReference flowReference : currentFlowStack)
-        {
-            flowList.add(getFlow(context, flowReference.getDocumentId(), flowReference.getId()));
-        }
-        return flowList;
-    }
-
     private void checkNull(final Object o, final String param)
     {
         if (o == null)
@@ -452,15 +428,16 @@ public class FlowHandlerImpl extends Flo
         }
     }
     
-    private FlowReference getCurrentFlowReference(FacesContext context, ClientWindow clientWindow)
+    private _FlowContextualInfo getCurrentFlowReference(FacesContext context, ClientWindow clientWindow)
     {
         if ( Boolean.TRUE.equals(context.getAttributes().get(RETURN_MODE)) )
         {
-            List<FlowReference> returnFlowList = getCurrentReturnModeFlowStack(
+            List<_FlowContextualInfo> returnFlowList = getCurrentReturnModeFlowStack(
                     context, clientWindow, CURRENT_FLOW_REQUEST_STACK);
             if (returnFlowList != null && !returnFlowList.isEmpty())
             {
-                return returnFlowList.get(returnFlowList.size()-1);
+                _FlowContextualInfo info = returnFlowList.get(returnFlowList.size()-1);
+                return info;
             }
             return null;
         }
@@ -468,55 +445,59 @@ public class FlowHandlerImpl extends Flo
         {
             Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
             String currentFlowMapKey = CURRENT_FLOW_STACK + clientWindow.getId();
-            List<FlowReference> currentFlowStack = (List<FlowReference>) sessionMap.get(currentFlowMapKey);
+            List<_FlowContextualInfo> currentFlowStack = 
+                (List<_FlowContextualInfo>) sessionMap.get(currentFlowMapKey);
             if (currentFlowStack == null)
             {
                 return null;
             }
-            return currentFlowStack.size() > 0 ? currentFlowStack.get(currentFlowStack.size()-1) : null;
+            return currentFlowStack.size() > 0 ? 
+                currentFlowStack.get(currentFlowStack.size()-1) : null;
         }
     }
     
-    private void pushFlowReference(FacesContext context, ClientWindow clientWindow, FlowReference flowReference)
+    private void pushFlowReference(FacesContext context, ClientWindow clientWindow, FlowReference flowReference,
+        String lastDisplayedViewId)
     {
         Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
         String currentFlowMapKey = CURRENT_FLOW_STACK + clientWindow.getId();
-        //LinkedList<FlowReference> currentFlowStack = (LinkedList<FlowReference>) sessionMap.get(currentFlowMapKey);
-        List<FlowReference> currentFlowStack = (List<FlowReference>) sessionMap.get(currentFlowMapKey);
+        List<_FlowContextualInfo> currentFlowStack = (List<_FlowContextualInfo>) sessionMap.get(currentFlowMapKey);
         if (currentFlowStack == null)
         {
-            currentFlowStack = new ArrayList<FlowReference>(4);
+            currentFlowStack = new ArrayList<_FlowContextualInfo>(4);
             sessionMap.put(currentFlowMapKey, currentFlowStack);
         }
-        currentFlowStack.add(flowReference);
-    }
-
-    private FlowReference popFlowReference(FacesContext context, ClientWindow clientWindow)
-    {
-        Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
-        String currentFlowMapKey = CURRENT_FLOW_STACK + clientWindow.getId();
-        //LinkedList<FlowReference> currentFlowStack = (LinkedList<FlowReference>) sessionMap.get(currentFlowMapKey);
-        List<FlowReference> currentFlowStack = (List<FlowReference>) sessionMap.get(currentFlowMapKey);
-        if (currentFlowStack == null)
-        {
-            return null;
-        }
-        return currentFlowStack.size() > 0 ? currentFlowStack.remove(currentFlowStack.size()-1) : null;
+        currentFlowStack.add(new _FlowContextualInfo(flowReference, lastDisplayedViewId));
     }
     
-    private List<FlowReference> getCurrentFlowStack(FacesContext context, ClientWindow clientWindow)
+    private List<_FlowContextualInfo> getCurrentFlowStack(FacesContext context, ClientWindow clientWindow)
     {
         Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
         String currentFlowMapKey = CURRENT_FLOW_STACK + clientWindow.getId();
-        //LinkedList<FlowReference> currentFlowStack = (LinkedList<FlowReference>) sessionMap.get(currentFlowMapKey);
-        List<FlowReference> currentFlowStack = (List<FlowReference>) sessionMap.get(currentFlowMapKey);
+        List<_FlowContextualInfo> currentFlowStack = (List<_FlowContextualInfo>) sessionMap.get(currentFlowMapKey);
         return currentFlowStack;
     }
 
     @Override
     public String getLastDisplayedViewId(FacesContext context)
     {
-        throw new UnsupportedOperationException("Not supported yet.");
+        Object session = context.getExternalContext().getSession(false);
+        if (session == null)
+        {
+            return null;
+        }
+        ClientWindow clientWindow = context.getExternalContext().getClientWindow();
+        if (clientWindow == null)
+        {
+            return null;
+        }
+        
+        _FlowContextualInfo info = getCurrentFlowReference(context, clientWindow);
+        if (info == null)
+        {
+            return null;
+        }
+        return info.getLastDisplayedViewId();
     }
 
     @Override
@@ -548,18 +529,17 @@ public class FlowHandlerImpl extends Flo
         else
         {
             // Return mode not active, activate it, copy the current flow stack.
-            List<FlowReference> currentFlowStack = getCurrentFlowStack(context, clientWindow);
+            List<_FlowContextualInfo> currentFlowStack = getCurrentFlowStack(context, clientWindow);
             
             Map<Object, Object> attributesMap = context.getAttributes();
             String returnFlowMapKey = CURRENT_FLOW_REQUEST_STACK + clientWindow.getId();
-            List<FlowReference> returnFlowStack = new ArrayList<FlowReference>(currentFlowStack);
+            List<_FlowContextualInfo> returnFlowStack = new ArrayList<_FlowContextualInfo>(currentFlowStack);
             attributesMap.put(returnFlowMapKey, returnFlowStack);
             context.getAttributes().put(RETURN_MODE, Boolean.TRUE);
         }
         
-        FlowReference flowReference = popFlowReferenceReturnMode(context, clientWindow, CURRENT_FLOW_REQUEST_STACK);
+        _FlowContextualInfo flowReference = popFlowReferenceReturnMode(context, clientWindow, CURRENT_FLOW_REQUEST_STACK);
         pushFlowReferenceReturnMode(context, clientWindow, FLOW_RETURN_STACK, flowReference);
-        //popFlowReferenceReturnMode(context, clientWindow);
     }
 
     @Override
@@ -572,12 +552,12 @@ public class FlowHandlerImpl extends Flo
             return;
         }
         
-        FlowReference flowReference = popFlowReferenceReturnMode(context, clientWindow, CURRENT_FLOW_REQUEST_STACK);
-        pushFlowReferenceReturnMode(context, clientWindow, FLOW_RETURN_STACK, flowReference);
+        _FlowContextualInfo flowReference = popFlowReferenceReturnMode(context, clientWindow, FLOW_RETURN_STACK);
+        pushFlowReferenceReturnMode(context, clientWindow, CURRENT_FLOW_REQUEST_STACK, flowReference);
         
         Map<Object, Object> attributesMap = context.getAttributes();
-        String returnFlowMapKey = CURRENT_FLOW_REQUEST_STACK + clientWindow.getId();
-        List<FlowReference> returnFlowStack = (List<FlowReference>) attributesMap.get(returnFlowMapKey);
+        String returnFlowMapKey = FLOW_RETURN_STACK + clientWindow.getId();
+        List<_FlowContextualInfo> returnFlowStack = (List<_FlowContextualInfo>) attributesMap.get(returnFlowMapKey);
         if (returnFlowStack != null && returnFlowStack.isEmpty())
         {
             context.getAttributes().put(RETURN_MODE, Boolean.FALSE);
@@ -585,28 +565,25 @@ public class FlowHandlerImpl extends Flo
     }
 
     private void pushFlowReferenceReturnMode(FacesContext context, ClientWindow clientWindow,
-            String stackKey, FlowReference flowReference)
+            String stackKey, _FlowContextualInfo flowReference)
     {
         Map<Object, Object> attributesMap = context.getAttributes();
         String currentFlowMapKey = stackKey + clientWindow.getId();
-        //LinkedList<FlowReference> currentFlowStack = (LinkedList<FlowReference>) sessionMap.get(currentFlowMapKey);
-        List<FlowReference> currentFlowStack = (List<FlowReference>) attributesMap.get(currentFlowMapKey);
+        List<_FlowContextualInfo> currentFlowStack = (List<_FlowContextualInfo>) attributesMap.get(currentFlowMapKey);
         if (currentFlowStack == null)
         {
-            //currentFlowStack = new LinkedList<FlowReference>();
-            currentFlowStack = new ArrayList<FlowReference>(4);
+            currentFlowStack = new ArrayList<_FlowContextualInfo>(4);
             attributesMap.put(currentFlowMapKey, currentFlowStack);
         }
         currentFlowStack.add(flowReference);
     }
 
-    private FlowReference popFlowReferenceReturnMode(FacesContext context, ClientWindow clientWindow,
+    private _FlowContextualInfo popFlowReferenceReturnMode(FacesContext context, ClientWindow clientWindow,
             String stackKey)
     {
         Map<Object, Object> attributesMap = context.getAttributes();
         String currentFlowMapKey = stackKey + clientWindow.getId();
-        //LinkedList<FlowReference> currentFlowStack = (LinkedList<FlowReference>) sessionMap.get(currentFlowMapKey);
-        List<FlowReference> currentFlowStack = (List<FlowReference>) attributesMap.get(currentFlowMapKey);
+        List<_FlowContextualInfo> currentFlowStack = (List<_FlowContextualInfo>) attributesMap.get(currentFlowMapKey);
         if (currentFlowStack == null)
         {
             return null;
@@ -614,45 +591,12 @@ public class FlowHandlerImpl extends Flo
         return currentFlowStack.size() > 0 ? currentFlowStack.remove(currentFlowStack.size()-1) : null;
     }
     
-    private List<FlowReference> getCurrentReturnModeFlowStack(FacesContext context, ClientWindow clientWindow,
+    private List<_FlowContextualInfo> getCurrentReturnModeFlowStack(FacesContext context, ClientWindow clientWindow,
             String stackKey)
     {
         Map<Object, Object> attributesMap = context.getAttributes();
         String currentFlowMapKey = stackKey + clientWindow.getId();
-        //LinkedList<FlowReference> currentFlowStack = (LinkedList<FlowReference>) sessionMap.get(currentFlowMapKey);
-        List<FlowReference> currentFlowStack = (List<FlowReference>) attributesMap.get(currentFlowMapKey);
+        List<_FlowContextualInfo> currentFlowStack = (List<_FlowContextualInfo>) attributesMap.get(currentFlowMapKey);
         return currentFlowStack;
     }
-        
-    private class FlowContext
-    {
-        public final static String FLOW_CONTEXT_KEY = "oam.flow.CTX";
-        
-        private List<String> currentFlowStack;
-        private int index;
-
-        public FlowContext getFlowContext(FacesContext facesContext)
-        {
-            FlowContext fctx = (FlowContext) facesContext.getAttributes().get(FLOW_CONTEXT_KEY);
-            if (fctx == null)
-            {
-                fctx = new FlowContext();
-            }
-            return fctx;
-        }
-        
-        public List<String> getCurrentFlowStack(FacesContext facesContext)
-        {
-            if (currentFlowStack == null)
-            {
-                Map<String, Object> sessionMap = facesContext.getExternalContext().getSessionMap();
-                String currentFlowMapKey = CURRENT_FLOW_STACK + 
-                    facesContext.getExternalContext().getClientWindow().getId();
-                // LinkedList<FlowReference> currentFlowStack = 
-                // (LinkedList<FlowReference>) sessionMap.get(currentFlowMapKey);
-                currentFlowStack = (List<String>) sessionMap.get(currentFlowMapKey);
-            }
-            return currentFlowStack;
-        }
-    }
 }

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/_FlowContextualInfo.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/_FlowContextualInfo.java?rev=1518877&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/_FlowContextualInfo.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/_FlowContextualInfo.java Fri Aug 30 01:34:44 2013
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.flow;
+
+import java.io.Serializable;
+
+/**
+ *
+ * @author lu4242
+ */
+class _FlowContextualInfo implements Serializable
+{
+    private static final long serialVersionUID = -3732849062185115847L;
+    
+    private FlowReference flowReference;
+    private String lastDisplayedViewId;
+
+    public _FlowContextualInfo()
+    {
+    }
+    
+    public _FlowContextualInfo(FlowReference flowReference, String lastDisplayedViewId)
+    {
+        this.flowReference = flowReference;
+        this.lastDisplayedViewId = lastDisplayedViewId;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int hash = 3;
+        hash = 23 * hash + (this.flowReference != null ? this.flowReference.hashCode() : 0);
+        hash = 23 * hash + (this.lastDisplayedViewId != null ? this.lastDisplayedViewId.hashCode() : 0);
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        final _FlowContextualInfo other = (_FlowContextualInfo) obj;
+        if (this.flowReference != other.flowReference && (this.flowReference == null || !this.flowReference.equals(other.flowReference)))
+        {
+            return false;
+        }
+        if ((this.lastDisplayedViewId == null) ? (other.lastDisplayedViewId != null) : !this.lastDisplayedViewId.equals(other.lastDisplayedViewId))
+        {
+            return false;
+        }
+        return true;
+    }
+    
+
+    /**
+     * @return the flowReference
+     */
+    public FlowReference getFlowReference()
+    {
+        return flowReference;
+    }
+
+    /**
+     * @param flowReference the flowReference to set
+     */
+    public void setFlowReference(FlowReference flowReference)
+    {
+        this.flowReference = flowReference;
+    }
+
+    /**
+     * @return the lastDisplayedViewId
+     */
+    public String getLastDisplayedViewId()
+    {
+        return lastDisplayedViewId;
+    }
+
+    /**
+     * @param lastDisplayedViewId the lastDisplayedViewId to set
+     */
+    public void setLastDisplayedViewId(String lastDisplayedViewId)
+    {
+        this.lastDisplayedViewId = lastDisplayedViewId;
+    }
+}

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/_FlowContextualInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/flow/FlowMyFacesRequestTestCase.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/flow/FlowMyFacesRequestTestCase.java?rev=1518877&r1=1518876&r2=1518877&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/flow/FlowMyFacesRequestTestCase.java (original)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/flow/FlowMyFacesRequestTestCase.java Fri Aug 30 01:34:44 2013
@@ -163,4 +163,97 @@ public class FlowMyFacesRequestTestCase 
         Assert.assertNull(currentFlow);
         Assert.assertEquals("/flow1_end.xhtml", facesContext.getViewRoot().getViewId());
     }
+    
+    @Test
+    public void testFlow1_3() throws Exception
+    {
+        setupRequest("/flow1_2.xhtml");
+        processLifecycleExecute();
+        
+        ConfigurableNavigationHandler handler = (ConfigurableNavigationHandler) facesContext.getApplication().getNavigationHandler();
+        
+        NavigationCase navCase = handler.getNavigationCase(facesContext, null, "flow1");
+        
+        Assert.assertNotNull(navCase);
+        
+        NavigationCase contentCase = handler.getNavigationCase(facesContext, null, "flow1_content");
+        
+        Assert.assertNull(contentCase);
+        
+        // Check begin view node
+        Assert.assertEquals("/flow1/begin.xhtml", navCase.getToViewId(facesContext));
+        
+        processRender();
+       
+        //Enter flow 1
+        UICommand button = (UICommand) facesContext.getViewRoot().findComponent("mainForm:startFlow1");
+        submit(button);
+        
+        processLifecycleExecute();
+        
+        Flow currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flow1", currentFlow.getId());
+        
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flow1","value1");
+        
+        processRender();
+        
+        UICommand button2 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:call_flow2");
+        submit(button2);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flow2", currentFlow.getId());
+        Assert.assertFalse(facesContext.getApplication().getFlowHandler().getCurrentFlowScope().containsKey("flow1"));
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flow2","value2");
+        
+        processRender();
+        
+        //Check current view is the begin of flow2
+        Assert.assertEquals("/flow2/begin.xhtml", facesContext.getViewRoot().getViewId());
+        
+        UICommand button3 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:content");
+        submit(button3);
+        processLifecycleExecute();
+        processRender();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flow2", currentFlow.getId());
+
+        NavigationCase endCase = handler.getNavigationCase(facesContext, null, "back");
+        Assert.assertNotNull(endCase);
+        
+        UICommand button4 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:back_flow");
+        submit(button4);
+        
+        processLifecycleExecute();
+        
+        // Check it should go back to flow1 
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flow1", currentFlow.getId());
+        Assert.assertTrue(facesContext.getApplication().getFlowHandler().getCurrentFlowScope().containsKey("flow1"));
+        // Check lastDisplayedViewId
+        Assert.assertEquals("/flow1/begin.xhtml", facesContext.getViewRoot().getViewId());
+        
+        processRender();
+        
+        endCase = handler.getNavigationCase(facesContext, null, "back");
+        Assert.assertNotNull(endCase);
+        
+        UICommand button5 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:back_flow");
+        submit(button5);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNull(currentFlow);
+        Assert.assertEquals("/flow1_2.xhtml", facesContext.getViewRoot().getViewId());
+        
+    }
+
 }

Modified: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/WEB-INF/flow1-flow.xml
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/WEB-INF/flow1-flow.xml?rev=1518877&r1=1518876&r2=1518877&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/WEB-INF/flow1-flow.xml (original)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/WEB-INF/flow1-flow.xml Fri Aug 30 01:34:44 2013
@@ -30,6 +30,8 @@
             <from-outcome>exit</from-outcome>
         </flow-return>
         
+        <flow-return id="back"/>
+        
         <navigation-rule>
             <from-view-id>*</from-view-id>
             <navigation-case>
@@ -69,6 +71,14 @@
             <from-outcome>exit</from-outcome>
         </flow-return>
         
+        <!-- The idea of this return is "back" is not mapped to anything,
+             so the navigation algorithm should not return any navigation
+             case and it should be used the last displayed view id by
+             default-->
+        <flow-return id="back">
+            <from-outcome>back</from-outcome>
+        </flow-return>
+        
         <navigation-rule>
             <from-view-id>*</from-view-id>
             <navigation-case>

Modified: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow1/begin.xhtml
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow1/begin.xhtml?rev=1518877&r1=1518876&r2=1518877&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow1/begin.xhtml (original)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow1/begin.xhtml Fri Aug 30 01:34:44 2013
@@ -33,6 +33,8 @@
         <h:commandButton value="End" action="content"/>
         
         <h:commandButton id="call_flow2" value="Start Flow 2" action="call_flow2"/>
+        <h:commandButton id="end_flow" value="End" action="end"/>
+        <h:commandButton id="back_flow" value="Back" action="back"/>
     </h:form>
     <!-- resolve outcome is quite useful to check how the flow target is resolved -->
     <h:link outcome="end" value="End Outcome Link"/>

Modified: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow1/content.xhtml
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow1/content.xhtml?rev=1518877&r1=1518876&r2=1518877&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow1/content.xhtml (original)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow1/content.xhtml Fri Aug 30 01:34:44 2013
@@ -30,7 +30,8 @@
     <h1>Myfaces Flow Examples</h1>
     <h2>begin.xhtml</h2>
     <h:form id="mainForm">
-        <h:commandButton value="End" action="end"/>
+        <h:commandButton id="end_flow" value="End" action="end"/>
+        <h:commandButton id="back_flow" value="Back" action="back"/>
     </h:form>
     <!-- resolve outcome is quite useful to check how the flow target is resolved -->
     <h:link outcome="end" value="End Outcome Link"/>

Modified: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow2/begin.xhtml
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow2/begin.xhtml?rev=1518877&r1=1518876&r2=1518877&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow2/begin.xhtml (original)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow2/begin.xhtml Fri Aug 30 01:34:44 2013
@@ -32,6 +32,7 @@
     <h:form id="mainForm">
         <h:commandButton id="content" value="Content" action="content"/>
         <h:commandButton id="end_flow" value="End" action="end"/>
+        <h:commandButton id="back_flow" value="Back" action="back"/>
     </h:form>
     <!-- resolve outcome is quite useful to check how the flow target is resolved -->
     <h:link outcome="end" value="End Outcome Link"/>

Modified: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow2/content.xhtml
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow2/content.xhtml?rev=1518877&r1=1518876&r2=1518877&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow2/content.xhtml (original)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow2/content.xhtml Fri Aug 30 01:34:44 2013
@@ -31,6 +31,7 @@
     <h2>begin.xhtml</h2>
     <h:form id="mainForm">
         <h:commandButton id="end_flow" value="End" action="end"/>
+        <h:commandButton id="back_flow" value="Back" action="back"/>
     </h:form>
     <!-- resolve outcome is quite useful to check how the flow target is resolved -->
     <h:link outcome="end" value="End Outcome Link"/>