Thursday, August 30, 2012

One of the main complexities with Oracle BPM - how to organize Human Task projects and components. Is preferable to avoid code duplication and having lots of generated ADF Data Control files in different ADF UI projects. Reusability problem can be solved by having generic Human Task handler - I will describe its concept in this blog.

One of the main principles defined in this post - pass through BPM payload only key attributes. Key attribute should identify business object in the process, but associated data for this business object always will be queried from database. This allows to implement reusable ADF UI for Human Tasks and avoid data transformation complexity in BPM. Of course this approach will work, if you will be granted access to the data.

Concept is tested and implemented as sample application, available for download - EmployeeManagementLab_v2.zip. This application implements BPM process with two Human Tasks, but there is only one ADF UI project (it serves both Human Tasks):

Human Task activities available in BPM process:

Now if you want to generate ADF UI for these Human Tasks - stop, wait a bit. Instead of generating separate ADF UI for each of these Human Task activities - create another dummy Human Task activity and we generate generic ADF UI from it. This generic Human Task should be configured with all required actions for any Human Task from the process:

Dummy Human Task is defined - GenericHumanTask:

We generate GenericHumanTaskUI project from this dummy Human Task:

Once ADF UI project was generated - delete dummy Human Task, we don't need it anymore. Change generated ADF Task Flow - add Router activity. Router decides to open page directly or set current row first (suppose first Human Task shows list of employees and second Human Task needs to display only one specific employee):

ADF UI Generic Human Task application is enabled with ADF Security, it defines application role to differentiate users from Router activity in the Task Flow - task-creator-role, this role is granted to the user who have access to the first Human Task - Assign Employee:

If flow goes through the method, where current row is set - key value is retrieved from BPM payload variable:

There is only one ADF UI page, it serves both Human Tasks:

Data is rendered conditionally for each of the tasks. First Human Task displays editable data and second - readonly. This is controlled on ADF BC EO level with ADF Security. Employees EO is enabled with Update security operation:

Update permission is granted to the task-creator-role, the same role which is allowed to open ADF UI page directly. This means user granted with such role will be able to change data:

Remember we exposed all operations for generic Human Task, now we can see all these operations available in Data Control:

ADF UI page for the Human Task is auto generated to support all these operations. Based on condition and Human Task configuration, ADF will render only available operations for specific Human Task. This is how we can maintain generic Human Task ADF UI for different BPM Human Task definitions:

Generic ADF UI is deployed as separate application:

The trick is to point both Human Task instances to the same ADF UI - ADF Task Flow.

Sunday, August 26, 2012

I will explain today implementation for Master-Detail validation rule - newMaster record insert is not allowed, if there are no Detail records added. ADF is powerful framework and there are different ways to implement same requirement - complexity is to choose the most suitable and optimal approach. Such validation rule can be implemented in Java, by overriding doDML() method on Entity Implementation class. While this works, also same rule can be implemented in Groovy script and declared as ADF BC business rule on Entity. Obviously its better to declare validation in standard way as Entity business rule, instead of coding it in Java logic (at least for current requirement) - it will make code maintenance and changes simpler.

Detail list with Employees is refreshed for new Department, based on Master-Detail relationship:

You can see - new Department info is available, but there are no Employees added, as per our validation rule such data change should be prevented. Yes, it works exactly as it should - ADF reports validation error for new Department record without Employees added:

Validation execution logic checks if rule should be executed. It gets current row status for Groovy object - adf.object.entityState. If status is translated (using custom method in Entity Implementation class) into New or Initialized - only in such case validation rule is triggered:

Custom method in Entity Implementation class to translate row status:

Additional tip for insert into Master-Detail, sample application overrides postChanges(...) method for Employees Entity Implementation - it checks if Master Departments record is new and forces post on Master (this is required if Association is not Composite to ensure Master-Detail posting order):

I will run this webinar using problem/solution approach. Problem will be described first, after that ADF best practice solution will be explained and demonstrated. I will accept questions during live session - there will be no need to wait for questions at the end.

Webinar abstract: This webinar highlights ADF best practices and will share information you can't read from a developer guide or book. Technical solutions based on day-to-day experiences from ADF development will also be included. The webinar will be organized in use case / solution best practice format. Featured topics include: resolving ADF BC Library imports, master-detail performance improvements, session scope access from ADF BC, LOV performance improvements, table loading performance, login and ADF security implementation, and finally, ADF BC activation/passivation and stress testing.

Thursday, August 23, 2012

I was preparing proof of concept for such scenario, where ADF application was working with multiple data sources. Requirement was to be able to select data source on runtime, before login. We had several DB users, different DB security applied to each of them - separate data source was defined. Different data source per business site, not really per business user - this would be too much. I would like to post and describe prepared sample application. Data Source runtime switch is implemented based on concept described in Jobinesh blog - Modifying the Application Module's JDBC DataSource at run time.

Download sample application - UserDataADFBCSample_v3.zip. This sample is based on application from my previous posts, it is enhanced with Data Source selection from login page.

Data Source runtime switch is implemented basically in two steps:

1. In the Model there is custom class that implements EnvInfoProvider. Specifically one method is overriden - getInfo(String, Object). This method reads data source name from session scope (its where we set it during login) and puts it into AM configuration:

2. Each Application Module must be set with proper configuration for jbo.envinfoprovider property. This property must point to our custom EnvInfoProvider class (see above):

Default Data Source name defined for Application Module is still important, ADF BC will use it in case if no custom Data Source name was provided:

I'm getting list of Data Sources from static VO:

This VO is exposed through Application Module Data Control. Keep in mind, even VO is static - AM still we be initialized on VO access. This means AM will establish connection to database, at that time when we will load static VO data. Custom Data Source name will not be set yet - default Data Source name will be used. Instance of static VO with list of Data Sources:

UI list with Data Sources can be created by drag and drop of DataSourcesView1 instance from Data Control into JSF page. Select Single Selection -> ADF Select One Choice option:

Once choice list was created, go to Login page definition and create Name attribute binding (based on same iterator as Data Source choice list):

This will allow us to access selected Data Source name from Login bean - doLogin() method:

Here how it looks on runtime - user selects Data Source from the list:

User logs in into application - Application Module configuration is initialized with Hr DB data source and data is rendered:

From the log we can see that after login, session cookie was changed. This happens because there are two Web sessions created always - before and after login (its how it works by default in ADF). This allows us to set custom Data Source name after login action is done. Remember - before login, Application Module is initialized with default Data Source:

Hr Test DB - is non existing Data Source, I'm using it only for test purpose - application should fail, to prove Application Module is using Data Source selected during login:

Indeed application breaks:

From the log we can see that Application Module was trying to connect with jdbc/HrTest Data Source - correct as expected:

Wednesday, August 15, 2012

There is requirement, when we need to disable/enable editable data access globally per user session for entire application. When implementing this requirement, you should keep in mind ADF BC passivation/activation - data should stay in correct state even between activation/passivation iterations. Global control for editable mode in ADF BC can based on - Solution for Sharing Global User Data in ADF BC. Sample application in this post, is based on that article. Described solution for global editable/readonly mode is generic across all Task Flows, EO's and AM's, there is no dependency to specific Task Flow, EO or AM.

Editable/Readonly access is set from session scope, user can trigger it by certain action. We should not access session scope directly in ADF BC, its why we override Data Control class - CustomADFBCDataControl (read more here) and pass session scope value into ADF BC User Data. CustomADFBCDataControl class contains overriden executeIteratorBindingIfNeeded() method responsible to prepare iterator binding, this method is called each time when data collection is accessed, it allows to pass correct editable or readonly flag and store it in User Data. Custom User Data is passivated/activated with ADF BC lifecycle, same data is accessed from generic EO implementation class isAttributeUpdateable(int) method.

Solution is tested with disabled AM pooling, to proof it works under stress load:

In the log you can see that, two AM were initialized - Locations and Departments. Data access (readonly/editable) variable was passed each time when data was accessed from iterator:

This allows to mark EO attributes in generic EO class for editable/readonly access.

Sample application implements different Task Flow for each tab, this means editable/readonly access is independent of Task Flow and control directly in ADF BC level through custom User Data variable initialized from Data Control class on data access generically: