=== added file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryPlanner.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryPlanner.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryPlanner.java 2013-09-29 15:41:22 +0000 @@ -0,0 +1,45 @@ +package org.hisp.dhis.analytics.event; + +/* + * Copyright (c) 2004-2013, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.util.List; + +import org.hisp.dhis.analytics.IllegalQueryException; + +/** + * @author Lars Helge Overland + */ +public interface EventQueryPlanner +{ + void validate( EventQueryParams params ) + throws IllegalQueryException; + + List planQuery( EventQueryParams params ); + +} === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsService.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsService.java 2013-09-28 16:27:09 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsService.java 2013-09-29 15:41:22 +0000 @@ -44,6 +44,7 @@ import org.hisp.dhis.analytics.event.EventAnalyticsManager; import org.hisp.dhis.analytics.event.EventAnalyticsService; import org.hisp.dhis.analytics.event.EventQueryParams; +import org.hisp.dhis.analytics.event.EventQueryPlanner; import org.hisp.dhis.analytics.event.QueryItem; import org.hisp.dhis.common.BaseIdentifiableObject; import org.hisp.dhis.common.Grid; @@ -104,6 +105,9 @@ private EventAnalyticsManager analyticsManager; @Autowired + private EventQueryPlanner queryPlanner; + + @Autowired private AnalyticsService analyticsService; // ------------------------------------------------------------------------- @@ -116,7 +120,7 @@ public Grid getAggregatedEventData( EventQueryParams params ) { - EventQueryPlanner.validate( params ); + queryPlanner.validate( params ); Grid grid = new ListGrid(); @@ -139,7 +143,7 @@ //TODO relative periods - List queries = EventQueryPlanner.planQuery( params ); + List queries = queryPlanner.planQuery( params ); for ( EventQueryParams query : queries ) { @@ -159,7 +163,7 @@ public Grid getEvents( EventQueryParams params ) { - EventQueryPlanner.validate( params ); + queryPlanner.validate( params ); Grid grid = new ListGrid(); @@ -187,7 +191,7 @@ Timer t = new Timer().start(); - List queries = EventQueryPlanner.planQuery( params ); + List queries = queryPlanner.planQuery( params ); t.getSplitTime( "Planned query, got: " + queries.size() ); === added file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventQueryPlanner.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventQueryPlanner.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventQueryPlanner.java 2013-09-29 15:41:22 +0000 @@ -0,0 +1,192 @@ +package org.hisp.dhis.analytics.event.data; + +/* + * Copyright (c) 2004-2013, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hisp.dhis.analytics.IllegalQueryException; +import org.hisp.dhis.analytics.event.EventQueryParams; +import org.hisp.dhis.analytics.event.EventQueryPlanner; +import org.hisp.dhis.common.ListMap; +import org.hisp.dhis.organisationunit.OrganisationUnit; +import org.hisp.dhis.period.Cal; +import org.hisp.dhis.program.Program; + +/** + * @author Lars Helge Overland + */ +public class DefaultEventQueryPlanner + implements EventQueryPlanner +{ + private static final Log log = LogFactory.getLog( DefaultEventQueryPlanner.class ); + + private static final String TABLE_BASE_NAME = "analytics_event_"; + + public void validate( EventQueryParams params ) + throws IllegalQueryException + { + String violation = null; + + if ( params == null ) + { + throw new IllegalQueryException( "Params cannot be null" ); + } + + if ( params.getOrganisationUnits().isEmpty() ) + { + violation = "At least one organisation unit must be specified"; + } + + if ( params.getPeriods() == null && ( params.getStartDate() == null || params.getEndDate() == null ) ) + { + violation = "Start and end date or at least one period must be specified"; + } + + if ( params.getStartDate() != null && params.getEndDate() != null ) + { + if ( params.getStartDate().after( params.getEndDate() ) ) + { + throw new IllegalQueryException( "Start date is after end date: " + params.getStartDate() + " - " + params.getEndDate() ); + } + } + + if ( violation != null ) + { + log.warn( "Validation failed: " + violation ); + + throw new IllegalQueryException( violation ); + } + } + + public List planQuery( EventQueryParams params ) + { + List queries = new ArrayList(); + + List groupedByPartition = groupByPartition( params ); + + for ( EventQueryParams byPartition : groupedByPartition ) + { + queries.addAll( groupByOrgUnitLevel( byPartition ) ); + } + + return queries; + } + + private List groupByPartition( EventQueryParams params ) + { + List list = new ArrayList(); + + Program program = params.getProgram(); + + if ( params.hasStartEndDate() ) + { + Date startDate = params.getStartDate(); + Date endDate = params.getEndDate(); + + Date currentStartDate = startDate; + Date currentEndDate = endDate; + + while ( true ) + { + if ( year( currentStartDate ) < year( endDate ) ) // Spans multiple + { + // Set end date to max of current year + + currentEndDate = maxOfYear( currentStartDate ); + + list.add( getQuery( params, currentStartDate, currentEndDate, program ) ); + + // Set start date to start of next year + + currentStartDate = new Cal( ( year( currentStartDate ) + 1 ), 1, 1 ).time(); + } + else + { + list.add( getQuery( params, currentStartDate, endDate, program ) ); + + break; + } + } + } + else + { + //TODO implement properly + params.setTableName( TABLE_BASE_NAME + year( params.getPeriods().get( 0 ).getStartDate() ) + "_" + program.getUid() ); + params.setPeriodType( params.getPeriods().get( 0 ).getPeriodType().getName() ); + list.add( params ); + } + + return list; + } + + private List groupByOrgUnitLevel( EventQueryParams params ) + { + ListMap levelOrgUnitMap = new ListMap(); + + for ( OrganisationUnit unit : params.getOrganisationUnits() ) + { + levelOrgUnitMap.putValue( unit.getLevel(), unit ); + } + + List queries = new ArrayList(); + + for ( Integer level : levelOrgUnitMap.keySet() ) + { + EventQueryParams query = params.instance(); + query.setOrganisationUnits( levelOrgUnitMap.get( level ) ); + query.setOrganisationUnitLevel( level ); + queries.add( query ); + } + + return queries; + } + + private static EventQueryParams getQuery( EventQueryParams params, Date startDate, Date endDate, Program program ) + { + EventQueryParams query = params.instance(); + query.setStartDate( startDate ); + query.setEndDate( endDate ); + query.setTableName( TABLE_BASE_NAME + year( startDate ) + "_" + program.getUid() ); + return query; + } + + private static int year( Date date ) + { + return new Cal( date ).getYear(); + } + + private static Date maxOfYear( Date date ) + { + return new Cal( year( date ), 12, 31 ).time(); + } +} === removed file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EventQueryPlanner.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EventQueryPlanner.java 2013-09-29 15:30:34 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EventQueryPlanner.java 1970-01-01 00:00:00 +0000 @@ -1,190 +0,0 @@ -package org.hisp.dhis.analytics.event.data; - -/* - * Copyright (c) 2004-2013, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hisp.dhis.analytics.IllegalQueryException; -import org.hisp.dhis.analytics.event.EventQueryParams; -import org.hisp.dhis.common.ListMap; -import org.hisp.dhis.organisationunit.OrganisationUnit; -import org.hisp.dhis.period.Cal; -import org.hisp.dhis.program.Program; - -/** - * @author Lars Helge Overland - */ -public class EventQueryPlanner -{ - private static final Log log = LogFactory.getLog( EventQueryPlanner.class ); - - private static final String TABLE_BASE_NAME = "analytics_event_"; - - public static void validate( EventQueryParams params ) - throws IllegalQueryException - { - String violation = null; - - if ( params == null ) - { - throw new IllegalQueryException( "Params cannot be null" ); - } - - if ( params.getOrganisationUnits().isEmpty() ) - { - violation = "At least one organisation unit must be specified"; - } - - if ( params.getPeriods() == null && ( params.getStartDate() == null || params.getEndDate() == null ) ) - { - violation = "Start and end date or at least one period must be specified"; - } - - if ( params.getStartDate() != null && params.getEndDate() != null ) - { - if ( params.getStartDate().after( params.getEndDate() ) ) - { - throw new IllegalQueryException( "Start date is after end date: " + params.getStartDate() + " - " + params.getEndDate() ); - } - } - - if ( violation != null ) - { - log.warn( "Validation failed: " + violation ); - - throw new IllegalQueryException( violation ); - } - } - - public static List planQuery( EventQueryParams params ) - { - List queries = new ArrayList(); - - List groupedByPartition = groupByPartition( params ); - - for ( EventQueryParams byPartition : groupedByPartition ) - { - queries.addAll( groupByOrgUnitLevel( byPartition ) ); - } - - return queries; - } - - private static List groupByPartition( EventQueryParams params ) - { - List list = new ArrayList(); - - Program program = params.getProgram(); - - if ( params.hasStartEndDate() ) - { - Date startDate = params.getStartDate(); - Date endDate = params.getEndDate(); - - Date currentStartDate = startDate; - Date currentEndDate = endDate; - - while ( true ) - { - if ( year( currentStartDate ) < year( endDate ) ) // Spans multiple - { - // Set end date to max of current year - - currentEndDate = maxOfYear( currentStartDate ); - - list.add( getQuery( params, currentStartDate, currentEndDate, program ) ); - - // Set start date to start of next year - - currentStartDate = new Cal( ( year( currentStartDate ) + 1 ), 1, 1 ).time(); - } - else - { - list.add( getQuery( params, currentStartDate, endDate, program ) ); - - break; - } - } - } - else - { - //TODO implement properly - params.setTableName( TABLE_BASE_NAME + year( params.getPeriods().get( 0 ).getStartDate() ) + "_" + program.getUid() ); - params.setPeriodType( params.getPeriods().get( 0 ).getPeriodType().getName() ); - list.add( params ); - } - - return list; - } - - private static List groupByOrgUnitLevel( EventQueryParams params ) - { - ListMap levelOrgUnitMap = new ListMap(); - - for ( OrganisationUnit unit : params.getOrganisationUnits() ) - { - levelOrgUnitMap.putValue( unit.getLevel(), unit ); - } - - List queries = new ArrayList(); - - for ( Integer level : levelOrgUnitMap.keySet() ) - { - EventQueryParams query = params.instance(); - query.setOrganisationUnits( levelOrgUnitMap.get( level ) ); - query.setOrganisationUnitLevel( level ); - queries.add( query ); - } - - return queries; - } - - private static EventQueryParams getQuery( EventQueryParams params, Date startDate, Date endDate, Program program ) - { - EventQueryParams query = params.instance(); - query.setStartDate( startDate ); - query.setEndDate( endDate ); - query.setTableName( TABLE_BASE_NAME + year( startDate ) + "_" + program.getUid() ); - return query; - } - - private static int year( Date date ) - { - return new Cal( date ).getYear(); - } - - private static Date maxOfYear( Date date ) - { - return new Cal( year( date ), 12, 31 ).time(); - } -} === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/resources/META-INF/dhis/beans.xml' --- dhis-2/dhis-services/dhis-service-analytics/src/main/resources/META-INF/dhis/beans.xml 2013-08-21 18:09:08 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/resources/META-INF/dhis/beans.xml 2013-09-29 15:41:22 +0000 @@ -42,6 +42,8 @@ + + === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EventQueryPlannerTest.java' --- dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EventQueryPlannerTest.java 2013-09-28 15:06:20 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EventQueryPlannerTest.java 2013-09-29 15:41:22 +0000 @@ -33,26 +33,30 @@ import java.util.Arrays; import java.util.List; -import org.hisp.dhis.DhisConvenienceTest; +import org.hisp.dhis.DhisSpringTest; import org.hisp.dhis.analytics.event.EventQueryParams; +import org.hisp.dhis.analytics.event.EventQueryPlanner; import org.hisp.dhis.organisationunit.OrganisationUnit; import org.hisp.dhis.period.Cal; import org.hisp.dhis.program.Program; -import org.junit.Before; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; /** * @author Lars Helge Overland */ public class EventQueryPlannerTest - extends DhisConvenienceTest + extends DhisSpringTest { private Program prA; private OrganisationUnit ouA; private OrganisationUnit ouB; - @Before - public void before() + @Autowired + private EventQueryPlanner queryPlanner; + + @Override + public void setUpTest() { prA = new Program(); prA.setUid( "programuidA" ); @@ -73,7 +77,7 @@ params.setEndDate( new Cal( 2012, 3, 20 ).time() ); params.setOrganisationUnits( Arrays.asList( ouA ) ); - List queries = EventQueryPlanner.planQuery( params ); + List queries = queryPlanner.planQuery( params ); assertEquals( 3, queries.size() ); @@ -98,7 +102,7 @@ params.setEndDate( new Cal( 2010, 9, 20 ).time() ); params.setOrganisationUnits( Arrays.asList( ouA ) ); - List queries = EventQueryPlanner.planQuery( params ); + List queries = queryPlanner.planQuery( params ); assertEquals( 1, queries.size() ); @@ -117,7 +121,7 @@ params.setEndDate( new Cal( 2012, 3, 20 ).time() ); params.setOrganisationUnits( Arrays.asList( ouA, ouB ) ); - List queries = EventQueryPlanner.planQuery( params ); + List queries = queryPlanner.planQuery( params ); assertEquals( 6, queries.size() ); }