← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 9665: Analytics, handling requests which contains both indicators, data elements, data sets

 

------------------------------------------------------------
revno: 9665
committer: Lars Helge Øverland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2013-01-30 15:46:01 +0200
message:
  Analytics, handling requests which contains both indicators, data elements, data sets
modified:
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/Dimension.java
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DimensionType.java
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java
  dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/AnalyticsServiceTest.java
  dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AnalyticsController.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-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java	2013-01-28 15:55:56 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java	2013-01-30 13:46:01 +0000
@@ -34,6 +34,7 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 
 import org.apache.commons.lang.StringUtils;
@@ -53,6 +54,7 @@
 @JacksonXmlRootElement( localName = "dxf2", namespace = Dxf2Namespace.NAMESPACE )
 public class DataQueryParams
 {
+    public static final String DATA_X_DIM_ID = "dx"; // IN, DE, DS
     public static final String INDICATOR_DIM_ID = "in";
     public static final String DATAELEMENT_DIM_ID = "de";
     public static final String DATASET_DIM_ID = "ds";
@@ -69,6 +71,8 @@
     private static final DimensionOption[] DIM_OPT_ARR = new DimensionOption[0];
     private static final DimensionOption[][] DIM_OPT_2D_ARR = new DimensionOption[0][];
     
+    private static final List<String> DATA_DIMS = Arrays.asList( INDICATOR_DIM_ID, DATAELEMENT_DIM_ID, DATASET_DIM_ID );
+    
     private List<Dimension> dimensions = new ArrayList<Dimension>();
     
     private List<Dimension> filters = new ArrayList<Dimension>();
@@ -115,7 +119,34 @@
     // -------------------------------------------------------------------------
 
     /**
-     * Creates a list of the names of all dimensions for this query. 
+     * Creates a list of dimensions for use as headers. Will replace any of
+     * the indicator, data element or data set dimensions with the common
+     * data x dimension.
+     */
+    public List<Dimension> getHeaderDimensions()
+    {
+        List<Dimension> list = new ArrayList<Dimension>( dimensions );
+        
+        ListIterator<Dimension> iter = list.listIterator();
+        
+        dimensions : while ( iter.hasNext() )
+        {
+            if ( DATA_DIMS.contains( iter.next().getDimension() ) )
+            {
+                iter.set( new Dimension( DATA_X_DIM_ID, DimensionType.DATA_X ) );
+                break dimensions;
+            }
+        }
+        
+        list.remove( new Dimension( INDICATOR_DIM_ID ) );
+        list.remove( new Dimension( DATAELEMENT_DIM_ID ) );
+        list.remove( new Dimension( DATASET_DIM_ID ) );
+        
+        return list;
+    }
+        
+    /**
+     * Creates a list of dimensions used to query. 
      */
     public List<Dimension> getQueryDimensions()
     {
@@ -137,11 +168,9 @@
     /**
      * Returns the index of the indicator dimension in the dimension map.
      */
-    public int getDataElementOrIndicatorDimensionIndex()
+    public int getIndicatorDimensionIndex()
     {
-        List<String> dims = getInputDimensionNamesAsList();
-        
-        return dims.contains( DATAELEMENT_DIM_ID ) ? dims.indexOf( DATAELEMENT_DIM_ID ) : dims.indexOf( INDICATOR_DIM_ID );
+        return getInputDimensionNamesAsList().indexOf( INDICATOR_DIM_ID );
     }
     
     /**
@@ -377,6 +406,9 @@
         return valueMap;
     }
 
+    /**
+     * Retrieves the options for the given dimension.
+     */
     public List<IdentifiableObject> getDimensionOptions( String dimension )
     {
         int index = dimensions.indexOf( new Dimension( dimension ) );
@@ -384,6 +416,9 @@
         return index != -1 ? dimensions.get( index ).getOptions() : null;
     }
 
+    /**
+     * Sets the options for the given dimension.
+     */
     public void setDimensionOptions( String dimension, DimensionType type, List<IdentifiableObject> options )
     {
         int index = dimensions.indexOf( new Dimension( dimension ) );
@@ -398,6 +433,9 @@
         }
     }
     
+    /**
+     * Retrieves the options for the given filter.
+     */
     public List<IdentifiableObject> getFilterOptions( String filter )
     {
         int index = filters.indexOf( new Dimension( filter ) );
@@ -405,6 +443,9 @@
         return index != -1 ? filters.get( index ).getOptions() : null;
     }
     
+    /**
+     * Sets the options for the given filter.
+     */
     public void setFilterOptions( String filter, DimensionType type, List<IdentifiableObject> options )
     {
         int index = filters.indexOf( new Dimension( filter ) );

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/Dimension.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/Dimension.java	2013-01-28 10:55:48 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/Dimension.java	2013-01-30 13:46:01 +0000
@@ -51,6 +51,12 @@
         this.dimension = dimension;
     }
 
+    public Dimension( String dimension, DimensionType type )
+    {
+        this.dimension = dimension;
+        this.type = type;
+    }
+
     public Dimension( String dimension, DimensionType type, List<IdentifiableObject> options )
     {
         this.dimension = dimension;

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DimensionType.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DimensionType.java	2013-01-22 07:59:25 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DimensionType.java	2013-01-30 13:46:01 +0000
@@ -1,10 +1,38 @@
 package org.hisp.dhis.analytics;
 
+/*
+ * Copyright (c) 2004-2012, 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.
+ */
+
 public enum DimensionType
 {
     INDICATOR,
     DATAELEMENT,
     DATASET,
+    DATA_X,
     CATEGORY_OPTION_COMBO,
     PERIOD,
     ORGANISATIONUNIT,

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java	2013-01-30 09:01:04 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java	2013-01-30 13:46:01 +0000
@@ -29,9 +29,10 @@
 
 import static org.hisp.dhis.analytics.AnalyticsTableManager.ANALYTICS_TABLE_NAME;
 import static org.hisp.dhis.analytics.AnalyticsTableManager.COMPLETENESS_TABLE_NAME;
+import static org.hisp.dhis.analytics.DataQueryParams.CATEGORYOPTIONCOMBO_DIM_ID;
 import static org.hisp.dhis.analytics.DataQueryParams.DATAELEMENT_DIM_ID;
-import static org.hisp.dhis.analytics.DataQueryParams.CATEGORYOPTIONCOMBO_DIM_ID;
 import static org.hisp.dhis.analytics.DataQueryParams.DATASET_DIM_ID;
+import static org.hisp.dhis.analytics.DataQueryParams.DATA_X_DIM_ID;
 import static org.hisp.dhis.analytics.DataQueryParams.DIMENSION_SEP;
 import static org.hisp.dhis.analytics.DataQueryParams.INDICATOR_DIM_ID;
 import static org.hisp.dhis.analytics.DataQueryParams.ORGUNIT_DIM_ID;
@@ -42,12 +43,15 @@
 import static org.hisp.dhis.common.IdentifiableObjectUtils.asTypedList;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Future;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.hisp.dhis.analytics.AggregationType;
 import org.hisp.dhis.analytics.AnalyticsManager;
 import org.hisp.dhis.analytics.AnalyticsService;
@@ -61,9 +65,11 @@
 import org.hisp.dhis.common.GridHeader;
 import org.hisp.dhis.common.IdentifiableObject;
 import org.hisp.dhis.constant.ConstantService;
+import org.hisp.dhis.dataelement.DataElement;
 import org.hisp.dhis.dataelement.DataElementGroupSet;
 import org.hisp.dhis.dataelement.DataElementOperand;
 import org.hisp.dhis.dataelement.DataElementService;
+import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.dataset.DataSetService;
 import org.hisp.dhis.expression.ExpressionService;
 import org.hisp.dhis.i18n.I18nFormat;
@@ -86,9 +92,12 @@
 public class DefaultAnalyticsService
     implements AnalyticsService
 {
+    private static final Log log = LogFactory.getLog( DefaultAnalyticsService.class );
+    
     private static final String VALUE_HEADER_NAME = "Value";
     
     //TODO completeness
+    //TODO make sure data x dims are successive
     
     @Autowired
     private AnalyticsManager analyticsManager;
@@ -123,6 +132,8 @@
 
     public Grid getAggregatedDataValues( DataQueryParams params ) throws Exception
     {
+        log.info( "Query: " + params );
+        
         Grid grid = new ListGrid();
 
         // ---------------------------------------------------------------------
@@ -131,7 +142,7 @@
 
         grid.setMetaData( params.getUidNameMap() );
         
-        for ( Dimension col : params.getDimensions() )
+        for ( Dimension col : params.getHeaderDimensions() )
         {
             grid.addHeader( new GridHeader( col.getDimensionName(), col.getDimension(), String.class.getName(), false, true ) );
         }
@@ -143,12 +154,15 @@
         // ---------------------------------------------------------------------
 
         if ( params.getIndicators() != null )
-        {         
-            int indicatorIndex = params.getDataElementOrIndicatorDimensionIndex();
-
+        {   
+            int indicatorIndex = params.getIndicatorDimensionIndex();
             List<Indicator> indicators = asTypedList( params.getIndicators() );
+                  
+            DataQueryParams dataSourceParams = new DataQueryParams( params );
+            dataSourceParams.removeDimension( DATAELEMENT_DIM_ID );
+            dataSourceParams.removeDimension( DATASET_DIM_ID );
             
-            DataQueryParams dataSourceParams = setDataElementsFromIndicators( params );
+            dataSourceParams = replaceIndicatorsWithDataElements( dataSourceParams, indicatorIndex );
 
             Map<String, Double> aggregatedDataMap = getAggregatedDataValueMap( dataSourceParams, ANALYTICS_TABLE_NAME );
 
@@ -300,7 +314,7 @@
                 
                 if ( dimension != null && options != null )
                 {
-                    params.getDimensions().add( getDimension( dimension, options, format ) );
+                    params.getDimensions().addAll( getDimension( dimension, options, format ) );
                 }
             }
         }
@@ -314,7 +328,7 @@
                 
                 if ( dimension != null && options != null )
                 {
-                    params.getFilters().add( getDimension( dimension, options, format ) );
+                    params.getFilters().addAll( getDimension( dimension, options, format ) );
                 }
             }
         }
@@ -331,33 +345,75 @@
     // Supportive methods
     // -------------------------------------------------------------------------
     
-    private Dimension getDimension( String dimension, List<String> options, I18nFormat format )
+    private List<Dimension> getDimension( String dimension, List<String> options, I18nFormat format )
     {
-        if ( INDICATOR_DIM_ID.equals( dimension ) )
-        {
-            return new Dimension( dimension, DimensionType.INDICATOR, asList( indicatorService.getIndicatorsByUid( options ) ) );
-        }
-        else if ( DATAELEMENT_DIM_ID.equals( dimension ) )
-        {
-            return new Dimension( dimension, DimensionType.DATAELEMENT, asList( dataElementService.getDataElementsByUid( options ) ) );
-        }
-        else if ( DATASET_DIM_ID.equals( dimension ) )
-        {
-            return new Dimension( dimension, DimensionType.DATASET, asList( dataSetService.getDataSetsByUid( options ) ) );
+        if ( DATA_X_DIM_ID.equals( dimension ) )
+        {
+            List<Dimension> dataDimensions = new ArrayList<Dimension>();
+            
+            List<IdentifiableObject> indicators = new ArrayList<IdentifiableObject>();
+            List<IdentifiableObject> dataElements = new ArrayList<IdentifiableObject>();
+            List<IdentifiableObject> dataSets = new ArrayList<IdentifiableObject>();
+            
+            options : for ( String uid : options )
+            {
+                Indicator in = indicatorService.getIndicator( uid );
+                
+                if ( in != null )
+                {
+                    indicators.add( in );
+                    continue options;
+                }
+                
+                DataElement de = dataElementService.getDataElement( uid );
+                
+                if ( de != null )
+                {
+                    dataElements.add( de );
+                    continue options;
+                }
+                
+                DataSet ds = dataSetService.getDataSet( uid );
+                
+                if ( ds != null )
+                {
+                    dataSets.add( ds );
+                    continue options;
+                }
+                
+                throw new IllegalQueryException( "Data dimension option identifier does not reference any option: " + uid );                
+            }
+            
+            if ( !indicators.isEmpty() )
+            {
+                dataDimensions.add( new Dimension( INDICATOR_DIM_ID, DimensionType.INDICATOR, indicators ) );
+            }
+            
+            if ( !dataElements.isEmpty() )
+            {
+                dataDimensions.add( new Dimension( DATAELEMENT_DIM_ID, DimensionType.DATAELEMENT, dataElements ) );
+            }
+            
+            if ( !dataSets.isEmpty() )
+            {
+                dataDimensions.add( new Dimension( DATASET_DIM_ID, DimensionType.DATASET, dataSets ) );
+            }
+            
+            return dataDimensions;
         }
         else if ( CATEGORYOPTIONCOMBO_DIM_ID.equals( dimension ) )
         {
-            return new Dimension( dimension, DimensionType.CATEGORY_OPTION_COMBO, new ArrayList<IdentifiableObject>() );
+            return Arrays.asList( new Dimension( dimension, DimensionType.CATEGORY_OPTION_COMBO, new ArrayList<IdentifiableObject>() ) );
         }
         else if ( ORGUNIT_DIM_ID.equals( dimension ) )
         {
-            return new Dimension( dimension, DimensionType.ORGANISATIONUNIT, asList( organisationUnitService.getOrganisationUnitsByUid( options ) ) );
+            return Arrays.asList( new Dimension( dimension, DimensionType.ORGANISATIONUNIT, asList( organisationUnitService.getOrganisationUnitsByUid( options ) ) ) );
         }
         else if ( PERIOD_DIM_ID.equals( dimension ) )
         {
             List<IdentifiableObject> list = new ArrayList<IdentifiableObject>();
-                        
-            periodLoop : for ( String isoPeriod : options )
+            
+            periods : for ( String isoPeriod : options )
             {
                 Period period = PeriodType.getPeriodFromIsoString( isoPeriod );
                 
@@ -365,49 +421,49 @@
                 {
                     period.setName( format != null ? format.formatPeriod( period ) : null );
                     list.add( period );
-                    continue periodLoop;
+                    continue periods;
                 }
                 
                 if ( RelativePeriodEnum.contains( isoPeriod ) )
                 {
                     RelativePeriodEnum relativePeriod = RelativePeriodEnum.valueOf( isoPeriod );
                     list.addAll( RelativePeriods.getRelativePeriodsFromEnum( relativePeriod, format, true ) );
-                    continue periodLoop;
+                    continue periods;
                 }
             }
             
-            return new Dimension( dimension, DimensionType.PERIOD, list );
+            return Arrays.asList( new Dimension( dimension, DimensionType.PERIOD, list ) );
         }
         
         OrganisationUnitGroupSet orgUnitGroupSet = organisationUnitGroupService.getOrganisationUnitGroupSet( dimension );
             
         if ( orgUnitGroupSet != null )
         {
-            return new Dimension( dimension, DimensionType.ORGANISATIONUNIT_GROUPSET, asList( organisationUnitGroupService.getOrganisationUnitGroupsByUid( options ) ) );
+            List<IdentifiableObject> ous = asList( organisationUnitGroupService.getOrganisationUnitGroupsByUid( options ) );
+            
+            return Arrays.asList( new Dimension( dimension, DimensionType.ORGANISATIONUNIT_GROUPSET, ous ) );
         }
         
         DataElementGroupSet dataElementGroupSet = dataElementService.getDataElementGroupSet( dimension );
         
         if ( dataElementGroupSet != null )
         {
-            return new Dimension( dimension, DimensionType.DATAELEMENT_GROUPSET, asList( dataElementService.getDataElementGroupsByUid( options ) ) );
+            List<IdentifiableObject> des = asList( dataElementService.getDataElementGroupsByUid( options ) );
+            
+            return Arrays.asList( new Dimension( dimension, DimensionType.DATAELEMENT_GROUPSET, des ) );
         }
         
         throw new IllegalQueryException( "Dimension identifier does not reference any dimension: " + dimension );
     }
     
-    private DataQueryParams setDataElementsFromIndicators( DataQueryParams params )
+    private DataQueryParams replaceIndicatorsWithDataElements( DataQueryParams params, int indicatorIndex )
     {
-        DataQueryParams immutableParams = new DataQueryParams( params );
-        
-        List<Indicator> indicators = asTypedList( immutableParams.getIndicators() );            
+        List<Indicator> indicators = asTypedList( params.getIndicators() );        
         List<IdentifiableObject> dataElements = asList( expressionService.getDataElementsInIndicators( indicators ) );
         
-        immutableParams.setDataElements( dataElements );
-        immutableParams.removeDimension( INDICATOR_DIM_ID );
-        immutableParams.removeDimension( DATASET_DIM_ID );
-        immutableParams.enableCategoryOptionCombos();
+        params.getDimensions().set( indicatorIndex, new Dimension( DATAELEMENT_DIM_ID, DimensionType.DATAELEMENT, dataElements ) );
+        params.enableCategoryOptionCombos();
         
-        return immutableParams;
+        return params;
     }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/AnalyticsServiceTest.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/AnalyticsServiceTest.java	2013-01-28 15:55:56 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/AnalyticsServiceTest.java	2013-01-30 13:46:01 +0000
@@ -123,7 +123,7 @@
     public void testGetFromUrl()
     {
         Set<String> dimensionParams = new HashSet<String>();
-        dimensionParams.add( "de:" + BASE_UID + "A," + BASE_UID + "B," + BASE_UID + "C," + BASE_UID + "D" );
+        dimensionParams.add( "dx:" + BASE_UID + "A," + BASE_UID + "B," + BASE_UID + "C," + BASE_UID + "D" );
         dimensionParams.add( "pe:2012,2012S1,2012S2" );
         dimensionParams.add( ouGroupSetA.getUid() + ":" + ouGroupA.getUid() + "," + ouGroupB.getUid() + "," + ouGroupC.getUid() );
         

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java	2013-01-28 15:55:56 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java	2013-01-30 13:46:01 +0000
@@ -29,7 +29,7 @@
 
 import static org.hisp.dhis.analytics.DataQueryParams.DIMENSION_SEP;
 import static org.hisp.dhis.analytics.DataQueryParams.ORGUNIT_DIM_ID;
-import static org.hisp.dhis.analytics.DataQueryParams.PERIOD_DIM_ID;
+import static org.hisp.dhis.analytics.DataQueryParams.*;
 import static org.hisp.dhis.common.IdentifiableObjectUtils.getList;
 import static org.hisp.dhis.analytics.AnalyticsTableManager.ANALYTICS_TABLE_NAME;
 import static org.junit.Assert.assertEquals;
@@ -53,6 +53,8 @@
 import org.hisp.dhis.dataelement.DataElementCategoryService;
 import org.hisp.dhis.dataelement.DataElementOperand;
 import org.hisp.dhis.dataelement.DataElementService;
+import org.hisp.dhis.indicator.Indicator;
+import org.hisp.dhis.indicator.IndicatorService;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.organisationunit.OrganisationUnitService;
 import org.hisp.dhis.period.Cal;
@@ -77,12 +79,17 @@
     private DataElementCategoryService categoryService;
     
     @Autowired
+    private IndicatorService indicatorService;
+    
+    @Autowired
     private OrganisationUnitService organisationUnitService;
     
     // -------------------------------------------------------------------------
     // Fixture
     // -------------------------------------------------------------------------
 
+    private Indicator inA;
+    
     private DataElement deA;
     private DataElement deB;
     private DataElement deC;
@@ -99,6 +106,10 @@
     @Override
     public void setUpTest()
     {
+        inA = createIndicator( 'A', null );
+        
+        indicatorService.addIndicator( inA );
+        
         deA = createDataElement( 'A' );
         deB = createDataElement( 'B' );
         deC = createDataElement( 'C' );
@@ -129,6 +140,40 @@
     // -------------------------------------------------------------------------
 
     @Test
+    public void testGetHeaderDimensions()
+    {
+        List<Dimension> expected = new ArrayList<Dimension>();
+        expected.add( new Dimension( DATA_X_DIM_ID ) );
+        expected.add( new Dimension( ORGUNIT_DIM_ID ) );
+        expected.add( new Dimension( PERIOD_DIM_ID ) );
+        
+        DataQueryParams params = new DataQueryParams();
+        params.setDataElements( getList( deA, deB ) );
+        params.setOrganisationUnits( getList( ouA, ouB ) );
+        params.setPeriods( getList( createPeriod( "2000Q1" ), createPeriod( "2000Q2" ) ) );
+        
+        assertEquals( expected, params.getHeaderDimensions() );
+        
+        params = new DataQueryParams();
+        params.setDataElements( getList( deA, deB ) );
+        params.setIndicators( getList( inA ) );
+        params.setOrganisationUnits( getList( ouA, ouB ) );
+        params.setPeriods( getList( createPeriod( "2000Q1" ), createPeriod( "2000Q2" ) ) );
+
+        assertEquals( expected, params.getHeaderDimensions() );
+        
+        expected = new ArrayList<Dimension>();
+        expected.add( new Dimension( ORGUNIT_DIM_ID ) );
+        expected.add( new Dimension( PERIOD_DIM_ID ) );
+
+        params = new DataQueryParams();
+        params.setOrganisationUnits( getList( ouA, ouB ) );
+        params.setPeriods( getList( createPeriod( "2000Q1" ), createPeriod( "2000Q2" ) ) );
+
+        assertEquals( expected, params.getHeaderDimensions() );
+    }
+    
+    @Test
     public void testSetGetCopy()
     {
         List<IdentifiableObject> desA = getList( deA, deB );

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AnalyticsController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AnalyticsController.java	2013-01-30 08:53:54 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AnalyticsController.java	2013-01-30 13:46:01 +0000
@@ -193,6 +193,8 @@
             return false;
         }
         
+        //TODO check if any dimension occur more than once
+        
         return true;        
     }
 }