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.

Monday, November 4, 2013

Smart Declarative Mode Support in ADF BC View Object Join

Declarative mode is known feature of ADF BC and promoted by Steve Muench back in 2008 - Declarative Data Filtering. Declarative mode allows to construct SQL statement on runtime dynamically, based on displayed attributes and ADF bindings in page definition. This is specifically useful for systems created with ADF, where tables are generic and contain long list of attributes. Instead of loading all attributes from DB, it makes perfect sense to load only required ones. There is one more cool feature of declarative mode - it knows how control SQL join on View Object level. Meaning - if attributes coming from joined EO are not rendered, ADF BC will update SQL statement and remove such join. Runtime control for joins is really important, as it may give real additional performance to the system.

Here you can see, what I'm talking about - Jobs EO is joined into Employees VO to provide additional attributes:


Empoyees VO is configured with Declarative mode - SQL statement is hidden, as it will be constructed dynamically on runtime:


Here is important hint - as you might be confused why Declarative mode doesn't work. You must go and set Selected in Query = false for each attribute in the VO. It seems to me like a JDEV bug, this should happen automatically. In this example, Selected in Query = false is set for Email attribute and all others:


There are two attributes added from joined Jobs EO - JobTitle and JobId. These attributes are set with Selected in Query = false as well:


There are two ADF task flows created for test purposes. Both are set with Isolate mode, in order to maintain separate instances of Employees VO. I will be using different sets of attributes in both of these task flows, to demonstrate that Declarative mode really works:


First ADF task flow brings table with 6 attributes. You should pay attention - there are no JOBS related attributes coming from the join:


Make sure ADF Logger is set to FINEST level for oracle.jbo package, this would allow to see a log output from ADF BC and spot executed SQL statement:


Table from above generates SQL statement for 6 attributes, as expected. There is one more great thing - SQL join with JOBS table is skipped, as there are no attributes displayed from that join:


Go to the second ADF task flow, here we are displaying 3 attributes only. One of these attributes - JobTitle, coming from the SQL join:


As it would be expected - SQL join is constructed in this case and 3 attributes are included into SQL query. This would result in less traffic between DB and the server, comparing to the default case when we would fetch all attribute values:


Download sample application - DeclarativeModeApp.zip.

Saturday, November 2, 2013

Find By Key and View Criteria Row Finder Methods vs. Get Row Method in ADF BC

You may have seen my previous blog post - WebLogic Stuck Thread Case - Large Fetch Generated by Get Row ADF BC Method. Blog reader was asking if it would be a solution to use instead of Get Row method, alternative methods - Find By Key, or View Criteria. Yes, these two methods perform much better comparing to Get Row, and there is no full intermediate row range scan.

I would like to present updated sample application, where these two methods mentioned above are implemented and tested - LargeFetchApp_v4.zip. Application module implementation class contains two methods, one for Find By Key (intentionally, I'm using key to be at the end of row set) and another for Row Finder based on View Criteria. If I would use View Criteria directly, rowset will become filtered, instead I'm using 12c feature Row Finder, it allows to use View Criteria to search for rows in the current rowset:


I'm using JDEV 12c, this is how Row Finder is defined (you can read more about Row Finder in my previous post - ADF BC 12c New Feature - Row Finder):


Row Finder is using View Criteria, search is done by the same key as in Find By Key method:


We load ADF table and press Find By Key method:


Instead of fetching all rows up to a row with a key 10099 (as it happens with Get Row method), new SQL query is executed and one row is fetched - as we need:


Press Find By Criteria to test second approach with Row Finder and View Criteria:


View Criteria calls new SQL query to search by ID and returns only one row, instead of fetching all rows:


This shows - both method are good enough and perform better than Get Row method. You should choose one of these methods, based on use case requirements.