← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 6272: Implemented period aggregation for reporting rates

 

------------------------------------------------------------
revno: 6272
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Thu 2012-03-15 17:04:20 +0100
message:
  Implemented period aggregation for reporting rates
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/completeness/DataSetCompletenessStore.java
  dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/aggregation/cache/AggregationCache.java
  dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/aggregation/cache/MemoryAggregationCache.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/AbstractDataSetCompletenessService.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/CompulsoryDataSetCompletenessService.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/RatioDataSetCompletenessService.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/RegistrationDataSetCompletenessService.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/jdbc/JDBCDataSetCompletenessStore.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/completeness/DataSetCompletenessServiceExportTest.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/completeness/DataSetCompletenessStore.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/completeness/DataSetCompletenessStore.java	2012-03-15 12:47:27 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/completeness/DataSetCompletenessStore.java	2012-03-15 16:04:20 +0000
@@ -31,7 +31,6 @@
 import java.util.Date;
 
 import org.hisp.dhis.dataset.DataSet;
-import org.hisp.dhis.period.Period;
 
 /**
  * @author Lars Helge Overland
@@ -41,20 +40,18 @@
 {
     String ID = DataSetCompletenessStore.class.getName();
     
-    int getCompleteDataSetRegistrations( DataSet dataSet, Period period, Collection<Integer> relevantSources );
-    
-    int getCompleteDataSetRegistrations( DataSet dataSet, Period period, Collection<Integer> relevantSources, Date deadline );
-
-    int getCompulsoryDataElementRegistrations( DataSet dataSet, Collection<Integer> children, Period period );
-    
-    int getCompulsoryDataElementRegistrations( DataSet dataSet, Collection<Integer> children, Period period, Date deadline );
-
-    int getNumberOfValues( DataSet dataSet, Collection<Integer> children, Period period, Date deadline );
+    Integer getCompleteDataSetRegistrations( DataSet dataSet, Collection<Integer> periods, Collection<Integer> relevantSources );
+    
+    Integer getCompleteDataSetRegistrations( DataSet dataSet, Collection<Integer> periods, Collection<Integer> relevantSources, Date deadline );
+
+    Integer getCompulsoryDataElementRegistrations( DataSet dataSet, Collection<Integer> children, Collection<Integer> periods );
+    
+    Integer getCompulsoryDataElementRegistrations( DataSet dataSet, Collection<Integer> children, Collection<Integer> periods, Date deadline );
+
+    Integer getNumberOfValues( DataSet dataSet, Collection<Integer> children, Collection<Integer> periods, Date deadline );
     
     Collection<DataSet> getDataSetsWithRegistrations( Collection<DataSet> dataSets );
     
-    Collection<Period> getPeriodsWithRegistrations( Collection<Period> periods );
-
     /**
      * Gets the percentage value for the datasetcompleteness with the given parameters.
      * 
@@ -63,7 +60,7 @@
      * @param sourceId the Source identifier.
      * @return the percentage value for the datasetcompleteness result with the given parameters.
      */
-    double getPercentage( int dataSetId, int periodId, int sourceId );
+    Double getPercentage( int dataSetId, int periodId, int sourceId );
     
     /**
      * Deletes the datasetcompleteness entries with the given parameters.

=== modified file 'dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/aggregation/cache/AggregationCache.java'
--- dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/aggregation/cache/AggregationCache.java	2011-12-26 10:07:59 +0000
+++ dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/aggregation/cache/AggregationCache.java	2012-03-15 16:04:20 +0000
@@ -31,6 +31,7 @@
 import java.util.Date;
 
 import org.hisp.dhis.period.Period;
+import org.hisp.dhis.period.PeriodType;
 
 /**
  * @author Lars Helge Overland
@@ -40,7 +41,9 @@
 {
     Collection<Integer> getIntersectingPeriods( Date startDate, Date endDate );
     
-    Collection<Integer> getPeriodsBetweenDates( final Date startDate, final Date endDate );
+    Collection<Integer> getPeriodsBetweenDates( Date startDate, Date endDate );
+    
+    Collection<Integer> getPeriodsBetweenDatesPeriodType( PeriodType periodType, Date startDate, Date endDate );
     
     Period getPeriod( int id );
     

=== modified file 'dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/aggregation/cache/MemoryAggregationCache.java'
--- dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/aggregation/cache/MemoryAggregationCache.java	2011-12-26 10:07:59 +0000
+++ dhis-2/dhis-services/dhis-service-datamart-default/src/main/java/org/hisp/dhis/datamart/aggregation/cache/MemoryAggregationCache.java	2012-03-15 16:04:20 +0000
@@ -35,6 +35,7 @@
 import org.hisp.dhis.organisationunit.OrganisationUnitService;
 import org.hisp.dhis.period.Period;
 import org.hisp.dhis.period.PeriodService;
+import org.hisp.dhis.period.PeriodType;
 import org.hisp.dhis.system.util.ConversionUtils;
 
 /**
@@ -51,7 +52,9 @@
 
     private final ThreadLocal<Map<String, Collection<Integer>>> intersectingPeriodCache = new ThreadLocal<Map<String,Collection<Integer>>>();
 
-    private final ThreadLocal<Map<String, Collection<Integer>>> periodBetweenCache = new ThreadLocal<Map<String,Collection<Integer>>>();
+    private final ThreadLocal<Map<String, Collection<Integer>>> periodBetweenDatesCache = new ThreadLocal<Map<String,Collection<Integer>>>();
+
+    private final ThreadLocal<Map<String, Collection<Integer>>> periodBetweenDatesPeriodTypeCache = new ThreadLocal<Map<String,Collection<Integer>>>();
 
     private final ThreadLocal<Map<String, Period>> periodCache = new ThreadLocal<Map<String,Period>>();
 
@@ -107,7 +110,7 @@
     {
         final String key = startDate.toString() + SEPARATOR + endDate.toString();
         
-        Map<String, Collection<Integer>> cache = periodBetweenCache.get();
+        Map<String, Collection<Integer>> cache = periodBetweenDatesCache.get();
         
         Collection<Integer> periods = null;
         
@@ -122,11 +125,35 @@
         
         cache.put( key, periods );
         
-        periodBetweenCache.set( cache );
-        
-        return periods;
-    }
-        
+        periodBetweenDatesCache.set( cache );
+        
+        return periods;
+    }
+
+    public Collection<Integer> getPeriodsBetweenDatesPeriodType( final PeriodType periodType, final Date startDate, final Date endDate )
+    {
+        final String key = periodType.getName() + SEPARATOR + startDate.toString() + SEPARATOR + endDate.toString();
+        
+        Map<String, Collection<Integer>> cache = periodBetweenDatesPeriodTypeCache.get();
+        
+        Collection<Integer> periods = null;
+        
+        if ( cache != null && ( periods = cache.get( key ) ) != null )
+        {
+            return periods;
+        }
+        
+        periods = ConversionUtils.getIdentifiers( Period.class, periodService.getPeriodsBetweenDates( periodType, startDate, endDate ) );
+        
+        cache = ( cache == null ) ? new HashMap<String, Collection<Integer>>() : cache;
+        
+        cache.put( key, periods );
+        
+        periodBetweenDatesPeriodTypeCache.set( cache );
+        
+        return periods;
+    }
+    
     public Period getPeriod( final int id )
     {
         final String key = String.valueOf( id );
@@ -178,7 +205,8 @@
     public void clearCache()
     {
         intersectingPeriodCache.remove();
-        periodBetweenCache.remove();
+        periodBetweenDatesCache.remove();
+        periodBetweenDatesPeriodTypeCache.remove();
         periodCache.remove();
         organisationUnitLevelCache.remove();
     }

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/AbstractDataSetCompletenessService.java'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/AbstractDataSetCompletenessService.java	2012-02-02 20:01:36 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/AbstractDataSetCompletenessService.java	2012-03-15 16:04:20 +0000
@@ -29,6 +29,7 @@
 
 import static org.hisp.dhis.setting.SystemSettingManager.DEFAULT_COMPLETENESS_OFFSET;
 import static org.hisp.dhis.setting.SystemSettingManager.KEY_COMPLETENESS_OFFSET;
+import static org.hisp.dhis.system.util.ConversionUtils.*;
 
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -44,6 +45,7 @@
 import org.hisp.dhis.completeness.DataSetCompletenessService;
 import org.hisp.dhis.completeness.DataSetCompletenessStore;
 import org.hisp.dhis.dataelement.DataElementService;
+import org.hisp.dhis.datamart.aggregation.cache.AggregationCache;
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.dataset.DataSetService;
 import org.hisp.dhis.jdbc.batchhandler.DataSetCompletenessResultBatchHandler;
@@ -78,6 +80,13 @@
         this.batchHandlerFactory = batchHandlerFactory;
     }
 
+    private AggregationCache aggregationCache;
+
+    public void setAggregationCache( AggregationCache aggregationCache )
+    {
+        this.aggregationCache = aggregationCache;
+    }
+
     protected OrganisationUnitService organisationUnitService;
 
     public void setOrganisationUnitService( OrganisationUnitService organisationUnitService )
@@ -119,7 +128,7 @@
     {
         this.systemSettingManager = systemSettingManager;
     }
-
+    
     // -------------------------------------------------------------------------
     // DataSetCompletenessService implementation
     // -------------------------------------------------------------------------
@@ -128,12 +137,12 @@
     // Abstract methods
     // -------------------------------------------------------------------------
 
-    public abstract int getRegistrations( DataSet dataSet, Collection<Integer> relevantSources, Period period );
+    public abstract int getRegistrations( DataSet dataSet, Collection<Integer> relevantSources, Collection<Integer> periods );
 
-    public abstract int getRegistrationsOnTime( DataSet dataSet, Collection<Integer> relevantSources, Period period,
+    public abstract int getRegistrationsOnTime( DataSet dataSet, Collection<Integer> relevantSources, Collection<Integer> periods,
         Date deadline );
 
-    public abstract int getSources( DataSet dataSet, Collection<Integer> relevantSources );
+    public abstract int getSources( DataSet dataSet, Collection<Integer> relevantSources, Collection<Integer> periods );
 
     // -------------------------------------------------------------------------
     // DataSetCompleteness
@@ -176,16 +185,15 @@
         Collection<OrganisationUnit> units = organisationUnitService.getOrganisationUnits( organisationUnitIds );
         Collection<DataSet> dataSets = dataSetService.getDataSets( dataSetIds );
 
-        periods = completenessStore.getPeriodsWithRegistrations( periods );
         dataSets = completenessStore.getDataSetsWithRegistrations( dataSets );
 
         OrganisationUnitHierarchy hierarchy = organisationUnitService.getOrganisationUnitHierarchy();
         hierarchy.prepareChildren( units );
-
-        // TODO Re-implement period aggregation with sql to improve performance
-
+        
         for ( final DataSet dataSet : dataSets )
         {
+            int dataSetFrequencyOrder = dataSet.getPeriodType().getFrequencyOrder();
+                
             for ( final OrganisationUnit unit : units )
             {
                 Collection<Integer> sources = hierarchy.getChildren( unit.getId() );
@@ -194,13 +202,15 @@
 
                 for ( final Period period : periods )
                 {
-                    if ( period.getPeriodType() != null && dataSet.getPeriodType() != null
-                        && period.getPeriodType().equals( dataSet.getPeriodType() ) )
+                    if ( period.getPeriodType() != null && period.getPeriodType().getFrequencyOrder() >= dataSetFrequencyOrder )
                     {
                         final Date deadline = getDeadline( period, days );
 
-                        final DataSetCompletenessResult result = getDataSetCompleteness( period, deadline, unit,
-                            relevantSources, dataSet );
+                        final Collection<Integer> periodsBetweenDates = 
+                            aggregationCache.getPeriodsBetweenDatesPeriodType( dataSet.getPeriodType(), period.getStartDate(), period.getEndDate() );
+                        
+                        final DataSetCompletenessResult result = getDataSetCompleteness( period, 
+                            periodsBetweenDates, deadline, unit, relevantSources, dataSet );
 
                         if ( result.getSources() > 0 )
                         {
@@ -215,6 +225,8 @@
 
         batchHandler.flush();
 
+        aggregationCache.clearCache();
+        
         completenessStore.createIndex();
 
         log.info( "Created index" );
@@ -239,18 +251,21 @@
 
         for ( final DataSet dataSet : dataSets )
         {
+            final Collection<Integer> periodsBetweenDates = getIdentifiers( Period.class, 
+                periodService.getPeriodsBetweenDates( dataSet.getPeriodType(), period.getStartDate(), period.getEndDate() ) );
+
             final Collection<Integer> relevantSources = getRelevantSources( dataSet, children );
 
             final DataSetCompletenessResult result = new DataSetCompletenessResult();
 
-            result.setSources( getSources( dataSet, relevantSources ) );
+            result.setSources( getSources( dataSet, relevantSources, periodsBetweenDates ) );
 
             if ( result.getSources() > 0 )
             {
                 result.setName( dataSet.getName() );
-                result.setRegistrations( getRegistrations( dataSet, relevantSources, period ) );
+                result.setRegistrations( getRegistrations( dataSet, relevantSources, periodsBetweenDates ) );
                 result.setRegistrationsOnTime( deadline != null ? getRegistrationsOnTime( dataSet, relevantSources,
-                    period, deadline ) : 0 );
+                    periodsBetweenDates, deadline ) : 0 );
 
                 result.setDataSetId( dataSet.getId() );
                 result.setPeriodId( periodId );
@@ -266,14 +281,16 @@
     public Collection<DataSetCompletenessResult> getDataSetCompleteness( int periodId,
         Collection<Integer> organisationUnitIds, int dataSetId )
     {
-        final Period period = periodService.getPeriod( periodId );
-
-        int days = (Integer) systemSettingManager.getSystemSetting( KEY_COMPLETENESS_OFFSET,
-            DEFAULT_COMPLETENESS_OFFSET );
-        Date deadline = getDeadline( period, days );
-
         final DataSet dataSet = dataSetService.getDataSet( dataSetId );
 
+        final Period period = periodService.getPeriod( periodId );
+        
+        final Collection<Integer> periodsBetweenDates = getIdentifiers( Period.class, periodService.getPeriodsBetweenDates( dataSet.getPeriodType(), period.getStartDate(), period.getEndDate() ) );
+
+        int days = (Integer) systemSettingManager.getSystemSetting( KEY_COMPLETENESS_OFFSET,
+            DEFAULT_COMPLETENESS_OFFSET );
+        Date deadline = getDeadline( period, days );
+
         final Collection<DataSetCompletenessResult> results = new ArrayList<DataSetCompletenessResult>();
 
         for ( final Integer unitId : organisationUnitIds )
@@ -285,7 +302,7 @@
 
             final Collection<Integer> relevantSources = getRelevantSources( dataSet, children );
 
-            final DataSetCompletenessResult result = getDataSetCompleteness( period, deadline, unit, relevantSources, dataSet );
+            final DataSetCompletenessResult result = getDataSetCompleteness( period, periodsBetweenDates, deadline, unit, relevantSources, dataSet );
 
             if ( result.getSources() > 0 )
             {
@@ -319,18 +336,18 @@
     // Supportive methods
     // -------------------------------------------------------------------------
 
-    private DataSetCompletenessResult getDataSetCompleteness( Period period, Date deadline, OrganisationUnit unit,
+    private DataSetCompletenessResult getDataSetCompleteness( Period period, Collection<Integer> periodsBetweenDates, Date deadline, OrganisationUnit unit,
         Collection<Integer> relevantSources, DataSet dataSet )
     {
         final DataSetCompletenessResult result = new DataSetCompletenessResult();
 
         result.setName( unit.getName() );
-        result.setSources( getSources( dataSet, relevantSources ) );
+        result.setSources( getSources( dataSet, relevantSources, periodsBetweenDates ) );
 
         if ( result.getSources() > 0 )
         {
-            result.setRegistrations( getRegistrations( dataSet, relevantSources, period ) );
-            result.setRegistrationsOnTime( deadline != null ? getRegistrationsOnTime( dataSet, relevantSources, period,
+            result.setRegistrations( getRegistrations( dataSet, relevantSources, periodsBetweenDates ) );
+            result.setRegistrationsOnTime( deadline != null ? getRegistrationsOnTime( dataSet, relevantSources, periodsBetweenDates,
                 deadline ) : 0 );
 
             result.setDataSetId( dataSet.getId() );

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/CompulsoryDataSetCompletenessService.java'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/CompulsoryDataSetCompletenessService.java	2012-03-15 12:47:27 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/CompulsoryDataSetCompletenessService.java	2012-03-15 16:04:20 +0000
@@ -31,26 +31,28 @@
 import java.util.Date;
 
 import org.hisp.dhis.dataset.DataSet;
-import org.hisp.dhis.period.Period;
 
 /**
  * @author Lars Helge Overland
  */
 public class CompulsoryDataSetCompletenessService
     extends AbstractDataSetCompletenessService
-{    
-    public int getRegistrations( DataSet dataSet, Collection<Integer> relevantSources, Period period )
-    {
-        return completenessStore.getCompulsoryDataElementRegistrations( dataSet, relevantSources, period );
-    }
-
-    public int getRegistrationsOnTime( DataSet dataSet, Collection<Integer> relevantSources, Period period, Date deadline )
-    {
-        return completenessStore.getCompulsoryDataElementRegistrations( dataSet, relevantSources, period, deadline );
-    }
-    
-    public int getSources( DataSet dataSet, Collection<Integer> relevantSources )
-    {
-        return relevantSources.size();
+{
+    @Override
+    public int getRegistrations( DataSet dataSet, Collection<Integer> relevantSources, Collection<Integer> periods )
+    {
+        return completenessStore.getCompulsoryDataElementRegistrations( dataSet, relevantSources, periods );
+    }
+
+    @Override
+    public int getRegistrationsOnTime( DataSet dataSet, Collection<Integer> relevantSources, Collection<Integer> periods, Date deadline )
+    {
+        return completenessStore.getCompulsoryDataElementRegistrations( dataSet, relevantSources, periods, deadline );
+    }
+
+    @Override
+    public int getSources( DataSet dataSet, Collection<Integer> relevantSources, Collection<Integer> periods )
+    {
+        return relevantSources.size() * periods.size();
     }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/RatioDataSetCompletenessService.java'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/RatioDataSetCompletenessService.java	2011-12-26 10:07:59 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/RatioDataSetCompletenessService.java	2012-03-15 16:04:20 +0000
@@ -32,7 +32,6 @@
 
 import org.hisp.dhis.dataelement.DataElementOperand;
 import org.hisp.dhis.dataset.DataSet;
-import org.hisp.dhis.period.Period;
 
 /**
  * @author Lars Helge Overland
@@ -41,20 +40,25 @@
 public class RatioDataSetCompletenessService
     extends AbstractDataSetCompletenessService
 {
-    public int getRegistrations( DataSet dataSet, Collection<Integer> relevantSources, Period period )
-    {
-        return completenessStore.getNumberOfValues( dataSet, relevantSources, period, null );
-    }
-
-    public int getRegistrationsOnTime( DataSet dataSet, Collection<Integer> relevantSources, Period period, Date deadline )
-    {
-        return completenessStore.getNumberOfValues( dataSet, relevantSources, period, null );
-    }
-    
-    public int getSources( DataSet dataSet, Collection<Integer> relevantSources )
+    @Override
+    public int getRegistrations( DataSet dataSet, Collection<Integer> relevantSources, Collection<Integer> periods )
+    {
+        return completenessStore.getNumberOfValues( dataSet, relevantSources, periods, null );
+    }
+
+    @Override
+    public int getRegistrationsOnTime( DataSet dataSet, Collection<Integer> relevantSources, Collection<Integer> periods, Date deadline )
+    {
+        return completenessStore.getNumberOfValues( dataSet, relevantSources, periods, null );
+    }
+
+    @Override
+    public int getSources( DataSet dataSet, Collection<Integer> relevantSources, Collection<Integer> periods )
     {
         Collection<DataElementOperand> operands = dataElementService.getAllGeneratedOperands( dataSet.getDataElements() );
         
-        return operands != null && relevantSources != null ? operands.size() * relevantSources.size() : 0; // Number of operands in data set times number of organisation units
+        // Number of operands in data set times number of organisation units times number of periods
+        
+        return operands != null && relevantSources != null ? ( operands.size() * relevantSources.size() * periods.size() ) : 0; 
     }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/RegistrationDataSetCompletenessService.java'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/RegistrationDataSetCompletenessService.java	2011-12-26 10:07:59 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/impl/RegistrationDataSetCompletenessService.java	2012-03-15 16:04:20 +0000
@@ -31,7 +31,6 @@
 import java.util.Date;
 
 import org.hisp.dhis.dataset.DataSet;
-import org.hisp.dhis.period.Period;
 
 /**
  * @author Lars Helge Overland
@@ -39,18 +38,21 @@
 public class RegistrationDataSetCompletenessService
     extends AbstractDataSetCompletenessService
 {
-    public int getRegistrations( DataSet dataSet, Collection<Integer> relevantSources, Period period )
-    {
-        return completenessStore.getCompleteDataSetRegistrations( dataSet, period, relevantSources );
-    }
-
-    public int getRegistrationsOnTime( DataSet dataSet, Collection<Integer> relevantSources, Period period, Date deadline )
-    {
-        return completenessStore.getCompleteDataSetRegistrations( dataSet, period, relevantSources, deadline );
-    }
-    
-    public int getSources( DataSet dataSet, Collection<Integer> relevantSources )
-    {
-        return relevantSources.size();
+    @Override
+    public int getRegistrations( DataSet dataSet, Collection<Integer> relevantSources, Collection<Integer> periods )
+    {
+        return completenessStore.getCompleteDataSetRegistrations( dataSet, periods, relevantSources );
+    }
+
+    @Override
+    public int getRegistrationsOnTime( DataSet dataSet, Collection<Integer> relevantSources, Collection<Integer> periods, Date deadline )
+    {
+        return completenessStore.getCompleteDataSetRegistrations( dataSet, periods, relevantSources, deadline );
+    }
+
+    @Override
+    public int getSources( DataSet dataSet, Collection<Integer> relevantSources, Collection<Integer> periods )
+    {
+        return relevantSources.size() * periods.size();
     }
 }

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/jdbc/JDBCDataSetCompletenessStore.java'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/jdbc/JDBCDataSetCompletenessStore.java	2012-03-15 12:47:27 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/java/org/hisp/dhis/completeness/jdbc/JDBCDataSetCompletenessStore.java	2012-03-15 16:04:20 +0000
@@ -71,7 +71,7 @@
     // Based on complete data set registrations
     // -------------------------------------------------------------------------
 
-    public int getCompleteDataSetRegistrations( DataSet dataSet, Period period, Collection<Integer> relevantSources )
+    public Integer getCompleteDataSetRegistrations( DataSet dataSet, Collection<Integer> periods, Collection<Integer> relevantSources )
     {
         if ( relevantSources == null || relevantSources.size() == 0 )
         {
@@ -82,13 +82,13 @@
             "SELECT COUNT(*) " +
             "FROM completedatasetregistration " +
             "WHERE datasetid = " + dataSet.getId() + " " +
-            "AND periodid = " + period.getId() + " " +
+            "AND periodid IN ( " + getCommaDelimitedString( periods ) + " ) " +
             "AND sourceid IN ( " + getCommaDelimitedString( relevantSources ) + " )";
         
         return statementManager.getHolder().queryForInteger( sql );
     }
 
-    public int getCompleteDataSetRegistrations( DataSet dataSet, Period period, Collection<Integer> relevantSources, Date deadline )
+    public Integer getCompleteDataSetRegistrations( DataSet dataSet, Collection<Integer> periods, Collection<Integer> relevantSources, Date deadline )
     {
         if ( relevantSources == null || relevantSources.size() == 0 )
         {
@@ -99,7 +99,7 @@
             "SELECT COUNT(*) " +
             "FROM completedatasetregistration " +
             "WHERE datasetid = " + dataSet.getId() + " " +
-            "AND periodid = " + period.getId() + " " +
+            "AND periodid IN ( " + getCommaDelimitedString( periods ) + " ) " +
             "AND sourceid IN ( " + getCommaDelimitedString( relevantSources ) + " ) " +
             "AND date <= '" + getMediumDateString( deadline ) + "'";
         
@@ -110,15 +110,14 @@
     // Based on compulsory data element operands
     // -------------------------------------------------------------------------
 
-    public int getCompulsoryDataElementRegistrations( DataSet dataSet, Collection<Integer> children, Period period )
+    public Integer getCompulsoryDataElementRegistrations( DataSet dataSet, Collection<Integer> children, Collection<Integer> periods )
     {
-        return getCompulsoryDataElementRegistrations( dataSet, children, period, null );
+        return getCompulsoryDataElementRegistrations( dataSet, children, periods, null );
     }
     
-    public int getCompulsoryDataElementRegistrations( DataSet dataSet, Collection<Integer> children, Period period, Date deadline )
+    public Integer getCompulsoryDataElementRegistrations( DataSet dataSet, Collection<Integer> children, Collection<Integer> periods, Date deadline )
     {           
-        final int compulsoryElements = dataSet.getCompulsoryDataElementOperands().size();        
-        final String childrenIds = TextUtils.getCommaDelimitedString( children );
+        final int compulsoryElements = dataSet.getCompulsoryDataElementOperands().size();
         final String deadlineCriteria = deadline != null ? "AND lastupdated < '" + DateUtils.getMediumDateString( deadline ) + "' " : "";
         
         final String sql = 
@@ -129,8 +128,8 @@
                 "ON dv.dataelementid=deo.dataelementid AND dv.categoryoptioncomboid=deo.categoryoptioncomboid " +
                 "JOIN datasetoperands dso " +
                 "ON deo.dataelementoperandid=dso.dataelementoperandid " +
-                "WHERE periodid = " + period.getId() + " " + deadlineCriteria +
-                "AND sourceid IN (" + childrenIds + ") " +
+                "WHERE periodid IN ( " + getCommaDelimitedString( periods ) + " ) " + deadlineCriteria +
+                "AND sourceid IN ( " + getCommaDelimitedString( children ) + " ) " +
                 "AND datasetid = " + dataSet.getId() + " GROUP BY sourceid) AS completed " +
             "WHERE completed.sources = " + compulsoryElements;
         
@@ -141,7 +140,7 @@
     // Based on number of data values
     // -------------------------------------------------------------------------
 
-    public int getNumberOfValues( DataSet dataSet, Collection<Integer> children, Period period, Date deadline )
+    public Integer getNumberOfValues( DataSet dataSet, Collection<Integer> children, Collection<Integer> periods, Date deadline )
     {
         final String childrenIds = TextUtils.getCommaDelimitedString( children );
         final String deadlineCriteria = deadline != null ? "AND lastupdated < '" + DateUtils.getMediumDateString( deadline ) + "' " : "";
@@ -151,7 +150,7 @@
             "JOIN datasetmembers dsm ON dv.dataelementid=dsm.dataelementid " +
             "JOIN dataset ds ON dsm.datasetid=ds.datasetid " +
             "WHERE ds.datasetid = " + dataSet.getId() + " " + deadlineCriteria +
-            "AND periodid = " + period.getId() + " " +
+            "AND periodid IN ( " + getCommaDelimitedString( periods ) + " ) " +
             "AND sourceid IN (" + childrenIds + ")";
 
         return statementManager.getHolder().queryForInteger( sql );
@@ -174,28 +173,11 @@
         return selection;
     }
 
-    public Collection<Period> getPeriodsWithRegistrations( Collection<Period> periods )
-    {
-        Collection<Period> selection = new ArrayList<Period>();
-        
-        for ( Period period : periods )
-        {
-            final String sql = "SELECT count(*) FROM completedatasetregistration WHERE periodid = " + period.getId();
-            
-            if ( statementManager.getHolder().queryForInteger( sql ) > 0 )
-            {
-                selection.add( period );
-            }
-        }
-        
-        return selection;
-    }
-
     // -------------------------------------------------------------------------
     // Aggregated data set completeness methods
     // -------------------------------------------------------------------------
 
-    public double getPercentage( int dataSetId, int periodId, int organisationUnitId )
+    public Double getPercentage( int dataSetId, int periodId, int organisationUnitId )
     {
         final String sql =
             "SELECT value " +

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/resources/META-INF/dhis/beans.xml	2012-03-05 16:37:17 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/resources/META-INF/dhis/beans.xml	2012-03-15 16:04:20 +0000
@@ -100,6 +100,7 @@
 
   <bean id="compulsoryDataCompletenessService" class="org.hisp.dhis.completeness.impl.CompulsoryDataSetCompletenessService">
     <property name="batchHandlerFactory" ref="batchHandlerFactory" />
+	<property name="aggregationCache" ref="org.hisp.dhis.datamart.aggregation.cache.AggregationCache" />
     <property name="organisationUnitService" ref="org.hisp.dhis.organisationunit.OrganisationUnitService" />
     <property name="dataSetService" ref="org.hisp.dhis.dataset.DataSetService" />
     <property name="dataElementService" ref="org.hisp.dhis.dataelement.DataElementService" />

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/completeness/DataSetCompletenessServiceExportTest.java'
--- dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/completeness/DataSetCompletenessServiceExportTest.java	2011-12-26 10:07:59 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/test/java/org/hisp/dhis/completeness/DataSetCompletenessServiceExportTest.java	2012-03-15 16:04:20 +0000
@@ -67,6 +67,7 @@
     private Period periodA;
     private Period periodB;
     private Period periodC;
+    private Period periodD;
     
     private OrganisationUnit unitA;
     private OrganisationUnit unitB;
@@ -78,8 +79,6 @@
     private Collection<Period> periods;
     private Collection<OrganisationUnit> units;
     
-    private ReportTable reportTable;
-    
     @Override
     public void setUpTest()
     {
@@ -100,19 +99,22 @@
         units = new ArrayList<OrganisationUnit>();
         
         monthly = new MonthlyPeriodType();
-        quarterly = new QuarterlyPeriodType(); //TODO fix
+        quarterly = new QuarterlyPeriodType();
         
         periodA = createPeriod( monthly, getDate( 2000, 1, 1 ), getDate( 2000, 1, 31 ) );
         periodB = createPeriod( monthly, getDate( 2000, 2, 1 ), getDate( 2000, 2, 28 ) );
-        periodC = createPeriod( quarterly, getDate( 2000, 1, 1 ), getDate( 2000, 2, 28 ) );
+        periodC = createPeriod( monthly, getDate( 2000, 3, 1 ), getDate( 2000, 3, 31 ) );
+        periodD = createPeriod( quarterly, getDate( 2000, 1, 1 ), getDate( 2000, 3, 31 ) );
         
         periodService.addPeriod( periodA );
         periodService.addPeriod( periodB );
         periodService.addPeriod( periodC );
+        periodService.addPeriod( periodD );
         
         periods.add( periodA );
         periods.add( periodB );
         periods.add( periodC );
+        periods.add( periodD );
         
         unitA = createOrganisationUnit( 'A' );
         unitB = createOrganisationUnit( 'B' );
@@ -141,9 +143,6 @@
         dataSetService.addDataSet( dataSetA );
         
         dataSets.add( dataSetA );
-        
-        reportTable = new ReportTable();
-        reportTable.setId( 1 );
     }
     
     @Override
@@ -159,6 +158,8 @@
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodA, unitC, null, "" ) );
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitB, null, "" ) );
         registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodB, unitA, null, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodC, unitA, null, "" ) );
+        registrationService.saveCompleteDataSetRegistration( new CompleteDataSetRegistration( dataSetA, periodC, unitC, null, "" ) );
         
         completenessService.exportDataSetCompleteness( getIdentifiers( DataSet.class, dataSets ),
             getIdentifiers( Period.class, periods ), getIdentifiers( OrganisationUnit.class, units ) );
@@ -170,5 +171,13 @@
         assertEquals( 100.0, completenessStore.getPercentage( dataSetA.getId(), periodB.getId(), unitB.getId() ) );
         assertEquals( 0.0, completenessStore.getPercentage( dataSetA.getId(), periodB.getId(), unitC.getId() ) );
         assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodB.getId(), unitA.getId() ) );
+
+        assertEquals( 0.0, completenessStore.getPercentage( dataSetA.getId(), periodC.getId(), unitB.getId() ) );
+        assertEquals( 100.0, completenessStore.getPercentage( dataSetA.getId(), periodC.getId(), unitC.getId() ) );
+        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodC.getId(), unitA.getId() ) );
+        
+        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodD.getId(), unitB.getId() ) );
+        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodD.getId(), unitC.getId() ) );
+        assertEquals( 66.7, completenessStore.getPercentage( dataSetA.getId(), periodD.getId(), unitA.getId() ) );
     }
 }