Wednesday, March 31, 2010

ADF 11g Contextual Event Framework: An Example

Often a page or a region within a page needs information from somewhere else on the page or from a different region. While you can pass parameters to obtain that information, doing so makes sense only when the parameters are well known and the inputs are EL-accessible to the page. Parameters are also useful when a task flow may need to be restarted if the parameter value changes.

However, suppose you have a task flow with multiple page fragments that contain various interesting values that could be used as input on one of the pages in the flow. If you were to use parameters to pass the value, the task flow would need to surface output parameters for the union of each of the interesting values on each and every fragment. Instead, for each fragment that contains the needed information, you can define a contextual event that will be raised when the page is submitted. The page or fragment that requires the information can then subscribe to the various events and receive the information through the event.

Events are configured in the page definition file for the page or region that will raise the event (the producer). In order to associate the producer with the consumer that will do something based on the event, you create an event map also in the page definition (when using events between regions, the page definition file which holds both the regions contains the event map).

The Contextual Event Framework in action.

Let’s start with a simple example. Take a look at the following situation: There is a page (PAGE-1) containing two 2 regions (these regions where created by dropping taskflows on PAGE-1). The first region (“edit employees”) will publish an event, and the second region (“show information”) is a subscriber to this event.
In other words, as soon as an event is published by “edit employees”, “show information” will respond to that event for instance by displaying the action performed in “edit employees”.

When the user clicks NEXT, a contextual event with a payLoad parameter is broadcasted by the edit employee task flow. This event is then consumed by the show information task flow and its handler, the getInformationByEmail() method which is derives the Email address.

The situation is shown in this simple diagram:



This example uses an event published by a command button. So how is this example implemented?

Adding an event to a action component.

To implement the above example the next button has to publish an event when the button is pressed by the user. There are two requirements to achieve this functionality. First of all an event has to be available in the producer page (or page fragment). This event can be created in the “contextual events tab” of the overview editor for the producer page definition.

In the Events section, click the Add icon. Now it is possible to enter the name of the event and define the payload data for the event. For example, if you want to pass an attribute value from the producer page to the consumer page, you can select Page Data and select the attribute from the tree structure. In this case the “input value” of the Email field is used, as displayed in this figure:



After creating this event it is not published automatically. There still need for a actual “publisher” So to be able to actually publish the event, it has to be associated by with the NEXT button.
To associate the NEXT button with the event, select the “NEXT” button, open the Contextual Events pane in the Property Inspector, and click the Add icon. Now it is possible to select an existing event. In this case select the “nextButtonPressed” event that was created previously, from the tree structure, as is shown here:



The event is now ready for publishing. In plain code the result of the above actions for the published event looks like this in the pageDefintion file of the “edit employees” page fragment:

 <action IterBinding="EmployeesView1Iterator" id="Next"  
RequiresUpdateModel="true" Action="next">
<events xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
<event name="nextButtonPressed"
customPayLoad="${bindings.Email.inputValue}"
eventType="button pressed event"/>
</events>
</action>
…………
</bindings>
<events xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
<event name="nextButtonPressed"
customPayLoad="${bindings.Email.inputValue}"
eventType="button pressed event"/>
</events>


Now that the event is published still nothing will happen at runtime because no component has subscribed to the event. Subscribing to the event is pretty straightforward.

Subscribing to an event.

First of all the “subscriber” needs a handler process. In this case the handler method is a method on the application module that returns a valid Email address; getInformationByEmail().
When this handler method is published to the client, it’s output can be dropped on the page fragment as an output text. By doing this a method action is created in the page definition of the information page. Now the action method can subscribe to the event published in the “edit employee” page.
The actual subscribing needs to be configured in the PAGE-1. This is the page where both fragments (“edit employees” and “show information”) are present. In the “page definition” overview tab of PAGE-1 it is possible to select the event to subscribe to. After selecting that event there is the possibility to add a subscription in the “subscribers” tab.
With the “Subscribe to Contextual Event” dialog open the subscription can be configured. Select the producer from the Publisher dropdown list. To add the handler, click the Search icon next to the Handler field and select the event handler (getInformationByEmail) from the tree. Finally add the parameters for the handler method:



What was just described with a lot of words is actually the creation of a very simple publish/subscribe mechanism: There is a published event (NextButtonPressed) that has a payload (email value) which is used as parameter (mailadress) by the subscriber (getInformationByEmail).

This is just a very simple example of what can be done with the Contextual Event Framework. An action component is not the only component that can publish an event. Also components like input components, table components can publish events. Events can also be published from a managed bean, and indirectly from javascript.

2 comments:

Srini.A said...

I would to publish button events in region-1 and consume them in region-2. This is little different from publishing the valueChange event. I have raised the button event. I have created the consumer method as shown below to get the text of the button event. I am failing to read the event. I am not sure if it is being published. I am not if I can find that through debugging.

In our business usecase, I have Purchase request in region-1 with create Item and SubItem buttons. I have a taskflow in region-2 with a

router to display item or subitem creation screen based on the action event in region-1.


public void receiveButtonEvent (ActionEvent actionEvent03){

RichCommandButton rcb = (RichCommandButton)actionEvent03.getComponent();
System.out.println("Action Text = "+rcb.getText());
String prAction = rcb.getText();
ADFUtil.setEL("#{requestScope.prAction}",prAction);
}

Is this correct? Where is the missing link? I really appreciate your insight to resolve this issue.

Anonymous said...

Hi Luc,
I have problem regarding Contextual event, which is described at OTN JDeveloper forum. Can you please take a look at this forum thread ?


https://forums.oracle.com/forums/thread.jspa?threadID=2379248&tstart=15

Thanks in advance...