← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 16975: CSV event export, wip

 

------------------------------------------------------------
revno: 16975
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Tue 2014-10-07 13:35:04 +0700
message:
  CSV event export, wip
added:
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/event/csv/
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/event/csv/CsvEventDataValue.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/event/csv/CsvEventUtils.java
modified:
  dhis-2/dhis-services/dhis-service-dxf2/pom.xml
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/event/EventController.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/RenderServiceMessageConverter.java
  dhis-2/pom.xml


--
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-services/dhis-service-dxf2/pom.xml'
--- dhis-2/dhis-services/dhis-service-dxf2/pom.xml	2014-07-23 14:53:00 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/pom.xml	2014-10-07 06:35:04 +0000
@@ -51,6 +51,10 @@
       <groupId>com.fasterxml.jackson.dataformat</groupId>
       <artifactId>jackson-dataformat-xml</artifactId>
     </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.dataformat</groupId>
+      <artifactId>jackson-dataformat-csv</artifactId>
+    </dependency>
   </dependencies>
 
   <properties>

=== added directory 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/event/csv'
=== added file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/event/csv/CsvEventDataValue.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/event/csv/CsvEventDataValue.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/event/csv/CsvEventDataValue.java	2014-10-07 06:35:04 +0000
@@ -0,0 +1,322 @@
+package org.hisp.dhis.dxf2.events.event.csv;
+
+/*
+ * Copyright (c) 2004-2014, 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 com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.hisp.dhis.event.EventStatus;
+import org.springframework.util.Assert;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+@JsonPropertyOrder( {
+    "event",
+    "status",
+    "program",
+    "programInstance",
+    "programStage",
+    "enrollment",
+    "enrollmentStatus",
+    "orgUnit",
+    "trackedEntityInstance",
+    "eventDate",
+    "dueDate",
+    "latitude",
+    "longitude",
+    "followUp",
+    "dataElement",
+    "value",
+    "providedElsewhere",
+    "storedBy"
+} )
+public class CsvEventDataValue
+{
+    private String event;
+
+    private EventStatus status = EventStatus.ACTIVE;
+
+    private String program;
+
+    private String programInstance;
+
+    private String programStage;
+
+    private String enrollment;
+
+    private EventStatus enrollmentStatus;
+
+    private String orgUnit;
+
+    private String trackedEntityInstance;
+
+    private String eventDate;
+
+    private String dueDate;
+
+    private Double latitude;
+
+    private Double longitude;
+
+    private Boolean followup;
+
+    private String dataElement;
+
+    private String value;
+
+    private Boolean providedElsewhere = false;
+
+    private String storedBy;
+
+    public CsvEventDataValue()
+    {
+    }
+
+    public CsvEventDataValue( CsvEventDataValue dataValue )
+    {
+        Assert.notNull( dataValue, "A non-null CsvOutputEventDataValue must be given as a parameter." );
+
+        this.event = dataValue.getEvent();
+        this.status = dataValue.getStatus();
+        this.program = dataValue.getProgram();
+        this.programInstance = dataValue.getProgramInstance();
+        this.programStage = dataValue.getProgramStage();
+        this.enrollment = dataValue.getEnrollment();
+        this.enrollmentStatus = dataValue.getEnrollmentStatus();
+        this.orgUnit = dataValue.getOrgUnit();
+        this.trackedEntityInstance = dataValue.getTrackedEntityInstance();
+        this.eventDate = dataValue.getEventDate();
+        this.dueDate = dataValue.getDueDate();
+        this.latitude = dataValue.getLatitude();
+        this.longitude = dataValue.getLongitude();
+        this.followup = dataValue.getFollowup();
+        this.dataElement = dataValue.getDataElement();
+        this.value = dataValue.getValue();
+        this.providedElsewhere = dataValue.getProvidedElsewhere();
+        this.storedBy = dataValue.getStoredBy();
+    }
+
+    @JsonProperty
+    public String getEvent()
+    {
+        return event;
+    }
+
+    public void setEvent( String event )
+    {
+        this.event = event;
+    }
+
+    @JsonProperty
+    public EventStatus getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus( EventStatus status )
+    {
+        this.status = status;
+    }
+
+    @JsonProperty
+    public String getProgram()
+    {
+        return program;
+    }
+
+    public void setProgram( String program )
+    {
+        this.program = program;
+    }
+
+    @JsonProperty
+    public String getProgramInstance()
+    {
+        return programInstance;
+    }
+
+    public void setProgramInstance( String programInstance )
+    {
+        this.programInstance = programInstance;
+    }
+
+    @JsonProperty
+    public String getProgramStage()
+    {
+        return programStage;
+    }
+
+    public void setProgramStage( String programStage )
+    {
+        this.programStage = programStage;
+    }
+
+    @JsonProperty
+    public String getEnrollment()
+    {
+        return enrollment;
+    }
+
+    public void setEnrollment( String enrollment )
+    {
+        this.enrollment = enrollment;
+    }
+
+    @JsonProperty
+    public EventStatus getEnrollmentStatus()
+    {
+        return enrollmentStatus;
+    }
+
+    public void setEnrollmentStatus( EventStatus enrollmentStatus )
+    {
+        this.enrollmentStatus = enrollmentStatus;
+    }
+
+    @JsonProperty
+    public String getOrgUnit()
+    {
+        return orgUnit;
+    }
+
+    public void setOrgUnit( String orgUnit )
+    {
+        this.orgUnit = orgUnit;
+    }
+
+    @JsonProperty
+    public String getTrackedEntityInstance()
+    {
+        return trackedEntityInstance;
+    }
+
+    public void setTrackedEntityInstance( String trackedEntityInstance )
+    {
+        this.trackedEntityInstance = trackedEntityInstance;
+    }
+
+    @JsonProperty
+    public String getEventDate()
+    {
+        return eventDate;
+    }
+
+    public void setEventDate( String eventDate )
+    {
+        this.eventDate = eventDate;
+    }
+
+    @JsonProperty
+    public String getDueDate()
+    {
+        return dueDate;
+    }
+
+    public void setDueDate( String dueDate )
+    {
+        this.dueDate = dueDate;
+    }
+
+    @JsonProperty
+    public Double getLatitude()
+    {
+        return latitude;
+    }
+
+    public void setLatitude( Double latitude )
+    {
+        this.latitude = latitude;
+    }
+
+    @JsonProperty
+    public Double getLongitude()
+    {
+        return longitude;
+    }
+
+    public void setLongitude( Double longitude )
+    {
+        this.longitude = longitude;
+    }
+
+    @JsonProperty
+    public Boolean getFollowup()
+    {
+        return followup;
+    }
+
+    public void setFollowup( Boolean followup )
+    {
+        this.followup = followup;
+    }
+
+    @JsonProperty
+    public String getDataElement()
+    {
+        return dataElement;
+    }
+
+    public void setDataElement( String dataElement )
+    {
+        this.dataElement = dataElement;
+    }
+
+    @JsonProperty
+    public String getValue()
+    {
+        return value;
+    }
+
+    public void setValue( String value )
+    {
+        this.value = value;
+    }
+
+    @JsonProperty
+    public Boolean getProvidedElsewhere()
+    {
+        return providedElsewhere;
+    }
+
+    public void setProvidedElsewhere( Boolean providedElsewhere )
+    {
+        this.providedElsewhere = providedElsewhere;
+    }
+
+    @JsonProperty
+    public String getStoredBy()
+    {
+        return storedBy;
+    }
+
+    public void setStoredBy( String storedBy )
+    {
+        this.storedBy = storedBy;
+    }
+}

=== added file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/event/csv/CsvEventUtils.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/event/csv/CsvEventUtils.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/events/event/csv/CsvEventUtils.java	2014-10-07 06:35:04 +0000
@@ -0,0 +1,113 @@
+package org.hisp.dhis.dxf2.events.event.csv;
+
+/*
+ * Copyright (c) 2004-2014, 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 com.fasterxml.jackson.databind.ObjectWriter;
+import com.fasterxml.jackson.dataformat.csv.CsvMapper;
+import com.fasterxml.jackson.dataformat.csv.CsvSchema;
+import org.hisp.dhis.dxf2.events.event.DataValue;
+import org.hisp.dhis.dxf2.events.event.Event;
+import org.hisp.dhis.dxf2.events.event.Events;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+public final class CsvEventUtils
+{
+    private static CsvMapper csvMapper = new CsvMapper();
+
+    private static CsvSchema csvSchema = csvMapper.schemaFor( CsvEventDataValue.class );
+
+    public static CsvMapper getCsvMapper()
+    {
+        return csvMapper;
+    }
+
+    public static CsvSchema getCsvSchema()
+    {
+        return csvSchema;
+    }
+
+    public static void writeEvents( OutputStream outputStream, Events events, boolean withHeaders ) throws IOException
+    {
+        ObjectWriter writer = getCsvMapper().writer( getCsvSchema().withUseHeader( withHeaders ) );
+
+        List<CsvEventDataValue> dataValues = new ArrayList<>();
+
+        for ( Event event : events.getEvents() )
+        {
+            CsvEventDataValue templateDataValue = new CsvEventDataValue();
+            templateDataValue.setEvent( event.getEvent() );
+            templateDataValue.setProgram( event.getProgram() == null ? events.getProgram() : event.getProgram() );
+            templateDataValue.setProgramInstance( events.getProgramInstance() );
+            templateDataValue.setProgramStage( event.getProgramStage() );
+            templateDataValue.setEnrollment( event.getEnrollment() );
+            templateDataValue.setEnrollmentStatus( event.getEnrollmentStatus() );
+            templateDataValue.setOrgUnit( event.getOrgUnit() );
+            templateDataValue.setTrackedEntityInstance( event.getTrackedEntityInstance() );
+            templateDataValue.setEventDate( event.getEventDate() );
+            templateDataValue.setDueDate( event.getDueDate() );
+            templateDataValue.setStoredBy( event.getStoredBy() );
+
+            if ( event.getCoordinate() != null )
+            {
+                templateDataValue.setLatitude( event.getCoordinate().getLatitude() );
+                templateDataValue.setLongitude( event.getCoordinate().getLongitude() );
+            }
+
+            templateDataValue.setFollowup( event.getFollowup() );
+
+            for ( DataValue value : event.getDataValues() )
+            {
+                CsvEventDataValue dataValue = new CsvEventDataValue( templateDataValue );
+                dataValue.setDataElement( value.getDataElement() );
+                dataValue.setValue( value.getValue() );
+                dataValue.setProvidedElsewhere( value.getProvidedElsewhere() );
+
+                if ( value.getStoredBy() != null )
+                {
+                    dataValue.setStoredBy( value.getStoredBy() );
+                }
+
+                dataValues.add( dataValue );
+            }
+        }
+
+        writer.writeValue( outputStream, dataValues );
+    }
+
+    private CsvEventUtils()
+    {
+    }
+}

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/event/EventController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/event/EventController.java	2014-10-04 02:37:01 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/event/EventController.java	2014-10-07 06:35:04 +0000
@@ -38,6 +38,7 @@
 import org.hisp.dhis.dxf2.events.event.EventService;
 import org.hisp.dhis.dxf2.events.event.Events;
 import org.hisp.dhis.dxf2.events.event.ImportEventTask;
+import org.hisp.dhis.dxf2.events.event.csv.CsvEventUtils;
 import org.hisp.dhis.dxf2.events.report.EventRowService;
 import org.hisp.dhis.dxf2.events.report.EventRows;
 import org.hisp.dhis.dxf2.events.trackedentity.TrackedEntityInstance;
@@ -125,6 +126,81 @@
     // READ
     // -------------------------------------------------------------------------
 
+    @RequestMapping( value = "", method = RequestMethod.GET, produces = { "application/csv", "text/csv" } )
+    @PreAuthorize( "hasRole('ALL') or hasRole('F_TRACKED_ENTITY_DATAVALUE_ADD')" )
+    public void getCsvEvents(
+        @RequestParam( required = false ) String program,
+        @RequestParam( required = false ) String programStage,
+        @RequestParam( required = false ) ProgramStatus programStatus,
+        @RequestParam( required = false ) Boolean followUp,
+        @RequestParam( required = false ) String trackedEntityInstance,
+        @RequestParam( required = false ) String orgUnit,
+        @RequestParam( required = false ) OrganisationUnitSelectionMode ouMode,
+        @RequestParam( required = false ) @DateTimeFormat( pattern = "yyyy-MM-dd" ) Date startDate,
+        @RequestParam( required = false ) @DateTimeFormat( pattern = "yyyy-MM-dd" ) Date endDate,
+        @RequestParam( required = false ) EventStatus status,
+        @RequestParam( required = false, defaultValue = "true") boolean withHeaders,
+        @RequestParam Map<String, String> parameters, Model model, HttpServletResponse response, HttpServletRequest request ) throws IOException
+    {
+        WebOptions options = new WebOptions( parameters );
+
+        Program pr = manager.get( Program.class, program );
+        ProgramStage prs = manager.get( ProgramStage.class, programStage );
+        List<OrganisationUnit> organisationUnits = new ArrayList<>();
+        TrackedEntityInstance tei = null;
+        OrganisationUnit rootOrganisationUnit = null;
+
+        if ( trackedEntityInstance != null )
+        {
+            tei = trackedEntityInstanceService.getTrackedEntityInstance( trackedEntityInstance );
+
+            if ( tei == null )
+            {
+                ContextUtils.conflictResponse( response, "Invalid trackedEntityInstance ID." );
+                return;
+            }
+        }
+
+        if ( orgUnit != null )
+        {
+            rootOrganisationUnit = manager.get( OrganisationUnit.class, orgUnit );
+
+            if ( rootOrganisationUnit == null )
+            {
+                ContextUtils.conflictResponse( response, "Invalid orgUnit ID." );
+                return;
+            }
+        }
+
+        if ( rootOrganisationUnit != null )
+        {
+            if ( OrganisationUnitSelectionMode.DESCENDANTS.equals( ouMode ) )
+            {
+                organisationUnits.addAll( organisationUnitService.getOrganisationUnitWithChildren( rootOrganisationUnit.getUid() ) );
+            }
+            else if ( OrganisationUnitSelectionMode.CHILDREN.equals( ouMode ) )
+            {
+                organisationUnits.add( rootOrganisationUnit );
+                organisationUnits.addAll( rootOrganisationUnit.getChildren() );
+            }
+            else // SELECTED
+            {
+                organisationUnits.add( rootOrganisationUnit );
+            }
+        }
+
+        Events events = eventService.getEvents( pr, prs, programStatus, followUp, organisationUnits, tei, startDate, endDate, status );
+
+        if ( options.hasPaging() )
+        {
+            Pager pager = new Pager( options.getPage(), events.getEvents().size(), options.getPageSize() );
+            events.setPager( pager );
+            events.setEvents( PagerUtils.pageCollection( events.getEvents(), pager ) );
+        }
+
+        CsvEventUtils.writeEvents( response.getOutputStream(), events, withHeaders );
+    }
+
     @RequestMapping( value = "", method = RequestMethod.GET )
     @PreAuthorize( "hasRole('ALL') or hasRole('F_TRACKED_ENTITY_DATAVALUE_ADD')" )
     public String getEvents(

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/RenderServiceMessageConverter.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/RenderServiceMessageConverter.java	2014-08-05 04:03:02 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/RenderServiceMessageConverter.java	2014-10-07 06:35:04 +0000
@@ -63,11 +63,11 @@
     {
         MediaType mediaType = inputMessage.getHeaders().getContentType();
 
-        if ( mediaType.getSubtype().equals( "json" ) )
+        if ( isJson( mediaType ) )
         {
             return renderService.fromJson( inputMessage.getBody(), clazz );
         }
-        else if ( mediaType.getSubtype().equals( "xml" ) )
+        else if ( isXml( mediaType ) )
         {
             return renderService.fromXml( inputMessage.getBody(), clazz );
         }
@@ -80,13 +80,24 @@
     {
         MediaType mediaType = outputMessage.getHeaders().getContentType();
 
-        if ( mediaType.getSubtype().equals( "json" ) )
+        if ( isJson( mediaType ) )
         {
             renderService.toJson( outputMessage.getBody(), object );
         }
-        else if ( mediaType.getSubtype().equals( "xml" ) )
+        else if ( isXml( mediaType ) )
         {
             renderService.toXml( outputMessage.getBody(), object );
         }
     }
+
+    private boolean isXml( MediaType mediaType )
+    {
+        return (mediaType.getType().equals( "application" ) || mediaType.getType().equals( "text" ))
+            && mediaType.getSubtype().equals( "xml" );
+    }
+
+    private boolean isJson( MediaType mediaType )
+    {
+        return mediaType.getType().equals( "application" ) && mediaType.getSubtype().equals( "json" );
+    }
 }

=== modified file 'dhis-2/pom.xml'
--- dhis-2/pom.xml	2014-09-24 17:24:34 +0000
+++ dhis-2/pom.xml	2014-10-07 06:35:04 +0000
@@ -920,6 +920,11 @@
         <artifactId>jackson-dataformat-xml</artifactId>
         <version>${jackson.version}</version>
       </dependency>
+      <dependency>
+        <groupId>com.fasterxml.jackson.dataformat</groupId>
+        <artifactId>jackson-dataformat-csv</artifactId>
+        <version>${jackson.version}</version>
+      </dependency>
 
       <!-- GeoTools -->
       <dependency>