← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 5411: first stab at serializing grid

 

------------------------------------------------------------
revno: 5411
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2011-12-14 13:52:07 +0100
message:
  first stab at serializing grid
added:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridRow.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridRows.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/adapter/GridRowsXmlAdapter.java
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridHeader.java
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/grid/ListGrid.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ReportTableController.java


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridHeader.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridHeader.java	2011-02-28 15:46:58 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridHeader.java	2011-12-14 12:52:07 +0000
@@ -1,5 +1,11 @@
 package org.hisp.dhis.common;
 
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
 import java.util.Arrays;
 import java.util.List;
 
@@ -33,30 +39,32 @@
 /**
  * @author Lars Helge Overland
  */
+@XmlRootElement( name = "header", namespace = Dxf2Namespace.NAMESPACE )
+@XmlAccessorType( value = XmlAccessType.NONE )
 public class GridHeader
 {
     private static final List<String> NUMERIC_TYPES = Arrays.asList( Float.class.getName(), Double.class.getName(), Long.class.getName(), Integer.class.getName() );
-    
+
     private String name;
-    
+
     private String column;
-    
+
     private String type;
-    
+
     private boolean hidden;
-    
+
     private boolean meta;
-    
+
     public GridHeader()
     {
     }
 
     /**
      * Sets the column property to the name value. Sets the type property to String.
-     * 
-     * @param name name
+     *
+     * @param name   name
      * @param hidden hidden
-     * @param meta meta
+     * @param meta   meta
      */
     public GridHeader( String name, boolean hidden, boolean meta )
     {
@@ -68,11 +76,11 @@
     }
 
     /**
-     * @param name name
+     * @param name   name
      * @param column column
-     * @param type type
+     * @param type   type
      * @param hidden hidden
-     * @param meta meta
+     * @param meta   meta
      */
     public GridHeader( String name, String column, String type, boolean hidden, boolean meta )
     {
@@ -83,11 +91,15 @@
         this.meta = meta;
     }
 
+    @XmlElement
+    @JsonProperty
     public boolean isNumeric()
     {
         return type != null && NUMERIC_TYPES.contains( type );
     }
-    
+
+    @XmlElement
+    @JsonProperty
     public String getName()
     {
         return name;
@@ -98,6 +110,8 @@
         this.name = name;
     }
 
+    @XmlElement
+    @JsonProperty
     public String getColumn()
     {
         return column;
@@ -108,6 +122,8 @@
         this.column = column;
     }
 
+    @XmlElement
+    @JsonProperty
     public String getType()
     {
         return type;
@@ -118,6 +134,8 @@
         this.type = type;
     }
 
+    @XmlElement
+    @JsonProperty
     public boolean isHidden()
     {
         return hidden;
@@ -128,6 +146,8 @@
         this.hidden = hidden;
     }
 
+    @XmlElement
+    @JsonProperty
     public boolean isMeta()
     {
         return meta;
@@ -151,19 +171,19 @@
         {
             return true;
         }
-        
+
         if ( object == null )
         {
             return false;
         }
-        
+
         if ( getClass() != object.getClass() )
         {
             return false;
         }
-        
+
         final GridHeader other = (GridHeader) object;
-        
+
         return name.equals( other.name );
     }
 }

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridRow.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridRow.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridRow.java	2011-12-14 12:52:07 +0000
@@ -0,0 +1,32 @@
+package org.hisp.dhis.common;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+@XmlRootElement( name = "row", namespace = Dxf2Namespace.NAMESPACE )
+@XmlAccessorType( value = XmlAccessType.NONE )
+public class GridRow
+{
+    private List<Object> row = new ArrayList<Object>();
+
+    @XmlElement
+    @JsonProperty
+    public List<Object> getRow()
+    {
+        return row;
+    }
+
+    public void setRow( List<Object> row )
+    {
+        this.row = row;
+    }
+}

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridRows.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridRows.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/GridRows.java	2011-12-14 12:52:07 +0000
@@ -0,0 +1,32 @@
+package org.hisp.dhis.common;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+@XmlRootElement( name = "rows", namespace = Dxf2Namespace.NAMESPACE )
+@XmlAccessorType( value = XmlAccessType.NONE )
+public class GridRows
+{
+    private List<GridRow> rows = new ArrayList<GridRow>();
+
+    @XmlElement
+    @JsonProperty
+    public List<GridRow> getRows()
+    {
+        return rows;
+    }
+
+    public void setRows( List<GridRow> rows )
+    {
+        this.rows = rows;
+    }
+}

=== added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/adapter/GridRowsXmlAdapter.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/adapter/GridRowsXmlAdapter.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/common/adapter/GridRowsXmlAdapter.java	2011-12-14 12:52:07 +0000
@@ -0,0 +1,61 @@
+package org.hisp.dhis.common.adapter;
+
+/*
+ * Copyright (c) 2004-2011, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ *   list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import org.hisp.dhis.common.GridRow;
+import org.hisp.dhis.common.GridRows;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import java.util.List;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+public class GridRowsXmlAdapter extends XmlAdapter<GridRows, List<List<Object>>>
+{
+    @Override
+    public List<List<Object>> unmarshal( GridRows rows ) throws Exception
+    {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public GridRows marshal( List<List<Object>> rows ) throws Exception
+    {
+        GridRows gridRows = new GridRows();
+
+        for ( List<Object> row : rows )
+        {
+            GridRow gridRow = new GridRow();
+            gridRow.setRow( row );
+            gridRows.getRows().add( gridRow );
+        }
+
+        return gridRows;
+    }
+}

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/grid/ListGrid.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/grid/ListGrid.java	2011-06-14 16:41:32 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/grid/ListGrid.java	2011-12-14 12:52:07 +0000
@@ -27,72 +27,73 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-import static org.hisp.dhis.system.util.MathUtils.getRounded;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 import net.sf.jasperreports.engine.JRException;
 import net.sf.jasperreports.engine.JRField;
-
 import org.apache.commons.math.stat.regression.SimpleRegression;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.hisp.dhis.common.Dxf2Namespace;
 import org.hisp.dhis.common.Grid;
 import org.hisp.dhis.common.GridHeader;
+import org.hisp.dhis.common.adapter.GridRowsXmlAdapter;
+
+import javax.xml.bind.annotation.*;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import java.util.*;
+
+import static org.hisp.dhis.system.util.MathUtils.getRounded;
 
 /**
  * @author Lars Helge Overland
  * @version $Id$
  */
+@XmlRootElement( name = "grid", namespace = Dxf2Namespace.NAMESPACE )
+@XmlAccessorType( value = XmlAccessType.NONE )
 public class ListGrid
     implements Grid
 {
     private static final String REGRESSION_SUFFIX = "_regression";
-    
+
     /**
      * The title of the grid.
      */
     private String title;
-    
+
     /**
      * The subtitle of the grid.
      */
     private String subtitle;
-    
+
     /**
      * The name of a potential corresponding table.
      */
     private String table;
-    
+
     /**
      * A List which represents the column headers of the grid.
      */
     private List<GridHeader> headers;
-    
+
     /**
      * A two dimensional List which simulates a grid where the first list
      * represents rows and the second represents columns.
      */
     private List<List<Object>> grid;
-    
+
     /**
      * Indicating the current row in the grid for writing data.
      */
     private int currentRowWriteIndex = -1;
-    
+
     /**
      * Indicating the current row in the grid for reading data.
      */
     private int currentRowReadIndex = -1;
-    
+
     /**
      * Represents a mapping between column names and the index of the column in the grid.
      */
     private Map<String, Integer> columnIndexMap = new HashMap<String, Integer>();
-    
+
     /**
      * Default constructor.
      */
@@ -101,11 +102,13 @@
         headers = new ArrayList<GridHeader>();
         grid = new ArrayList<List<Object>>();
     }
-    
+
     // ---------------------------------------------------------------------
     // Public methods
     // ---------------------------------------------------------------------
 
+    @XmlElement
+    @JsonProperty
     public String getTitle()
     {
         return title;
@@ -114,10 +117,12 @@
     public Grid setTitle( String title )
     {
         this.title = title;
-        
+
         return this;
     }
 
+    @XmlElement
+    @JsonProperty
     public String getSubtitle()
     {
         return subtitle;
@@ -126,31 +131,36 @@
     public Grid setSubtitle( String subtitle )
     {
         this.subtitle = subtitle;
-        
+
         return this;
     }
-    
+
+    @XmlElement
+    @JsonProperty
     public String getTable()
     {
         return table;
     }
-    
+
     public Grid setTable( String table )
     {
         this.table = table;
-        
+
         return this;
     }
 
     public Grid addHeader( GridHeader header )
     {
         headers.add( header );
-        
+
         updateColumnIndexMap();
-        
+
         return this;
     }
-    
+
+    @XmlElementWrapper( name = "headers" )
+    @XmlElement( name = "header" )
+    @JsonProperty( value = "headers" )
     public List<GridHeader> getHeaders()
     {
         return headers;
@@ -159,7 +169,7 @@
     public List<GridHeader> getVisibleHeaders()
     {
         List<GridHeader> tempHeaders = new ArrayList<GridHeader>();
-        
+
         for ( GridHeader header : headers )
         {
             if ( !header.isHidden() )
@@ -167,67 +177,74 @@
                 tempHeaders.add( header );
             }
         }
-        
+
         return tempHeaders;
     }
-     
+
+    @XmlElement
+    @JsonProperty
     public int getHeight()
-    {        
-        return ( grid != null && grid.size() > 0 ) ? grid.size() : 0;
+    {
+        return (grid != null && grid.size() > 0) ? grid.size() : 0;
     }
-    
+
+    @XmlElement
+    @JsonProperty
     public int getWidth()
     {
         verifyGridState();
-        
-        return ( grid != null && grid.size() > 0 ) ? grid.get( 0 ).size() : 0;
+
+        return (grid != null && grid.size() > 0) ? grid.get( 0 ).size() : 0;
     }
-    
+
     public int getVisibleWidth()
     {
         verifyGridState();
-        
-        return ( grid != null && grid.size() > 0 )  ? getVisibleRows().get( 0 ).size() : 0;
+
+        return (grid != null && grid.size() > 0) ? getVisibleRows().get( 0 ).size() : 0;
     }
-    
+
     public Grid addRow()
     {
         grid.add( new ArrayList<Object>() );
-        
+
         currentRowWriteIndex++;
-        
+
         return this;
     }
-    
+
     public Grid addValue( Object value )
     {
         grid.get( currentRowWriteIndex ).add( value );
-        
+
         return this;
     }
-    
+
     public List<Object> getRow( int rowIndex )
     {
         return grid.get( rowIndex );
     }
-    
+
+    @XmlElement
+    @XmlJavaTypeAdapter( GridRowsXmlAdapter.class )
+    @JsonProperty
     public List<List<Object>> getRows()
     {
         return grid;
     }
-    
+
     public List<List<Object>> getVisibleRows()
     {
         verifyGridState();
-        
+
         List<List<Object>> tempGrid = new ArrayList<List<Object>>();
-        
+
         if ( headers != null && headers.size() > 0 )
         {
             for ( List<Object> row : grid )
             {
                 List<Object> tempRow = new ArrayList<Object>();
-                
+
                 for ( int i = 0; i < row.size(); i++ )
                 {
                     if ( !headers.get( i ).isHidden() )
@@ -235,102 +252,102 @@
                         tempRow.add( row.get( i ) );
                     }
                 }
-                
+
                 tempGrid.add( tempRow );
             }
         }
-        
+
         return tempGrid;
     }
-        
+
     public List<Object> getColumn( int columnIndex )
     {
         List<Object> column = new ArrayList<Object>();
-        
+
         for ( List<Object> row : grid )
         {
             column.add( row.get( columnIndex ) );
         }
-        
+
         return column;
     }
-    
+
     public Object getValue( int rowIndex, int columnIndex )
     {
         if ( grid.size() < rowIndex || grid.get( rowIndex ) == null || grid.get( rowIndex ).size() < columnIndex )
         {
             throw new IllegalArgumentException( "Grid does not contain the requested row / column" );
         }
-        
+
         return grid.get( rowIndex ).get( columnIndex );
     }
-    
+
     public Grid addColumn( List<Object> columnValues )
     {
         verifyGridState();
-        
+
         int rowIndex = 0;
         int columnIndex = 0;
-        
+
         if ( grid.size() != columnValues.size() )
         {
             throw new IllegalStateException( "Number of column values (" + columnValues.size() + ") is not equal to number of rows (" + grid.size() + ")" );
         }
-        
+
         for ( int i = 0; i < grid.size(); i++ )
         {
             grid.get( rowIndex++ ).add( columnValues.get( columnIndex++ ) );
         }
-        
+
         return this;
     }
-    
+
     public Grid removeColumn( int columnIndex )
     {
         verifyGridState();
-        
+
         if ( headers.size() > 0 )
         {
             headers.remove( columnIndex );
         }
-        
+
         for ( List<Object> row : grid )
         {
             row.remove( columnIndex );
         }
-        
+
         updateColumnIndexMap();
-        
+
         return this;
     }
-    
+
     public Grid removeColumn( GridHeader header )
     {
         int index = headers.indexOf( header );
-        
+
         if ( index != -1 )
         {
             removeColumn( index );
         }
-        
+
         return this;
     }
-    
+
     public Grid limitGrid( int limit )
     {
         if ( limit < 0 )
         {
             throw new IllegalStateException( "Illegal limit: " + limit );
         }
-        
+
         if ( limit > 0 && limit <= getHeight() )
         {
             grid = grid.subList( 0, limit );
         }
-        
+
         return this;
     }
-    
+
     public Grid limitGrid( int startPos, int endPos )
     {
         if ( startPos < 0 || endPos < startPos || endPos > getHeight() )
@@ -342,45 +359,45 @@
 
         return this;
     }
-    
+
     public Grid sortGrid( int columnIndex, int order )
     {
         columnIndex = columnIndex - 1;
-        
+
         if ( columnIndex < 0 || columnIndex >= getWidth() )
         {
             throw new IllegalArgumentException( "Column index out of bounds: " + columnIndex );
         }
-        
+
         Collections.sort( grid, new GridRowComparator( columnIndex, order ) );
-        
+
         return this;
     }
-    
+
     public Grid addRegressionColumn( int columnIndex, boolean addHeader )
     {
         verifyGridState();
-        
+
         SimpleRegression regression = new SimpleRegression();
-        
+
         List<Object> column = getColumn( columnIndex );
-        
+
         int index = 0;
-        
+
         for ( Object value : column )
         {
             if ( Double.parseDouble( String.valueOf( value ) ) != 0.0 ) // 0 omitted from regression
             {
-                regression.addData( index++, Double.parseDouble( String.valueOf(  value ) ) );
+                regression.addData( index++, Double.parseDouble( String.valueOf( value ) ) );
             }
         }
-        
+
         List<Object> regressionColumn = new ArrayList<Object>();
-        
+
         for ( int i = 0; i < column.size(); i++ )
         {
             final double predicted = regression.predict( i );
-            
+
             if ( !Double.isNaN( predicted ) ) // Enough values must exist for regression
             {
                 regressionColumn.add( getRounded( predicted, 1 ) );
@@ -392,20 +409,20 @@
         }
 
         addColumn( regressionColumn );
-        
+
         if ( addHeader && columnIndex < headers.size() )
         {
             GridHeader header = headers.get( columnIndex );
-            
+
             if ( header != null )
             {
-                GridHeader regressionHeader = new GridHeader( header.getName() + REGRESSION_SUFFIX, 
+                GridHeader regressionHeader = new GridHeader( header.getName() + REGRESSION_SUFFIX,
                     header.getColumn() + REGRESSION_SUFFIX, header.getType(), header.isHidden(), header.isMeta() );
-                
+
                 addHeader( regressionHeader );
             }
-        }            
-        
+        }
+
         return this;
     }
 
@@ -417,20 +434,20 @@
         throws JRException
     {
         boolean next = ++currentRowReadIndex < getHeight();
-        
+
         if ( !next )
         {
             currentRowReadIndex = -1; // Reset and return false
         }
-        
+
         return next;
     }
-    
+
     public Object getFieldValue( JRField field )
         throws JRException
     {
         Integer index = columnIndexMap.get( field.getName() );
-        
+
         return index != null ? getRow( currentRowReadIndex ).get( index ) : null;
     }
 
@@ -444,19 +461,19 @@
      */
     private void verifyGridState()
     {
-        Integer rowLength = null;    
-    
+        Integer rowLength = null;
+
         for ( List<Object> row : grid )
         {
             if ( rowLength != null && rowLength != row.size() )
             {
                 throw new IllegalStateException( "Grid rows do not have the same number of cells, previous: " + rowLength + ", this: " + row.size() );
             }
-            
+
             rowLength = row.size();
         }
     }
-    
+
     /**
      * Updates the mapping between header columns and grid indexes. This method
      * should be invoked whenever the columns are manipulated.
@@ -464,13 +481,13 @@
     private void updateColumnIndexMap()
     {
         columnIndexMap.clear();
-        
+
         for ( int i = 0; i < headers.size(); i++ )
         {
             columnIndexMap.put( headers.get( i ).getColumn(), i );
         }
     }
-    
+
     // -------------------------------------------------------------------------
     // toString
     // -------------------------------------------------------------------------
@@ -479,24 +496,24 @@
     public String toString()
     {
         StringBuffer buffer = new StringBuffer( "[\n" );
-        
+
         if ( headers != null && headers.size() > 0 )
         {
             List<String> headerNames = new ArrayList<String>();
-            
+
             for ( GridHeader header : headers )
             {
                 headerNames.add( header.getName() );
             }
-            
-            buffer.append( headerNames  ).append( "\n" );
+
+            buffer.append( headerNames ).append( "\n" );
         }
-        
+
         for ( List<Object> row : grid )
         {
             buffer.append( row ).append( "\n" );
         }
-        
+
         return buffer.append( "]" ).toString();
     }
 
@@ -515,29 +532,29 @@
             this.columnIndex = columnIndex;
             this.order = order;
         }
-        
+
         @Override
-        @SuppressWarnings("unchecked")
+        @SuppressWarnings( "unchecked" )
         public int compare( List<Object> list1, List<Object> list2 )
         {
             if ( order == 0 )
             {
                 return 0;
             }
-            
-            if ( list1 == null || list1.get( columnIndex ) == null || !( list1.get( columnIndex ) instanceof Comparable<?> ) )
+
+            if ( list1 == null || list1.get( columnIndex ) == null || !(list1.get( columnIndex ) instanceof Comparable<?>) )
             {
                 return 1; // Null comes last
             }
-            
-            if ( list2 == null || list2.get( columnIndex ) == null || !( list2.get( columnIndex ) instanceof Comparable<?> ) )
+
+            if ( list2 == null || list2.get( columnIndex ) == null || !(list2.get( columnIndex ) instanceof Comparable<?>) )
             {
                 return -1; // Null comes last
             }
-            
+
             final Comparable<Object> value1 = (Comparable<Object>) list1.get( columnIndex );
             final Comparable<Object> value2 = (Comparable<Object>) list2.get( columnIndex );
-            
+
             return order > 0 ? value2.compareTo( value1 ) : value1.compareTo( value2 );
         }
     }

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ReportTableController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ReportTableController.java	2011-12-14 11:54:43 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ReportTableController.java	2011-12-14 12:52:07 +0000
@@ -121,6 +121,33 @@
         return "reportTable";
     }
 
+    @RequestMapping( value = "/{uid}/data", method = RequestMethod.GET )
+    public String getReportTableDATA( @PathVariable( "uid" ) String uid, Model model,
+                                      @RequestParam( value = "organisationUnit", required = false ) String organisationUnitUid,
+                                      @RequestParam( value = "period", required = false ) String period,
+                                      HttpServletResponse response ) throws I18nManagerException, IOException
+    {
+        if ( organisationUnitUid == null && period == null )
+        {
+            response.setStatus( HttpServletResponse.SC_BAD_REQUEST );
+            response.setContentType( "text/plain" );
+
+            PrintWriter writer = new PrintWriter( response.getOutputStream() );
+            writer.println( "GRID needs either organisationUnit or period parameter." );
+            writer.flush();
+
+            return "grid";
+        }
+
+        Date date = period != null ? DateUtils.getMediumDate( period ) : new Date();
+
+        Grid grid = reportTableService.getReportTableGrid( uid, i18nManager.getI18nFormat(), date, organisationUnitUid );
+
+        model.addAttribute( "model", grid );
+
+        return "grid";
+    }
+
     @RequestMapping( value = "/{uid}/data.pdf", method = RequestMethod.GET )
     public void getReportTablePDF( @PathVariable( "uid" ) String uid,
                                    @RequestParam( value = "organisationUnit", required = false ) String organisationUnitUid,