Tuesday, September 26, 2006

Optimistic Sums

Suppose you are developing reports for the Sales team. Your reports are providing insight into the sales channel. Your reports aggregate the sales estimates rolling the estimates up to the executive vice president of sales. The management team wants to see a bit more optimistic view of the sales forecasts. They ask you, "is there any way that you can manipulate the reports to provide a more optimistic view of the sales estimates."

Now my initial reaction would be one of alarm, "you want me to do what?" But then my curiosity would get a hold of me, is there a good way to do this? What is the best way?

First, you could create custom Birt Script sprinkled through out your reports that would round up the numbers as they are imported. Second, you could manipulate the data in the database either when you query it, or in the raw data. Third, you could create custom java functions to that you would integrate into your BIRT script. Fourth, you could make a Bugzilla entry and ask the BIRT team to add the new function.

Yes, there are a lot of ways that you could solve this problem, but there are issues with each method. None of them provide a really seamless way to customize your implementation of BIRT. Fortunately, BIRT ships with a standard way to add new aggregate functions to the basic BIRT Total functions. It is all done through the org.eclipse.birt.data.aggregation extension point.  This post will walk you through the process of using the aggregation extension point to create your own OptimisticSum function and add it to your BIRT implementation.

The entire Eclipse Platform is built through a common extendable framework. In short Eclipse is made of a large number of plug-ins. Each plug-in can provide the ability to customize or extend its behavior through an extension point. When you create an implementation of an extension point, you are creating an extension. So BIRT is made up all of the BIRT plug-ins. Each BIRT plug-in has defined extension points where you can define new BIRT functions. What we are going to do is extend the org.eclipse.birt.data.aggregation extension point.

If you are interested in Eclipse extensions, there are a number of resources that you can use. In the standard Eclipse help, there are three guides that you may find useful: Platform Plug-in Developer Guide, JDT Plug-in Developer Guide, and the Plug-in Development Environment Guide all provide great information on plug-in development. In addition, "The Java Developer's Guide to Eclipse" provides a complete overview of the entire Eclipse plug-in development process.

Fortunately, you don't need to know that much to do a simple BIRT aggregate extension. I have created an eleven minute screen-cast that walks you through the entire process of creating a BIRT aggregate extension. You can find it here.

I also have a plug-in project that demonstrates the OptimisticSum control available here.

Here is an outline of the high level steps that are required to create a BIRT data aggregate extension:

1) Create a plug-in project

2) Add a dependency on the org.eclipse.birt.data plugin

3) Create an extension of the org.eclipse.birt.data.aggregation extension point

4) Configure the plugin.xml, here is a sample

<extension  id="com.innoventsolutions.aggregate" name="TotalPlus" point="org.eclipse.birt.data.aggregation">
  
<aggregations>
      <Aggregation aggregationClass="com.innoventsolutions.aggregate.OptimisticSum"
name="OptimisticSum">
         <UIInfo parameterMetaInfo="String a, String b, String c" textData="Total.OptimisticSum()" tip="New Optimistic Sum tip~"/>
      </aggregation>
   </aggregations>
</extension>

5) Create an aggregationClass which either extends:
org.eclipse.birt.data.engine.api.aggregation.Aggregation
or implement the following interface:
org.eclipse.birt.data.engine.api.aggregation.IAggregation
If you are creating a single pass aggregate (one trip through the data) just extend the Aggregation class. If you need to do multiple passes over the data use implement the IAggregation interface.

6) In your aggregationClass implement the following methods
getName = name of the function
getType = 0 for Summary function, or 1 for Running function
getParameterDefn = is a boolean array, set to true for each required parameter.
newAccumulator = instantiate an instance of an Accumulator (see next step)

7) Create an extension of the
org.eclipse.birt.data.engine.api.aggregation.Accumulator

8) Implement the following methods in your Accumulator
getValue = returns the value that you have been accumulating
onRow = receives an array of parameters that you use to fulfill your function.  For each row of data returned by your DataStream, the onRow event will be called one time. 

9) Test / Debug your new plugin by running the project as an Eclipse Application. This will open a new instance of Eclipse. This new 'Runtime' instance of Eclipse will allow you to open up report designs and test your code.  If you use the Debug Eclipse Application option when you test your plugin project, you will be able to step through your code, just like in standard Java development with Eclipse.

10) When you have completed your testing you can create a plugin jar by using the export feature on the project and export your project as a Plug-in Development => Deployable Plug-ins and fragments options to create a jar file.  Simply dropping that jar file into the plugins directory of your BIRT deployment, and you custom function will be available.

Good luck creating your own BIRT Functions.

Scott