Tuesday, February 9, 2010

A sample ADF BC application based on StoredProcedure

Sometimes you may need to use stored procedures/functions to read/write data from underlying tables. You can still leverage the benefits of ADF persistence layer by smartly wrapping the stored procedures using ViewObjects and EnityObjects.
I’m sharing a sample ADF BC application that uses stored procedures for reading and writing to the table.

Solution is simple and straight forward...
1. Create an EntityObject and override the below methods
   protected void doSelect(boolean lock)
   protected void doDML(int operation, TransactionEvent e)
Please refer the below topic in Fusion Developer's Guide to learn more …
38.5 Basing an Entity Object on a PL/SQL Package API

2. Define a ViewObject based on the above EntityObject. Override the below 'life cycle methods' to inject your custom code(for populating data form a REF CURSOR).
  protected void create()
  protected void executeQueryForCollection(Object qc, Object[] params, int numUserParams) 
  protected ViewRowImpl createRowFromResultSet(Object qc, ResultSet rs)
  protected boolean hasNextForCollection(Object qc)
  protected ViewRowImpl createRowFromResultSet(Object qc, ResultSet rs)
  protected void releaseUserDataForCollection(Object qc, Object rs)

Please refer the below topic in Fusion Developer's Guide to learn more…
39.8 Using Programmatic View Objects for Alternative Data Sources

You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS1]
PS: Unzip the attachment and run the script(StoredProcedureExample/script) to set up the required DB objects for running this demo

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

Friday, February 5, 2010

A common mistake while iterating through <af:table> rows

One common mistake while iterating through the rows of a table is failing to restore the row currency after the iteration.
Consider a use case scenario where selected rows of a table need to be processed whenever user does some action. Solution is to stamp each row and process them on by one. The most common mistake here is forgetting to restore the row currency.

Wrong Implementation:

public void someEvent(ActionEvent actionEvent) {
  RowKeySet selectedRowKeys = someTable.getSelectedRowKeys();
  if (selectedRowKeys != null) {
    Iterator iter = selectedRowKeys.iterator();
    if (iter != null && iter.hasNext()) {
    
    Object rowKey = iter.next();
    //stamp row
    someTable.setRowKey(rowKey);
    JUCtrlHierNodeBinding rowData =
        (JUCtrlHierNodeBinding)someTable.getRowData();
        
    //Do something here...
    
    }
 }
}

Ooops...Unfortunately the above code fails with the below error.


java.lang.NullPointerException
 at oracle.adfinternal.view.faces.model.binding.RowDataManager.getRowIndex(RowDataManager.java:187)
 at oracle.adfinternal.view.faces.model.binding.FacesCtrlHierBinding$FacesModel.getRowIndex(FacesCtrlHierBinding.java:570)
 at org.apache.myfaces.trinidad.component.UIXIterator._fixupFirst(UIXIterator.java:414)
 at org.apache.myfaces.trinidad.component.UIXIterator.__encodeBegin(UIXIterator.java:392)
 at org.apache.myfaces.trinidad.component.UIXTable.__encodeBegin(UIXTable.java:168)
 at org.apache.myfaces.trinidad.component.UIXCollection.encodeBegin(UIXCollection.java:517)
 at org.apache.myfaces.trinidad.component.UIXComponentBase.__encodeRecursive(UIXComponentBase.java:1478)
 at org.apache.myfaces.trinidad.component.UIXComponentBase.encodeAll(UIXComponentBase.java:771)

What went wrong here?

A close analysis shows that stamping a row modifies the currency each time. So once the processing is over, it's mandatory to restore the currency with original value. Otherwise row Index may point to different(wrong RowKey) currency which is missing from RowDataManager of the binding layer, and result in NullPointerException when the page refreshes. Solution is simple, change the above code as shown below to restore currency as last step.

Correct Implementation:

public void someEvent(ActionEvent actionEvent) {

  RowKeySet selectedRowKeys = someTable.getSelectedRowKeys();
  
  //Store original rowKey
  Object oldRowKey = someTable.getRowKey();
  try{ 

    if (selectedRowKeys != null) {
      Iterator iter = selectedRowKeys.iterator();
      if (iter != null && iter.hasNext()) {
      Object rowKey = iter.next();
      someTable.setRowKey(rowKey); //stamp row
      JUCtrlHierNodeBinding rowData =
        (JUCtrlHierNodeBinding)someTable.getRowData();
      //Do something here
      }
    }

  }finally{

    //Restore the original rowKey
    someTable.setRowKey(oldRowKey);

  }
}


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