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 2016/05/13 22:35:50 UTC

svn commit: r1743767 - in /myfaces/core/trunk/impl/src: main/java/org/apache/myfaces/application/ main/java/org/apache/myfaces/flow/ main/java/org/apache/myfaces/flow/cdi/ main/java/org/apache/myfaces/flow/impl/ main/java/org/apache/myfaces/flow/util/ ...

Author: lu4242
Date: Fri May 13 22:35:49 2016
New Revision: 1743767

URL: http://svn.apache.org/viewvc?rev=1743767&view=rev
Log:
MYFACES-4045 Review Faces Flow reentrant condition

Added:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/util/
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/util/FlowUtils.java
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flowA/
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flowA/content.xhtml
      - copied unchanged from r1743449, myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow5/content.xhtml
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flowA/flowA.xhtml
      - copied, changed from r1743449, myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow5/flow5.xhtml
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flowB/
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flowB/content.xhtml
      - copied unchanged from r1743449, myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow5/content.xhtml
    myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flowB/flowB.xhtml
      - copied, changed from r1743449, myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow5/flow5.xhtml
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/main/java/org/apache/myfaces/flow/cdi/DefaultCDIFacesFlowProvider.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/FlowScopeBeanHolder.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/FlowScopedContextImpl.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/impl/DefaultFacesFlowProvider.java
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/flow/FlowMyFacesCDIRequestTestCase.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/flow_base.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=1743767&r1=1743766&r2=1743767&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 May 13 22:35:49 2016
@@ -564,7 +564,8 @@ public class NavigationHandlerImpl
                 {
                     if (startFlow)
                     {
-                        if (flowHandler.isActive(facesContext, targetFlow.getDefiningDocumentId(), targetFlow.getId()))
+                        if (flowHandler.isActive(facesContext, targetFlow.getDefiningDocumentId(), targetFlow.getId())
+                            && targetFlowCallNode == null)
                         {
                             // Add the transition to exit from the flow
                             Flow baseReturnFlow = navigationContext.getCurrentFlow(facesContext);

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=1743767&r1=1743766&r2=1743767&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 May 13 22:35:49 2016
@@ -232,11 +232,12 @@ public class FlowHandlerImpl extends Flo
         }
         else
         {
-            // Both sourceFlow and targetFlow are not null, so we need to check the direction
+            // Both sourceFlow and targetFlow are not null, if there is no call node set (force enter flow)
+            // 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<_FlowContextualInfo> currentFlowStack = getCurrentFlowStack(context, clientWindow);
-            if (currentFlowStack != null)
+            if (currentFlowStack != null && outboundCallNode == null)
             {
                 FlowReference targetFlowReference = new FlowReference(
                         targetFlow.getDefiningDocumentId(), targetFlow.getId());
@@ -302,7 +303,7 @@ public class FlowHandlerImpl extends Flo
 
         if (sourceFlowIndex != -1)
         {
-            // From sourceFlowIndex, add all flows 
+            // From sourceFlowIndex, remove(add to flowsToRemove list) all flows 
             traverseDependantFlows(sourceFlowReference, sourceFlowIndex+1, currentFlowStack, flowsToRemove);
 
             // Remove all marked elements
@@ -314,7 +315,16 @@ public class FlowHandlerImpl extends Flo
                     FlowReference fr = fci.getFlowReference();
                     doBeforeExitFlow(context, getFlow(context, fr.getDocumentId(), fr.getId()));
                     //popFlowReference(context, clientWindow, currentFlowStack, i);
-                    currentFlowStack.remove(fci);
+
+                    //Remove flows from the last to the first to keep the right sequence.
+                    for (int j = currentFlowStack.size()-1; j >= 0; j--)
+                    {
+                        if (currentFlowStack.get(j) == fci)
+                        {
+                            currentFlowStack.remove(j);
+                            break;
+                        }
+                    }
                 }
             }
 

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/DefaultCDIFacesFlowProvider.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/DefaultCDIFacesFlowProvider.java?rev=1743767&r1=1743766&r2=1743767&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/DefaultCDIFacesFlowProvider.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/DefaultCDIFacesFlowProvider.java Fri May 13 22:35:49 2016
@@ -27,6 +27,7 @@ import javax.enterprise.inject.spi.BeanM
 import javax.faces.context.FacesContext;
 import javax.faces.flow.Flow;
 import org.apache.myfaces.cdi.util.CDIUtils;
+import org.apache.myfaces.flow.util.FlowUtils;
 import org.apache.myfaces.spi.FacesFlowProvider;
 
 /**
@@ -102,8 +103,7 @@ public class DefaultCDIFacesFlowProvider
                 mapKey);
             if (map == null)
             {
-                map = new FlowScopeMap(getBeanManager(), flow.getClientWindowFlowId(
-                    facesContext.getExternalContext().getClientWindow()));
+                map = new FlowScopeMap(getBeanManager(), FlowUtils.getFlowMapKey(facesContext, flow));
                 
                 facesContext.getAttributes().put(mapKey, map);
             }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/FlowScopeBeanHolder.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/FlowScopeBeanHolder.java?rev=1743767&r1=1743766&r2=1743767&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/FlowScopeBeanHolder.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/FlowScopeBeanHolder.java Fri May 13 22:35:49 2016
@@ -45,7 +45,7 @@ import org.apache.myfaces.cdi.view.Appli
 import org.apache.myfaces.context.ReleaseableExternalContext;
 import org.apache.myfaces.context.servlet.StartupFacesContextImpl;
 import org.apache.myfaces.context.servlet.StartupServletExternalContextImpl;
-import org.apache.myfaces.flow.FlowReference;
+import org.apache.myfaces.flow.util.FlowUtils;
 import org.apache.myfaces.shared.config.MyfacesConfig;
 import org.apache.myfaces.shared.context.ExceptionHandlerImpl;
 
@@ -308,26 +308,6 @@ public class FlowScopeBeanHolder impleme
         }
     }
     
-    public String getFlowMapKey(FacesContext facesContext, FlowReference flowReference)
-    {
-        Flow flow = null;
-        if (flowReference.getDocumentId() == null)
-        {
-            flow = facesContext.getApplication().getFlowHandler().getFlow(
-                facesContext, "", flowReference.getId());
-        }
-        else
-        {
-            flow = facesContext.getApplication().getFlowHandler().getFlow(
-                facesContext, flowReference.getDocumentId(), flowReference.getId());
-        }
-        if (flow != null)
-        {
-            return flow.getClientWindowFlowId(facesContext.getExternalContext().getClientWindow());
-        }
-        return null;
-    }
-
     public void createCurrentFlowScope(FacesContext facesContext)
     {
         ClientWindow cw = facesContext.getExternalContext().getClientWindow();
@@ -335,8 +315,7 @@ public class FlowScopeBeanHolder impleme
         
         FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
         Flow flow = flowHandler.getCurrentFlow(facesContext);
-        String flowMapKey = flow.getClientWindowFlowId(
-            facesContext.getExternalContext().getClientWindow());
+        String flowMapKey = FlowUtils.getFlowMapKey(facesContext, flow);
 
         List<String> activeFlowKeys = activeFlowMapKeys.get(baseKey);
         if (activeFlowKeys == null)
@@ -356,8 +335,7 @@ public class FlowScopeBeanHolder impleme
         
         FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
         Flow flow = flowHandler.getCurrentFlow(facesContext);
-        String flowMapKey = flow.getClientWindowFlowId(
-            facesContext.getExternalContext().getClientWindow());
+        String flowMapKey = FlowUtils.getFlowMapKey(facesContext, flow);
 
         ContextualStorage contextualStorage = storageMap.remove(flowMapKey);
         if (contextualStorage != null)

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/FlowScopedContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/FlowScopedContextImpl.java?rev=1743767&r1=1743766&r2=1743767&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/FlowScopedContextImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/cdi/FlowScopedContextImpl.java Fri May 13 22:35:49 2016
@@ -37,6 +37,7 @@ import org.apache.myfaces.cdi.util.BeanP
 import org.apache.myfaces.cdi.util.ContextualInstanceInfo;
 import org.apache.myfaces.cdi.util.ContextualStorage;
 import org.apache.myfaces.flow.FlowReference;
+import org.apache.myfaces.flow.util.FlowUtils;
 
 /**
  * Minimal implementation of FlowScope.
@@ -110,8 +111,7 @@ public class FlowScopedContextImpl imple
         Flow flow = flowHandler.getCurrentFlow(facesContext);
         if (flow != null)
         {
-            flowMapKey = flow.getClientWindowFlowId(
-                facesContext.getExternalContext().getClientWindow());
+            flowMapKey = FlowUtils.getFlowMapKey(facesContext, flow);
         }
         return flowMapKey;
     }
@@ -182,7 +182,7 @@ public class FlowScopedContextImpl imple
         FlowReference reference = flowBeanReferences.get(((Bean)bean).getBeanClass());
         if (reference != null)
         {
-            String flowMapKey = getFlowScopeBeanHolder().getFlowMapKey(facesContext, reference);
+            String flowMapKey = FlowUtils.getFlowMapKey(facesContext, reference);
             if (flowMapKey != null)
             {
                 ContextualStorage storage = getContextualStorage(false, flowMapKey);
@@ -243,7 +243,7 @@ public class FlowScopedContextImpl imple
         FlowReference reference = flowBeanReferences.get(((Bean)bean).getBeanClass());
         if (reference != null)
         {
-            String flowMapKey = getFlowScopeBeanHolder().getFlowMapKey(facesContext, reference);
+            String flowMapKey = FlowUtils.getFlowMapKey(facesContext, reference);
             if (flowMapKey != null)
             {
                 ContextualStorage storage = getContextualStorage(false, flowMapKey);

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/impl/DefaultFacesFlowProvider.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/impl/DefaultFacesFlowProvider.java?rev=1743767&r1=1743766&r2=1743767&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/impl/DefaultFacesFlowProvider.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/impl/DefaultFacesFlowProvider.java Fri May 13 22:35:49 2016
@@ -24,6 +24,7 @@ import java.util.concurrent.ConcurrentHa
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import javax.faces.flow.Flow;
+import org.apache.myfaces.flow.util.FlowUtils;
 import org.apache.myfaces.spi.FacesFlowProvider;
 
 /**
@@ -62,8 +63,7 @@ public class DefaultFacesFlowProvider ex
     @Override
     public void doBeforeExitFlow(FacesContext facesContext, Flow flow)
     {
-        String flowMapKey = flow.getClientWindowFlowId(
-            facesContext.getExternalContext().getClientWindow());
+        String flowMapKey = FlowUtils.getFlowMapKey(facesContext, flow);
         String fullToken = FLOW_SESSION_MAP_SUBKEY_PREFIX + SEPARATOR_CHAR + flowMapKey;
 
         String mapKey = CURRENT_FLOW_SCOPE_MAP+SEPARATOR_CHAR+
@@ -102,12 +102,11 @@ public class DefaultFacesFlowProvider ex
             map = (Map<Object, Object>) facesContext.getAttributes().get(mapKey);
             if (map == null)
             {
-                String flowMapKey = flow.getClientWindowFlowId(
-                    facesContext.getExternalContext().getClientWindow());
+                String flowMapKey = FlowUtils.getFlowMapKey(facesContext, flow);
                 
-                map = new FlowScopeMap(this, flowMapKey);
                 //String fullToken = FLOW_SESSION_MAP_SUBKEY_PREFIX + SEPARATOR_CHAR + flowMapKey;
                 //map = createOrRestoreMap(facesContext, fullToken);
+                map = new FlowScopeMap(this, flowMapKey);
                 
                 facesContext.getAttributes().put(mapKey, map);
             }

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/util/FlowUtils.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/util/FlowUtils.java?rev=1743767&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/util/FlowUtils.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/flow/util/FlowUtils.java Fri May 13 22:35:49 2016
@@ -0,0 +1,81 @@
+/*
+ * 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.util;
+
+import java.util.List;
+import javax.faces.context.FacesContext;
+import javax.faces.flow.Flow;
+import org.apache.myfaces.flow.FlowHandlerImpl;
+import org.apache.myfaces.flow.FlowReference;
+
+/**
+ *
+ */
+public class FlowUtils
+{
+    public static String getFlowMapKey(FacesContext facesContext, FlowReference flowReference)
+    {
+        Flow flow = null;
+        if (flowReference.getDocumentId() == null)
+        {
+            flow = facesContext.getApplication().getFlowHandler().getFlow(
+                facesContext, "", flowReference.getId());
+        }
+        else
+        {
+            flow = facesContext.getApplication().getFlowHandler().getFlow(
+                facesContext, flowReference.getDocumentId(), flowReference.getId());
+        }
+        if (flow != null)
+        {
+            return FlowUtils.getFlowMapKey(facesContext, flow);
+        }
+        return null;
+    }    
+    
+    public static String getFlowMapKey(FacesContext facesContext, Flow flow)
+    {
+        String flowMapKey = flow.getClientWindowFlowId(
+            facesContext.getExternalContext().getClientWindow());
+        int flowIndex = getFlowIndex(facesContext, flow);
+        if (flowIndex > 0)
+        {
+            flowMapKey = flowMapKey + "_" + flowIndex;
+        }
+        return flowMapKey;
+    }
+    
+    private static int getFlowIndex(FacesContext facesContext, Flow flow)
+    {
+        List<Flow> list = FlowHandlerImpl.getActiveFlows(facesContext, 
+                facesContext.getApplication().getFlowHandler());
+        FlowReference flowRef = new FlowReference(flow.getDefiningDocumentId(), flow.getId());
+        int flowIndex = 0;
+        for (Flow f : list)
+        {
+            FlowReference fr = new FlowReference(f.getDefiningDocumentId(), f.getId());
+            if (flowRef.equals(fr))
+            {
+                flowIndex++;
+            }
+        }
+        return flowIndex;
+    }
+
+}

Modified: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/flow/FlowMyFacesCDIRequestTestCase.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/flow/FlowMyFacesCDIRequestTestCase.java?rev=1743767&r1=1743766&r2=1743767&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/flow/FlowMyFacesCDIRequestTestCase.java (original)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/flow/FlowMyFacesCDIRequestTestCase.java Fri May 13 22:35:49 2016
@@ -247,5 +247,251 @@ public class FlowMyFacesCDIRequestTestCa
         Assert.assertEquals("/flow5/flow5.xhtml", facesContext.getViewRoot().getViewId());
 
         renderResponse();
-    } 
+    }
+    
+    /**
+     * This tests do the following:
+     * 
+     * - Start Flow A
+     * - Call Flow B
+     * - Call Flow A
+     * - Call Flow B
+     * - Return from Flow B
+     * - Return from Flow A
+     * - Return from Flow B
+     */
+    @Test
+    public void testFlowA_1() throws Exception
+    {
+        startViewRequest("/flow_base.xhtml");
+        processLifecycleExecute();
+        
+        ConfigurableNavigationHandler handler = (ConfigurableNavigationHandler) facesContext.getApplication().getNavigationHandler();
+        
+        renderResponse();
+       
+        //Enter flow 1
+        UICommand button = (UICommand) facesContext.getViewRoot().findComponent("mainForm:startFlowA");
+        client.submit(button);
+        
+        processLifecycleExecute();
+        
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowA","valueA_1");
+        Assert.assertEquals("/flowA/flowA.xhtml", facesContext.getViewRoot().getViewId());
+        
+        Flow currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals(currentFlow.getId(), "flowA");
+        
+        renderResponse();
+        
+        UICommand button2 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:call_flow_B");
+        client.submit(button2);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowB", currentFlow.getId());
+        Assert.assertFalse(facesContext.getApplication().getFlowHandler().getCurrentFlowScope().containsKey("flowA"));
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowB","valueB_1");
+        
+        renderResponse();
+        
+        //Check current view is the begin of flow2
+        Assert.assertEquals("/flowB/flowB.xhtml", facesContext.getViewRoot().getViewId());
+        
+        UICommand button3 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:call_flow_A");
+        client.submit(button3);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowA", currentFlow.getId());
+        Assert.assertFalse(facesContext.getApplication().getFlowHandler().getCurrentFlowScope().containsKey("flowB"));
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowA","valueA_2");
+        
+        renderResponse();
+        
+        //Check current view is the begin of flow2
+        Assert.assertEquals("/flowA/flowA.xhtml", facesContext.getViewRoot().getViewId());
+        
+        UICommand button4 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:call_flow_B");
+        client.submit(button4);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowB", currentFlow.getId());
+        Assert.assertFalse(facesContext.getApplication().getFlowHandler().getCurrentFlowScope().containsKey("flowA"));
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowB","valueB_2");
+        
+        renderResponse();
+        
+        //Check current view is the begin of flow2
+        Assert.assertEquals("/flowB/flowB.xhtml", facesContext.getViewRoot().getViewId());
+        
+        UICommand button5 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:end_flow");
+        client.submit(button5);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowA", currentFlow.getId());
+        Assert.assertEquals("valueA_2", facesContext.getApplication().getFlowHandler().getCurrentFlowScope().get("flowA"));
+        
+        renderResponse();
+        
+        UICommand button6 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:end_flow");
+        client.submit(button6);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowB", currentFlow.getId());
+        Assert.assertEquals("valueB_1", facesContext.getApplication().getFlowHandler().getCurrentFlowScope().get("flowB"));
+
+        renderResponse();
+        
+        UICommand button7 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:end_flow");
+        client.submit(button7);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowA", currentFlow.getId());
+        Assert.assertEquals("valueA_1", facesContext.getApplication().getFlowHandler().getCurrentFlowScope().get("flowA"));
+        
+        renderResponse();
+    }
+    
+    @Test
+    public void testFlowA_2() throws Exception
+    {
+        startViewRequest("/flow_base.xhtml");
+        processLifecycleExecute();
+        
+        ConfigurableNavigationHandler handler = (ConfigurableNavigationHandler) facesContext.getApplication().getNavigationHandler();
+        
+        renderResponse();
+       
+        //Enter flow A
+        UICommand button = (UICommand) facesContext.getViewRoot().findComponent("mainForm:startFlowA");
+        client.submit(button);
+        
+        processLifecycleExecute();
+        
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowA","valueA_1");
+        Assert.assertEquals("/flowA/flowA.xhtml", facesContext.getViewRoot().getViewId());
+        
+        Flow currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals(currentFlow.getId(), "flowA");
+        
+        renderResponse();
+        
+        //Go to base
+        UICommand button2 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:go_flow_base");
+        client.submit(button2);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        // We are still on flowA, just returned to base
+        Assert.assertEquals("flowA", currentFlow.getId());
+        
+        renderResponse();
+        
+        //Enter flow B
+        UICommand button3 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:startFlowB");
+        client.submit(button3);
+        
+        processLifecycleExecute();
+        
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowB","valueB_1");
+        Assert.assertEquals("/flowB/flowB.xhtml", facesContext.getViewRoot().getViewId());
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals(currentFlow.getId(), "flowB");
+        
+        renderResponse();
+        
+        // Call flow A through flow call
+        UICommand button4 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:call_flow_A");
+        client.submit(button4);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowA", currentFlow.getId());
+        Assert.assertFalse(facesContext.getApplication().getFlowHandler().getCurrentFlowScope().containsKey("flowB"));
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowA","valueA_2");
+        
+        renderResponse();
+        
+        //Check current view is the begin of flow2
+        Assert.assertEquals("/flowA/flowA.xhtml", facesContext.getViewRoot().getViewId());
+
+        // Call flow B through flow call
+        UICommand button5 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:call_flow_B");
+        client.submit(button5);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowB", currentFlow.getId());
+        Assert.assertFalse(facesContext.getApplication().getFlowHandler().getCurrentFlowScope().containsKey("flowA"));
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowB","valueB_2");
+        
+        renderResponse();
+        
+        //Check current view is the begin of flow2
+        Assert.assertEquals("/flowB/flowB.xhtml", facesContext.getViewRoot().getViewId());
+        
+        UICommand button6 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:end_flow");
+        client.submit(button6);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowA", currentFlow.getId());
+        Assert.assertEquals("valueA_2", facesContext.getApplication().getFlowHandler().getCurrentFlowScope().get("flowA"));
+        
+        renderResponse();
+        
+        UICommand button7 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:end_flow");
+        client.submit(button7);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowB", currentFlow.getId());
+        Assert.assertEquals("valueB_1", facesContext.getApplication().getFlowHandler().getCurrentFlowScope().get("flowB"));
+
+        renderResponse();
+        
+        UICommand button8 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:end_flow");
+        client.submit(button8);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowA", currentFlow.getId());
+        Assert.assertEquals("valueA_1", facesContext.getApplication().getFlowHandler().getCurrentFlowScope().get("flowA"));
+        
+        renderResponse();
+        
+    }
 }

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=1743767&r1=1743766&r2=1743767&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 May 13 22:35:49 2016
@@ -1425,5 +1425,251 @@ public class FlowMyFacesRequestTestCase
         renderResponse();
 
     }
+
+    /**
+     * This tests do the following:
+     * 
+     * - Start Flow A
+     * - Call Flow B
+     * - Call Flow A
+     * - Call Flow B
+     * - Return from Flow B
+     * - Return from Flow A
+     * - Return from Flow B
+     */
+    @Test
+    public void testFlowA_1() throws Exception
+    {
+        startViewRequest("/flow_base.xhtml");
+        processLifecycleExecute();
+        
+        ConfigurableNavigationHandler handler = (ConfigurableNavigationHandler) facesContext.getApplication().getNavigationHandler();
+        
+        renderResponse();
+       
+        //Enter flow 1
+        UICommand button = (UICommand) facesContext.getViewRoot().findComponent("mainForm:startFlowA");
+        client.submit(button);
+        
+        processLifecycleExecute();
+        
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowA","valueA_1");
+        Assert.assertEquals("/flowA/flowA.xhtml", facesContext.getViewRoot().getViewId());
+        
+        Flow currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals(currentFlow.getId(), "flowA");
+        
+        renderResponse();
+        
+        UICommand button2 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:call_flow_B");
+        client.submit(button2);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowB", currentFlow.getId());
+        Assert.assertFalse(facesContext.getApplication().getFlowHandler().getCurrentFlowScope().containsKey("flowA"));
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowB","valueB_1");
+        
+        renderResponse();
+        
+        //Check current view is the begin of flow2
+        Assert.assertEquals("/flowB/flowB.xhtml", facesContext.getViewRoot().getViewId());
+        
+        UICommand button3 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:call_flow_A");
+        client.submit(button3);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowA", currentFlow.getId());
+        Assert.assertFalse(facesContext.getApplication().getFlowHandler().getCurrentFlowScope().containsKey("flowB"));
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowA","valueA_2");
+        
+        renderResponse();
+        
+        //Check current view is the begin of flow2
+        Assert.assertEquals("/flowA/flowA.xhtml", facesContext.getViewRoot().getViewId());
+        
+        UICommand button4 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:call_flow_B");
+        client.submit(button4);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowB", currentFlow.getId());
+        Assert.assertFalse(facesContext.getApplication().getFlowHandler().getCurrentFlowScope().containsKey("flowA"));
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowB","valueB_2");
+        
+        renderResponse();
+        
+        //Check current view is the begin of flow2
+        Assert.assertEquals("/flowB/flowB.xhtml", facesContext.getViewRoot().getViewId());
+        
+        UICommand button5 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:end_flow");
+        client.submit(button5);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowA", currentFlow.getId());
+        Assert.assertEquals("valueA_2", facesContext.getApplication().getFlowHandler().getCurrentFlowScope().get("flowA"));
+        
+        renderResponse();
+        
+        UICommand button6 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:end_flow");
+        client.submit(button6);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowB", currentFlow.getId());
+        Assert.assertEquals("valueB_1", facesContext.getApplication().getFlowHandler().getCurrentFlowScope().get("flowB"));
+
+        renderResponse();
+        
+        UICommand button7 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:end_flow");
+        client.submit(button7);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowA", currentFlow.getId());
+        Assert.assertEquals("valueA_1", facesContext.getApplication().getFlowHandler().getCurrentFlowScope().get("flowA"));
+        
+        renderResponse();
+    }
+    
+    @Test
+    public void testFlowA_2() throws Exception
+    {
+        startViewRequest("/flow_base.xhtml");
+        processLifecycleExecute();
+        
+        ConfigurableNavigationHandler handler = (ConfigurableNavigationHandler) facesContext.getApplication().getNavigationHandler();
+        
+        renderResponse();
+       
+        //Enter flow A
+        UICommand button = (UICommand) facesContext.getViewRoot().findComponent("mainForm:startFlowA");
+        client.submit(button);
+        
+        processLifecycleExecute();
+        
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowA","valueA_1");
+        Assert.assertEquals("/flowA/flowA.xhtml", facesContext.getViewRoot().getViewId());
+        
+        Flow currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals(currentFlow.getId(), "flowA");
+        
+        renderResponse();
+        
+        //Go to base
+        UICommand button2 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:go_flow_base");
+        client.submit(button2);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        // We are still on flowA, just returned to base
+        Assert.assertEquals("flowA", currentFlow.getId());
+        
+        renderResponse();
+        
+        //Enter flow B
+        UICommand button3 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:startFlowB");
+        client.submit(button3);
         
+        processLifecycleExecute();
+        
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowB","valueB_1");
+        Assert.assertEquals("/flowB/flowB.xhtml", facesContext.getViewRoot().getViewId());
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals(currentFlow.getId(), "flowB");
+        
+        renderResponse();
+        
+        // Call flow A through flow call
+        UICommand button4 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:call_flow_A");
+        client.submit(button4);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowA", currentFlow.getId());
+        Assert.assertFalse(facesContext.getApplication().getFlowHandler().getCurrentFlowScope().containsKey("flowB"));
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowA","valueA_2");
+        
+        renderResponse();
+        
+        //Check current view is the begin of flow2
+        Assert.assertEquals("/flowA/flowA.xhtml", facesContext.getViewRoot().getViewId());
+
+        // Call flow B through flow call
+        UICommand button5 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:call_flow_B");
+        client.submit(button5);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowB", currentFlow.getId());
+        Assert.assertFalse(facesContext.getApplication().getFlowHandler().getCurrentFlowScope().containsKey("flowA"));
+        facesContext.getApplication().getFlowHandler().getCurrentFlowScope().put("flowB","valueB_2");
+        
+        renderResponse();
+        
+        //Check current view is the begin of flow2
+        Assert.assertEquals("/flowB/flowB.xhtml", facesContext.getViewRoot().getViewId());
+        
+        UICommand button6 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:end_flow");
+        client.submit(button6);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowA", currentFlow.getId());
+        Assert.assertEquals("valueA_2", facesContext.getApplication().getFlowHandler().getCurrentFlowScope().get("flowA"));
+        
+        renderResponse();
+        
+        UICommand button7 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:end_flow");
+        client.submit(button7);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowB", currentFlow.getId());
+        Assert.assertEquals("valueB_1", facesContext.getApplication().getFlowHandler().getCurrentFlowScope().get("flowB"));
+
+        renderResponse();
+        
+        UICommand button8 = (UICommand) facesContext.getViewRoot().findComponent("mainForm:end_flow");
+        client.submit(button8);
+        
+        processLifecycleExecute();
+        
+        currentFlow = facesContext.getApplication().getFlowHandler().getCurrentFlow(facesContext);
+        Assert.assertNotNull(currentFlow);
+        Assert.assertEquals("flowA", currentFlow.getId());
+        Assert.assertEquals("valueA_1", facesContext.getApplication().getFlowHandler().getCurrentFlowScope().get("flowA"));
+        
+        renderResponse();
+        
+    }
+    
 }

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=1743767&r1=1743766&r2=1743767&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 May 13 22:35:49 2016
@@ -251,5 +251,43 @@
         </navigation-case>
     </navigation-rule>
     
+    <flow-definition id="flowA">
+
+        <flow-return id="end">
+            <from-outcome>exit</from-outcome>
+        </flow-return>
+        
+        <flow-call id="call_flow_B">
+            <flow-reference>
+                <flow-document-id>flow_def_1</flow-document-id>
+                <flow-id>flowB</flow-id>
+            </flow-reference>
+        </flow-call>        
+        
+        <view id="content">
+            <vdl-document>/flowA/content.xhtml</vdl-document>
+        </view>
+        
+    </flow-definition>    
+    
+    <flow-definition id="flowB">
+
+        <flow-return id="end">
+            <from-outcome>exit</from-outcome>
+        </flow-return>
+
+        <flow-call id="call_flow_A">
+            <flow-reference>
+                <flow-document-id>flow_def_1</flow-document-id>
+                <flow-id>flowA</flow-id>
+            </flow-reference>
+        </flow-call>        
+        
+        <view id="content">
+            <vdl-document>/flowB/content.xhtml</vdl-document>
+        </view>
+        
+    </flow-definition>
+    
 </faces-config>
         

Copied: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flowA/flowA.xhtml (from r1743449, myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow5/flow5.xhtml)
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flowA/flowA.xhtml?p2=myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flowA/flowA.xhtml&p1=myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow5/flow5.xhtml&r1=1743449&r2=1743767&rev=1743767&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow5/flow5.xhtml (original)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flowA/flowA.xhtml Fri May 13 22:35:49 2016
@@ -33,6 +33,8 @@
         <h:commandButton value="End" action="content"/>
         <h:commandButton id="end_flow" value="End" action="end"/>
         <h:commandButton id="back_flow" value="Back" action="back"/>
+        <h:commandButton id="go_flow_B" value="Go to base" action="flowB"/>
+        <h:commandButton id="call_flow_B" value="Call Flow B" action="call_flow_B"/>
         <h:commandButton id="go_flow_base" value="Go to base" action="flow_base"/>
     </h:form>
     <!-- resolve outcome is quite useful to check how the flow target is resolved -->

Copied: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flowB/flowB.xhtml (from r1743449, myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow5/flow5.xhtml)
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flowB/flowB.xhtml?p2=myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flowB/flowB.xhtml&p1=myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow5/flow5.xhtml&r1=1743449&r2=1743767&rev=1743767&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow5/flow5.xhtml (original)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flowB/flowB.xhtml Fri May 13 22:35:49 2016
@@ -33,6 +33,8 @@
         <h:commandButton value="End" action="content"/>
         <h:commandButton id="end_flow" value="End" action="end"/>
         <h:commandButton id="back_flow" value="Back" action="back"/>
+        <h:commandButton id="go_flow_A" value="Go to base" action="flowA"/>
+        <h:commandButton id="call_flow_A" value="Call Flow A" action="call_flow_A"/>
         <h:commandButton id="go_flow_base" value="Go to base" action="flow_base"/>
     </h:form>
     <!-- resolve outcome is quite useful to check how the flow target is resolved -->

Modified: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow_base.xhtml
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow_base.xhtml?rev=1743767&r1=1743766&r2=1743767&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow_base.xhtml (original)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/application/flow/flow_base.xhtml Fri May 13 22:35:49 2016
@@ -38,6 +38,9 @@
             <h:commandButton id="returnFlow4" action="back_flow_4" value="Return Flow 4"/>
             <h:commandButton id="returnFlow1_3" action="back_flow_1_3" value="Return from Flow 1 and 3"/>
             <h:commandButton id="returnFlow1_4" action="back_flow_1_4" value="Return from Flow 1 and 4"/>
+            
+            <h:commandButton id="startFlowA" action="flowA" value="Start Flow A"/>            
+            <h:commandButton id="startFlowB" action="flowB" value="Start Flow B"/>
         </h:form>
     </h:panelGrid>
 </h:body>