← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 17712: support csv, pdf, xls in web-api GET requests, only output simple types (field filtering is support...

 

------------------------------------------------------------
revno: 17712
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Tue 2014-12-16 16:45:59 +0100
message:
  support csv,pdf,xls in web-api GET requests, only output simple types (field filtering is supported), wip (only csv implemented fully)
added:
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/serializers/CsvNodeSerializer.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/serializers/ExcelNodeSerializer.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/serializers/PdfNodeSerializer.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/CsvMessageConverter.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/ExcelMessageConverter.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/PdfMessageConverter.java
modified:
  dhis-2/dhis-api/pom.xml
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/AbstractNodeSerializer.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/DefaultNodeService.java
  dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/servlet.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-api/pom.xml'
--- dhis-2/dhis-api/pom.xml	2014-11-20 18:38:54 +0000
+++ dhis-2/dhis-api/pom.xml	2014-12-16 15:45:59 +0000
@@ -56,6 +56,10 @@
       <artifactId>jackson-dataformat-xml</artifactId>
     </dependency>
     <dependency>
+      <groupId>com.fasterxml.jackson.dataformat</groupId>
+      <artifactId>jackson-dataformat-csv</artifactId>
+    </dependency>
+    <dependency>
       <groupId>org.smslib</groupId>
       <artifactId>smslib</artifactId>
     </dependency>

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/AbstractNodeSerializer.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/AbstractNodeSerializer.java	2014-07-27 16:21:57 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/AbstractNodeSerializer.java	2014-12-16 15:45:59 +0000
@@ -140,7 +140,7 @@
 
     protected abstract void endWriteCollectionNode( CollectionNode collectionNode ) throws Exception;
 
-    private void dispatcher( Node node ) throws Exception
+    protected void dispatcher( Node node ) throws Exception
     {
         switch ( node.getType() )
         {

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/DefaultNodeService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/DefaultNodeService.java	2014-06-16 10:42:58 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/DefaultNodeService.java	2014-12-16 15:45:59 +0000
@@ -28,28 +28,26 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
  */
 
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.hisp.dhis.node.types.RootNode;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import javax.annotation.PostConstruct;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.List;
 import java.util.Map;
 
-import javax.annotation.PostConstruct;
-
-import org.hisp.dhis.node.types.RootNode;
-import org.springframework.beans.factory.annotation.Autowired;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
 /**
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
  */
 public class DefaultNodeService implements NodeService
 {
-    @Autowired(required = false)
+    @Autowired( required = false )
     private List<NodeSerializer> nodeSerializers = Lists.newArrayList();
 
-    @Autowired(required = false)
+    @Autowired( required = false )
     private List<NodeDeserializer> nodeDeserializers = Lists.newArrayList();
 
     private Map<String, NodeSerializer> nodeSerializerMap = Maps.newHashMap();

=== added file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/serializers/CsvNodeSerializer.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/serializers/CsvNodeSerializer.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/serializers/CsvNodeSerializer.java	2014-12-16 15:45:59 +0000
@@ -0,0 +1,191 @@
+package org.hisp.dhis.node.serializers;
+
+/*
+ * 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.dataformat.csv.CsvFactory;
+import com.fasterxml.jackson.dataformat.csv.CsvGenerator;
+import com.fasterxml.jackson.dataformat.csv.CsvMapper;
+import com.fasterxml.jackson.dataformat.csv.CsvSchema;
+import com.google.common.collect.Lists;
+import org.hisp.dhis.node.AbstractNodeSerializer;
+import org.hisp.dhis.node.Node;
+import org.hisp.dhis.node.types.CollectionNode;
+import org.hisp.dhis.node.types.ComplexNode;
+import org.hisp.dhis.node.types.RootNode;
+import org.hisp.dhis.node.types.SimpleNode;
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.annotation.ScopedProxyMode;
+import org.springframework.stereotype.Component;
+
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+@Component
+@Scope( value = "prototype", proxyMode = ScopedProxyMode.INTERFACES )
+public class CsvNodeSerializer extends AbstractNodeSerializer
+{
+    public static final String[] CONTENT_TYPES = { "application/csv", "text/csv" };
+
+    private static CsvMapper csvMapper = new CsvMapper();
+
+    private static CsvFactory csvFactory = csvMapper.getFactory();
+
+    private CsvGenerator csvGenerator;
+
+    @Override
+    public List<String> contentTypes()
+    {
+        return Lists.newArrayList( CONTENT_TYPES );
+    }
+
+    @Override
+    protected void startSerialize( RootNode rootNode, OutputStream outputStream ) throws Exception
+    {
+        csvGenerator = csvFactory.createGenerator( outputStream );
+
+        CsvSchema.Builder schemaBuilder = CsvSchema.builder()
+            .setUseHeader( true );
+
+        // build schema
+        for ( Node child : rootNode.getChildren() )
+        {
+            if ( child.isCollection() )
+            {
+                if ( !child.getChildren().isEmpty() )
+                {
+                    Node node = child.getChildren().get( 0 );
+
+                    for ( Node property : node.getChildren() )
+                    {
+                        if ( property.isSimple() )
+                        {
+                            schemaBuilder.addColumn( property.getName() );
+                        }
+                    }
+                }
+            }
+        }
+
+        csvGenerator.setSchema( schemaBuilder.build() );
+    }
+
+    @Override
+    protected void flushStream() throws Exception
+    {
+        csvGenerator.flush();
+    }
+
+    @Override
+    protected void startWriteRootNode( RootNode rootNode ) throws Exception
+    {
+        for ( Node child : rootNode.getChildren() )
+        {
+            if ( child.isCollection() )
+            {
+                for ( Node node : child.getChildren() )
+                {
+                    csvGenerator.writeStartObject();
+
+                    for ( Node property : node.getChildren() )
+                    {
+                        if ( property.isSimple() )
+                        {
+                            writeSimpleNode( (SimpleNode) property );
+                        }
+                    }
+
+                    csvGenerator.writeEndObject();
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void endWriteRootNode( RootNode rootNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void startWriteSimpleNode( SimpleNode simpleNode ) throws Exception
+    {
+        String value = String.format( "%s", simpleNode.getValue() );
+
+        if ( Date.class.isAssignableFrom( simpleNode.getValue().getClass() ) )
+        {
+            SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ" );
+            dateFormat.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
+            value = dateFormat.format( (Date) simpleNode.getValue() );
+        }
+
+        csvGenerator.writeObjectField( simpleNode.getName(), value );
+    }
+
+    @Override
+    protected void endWriteSimpleNode( SimpleNode simpleNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void startWriteComplexNode( ComplexNode complexNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void endWriteComplexNode( ComplexNode complexNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void startWriteCollectionNode( CollectionNode collectionNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void endWriteCollectionNode( CollectionNode collectionNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void dispatcher( Node node ) throws Exception
+    {
+
+    }
+}

=== added file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/serializers/ExcelNodeSerializer.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/serializers/ExcelNodeSerializer.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/serializers/ExcelNodeSerializer.java	2014-12-16 15:45:59 +0000
@@ -0,0 +1,129 @@
+package org.hisp.dhis.node.serializers;
+
+/*
+ * 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.google.common.collect.Lists;
+import org.hisp.dhis.node.AbstractNodeSerializer;
+import org.hisp.dhis.node.types.CollectionNode;
+import org.hisp.dhis.node.types.ComplexNode;
+import org.hisp.dhis.node.types.RootNode;
+import org.hisp.dhis.node.types.SimpleNode;
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.annotation.ScopedProxyMode;
+import org.springframework.stereotype.Component;
+
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+@Component
+@Scope( value = "prototype", proxyMode = ScopedProxyMode.INTERFACES )
+public class ExcelNodeSerializer extends AbstractNodeSerializer
+{
+    public static final String[] CONTENT_TYPES = { "application/vnd.ms-excel" };
+
+    @Override
+    public List<String> contentTypes()
+    {
+        return Lists.newArrayList( CONTENT_TYPES );
+    }
+
+    @Override
+    protected void startSerialize( RootNode rootNode, OutputStream outputStream ) throws Exception
+    {
+        outputStream.write( "Hello Excel".getBytes() );
+        outputStream.flush();
+    }
+
+    @Override
+    protected void flushStream() throws Exception
+    {
+
+    }
+
+    @Override
+    protected void startWriteRootNode( RootNode rootNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void endWriteRootNode( RootNode rootNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void startWriteSimpleNode( SimpleNode simpleNode ) throws Exception
+    {
+        String value = String.format( "%s", simpleNode.getValue() );
+
+        if ( Date.class.isAssignableFrom( simpleNode.getValue().getClass() ) )
+        {
+            SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ" );
+            dateFormat.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
+            value = dateFormat.format( (Date) simpleNode.getValue() );
+        }
+    }
+
+    @Override
+    protected void endWriteSimpleNode( SimpleNode simpleNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void startWriteComplexNode( ComplexNode complexNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void endWriteComplexNode( ComplexNode complexNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void startWriteCollectionNode( CollectionNode collectionNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void endWriteCollectionNode( CollectionNode collectionNode ) throws Exception
+    {
+
+    }
+}

=== added file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/serializers/PdfNodeSerializer.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/serializers/PdfNodeSerializer.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/node/serializers/PdfNodeSerializer.java	2014-12-16 15:45:59 +0000
@@ -0,0 +1,129 @@
+package org.hisp.dhis.node.serializers;
+
+/*
+ * 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.google.common.collect.Lists;
+import org.hisp.dhis.node.AbstractNodeSerializer;
+import org.hisp.dhis.node.types.CollectionNode;
+import org.hisp.dhis.node.types.ComplexNode;
+import org.hisp.dhis.node.types.RootNode;
+import org.hisp.dhis.node.types.SimpleNode;
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.annotation.ScopedProxyMode;
+import org.springframework.stereotype.Component;
+
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+@Component
+@Scope( value = "prototype", proxyMode = ScopedProxyMode.INTERFACES )
+public class PdfNodeSerializer extends AbstractNodeSerializer
+{
+    public static final String[] CONTENT_TYPES = { "application/pdf" };
+
+    @Override
+    public List<String> contentTypes()
+    {
+        return Lists.newArrayList( CONTENT_TYPES );
+    }
+
+    @Override
+    protected void startSerialize( RootNode rootNode, OutputStream outputStream ) throws Exception
+    {
+        outputStream.write( "Hello PDF".getBytes() );
+        outputStream.flush();
+    }
+
+    @Override
+    protected void flushStream() throws Exception
+    {
+
+    }
+
+    @Override
+    protected void startWriteRootNode( RootNode rootNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void endWriteRootNode( RootNode rootNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void startWriteSimpleNode( SimpleNode simpleNode ) throws Exception
+    {
+        String value = String.format( "%s", simpleNode.getValue() );
+
+        if ( Date.class.isAssignableFrom( simpleNode.getValue().getClass() ) )
+        {
+            SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ" );
+            dateFormat.setTimeZone( TimeZone.getTimeZone( "UTC" ) );
+            value = dateFormat.format( (Date) simpleNode.getValue() );
+        }
+    }
+
+    @Override
+    protected void endWriteSimpleNode( SimpleNode simpleNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void startWriteComplexNode( ComplexNode complexNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void endWriteComplexNode( ComplexNode complexNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void startWriteCollectionNode( CollectionNode collectionNode ) throws Exception
+    {
+
+    }
+
+    @Override
+    protected void endWriteCollectionNode( CollectionNode collectionNode ) throws Exception
+    {
+
+    }
+}

=== added file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/CsvMessageConverter.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/CsvMessageConverter.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/CsvMessageConverter.java	2014-12-16 15:45:59 +0000
@@ -0,0 +1,87 @@
+package org.hisp.dhis.webapi.messageconverter;
+
+/*
+ * 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.google.common.collect.ImmutableList;
+import org.hisp.dhis.node.NodeService;
+import org.hisp.dhis.node.types.RootNode;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpInputMessage;
+import org.springframework.http.HttpOutputMessage;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.AbstractHttpMessageConverter;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.http.converter.HttpMessageNotWritableException;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+@Component
+public class CsvMessageConverter extends AbstractHttpMessageConverter<RootNode>
+{
+    public static final ImmutableList<MediaType> SUPPORTED_MEDIA_TYPES = ImmutableList.<MediaType>builder()
+        .add( new MediaType( "application", "csv" ) )
+        .add( new MediaType( "text", "csv" ) )
+        .build();
+
+    @Autowired
+    private NodeService nodeService;
+
+    public CsvMessageConverter()
+    {
+        setSupportedMediaTypes( SUPPORTED_MEDIA_TYPES );
+    }
+
+    @Override
+    protected boolean supports( Class<?> clazz )
+    {
+        return RootNode.class.equals( clazz );
+    }
+
+    @Override
+    protected boolean canRead( MediaType mediaType )
+    {
+        return false;
+    }
+
+    @Override
+    protected RootNode readInternal( Class<? extends RootNode> clazz, HttpInputMessage inputMessage ) throws IOException, HttpMessageNotReadableException
+    {
+        return null;
+    }
+
+    @Override
+    protected void writeInternal( RootNode rootNode, HttpOutputMessage outputMessage ) throws IOException, HttpMessageNotWritableException
+    {
+        nodeService.serialize( rootNode, "application/csv", outputMessage.getBody() );
+    }
+}

=== added file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/ExcelMessageConverter.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/ExcelMessageConverter.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/ExcelMessageConverter.java	2014-12-16 15:45:59 +0000
@@ -0,0 +1,86 @@
+package org.hisp.dhis.webapi.messageconverter;
+
+/*
+ * 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.google.common.collect.ImmutableList;
+import org.hisp.dhis.node.NodeService;
+import org.hisp.dhis.node.types.RootNode;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpInputMessage;
+import org.springframework.http.HttpOutputMessage;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.AbstractHttpMessageConverter;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.http.converter.HttpMessageNotWritableException;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+@Component
+public class ExcelMessageConverter extends AbstractHttpMessageConverter<RootNode>
+{
+    public static final ImmutableList<MediaType> SUPPORTED_MEDIA_TYPES = ImmutableList.<MediaType>builder()
+        .add( new MediaType( "application", "vnd.ms-excel" ) )
+        .build();
+
+    @Autowired
+    private NodeService nodeService;
+
+    public ExcelMessageConverter()
+    {
+        setSupportedMediaTypes( SUPPORTED_MEDIA_TYPES );
+    }
+
+    @Override
+    protected boolean supports( Class<?> clazz )
+    {
+        return RootNode.class.equals( clazz );
+    }
+
+    @Override
+    protected boolean canRead( MediaType mediaType )
+    {
+        return false;
+    }
+
+    @Override
+    protected RootNode readInternal( Class<? extends RootNode> clazz, HttpInputMessage inputMessage ) throws IOException, HttpMessageNotReadableException
+    {
+        return null;
+    }
+
+    @Override
+    protected void writeInternal( RootNode rootNode, HttpOutputMessage outputMessage ) throws IOException, HttpMessageNotWritableException
+    {
+        nodeService.serialize( rootNode, "application/vnd.ms-excel", outputMessage.getBody() );
+    }
+}

=== added file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/PdfMessageConverter.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/PdfMessageConverter.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/webapi/messageconverter/PdfMessageConverter.java	2014-12-16 15:45:59 +0000
@@ -0,0 +1,86 @@
+package org.hisp.dhis.webapi.messageconverter;
+
+/*
+ * 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.google.common.collect.ImmutableList;
+import org.hisp.dhis.node.NodeService;
+import org.hisp.dhis.node.types.RootNode;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpInputMessage;
+import org.springframework.http.HttpOutputMessage;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.AbstractHttpMessageConverter;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.http.converter.HttpMessageNotWritableException;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+@Component
+public class PdfMessageConverter extends AbstractHttpMessageConverter<RootNode>
+{
+    public static final ImmutableList<MediaType> SUPPORTED_MEDIA_TYPES = ImmutableList.<MediaType>builder()
+        .add( new MediaType( "application", "pdf" ) )
+        .build();
+
+    @Autowired
+    private NodeService nodeService;
+
+    public PdfMessageConverter()
+    {
+        setSupportedMediaTypes( SUPPORTED_MEDIA_TYPES );
+    }
+
+    @Override
+    protected boolean supports( Class<?> clazz )
+    {
+        return RootNode.class.equals( clazz );
+    }
+
+    @Override
+    protected boolean canRead( MediaType mediaType )
+    {
+        return false;
+    }
+
+    @Override
+    protected RootNode readInternal( Class<? extends RootNode> clazz, HttpInputMessage inputMessage ) throws IOException, HttpMessageNotReadableException
+    {
+        return null;
+    }
+
+    @Override
+    protected void writeInternal( RootNode rootNode, HttpOutputMessage outputMessage ) throws IOException, HttpMessageNotWritableException
+    {
+        nodeService.serialize( rootNode, "application/pdf", outputMessage.getBody() );
+    }
+}

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/servlet.xml'
--- dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/servlet.xml	2014-12-04 06:39:46 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/resources/META-INF/dhis/servlet.xml	2014-12-16 15:45:59 +0000
@@ -28,6 +28,9 @@
       <ref bean="jsonMessageConverter" />
       <ref bean="jsonPMessageConverter" />
       <ref bean="xmlMessageConverter" />
+      <ref bean="csvMessageConverter" />
+      <ref bean="pdfMessageConverter" />
+      <ref bean="excelMessageConverter" />
       <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
       <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
       <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>