=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/Cal.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/Cal.java 2013-03-04 14:44:15 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/Cal.java 2013-08-21 18:09:08 +0000 @@ -55,6 +55,16 @@ calendar.clear(); set( year, month, day ); } + + /** + * @param date the date. + */ + public Cal( Date date ) + { + calendar = new GregorianCalendar(); + calendar.clear(); + calendar.setTime( date ); + } /** * Sets the time of the calendar to now. === 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-08-17 09:24:30 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/DataQueryParams.java 2013-08-21 18:09:08 +0000 @@ -88,9 +88,9 @@ public static final String DISPLAY_NAME_PERIOD = "Period"; public static final String DISPLAY_NAME_ORGUNIT = "Organisation unit"; - private static final String DIMENSION_NAME_SEP = ":"; - private static final String OPTION_SEP = ";"; - private static final String ITEM_SEP = "-"; + public static final String DIMENSION_NAME_SEP = ":"; + public static final String OPTION_SEP = ";"; + public static final String ITEM_SEP = "-"; public static final List DATA_DIMS = Arrays.asList( INDICATOR_DIM_ID, DATAELEMENT_DIM_ID, DATAELEMENT_OPERAND_ID, DATASET_DIM_ID ); public static final List FIXED_DIMS = Arrays.asList( DATA_X_DIM_ID, INDICATOR_DIM_ID, DATAELEMENT_DIM_ID, DATASET_DIM_ID, PERIOD_DIM_ID, ORGUNIT_DIM_ID ); === added directory 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event' === added file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventAnalyticsManager.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventAnalyticsManager.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventAnalyticsManager.java 2013-08-21 18:09:08 +0000 @@ -0,0 +1,38 @@ +package org.hisp.dhis.analytics.event; + +/* + * Copyright (c) 2004-2012, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.hisp.dhis.common.Grid; + +/** + * @author Lars Helge Overland + */ +public interface EventAnalyticsManager +{ + Grid getEvents( EventQueryParams params, Grid grid ); +} === added file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventAnalyticsService.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventAnalyticsService.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventAnalyticsService.java 2013-08-21 18:09:08 +0000 @@ -0,0 +1,42 @@ +package org.hisp.dhis.analytics.event; + +/* + * Copyright (c) 2004-2012, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.util.Set; + +import org.hisp.dhis.common.Grid; + +/** + * @author Lars Helge Overland + */ +public interface EventAnalyticsService +{ + Grid getEvents( EventQueryParams params ); + + EventQueryParams getFromUrl( String program, String stage, String startDate, String endDate, Set item, Set orgUnits ); +} === added file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryParams.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryParams.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/EventQueryParams.java 2013-08-21 18:09:08 +0000 @@ -0,0 +1,158 @@ +package org.hisp.dhis.analytics.event; + +/* + * Copyright (c) 2004-2009, 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.hisp.dhis.organisationunit.OrganisationUnit; +import org.hisp.dhis.program.Program; +import org.hisp.dhis.program.ProgramStage; + +/** + * @author Lars Helge Overland + */ +public class EventQueryParams +{ + private Program program; + + private ProgramStage programStage; + + private Date startDate; + + private Date endDate; + + private List items = new ArrayList(); + + private List organisationUnits = new ArrayList(); + + private String tableName; + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + public EventQueryParams() + { + } + + public EventQueryParams( EventQueryParams params ) + { + this.program = params.getProgram(); + this.programStage = params.getProgramStage(); + this.startDate = params.getStartDate(); + this.endDate = params.getEndDate(); + this.items = new ArrayList( params.getItems() ); + this.organisationUnits = new ArrayList( params.getOrganisationUnits() ); + this.tableName = params.getTableName(); + } + + // ------------------------------------------------------------------------- + // Logic + // ------------------------------------------------------------------------- + + public boolean hasOrganisationUnits() + { + return organisationUnits != null && !organisationUnits.isEmpty(); + } + + // ------------------------------------------------------------------------- + // Getters and setters + // ------------------------------------------------------------------------- + + public Program getProgram() + { + return program; + } + + public void setProgram( Program program ) + { + this.program = program; + } + + public ProgramStage getProgramStage() + { + return programStage; + } + + public void setProgramStage( ProgramStage programStage ) + { + this.programStage = programStage; + } + + public Date getStartDate() + { + return startDate; + } + + public void setStartDate( Date startDate ) + { + this.startDate = startDate; + } + + public Date getEndDate() + { + return endDate; + } + + public void setEndDate( Date endDate ) + { + this.endDate = endDate; + } + + public List getItems() + { + return items; + } + + public void setItems( List items ) + { + this.items = items; + } + + public List getOrganisationUnits() + { + return organisationUnits; + } + + public void setOrganisationUnits( List organisationUnits ) + { + this.organisationUnits = organisationUnits; + } + + public String getTableName() + { + return tableName; + } + + public void setTableName( String tableName ) + { + this.tableName = tableName; + } +} === added file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/QueryItem.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/QueryItem.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/QueryItem.java 2013-08-21 18:09:08 +0000 @@ -0,0 +1,101 @@ +package org.hisp.dhis.analytics.event; + +/* + * Copyright (c) 2004-2012, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.hisp.dhis.common.IdentifiableObject; + +/** + * @author Lars Helge Overland + */ +public class QueryItem +{ + private IdentifiableObject item; + + private String operator; + + private String filter; + + // ------------------------------------------------------------------------- + // Constructors + // ------------------------------------------------------------------------- + + public QueryItem( IdentifiableObject item ) + { + this.item = item; + } + + public QueryItem( IdentifiableObject item, String operator, String filter ) + { + this.item = item; + this.operator = operator; + this.filter = filter; + } + + // ------------------------------------------------------------------------- + // Logic + // ------------------------------------------------------------------------- + + public boolean hasFilter() + { + return operator != null && !operator.isEmpty() && filter != null && !filter.isEmpty(); + } + + // ------------------------------------------------------------------------- + // Getters and setters + // ------------------------------------------------------------------------- + + public IdentifiableObject getItem() + { + return item; + } + + public void setItem( IdentifiableObject item ) + { + this.item = item; + } + + public String getOperator() + { + return operator; + } + + public void setOperator( String operator ) + { + this.operator = operator; + } + + public String getFilter() + { + return filter; + } + + public void setFilter( String filter ) + { + this.filter = filter; + } +} === added directory 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data' === added 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 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/DefaultEventAnalyticsService.java 2013-08-21 18:09:08 +0000 @@ -0,0 +1,224 @@ +package org.hisp.dhis.analytics.event.data; + +/* + * Copyright (c) 2004-2012, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import static org.hisp.dhis.analytics.DataQueryParams.OPTION_SEP; + +import java.util.Date; +import java.util.List; +import java.util.Set; + +import org.hisp.dhis.analytics.IllegalQueryException; +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.QueryItem; +import org.hisp.dhis.common.Grid; +import org.hisp.dhis.common.GridHeader; +import org.hisp.dhis.common.IdentifiableObject; +import org.hisp.dhis.dataelement.DataElement; +import org.hisp.dhis.dataelement.DataElementService; +import org.hisp.dhis.organisationunit.OrganisationUnit; +import org.hisp.dhis.organisationunit.OrganisationUnitService; +import org.hisp.dhis.patient.PatientAttribute; +import org.hisp.dhis.patient.PatientAttributeService; +import org.hisp.dhis.patient.PatientIdentifierType; +import org.hisp.dhis.patient.PatientIdentifierTypeService; +import org.hisp.dhis.program.Program; +import org.hisp.dhis.program.ProgramService; +import org.hisp.dhis.program.ProgramStage; +import org.hisp.dhis.program.ProgramStageService; +import org.hisp.dhis.system.grid.ListGrid; +import org.hisp.dhis.system.util.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author Lars Helge Overland + */ +public class DefaultEventAnalyticsService + implements EventAnalyticsService +{ + @Autowired + private ProgramService programService; + + @Autowired + private ProgramStageService programStageService; + + @Autowired + private DataElementService dataElementService; + + @Autowired + private PatientAttributeService attributeService; + + @Autowired + private PatientIdentifierTypeService identifierTypeService; + + @Autowired + private OrganisationUnitService organisationUnitService; + + @Autowired + private EventAnalyticsManager analyticsManager; + + // ------------------------------------------------------------------------- + // EventAnalyticsService implementation + // ------------------------------------------------------------------------- + + //TODO table name + //TODO org unit children / descendants + + public Grid getEvents( EventQueryParams params ) + { + Grid grid = new ListGrid(); + + grid.addHeader( new GridHeader( "Event", "psi" ) ); + grid.addHeader( new GridHeader( "Program stage", "ps" ) ); + grid.addHeader( new GridHeader( "Executiondate", "executiondate" ) ); + grid.addHeader( new GridHeader( "Organisation unit", "ou" ) ); + + for ( QueryItem queryItem : params.getItems() ) + { + IdentifiableObject item = queryItem.getItem(); + + grid.addHeader( new GridHeader( item.getName(), item.getUid() ) ); + } + + List queries = EventQueryPlanner.planQuery( params ); + + for ( EventQueryParams query : queries ) + { + analyticsManager.getEvents( query, grid ); + } + + return grid; + } + + public EventQueryParams getFromUrl( String program, String stage, String startDate, String endDate, Set item, Set orgUnits ) + { + EventQueryParams params = new EventQueryParams(); + + Program pr = programService.getProgram( program ); + + if ( pr == null ) + { + throw new IllegalQueryException( "Program does not exist: " + program ); + } + + ProgramStage ps = programStageService.getProgramStage( stage ); + + if ( stage != null && !stage.isEmpty() && ps == null ) + { + throw new IllegalQueryException( "Program stage is specified but does not exist: " + stage ); + } + + Date start = null; + Date end = null; + + try + { + start = DateUtils.getMediumDate( startDate ); + end = DateUtils.getMediumDate( endDate ); + } + catch ( RuntimeException ex ) + { + throw new IllegalQueryException( "Start date or end date is invalid: " + startDate + " " + endDate ); + } + + if ( start.after( end ) ) + { + throw new IllegalQueryException( "Start date is after end date: " + startDate + " - " + endDate ); + } + + if ( item != null ) + { + for ( String it : item ) + { + if ( it != null && !it.contains( OPTION_SEP ) ) + { + params.getItems().add( new QueryItem( getItem( it ) ) ); + } + else if ( it != null ) + { + String[] split = it.split( OPTION_SEP ); + + if ( split == null || split.length != 3 ) + { + throw new IllegalQueryException( "Item filter has invalid format: " + it ); + } + + params.getItems().add( new QueryItem( getItem( split[0] ), split[1], split[2] ) ); + } + } + } + + if ( orgUnits != null ) + { + for ( String orgUnit : orgUnits ) + { + OrganisationUnit ou = organisationUnitService.getOrganisationUnit( orgUnit ); + + if ( ou != null ) + { + params.getOrganisationUnits().add( ou ); + } + } + } + + params.setProgram( pr ); + params.setProgramStage( ps ); + params.setStartDate( start ); + params.setEndDate( end ); + + return params; + } + + private IdentifiableObject getItem( String item ) + { + DataElement de = dataElementService.getDataElement( item ); + + if ( de != null ) + { + return de; + } + + PatientAttribute at = attributeService.getPatientAttribute( item ); + + if ( at != null ) + { + return at; + } + + PatientIdentifierType it = identifierTypeService.getPatientIdentifierType( item ); + + if ( it != null ) + { + return it; + } + + throw new IllegalQueryException( "Item identifier does not reference any item: " + item ); + } +} === added 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 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/EventQueryPlanner.java 2013-08-21 18:09:08 +0000 @@ -0,0 +1,75 @@ +package org.hisp.dhis.analytics.event.data; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.hisp.dhis.analytics.event.EventQueryParams; +import org.hisp.dhis.period.Cal; +import org.hisp.dhis.program.Program; + +public class EventQueryPlanner +{ + private static final String TABLE_BASE_NAME = "analytics_event_"; + + public static List planQuery( EventQueryParams params ) + { + return splitByPartition( params ); + } + + private static List splitByPartition( EventQueryParams params ) + { + List list = new ArrayList(); + + Program program = params.getProgram(); + + 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; + } + } + + return list; + } + + private static EventQueryParams getQuery( EventQueryParams params, Date startDate, Date endDate, Program program ) + { + EventQueryParams query = new EventQueryParams( params ); + 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(); + } +} === added file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEventAnalyticsManager.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEventAnalyticsManager.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/event/data/JdbcEventAnalyticsManager.java 2013-08-21 18:09:08 +0000 @@ -0,0 +1,110 @@ +package org.hisp.dhis.analytics.event.data; + +/* + * Copyright (c) 2004-2012, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import static org.hisp.dhis.common.IdentifiableObjectUtils.getUids; +import static org.hisp.dhis.system.util.DateUtils.getMediumDateString; +import static org.hisp.dhis.system.util.TextUtils.getQuotedCommaDelimitedString; +import static org.hisp.dhis.system.util.TextUtils.removeLast; + +import org.hisp.dhis.analytics.event.EventAnalyticsManager; +import org.hisp.dhis.analytics.event.EventQueryParams; +import org.hisp.dhis.analytics.event.QueryItem; +import org.hisp.dhis.common.Grid; +import org.hisp.dhis.common.IdentifiableObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.rowset.SqlRowSet; + +/** + * @author Lars Helge Overland + */ +public class JdbcEventAnalyticsManager + implements EventAnalyticsManager +{ + @Autowired + private JdbcTemplate jdbcTemplate; + + // ------------------------------------------------------------------------- + // EventAnalyticsManager implementation + // ------------------------------------------------------------------------- + + public Grid getEvents( EventQueryParams params, Grid grid ) + { + String sql = "select psi,ps,executiondate,ou,"; + + for ( QueryItem queryItem : params.getItems() ) + { + IdentifiableObject item = queryItem.getItem(); + + sql += item.getUid() + ","; + } + + sql = removeLast( sql, 1 ) + " "; + + sql += "from " + params.getTableName() + " "; + sql += "where executiondate >= '" + getMediumDateString( params.getStartDate() ) + "' "; + sql += "and executiondate <= '" + getMediumDateString( params.getEndDate() ) + "' "; + + if ( params.hasOrganisationUnits() ) + { + sql += "and ou in (" + getQuotedCommaDelimitedString( getUids( params.getOrganisationUnits() ) ) + ") "; + } + + if ( params.getProgramStage() != null ) + { + sql += "and ps = '" + params.getProgramStage() + "' "; + } + + for ( QueryItem filter : params.getItems() ) + { + if ( filter.hasFilter() ) + { + sql += "and " + filter.getFilter() + " " + filter.getOperator() + " '" + filter.getFilter() + "' "; + } + } + + int rowLength = grid.getHeaders().size(); + + SqlRowSet rowSet = jdbcTemplate.queryForRowSet( sql ); + + while ( rowSet.next() ) + { + grid.addRow(); + + for ( int i = 0; i < rowLength; i++ ) + { + int index = i + 1; + + grid.addValue( rowSet.getString( index ) ); + } + } + + return grid; + } +} === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/PartitionUtils.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/PartitionUtils.java 2013-08-20 22:48:23 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/PartitionUtils.java 2013-08-21 18:09:08 +0000 @@ -34,7 +34,6 @@ import org.hisp.dhis.common.ListMap; import org.hisp.dhis.common.NameableObject; import org.hisp.dhis.period.Period; -import org.hisp.dhis.period.PeriodType; import org.hisp.dhis.period.YearlyPeriodType; /** @@ -67,19 +66,6 @@ return tableName + SEP + year.getIsoDate(); } - - public static Period getPeriod( String tableName ) - { - if ( tableName == null || tableName.indexOf( SEP ) == -1 ) - { - return null; - } - - String[] split = tableName.split( SEP ); - String isoPeriod = split[split.length - 1]; - - return PeriodType.getPeriodFromIsoString( isoPeriod ); - } public static ListMap getTableNamePeriodMap( List periods, String tableName ) { === 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 10:08:02 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/resources/META-INF/dhis/beans.xml 2013-08-21 18:09:08 +0000 @@ -2,6 +2,8 @@ + + @@ -26,12 +28,20 @@ + + + + + + + + === added directory 'dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event' === added directory 'dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data' === added file 'dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsServiceTest.java' --- dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsServiceTest.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EventAnalyticsServiceTest.java 2013-08-21 18:09:08 +0000 @@ -0,0 +1,84 @@ +package org.hisp.dhis.analytics.event.data; + +/* + * Copyright (c) 2004-2012, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.hisp.dhis.DhisSpringTest; +import org.hisp.dhis.analytics.event.EventAnalyticsService; +import org.hisp.dhis.dataelement.DataElement; +import org.hisp.dhis.dataelement.DataElementService; +import org.hisp.dhis.patient.PatientAttribute; +import org.hisp.dhis.patient.PatientAttributeService; +import org.hisp.dhis.patient.PatientIdentifierType; +import org.hisp.dhis.patient.PatientIdentifierTypeService; +import org.hisp.dhis.program.Program; +import org.hisp.dhis.program.ProgramService; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author Lars Helge Overland + */ +public class EventAnalyticsServiceTest + extends DhisSpringTest +{ + @Autowired + private EventAnalyticsService analyticsService; + + @Autowired + private ProgramService programService; + + @Autowired + private DataElementService dataElementService; + + @Autowired + private PatientAttributeService attributeService; + + @Autowired + private PatientIdentifierTypeService identifierTypeService; + + private Program prA; + private DataElement deA; + private DataElement deB; + private PatientAttribute atA; + private PatientAttribute atB; + private PatientIdentifierType itA; + private PatientIdentifierType itB; + + @Override + public void setUpTest() + { + prA = createProgram( 'A', null, null ); + + } + + @Test + public void testGetFromUrl() + { + + } +} === added 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 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/event/data/EventQueryPlannerTest.java 2013-08-21 18:09:08 +0000 @@ -0,0 +1,91 @@ +package org.hisp.dhis.analytics.event.data; + +/* + * Copyright (c) 2004-2012, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.hisp.dhis.analytics.event.EventQueryParams; +import org.hisp.dhis.period.Cal; +import org.hisp.dhis.program.Program; +import org.junit.Test; + +/** + * @author Lars Helge Overland + */ +public class EventQueryPlannerTest +{ + @Test + public void testPlanQueryA() + { + Program prA = new Program(); + prA.setUid( "programuidA" ); + + EventQueryParams params = new EventQueryParams(); + params.setProgram( prA ); + params.setStartDate( new Cal( 2010, 6, 1 ).time() ); + params.setEndDate( new Cal( 2012, 3, 20 ).time() ); + + List queries = EventQueryPlanner.planQuery( params ); + + assertEquals( 3, queries.size() ); + + assertEquals( new Cal( 2010, 6, 1 ).time(), queries.get( 0 ).getStartDate() ); + assertEquals( new Cal( 2010, 12, 31 ).time(), queries.get( 0 ).getEndDate() ); + assertEquals( new Cal( 2011, 1, 1 ).time(), queries.get( 1 ).getStartDate() ); + assertEquals( new Cal( 2011, 12, 31 ).time(), queries.get( 1 ).getEndDate() ); + assertEquals( new Cal( 2012, 1, 1 ).time(), queries.get( 2 ).getStartDate() ); + assertEquals( new Cal( 2012, 3, 20 ).time(), queries.get( 2 ).getEndDate() ); + + assertEquals( "analytics_event_2010_programuidA", queries.get( 0 ).getTableName() ); + assertEquals( "analytics_event_2011_programuidA", queries.get( 1 ).getTableName() ); + assertEquals( "analytics_event_2012_programuidA", queries.get( 2 ).getTableName() ); + } + + @Test + public void testPlanQueryB() + { + Program prA = new Program(); + prA.setUid( "programuidA" ); + + EventQueryParams params = new EventQueryParams(); + params.setProgram( prA ); + params.setStartDate( new Cal( 2010, 3, 1 ).time() ); + params.setEndDate( new Cal( 2010, 9, 20 ).time() ); + + List queries = EventQueryPlanner.planQuery( params ); + + assertEquals( 1, queries.size() ); + + assertEquals( new Cal( 2010, 3, 1 ).time(), queries.get( 0 ).getStartDate() ); + assertEquals( new Cal( 2010, 9, 20 ).time(), queries.get( 0 ).getEndDate() ); + + assertEquals( "analytics_event_2010_programuidA", queries.get( 0 ).getTableName() ); + } +} === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/PartitionUtilsTest.java' --- dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/PartitionUtilsTest.java 2013-08-20 22:48:23 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/test/java/org/hisp/dhis/analytics/table/PartitionUtilsTest.java 2013-08-21 18:09:08 +0000 @@ -29,16 +29,12 @@ import static org.hisp.dhis.DhisConvenienceTest.createPeriod; import static org.hisp.dhis.analytics.AnalyticsTableManager.ANALYTICS_TABLE_NAME; -import static org.hisp.dhis.analytics.AnalyticsTableManager.TABLE_TEMP_SUFFIX; import static org.hisp.dhis.common.NameableObjectUtils.getList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.hisp.dhis.common.ListMap; import org.hisp.dhis.common.NameableObject; -import org.hisp.dhis.period.Cal; -import org.hisp.dhis.period.Period; -import org.hisp.dhis.period.YearlyPeriodType; import org.junit.Test; /** @@ -46,7 +42,6 @@ */ public class PartitionUtilsTest { - private static final String TABLE_NAME_TEMP = ANALYTICS_TABLE_NAME + TABLE_TEMP_SUFFIX; private static final String TABLE_NAME = ANALYTICS_TABLE_NAME; @Test @@ -57,19 +52,7 @@ assertEquals( TABLE_NAME + "_2002", PartitionUtils.getTableName( createPeriod( "2002Q2" ), TABLE_NAME ) ); assertEquals( TABLE_NAME + "_2003", PartitionUtils.getTableName( createPeriod( "2003S2" ), TABLE_NAME ) ); } - - @Test - public void testGetPeriod() - { - Cal cal = new Cal(); - - Period p1 = new YearlyPeriodType().createPeriod( cal.set( 2000, 4, 1 ).time() ); - Period p2 = new YearlyPeriodType().createPeriod( cal.set( 2001, 10, 1 ).time() ); - - assertEquals( p1, PartitionUtils.getPeriod( TABLE_NAME_TEMP + "_2000" ) ); - assertEquals( p2, PartitionUtils.getPeriod( TABLE_NAME_TEMP + "_2001" ) ); - } - + @Test public void testGetTablePeriodMap() { === added file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/EventAnalyticsController.java' --- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/EventAnalyticsController.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/EventAnalyticsController.java 2013-08-21 18:09:08 +0000 @@ -0,0 +1,81 @@ +package org.hisp.dhis.api.controller; + +/* + * Copyright (c) 2004-2012, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.util.Set; + +import javax.servlet.http.HttpServletResponse; + +import org.hisp.dhis.analytics.event.EventAnalyticsService; +import org.hisp.dhis.analytics.event.EventQueryParams; +import org.hisp.dhis.api.utils.ContextUtils; +import org.hisp.dhis.api.utils.ContextUtils.CacheStrategy; +import org.hisp.dhis.common.Grid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +@Controller +public class EventAnalyticsController +{ + private static final String RESOURCE_PATH = "/analytics/events"; + + @Autowired + private EventAnalyticsService analyticsService; + + @Autowired + private ContextUtils contextUtils; + + // ------------------------------------------------------------------------- + // Resources + // ------------------------------------------------------------------------- + + @RequestMapping( value = RESOURCE_PATH + "/{program}", method = RequestMethod.GET, produces = { "application/json", "application/javascript" } ) + public String getJson( // JSON, JSONP + @PathVariable String program, + @RequestParam(required=false) String stage, + @RequestParam String startDate, + @RequestParam String endDate, + @RequestParam Set item, + @RequestParam(required=false) Set orgUnits, + Model model, + HttpServletResponse response ) throws Exception + { + EventQueryParams params = analyticsService.getFromUrl( program, stage, startDate, endDate, item, orgUnits ); + + contextUtils.configureResponse( response, ContextUtils.CONTENT_TYPE_JSON, CacheStrategy.RESPECT_SYSTEM_SETTING ); + Grid grid = analyticsService.getEvents( params ); + model.addAttribute( "model", grid ); + model.addAttribute( "viewClass", "detailed" ); + return "grid"; + } +}