20 May 2012

Working with VO's built-in aggregation functions

When we work with View Link accessors or Association accessors we can use Groovy for aggregation calculations in a very convenient way. Groovy API provides five predefined functions:
  • accessor.sum("expr")
  • accessor.count("expr")
  • accessor.avg("expr")
  • accessor.min("expr")
  • accessor.max("expr")
This API is commonly used to calculate values of transient attributes in the master VO's.  But what if we don't have any master-detail relationship and don't have any accessors? We just have a ViewObject and we need to do some aggregation calculations on it - this is very common use case.  The common practice for this issue is to write custom Java method in the ViewObjectImpl class. But we have already five (that is enough for most cases) built-in methods used by the Groovy API. These methods are implemented by the ViewRowSetImpl (extends RowSetHelper) class and as any useful methods these ones are private. Groovy API uses InvokerHelper class to invoke them as it could be easily seen from the call stack. Let's do the same. Off-course these built-in methods can be deprecated in the future in the latest versions of ADF and we should be aware of that, but until it has not happened we do the following:
 
     1. Create an inner helper class in our ViewObjectImpl
   private class AgrFuncHelper extends HashMap
  {
    private String funcName;

    public AgrFuncHelper(String funcName) 
    {
      super();
      this.funcName = funcName;  
    }


    public Object get(Object key) 
    {
      //Invoke private method
      //of our DefaultRowSet (sum,count,avg,min,max)
      //key is argument expression for the aggr funcion being called
      //sum("Salary")

      return InvokerHelper.invokeMethod(getDefaultRowSet(), funcName, key);
    }

  }

 
    2. Publish aggregation methods
  public Map getSum() 
  {
    return new AgrFuncHelper("sum");
  }
  
  public Map getCount() 
  {
    return new AgrFuncHelper("count");
  }

 
   3. Use the methods in jspx
<af:outputText value="#{bindings.EmployeesView1Iterator.viewObject.sum['Salary']}"                        
   id="ot12"/>
<af:outputText value="#{bindings.EmployeesView1Iterator.viewObject.count['*']}" 
  id="ot13"/>
 


That's it!

4 comments:

  1. Very good, works also for a solution with a filtered table!!! Thx Gregor

    ReplyDelete
  2. This is genius - thank you. I am using this to publish a column in my table to display the percentage total for each row in the table. Do you happen to know how I can use your functionality in an ordinary bar graph where I want to have y-axis mapped as if it were my pseudo percentage column? Pareto seems to be the closest graph type but it has extra bells and whistles that the customer hates.

    ReplyDelete
  3. epic - thankyou! I second the genius comment!

    ReplyDelete

Post Comment