This chapter describes how to create, publish, and subscribe to contextual events to facilitate communications between regions.
This chapter includes the following sections:
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.
In the StoreFront module, contextual events are used in the customer registration page to display the appropriate informational topic. The user registration page register.jspx
contains two regions. One region contains the customer registration task flow customer-registration-task-flow,
and the other contains the informational topic task flow help-task-flow
. A contextual event is passed from the customer registration region to the informational topic region so that the informational topic task flow can display the information topic. At design time, the event name, producer region, consumer region, consumer handler, and other information is stored in the event map section of the page definition file, as shown in Example 34-1.
Example 34-1 Event Map in the registerPageDef.xml File
<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent"> <event name="queueHelpTopic"> <producer region="*"> <consumer region="helptaskflow1" handler="helpPageDef.findHelpTextById"> <parameters> <parameter name="helpTopicId" value="${payLoad}"/> </parameters> </consumer> </producer> </event> </eventMap>
At runtime, when users enter the customer registration task flow, they progress through a series of view activities from Basic Information to Address and then to Payment Options by entering data and clicking the Next button. When the user clicks Next, a contextual event with a payLoad
parameter is broadcasted by the customer registration task flow. This event is then consumed by the information task flow and its handler, the helpPageDef.findHelpTextById()
method. The consuming method uses the payLoad
parameter to determine which information topic text to display. In the event map, you can specify EL expressions to bind the input parameters to variables and parameters of the page.
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). If the consuming page is in a dynamic region, the event map should be in the page definition file of the consuming page and the producer's attribute region set to "*". The attribute region is set to "*" because at design time, the framework cannot determine the relative path to the producer.
You can raise a contextual event for an action binding, a method action binding, a value attribute binding, or a range binding (table, tree, or list binding). You also can conditionally fire an event and conditionally handle an event using EL expressions.
For action and method action bindings, the event is raised when the action or method is executed. The payLoad
contains the method return value. You can also raise a contextual event from an ADF Faces event such as clicking a button or selecting from a menu. An eventBinding
is created in the page definition to define the event.
For a value attribute binding, the event is triggered by the binding container and raised after the attribute is set successfully. The payLoad
is an instance of DCBindingContainerValueChangeEvent
, which provides access to the new and old value, the producer iterator, the binding container, and the source. If the payLoad
property is changed to point to a custom data object, then the payLoad
reference will return the object instead. Example 34-2 shows a value change event inside an attribute value binding associated with an input component. The event, valueChangeEvent
, will be dispatched when the user changes the value of LAST_NAME
in the page.
Example 34-2 Value Attribute Event in the Page Definition File
<attributeValues IterBinding="DeptView1Iterator" id="Dname" xmlns="http://xmlns.oracle.com/adfm/jcuimodel"> <events xmlns="http://xmlns.oracle.com/adfm/contextualEvent"> <event name="valueChangeEvent"/> </events> <AttrNames xmlns="http://xmlns.oracle.com/adfm/uimodel"> <Item Value="LAST_NAME"/> </AttrNames> </attributeValues> </bindings> <eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent"> <event name="valueChangeEvent"> <producer region="LAST_NAME"> <consumer region="" handler="consumeEvent"/> </producer> </event> </eventMap>
For an range binding (tree, table, list), the event is raised after the currency change has succeeded. The payLoad
is an instance of DCBindingContainerValueChangeEvent
, which provides access to the new and old value, the producer iterator, the binding container, and the source.
Value attribute binding and range binding contextual events may also be triggered by navigational changes. For example, if you create an event inside a tree table binding, the event will be dispatched when the user selects a different node of the tree in the page.
You use the Contextual Events section under the Behavior section in the Property Inspector to create, publish, and subscribe to contextual events. The Contextual Events panel will only appear when you select eligible components or regions in the page, as shown in Figure 34-1.
You can also subscribe to contextual events using the overview editor for page definition file's Contextual Events tab Subscriber section, as shown Figure 34-2
Contextual events are not the same as the business events that can be raised by ADF Business Components or the events raised by UI components. For a description of these types of events, see the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework. Contextual events can be used, however, in association with UI events. In this case, an action listener that is invoked due to a UI event can, in turn, invoke a method action binding that then raises the event.
The contextual events framework provides the communications between regions within a page. The framework provides the page with the ability to map events that are produced and consumed by the various regions on the page. You can use JDeveloper to declaratively publish events using the page definition file. Similarly, you can declaratively subscribe to those events from the page definition file. You can pass parameters with the event and implement handlers to respond to an event. Other ways to create contextual events include using managed beans and using JavaScript. Note that contextual events do not require regions to be refreshed for the region to uptake parameters.
There are three kinds of communication patterns between a region and the parent page: parent to region, region to parent, and region to region. The contextual events framework is the most powerful communication implementation that works for all three of these scenarios. Also note that contextual events do not require a region to be refreshed in order to consume input parameters.
You should use contextual events to communicate between ADF regions. While it is possible to use ADF task flow parameters to communicate between regions, doing so may create direct dependencies between the regions. ADF task flow parameters may be fine for static regions, but using contextual events will allow you to implement independent communications between regions.
For example, a page may contain a region with a form for entering employee information. When the user updates the employee Id and presses the submit button, a value change contextual event is raised and the employee Id value is also passed as payLoad. On the same page, another region subscribes to and consumes the event and displays departmental information about the selected employee based on the payLoad information passed with the contextual event.
You may find it helpful to understand other ADF features before you work with contextual events. Following are links to other functionality that may be of interest.
You can also use ADF task flow parameters to communicate between ADF regions. For more information about using task flows and regions, see Chapter 21, "Using Task Flows as Regions."
You create contextual events by first creating and publishing the event on the producer based on a method action, action, value attribute, or list binding. On the consumer, you subscribe to the event and create a handler to process the event.
Typically, you create a parent page with regions that contain task flows and view activities. You create contextual events in one region to be published for consumer event handlers in the other region. For more information about using task flows and regions, see Chapter 21, "Using Task Flows as Regions."
Note:
You can also publish an action contextual event from code (for example, from within a managed bean). You can usegetBindingContainer().getEventDispatcher
which returns an instance of EventDispatcher
. EventDispatcher
has public APIs which you can use to programmatically raise contextual events.You use the Property Inspector to create contextual events in the producer's page.
It may be helpful to have an understanding of the options that are available to you when you create contextual events. For more information, see Section 34.2, "Creating Contextual Events Declaratively."
You may also find it helpful to understand functionality that can be used with contextual events. For more information, see Section 34.1.2, "Additional Functionality for Contextual Events."
You will need to complete this task:
In the producer page, drag and drop a component from the Data Controls panel to the page that will trigger the event.
The component must have a method action, action, value attribute, or list binding. In the StoreFront module, the setHelpId()
method from the Data Controls panel was added to the page.
In the Property Inpector expand the Behavior section.
In the Publish Events section, click the Add icon.
In the Publish Contextual Events dialog:
Select Create New Event.
Enter the name of the event.
If you are using a table, tree, or tree table, a Node field appears for you to enter the node that will publish the event.
Select Pass Custom Value From if you want to pass payload data to the consumer.
If you are passing payload data, select the type of data from the dropdown list.
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.
You can conditionally raise the event by entering an EL expression in the Raise Condition tab.
For instance, entering an expression such as ${bindings.LAST_NAME.inputValue == 'KING'}
will cause the event to be raised only if the customer's last name is KING.
Click OK.
The event is created on the page, but it is not ready for publishing until it is associated with the component binding.
You use the overview editor for page definition files on the parent page to subscribe to contextual events.
It may be helpful to have an understanding of the options that are available to you when you create contextual events. For more information, see Section 34.2, "Creating Contextual Events Declaratively."
You may also find it helpful to understand functionality that can be used with contextual events. For more information, see Section 34.1.2, "Additional Functionality for Contextual Events."
You will need to complete this task:
To subscribe and consume the event:
In the consuming page, add the components that may respond to the event.
In the StoreFront module, the findHelpTextById
method handler return value, String, is dropped onto the page as an outputText
component to display the help information.
Create a handler to process the event and its payload data.
In the StoreFrontModule example, the findHelpTextById
handler method was created in the LookupServiceAMDataControl
module.
In the overview editor for the consumer page definition's Bindings and Executables tab Bindings section, click the Add icon.
In the Insert Item dialog, select methodAction and click OK.
In the Create Action Binding dialog:
Select the data collection where you have created your handler.
From the Operation dropdown list, select the handler.
Click OK.
In the overview editor for the consumer page definition's Bindings and Executables tab Bindings section, click the Add icon.
In the Insert Item dialog, select attributeValue and click OK.
In the Create Attribute Binding dialog:
From the Data Source dropdown list, select Variable.
Select the return value of the handler as the Attribute.
Click OK.
In the overview editor Contextual Events tab, click Subscribers and click the Add icon in the Event Subscribers section.
In the Subscribe to Contextual Event dialog, click the Search icon.
In the Select Contextual Events dialog, select the event you want to subscribe to from the tree and click OK.
In the Subscribe to Contextual Event dialog:
Select the producer or <Any> from the Publisher dropdown list. A contextual event can have more than one producer.
Selecting <Any> will allow the consumer to subscribe to any producer producing the selected event. In the page definition file, the producer
attribute will be set to the wildcard "*". If your producer is in a dynamic region, you should set this field to <Any> so that the subscriber can consume from any producer.
Click the Search icon next to the Handler field.
In the Select Handler dialog, select the event handler from the tree and click OK.
If the handler requires parameters, select the Parameters tab, click Add, and enter name-value pair as parameters.
If you want to conditionally handle the event, select the Handle tab, and enter an EL Expression that determines the conditions under which the handler will process the event.
Click OK.
Note:
You can edit the event map by right-clicking the page definition in the Structure window and choosing Edit Event Map. You can also edit event attributes in the page definition file or in the Property Inspector.When you create an event for the producer, JDeveloper adds an events
element to the page definition file. Each event name is added as a child. Example 34-3 shows the event on the setHelpId
method action binding in the account_basicinformationPageDef
page definition file of the StoreFront module. This is the page definition for the Basic Information view of the customer registration task flow.
Example 34-3 Event Definition for the Producer
<methodAction id="setHelpId" InstanceName="LookupServiceAMDataControl.dataProvider" DataControl="LookupServiceAMDataControl" RequiresUpdateModel="true" Action="invokeMethod" MethodName="setHelpId" IsViewObjectMethod="false" ReturnName="LookupServiceAMDataControl. methodResults.setHelpId_ LookupServiceAMDataControl_dataProvider_ setHelpId_result"> <NamedData NDName="usage" NDValue="CREATE_PROFILE" NDType="java.lang.String"/> <events xmlns="http://xmlns.oracle.com/adfm/contextualEvent"> <event name="queueHelpTopic"/> </events>
When the method action binding is invoked, the event is broadcasted to its consumers.
When you configure an event map, JDeveloper creates an event map entry in the corresponding page definition file. Example 34-4 shows the event map on the registerPageDef
page definition file that maps the queueHelpTopic
event from the customerregistrationtaskflow1
region to the helptaskflow1
region. It also maps the helpPageDef.findHelpTextById
handler method bindings that is defined in the helpPageDef
page definition file. The consumer invokes a method that determine the information text to display based on the parameters that are passed into it. The mapping is in the registerPageDef
page definition, as that is the parent container for both the customerregistrationtaskflow1
and the helptaskflow1
regions.
Example 34-4 Event Map in the Parent Page Definition File
<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent"> <event name="queueHelpTopic"> <producer region="*"> <consumer region="helptaskflow1" handler="helpPageDef.findHelpTextById"> <parameters> <parameter name="helpTopicId" value="${payLoad}"/> </parameters> </consumer> </producer> </event> </eventMap>
You can control the dispatch of contextual events to child regions at the application level or at the page level.
It may be helpful to have an understanding of the options that are available to you when you create contextual events. For more information, see Section 34.2, "Creating Contextual Events Declaratively."
You may also find it helpful to understand functionality that can be used with contextual events. For more information, see Section 34.1.2, "Additional Functionality for Contextual Events."
To disable event dispatch at the application level, set the dynamicEventSubscriptions
property to false
in the adf-config.xml
file, as shown in Example 34-5.
You can disable the event dispatch to regions that have an event map with producers as wildcards.
Example 34-5 Disabling Contextual Event Dispatch at the Application Level Using adf-config.xml
<?xml version="1.0" encoding="windows-1252" ?> <adf-config xmlns="http://xmlns.oracle.com/adf/config" xmlns:cef="http://xmlns.oracle.com/adfm/contextualEvent"> <cef:DynamicRegionEventsConfig dynamicEventSubscriptions="false"> </cef:DynamicRegionEventsConfig> </adf-config>
To disable event dispatch at the individual page level, set the dynamicEventSubscriptions
property to false
in the associated page definition file, as shown in Example 34-6.
Contextual events will not be passed to the page and any of its children.
If both the event producer and the consumer are defined in the same page definition file, then after the corresponding page is invoked and the binding container is created, the event is raised when:
The corresponding method or action binding is executed
A value binding is set successfully
A range binding currency is set successfully
For a method binding, the result of the method execution forms the payload of the event, and the event is queued. In the Invoke Application phase of the JSF lifecycle, all the queued events will be dispatched. The event dispatcher associated with the binding container checks the event map (also in the binding container, as it is part of the same page definition file) for a consumer interested in that event and delivers the event to the consumer.
When the producer and consumer are in different regions, the event is first dispatched to any consumer in the same container, and then the event propagation is delegated to the parent binding container. This process continues until the parent or the topmost binding container is reached. After the topmost binding container is reached, the event is again dispatched to child-binding containers that have regions with pages that have producer set to wildcard "*
".
You create contextual events by first creating the event on the producer. You then determine the consumer of the event, and map the producer to the consumer.
It may be helpful to have an understanding of the options that are available to you when you create contextual events. For more information, see Section 34.3, "Creating Contextual Events Manually."
You may also find it helpful to understand functionality that can be used with contextual events. For more information, see Section 34.1.2, "Additional Functionality for Contextual Events."
You will need to complete this task:
In the Application Navigator, open the page definition file that contains the binding for the producer of the event.
A producer must have an associated binding that will be used to raise the event. For example, if a method or operation will be the producer, the associated action binding or method action binding will contain the event.
In the Structure window, right-click the binding for the producer and choose Insert inside binding name > events or Insert inside binding name > Contextual Events > events.
In the Structure window, right-click the events element just created, and choose Insert inside events > event.
In the Insert event dialog, enter a name for the event in the name field, and click Finish.
The event is now created. By default, any return of the associated method or operation will be taken as the payload for the event and stored in the EL-accessible variable ${payLoad}
. You now need to map the event to the consumer, and to configure any payload that needs to be passed to the consumer.
Open the page definition that contains the binding for the consumer.
The binding container represented by this page provides access to the events from the current scope, including all contained binding containers (such as task flow regions). If regions or other nested containers need to be aware of the event, the event map should be in the page definition of the page in the consuming region.
In the Structure window, right-click the topmost node that represents the page definition, and choose Edit Event Map.
Note:
If the producer event comes from a page in an embedded dynamic region, you may not be able to edit the event map using the Event Map Editor. You can manually create the event map by editing the page definition file or use insert inside steps, as described in Section 34.3, "Creating Contextual Events Manually."In the Event Map Editor, click the Add icon to add an event entry.
In the Add New EventMap Entry dialog, do the following:
Use the Producer dropdown menu to choose the producer.
Use the Event Name dropdown menu to choose the event.
Use the Consumer dropdown menu to choose the consumer. This should be the actual method that will consume the event.
If the consuming method or operation requires parameters, click the Add icon.
In the Param Name field, enter the name of the parameter expected by the method. In the Param Value field, enter the value. If this is to be the payload from the event, you can access this value using the ${payLoad}
expression. If the payload contains many parameters and you don't need them all, use the ellipses button to open the Expression Builder dialog. You can use this dialog to select specific parameters under the payload node.
You can also click the Parameters ellipses button to launch the selection dialog.
Click OK.
In the Event Map Editor, click OK.
You can publish an action contextual event from code such as from within a managed bean. You bind the producer component to the method in the managed bean, as shown in Example 34-7.
In this example, the producer is a command button that invokes an action binding and the consumer is an outputText
component that displays a string. They are both on the same page.
Example 34-7 Event Producer and Event Consumer on the JSF
<af:form id="f1"> <af:commandButton value="eventProducerButton1" id="cb1" action="#{MyBean.myActionPerformed}" /> <af:panelLabelAndMessage label="#{bindings.return.hints.label}"id="plam1"> <af:outputText value="#{bindings.return.inputValue}" id="ot1"/> </af:panelLabelAndMessage> </af:form>
The page definition file contains the method action bindings for the producer, the consumer, and the event map, as shown in Example 34-8.
Example 34-8 Page Definition with Event Producer, Event Consumer, and Event Map
<executables> <variableIterator id="variables"> <variable Type="java.lang.String" Name="eventConsumer_return" IsQueriable="false" IsUpdateable="0" DefaultValue="${bindings.eventConsumer.result}"/> </variableIterator> </executables> <bindings> <methodAction id="eventProducer" InstanceName="AppModuleDataControl.dataProvider" DataControl="AppModuleDataControl" RequiresUpdateModel="true" Action="invokeMethod" MethodName="eventProducer" IsViewObjectMethod="false" ReturnName="AppModuleDataControl.methodResults.eventProducer_ AppModuleDataControl_dataProvider_eventProducer_result"> <events xmlns="http://xmlns.oracle.com/adfm/contextualEvent"> <event name="myEvent"/> </events> </methodAction> <methodAction id="eventConsumer" RequiresUpdateModel="true" Action="invokeMethod" MethodName="eventConsumer" IsViewObjectMethod="false" DataControl="AppModuleDataControl" InstanceName="AppModuleDataControl.dataProvider" ReturnName="AppModuleDataControl.methodResults.eventConsumer_ AppModuleDataControl_dataProvider_eventConsumer_result"> <NamedData NDName="str" NDValue="test" NDType="java.lang.String"/> </methodAction> <attributeValues IterBinding="variables" id="return"> <AttrNames> <Item Value="eventConsumer_return"/> </AttrNames> </attributeValues> </bindings> <eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent"> <event name="myEvent"> <producer region="eventProducer"> <consumer region="" handler="eventConsumer"> <parameters> <parameter name="test" value="${payLoad}"/> </parameters> </consumer> </producer> </event> </eventMap>
When the button is pressed, the myActionPerformed
method is invoked and calls the following methods to generate the contextual event with "myString" as the payLoad:
BindingContainer bc = (BindingContainer)fc.getApplication().evaluateExpressionGet(fc,"#{bindings}", BindingContainer.class); JUCtrlActionBinding actionBnd = (JUCtrlActionBinding)bc.getControlBinding("eventProducer"); ... ((DCBindingContainer)bc).getEventDispatcher().queueEvent(actionBnd. getEventProducer(),"myString"); ((DCBindingContainer)bc).getEventDispatcher().processContextualEvents(); return null;
Every action and method binding that is accessible from a managed bean can be invoked from JavaScript. ADF Faces provides an af:serverListener
operation component that can be used to call a managed bean method from client-side JavaScript. To invoke this component using the referenced managed bean method, use the BindingContext
object to look up the current BindingContainer
and to access the OperationBinding
or a JUEventBinding
binding. The af:serverListener
component can also be used to send a message payload
from the browser client to the managed bean method.
Under most circumstances, you can create the event map using the Event Map Editor as described in Section 34.3, "Creating Contextual Events Manually." However, in situations such as when the producer event is from a page in an embedded dynamic region, the Event Map Editor at design time cannot obtain the necessary information to create an event map.
It may be helpful to have an understanding of the options that are available to you when you create contextual events. For more information, see Section 34.6, "Creating the Event Map Manually."
You may also find it useful to understand functionality that can be used with contextual events. For more information, see Section 34.1.2, "Additional Functionality for Contextual Events."
To create the event map manually:
In the Application Navigator, open the page definition that contains the binding for the consumer.
In the Structure window, right-click the topmost node that represents the page definition, and choose Insert inside pagedef name > eventMap.
In the Structure window, select the eventMap node, right-click and choose Insert inside eventMap > event.
In the Insert Event dialog, enter the name of the event and click OK.
Repeat steps 3 and 4 to add more events.
Select the event node, right-click and choose Insert inside event > producer.
In the Insert Producer dialog, enter the name of the binding that is producing this event and click OK.
You can also enter the name of the region which has the event producer, in which case all the consumers specified under this tag can consume the event. You can also enter "*" to denote that this event is available for all consumers under this tag.
Select the producer node, right-click, and choose Insert inside producer > consumer.
In the Insert Consumer dialog, enter the name of the handler that will consume the event and click OK.
Repeat steps 7 and 8 to add more consumers.
If there are parameters being passed, add the parameter name and value.
Select the consumer node, right-click, and choose Insert inside consumer > parameters.
Select the parameters node, right-click, and choose Insert inside parameters > parameter.
In the Insert Parameter dialog, enter the name of the parameter and the value of the parameter and click OK. The value can be an EL expression.
Repeat this step to add more parameters.
By default, the contextual event framework uses EventDispatcherImpl
to dispatch events that would traverse through the regions. You can create a custom event dispatcher to override the default event dispatcher to provide custom behaviors. After you have created the custom event dispatcher, you must register it in the Databindings.cpx
file to override the default dispatcher.
It may be helpful to have an understanding of the options that are available to you when you create contextual events. For more information, see Section 34.7, "Registering a Custom Dispatcher."
You may also find it useful to understand functionality that can be used with contextual events. For more information, see Section 34.1.2, "Additional Functionality for Contextual Events."
To register a custom event dispatcher:
Create a custom event dispatcher Java class based on the EventDispatcher
class.
Register the custom event dispatcher in the Databindings.cpx
file with a fully qualified name using the following format:
EventDispatcher="package_name.CustomEventDispatcher_name"
Example 34-9 shows the code for a custom event dispatcher called NewCustomEventDispatcher
created in package NewPackage
.
Create the event in the producer's page definition. For more information, see Section 34.2, "Creating Contextual Events Declaratively," or Section 34.3, "Creating Contextual Events Manually."
Create the event map in the consumer region if the consumer is in a dynamic region. If the consumer is not in a dynamic region, you can also specify the event map in the parent page which holds both the producer and consumer regions. For more information, see Section 34.6, "Creating the Event Map Manually."