Saturday, April 24, 2010

Flex OLAP Aggregators Fix for Null and Undefined Values

There is very little information available on Adobe Flex data visualization components. Sometimes I even question whether it is used in production at all. In one of our recent projects we used OLAP components extensively. It is the first time I had to check out the source of component so often: to check out how it is supposed to work and to fix issues (and there are quite a lot).

Data visualization provides a set of aggregators: sum, average, count, max, min. But there is an issue how they handle null or undefined values. Result defaults to 0(zero) even if there is no value defined for given dataField in a dataprovider or all values are null/undefined. Maybe it is by design, but it is not how it is used in real world scenarios. For example, Flex chart components support null/undefined values and there is even interpolateValues property in LineSeries to handle exactly this situation.

Fortunately, it is easy to fix. Let’s look at mx.olap.aggregators.SumAggregator source code for example. There are 3 methods of interest to us: computeBegin, computeLoop, and computeEnd. First, computeBegin is called and you create a holder object where temporary data will be stored as aggregation proceeds. Next, there is a call to computeLoop for every object in dataprovider where you update your holder object. Finally, computeEnd is called where you compute the final result and return it back. You see, the problem is in computeBegin and computeLoop:

1: public function computeBegin(dataField:String):Object
2: {
3:   var newObj:Object = {};
4:   newObj[dataField] = 0;
5:   return newObj;
6: }
8: public function computeLoop(data:Object, dataField:String,
9:                             rowData:Object):void
10: {
11:   var value:Number = rowData[dataField];        
12:   if (typeof(value) == "xml")
13:     value = Number(value.toString());
14:   if (!data.hasOwnProperty(dataField))
15:     data[dataField] = value ;
16:   else
17:     data[dataField] += value;
18: }


In comuteBegin holder object is immediately initialized to default 0 value (line 4). We can simply comment it, because in computeLoop this case is handled (line 14). But computeLoop has its own problems. There is no check for null/NaN values. So, if some of data objects does not have a value for given dataField the whole result is broken. Another problem is line 12. How Number type variable is supposed to be of type xml is beyond me. This check should be done before casting to Number. Looks like untested and unreviewed code to me. But interesting thing is how it stayed this way for 3 years. Anyway, here is the fixed version for sum aggregator:

public function computeBegin(dataField:String):Object
return  {};
public function computeLoop(data:Object, dataField:String,
  var value:Object = rowData[dataField];
  if(value == null)
  if (typeof(value) == "xml")
    value = Number(value.toString());
    value = Number(value);
  if(isNaN(value as Number))
  if (!data.hasOwnProperty(dataField))
    data[dataField] = value;
    data[dataField] += value;

Other aggregators can be fixed just the same way.

Friday, April 16, 2010

How To: Tomcat 6, BlazeDS 3.2, Hibernate 3.5 (JPA 2), Spring 3, Maven 2 – Part 1

In the following series of articles I want to explore how to set up a RIA project based on the latest stable Java and Flex stack using Maven and Eclipse. One would expect it to be easy enough and it is, but as always evil is in the details.

Prerequisites: recent version of Eclipse(3.4, 3.5) and m2eclipse plugin from SonaType.

Creating Web Project in Eclipse with Maven Dependency Management

In one of my previous posts I have tried to express my love for Maven. Using it from command prompt is a pleasure: quickly generating projects from templates(archetypes), building, running test, packaging and deploying, all is good. These are repetitive steps that need to be automated and maven handles that quite good. But we also need our old good IDEs with all the features we are used to have and got addicted to. So we need to look at our project from several different perspectives. To do that we need to set our project so that Maven and Eclipse understand the format/structure.

There are two ways to go: create Dynamic Web Project in Eclipse and enable Maven Dependency Management in it or create new Maven Project and enable Dynamic Web Module Facet in it.

First approach is more appropriate when you have some project in progress and want to start managing its dependencies with Maven. You can accomplish this from Project context menu/Maven/Enable Dependency Management. But it is not enough, you will have to modify folder structure according to established Maven project structure standards. Your sources should be in src/main/java and web content should be in src/main/webapp. Then you will have to edit some configuration files. For example you need to edit wb-resource parameters in org.eclipse.wst.common.component file located in .settings folder, and some more.

It looks like too much manual modification of Eclipse managed and hidden(by default) settings files and that is why I prefer the second way (with some maven plug-in help of course). Here is a step by step explanation:

1. Create new Maven Project. Check “Create a simple maven project(skip archetype selection)” option and set packaging to WAR. You have a working maven project structure. No we would like to work with the project as if it is native eclipse dynamic web project.

2. But first you should modify your pom.xml file to enable Java version 1.5 (or 1.6, what ever you need). It is necessary,  because  by default Maven compiles java code as Java 1.4. We also need this configuration for the next step. Just add the following xml in you pom.xml file:


It may look like too much custom xml, but after you work with maven for some time those plugin/dependency/groupId/artifactId elements just become part of your programming lexicon and m2eclipse plug-in with its code completion really helps here.

3. Now from Project context menu select Run As/Maven build… with the following options:

Goals = eclipse:eclipse

Parameter Name = wtpversion, Parameter Value = 2.0

After you run this maven build you get standard Eclipse Dynamic Web Project with Java Facet and Dynamic Web Module Facet enabled. Check it out from Project Properties / Project Facets section. Now you can configure Targeted Runtime (Tomcat 6 in our case) and other possible configurations you need just the same way you did it before maven era.

In Part2 we will explore how to further edit pom.xml file and add BlazeDS support using excellent Spring framework.