Sunday, November 28, 2010

Immediate Row Level Lock Management for ADF 11g Transactional Applications

Oracle ADF 11g framework is primarily designed for enterprise applications. Majority of enterprise applications are processing user transactions, it is important to preserve proper transaction state for every user. Oracle ADF 11g out of the box provides pessimistic and optimistic locking support - Optimistic and Pessimistic Locking in Oracle ADF BC. Generally, optimistic locking is recommended for Web applications, pessimistic locking mechanism will lock current record once user will edit it. However, for specific applications (especially bank and insurance sector), we have quite natural business requirement to lock record directly after this record was opened for editing. Such type of locking is stronger than pessimistic locking - it locks record even before user starts editing it. Its very important to understand how to tune and control ADF 11g runtime parameters, when implementing immediate locking solutions. Today I will describe how immediate locking use case can be implemented with ADF BC and ADF Task Flows. My next posts will provide information about ADF BC parameters tuning for reliable immediate row locking mechanism.

Download sample application - RowLockingApp.zip. This sample contains one ADF task flow based on JSF fragments. Default activity represents read-only table with Employees data. When user hits employee editing button, navigation is passed to Method Call activity - it invokes method from Application Module Implementation class to lock current record from Employees VO. If current record is not locked by another user - lock is set and editing screen opens successfully. Otherwise, if current record is already locked by another user - we render information message and display data in read-only mode:


Immediate row locking mechanism is implemented by overriding AM and EO implementation classes:


Custom row locking method from AM implementation class is exposed through client interface:


This method retrieved current row from VO and invoked VO lock method. If current row is already locked by another user or lock fails, we catch exception and return negative parameter value into Controller layer:


If current row is already locked, we want to render it in read-only mode. This can be achieved by overriding isAttributeUpdateable(int i) method from EO implementation class. If attempt to lock current record failed, this means user can't edit any attributes - read-only mode:


Controller layer receives result of locking method from AM implementation class and stores into Page Flow Scope:


This value is used to render or not information message about failed locking attempt:


Rendered property is referencing value from Page Flow Scope:


If current row was not locked by another user and current user performs successful lock - lock will remain until user will commit or rollback his changes for current row. Its almost true, but not completely. What will happen if user will close browser without performing commit/rollback or even without doing proper logout action? Good news - obtained lock will be removed automatically, after web session times out. After web session time out, database connection still will remain open and can be reused by another AM instances. However current web session AM instance will be destroyed, this means database lock obtained by that session also will be removed. This means if user will forget to commit/rollback or logout, longest time when current row will remain locked is equal to web session time out time. You should keep this in mind, when configuring and tuning your ADF 11g application. Default web session time out - 30 minutes is sufficient in most of the cases.

In order to test locking behavior, I have set web session timeout to 5 minutes:


Let's experiment a bit and see how it works. User A logs in into application and opens Employees list screen:


User A select record and opens it for editing, lock is applied automatically:


We can see from the log, lock is successful for user A:


Another user B selects the same record:


And opens it for editing, however same record is already locked by user A - lock for user B fails and data is rendered in read-only mode with information message:


Lock for user B fails:


Lock from user A will remain until commit/rollback or logout. Let's say user A will not do any of mentioned actions and just will leave from his work place by closing browser or keeping it open. Two sessions, one for user A and another for user B are active:


Because of inactivity, user A session will timeout after 5 minutes (as it is set in web.xml) and AM instance will be released:


When user A will return to check his work, he will receive session timeout message and will be forced to login again - of course lock will be lost:



Next release of ADF 11g - PS3 provides user-friendly popup message for session timeout.

After waiting 5 minutes (session timeout for user A), user B will be able to lock released record and perform required changes:


4 comments:

  1. Hi, I was trying your sample application. But it asked for a login for jazn.com when I ran the application. What is the login to use the application?
    Thanks,

    Also, I've tried the suggestion in my own application and couldn't get it to work.

    my code:

    if (groupEO.isLocked()){
    throw new Exception("already locked");
    }
    else{
    try{
    groupEO.lock();
    }
    catch(Exception e){
    throw new Exception("lock failed");
    }
    }

    What I observed is that when session A entered the lock, groupEO.lock() succeeded and groupEO.isLocked() returned true after the lock() call (was false before). But when session B entered the method, groupEO.isLocked() was false instead of true and it went ahead and executed lock() successfully. Appears that the two locks aren't the same lock.

    ReplyDelete
  2. Yes of course, you must run it with ADF Security enabled. See jazn-data.xml, there is default user redsam/welcome1 defined.

    Andrejus

    ReplyDelete
  3. Hi! first congratulation for the blog. I was trying to implemet lock in my application. Lock work correctly only if i set a breakpoint into isAttributeUpdateable methods. If i run application without breakpoint the page is always locked. why? thanks a lot

    ReplyDelete
  4. I was trying to implemet lock in my application. Lock work correctly only if i set a breakpoint into isAttributeUpdateable methods. If i run application without breakpoint the page is always locked. why? thanks a lot

    ReplyDelete