Monday, July 26, 2010

ADF Task Flow Region interaction with Parent Action activity

When you use Task Flows in your ADF 11g Web Application then you probably need to have some ADF Region interaction with other Regions or its containing JSF page. In this blogpost I will show you can control a dynamic Region from a other Region ( Task Flow ) with a Parent Action Activity. Off course you change the bean used for the dynamic region from backing bean scope to session bean scope and call this bean from every Task Flow. This works perfectly but you ADF has a better solution for this and you don't need to change the scope of the dynamic Task Flow bean.

For this blogpost I made an Example with one JSPX page and this page contains two Regions. The first is the Top TF and the second is a dynamic Region with Center 1 & 2 TF. Start is part of the JSPX page and can call the Center 1 & 2 methods directly in the dynamic region bean.
For showing the Center Task Flows from the Top Task Flow you can use the Parent Action activity. 

Here is the code of the main JSPX page with in the start facet ,the two buttons which can call the backingbean methods.
<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <f:view>
    <af:document id="d1" title="Example">
      <af:form id="f1">
        <af:panelStretchLayout id="psl1" startWidth="239px" topHeight="95px">
          <f:facet name="center">
            <af:region value="#{bindings.dynamicRegion1.regionModel}" id="centerRegion"/>
          </f:facet>
          <f:facet name="start">
            <af:panelHeader text="Start" id="ph1" inlineStyle="width:239px; height:423px;">
              <f:facet name="toolbar">
                <af:toolbar id="t1">
                  <af:commandToolbarButton text="Center1"
                                           id="ctb1"
                                           action="#{backingBeanScope.MainRegionHandler.showCenter1TF}"/>
                  <af:commandToolbarButton text="Center2"
                                           id="ctb2"
                                           action="#{backingBeanScope.MainRegionHandler.showCenter2TF}"/>
                </af:toolbar>
              </f:facet>
            </af:panelHeader>
          </f:facet>
          <f:facet name="top">
            <af:region value="#{bindings.top1.regionModel}" id="centerTop"/>
          </f:facet>
        </af:panelStretchLayout>
      </af:form>
    </af:document>
  </f:view>
</jsp:root>
The dynamic region bean with the showCenter1TF and showCenter2TF methods.
package nl.whitehorses.adf.tf.view.beans;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;

import oracle.adf.controller.TaskFlowId;
import oracle.adf.view.rich.context.AdfFacesContext;

public class MainRegionHandler {

    private String taskFlowIdCenter1 = "/WEB-INF/center1.xml#center1";
    private String taskFlowIdCenter2 = "/WEB-INF/center2.xml#center2";
    private String taskFlowId = taskFlowIdCenter1;

    public MainRegionHandler() {
    }

    public TaskFlowId getDynamicTaskFlowId() {
        return TaskFlowId.parse(taskFlowId);
    }

    public String showCenter1TF() {
        taskFlowId = taskFlowIdCenter1;
        AdfFacesContext.getCurrentInstance().addPartialTarget(getUIComponent("centerRegion"));  
        return null;
    }

    public String showCenter2TF() {
        taskFlowId = taskFlowIdCenter2;
        AdfFacesContext.getCurrentInstance().addPartialTarget(getUIComponent("centerRegion"));  
        return null;
    }

    private UIComponent getUIComponent(String name) {
        FacesContext facesCtx = FacesContext.getCurrentInstance();
        return facesCtx.getViewRoot().findComponent(name);
    }

}
From the Start facet on the main page it is easy to show the right Center Task Flow. From the Top Task Flow you need to do more. First you need to change the parent Task Flow. ( this works in a bounded or unbounded Task Flow ). Add two Method Call activities and a Wildcard Control Flow Rule.
You will later call the goCenter1 and goCenter2 Control Flow cases  from the Top Task Flow. This will activate the method call which call the right method in the dynamic region bean. After a successful invocation, it will use the return Control Flow case to return to the page.
The property window of the showCenter1TF Method Call activity looks like this. Here you need to provide the Method value and provide the Fixed Outcome.
Next step is to change the Top Task Flow where you also need to add a Wildcard Control Flow Rule together with two Parent Action activities.
The Parent Action property window looks like this. Here you need to provide the Parent Outcome , this must match with the Control Flow Case of the parent Task Flow and here is the Outcome also return.


And at last the Top fragment with the two buttons which calls the right Control Flow Case.
<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich"
          xmlns:f="http://java.sun.com/jsf/core">
  <af:panelHeader text="Top TF" id="ph1"
                  inlineStyle="width:995px; height:84px;">
              <f:facet name="toolbar">
                <af:toolbar id="t1">
                  <af:commandToolbarButton text="Center1"
                                           id="ctb1"
                                           action="showCenter1TF"/>
                  <af:commandToolbarButton text="Center2"
                                           id="ctb2"
                                           action="showCenter2TF"/>
                </af:toolbar>
              </f:facet>
  </af:panelHeader>
</jsp:root>
That's all and here is the example workspace.

16 comments:

  1. Thanks for this mate. I'm bookmarking this site now. This site is awesome and this will help me in my java training.

    ReplyDelete
  2. I am using UI shell template. in it i have activity that shows in a tab. i cant call another activity using the launcher method because i get a NullPointerError. It cant see the activity under WEB-INF/Flows. How do i over come this?

    ReplyDelete
  3. Hi

    Can you give me more information what you are doing ( in detail )

    thanks Edwin

    ReplyDelete
  4. Hello Edwin, I found your post and example workspace very helpful, thank you. I'm also trying to enhance the functionality of your example by nesting a left hand menu inside tabs, but I'm having some hard time trying to get it right. I was wondering if you could help me understand a little bit more on what I could be doing wrong. The desired layout would look something like this:

    ----------------------
    | Tab 1 | Tab 2
    ----------------------
    | Option 1 | *Content*
    | Option 2 |

    The way I try to achieve this is by using a region at the top for tabs, which updates a dynamic region used for left hand side menu (which is another region) and another dynamic region for the content of the application. I'm also using different beans, one for the tabs, and one bean for each menu that resides inside the tabs. I have doubts about the task flow architecture I'm using, and would like some guidance on that front.

    This comment is getting long and not sure if I'm getting the point across. If you could help me please let me know if I should carry on, or if I should provide an email address so you can contact me in order for me to send you more details. Would be easier to explain with some other way of showing info rather than just plain text, in any case thank you for your time.

    ReplyDelete
  5. Hi,

    you can use the dynamic regions for tab to menu and one for the menu to content

    you dont need parent action unless you want to switch tab from the menu

    make sure that the dynamic regions have sessionscope instead of backingbean scope.

    else you in the menu you will reset the screen.

    thanks

    ReplyDelete
  6. Hi Edwin,

    Once again a very helpful example. It works great for me in JDeveloper (11.1.1.2 and 11.1.1.3) but once I try to deploy it on the weblogic server (10.3) it does not refresh the task flow region anymore. I even tried to deploy it from the console of the embedded WLC but still does not work. Did you notice that also. Any work around.
    Thanks
    Laurent

    ReplyDelete
  7. Hi,

    It should work perfectly.
    Did you deploy it from the application menu and the wls needs to have the adf runtime /webcenter or soa suite add on. And at last you need to enable the jrf option in the wls domain.

    ReplyDelete
  8. Hi Edwin,

    My WLS server has all the modules you mentioned installed and jrf option enabled.
    I tested it on the integrated WLS server that comes with JDev (the same one that startup from within JDeveloper).
    I close JDeveloper, I go to a command line window, type C:\JDeveloper\system11.1.1.2.36.55.36\DefaultDomain\bin\startWebLogic.cmd to start the
    integrated WLS server. I go to the console window for the integrated server : http://localhost:7101/console and
    deploy your application (prior to this in JDeveloper I deployed you app as a .ear file from the application menu).
    When I run the page it will not refresh the region when I click on the button the way it does when I start the application from within JDeveloper.
    Strange!
    I can send you the .ear file that gets created so you can try if you wish.
    Thanks a lot.
    Laurent

    ReplyDelete
  9. Hi,

    Very strange, what can be is that your war deployment profile needs to include more ADF jars.

    The generated ear/war is not the same when you run it on the embedded wls.

    Dont you get any error in the server logs.

    hope this helps.

    ReplyDelete
  10. Hi Edwin,

    I tried to add more jar files etc... but still get the same problem. I check the server and did not get any errors in the log.
    In what way the ear/war are differents?
    Thanks for your time.
    Laurent

    ReplyDelete
  11. Hi,

    Ok send me your project and I will take a look at it.

    send it to biemond at gmail dot com

    thanks

    ReplyDelete
  12. Hi Edwin,

    Thanks for looking at my project. Everything was fine but as you recommended calling main instead of main.jspx made all the difference. It is working great that way with no changes.
    Thanks a lot and I love your blogs.
    Laurent

    ReplyDelete
  13. Hi Edwin,

    Your post is very helpful! I follow your example and almost get what I want to achieve. What I'm trying to do is: I have a parent jsff (in the parentTF). In this jsff, there are two tabs: tab1 and tab2. In tab2, I use a task flow (childTF) as region. I want to click a button in the jsff in the childTF to go back to tab1 and close tab2. I follow your example to have a parent action in the childTF, whose parent outcome points to a method call in the parentTF. In the method call I get the binding of tab1 and tab2, and set their disclosed property. I check that these are properties are successfully set when I click the button in the jsff in the childTF, but I can only see the change to take effect after I refresh the page. Usually we can set the partial trigger to resolve this problem. However that seems doesn't apply to this case, because the tab ui component and the button are in two different jsff. Could you advice how to resolve this problem? Thanks in advance. I appreciate your help!

    -Sa

    ReplyDelete
  14. Hi,

    you should find all the UIcomponents from a managed bean (main page) and lookup the regions, from there you can lookup the other ui components.

    Then with ADFFacesContect fires some ppr. This will work.

    ReplyDelete
  15. Hi Edwin,


    I am using jdeveloper 11.1.2.0.0

    We are using UI shell template. We have an managed bean and we will using

    {
    TabContext tabContext = TabContext.getCurrentInstance();
    try
    {
    tabContext.setMainContent("/WEB-INF/Taskflowxml#task_flow");
    }
    catch (TabContext.TabContentAreaDirtyException toe)
    {
    // TODO: warn user TabContext api needed for this use case.
    }
    In the template we are having two command link in which we are having action listener and we writing as above. In the first taskflow we are showing one jsff . From there we are navigation to Another region of different task flow.
    When i am clicking the one command link in template from second region of another task flow . It is not redirecting to first page.

    I debug the code .Control coming in the action listener of that method as above .From there it went to correct jsff and stopped there.Very weird behavior.

    Plese suggest how to resolve.

    ReplyDelete
    Replies
    1. Hi,

      Don't know exactly what your problem is , Do you add the Tabcontext as parameter on the Task Flows.
      and can you catch the error, maybe add some logging to this catch.

      thanks.

      Delete