Sunday, December 26, 2010

TestCase: Programmatically Navigating in Parent TaskFlow based on outcome of another Taskflow in popup.

This blog contains the test case for the solution of previous blog Programmatically Navigating in Parent TaskFlow based on outcome of another Taskflow in popup.

Testcase:
I have a parent taskflow (say PTF) having a jsff page (say ParentPage) and you can navigate to two other pages Outcome1 and Outcome2 as shown below:


Decision to navigate to either Outcome1 or Outcome2 is based on the return activity of another Taskflow (say CTF2) which is dropped as region in dialog of popup on ParentPage. Since CTF is dropped as a region inside popup we would have to programmatically navigate on parent taskflow(PTF). Also since there could be more than one return activity in CTF to exit taskflow, its just not enough to know that takflow is ended. We also need to know so that we could appropriately take decision. Here are the two outcome of the child taskflow.


As you can see in the child taskflow (CTF) there are two return activities namely ReturnActivity1 and ReturnActivity2. Now lets go the solution.

As a first approach to the solution create a return taskflow parameter for the child taskflow (CTF) as shown and set the value to a pageFlowScope value.


Within the Child taskflow make sure the value of the pageFlowScope parameter is set to correct return activity before the taskflow return activity executes. This could be done either by method call activity return the taskflow return value and setting it to pageFlowScope.


Or by dropping setActionListener on the button/menu that leads to the return activity and set the pageFlowScope on it. On a bean create a method that would act as a finalizer for CTF to capture the value in a variable.

    public String ReturnActivityValue = null;

    public void finalizerForCTF(){
        Map taskFlowReturnParameters = getCurrentTaskFlowReturnParameters();
        ReturnActivityValue = getReturnActivityValue(taskFlowReturnParameters);
     }
    public static TaskFlowId getTaskFlowId() {
        ControllerContext controllerContext = ControllerContext.getInstance();
        ViewPortContext currentViewPort = controllerContext.getCurrentViewPort();
        TaskFlowContext taskFlowContext = currentViewPort.getTaskFlowContext();
        TaskFlowId taskFlowId = taskFlowContext.getTaskFlowId();
        return taskFlowId;
      }   
     public static Map getCurrentTaskFlowReturnParameters() { 
         return getReturnParameters(getTaskFlowId()); 
     }                     
     public static Map getReturnParameters(TaskFlowId taskFlowId) { 
         assert taskFlowId != null;      
         TaskFlowDefinition taskFlowDefinition = getTaskFlowDefinition(taskFlowId); 
         Map namedParameters = taskFlowDefinition.getReturnValues(); 
         return namedParameters; 
       }    
     public static TaskFlowDefinition getTaskFlowDefinition(TaskFlowId taskFlowId) { 
         assert taskFlowId != null;        
         MetadataService metadataService = MetadataService.getInstance(); 
         TaskFlowDefinition taskFlowDefinition = metadataService.getTaskFlowDefinition(taskFlowId); 
         return taskFlowDefinition; 
       }  
   
     public String getReturnActivityValue(Map btfParameters) { 
         HashMap taskFlowParameterValues = new HashMap(); 
         FacesContext facesContext = FacesContext.getCurrentInstance(); 
         Application application = facesContext.getApplication(); 
         AdfFacesContext adfFacesContext = AdfFacesContext.getCurrentInstance(); 
         Map pageFlowScope = adfFacesContext.getPageFlowScope();
         String returnValue = null;
        
         for (Object parameter : btfParameters.values()) { 
           NamedParameter namedParameter = (NamedParameter)parameter; 
           String parameterName = namedParameter.getName(); 
           String parameterExpression = namedParameter.getValueExpression(); 
           Object parameterValue; 
           String stringValue;         
        
           if (parameterExpression == null) { 
             parameterValue = pageFlowScope.get(parameterName); 
           } else { 
             parameterValue = application.evaluateExpressionGet(facesContext, parameterExpression, Object.class); 
           } 
        
           if (parameterValue != null) { 
             try { 
               stringValue = parameterValue.toString(); 
             } catch (Exception e) { 
               stringValue = ""; 
             } 
           } else { 
             stringValue = ""; 
           }
             if("ReturnActivityValue".equalsIgnoreCase(parameterName)){
                 returnValue = stringValue;
             }           
         } 
         return returnValue;
       }


Associate finalizerForCTF() with the CTF takflow as below:



Create a method in bean to associate with the region of CTF taskflow. Here is how method looks:

    private static final String Exit1Value = "RA1";
    private static final String Exit2Value = "RA2";
        public void regionNavationListener(RegionNavigationEvent regionNavigationEvent) {
        if(regionNavigationEvent.getNewViewId() == null && ReturnActivityValue != null){
            if(Exit1Value.equalsIgnoreCase(ReturnActivityValue)){
                navigate("outcome1");
            }else if(Exit2Value.equalsIgnoreCase(ReturnActivityValue)){
                navigate("outcome2");
            }
        }
       
    }
    public void navigate(String controlFlowCase){
        NavigationHandler nvHndlr  =
        FacesContext.getCurrentInstance().getApplication().getNavigationHandler();
        nvHndlr .handleNavigation(FacesContext.getCurrentInstance(), null,
        controlFlowCase);
    }

Associate the method with region navigation listener.

Programmatically Navigating in Parent TaskFlow based on outcome of another Taskflow in popup.

In this article I will to show how can we navigate in parent taskflow based on outcome of another taskflow on the parent page dropped as a region or is being used in a popup. It seems that currently we do not have any public API’s to get these details from the Taskflow. However the good news is an ER 10198616 has been logged by Frank Nimphius to request public API’s for them.

Credit for the solution below goes to Chris Muir and Frank Nimphius for showing me way that led to this solution through thread posted in Oracle forum. Also code to access the taskflow API’s were taken from the blog  JDev: Programmatically capturing task flow parameters.

Issue at hand:
From a parent page a popup is launched that contains a taskflow which contained various ReturnActivity with different outcome. Based on what the outcome value of return activity a navigation in parent taskflow needs to be activated.

Solution:
We could achieve above by:
1. Storing the Taskflow Return Value in a Taskflow Return Parameter.
2. Programmatically capturing the Taskflow Return Parameter value in bean through Taskflow finalizer.
3. In RegionNavigationListener, based on the value captured in step 2, navigate to appropriate view or Taskflow.

To get the closer look you can check post TestCase: Programmatically Navigating in Parent TaskFlow based on outcome of another Taskflow in popup.

How to navigate programmatically using ControlFlow Case.

There are times when we wish to navigate from code instead of using the ‘Action’ property of UI component and at same time we like to use the ControlFlow cases defined in the taskflow. Well if you wish to do that you can use handleNavigation method from NavigationHandler class in javax.faces.application package.

Here is the sample:
            NavigationHandler  nvHndlr = FacesContext.getCurrentInstance().getApplication().getNavigationHandler();
            nvHndlr.handleNavigation(FacesContext.getCurrentInstance(), null, "PROVIDE_CONTROL_FLOW_CASE_NAME");