Wednesday, November 27, 2013

UKOUG Tech13 - Red Samurai Real ADF Experience Sessions

UKOUG Tech13 conference is around the corner and we are completely prepared. My colleague - Florin Marcus and myself, will be presenting together our sessions this coming Sunday, December 1st at UKOUG Tech13 Super Sunday event. If you are around, please stop by and ask ADF questions - we are going to be more than happy to help you out.

I would like to post short summary about sessions we are going to present. There are two sessions:

1. ADF Anti-Patterns: Dangerous Tutorials


We are going to share very important hints, usually hidden behind typical ADF tutorials available on the Web and demo side-effects for various default ADF settings. This will be live ADF code session, each of the points will be explained directly in JDeveloper, without using boring Power Point slides.

There will be real ADF tuning tricks explained, collected through years of ADF experience.

2. ADF Development Survival Kit


Wouldn't it be great to hear how to build your own ADF Performance Audit Tool? We are going to explain how our ADF Performance Audit Tool works and even more important - how it is built, so you can build yours, once back home. Here is architecture preview to be explained:


We are going to focus on importance of PL/SQL code reuse while building ADF applications and modernizing Oracle Forms systems. There will be a demo, followed by detailed explanation how our PL/SQL reuse tool for ADF is implemented and how it works from ADF BC:


We are going even further than that - will be explaining Red Samurai process to reuse existing PL/SQL or Web Services code in ADF BC through automation and injection:


Thanks for reading my blog and hope to see you on UKOUG, will be extremely happy to chat with you - blog reader.

Sunday, November 24, 2013

Controlling ADF BC Mandatory Attribute Validation Conditionally

I was looking for a solution to control ADF BC attribute mandatory validation conditionally, and there is one - we can implement dynamic switch for attribute mandatory validation. Thanks to Steve Muench, who was helping to implement this requirement - I'm able to provide working sample. The main idea is - based on master attribute value, set dependent attribute to become mandatory/non-mandatory automatically. This will be implemented by controlling dynamic mandatory attribute rule in ADF BC level.

Make sure to download sample application, to test this use case - DynamicMandatoryAttrApp.zip. Test is fairly simple, there is special column displaying true/false values - meaning if CommissionPct attribute is set to be required or no in the current row. CommissionPct attribute is set to be mandatory, if Salary attribute value is greater than 10000:


You should see for Employee ID = 108, CommissionPct attribute is set to be mandatory. Try to set Salary attribute value for this employee to be less than 10000, CommissionPct attribute becomes non-mandatory instantly:


We are going to check now, how such functionality is implemented in ADF BC. There is custom Entity Attributes Hints class registered in EO implementation class:


Through this custom class we can intercept all calls to ADF BC to retrieve hints for given attribute. Mandatory property is one of the hints, this is how we can return true or false conditionally.

If you are running ADF version starting from 11g R2 or 12c, there is internal issue - it requires to set attribute index explicitly through getAttributeHints(name) method. Otherwise, custom class for Entity Attribute Hints - will be ignored:


In the custom class for Entity Attribute Hints, we can override standard method - getHint(locale, name). In this method we could evaluate conditionally or mandatory checks, as in this example CommissionPct attribute is marked to be mandatory, only if Salary value is greater than 10000:


Initially, CommissionPct attribute is set to be non-mandatory:


There are several changes required on ADF UI level, to make it work correctly. I would recommend to set contentDelivery=immediate and immediate=true for the ADF table component, this allows to reduce number of validation error popups:


When Salary attribute changes, we need to refresh dependent CommissionPct attribute, however it would not work to use regular PartialTrigger dependency and bypass validation error. We need to create binding reference and call partial target refresh programmatically. Read more here - Conditionally Required Fields in Oracle ADF Faces Rich Client. Similar binding is created for Panel Collection:


Salary attribute is set with AutoSubmit=true and Value Change Listener (we refresh table component):


Refresh is done from table component:


Make sure to change ADF UI mandatory expression, to use row.bindings.CommissionPct.hints.mandatory. Otherwise, with default expression generated for ADF table column attribute by JDeveloper, ADF UI fails to trigger getHint method in ADF BC for mandatory check:

Saturday, November 16, 2013

Creating ADF BC View Object Instances On The Fly

This post is to describe such use case, where we have a set of common Entity Objects and want to handle View Objects and UI dynamically. This is common use case for simpler screens, usually common Entity Objects are provided from the library, but instead of creating hundreds of similar View Objects and UI fragments - we can handle such screens in generic way, by creating View Object instances programmatically and later using them through dynamic iterator.

Sample application - ADFDynamicReportUI_v3.zip is based on my previous post - ADF Generator for Dynamic ADF BC and ADF UI - Recreate. This sample is utilising ADF BC API for ViewDefImpl, VO instances are created and registered on the fly using this API.

There are two EO's created in the sample application:


Custom method is defined in Application Module implementation class - constructVOInstance, this method is used to create VO instances programmatically:


Here you can see how VO instances are created and registered:


We pass as a parameter - EO name, based on this name for VO is constructed. We check if VO with the same name already is registered, if not - VO will be created from EO. There is no need to set attributes one by one for VO, we can get all attributes directly from EO. SQL statement is created by API, based on EO information. Finally - create VO instance, based on VO definition, this will expose it to the Data Control and we could access it later on runtime from bindings. VO name is returned by the method, this is used later in the page definition to supply dynamic reference to the iterator.

Dynamic reference of the VO instance is defined in the page definition, I'm getting it from Page Flow Scope (initialized through Method Call activity calling dynamic VO construction method):


UI table is rendered with the help of ADF dynamic table component, this is pretty easy part:


Before actual UI fragment with the table is opened, we call Method Call activity and invoke dynamic VO construction method exposed through AM client interface - this allows to prepare current VO instance based on passed EO name parameter:


EO name parameter is defined as required on the task flow level, rendering UI fragment with dynamic table:


For the test purposes, I have created simple main page and passing parameters for Employees and Departments having two different regions. In real use cases, this can be changed by loading the same region and passing different EO name from menu model:


Here what we can see on UI - first tab brings dynamic VO instance for Employees:


Second tab brings another dynamic VO instance, reusing the same UI - this time for Departments:

Sunday, November 10, 2013

ADF Controller Save Points - Save For Later Implementation with PS_TXN

This blog post will be based on ADF Developer Guide section - 24.7 Using Save Points in Task Flows. I will be describing out of the box 'save for later' functionality provided by ADF BC (Model) and ADF Task Flows (Controller). This will be especially useful for complex forms, where users would prefer to save their work in progress and come back to it later, to finish with the remaining details. We could split transaction and allow to complete that transaction later, even during next login. Such functionality can be achieved with ADF out of the box feature - Save Points (see link to the documentation provided above). In the background Save Point functionality is based on passivation/activation process handled in PS_TXN table. Save point is creating labels and associating these labels with temporary data stored in PS_TXN.

Sample application - ADFTaskFlowSavePointApp.zip, is enabled with Save Points. To enable Save Points support, is enough to provide Data Source for the Save Points:


ADF application should create required table for Save Points automatically, same as PS_TXN table. Table for Save Points - ORADFCSAVPT. This table keeps information about current Save Points for every user:


ADF Task Flow, where we would enable Save Points is same as any other ADF Task Flow. There is only one extra activity created - Save Point Restore. This activity takes Save Point ID and restores it:


Save Point Restore activity takes Save Point ID to restore through property:


Looking from UI perspective, Save Point management can be implemented with options to create Save Point, display a list of previously created Save Points and restore one of the selected Save Points:


Create Save Point method is using Save Point Manager API to create new Save Point:


The same Save Point Manager is used to remove previously created Save Point. In order to restore Save Point, we need to provide Save Point ID, this is retrieved from the list:


List with Save Points is populated through Save Point Manager API and is exposed through Data Control:


We can test it now, sample application is enabled with ADF Security and we can login with redsam user:


Navigate to the next row and change Hire Date value - create new Save Point by providing its name and pressing Create Save Point button - newly created Save Point will appear in the list:


Login with another user - scott:


Save Point API is aware about ADF Security Context and it knows there are no yet Save Points created for scott user:


Let's create one after changing Salary value:


And one more after changing Hire Date value, now both Salary and Hire Date will be added to Save Point:


We can see in the DB table, there are three Save Points created. One for redsam user and two for scott - names are taken from ADF Security by Save Point API automatically:


Here is the prove for my earlier statement - Save Points are working based on PS_TXN passivation/activation. When Save Point is created - passivation happens. Later during Save Point restore, it activates data based on Save Point label from PS_TXN table:


You can get similar log displayed, by setting FINEST ADF log level for oracle.jbo package:


Let's login again with redsam user and try to restore previously created Save Point:


After login, data from DB is displayed as it should be:


Choose to restore previously created Save Point - Pending hire date change. This will reset current row and apply edited data for Hire Date:


User can continue with data change and transaction.

Login with the second user - scott:


Data is loaded from DB, there are two Save Points available in the list:


Select first one - to reset current row and bring edited Salary value:


Select second one - both Salary and Hire Date will be reset to edited values:


I can see ADF Controller Save Points very useful in combination with ADF BC for complex forms implementation, where we need to provide option to split or delay transaction. This is possible because of ADF BC - another plus for ADF BC in ADF.