Saturday, September 24, 2011

What you may need to know about DBTransaction::postChanges()

In some specific use case scenarios both entity objects and stored procedures may need to co exist in your business logic implementation. This may arise if you are migrating(replacing) existing applications with ADF based application, and your customer wants to reuse some pieces from the legacy application. When you start identifying reusable pieces, in most of the cases, all eyes may be on stored procedures - we may need to accept the realities ;). As the data update logic is scattered across entity objects and stored procedure you may end up in calling DBTransaction::postChanges() to post the entity changes to data base before invoking stored procedure. Usage of DBTransaction::postChanges() is permitted if you commit the transaction within the same request. However there are some points you may need to aware of to make your implementation more perfect.

 To understand the DBTransaction::postChanges(), let us take step back and analyze the transaction commit cycle first. Consider a typical use case , where you have modified entity data, and finally you call DBTransaction::commit () to commit the transaction.
The sequence of actions that happens behind the transaction commit cycle are as follows:
The DBTransactionImpl calls...

  1. applicationModule::beforeCommit() 
  2. validate for each entry in validation listener list ( this in turn validates each EO )
  3. applicationModule::afterCommit() 
  4. postChanges() on each entry in transaction post listener list 
  5. beforeCommit for each entry in transaction listener list 
  6. commit transaction 
  7. afterCommit() for each entry in transaction listener list - EO/VO cache is cleared based on the configurations.

DBTransactionImpl maintains 3 lists to carry out the commit cycle. 1. validation listener list 2. transaction post listener list 3.transaction listener list. When you dirty an EO instance, it will get added to these three lists. If you call DBTransaction::postChanges(), step 4 alone gets executed from the above sequence and this operation clears transaction post listener list alone. In nutshell EOs will remain attached to the validate/transaction listener list till you call commit. This may have some side effect in certain scenarios.
 In case if you need to invoke postChanges() multiple times, you can manually clear the above said lists as shown in the following code snippet
    // Get VewRowImpl someVewRowImpl from VO  
    someVewRowImpl.setAttribute( "SomeAttrib","New Value");  
    EntityImpl someEOImpl = someVewRowImpl.getEntity(0);  
    DBTransaction txn = getDBTransaction();  
    txn.validate();  
    txn.postChanges();  
    txn.removeTransactionPostListener(someEOImpl); 
 
    //The below two lines may cause your EO to skip 
    // beforeCommit() and afterCommit() call backs.
    //Normally you can skip the below two lines, 
    // use it if you need to clear the EO cache once data is posted to DB
    // This makes sense if you have millions of rows in an update and
    // and you want to get rid of the cached rows without any delay
    txn.removeTransactionListener(someEOImpl); 
    txn.clearEntityCache(null);   

Wednesday, September 14, 2011

Forcing Task Flow instances with Shared Data Control to use different view object instances

If you have have a task flow designed to use shared data control, and still don't want different instances of task flows to use same view object instances, then this post is for you.

Use case: Multiple instances of task flow should share same transaction context, however each UI should work independently when they are embedded in a parent page. As of now, there is no direct support for this. In this post I'm sharing a work around solution for this kind of scenario.

Solution: As I said earlier, this is just a work around solution, and intended to give you some idea on the implementation. Feel free to modify the code in the attached sample to meet your use cases.

Step 1. Edit the iterator used for for those pages fragments which needs to work independently, and alter binding for the view object instance used for this iterator to use an EL. EL takes the view object instance name from a PageFlow scoped variable.

 <iterator Binds="#{pageFlowScope.VOInstName}" RangeSize="25" DataControl="AppModuleDataControl" id="DepartmentsView1Iterator"/>  

Step 2. The PageFlow scoped variable that stores view object instance name used in the EL(step1 ) is populated from task flow initializer with some unique names. Task flow has a default method activity defined which will create corresponding view object instance in the Application Module before showing the page.

Download

You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

A glance at the implementation

Run main.jsf.
This page contains multiple instances of dept-task-flow-definition. However the page fragment used in each instances of task flow works independently using different view object instances eve though the dept-task-flow-definition has shared Data Control scope. This is done using the above idea. Take a look at TaskFlowDCHelper class to learn more about the implementation. Method TaskFlowDCHelper::initDataSource() generates the view object instance name for each instance and the same is set as initializer for dept-task-flow-definition. Method TaskFlowDCHelper::cleanupDataSource() is set as finalizer for task flow.

Transient attributes as Primary Key for a View Object, a bad idea?

Answer is YES for certain use cases where
1. Recalculation of transient attributes are expensive and
2. If the run time needs to touch PK attribute multiple times while serving requests from a client. An example for this scenario may be expanding multiple level of tree node. Please note that in this case the value of transient attributes are getting recalculated each time. In such scenarios, better go for other option like SQL derived attributes, if feasible.

Thanks to Blaise Ribet who shared this point!

Tuesday, September 6, 2011

Programmatically switching LOV queries at run time

In today's post, I'm Sharing a simple application which make use of ViewObjectImpl::prepareRowSetForQuery(ViewRowSetImpl vrs) on LOV source view object to alter the query at run time. LOV switcher is the ideal solution to switch LOVs at runtime. However there are odd scenarios where you may have N number of data sources for LOV which is known only at run time. This approach may work for you in such cases. [ The concept used in this post is inspired by a solution provided by Steve Muench in an internal discussion thread ]

Download

You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

A glance at the implementation

1. Run test.jspx
2. Data source for LOV defined on ManagerId changes based on the values keyed in for DepartmentId field. If you leave Department empty, data is queried from EMPLOYEES table. If DepartmentId present for the row data for LOV is queried from DEPARTMENTS table for DepartmentId. The query switching is done programmatically from the over ridden prepareRowSetForQuery(...) method. Note that ViewObject definition doesn't change in the implementation, query alone changes.

Please see ManagerViewObjImpl::prepareRowSetForQuery(ViewRowSetImpl vrs) to learn more about the query switching details.

Thursday, September 1, 2011

Hot Deployment - What Works, What Doesn't, What's Promising

Hot Deployment was one of the coolest feature of 11.1.2.0.0 release. Look like there are lot of confusion centered around on this topic. This post is meant for clarifying the offerings on Hot Deployment available with JDeveloper 11.1.2.0.0 release

Hot Deployment - What Works and What's Promising?
Please see 36.4 Reloading Oracle ADF Metadata in Integrated WebLogic Server in Fusion Developers Guide. Below is the excerpt for your quick reference ....

JDeveloper support for hot reloading of Oracle ADF metadata is an alternative to quitting the running application, editing your project's XML definition files, redeploying, and rerunning the application in Integrated WebLogic Server to view the latest changes.
Changes that you make to the Fusion web application projects will not be picked up automatically by an application that you have deployed to Integrated WebLogic Server. You can, however, reload metadata from the data model project and user interface project any time you want to synchronize the running application with changes you have made to your application's XML definition files.
To reload metadata so your changes are reflected in the deployed Fusion web application, you must recompile the project and refresh the web browser.
Metadata that JDeveloper will hot reload in Integrated WebLogic Server, include:
  • In the data model project, changes to the definition files of business components.
  • In the user interface project, changes to the binding definitions in the page definition files and changes to task flows in the task flow definition files.
This support makes it possible to make incremental changes and test them.

What doesn't work and why?

Well, simply changing the meta xml files or class files will not have any effect on runtime unless you recompile the project and refresh the web browser. This is because the DefinitionManager responsible for detecting meta xml file changes will not check the source folder for changes,rather it will scan output path for modified items. Apparently recompiling the project copy the meta files and class files to the output folder and all works after this step.

Please note that, your web page will continue detecting the changes dynamically(without recompiling the project) as it was doing in prior releases.