Monday, October 28, 2013

Showing Modified rows in a table using filtering feature

I came across a requirement where a table having a list of employee entities. The table is not a updatable table. So each row is modified by a form that comes up in a dialog on selecting a row. A new row is created on clicking + icon in the table toolbar. This table has filtering enabled. I have a flag "Show only to be submitted entities". On selecting the checkbox corresponding to that flag, the table should show only the newly added or modified rows.

To achieve this, I followed a simple approach of using filtering. Firstly I maintained a transient attribute in the entity which is a plain string and is updated on every new row creation or modification. I call that attribute a marker and the values are (N) for newly newly added ones and (M) for modified ones. On clicking the "Show only to be submitted entities"checkbox, I am populating a filter criteria saying marker startswith "(". Then queued the queryevent. This table has filtering enabled. So I also ensured that the existing filters are not disturbed. The "showOnlyToSubmitEntities" is boolean flag that preserves the selection of "Show only to be submitted entities" checkbox. If it is selected, the filter criteria is applied with marker added to it. Else it is removed.

Queuing event on selecting checkbox: (getTable() method returns the binding of the RichTable)

                  FilterableQueryDescriptor queryDescriptor =
                        (FilterableQueryDescriptor)getTable().getFilterModel();
                  getTable().queueEvent(new QueryEvent(getTable(), queryDescriptor));
----------------------------------------------------------------------------------------------------------------------

Handling the query event:

          FilterableQueryDescriptor fqd =
              (FilterableQueryDescriptor)queryEvent.getDescriptor();
          Iterator itr = null;

          if (showOnlyToSubmitEntities != null && showOnlyToSubmitEntities) {
              fqd.getFilterCriteria().put("marker", "(");
          } else {
              itr = fqd.getFilterCriteria().entrySet().iterator();
              while (itr.hasNext()) {
                  if (((Map.Entry)itr.next()).getKey().equals("legend")) {
                      itr.remove();
                  }
              }
          }

          ADFUtil.invokeEL(el, new Class[] { QueryEvent.class },
                           new Object[] { queryEvent });

Thursday, October 24, 2013

some best practices



The ADF Framework promotes the MVC pattern through the use of a well defined view, controller and model layers. The view layer is the JSPX fragments and associated backing bean code, the controller is the binding layer (ADFc) and the model is the business layer, typically ADF BC. A central tenet of the MVC pattern is that view and model communication is orchestrated by the controller layer. 

In some implementations, the backing bean code often directly invokes the Business tier directly without using the binding layer. The end result of this is a tight coupling between the view and model layer, where changes to the model layer could easily break the view layer code.Such implementation is also at risk since the benefits of the controller layer like contextual events, or deferred execution cannot now be performed. This also makes the code difficult to customize and change later.

Recommendation:
Re-factor the view layer code to use the binding layer. The view layer code should not directly invoke business methods, bypassing the ADF controller or the binding layer.

For example if you need to use any method define inside the applicationModule class, DON’T make a reference of the applicationModule in your code instead bind this method to the page and use the below code to access it:

         BindingContainer bindings =BindingContext.getCurrent().getCurrentBindingsEntry();
         OperationBinding submitTable = bindings.getOperationBinding("OperationName");
         submitTable.getParamsMap().put( "Parameters" , "data" );
         submitTable.execute();

---------------------------------


Best Practice for iterating over View Object rows
Create a secondary RowSetIterator if the business logic needs to iterate over rows of view. Note that the default RowSetIterator is typically bound to the UI components and use of it in
business logic will give inconsistent results at runtime. Call closeRowSetIterator() on the RowSetIterator instance once the business logic is done with the iteration. An example would be as follows:
public void checkAllPolicies() {
RowSetIterator policyRSI = null;
try {
ViewObject vo = findViewObject("PolicyVO");
vo.setNamedWhereClauseParam("policyNumber", getPolicyNumber());
vo.executeQuery();
//Create secondary row set iterator
policyRSI = vo.createRowSetIterator("customRowSet");
while (policyRSI.hasNext()) {
Row policyRow = policyRSI.next();
// -- business logic
}
} finally {
//Close the secondary row set iterator
if (policyRSI!= null)
policyRSI.closeRowSetIterator();
}
}


When iterating over view objects that are also used in the UI, the access mode can be set programmatically at runtime. You can restore the original access mode later based on the use case. The advantage of doing this programmatically is that you can use the forward-only mode only when needed, while other users of the view object, like the UI, will not be affected.
public void iteratePolicyVO() {
ViewObject vo = findViewObject("PolicyVO");
byte origMode = empVO.getAccessMode();
vo.setNamedWhereClauseParam("policyNumber", getPolicyNumber());
//Set access mode to FORWARD_ONLY
empVO.setAccessMode(ViewObject.FORWARD_ONLY);
vo.executeQuery();
while (vo.hasNext()) {
Row policyRow = vo.next();
// -- Business logic
}
//Restore the access mode
empVO.setAccessMode(origMode);
}
  ----------------------------------------------------------

Please make sure that you take care of the following in your code.

1      All the beans that you use in your code irrespective of the scope should implement searializable.
2      As a best practice for ADF, try as much as you can to not use binding for the UIcomponent and if you really need to use it, don’t use it in a memory scope more than Request or Back bean
scope. UIcomponent binding is only valid in request scope and backing bean scope. UIComponents are non-serializable, and therefore cannot be stored into any memory that would cause them to live longer than one request. If you need to keep a reference to a component longer than that you may use a component reference.

Please check the below link:

See “2.6.3 What You May Need to Know About Component Bindings and Managed Beans”

        Review your code and make sure you do the following:

1      Remove UIComponent Binding if there is a alternative way to do the same logic
2      If you must use it, make sure that you don’t use UIComponent bindings in beans that live longer than request scope and backing bean scope.
3      This is the last option. In case you have used component binding in beans with scope higher than request scope and backing bean scope, you can use  the component reference API to make the UI component also searializable.