=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/PeriodType.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/PeriodType.java 2014-10-24 11:45:30 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/PeriodType.java 2014-10-24 12:15:42 +0000 @@ -247,7 +247,6 @@ { return periodCache.get( getCacheKey( date ), new Callable() { - @Override public Period call() throws Exception { return createPeriod( createCalendarInstance( date ) ); @@ -284,7 +283,6 @@ { return periodCache.get( getCacheKey( calendar, date ), new Callable() { - @Override public Period call() throws Exception { return createPeriod( calendar.fromIso( DateTimeUnit.fromJdkDate( date ) ), calendar ); === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalStore.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalStore.java 2014-10-24 11:45:30 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalStore.java 2014-10-24 12:15:42 +0000 @@ -32,6 +32,9 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import org.hibernate.Criteria; import org.hibernate.criterion.Restrictions; @@ -53,6 +56,9 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.rowset.SqlRowSet; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + /** * @author Jim Grace */ @@ -60,6 +66,18 @@ extends HibernateGenericStore implements DataApprovalStore { + private static Cache PERIOD_CACHE = CacheBuilder.newBuilder() + .expireAfterAccess( 10, TimeUnit.MINUTES ).initialCapacity( 1000 ) + .maximumSize( 2000 ).build(); + + private static Cache OPTION_COMBO_CACHE = CacheBuilder.newBuilder() + .expireAfterAccess( 10, TimeUnit.MINUTES ).initialCapacity( 10000 ) + .maximumSize( 50000 ).build(); + + private static Cache ORGANISATION_UNIT_CACHE = CacheBuilder.newBuilder() + .expireAfterAccess( 10, TimeUnit.MINUTES ).initialCapacity( 10000 ) + .maximumSize( 50000 ).build(); + // ------------------------------------------------------------------------- // Dependencies // ------------------------------------------------------------------------- @@ -248,44 +266,72 @@ Set userDataApprovals = new HashSet<>(); - while ( rowSet.next() ) - { - Integer attributeOptionComboId = rowSet.getInt( 1 ); - Integer periodId = rowSet.getInt( 2 ); - Integer level = rowSet.getInt( 3 ); - Integer orgUnitId = rowSet.getInt( 4 ); - Boolean accepted = rowSet.getBoolean( 5 ); - - if ( attributeOptionComboId == previousAttributeOptionComboId && periodId == previousPeriodId && level > previousLevel ) - { - continue; - } - - previousAttributeOptionComboId = attributeOptionComboId; - previousPeriodId = periodId; - previousLevel = level; - - DataElementCategoryOptionCombo attributeOptionCombo = categoryService.getDataElementCategoryOptionCombo( attributeOptionComboId ); - Period period = periodService.getPeriod( periodId ); - DataApprovalLevel dataApprovalLevel = ( level == null ? null : levelMap.get( level ) ); - OrganisationUnit orgUnit = ( orgUnitId == null ? null : organisationUnitService.getOrganisationUnit( orgUnitId ) ); - - //TODO: currently special cased for PEFPAR's requirements. Can we make it more generic? - if ( level > 1 && attributeOptionCombo.equals( defaultOptionCombo ) ) - { - for ( OrganisationUnit ou : getUserOrgsAtLevel( 3 ) ) - { - DataApproval da = new DataApproval( dataApprovalLevel, null, period, ou, attributeOptionCombo, accepted, null, null ); - - userDataApprovals.add( da ); - } - - continue; - } - - DataApproval da = new DataApproval( dataApprovalLevel, null, period, orgUnit, attributeOptionCombo, accepted, null, null ); - - userDataApprovals.add( da ); + try + { + while ( rowSet.next() ) + { + final Integer aoc = rowSet.getInt( 1 ); + final Integer pe = rowSet.getInt( 2 ); + final Integer level = rowSet.getInt( 3 ); + final Integer ou = rowSet.getInt( 4 ); + final Boolean accepted = rowSet.getBoolean( 5 ); + + if ( aoc == previousAttributeOptionComboId && pe == previousPeriodId && level > previousLevel ) + { + continue; + } + + previousAttributeOptionComboId = aoc; + previousPeriodId = pe; + previousLevel = level; + + DataApprovalLevel dataApprovalLevel = ( level == null ? null : levelMap.get( level ) ); + + DataElementCategoryOptionCombo optionCombo = ( aoc == null || aoc == 0 ? null : OPTION_COMBO_CACHE.get( aoc, new Callable() + { + public DataElementCategoryOptionCombo call() throws ExecutionException + { + return categoryService.getDataElementCategoryOptionCombo( aoc ); + } + } ) ); + + Period period = ( pe == null || pe == 0 ? null : PERIOD_CACHE.get( pe, new Callable() + { + public Period call() throws ExecutionException + { + return periodService.getPeriod( pe ); + } + } ) ); + + OrganisationUnit orgUnit = ( ou == null || ou == 0 ? null : ORGANISATION_UNIT_CACHE.get( ou, new Callable() + { + public OrganisationUnit call() throws ExecutionException + { + return organisationUnitService.getOrganisationUnit( ou ); + } + } ) ); + + //TODO: currently special cased for PEFPAR's requirements. Can we make it more generic? + if ( level > 1 && optionCombo.equals( defaultOptionCombo ) ) + { + for ( OrganisationUnit unit : getUserOrgsAtLevel( 3 ) ) + { + DataApproval da = new DataApproval( dataApprovalLevel, null, period, unit, optionCombo, accepted, null, null ); + + userDataApprovals.add( da ); + } + + continue; + } + + DataApproval da = new DataApproval( dataApprovalLevel, null, period, orgUnit, optionCombo, accepted, null, null ); + + userDataApprovals.add( da ); + } + } + catch ( ExecutionException ex ) + { + throw new RuntimeException( ex ); } return userDataApprovals;