← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 9686: Analytics, fixed bug with period as filter. Centralized validation of queries.

 

------------------------------------------------------------
revno: 9686
committer: Lars Helge Øverland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Fri 2013-02-01 16:57:34 +0200
message:
  Analytics, fixed bug with period as filter. Centralized validation of queries.
modified:
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsService.java
  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/QueryPlanner.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/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java
  dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcAnalyticsManager.java
  dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.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/AnalyticsService.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsService.java	2013-01-28 15:55:56 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsService.java	2013-02-01 14:57:34 +0000
@@ -35,9 +35,11 @@
 
 public interface AnalyticsService
 {
-    Grid getAggregatedDataValues( DataQueryParams params ) throws Exception;
+    Grid getAggregatedDataValues( DataQueryParams params ) 
+        throws IllegalQueryException, Exception;
     
-    Map<String, Double> getAggregatedDataValueMap( DataQueryParams params, String tableName ) throws Exception;
+    Map<String, Double> getAggregatedDataValueMap( DataQueryParams params, String tableName ) 
+        throws IllegalQueryException, Exception;
     
     DataQueryParams getFromUrl( Set<String> dimensionParams, Set<String> filterParams, 
         AggregationType aggregationType, String measureCriteria, I18nFormat format );

=== 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-02-01 11:13:47 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java	2013-02-01 14:57:34 +0000
@@ -270,7 +270,7 @@
 
         if ( dataPeriodType != null )
         {
-            for ( IdentifiableObject aggregatePeriod : getPeriods() )
+            for ( IdentifiableObject aggregatePeriod : getDimensionOrFilter( PERIOD_DIM_ID ) )
             {
                 Period dataPeriod = dataPeriodType.createPeriod( ((Period) aggregatePeriod).getStartDate() );
                 
@@ -293,7 +293,14 @@
         {
             this.periodType = this.dataPeriodType.getName();
             
-            setPeriods( new ArrayList<IdentifiableObject>( getDataPeriodAggregationPeriodMap().keySet() ) );
+            if ( getPeriods() != null ) // Period is dimension
+            {
+                setPeriods( new ArrayList<IdentifiableObject>( dataPeriodAggregationPeriodMap.keySet() ) );
+            }
+            else // Period is filter
+            {
+                setFilterPeriods( new ArrayList<IdentifiableObject>( dataPeriodAggregationPeriodMap.keySet() ) );
+            }
         }
     }
     

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java	2013-01-17 17:49:13 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/QueryPlanner.java	2013-02-01 14:57:34 +0000
@@ -32,6 +32,17 @@
 public interface QueryPlanner
 {
     /**
+     * Validates the given query. Throws an IllegalQueryException if the query
+     * is not valid with a descriptive message. Returns normally if the query is
+     * valid.
+     * 
+     * @param params the query.
+     * @throws IllegalQueryException if the query is invalid.
+     */
+    void validate( DataQueryParams params )
+        throws IllegalQueryException;
+    
+    /**
      * Creates a list of DataQueryParams. It is mandatory to group the queries by
      * the following criteria: 1) partition / year 2) period type 3) organisation 
      * unit level. If the number of queries produced by this grouping is equal or
@@ -48,5 +59,6 @@
      * @param tableName the base table name.
      * @return list of data query params.
      */
-    List<DataQueryParams> planQuery( DataQueryParams params, int optimalQueries, String tableName );
+    List<DataQueryParams> planQuery( DataQueryParams params, int optimalQueries, String tableName )
+        throws IllegalQueryException;
 }

=== 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-02-01 11:45:27 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultAnalyticsService.java	2013-02-01 14:57:34 +0000
@@ -90,7 +90,6 @@
 import org.hisp.dhis.system.util.SystemUtils;
 import org.hisp.dhis.system.util.Timer;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.util.Assert;
 
 public class DefaultAnalyticsService
     implements AnalyticsService
@@ -134,10 +133,13 @@
     // Implementation
     // -------------------------------------------------------------------------
 
-    public Grid getAggregatedDataValues( DataQueryParams params ) throws Exception
+    public Grid getAggregatedDataValues( DataQueryParams params )
+        throws IllegalQueryException, Exception
     {
         log.info( "Query: " + params );
         
+        queryPlanner.validate( params );
+        
         Grid grid = new ListGrid();
 
         // ---------------------------------------------------------------------
@@ -188,8 +190,6 @@
                     {
                         Period period = (Period) DimensionOption.getPeriodOption( options );
                         
-                        Assert.notNull( period );
-                        
                         Double value = expressionService.getIndicatorValue( indicator, period, valueMap, constantMap, null );
                         
                         if ( value != null )
@@ -268,8 +268,11 @@
         return grid;
     }
     
-    public Map<String, Double> getAggregatedDataValueMap( DataQueryParams params, String tableName ) throws Exception
+    public Map<String, Double> getAggregatedDataValueMap( DataQueryParams params, String tableName )
+        throws IllegalQueryException, Exception
     {
+        queryPlanner.validate( params );
+        
         Timer t = new Timer().start();
 
         int optimalQueries = MathUtils.getWithin( SystemUtils.getCpuCores(), 1, 6 );

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java	2013-01-30 20:37:26 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/DefaultQueryPlanner.java	2013-02-01 14:57:34 +0000
@@ -31,8 +31,7 @@
 import static org.hisp.dhis.analytics.AggregationType.AVERAGE_INT;
 import static org.hisp.dhis.analytics.AggregationType.AVERAGE_INT_DISAGGREGATION;
 import static org.hisp.dhis.analytics.AggregationType.SUM;
-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.INDICATOR_DIM_ID;
 import static org.hisp.dhis.dataelement.DataElement.AGGREGATION_OPERATOR_AVERAGE;
 import static org.hisp.dhis.dataelement.DataElement.AGGREGATION_OPERATOR_SUM;
 import static org.hisp.dhis.dataelement.DataElement.VALUE_TYPE_BOOL;
@@ -44,7 +43,7 @@
 import org.hisp.dhis.analytics.AggregationType;
 import org.hisp.dhis.analytics.DataQueryParams;
 import org.hisp.dhis.analytics.Dimension;
-import org.hisp.dhis.analytics.DimensionType;
+import org.hisp.dhis.analytics.IllegalQueryException;
 import org.hisp.dhis.analytics.QueryPlanner;
 import org.hisp.dhis.analytics.table.PartitionUtils;
 import org.hisp.dhis.common.IdentifiableObject;
@@ -58,13 +57,12 @@
 import org.hisp.dhis.system.util.MathUtils;
 import org.hisp.dhis.system.util.PaginatedList;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.util.Assert;
 
 public class DefaultQueryPlanner
     implements QueryPlanner
 {
-    //TODO call getLevelOrgUnitMap once
-    //TODO shortcut group by methods when only 1 option
+    //TODO call getLevelOrgUnitMap once?
+    //TODO shortcut group by methods when only 1 option?
     
     @Autowired
     private OrganisationUnitService organisationUnitService;
@@ -72,12 +70,36 @@
     // -------------------------------------------------------------------------
     // DefaultQueryPlanner implementation
     // -------------------------------------------------------------------------
+
+    public void validate( DataQueryParams params )
+        throws IllegalQueryException
+    {
+        if ( params == null || params.getDimensions().isEmpty() )
+        {
+            throw new IllegalQueryException( "At least one dimension must be specified" );
+        }
+        
+        if ( !params.dimensionsAsFilters().isEmpty() )
+        {
+            throw new IllegalQueryException( "Dimensions cannot be specified as dimension and filter simultaneously: " + params.dimensionsAsFilters() );
+        }
+        
+        if ( !params.hasPeriods() )
+        {
+            throw new IllegalQueryException( "At least one period must be specified as dimension or filter" );
+        }
+        
+        if ( params.getFilters() != null && params.getFilters().contains( new Dimension( INDICATOR_DIM_ID ) ) )
+        {
+            throw new IllegalQueryException( "Indicators cannot be specified as filter" );
+        }
+                
+        //TODO check if any dimension occur more than once
+    }
     
     public List<DataQueryParams> planQuery( DataQueryParams params, int optimalQueries, String tableName )
     {
-        Assert.isTrue( !params.getDimensions().isEmpty() );
-        Assert.isTrue( params.dimensionsAsFilters().isEmpty() );
-        Assert.isTrue( params.hasPeriods() );
+        validate( params );
 
         // ---------------------------------------------------------------------
         // Group queries by partition, period type and organisation unit level
@@ -130,13 +152,6 @@
             }
         }
 
-        // ---------------------------------------------------------------------
-        // Set filters for each period type and organisation unit level
-        // ---------------------------------------------------------------------
-        
-        queries = setFilterByPeriodType( queries );
-        queries = setFilterByOrgUnitLevel( queries );
-        
         if ( queries.size() >= optimalQueries )
         {
             return queries;
@@ -222,7 +237,7 @@
                 queries.add( query );            
             }
         }
-        else
+        else if ( params.getFilterPeriods() != null && !params.getFilterPeriods().isEmpty() )
         {
             ListMap<String, IdentifiableObject> tablePeriodMap = PartitionUtils.getTablePeriodMap( params.getFilterPeriods(), tableName );
             
@@ -234,6 +249,10 @@
                 queries.add( query );            
             }
         }
+        else
+        {
+            throw new IllegalQueryException( "Query does not contain any period dimension options" );
+        }
         
         return queries;
     }
@@ -246,20 +265,33 @@
     {
         List<DataQueryParams> queries = new ArrayList<DataQueryParams>();
 
-        if ( params.getPeriods() == null || params.getPeriods().isEmpty() )
-        {
-            queries.add( new DataQueryParams( params ) );
-            return queries;
-        }
-        
-        ListMap<String, IdentifiableObject> periodTypePeriodMap = getPeriodTypePeriodMap( params.getPeriods() );
-
-        for ( String periodType : periodTypePeriodMap.keySet() )
-        {
-            DataQueryParams query = new DataQueryParams( params );
-            query.setPeriods( periodTypePeriodMap.get( periodType ) );
-            query.setPeriodType( periodType );
-            queries.add( query );
+        if ( params.getPeriods() != null && !params.getPeriods().isEmpty() )
+        {
+            ListMap<String, IdentifiableObject> periodTypePeriodMap = getPeriodTypePeriodMap( params.getPeriods() );
+    
+            for ( String periodType : periodTypePeriodMap.keySet() )
+            {
+                DataQueryParams query = new DataQueryParams( params );
+                query.setPeriods( periodTypePeriodMap.get( periodType ) );
+                query.setPeriodType( periodType );
+                queries.add( query );
+            }
+        }
+        else if ( params.getFilterPeriods() != null && !params.getFilterPeriods().isEmpty() )
+        {
+            ListMap<String, IdentifiableObject> periodTypePeriodMap = getPeriodTypePeriodMap( params.getFilterPeriods() );
+            
+            for ( String periodType : periodTypePeriodMap.keySet() )
+            {
+                DataQueryParams query = new DataQueryParams( params );
+                query.setFilterPeriods( periodTypePeriodMap.get( periodType ) );
+                query.setPeriodType( periodType );
+                queries.add( query );
+            }
+        }
+        else
+        {
+            throw new IllegalQueryException( "Query does not contain any period dimension options" );
         }
         
         return queries;        
@@ -273,22 +305,36 @@
     {
         List<DataQueryParams> queries = new ArrayList<DataQueryParams>();
 
-        if ( params.getOrganisationUnits() == null || params.getOrganisationUnits().isEmpty() )
+        if ( params.getOrganisationUnits() != null && !params.getOrganisationUnits().isEmpty() )
+        {
+            ListMap<Integer, IdentifiableObject> levelOrgUnitMap = getLevelOrgUnitMap( params.getOrganisationUnits() );
+            
+            for ( Integer level : levelOrgUnitMap.keySet() )
+            {
+                DataQueryParams query = new DataQueryParams( params );
+                query.setOrganisationUnits( levelOrgUnitMap.get( level ) );
+                query.setOrganisationUnitLevel( level );
+                queries.add( query );
+            }
+        }
+        else if ( params.getFilterOrganisationUnits() != null && !params.getFilterOrganisationUnits().isEmpty() )
+        {
+            ListMap<Integer, IdentifiableObject> levelOrgUnitMap = getLevelOrgUnitMap( params.getFilterOrganisationUnits() );
+            
+            for ( Integer level : levelOrgUnitMap.keySet() )
+            {
+                DataQueryParams query = new DataQueryParams( params );
+                query.setFilterOrganisationUnits( levelOrgUnitMap.get( level ) );
+                query.setOrganisationUnitLevel( level );
+                queries.add( query );
+            }
+        }
+        else
         {
             queries.add( new DataQueryParams( params ) );
             return queries;
         }
         
-        ListMap<Integer, IdentifiableObject> levelOrgUnitMap = getLevelOrgUnitMap( params.getOrganisationUnits() );
-        
-        for ( Integer level : levelOrgUnitMap.keySet() )
-        {
-            DataQueryParams query = new DataQueryParams( params );
-            query.setOrganisationUnits( levelOrgUnitMap.get( level ) );
-            query.setOrganisationUnitLevel( level );
-            queries.add( query );
-        }
-        
         return queries;    
     }
     
@@ -324,6 +370,8 @@
             queries.add( new DataQueryParams( params ) );
             return queries;
         }
+
+        Dimension groupSet = null;
         
         if ( params.getDataElements() != null && !params.getDataElements().isEmpty() )
         {
@@ -338,13 +386,8 @@
                 query.setAggregationType( aggregationType );
                 queries.add( query );
             }
-            
-            return queries;
         }
-        
-        Dimension groupSet = null;
-        
-        if ( params.getDataElementGroupSets() != null && !params.getDataElementGroupSets().isEmpty() &&
+        else if ( params.getDataElementGroupSets() != null && !params.getDataElementGroupSets().isEmpty() &&
             ( groupSet = params.getDataElementGroupSets().iterator().next() ).getOptions() != null && !groupSet.getOptions().isEmpty() )
         {
             PeriodType periodType = PeriodType.getPeriodTypeByName( params.getPeriodType() );
@@ -358,13 +401,14 @@
                 query.setAggregationType( aggregationType );
                 queries.add( query );
             }
-            
-            return queries;
         }
+        else
+        {
+            DataQueryParams query = new DataQueryParams( params );
+            query.setAggregationType( SUM );
+            queries.add( query );            
+        }        
         
-        DataQueryParams query = new DataQueryParams( params );
-        query.setAggregationType( SUM );
-        queries.add( query );
         return queries;
     }
         
@@ -396,55 +440,6 @@
     }
     
     /**
-     * Replaces the period filter with individual filters for each period type.
-     */
-    private List<DataQueryParams> setFilterByPeriodType( List<DataQueryParams> queries )
-    {
-        for ( DataQueryParams params : queries )
-        {
-            if ( params.getFilterPeriods() != null && !params.getFilterPeriods().isEmpty() )
-            {
-                ListMap<String, IdentifiableObject> map = getPeriodTypePeriodMap( params.getFilterPeriods() );
-
-                params.getFilters().remove( new Dimension( PERIOD_DIM_ID ) );
-                
-                for ( String periodType : map.keySet() )
-                {
-                    params.getFilters().add( new Dimension( PERIOD_DIM_ID, DimensionType.PERIOD, map.get( periodType ) ) );
-                    params.setPeriodType( periodType );
-                }                
-            }
-        }
-        
-        return queries;
-    }
-    
-    /**
-     * Replaces the organisation unit filter with individual filters for each
-     * organisation unit level.
-     */
-    private List<DataQueryParams> setFilterByOrgUnitLevel( List<DataQueryParams> queries )
-    {
-        for ( DataQueryParams params : queries )
-        {
-            if ( params.getFilterOrganisationUnits() != null && !params.getFilterOrganisationUnits().isEmpty() )
-            {
-                ListMap<Integer, IdentifiableObject> map = getLevelColumnOrgUnitMap( params.getFilterOrganisationUnits() );
-                
-                params.getFilters().remove( new Dimension( ORGUNIT_DIM_ID ) );
-                
-                for ( Integer level : map.keySet() )
-                {
-                    params.getFilters().add( new Dimension( ORGUNIT_DIM_ID, DimensionType.ORGANISATIONUNIT, map.get( level ) ) );
-                    params.setOrganisationUnitLevel( level );
-                }
-            }
-        }
-        
-        return queries;
-    }
-    
-    /**
      * Creates a mapping between period type name and period for the given periods.
      */
     private ListMap<String, IdentifiableObject> getPeriodTypePeriodMap( Collection<IdentifiableObject> periods )
@@ -478,25 +473,7 @@
         
         return map;
     }
-    
-    /**
-     * Creates a mapping between the level column and organisation unit for the 
-     * given organisation units.
-     */
-    private ListMap<Integer, IdentifiableObject> getLevelColumnOrgUnitMap( Collection<IdentifiableObject> orgUnits )
-    {
-        ListMap<Integer, IdentifiableObject> map = new ListMap<Integer, IdentifiableObject>();
-        
-        for ( IdentifiableObject orgUnit : orgUnits )
-        {
-            int level = organisationUnitService.getLevelOfOrganisationUnit( ((OrganisationUnit) orgUnit).getUid() );
-            
-            map.putValue( level, orgUnit );
-        }
-        
-        return map;
-    }
-    
+        
     /**
      * Creates a mapping between the aggregation type and data element for the
      * given data elements and period type.
@@ -552,7 +529,7 @@
             }
             else
             {
-                if ( dataPeriodType == null || aggregationPeriodType.getFrequencyOrder() >= dataPeriodType.getFrequencyOrder() )
+                if ( dataPeriodType == null || aggregationPeriodType == null || aggregationPeriodType.getFrequencyOrder() >= dataPeriodType.getFrequencyOrder() )
                 {
                     map.putValue( AVERAGE_INT, element );
                 }

=== modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcAnalyticsManager.java'
--- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcAnalyticsManager.java	2013-01-28 15:55:56 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/data/JdbcAnalyticsManager.java	2013-02-01 14:57:34 +0000
@@ -177,6 +177,11 @@
         {
             int periodIndex = params.getPeriodDimensionIndex();
             
+            if ( periodIndex == -1 )
+            {
+                return; // Period is filter, nothing to replace
+            }
+            
             Set<String> keys = new HashSet<String>( dataValueMap.keySet() );
             
             for ( String key : keys )

=== 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-30 13:46:01 +0000
+++ dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/data/QueryPlannerTest.java	2013-02-01 14:57:34 +0000
@@ -46,6 +46,7 @@
 import org.hisp.dhis.analytics.DataQueryParams;
 import org.hisp.dhis.analytics.Dimension;
 import org.hisp.dhis.analytics.DimensionOption;
+import org.hisp.dhis.analytics.IllegalQueryException;
 import org.hisp.dhis.analytics.QueryPlanner;
 import org.hisp.dhis.common.IdentifiableObject;
 import org.hisp.dhis.dataelement.DataElement;
@@ -103,6 +104,8 @@
     private OrganisationUnit ouD;
     private OrganisationUnit ouE;
 
+    //TODO test for indicators, periods in filter
+    
     @Override
     public void setUpTest()
     {
@@ -480,7 +483,7 @@
     /**
      * Expected to fail because of no periods specified.
      */
-    @Test( expected = IllegalArgumentException.class )
+    @Test( expected = IllegalQueryException.class )
     public void planQueryG()
     {
         DataQueryParams params = new DataQueryParams();
@@ -539,6 +542,19 @@
             assertDimensionNameNotNull( query );
         }
     }
+
+    /**
+     * No periods specified, illegal query.
+     */
+    @Test( expected=IllegalQueryException.class )
+    public void planQueryJ()
+    {
+        DataQueryParams params = new DataQueryParams();
+        params.setDataElements( getList( deA, deB, deC, deD ) );
+        params.setOrganisationUnits( getList( ouA, ouB, ouC, ouD, ouE ) );
+        
+        queryPlanner.planQuery( params, 4, ANALYTICS_TABLE_NAME );
+    }
     
     // -------------------------------------------------------------------------
     // Supportive methods

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java	2013-01-15 11:43:12 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/expression/DefaultExpressionService.java	2013-02-01 14:57:34 +0000
@@ -150,7 +150,7 @@
         {
             final double numeratorValue = calculateExpression( generateExpression( indicator.getNumerator(), valueMap, constantMap, days, false ) );
             
-            final double annualizationFactor = DateUtils.getAnnualizationFactor( indicator, period.getStartDate(), period.getEndDate() );
+            final double annualizationFactor = period != null ? DateUtils.getAnnualizationFactor( indicator, period.getStartDate(), period.getEndDate() ) : 1d;
             final double factor = indicator.getIndicatorType().getFactor();
             final double aggregatedValue = ( numeratorValue / denominatorValue ) * factor * annualizationFactor;
             

=== 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-31 10:59:22 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/AnalyticsController.java	2013-02-01 14:57:34 +0000
@@ -35,7 +35,6 @@
 import org.hisp.dhis.analytics.AggregationType;
 import org.hisp.dhis.analytics.AnalyticsService;
 import org.hisp.dhis.analytics.DataQueryParams;
-import org.hisp.dhis.analytics.Dimension;
 import org.hisp.dhis.analytics.IllegalQueryException;
 import org.hisp.dhis.api.utils.ContextUtils;
 import org.hisp.dhis.api.utils.ContextUtils.CacheStrategy;
@@ -50,8 +49,6 @@
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 
-import static org.hisp.dhis.analytics.DataQueryParams.*;
-
 @Controller
 public class AnalyticsController
 {
@@ -81,11 +78,6 @@
     {
         DataQueryParams params = analyticsService.getFromUrl( dimension, filter, aggregationType, measureCriteria, i18nManager.getI18nFormat() );
 
-        if ( !valid( params, response ) )
-        {
-            return null;
-        }
-        
         contextUtils.configureResponse( response, ContextUtils.CONTENT_TYPE_JSON, CacheStrategy.NO_CACHE ); //TODO        
         Grid grid = analyticsService.getAggregatedDataValues( params );        
         model.addAttribute( "model", grid );
@@ -104,11 +96,6 @@
     {
         DataQueryParams params = analyticsService.getFromUrl( dimension, filter, aggregationType, measureCriteria, i18nManager.getI18nFormat() );
 
-        if ( !valid( params, response ) )
-        {
-            return;
-        }
-        
         contextUtils.configureResponse( response, ContextUtils.CONTENT_TYPE_XML, CacheStrategy.NO_CACHE ); //TODO        
         Grid grid = analyticsService.getAggregatedDataValues( params );
         GridUtils.toXml( grid, response.getOutputStream() );
@@ -125,11 +112,6 @@
     {
         DataQueryParams params = analyticsService.getFromUrl( dimension, filter, aggregationType, measureCriteria, i18nManager.getI18nFormat() );
 
-        if ( !valid( params, response ) )
-        {
-            return;
-        }
-        
         contextUtils.configureResponse( response, ContextUtils.CONTENT_TYPE_CSV, CacheStrategy.NO_CACHE ); //TODO        
         Grid grid = analyticsService.getAggregatedDataValues( params );
         GridUtils.toCsv( grid, response.getOutputStream() );
@@ -146,55 +128,19 @@
     {
         DataQueryParams params = analyticsService.getFromUrl( dimension, filter, aggregationType, measureCriteria, i18nManager.getI18nFormat() );
 
-        if ( !valid( params, response ) )
-        {
-            return;
-        }
-        
         contextUtils.configureResponse( response, ContextUtils.CONTENT_TYPE_HTML, CacheStrategy.NO_CACHE ); //TODO        
         Grid grid = analyticsService.getAggregatedDataValues( params );
         GridUtils.toHtml( grid, response.getWriter() );
     }
-    
+
+    // -------------------------------------------------------------------------
+    // Exception handling
+    // -------------------------------------------------------------------------
+  
     @ExceptionHandler(IllegalQueryException.class)
     public void handleError( IllegalQueryException ex, HttpServletResponse response )
         throws IOException
     {
         ContextUtils.conflictResponse( response, ex.getMessage() );
     }
-    
-    // -------------------------------------------------------------------------
-    // Supportive methods
-    // -------------------------------------------------------------------------
-      
-    private boolean valid( DataQueryParams params, HttpServletResponse response )
-    {
-        if ( params == null || params.getDimensions().isEmpty() )
-        {
-            ContextUtils.conflictResponse( response, "At least one dimension must be specified" );
-            return false;
-        }
-        
-        if ( !params.dimensionsAsFilters().isEmpty() )
-        {
-            ContextUtils.conflictResponse( response, "Dimensions cannot be specified as dimension and filter simultaneously: " + params.dimensionsAsFilters() );
-            return false;
-        }
-        
-        if ( !params.hasPeriods() )
-        {
-            ContextUtils.conflictResponse( response, "At least one period must be specified as dimension or filter" );
-            return false;
-        }
-        
-        if ( params.getFilters() != null && params.getFilters().contains( new Dimension( INDICATOR_DIM_ID ) ) )
-        {
-            ContextUtils.conflictResponse( response, "Indicators cannot be specified as filter" );
-            return false;
-        }
-                
-        //TODO check if any dimension occur more than once
-        
-        return true;        
-    }
 }