Tuesday, April 23, 2013

Using ADF Client Side Listeners & Server Side Listeners to save panelSplitter position in a managed bean

In some cases where we find the framework supported events and handlers to be inadequate and need a custom event to be handled by the components. ADF Client side and server side listeners work in conjunction with each other to suffice such a requirement.

One such example is with panelSplitter component. Let us say a user wants to save the state of panelSplitter (splitter position) in session, then below solution would be handy.

The af:clientListener and af:serverListener tags are defined for a panelSplitter component as follows:

<af:panelSplitter id="ps1" label="MySplitter">
  <af:clientListener method="propertyChangeClientListener" type="propertyChange"/>
  <af:serverListener type="mySplitterCustomEvent"
                     method="#{mybean.handleSplitterPositionChange}"/>
</af:inputText>


On changing the splitter position through user action, the client listener invokes the below javascript method - propertyChangeClientListener(). That method indirectly invokes the server side listener by raising a particular event that the server side listener is waiting for. That event here is "mySplitterCustomEvent". This event is queued in AdfCustomEvent with the parameter as splitterPosition value and a configuration value "true" to make this immediate on server.

function propertyChangeClientListener(e) {
    var inputComp = AdfPage.PAGE.findComponent(e.getSource().getClientId());
    if(e.getPropertyName().toString() == "splitterPosition"){
      var newVal = e.getNewValue();
      AdfCustomEvent.queue(inputComp, "mySplitterCustomEvent",
                                 // Send one parameter
                                 {splitterPosition:newVal},
                                 // Make it "immediate" on the server
                                 true);
    }
}

Given below is the server side listener method. This method reads the value of the splitterPosition from the custom event received and stores the value in a managed bean "resizeBean".

public void handleSplitterPositionChange(ClientEvent event){
     ResizePersistenceBean resizeBean = null;
    try{
       //Use ADFUtil class posted in my earlier blogs
        resizeBean = (ResizePersistenceBean)ADFUtil.evaluateEL("#{resizePersistenceBean}");
       if(!event.getParameters().get("splitterPosition").toString().equals("")){
        resizeBean.setSplitterPosition((int)(Float.parseFloat(event.getParameters().get("splitterPosition").toString())));
       }
    }catch(Exception e){
       resizeBean.setSplitterPosition(200);
    }
}

Thursday, April 18, 2013

Remote Debugging of ADF web applications in Weblogic

We can debug our ADF web application by having the code pointed to a stand alone weblogic server.

To achieve that the startWeblogic.sh script that is present in <domain_dir>/bin/ , should be modified to keep the below entry, usually after java -version line

JAVA_OPTIONS="-Xdebug -Djava.compiler=NONE -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,address=10171,suspend=n $JAVA_OPTIONS"

After the above change, the startWeblogic.sh is executed to bring up the server. Now the server listens at 10171 port for debugging.

Now, go to your adf application and choose the project that has the code you want to debug. Click on the Project Properties and edit the current run configuration with the host name and debug port details as shown in below pic.
Now save the project and right click on it and select "start Remote Debugger". This will make the project to attach to server at the debug port as mentioned. 

With this, when server is running the use case whose code is in the project configured, the control flows to the source code attached and can be debugged with debug points.

Thursday, April 4, 2013

Traversing ViewCriteria hierarchy

A ViewCriteria instance is an hierarchy of Criteria Rows and Criteria Items. Criteria Item is the smallest unit which contains an Operand, Operator and Value(Either Literal or Bind Variable).

A ViewCriteriaRow can have multipe ViewCriteriaItem instances and a ViewCriteria can have multiple ViewCriteriaRows. Let us assume appliedVC is an applied ViewCriteria to a ViewObject.


The below code snippet traverses the ViewCriteria and locates a particular ViewCriteriaItem and removes. Before removing it reads the value and stores it in a variable.



            boolean found = false;
            while (appliedVC.hasNext() && !found) {
                vcr = (ViewCriteriaRow)appliedVC.next();
                if (vcr != null) {
                   ViewCriteriaItem[] vcis = vcr.getCriteriaItemArray();
                   if (vcis != null && vcis.length > 0) {
                       for (int j = 0; j < vcis.length && !found; j++) {
                           ViewCriteriaItem vci = vcis[j];
                           if(vci!= null && vci.getAttributeDef()!=null && vci.getAttributeDef().getName().equals("MyFlag")){
                                System.out.println("****"+vci.getAttributeDef().getName()+"***"+vci.getValue());
                                if(vci.getValue()!=null){
                                    myFlagVal = vci.getValue().toString();
                                    vcr.removeCriteriaItem("MasterOrgFlag", vci);
                                    found=true;
                                }
                           }
                       }
                   }
                }
            }

Replacing a particular ViewCriteriaItem with custom where condition

Sometimes we may come across a situation where we want to have a field in Search Component in UI but don't want the corresponding view criteria item to be part of the where clause generated for the ViewObject. This requirement generally comes when the value set for the search field in UI is used to decide which custom where condition to be added instead of the search field itself.

This requirement makes more sense when a ViewObject is read-only based on a sql query and you want the query execution mode for the ViewCriteria to be Database.

You need to override the getCriteriaItemClause() method of the ViwObject

The below code snippet looks for the search field "ManagerOnly" which has two possible values "Y"/"N". If the Value is "Y", a custom where condition has to be returned else nothing, which means there won't be any clause generated for the corresponding criteria item.

(Assumption: There is Emp schema where Emp details are stored in Employee table. Manager is highest in hierarchy and the manager_id value for manager will be its own employee id.)

 @Override
    public String getCriteriaItemClause(ViewCriteriaItem vci) {
      if (vci.getAttributeDef().getName().equals("ManagerOnly") &&      vci.getViewCriteria().getName().contains("MyEmpViewCriteria")&& vci.getValue().equals("Y")) {
        return "EMPLOYEE_ID=MANAGER_ID";
      } else { //If the attribute is not "ManagerOnly" retain the default behavior.
        return super.getCriteriaItemClause(vci);
      }
    }

Adding a where clause to a View Object through dummy View Criteria

This can be done by creating a dummy view criteria in View object without any criteria items in it. Then in the code like prepareRowSetForQuery() method of View Object the following can be done to achieve that.

        ViewCriteria vc = this.getViewCriteria("getMyItems");
       
        CriteriaClauses c = new CriteriaClauses();
        c.setClauseForQuery("OrgId IS NOT NULL");
        vc.setClauses(c);

The above will add where clause to the View object. In case multiple view criterias are used this will retain them as well while appending the where clause generated by it.

Programmatically applying View Criteria

A ViewObject can be defined with multiple ViewCriterias having multiple Criteria Items within it.
For a ViewObject consumer to execute it with a specific ViewCriteria programmatically, below is the code assuming "am" is the Application Module instance.

 ViewObject pVO = _am.findViewObject("OrgOrganizationDefinitionsSecuredP1");
  if(pVO != null){
     ViewCriteriaManager vcm = pVO.getViewCriteriaManager();
     ViewCriteria vc =   vcm.getViewCriteria("myCriteria");
     ViewCriteria dsvc  =  vcm.getViewCriteria("getDSBackedOrgs");
           
      ViewCriteriaRow vcr = vc.createViewCriteriaRow();
      vcr.setAttribute("MasterOrgFlag", "= Y");
      vcr.setConjunction(ViewCriteriaRow.VC_CONJ_AND);
      vc.add(vcr);

     ViewCriteriaRow vcr1 = (ViewCriteriaRow)vc.createViewCriteriaRow();
     vcr1.setAttribute("OrganizationCode", "= V1");
     vcr1.setConjunction(ViewCriteriaRow.VC_CONJ_AND);
     vc.add(vcr1);

     pVO.applyViewCriteria(vc);
     pVO.applyViewCriteria(dsvc,true);
     pVO.executeQuery();   
  }  


The above piece of code programmatically applies a view criteria of my choice among the list of view criterias defined for the view object. It programmatically adds criteria rows to it. Each criteria row can have multiple criteria items and each such item corresponds to one where condition in SQL Where clause. The setAttribute method on ViewCriteriaRow defines a criteria item here.

Another important finding in the above code is the way to apply multiple criterias to a view object. The applyViewCriteria(<ViewCriteriaName>) method clears of the existing list of applied view criterias and applies the current one. The applyViewCriteria(<ViewCriteriaName>, true) appends the current view criteria to the existing list.