Friday, December 16, 2011

Showing A Message Before The Page Is Rendered.

One of my client's requirement was to show a message on the UI if the rows to be rendered on the UI are more than 150. This was required to inform the user that "For better performance, download the records in an excel". In this blog, I am writing my findings about how I did it.

For this blog, I am using SCOTT.EMP table, and will show the warning if the row count is greater than 10 instead of 150. The final outcome will look like this:



Here is how it can be done. Consider the following project:


Here the model is pretty simple, created a simple VO based on SCOTT.EMP table to include all the employee records. Included the EmpVO in the application module. In the view project, highlighted the files used:

  1. baseTaskFlow.xml - Its the bounded task flow which contains the activities to excute EmpVO, a method activity to render the message, and then the view activity to render the table showing the employees records.
  2. BasePage.jspx - This page shows the baseTaskFlow as a region.
  3. EmployeesView.jsff - Contains the table to render employees records.
  4. EmployeesViewBean.java - The request scope bean that contains the method to render the message.

Here is how the baseTaskFlow looks like:



Here, executeEmpVO simply executes the EmpVO. Its a method written in AppModuleAMImpl and here is the code of AmmModuleAMImpl:

package model;

import model.common.AppModule;

import oracle.jbo.server.ApplicationModuleImpl;
import oracle.jbo.server.ViewObjectImpl;

public class AppModuleImpl extends ApplicationModuleImpl implements AppModule {
    /**
     * This is the default constructor (do not remove).
     */
    public AppModuleImpl() {
    }

    /**
     * Container's getter for EmpVO1.
     * @return EmpVO1
     */
    public ViewObjectImpl getEmpVO1() {
        return (ViewObjectImpl)findViewObject("EmpVO1");
    }
  
    public void executeEmpVO(){
        getEmpVO1().executeQuery();
    }
}

The renderMessage is a method-call activity that calls the renderRowsExceededPopupMessage() method of the EmployeesViewBean, and here is its complete code:

package view;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCBindingContainer;
import oracle.adf.model.binding.DCIteratorBinding;
import oracle.binding.BindingContainer;

public class EmployeesViewBean {
    public EmployeesViewBean() {
    }
  
    public void renderRowsExceededPopupMessage(){
      
      BindingContext bindingctx = BindingContext.getCurrent();
      BindingContainer bindings = null;
      bindings = bindingctx.getCurrentBindingsEntry();
      DCBindingContainer bindingsImpl = (DCBindingContainer) bindings;
      DCIteratorBinding dciter = null;
      //access the iterator by its ID value in the PageDef file.
      dciter = bindingsImpl.findIteratorBinding("EmpVO1Iterator");
      long estRowCount = dciter.getEstimatedRowCount();
    
      if(estRowCount> 10){

        FacesContext fctx = FacesContext.getCurrentInstance();
        FacesMessage message = new FacesMessage("For the current selection criteria, the estimated row count is " + estRowCount + ". We recommend to export data to excel for row count greater that 10.");
        fctx.addMessage(null, message);

      }
    }
}

For this method to work, you need an iterator binding to EmpVO, that we are rendering in the EmployeesView view activity.

For that, create the page definition of the method-call activity, and add an iterator binding of EmpVO in the executable section, as shown below:



This is the important step. Rest all is simple.

Next, the EmployeesView.jsff is a simple page fragment having EmpVO rendered as a table.
After completing the task flow, drop the task flow as a region to BasePage.jspx and run it.
You will get an output like show in first figure.
That's all.



Tuesday, December 6, 2011

DVT Graphs Event Handlers

While writing event handling code for graphs, we need to take care of the following hierarchy:



That's because different graphs click events return different type of ComponentHandle references.
For example to handle Pie Graph's click event, we need to write the code similar to the following code snippet:

    public void pieClick(ClickEvent event) {
        // Add event code here...
        ComponentHandle handle = event.getComponentHandle();
        String seriesName = null;
        String seriesValue = null;
        Long clickedValue = null;
       
        if (handle instanceof DataComponentHandle){
                DataComponentHandle dhandle = (DataComponentHandle)handle;
                clickedValue = (Long)dhandle.getValue(DataComponentHandle.UNFORMATTED_VALUE);
                // Get the series attributes
                Attributes [] seriesInfo = dhandle.getSeriesAttributes();
                if(seriesInfo != null)
                {
                    for(Attributes attrs: seriesInfo)
                    {
                        seriesName = attrs.getValue(Attributes.LABEL_ATTRIBUTE).toString();
                        if(seriesName.equals("Status"))
                            seriesValue = attrs.getValue(Attributes.LABEL_VALUE).toString();   
                       
                    }
                }
        }
    . . .
    }   

Whereas while handling Line Graph's click event, the event handler looks like :

    public void graphClicked(ClickEvent clickEvent) {
          // Add event code here...
          ComponentHandle handle = clickEvent.getComponentHandle();
          if (handle instanceof SeriesComponentHandle) {
                  // Get the series attributes
                  Attributes [] seriesInfo = ((SeriesComponentHandle)handle).getSeriesAttributes();
                  String data = "";
                  if(seriesInfo != null) {
                          for(Attributes attrs: seriesInfo) {
                                  data += "Series value: " + attrs.getValue(Attributes.LABEL_VALUE);
                                  data += " Series name: " + attrs.getValue(Attributes.LABEL_ATTRIBUTE);
                                  data += " Series value id: " + attrs.getValue(Attributes.ID_VALUE);
                                  data += " Series name id: " + attrs.getValue(Attributes.ID_ATTRIBUTE);
                          }
                  }
          }
      . . .
    }

For Pie Graph, we look for DataComponentHandle to fetch desired attribute values, whereas for Line Graph, we look for SeriesComponentHandle.

Event handlers for other graphs are listed in the above image.