You are here

Inter-Component-Communication between Taskflows in ADF and WebCenter

In my Inter Component Communication series I explain how we can allow components to communicate with each other. I already explained how portlets can communicate with each other by using parameters and how you can pass parameters from a portlet to a taskflow.

In this post I will explain how we can allow two taskflows to communicate with each other by using contextual events. This is a concept introduced by the ADF framework. I have to admit, when I develop ADF application I seldom use contextual events but when developing taskflows for WebCenter, it suddenly gets really important. The reason for this is that a portal requires its components to be able to communicate with other components without knowing about these component in advance.

From a portlet this has been standardized by the JSR 286 standard. When working with taskflows we need something similar and this is contextual events. This is the same principle as triggering and consuming events from a portlet. So basically Oracle introduced a portal concept in its ADF framework which is a good thing.

In this example I start with a simple ADF Fusion Applicaitons that contains two taskflows:

  • EmployeeTF: Shows a table of employees based upon a department ID
  • DepartmentTF: shows an overview and edit of a department

Both taskflows are completely independent. The model itself is also quite simple:

I also added a View Criteria to the EmployeeView in order to filter on department:

And that's the data model exposed by the Application Module:

EmpByDept is the view criteria instead of the employees view.

The application also has an index.jspx page in the ViewController project that contains both taskflows. When you run the index.jspx page you will notice that both taskflows have nothing in common. The Employee taskflow will display all the employees, no matter which department we select.

You can download the start of this application here

We are going to change this so when we select a department, it will trigger a contextual event so that the employee taskflow can be notified and update its table.

Adding a publishing event

The principle for contextually wiring taskflows to each other is the same as portlets:

  1. Define an event on the producer taskflow
  2. Define an event on the listener taskflow
  3. Consume both taskflows on the same page
  4. Wire the events together
    1. These steps are the same as wiring portlets together so that should look familiar. The way we define events on taskflow is just a little different.

      With taskflows, events are defined in the binding layer of the framework. This means that before you can create an event, you should have something that is able to trigger an event in the binding layer. This can be either a method, action or attributeValue.

      So in our case, we want to trigger the event when we select a department. We also want to add the departmentId on the payload so we can use it to set the view criteria on the employee taskflow.

      In order for this to work we need to create a custom method in a custom data control so we can add the event.

      Let's create a Java class that will be used as our data control:

      And this is the code:

      1. public class DepartmentDC {
      2.     public DepartmentDC() {
      3.         super();
      4.     }
      5.    
      6.     public void selectDepartment(){
      7.         System.out.println("Triggering event");
      8.     }
      9. }

      As you can see, really easy. We just need this method to find out when the method has been called.
      Now we need to create a data control out of this class.
      In the projects window, right click on the java class and select Create Data Control:

      Now drag and drop the selectDepartment method from this DC inside the colActions column in the departments overview.jsff:

      I also add the action attribute so it will navigate to the edit view of the taskflow. This is the final code of the commandLink:

      1. <af:commandLink actionListener="#{bindings.selectDepartment.execute}"
      2.      text="selectDepartment" action="edit" id="cl1"/>

      So now we have created a commandLink that is bound to an action in the bindings layer. This means that when we add an event to the action that this commandLink executes, the event will be triggered as well.

      So let's add the event now.
      Go to the bindings of the overview.jsff. Select the selectDepartment method and right click on it. Select Insert Inside selectDepartment and select event from the context menu:

      Open the structure window and right click on the events as part of the selectDepartment. Select Insert Inside events and select eventin the context menu.

      Specify selectDept as the event name. This is the event that will be triggered and that will be exposed to the external world.

      Now we still need to define our payload. The event needs to pass the selected departmentId so we need to add an attributeValue that will be used as a reference for the departmentId that we can add to the payload of the event.

      In the bindings section of the pagedefiniion click on the add button and select attributeValues:

      Select the Departments iterator from the data source and select DepartmentId as the attribute:

      Now we have an attribute that is bound the same instance than our department table. This means that when we select a row in the departments table, the departmentId gets updated with a new value so we can use this to power our payload.

      Open the source of the pagedef of the overview.jsff and modify the selectDept event by adding the customPayload attribute so it points to the departmentId.

      This is what the full methodAction source should look like with the event:

      1. <methodAction id="selectDepartment" RequiresUpdateModel="true"
      2.     Action="invokeMethod" MethodName="selectDepartment"
      3.     IsViewObjectMethod="false" DataControl="DepartmentDC"
      4.     InstanceName="DepartmentDC.dataProvider">
      5.   <events xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
      6.     <event name="selectDept" customPayLoad="#{bindings.DepartmentId.inputValue}"/>
      7.   </events>
      8. </methodAction>

      Now the producer is ready.

      When we press the selectDepartment button, the selectDept event will trigger and the DepartmentId will be added on the payload of the event.

      Now let's add an event on the employee taskflow:

      Creating a consuming event

      Currently the Employee overview does not have anything in its binding that can react on the event so we need to add something. Because we need to filter the results of our table, we need to add the ExecuteWithParams method to the bindings. This will execute the view criteria and thus filter the results based upon the payload of the triggering event.

      In the bindings of the empOverview.jsff add the ExecuteWithParams action:

      The confusing part here is that we don't have to specify a value for the pDepId parameter. This will be done during the wiring of both taskflows on the page itself!

      Wiring both taskflows together

      The only thing left for us is to wire both taskflows together. On the index.jspx page go to the bindings and open the Contextual events tab.

      Open the Subscriber tab and click on the Add sign.

      This popup allows us to wire events together. Events can come from any page definition. If you click on the browse button of the event field you will see all the events from all the page definitions that are accessible by the current page:

      The event field is the publisher event so we should select the selectDept event.

      In the handler field we should select the ExecuteWithParams method of the EmployeeTF.

      This means that when the page notices that the selectDept event has been triggered, the page will notify the employee taskflow and execute the ExecuteWithParams method inside the employee taskflow.

      The only thing we need to do is bind the payload to the input parameter of the ExecuteWithParam method.

      In the parameters section click the add button and specify pDepId in the Name and #{payLoad} in the Value section. Each event has a payload and we can access it with the EL #{payLoad} so we can pass the payload to the ExecuteWithParam.

      This is the result:

      That's it.

      Run the index.jspx and test it by selecting the selectDepartment button.

      That's how you wire taskflows together.

      The important part to remember is that you always have to have something in the page definition that can trigger the event like an action or method.

      In the consuming part you bind the payload of the triggering event to the consuming event by mapping its input parameters with the payload of the triggering event.

      You can download the finished application here.

Category: 
ADF Tags: 

Comments

Hi Yannick,
Good post,i have a question here,i have two bounded Taskflows and both are in one page and i don't have any data control,bcoz i am getting data directly from other Services.In that case i need to pass some value from one region to another region by a button action.

i will appreciate Ur valuable feedback Yannick

The only way to have contextual events is through the bindings so you have to create a DC based upon a pojo so you can use those methods to trigger and process the event.

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer