Sunday, February 27, 2011

Yet another reason for "JBO-25014: Another user has changed the row with primary key oracle.jbo.Key"

I've discussed one possible (tricky) reason for JBO-25014 error in one of my previous post - 'What you may need to know about Nested Application Module' . Recently I noticed yet another interesting reason for the above said JBO-25014 error. Let me summarize the same for the benefit of the ADF community.

Use case

This use case has two view objects - SimpleEmployeeViewObject and DetailedEmployeeViewObject, both are based on the same entity object - EmployeeEntityObject. A specific business functionality is implemented using the above ViewObjects as listed below.

1. SimpleEmployeeViewObject queries the DB by calling SimpleEmployeeViewObject.executeQuery(). The code doesn't fetch any records at this stage(I meant that, this code just got the executeQuery call, no iteration logic). However this call results in the creation of result set/cursor, and leaves it opened.

2. Then, DetailedEmployeeViewObject queries by calling DetailedEmployeeViewObject.executeQuery(). Here the code fetches set of records and modifies the record with EmployeeID = 101.

3. Commits the Transaction, and then call DetailedEmployeeViewObject.clearCache()

4. As a next step, SimpleEmployeeViewObject tries to get the employee record with EmployeeID = 101. Note that, SimpleEmployeeViewObject does not call executeQuery here, instead queries the RowSet(retrieved at Step 1) for the record. This may return the stale row from the opened cursor, and apparently this row doesn't reflect the modified attributes from database (committed at Step 3). This step modifies the retrieved record and commits the transaction.

5. At Step 4, the 'commit' operation may tries to locks the row, it compares the original values of all the persistent attributes in the entity cache as they were last retrieved from the database with the values of those attributes just retrieved from the database during the lock operation. Apparently this may throw "JBO-25014: Another user has changed the row with primary key oracle.jbo.Key[101]" as the entity object is populated with a stale row set.

What is the solution ?

The solution is to close the opened cursor(result set) having the stale data after the commit at Step3 ( before the next transaction). Please note that, ADF BC runtime closes the result set/curosr as part of Transaction::rollback(). However Transaction::commit() doesn't touch the opened cursors, by default.

The easiest work around here is to call SimpleEmployeeViewObject.executeQuery() before step4. Either you can do it through a explicit call or you can move this call to SimpleEmployeeViewObjectImpl::afterCommit(TransactionEvent event) method.

Re-querying all View Objects on commit

On a related note, you can configure a specific Application Module to refresh all its View Objects after the commit of a transaction by setting RequeryOnCommit="true". This setting may cause all the 'queried' View Objects of the Application Module to requery/refresh after the commit. This setting also may help you to solve error that we discussed in this post (You should be careful while keeping this ON as this result in expensive requery of all View Objects belonging to the Application Module).

 <AppModule  
  xmlns="http://xmlns.oracle.com/bc4j"  
  Name="AppModule"  
  Version="11.1.1.59.23"  
  ClearCacheOnRollback="true" RequeryOnCommit="true" 
  ComponentClass="model.AppModuleImpl"  
  ComponentInterface="model.common.AppModule"  
  ClientProxyName="model.client.AppModuleClient">  

Tuesday, February 22, 2011

<af:setPropertyListener> not working on <af:popup> with childCreation="deferred" !

You should be careful while using <af:setPropertyListener> on <af:popup>. There is a known limitation when you use <af:setPropertyListener> with 'popupFetch' type to initialize the properties/parameters for a <af:popup>. The relevant jsf snippet may look like as shown in the following diagram.

 <af:popup id="p1" contentDelivery="lazyUncached"  
       childCreation="deferred">  
  <af:setPropertyListener from="'check'" to="#{requestScope.params}"  
    type="popupFetch"/>  
  <af:dialog id="d2" title="Check">  
   <af:outputText value="Param from the caller: #{requestScope.params}"  
    id="ot2"/>  
   </af:dialog>  
 </af:popup>    

When you run this page, you may notice that the setPropertyListener with a popupFetch type is not getting called for the first time, and the same works without issues from next time onwards.

What goes wrong here?

Let me try to summarize the reason for this behavior. In the above jsf snippet, <af:setPropertyListener> resides inside the popup body which is not available/processed when the parent page renders for the first time because of the deferred 'child creation' settings (childCreation ="deferred") for the popup. With this deferred configuration popup body is processed when you really ask for it. Please note that, af:setPropertyListener is expected to be evaluated/processed during the Apply Request Values phase in JSF life cycle which may happen much before the Render Response phase. When user opts to view popup, reuest reaches server and JSF lifecycle starts. As there is no popup body at this stage, there is no af:setPropertyListener tag for processing at Apply Request Values phase. Later in the JSF life cycle, popup body is processed at Render Response phase. Apparently next request for showing popup may have fully processed popup body in place, and everything may work as expected at this time.


The work around solution is to use the popupFetchListener method to establish state(pass parameters) instead of <af:setPropertyListener>. If you modify the above jsf snippet as shown below, this use case will work.

 <af:popup id="p2" contentDelivery="lazyUncached"  
       childCreation="deferred"  
       popupFetchListener="#{TestBean.popupFetchAction}">  
  <af:dialog id="d3" title="Check">  
   <af:outputText value="Param from the caller: #{requestScope.params}"  
             id="ot3"/>  
  </af:dialog>  
 </af:popup>  
 public class TestBean {  
  public void popupFetchAction(PopupFetchEvent popupFetchEvent) {  
   ADFContext.getCurrent().getRequestScope().put("params", "check");  
  }  
 }   

Please note that this issue is being tracked as an 'Enhancement Request' by ADF Faces team. Once this is done the above stated limitation is no longer valid.



Learn More ...

There are a lot more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html

Overriding Control Hints of a View Object on the fly

I recently came across a use case where the requirement was to fetch Attribute Hints(display width, label etc.) for a View Object(and Entity Object) on the fly from an external system. Let me share a simple possible solution for this specific use case.

A glance at the implementation

The idea is to override ViewRowImpl::createViewRowAttrHints(AttributeDefImpl attrDef) to return a custom implementation of ViewRowAttrHintsImpl class. The same concept has been discussed in one of my previous post sometime back - Decorate UI with view row Attribute's User Interface hints. Please note that, this is the place( custom ViewRowAttrHintsImpl class - LazyViewRowAttrHintsImpl) where we are adding the hook to retrieve the Attribute Hints from third party service.

@Override
protected ViewRowAttrHintsImpl createViewRowAttrHints(AttributeDefImpl attrDef) {
  return new LazyViewRowAttrHintsImpl(attrDef, this);
}

The constructor of LazyViewRowAttrHintsImpl may look like as shown in the following code snippet. Please take a look at th source of LazyViewRowAttrHintsImpl.java to get a feel of the implementation (work space is attached at the end of this post).


 public class LazyViewRowAttrHintsImpl 
                     extends ViewRowAttrHintsImpl {
  
  public LazyViewRowAttrHintsImpl(
           AttributeDefImpl attributeDefImpl,
           ViewRowImpl viewRowImpl) {
    super(attributeDefImpl, viewRowImpl);

    //The following call retrieves AttrHints 
    //from third party service
    //and add the same to Attribute Defn of VO
    decorateWithLazyHints(attributeDefImpl);
  } ...

You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS3 + HR Schema]

How to run this sample?

Please run the dept.jspx. You may notice that default UI hints ( such as label, field width etc. ) are overridden with values from a dummy service( UIHintsService ).

Customizing the width of a UI control using contentStyle attribute

You can use contentStyle attribute to override the default width of specific types of UI controls. This property is applicable for single select and multiple select controls( af:selectOneChoice, af:selectManyShuttle, af:selectBooleanRadio etc.) and input controls( af:inputText, af:inputRangeSlider, af:inputListOfValues,af:richTextEditor etc. ).

<af:selectOneChoice  contentStyle="width:200px" label="Select an Item:" id="soc1">

From Web User Interface Developer's Guide ...
If the field is wider than the space allocated, the browser will not truncate the field but instead will take space from the label columns. This potentially could cause the labels to wrap more than you would like. In this case, you may want to consider reducing the width of the field contents (for example, use a smaller contentStyle width on an inputText component).

However, you should be cautious while using 'contentStyle' to override the default width of the controls, especially with controls like af:selectOneChoice. In case of af:selectOneChoice, by default, run time would try to set the 'width' by considering the maximum size of the displayed list item values. This 'defaulting behavior' is useful if your application is later enhanced to support a different language where the width of the af:selectOneChoice may vary based on the language characteristics.

Wednesday, February 2, 2011

Creating Custom History Types

While dealing with business data, 'history' has its own role to play. The 'history' here means, data specific to a point in time. Most of the enterprise application may capture audit information when the user commits a business transaction. These audit data may includes previous value of some sensitive attributes, user who modified the data, modified date etc. ADF BC framework ships with a number of history types, but you can also create your own on need basis.

Life cycle of a 'history type' attribute

Question here is, who does update these attributes (and when)? Well, this job is done by the ADF BC run time at prepareForDML phase of a transaction post cycle. When you commit/post a transaction, Transaction Manager would take each entity object through a transaction post cycle as shown in the following diagram.


prepareForDML - Issues pre-doDML ntofication for all entities, this is used to assign history values before an entity row is saved. Run time uses attribute definition to identify the nature of each attribute and takes appropriate actions.

doDML - Performs the appropriate SQL Data Manipulation Language operations on the database to reflect an update, delete or insert operation on an Entity Object beforeCommit

beforeCommit - This is invoked on each modified entity instance after the changes have been posted to the database, but before they are committed. Last chance for you to validate your business data(if you have some data validation logic built using stored procedure, you can hook that call here). This is also a place for invoking third party services passing data from the current entity instance.

afterCommit - Send notifications about a change to an entity object's state. This is invoked on the entity instance after committing data to DB.

History types are very much extensible in ADF, you can build your own history type without much effort. This part is very well documented in Fusion Developer's Guide, please see topic 38.10 Creating New History Types to learn more. In this post, I'm sharing simple example built using custom history type.

You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS3 + HR Schema]

A glance at the implementation

This example captures the old value of DepartmentName attribute using DepartmentNameAudit field whenever DepartmentName changes( DepartmentNameAudit is a custom 'history type'). I'm highlighting the steps for creating custom history type used in this example - 'modified value'.

1. Define a new history type(modified value) using the editor( Tools->Preferences->Business Components->History Types)


2. Provide implementation for the custom history type by overriding EntityImpl::getHistoryContextForAttribute(...)

@Override
protected Object getHistoryContextForAttribute(AttributeDefImpl attr) {

  if (attr.getHistoryKind() == MODIFIED_VALUE_HISTORY_TYPE) {
  // your logic goes here
  // return the value for the history type attribute
  }
  return super.getHistoryContextForAttribute(attr);
}


3. Mark the desired attribute using newly defined history type



How to run this sample?

1. Download the source and extract this to you local host.

2. This example uses HR schema. The attribute DepartmentNameAudit in Departments entity is mapped to OLD_DEPARTMENT_NAME column in DEPARTMENTS table. If you want to run the sample, then please add this extra column to DEPARTMENTS table.

ALTER TABLE DEPARTMENTS ADD OLD_DEPARTMENT_NAME varchar2(30);

3. Run main.jspx

4. Modify Department Name field and commit the changes. Please see the corresponding record in you database table(DEPARTMENTS). The column OLD_DEPARTMENT_NAME may have the previous value of DEPARTMENT_NAME.


Learn More ...

There are a lot more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html