We were discussing in our project, if we should use Contextual Events Framework or not. Part of the team was saying Contextual Events Framework have quite many defects and who knows, may be it will be unsupported in next ADF releases. However, I personally don't think its the case - Oracle is gathering community feedback for Contextual Events Framework improvements, this means it will be stabilized and improved. For now, I would recommend not to use too much fancy functionality, but stick with fundamental parts of Contextual Events Framework, this will ensure easy migration during future ADF 11g releases.
When we would need to use Contextual Events Framework? Its possible to communicate between ADF Regions without it, just by using ADF Task Flow parameters - Communicating Between ADF Regions Without Contextual Events Framework. While its true, there is one important thing - direct dependency between two regions. It would work for static predefined systems, but if would expose our ADF Task Flows as components - consumers will decide what combination and what subset of these components will be used in their systems. In this case, we can't map both ADF Task Flows through parameters. Its when Contextual Events Framework is useful, it allows to implement independent communication between ADF 11g regions, and provide these regions as components to third party applications.
I will describe how you can use Contextual Events Framework in combination with ADF 11g Dynamic Regions.
Download sample application - ContextualDynamicRegions.zip. This application implements one static region to list all departments and additionally it contains dynamic region group with departments and employees information - three ADF 11g Task Flows:
Departments in static region are presented using table component, in the current release it doesn't work to define in declarative way Contextual Event for table selection (well, there is wizard option - but its not functional). In general, I prefer to raise and receive Contextual Events from Java methods. In order to raise Contextual Event, when row in departments table is selected, we need to define Selection Listener for this table:
Selection Listener will process typical Selection Event and raise Contextual Event:
You can see, additionally to Selection Listener, I'm raising another Contextual Event for Save action. So, there are two events produced in my sample application - one for table selection, another for Save button.
In order to raise these events successfully, we need to define event bindings - event name, type and payload. Its important to say, for custom payload you need to use $ expression, because # expression will not be processed on runtime for Contextual Event custom payload:
Employees region will receive and process Contextual Event for table selection - it will display employees based on currently selected department:
You need to generate Data Control for receiver class and register Java method in receiver Page Definition:
In order to catch Contextual Event successfully, event map between event and consumer must be defined. In my case, Java method is specified as receiver.
It would work well already, if we would not have ADF 11g Dynamic Region requirement. When switch between Dynamic Region happens, Contextual Event is not propagated to newly initialized region - this means we need to pass payload value through ADF Task Flow parameter for initial initialization:
When dynamic region for Employees will be first time initialized, it will invoke Method Action to filter employees by department, based on input parameter. All subsequent requests will be handled by Contextual Event framework and processed directly - without triggering Method Action, but calling receiver method directly:
Method Action binding associated with initial action from task flow, gets input value from task flow parameter:
There is another declaration for the same method, where input value is set dynamically, based on Contextual Event payload:
Now we are done with our components part - there are two Contextual Events raised and one of them is handled.
Let's move to third party application, where our provided components (ADF Task Flows) will be used:
Third party application declares one static ADF Task Flow for department list and one Dynamic Region with parameter map:
Also you can see, two receiver methods are declared in third party application:
Receiver methods are implemented in Main bean class, its where Dynamic Region address is handled as well. There is another class to construct Dynamic Region parameters map:
Parameters map implements HashMap and provides setter method to update parameter value:
We came to the key part of the application - Dynamic Region address management code. You can see there are two receiver methods for Contextual Events raised by components. Receiver methods assign Dynamic Region address and store it in PageFlowScope. Then page is refreshed to render current Dynamic Region. We need to refresh page, otherwise Dynamic Region is not updated based on new address. I'm storing Dynamic Region address in PageFlowScope, to preserve it in between Contextual Events, otherwise address will be lost. Dynamic Region address switch is triggered, only in case if Contextual Event delivers new address to be set. If it is table selection event, payload is used to initialize input parameter for Employees flow:
When different Contextual Event is received, Dynamic Region is switched using page refresh code:
On runtime, we can select department from static Master area - dynamic region from Detail area will render employees based on received Contextual Event:
We can select another department, new Contextual Event for table selection will be sent and list of employees will be updated:
When we press Save button, another Contextual Event is triggered - this is a signal to switch Dynamic Region:
When there will be another row selected again, Dynamic Region will switch back based on another Contextual Event. Dynamic Region will be initialized and filtered based on Input Parameter from payload, all subsequent filtering will be done directly based on Contextual Event: