=== modified file 'dhis-2/dhis-services/dhis-service-analytics/pom.xml' --- dhis-2/dhis-services/dhis-service-analytics/pom.xml 2013-05-31 08:27:38 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/pom.xml 2013-08-21 10:08:02 +0000 @@ -27,6 +27,10 @@ org.hisp.dhis + dhis-service-patient + + + org.hisp.dhis dhis-service-administration === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsTable.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsTable.java 2013-08-20 22:48:23 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsTable.java 2013-08-21 11:56:16 +0000 @@ -27,6 +27,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import java.util.List; + import org.hisp.dhis.period.Period; import org.hisp.dhis.program.Program; @@ -36,6 +38,8 @@ public class AnalyticsTable { private String baseName; + + private List dimensionColumns; private Period period; @@ -45,20 +49,23 @@ { } - public AnalyticsTable( String baseName ) + public AnalyticsTable( String baseName, List dimensionColumns ) { this.baseName = baseName; + this.dimensionColumns = dimensionColumns; } - public AnalyticsTable( String baseName, Period period ) + public AnalyticsTable( String baseName, List dimensionColumns, Period period ) { this.baseName = baseName; + this.dimensionColumns = dimensionColumns; this.period = period; } - public AnalyticsTable( String baseName, Period period, Program program ) + public AnalyticsTable( String baseName, List dimensionColumns, Period period, Program program ) { this.baseName = baseName; + this.dimensionColumns = dimensionColumns; this.period = period; this.program = program; } @@ -113,6 +120,16 @@ this.baseName = baseName; } + public List getDimensionColumns() + { + return dimensionColumns; + } + + public void setDimensionColumns( List dimensionColumns ) + { + this.dimensionColumns = dimensionColumns; + } + public Period getPeriod() { return period; === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsTableManager.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsTableManager.java 2013-08-20 23:17:09 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/AnalyticsTableManager.java 2013-08-21 11:56:16 +0000 @@ -107,17 +107,6 @@ Future populateTableAsync( ConcurrentLinkedQueue tables ); /** - * Returns a list of string arrays in where the first index holds the database - * column name, the second index holds the database column data type and the - * third column holds a table alias and name, i.e.: - * - * 0 = database column name - * 1 = database column data type - * 2 = column alias and name - */ - List getDimensionColumns( AnalyticsTable table ); - - /** * Retrieves the start date of the period of the earliest data value row. */ Date getEarliestData(); === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/scheduling/AnalyticsTableTask.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/scheduling/AnalyticsTableTask.java 2013-03-15 16:33:34 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/scheduling/AnalyticsTableTask.java 2013-08-21 11:56:16 +0000 @@ -52,6 +52,9 @@ @Resource(name="org.hisp.dhis.analytics.CompletenessTargetTableService") private AnalyticsTableService completenessTargetTableService; + @Resource(name="org.hisp.dhis.analytics.EventAnalyticsTableService") + private AnalyticsTableService eventAnalyticsTableService; + @Autowired private ResourceTableService resourceTableService; @@ -95,6 +98,10 @@ completenessTargetTableService.update( last3Years, taskId ); + notifier.notify( taskId, "Updating event analytics tables" ); + + eventAnalyticsTableService.update( last3Years, taskId ); + notifier.notify( taskId, INFO, "Analytics tables updated", true ); } } === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/AbstractJdbcTableManager.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/AbstractJdbcTableManager.java 2013-08-20 23:17:09 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/AbstractJdbcTableManager.java 2013-08-21 11:56:16 +0000 @@ -51,6 +51,7 @@ import org.springframework.jdbc.BadSqlGrammarException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.scheduling.annotation.Async; +import org.springframework.transaction.annotation.Transactional; /** * @author Lars Helge Overland @@ -83,9 +84,25 @@ protected JdbcTemplate jdbcTemplate; // ------------------------------------------------------------------------- + // Abstract methods + // ------------------------------------------------------------------------- + + /** + * Returns a list of string arrays in where the first index holds the database + * column name, the second index holds the database column data type and the + * third column holds a table alias and name, i.e.: + * + * 0 = database column name + * 1 = database column data type + * 2 = column alias and name + */ + protected abstract List getDimensionColumns( AnalyticsTable table ); + + // ------------------------------------------------------------------------- // Implementation // ------------------------------------------------------------------------- - + + @Transactional public List getTables( boolean last3YearsOnly ) { Date threeYrsAgo = new Cal().subtract( Calendar.YEAR, 2 ).set( 1, 1 ).time(); @@ -95,6 +112,7 @@ return getTables( earliest, latest ); } + @Transactional public List getTables( Date earliest, Date latest ) { String baseName = getTableName(); @@ -105,7 +123,7 @@ for ( Period period : periods ) { - tables.add( new AnalyticsTable( baseName, period ) ); + tables.add( new AnalyticsTable( baseName, getDimensionColumns( null ), period ) ); } return tables; === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/DefaultAnalyticsTableService.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/DefaultAnalyticsTableService.java 2013-08-20 23:17:09 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/DefaultAnalyticsTableService.java 2013-08-21 11:56:16 +0000 @@ -147,7 +147,7 @@ // ------------------------------------------------------------------------- // Supportive methods // ------------------------------------------------------------------------- - + private void createTables( List tables ) { for ( AnalyticsTable table : tables ) @@ -218,7 +218,7 @@ for ( AnalyticsTable table : tables ) { - List columns = tableManager.getDimensionColumns( table ); + List columns = table.getDimensionColumns(); for ( String[] column : columns ) { === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcAnalyticsTableManager.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcAnalyticsTableManager.java 2013-08-20 23:17:09 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcAnalyticsTableManager.java 2013-08-21 10:08:02 +0000 @@ -80,7 +80,7 @@ { return "analytics"; } - + public void createTable( AnalyticsTable table ) { final String tableName = table.getTempTableName(); === modified file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcCompletenessTargetTableManager.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcCompletenessTargetTableManager.java 2013-08-20 23:17:09 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcCompletenessTargetTableManager.java 2013-08-21 11:56:16 +0000 @@ -38,6 +38,7 @@ import org.hisp.dhis.organisationunit.OrganisationUnitGroupSet; import org.hisp.dhis.organisationunit.OrganisationUnitLevel; import org.springframework.scheduling.annotation.Async; +import org.springframework.transaction.annotation.Transactional; /** * @author Lars Helge Overland @@ -46,10 +47,11 @@ extends AbstractJdbcTableManager { @Override + @Transactional public List getTables( boolean last3YearsOnly ) { List tables = new ArrayList(); - tables.add( new AnalyticsTable( getTableName() ) ); + tables.add( new AnalyticsTable( getTableName(), getDimensionColumns( null ) ) ); return tables; } === added file 'dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcEventAnalyticsTableManager.java' --- dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcEventAnalyticsTableManager.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/java/org/hisp/dhis/analytics/table/JdbcEventAnalyticsTableManager.java 2013-08-21 11:56:16 +0000 @@ -0,0 +1,221 @@ +package org.hisp.dhis.analytics.table; + +/* + * 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.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.Future; + +import org.hisp.dhis.analytics.AnalyticsTable; +import org.hisp.dhis.dataelement.DataElement; +import org.hisp.dhis.organisationunit.OrganisationUnitLevel; +import org.hisp.dhis.period.Period; +import org.hisp.dhis.program.Program; +import org.hisp.dhis.program.ProgramService; +import org.hisp.dhis.system.util.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.transaction.annotation.Transactional; + +import static org.hisp.dhis.system.util.TextUtils.removeLast; + +/** + * @author Lars Helge Overland + */ +public class JdbcEventAnalyticsTableManager + extends AbstractJdbcTableManager +{ + @Autowired + private ProgramService programService; + + // ------------------------------------------------------------------------- + // Implementation + // ------------------------------------------------------------------------- + + @Override + @Transactional + public List getTables( Date earliest, Date latest ) + { + String baseName = getTableName(); + + List periods = PartitionUtils.getPeriods( earliest, latest ); + + List tables = new ArrayList(); + + for ( Period period : periods ) + { + for ( Program program : programService.getAllPrograms() ) + { + AnalyticsTable table = new AnalyticsTable( baseName, null, period, program ); + List dimensionColumns = getDimensionColumns( table ); + table.setDimensionColumns( dimensionColumns ); + tables.add( table ); + } + } + + return tables; + } + + public boolean validState() + { + return jdbcTemplate.queryForRowSet( "select dataelementid from patientdatavalue limit 1" ).next(); + } + + public String getTableName() + { + return "analytics_event"; + } + + public void createTable( AnalyticsTable table ) + { + final String tableName = table.getTempTableName(); + + final String sqlDrop = "drop table " + tableName; + + executeSilently( sqlDrop ); + + String sqlCreate = "create table " + tableName + " ("; + + for ( String[] col : getDimensionColumns( table ) ) + { + sqlCreate += col[0] + " " + col[1] + ","; + } + + sqlCreate = removeLast( sqlCreate, 1 ) + ")"; + + log.info( "Create SQL: " + sqlCreate ); + + executeSilently( sqlCreate ); + } + + @Async + @Override + public Future populateTableAsync( ConcurrentLinkedQueue tables ) + { + taskLoop : while ( true ) + { + AnalyticsTable table = tables.poll(); + + if ( table == null ) + { + break taskLoop; + } + + final String start = DateUtils.getMediumDateString( table.getPeriod().getStartDate() ); + final String end = DateUtils.getMediumDateString( table.getPeriod().getEndDate() ); + + String sql = "insert into " + table.getTempTableName() + " ("; + + for ( String[] col : getDimensionColumns( table ) ) + { + sql += col[0] + ","; + } + + sql = removeLast( sql, 1 ) + ") select "; + + for ( String[] col : getDimensionColumns( table ) ) + { + sql += col[2] + ","; + } + + sql = removeLast( sql, 1 ) + " "; + + sql += + "from programstageinstance psi " + + "left join programinstance pi on psi.programinstanceid=pi.programinstanceid " + + "left join programstage ps on psi.programstageid=ps.programstageid " + + "left join program pr on pi.programid=pr.programid " + + "left join _orgunitstructure ous on psi.organisationunitid=ous.organisationunitid " + + "where psi.executiondate >= '" + start + "' " + + "and psi.executiondate <= '" + end + "' " + + "and pr.programid=" + table.getProgram().getId() + ";"; + + log.info( "Populate SQL: "+ sql ); + + jdbcTemplate.execute( sql ); + } + + return null; + } + + public List getDimensionColumns( AnalyticsTable table ) + { + List columns = new ArrayList(); + + Collection levels = + organisationUnitService.getOrganisationUnitLevels(); + + for ( OrganisationUnitLevel level : levels ) + { + String column = PREFIX_ORGUNITLEVEL + level.getLevel(); + String[] col = { column, "character(11)", "ous." + column }; + columns.add( col ); + } + + for ( DataElement dataElement : table.getProgram().getAllDataElements() ) + { + String select = "(select value from patientdatavalue where programstageinstanceid=" + + "psi.programstageinstanceid and dataelementid=" + dataElement.getId() + ") as " + dataElement.getUid(); + + String[] col = { dataElement.getUid(), "character(255)", select }; + columns.add( col ); + } + + String[] psi = { "psi", "character(11) not null", "psi.uid" }; + String[] ps = { "ps", "character(11) not null", "ps.uid" }; + String[] ed = { "executiondate", "date", "psi.executiondate" }; + + columns.addAll( Arrays.asList( psi, ps, ed ) ); + + return columns; + } + + public Date getEarliestData() + { + final String sql = "select min(pdv.timestamp) from patientdatavalue pdv"; + + return jdbcTemplate.queryForObject( sql, Date.class ); + } + + public Date getLatestData() + { + final String sql = "select max(pdv.timestamp) from patientdatavalue pdv"; + + return jdbcTemplate.queryForObject( sql, Date.class ); + } + + @Async + public Future applyAggregationLevels( ConcurrentLinkedQueue tables, Collection dataElements, int aggregationLevel ) + { + return null; // Not relevant + } +} === 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-03-04 14:44:15 +0000 +++ dhis-2/dhis-services/dhis-service-analytics/src/main/resources/META-INF/dhis/beans.xml 2013-08-21 10:08:02 +0000 @@ -8,6 +8,8 @@ + + @@ -20,6 +22,10 @@ + + + + === modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/TextUtils.java' --- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/TextUtils.java 2013-01-16 18:23:37 +0000 +++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/TextUtils.java 2013-08-21 11:56:16 +0000 @@ -136,6 +136,30 @@ } /** + * Removes the last given number of characters from the given string. Returns + * null if the string is null. Returns an empty string if characters is less + * than zero or greater than the length of the string. + * + * @param string the string. + * @param characters number of characters to remove. + * @return the substring. + */ + public static String removeLast( String string, int characters ) + { + if ( string == null ) + { + return null; + } + + if ( characters < 0 || characters > string.length() ) + { + return EMPTY; + } + + return string.substring( 0, string.length() - characters ); + } + + /** * Trims the given string from the end. * * @param value the value to trim.