Thursday, October 28, 2010

Oracle ADF 11g is a key framework for Oracle Fusion Middleware 11g family products, same applies for Oracle BPM 11g Suite. When it comes time to application implementation on top of defined processes - its when Oracle ADF 11g comes into picture. I will present today fairly simple BPM process and will describe how we can initialize process payload with real data from database using ADF.

We can assume initial process looks like the following:

It implements two Human Tasks defined for two different roles - TeamLeaders and ProjectManagers. The logic is simple - TeamsLeaders role can initialize the task and ProjectManagers role can approve it. Download sample application for today post - EmployeeManagementLab.zip.

I will remove this initialization script and will explain how you can initialize payload with real data from table selection:

I will retrieve initialization data from ADF BC project, you can base your Model on Web Service or EJB - no difference, ADF provides unified Data Control for different Model implementations. My ADF BC project based on HR database schema:

In this example I'm using default auto-generated ADF Task Flow for Human Task:

Auto generated ADF Faces screen for Human Task looks similar:

I have drag&dropped Panel Collection component from ADF Faces Components palette, its where Table component will be defined:

You should expand Data Controls tab to see available data collections and methods. In this example I want to create table component with Employees data, user will be able to select one Employee and enable process payload with this data:

I can create data bounded table on Employees data collection, just by drag&drop from Data Controls:

Save and Undo operations also are provided by Data Control:

Now is one of most important steps to understand - we must have attributes defined from both data collections (BPM process payload and Employees table) in Page Definition. Attributes for BPM process payload form are auto-generated, we need to define attributes that represent Employees collection by ourselves - this will allow to access currently selected row:

All attributes for Employees collection:

Every attribute is pointing to the same iterator, it brings data from ADF BC Data Control:

Next step is to override Table component selection listener, we need to process table selection event and assign payload programmatically:

Selection listener is overridden using SelectionListener table property, it should point to the Java bean method:

Java bean is created as simple Java class:

This class is declared in ADF Bounded Task Flow, same task flow where Human Task is auto-generated:

Selection listener is overridden inside Java bean class:

Inside selection listener, first we are processing table selection event. Next, using ADFUtils class helper methods, we are copying values from currently selected row into BPM process payload:

There are various approaches to copy values from one collection into another, for example you can access iterator directly and get current row, then you will need to operate with real attribute names defined in Data Control. I prefer to operate through defined Attributes, this allows to be independent from naming changes in Data Control.

Values are copied into payload, additionally we need to set Partial Trigger refresh relationship from Employees table to process payload form - to show payload changes based on different row selection:

This can be achieved both declaratively and programmatically, I will go with Java coding approach in this sample. Mainly because declarative approach will trigger refresh always, however in the future I will want to be it conditional. I need to set Binding property for payload form, this will allow to operate it from code:

Binding is defined in same Java bean, where we have selection listener:

It is enough to use defined binding from standard ADF API to send partial refresh event from table to form:

Sunday, October 17, 2010

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:

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:

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: