Friday, January 16, 2009

Passing ADF events between Task Flow regions

Passing events and handle these events in an ADF Task Flow region or page is in JDeveloper 11G very simple and you don't need to program java to achieve this. Lucas already made an article about this where he use java to achieve this.
To explain the ADF way, I made a page which is located in the default unbounded Task Flow adfc-config.xml. This ADF JSF page contains two bounded Task Flows. The Task Flow contains one page fragment with has its own HR department iterator.
In this blog I will show you the different ADF Event options.

Let's start with an easy one. When I press on the next button of the Left department region then I want that the right region also goes to the next department.
First we need to define the event. Start by opening the Left page fragment page ( this page will fire the event) and go the bindings tab. This will give you an overview of the ADF bindings. The Structure window will also give you an overview. Here we will select the Next action

Use the right button so we can add the events element to this action binding.

Add an event element to the events element.


Give the event a meaningfull name

That's all for defining event on a binding. You can add an event on every adf binding type( For example, a methodaction, an action or an attributevalue)
This is how it looks in the pagedef.

<action IterBinding="DepartmentsViewTFLeftIterator" id="Next"
RequiresUpdateModel="true" Action="next">
<events xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
<event name="LeftNext"/>
</events>
</action>

The next step is to do something with this event. For this we need to open jsf the page which contains the departments Task Flow regions. This pagedef is the event mediator. It listen for events and can start the action or method in a pagedef.
Go the bindings tab of the jsf page and open the structure window.

Select the pagedef root node and press Edit Event Map


This opens the event wizard where we can add a new eventmap entry
We need to select the producer of the event. Go the pagedef of the department region and select the LeftNext event.

The next step is to select the action or method action in the other department region pagedf. You can only select action or methodactions. That's all. The next button in the left department also fire the next action of the right department region.

This is how the pagedef of the main jsf page looks like

<?xml version="1.0" encoding="UTF-8" ?>
<pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel"
version="11.1.1.51.88" id="mainPageDef"
Package="nl.whitehorses.view.pageDefs">
<parameters/>
<executables>
<taskFlow id="taskflowdefinitionleft1"
taskFlowId="/WEB-INF/task-flow-definition-left.xml#task-flow-definition-left"
xmlns="http://xmlns.oracle.com/adf/controller/binding"/>
<taskFlow id="taskflowdefinitionright1"
taskFlowId="/WEB-INF/task-flow-definition-right.xml#task-flow-definition-right"
xmlns="http://xmlns.oracle.com/adf/controller/binding"/>
</executables>
<bindings/>
<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
<event name="LeftNext">
<producer region="taskflowdefinitionleft1.leftPageDef.Next">
<consumer region="taskflowdefinitionright1"
handler="rightPageDef.Next"/>
</producer>
</event>
</eventMap>
</pageDefinition>


We can make it more complex by adding parameters to an event. For this I will add an event to SetCurrentRowWithKeyValue operation in the left department and fire the SetCurrentRowWithKeyValue of the right region. So I can lookup the department in the left and right department region. The only difference with this and the Next action is that we need to pass the rowKey variable. We have to do the same actions as with the Next action event.
Add the rowKey variable and its value.
In my case I add a setActionlistener to the button which fires the setCurrentRow operation. This setActionlistener copies the rowkey to the request bean or you can use the special PayLoad variable.
The Payload variable has some handy attributes. For Example is you add an event on an attributevalue like departmentId then ${payload.newValue} contains the new value of the attribute.
If the called operation returns an value then this value is stored in the payload variable.

To fire more operations on an event we can add more consumers to an event. Here is an example of this.

<event name="Change">
<producer region="*">
<consumer region="taskflowdefinitionright1"
handler="rightPageDef.valueMethod">
<parameters>
<parameter name="attribute" value="${payLoad.newValue}"/>
</parameters>
</consumer>
<consumer region="taskflowdefinitionleft1"
handler="leftPageDef.valueMethod">
<parameters>
<parameter name="attribute" value="${payLoad.newValue}"/>
</parameters>
</consumer>
</producer>
</event>

In the example I used an * in the producer region. This means that it listen for an event with the name Change and it does not matter which pagedef fires this event.

Here is my example workspace.

13 comments:

  1. Hi,
    I'm trying to passing un event between main page and a Task Flow region, using your method.
    My main page is a jsff (it's in an other taskFlow). In the executables of this main pagedef, i have a "searchRegion",a "taskFlow" and iterators.

    I have 2 problems :
    - First, when i "right clic on the pagedef root node and press Edit Event Map", nothing append... the wizard doesn't appear. I have to remove the taskFlow from "executables" and then, "right clic on the pagedef root node and press Edit Event Map" is ok : wizard appear.

    - Second, when i insert event in the wizard, and look "source" of the pageDef, event is not valid! I have this error :
    "INTERNAL : NullPointerException at NodeManager.findPageDefinitionNode [...] "
    I have to remove the "SearchRegion" and then, it's ok.
    But i need the searchRegion and the taskFlow... how can i do?

    Can you reproduce? do you have any response?

    You can find 2 screenShot here :

    Executables

    Internal Exception

    Thanks

    Clément

    ReplyDelete
  2. Sorry for the double post, links for screenShot doesn't appear.

    Here they are :
    Executables :
    http://img23.imageshack.us/img23/4079/executablessearchtaskbv3.jpg

    Internal Exception :
    http://img243.imageshack.us/img243/5185/nullpointerexjy9.jpg

    Thanks

    Clément

    ReplyDelete
  3. Hi Clement,

    Very strange what is the jdev version you are using.

    My main page is a jsf page and not a fragment. I think you hit a bug or not supported situation.

    I will test this.

    thanks Edwin

    ReplyDelete
  4. I'm using JDev version 11.1.1.0.0.

    Thanks for your help

    Clément

    ReplyDelete
  5. Hi , re-tested your case.

    with a jsf page and jsff page fragment I can open the wizard, even with a inner task flow and a search region. no problem.

    but I can not select an event producer from the jsff page fragment , only from the main page I can select an producer in a jsff page.

    this is my version , please upgrade your jdev. Your project with inner task flows and events are not supported that's why it is not working in your version and in the version you can not do it. you should try to use a backing bean and call from this the right method actions.

    this is my version
    Studio Edition Version 11.1.1.0.1
    Build JDEVADF_MAIN.BOXER_GENERIC_081203.1854.5188
    this is the 3 dec 2008 build.

    thanks Edwin

    ReplyDelete
  6. Hi,
    So i'll continue to use "backing bean" method as i used before.
    Perhaps it will be supported in jdev next version.

    Thanks for your work.

    Clément

    ReplyDelete
  7. I posted info on a simple way to refresh tables in other regions using a requestScope variable
    http://dkleppinger.blogspot.com/

    ReplyDelete
  8. Hi Edwin,

    I found your blog very interesting. I am trying to portletize the 2 task flows and have them as two portlets that communicate between each others. I just use the "LeftNext" simple event to simplify but I cannot have the event of one portlet(left) refresh the other portlet(right). Did you have any chances to work on this? I would like to know why I am not able to have the event picked up at the portlet level.
    I used this tutorial to help me "http://download.oracle.com/docs/cd/E12839_01/webcenter.1111/e10148/jpsdg_bridge.htm" but I cannot seem to make it work. The second portlet just does not see the first event.
    Any idea?
    Thanks a lot for your great blogs by the way.
    Laurent

    ReplyDelete
  9. Hi Laurent,

    strange I am doing the same and always got some problems but only with passing a string collection

    here is my testcase I also send it to oracle. I didn't have a reply yet

    http://www.sbsframes.nl/jdeveloper/Webcenter_TaskFlows.zip

    the trick is in taskflow you can fire the method action directy in a page ,

    in a portlet you can pass the data with the inputparameter of the taskflow and the first default activity must be method which does the action and then go the view.

    thanks



    thanks

    ReplyDelete
  10. Thanks Edwin. I still cannot find a way to have the event firing between the two portlets. I checked your file and I set up everything the same way but when I fire the NextLeft event it does not fire the event on the other side. Any idea? Any chances you could post how you did it (with source code) with this example.
    Thanks Laurent

    ReplyDelete
  11. Hi Laurent,

    can you send me your testcase at biemond at gmail dot com

    thanks Edwin

    ReplyDelete
  12. Hi Edwin I am bit late on this example, however I noticed without using contextual events, I noticed departments in left and right regions are getting refreshed.
    How this can happen, did i missed some thing or latest jdev quick templates takes care this automatically by any chance ?

    ReplyDelete
  13. please ignore my previous request, it happens during shared data control flag was checked in both bounded taskflows :)

    ReplyDelete