Friday, December 14, 2012

UniqueKey Validator in case of a multi-user/concurrent scenario

I have an EntityObject which is based on a db table that has a Unique index defined on two of its attributes(say - id,code). I have a VO based on this EO and it is used by "updatable table" in the UI.

I have a concurrent scenario like this

1.user1 enters and click on + button to create a new row
2.user2 enters and click on + button to create a new row
3.user1 enters the values
4.user2 enters values with id & code same as entered by user1
5.user1 clicks on save button
6.user2 clicks on save button
7.user1 save operations is success
8.user2 gets Application error due to an incident. Incident log says that it is due to violating the Unique index in the db and the exception is java.sql.SQLIntegrityConstraintViolationException

To handle this issue, I did the following

I created an AltKey in the EO on attributes id & code and then created an UniqueKey Validator on the AltKey. When tested, I noticed that I still get the incident same as in Step-8 in the above scenario. I suspect the Unique key Validator is only checking the cache and not the db.

If a user clicks + button twice and enters the same values in both the rows and then clicks on save button, the unique key validator seems to be working but not in the multi-user/concurrent scenario i mentioned above.

Then  I tried setting EntityLevelOnly="true" for the unique key validator from property inspector and it worked.

Thursday, December 13, 2012

Iterating on the selected rows of adf table


Below is the code snippet to iterate over the selected rows of an adf table.

//table is the ADF component reference created using the table's binding attribute

RowKeySet rks = table.getSelectedRowKeys();
Iterator it = rks.iterator();
while (it.hasNext()) {
 List selectedRowKeyPath = (List)it.next();            
 Row row = ((JUCtrlHierNodeBinding)table.getRowData(selectedRowKeyPath)).getRow();
 System.out.println("Row Attribute-1 " + row.getAttribute(1));
}

Explicitly setting values to the model

While the ADF lifecycle updates the model values respective to each of the UI components participating in Create/Edit/Delete use cases by its own,  some times we may need to explicitly update the model value corresponding to a UI component.

E.g. Let us say we have a input text component that has a value change listener. The value change listener is triggered before the corresponding model value is updated. In case we want to update the model value explicitly with value change listener, we can use processUpdates method of the UI component.

Ex: RichOutputText.processUpdates(FacesContext.getCurrentInstance())

How to obtain AM instance & Bindings from a backing/managed bean?

Some times we may need to access the Application Module instance from the backing bean. E.g. when we want to invoke some custom method in AM from a event listener in the backing bean.

DCBindingContainer bindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();

TestAMImpl am = (TestAMImpl)bindings.getDataControl().getDataProvider();

With the am reference we can invoke any of its public method.

The BindingContext here corresponds to DataBindings.cpx file in the ADF application. That file contains mappings of all the pages and their page definitions within the application.

The  DCBindingContainer here corresponds to the pageDefintion (nothing but bindings)of the current page/pagefragment. So we can read not only the AM instance being referred through the datacontrol but also the iterators, the actions, etc from it.

How to iterate and read the rowset of ADF Table

Let us say, we have an ADF table in our jsff file. It will have the Node binding under the bindings section of the respective page definition of the jsff and also an iterator under the executables section of page definition.

The below code fragment gets the Current Binding container.

DCBindingContainer bindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();

The below code fragment gets the iterator binding from the current binding container.

DCIteratorBinding dcIteratorBinding = bindings.findIteratorBinding("<IteratorId>");


The below code fragment gets the iterator and shows how to access a row from it using a row key.

RowSetIterator rsiRows = dcIteratorBinding.getRowSetIterator();
Row row = rsiRows.getRow(<Key object>);       

The below code fragment gets the list of selected rows in case multiple row selection is enabled.


RowKeySet rks =  <RichTable object>.getSelectedRowKeys();
Iterator it = rks.iterator();
int i = 0;


while (it.hasNext()) {
   i++;
   List selectedRowKeyPath = (List)it.next();  
   Row row = rsiRows.getRow((Key)selectedRowKeyPath.get(0));
   System.out.println("Selected Row no#"+i+" "+row.getAttribute("Name"));
}