← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 19537: ADX import - WIP

 

------------------------------------------------------------
revno: 19537
committer: Bob Jolliffe <bobjolliffe@xxxxxxxxx>
branch nick: dhis2
timestamp: Fri 2015-07-03 17:31:04 +0100
message:
  ADX import - WIP
  
  Very much can be optimized but but basics are working
  See https://github.com/dhis2/adx/tree/master/IHE/dhis for "integration testing"
added:
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/adx/ADXException.java
  dhis-2/dhis-web/dhis-web-ohie/src/main/java/org/hisp/dhis/web/ohie/adx/
  dhis-2/dhis-web/dhis-web-ohie/src/main/java/org/hisp/dhis/web/ohie/adx/webapi/
  dhis-2/dhis-web/dhis-web-ohie/src/main/java/org/hisp/dhis/web/ohie/adx/webapi/ADXController.java
modified:
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/adx/DefaultADXDataService.java
  dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/PipedImporter.java
  dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/adx/DefaultADXDataServiceTest.java
  dhis-2/dhis-web/dhis-web-ohie/src/main/resources/META-INF/dhis/webapi-ohie.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
=== added file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/adx/ADXException.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/adx/ADXException.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/adx/ADXException.java	2015-07-03 16:31:04 +0000
@@ -0,0 +1,41 @@
+package org.hisp.dhis.dxf2.adx;
+
+/*
+ * Copyright (c) 2015, UiO
+ * 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.
+ *
+ * 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 HOLDER 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.
+ */
+
+/**
+ * A simple wrapper for ADX checked exceptions
+ * 
+ * @author bobj
+ */
+public class ADXException
+    extends Exception
+{
+    public ADXException(String msg) 
+    {
+        super(msg);
+    }
+}

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/adx/DefaultADXDataService.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/adx/DefaultADXDataService.java	2015-06-19 14:55:47 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/adx/DefaultADXDataService.java	2015-07-03 16:31:04 +0000
@@ -28,20 +28,22 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import com.sun.org.apache.xml.internal.utils.XMLChar;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PipedOutputStream;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 import javax.xml.stream.XMLOutputFactory;
 import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
 import javax.xml.stream.XMLStreamException;
@@ -53,6 +55,20 @@
 import org.amplecode.staxwax.reader.XMLReader;
 import javax.xml.stream.XMLStreamReader;
 import javax.xml.stream.XMLStreamWriter;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hisp.dhis.common.IdentifiableProperty;
+import org.hisp.dhis.dataelement.CategoryComboMap;
+import org.hisp.dhis.dataelement.CategoryComboMap.CategoryComboMapException;
+import org.hisp.dhis.dataelement.DataElement;
+import org.hisp.dhis.dataelement.DataElementCategory;
+import org.hisp.dhis.dataelement.DataElementCategoryCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryOptionCombo;
+import org.hisp.dhis.dataelement.DataElementCategoryService;
+import org.hisp.dhis.dataelement.DataElementService;
+import org.hisp.dhis.dataset.DataSet;
+import org.hisp.dhis.dataset.DataSetService;
+import org.hisp.dhis.dxf2.adx.ADXPeriod.ADXPeriodException;
 import org.hisp.dhis.dxf2.datavalueset.PipedImporter;
 import org.hisp.dhis.dxf2.importsummary.ImportStatus;
 import org.hisp.dhis.dxf2.importsummary.ImportSummary;
@@ -66,24 +82,60 @@
 public class DefaultADXDataService
     implements ADXDataService
 {
-    @Autowired
-    protected DataValueSetService dataValueSetService;
+    private static final Log log = LogFactory.getLog( DefaultADXDataService.class );
 
-    protected ExecutorService executor;
+    // -------------------------------------------------------------------------
+    // Constants
+    // -------------------------------------------------------------------------
 
     public static final int PIPE_BUFFER_SIZE = 4096;
 
     public static final int TOTAL_MINUTES_TO_WAIT = 5;
 
+    // -------------------------------------------------------------------------
+    // Dependencies
+    // -------------------------------------------------------------------------
+
+    @Autowired
+    protected DataValueSetService dataValueSetService;
+
     public void setDataValueSetService( DataValueSetService dataValueSetService )
     {
         this.dataValueSetService = dataValueSetService;
     }
 
+    @Autowired
+    protected DataElementService dataElementService;
+
+    public void setDataElementService( DataElementService dataElementService )
+    {
+        this.dataElementService = dataElementService;
+    }
+
+    @Autowired
+    protected DataElementCategoryService categoryService;
+
+    public void setCategoryService( DataElementCategoryService categoryService )
+    {
+        this.categoryService = categoryService;
+    }
+
+    @Autowired
+    protected DataSetService dataSetService;
+
+    public void setDataSetService( DataSetService dataSetService )
+    {
+        this.dataSetService = dataSetService;
+    }
+
+    // -------------------------------------------------------------------------
+    // Public methods
+    // -------------------------------------------------------------------------
+    
     @Override
     public void getData( DataExportParams params, OutputStream out )
     {
-        throw new UnsupportedOperationException( "Not supported yet." );
+        throw new UnsupportedOperationException( "ADX export not supported yet." );
     }
 
     @Override
@@ -94,12 +146,16 @@
         XMLReader adxReader = XMLFactory.getXMLReader( in );
 
         ImportSummaries importSummaries = new ImportSummaries();
-
+        
         adxReader.moveToStartElement( ADXConstants.ROOT, ADXConstants.NAMESPACE );
-
-        // TODO: inject this?
-        executor = Executors.newSingleThreadExecutor();
-
+        
+        Set<DataElementCategory> attributeCategories = new HashSet<>(categoryService.getAttributeCategories());
+
+        Set<DataElementCategory> categories = new HashSet<>(categoryService.getAllDataElementCategories());
+
+        ExecutorService executor = Executors.newSingleThreadExecutor();
+        
+        // submit each ADX group to DXF importer as a datavalueSet
         while ( adxReader.moveToStartElement( ADXConstants.GROUP, ADXConstants.NAMESPACE ) )
         {
             try (PipedOutputStream pipeOut = new PipedOutputStream())
@@ -108,67 +164,266 @@
                 futureImportSummary = executor.submit(new PipedImporter( dataValueSetService, importOptions, pipeOut ) );
                 XMLOutputFactory factory = XMLOutputFactory.newInstance();
                 XMLStreamWriter dxfWriter = factory.createXMLStreamWriter( pipeOut );
-                parseADXGroupToDxf( adxReader, dxfWriter );
+                parseADXGroupToDxf( adxReader, dxfWriter, importOptions );
                 pipeOut.flush();
 
-                importSummaries.addImportSummary( futureImportSummary.get( TOTAL_MINUTES_TO_WAIT, TimeUnit.SECONDS ) );
+                importSummaries.addImportSummary( futureImportSummary.get( TOTAL_MINUTES_TO_WAIT, TimeUnit.MINUTES ) );
             } 
-            catch ( IOException | XMLStreamException | InterruptedException | ExecutionException | TimeoutException ex )
+            catch ( IOException | XMLStreamException | InterruptedException | 
+                ExecutionException | TimeoutException |ADXException | ADXPeriodException ex )
             {
                 ImportSummary importSummary = new ImportSummary();
                 importSummary.setStatus( ImportStatus.ERROR );
                 importSummary.setDescription( "Exception: " + ex.getMessage() );
                 importSummaries.addImportSummary( importSummary );
-                Logger.getLogger( DefaultADXDataService.class.getName() ).log( Level.SEVERE, null, ex );
-            }
+                log.warn( "Import failed: " + ex );
+            } 
         }
+        
+        executor.shutdown();
 
         return importSummaries;
     }
 
-    protected void parseADXGroupToDxf( XMLReader adxReader, XMLStreamWriter dxfWriter ) throws XMLStreamException
+    // -------------------------------------------------------------------------
+    // Utitility methods
+    // -------------------------------------------------------------------------
+
+    protected void parseADXGroupToDxf( XMLReader adxReader, XMLStreamWriter dxfWriter, ImportOptions importOptions ) 
+        throws XMLStreamException, ADXException, ADXPeriodException
     {
         dxfWriter.writeStartDocument( "1.0" );
         dxfWriter.writeStartElement( "dataValueSet" );
         dxfWriter.writeDefaultNamespace( "http://dhis2.org/schema/dxf/2.0"; );
 
+        IdentifiableProperty dataElementIdScheme = importOptions.getDataElementIdScheme();
+
         Map<String, String> groupAttributes = readAttributes( adxReader );
 
+        if (!groupAttributes.containsKey( "period"))
+        {
+            throw new ADXException("'period' attribute is required on 'group'");
+        }
+        
+        if (!groupAttributes.containsKey( "orgUnit"))
+        {
+            throw new ADXException("'orgUnit' attribute is required on 'group'");
+        }
+
+        // translate adx period to dxf2
         String periodStr = groupAttributes.get( ADXConstants.PERIOD );
         groupAttributes.remove( ADXConstants.PERIOD );
-
         Period period = ADXPeriod.parse( periodStr );
         dxfWriter.writeAttribute( "period", period.getIsoDate() );
+
+        // process adx group attributes
+        if (!groupAttributes.containsKey( "attributeOptionCombo") && groupAttributes.containsKey( "dataSet"))
+        {
+            log.debug( "No attributeOptionCombo present.  Check dataSet for attribute categorycombo");
+            
+            DataSet dataSet = getDataSetByIdentifier( groupAttributes.get( "dataSet"), dataElementIdScheme );
+            groupAttributes.put( "dataSet", dataSet.getUid());
+            DataElementCategoryCombo attributeCombo = dataSet.getCategoryCombo();
+            attributesToDXF("attributeOptionCombo", attributeCombo, groupAttributes, dataElementIdScheme);
+        }
         
-        // pass through the remaining attributes to dxf
+        // write the remaining attributes through to dxf stream
         for ( String attribute : groupAttributes.keySet() )
         {
             dxfWriter.writeAttribute( attribute, groupAttributes.get( attribute ) );
         }
-
+        
+        // process the dataValues
         while ( adxReader.moveToStartElement( ADXConstants.DATAVALUE, ADXConstants.GROUP ) )
         {
-            parseADXDataValueToDxf( adxReader, dxfWriter );
+            parseADXDataValueToDxf( adxReader, dxfWriter, importOptions );
         }
+        
         dxfWriter.writeEndElement();
         dxfWriter.writeEndDocument();
     }
 
-    protected void parseADXDataValueToDxf( XMLReader adxReader, XMLStreamWriter dxfWriter ) throws XMLStreamException
+    protected void parseADXDataValueToDxf( XMLReader adxReader, XMLStreamWriter dxfWriter,  ImportOptions importOptions ) 
+        throws XMLStreamException, ADXException
     {
+        Map<String, String> dvAttributes = readAttributes( adxReader );
+
+        if (!dvAttributes.containsKey( "dataElement"))
+        {
+            throw new ADXException("'dataElement' attribute is required on 'dataValue'");
+        }
+        
+        if (!dvAttributes.containsKey( "value"))
+        {
+            throw new ADXException("'value' attribute is required on 'dataValue'");
+        }
+        
+        IdentifiableProperty dataElementIdScheme = importOptions.getDataElementIdScheme();
+
         dxfWriter.writeStartElement( "dataValue" );
-
-        Map<String, String> groupAttributes = readAttributes( adxReader );
-
+        
+        DataElement dataElement = getDataElementByIdentifier( dvAttributes.get( "dataElement"), dataElementIdScheme );
+        DataElementCategoryCombo categoryCombo = dataElement.getCategoryCombo();
+            
+        attributesToDXF("categoryOptionCombo", categoryCombo, dvAttributes, dataElementIdScheme);
+        
+        // if dataelement type is string we need to pick out the 'annotation' element
+        if (dataElement.getType().equals( DataElement.VALUE_TYPE_STRING ))
+        {
+            adxReader.moveToStartElement( "annotation", "datavalue");
+            if (adxReader.isStartElement("annotation"))
+            {
+                String textValue = adxReader.getElementValue();
+                dvAttributes.put( "value", textValue);
+            }
+            else
+            {
+                throw new ADXException("Dataelement " + dataElement.getShortName() + " expects text annotation");
+            }
+        }
         // pass through the remaining attributes to dxf
-        for ( String attribute : groupAttributes.keySet() )
+        for ( String attribute : dvAttributes.keySet() )
         {
-            dxfWriter.writeAttribute( attribute, groupAttributes.get( attribute ) );
+            dxfWriter.writeAttribute( attribute, dvAttributes.get( attribute ) );
         }
         dxfWriter.writeEndElement();
     }
-
-    // TODO  this should really be part of staxwax library
+    
+    protected Map<String,DataElementCategory> createCategoryMap(DataElementCategoryCombo catcombo) 
+        throws ADXException
+    {
+        Map<String,DataElementCategory> categoryMap = new HashMap<>();
+        
+        List<DataElementCategory> categories = catcombo.getCategories();
+            
+        for (DataElementCategory category : categories)
+        {
+            String categoryCode = category.getCode();
+            if (categoryCode==null || !XMLChar.isValidName( categoryCode ))
+            {
+                throw new ADXException("Category code for " + category.getName() + " is missing or invalid: "+ categoryCode);
+            }
+            categoryMap.put( category.getCode(), category);
+        }
+        
+        return categoryMap;
+    }
+    
+    protected DataElementCategoryOptionCombo getCatOptComboFromAttributes (Map<String,String> attributes, 
+            DataElementCategoryCombo catcombo, IdentifiableProperty scheme) 
+            throws ADXException
+    {
+
+        CategoryComboMap catcomboMap;
+        try
+        {
+            catcomboMap = new CategoryComboMap(catcombo, scheme);
+            log.debug(catcomboMap.toString());
+
+        } catch ( CategoryComboMapException ex )
+        {
+            log.warn("Failed to create catcomboMap from " + catcombo);
+            throw new ADXException(ex.getMessage());
+        }
+        
+        String compositeIdentifier ="";
+        for (DataElementCategory category : catcomboMap.getCategories())
+        {
+            String catCode = category.getCode();
+            if (catCode == null) 
+                throw new RuntimeException("No category matching " + catCode);
+            String catAttribute = attributes.get(catCode);
+            if (catAttribute == null) 
+                throw new RuntimeException("Missing required attribute from catcombo: " + catCode);
+            compositeIdentifier += "\"" + catAttribute + "\"";
+        }
+        DataElementCategoryOptionCombo catoptcombo = catcomboMap.getCategoryOptionCombo(compositeIdentifier);
+        
+        if (catoptcombo == null)
+        {
+            throw new ADXException("Invalid attributes:" + attributes);
+        }
+        return catoptcombo; 
+    }
+    
+    protected void attributesToDXF( String optionComboName, DataElementCategoryCombo catCombo, Map<String, String> attributes, IdentifiableProperty scheme ) 
+        throws ADXException
+    {
+        log.debug("adx attributes: " + attributes);
+        
+        if (catCombo == categoryService.getDefaultDataElementCategoryCombo()) 
+        {
+            // nothing to do
+            return;
+        }
+        Map<String,DataElementCategory> categoryMap = createCategoryMap(catCombo);
+            
+        Map<String,String> attributeOptions = new HashMap<>();
+        Set<String> attributeKeys = attributes.keySet();
+        for (String category :  categoryMap.keySet())
+        {
+            if (attributes.containsKey( category))
+            {
+                attributeOptions.put( category, attributes.get( category) );
+                attributes.remove( category );
+            }
+            else
+            {
+                throw new ADXException ("catcombo " + catCombo.getName() + " must have " + categoryMap.get( category).getName());
+            }
+         }
+            
+        DataElementCategoryOptionCombo catOptCombo = getCatOptComboFromAttributes( attributeOptions, catCombo, scheme);
+        attributes.put( optionComboName, catOptCombo.getUid());
+        
+        log.debug("dxf attributes: " + attributes);
+    }
+    
+    // -------------------------------------------------------------------------
+    // The following methods are very general and should probably be implemented elsewhere
+    // -------------------------------------------------------------------------
+
+    protected DataSet getDataSetByIdentifier(String id, IdentifiableProperty scheme) throws ADXException
+    {
+        DataSet dataSet = null;
+        switch (scheme) {
+            case CODE:
+                dataSet = dataSetService.getDataSetByCode( id );
+                break;
+            case UID:
+                dataSet = dataSetService.getDataSet(id );
+                break;
+            default:
+                throw new ADXException("Only CODE or UID supported for dataSet identifier");
+        }
+        
+        if (dataSet==null)
+            throw new ADXException("No dataSet matching " + id);
+        
+        return dataSet;
+    }
+
+    protected DataElement getDataElementByIdentifier(String id, IdentifiableProperty scheme) throws ADXException
+    {
+        DataElement dataElement = null;
+        switch (scheme) {
+            case CODE:
+                dataElement = dataElementService.getDataElementByCode( id );
+                break;
+            case UID:
+                dataElement = dataElementService.getDataElement(id );
+                break;
+            default:
+                throw new ADXException("Only CODE or UID supported for dataElement identifier");
+        }
+        
+        if (dataElement==null)
+            throw new ADXException("No dataElement matching " + id);
+        
+        return dataElement;
+    }
+
+    // TODO  this should be part of staxwax library
     protected Map<String, String> readAttributes( XMLReader staxWaxReader ) throws XMLStreamException
     {
         Map<String, String> attributes = new HashMap<>();
@@ -188,4 +443,5 @@
 
         return attributes;
     }
+
 }

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/PipedImporter.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/PipedImporter.java	2015-06-19 21:34:53 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/PipedImporter.java	2015-07-03 16:31:04 +0000
@@ -37,7 +37,6 @@
 import org.hisp.dhis.dxf2.common.ImportOptions;
 import org.hisp.dhis.dxf2.importsummary.ImportStatus;
 import org.hisp.dhis.dxf2.importsummary.ImportSummary;
-import org.hisp.dhis.user.CurrentUserService;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
 
@@ -61,7 +60,7 @@
 
     private final ImportOptions importOptions;
 
-    private Authentication authentication;
+    private final Authentication authentication;
 
     public PipedImporter( DataValueSetService dataValueSetService, ImportOptions importOptions, PipedOutputStream pipeOut )
         throws IOException

=== modified file 'dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/adx/DefaultADXDataServiceTest.java'
--- dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/adx/DefaultADXDataServiceTest.java	2015-06-19 14:55:47 +0000
+++ dhis-2/dhis-services/dhis-service-dxf2/src/test/java/org/hisp/dhis/dxf2/adx/DefaultADXDataServiceTest.java	2015-07-03 16:31:04 +0000
@@ -30,7 +30,9 @@
 
 import java.io.InputStream;
 import org.hisp.dhis.DhisSpringTest;
+import static org.hisp.dhis.common.IdentifiableProperty.CODE;
 import org.hisp.dhis.datavalue.DataValue;
+import org.hisp.dhis.dxf2.common.ImportOptions;
 import org.hisp.dhis.dxf2.datavalueset.DataValueSetService;
 import org.hisp.dhis.dxf2.importsummary.ImportSummaries;
 import org.hisp.dhis.jdbc.batchhandler.DataValueBatchHandler;
@@ -75,7 +77,11 @@
     {
         InputStream in = new ClassPathResource( SIMPLE_ADX_SAMPLE ).getInputStream();
         
-        ImportSummaries importSummaries =  adxDataService.postData(in, null);
+        ImportOptions options = new ImportOptions();
+        options.setDataElementIdScheme( "CODE");
+        options.setOrgUnitIdScheme( "CODE" );
+        
+        ImportSummaries importSummaries =  adxDataService.postData(in, options);
         
         assertEquals(importSummaries.getImportSummaries().size(), 2);
         // only testing this far .. summaries are full of conflicts for now ...

=== added directory 'dhis-2/dhis-web/dhis-web-ohie/src/main/java/org/hisp/dhis/web/ohie/adx'
=== added directory 'dhis-2/dhis-web/dhis-web-ohie/src/main/java/org/hisp/dhis/web/ohie/adx/webapi'
=== added file 'dhis-2/dhis-web/dhis-web-ohie/src/main/java/org/hisp/dhis/web/ohie/adx/webapi/ADXController.java'
--- dhis-2/dhis-web/dhis-web-ohie/src/main/java/org/hisp/dhis/web/ohie/adx/webapi/ADXController.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-ohie/src/main/java/org/hisp/dhis/web/ohie/adx/webapi/ADXController.java	2015-07-03 16:31:04 +0000
@@ -0,0 +1,79 @@
+package org.hisp.dhis.web.ohie.adx.webapi;
+
+/*
+ * Copyright (c) 2004-2015, 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.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hisp.dhis.dxf2.common.ImportOptions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+import org.hisp.dhis.dxf2.adx.ADXDataService;
+import org.hisp.dhis.dxf2.common.JacksonUtils;
+import org.hisp.dhis.dxf2.importsummary.ImportSummaries;
+
+import static org.hisp.dhis.webapi.utils.ContextUtils.*;
+
+/**
+ *
+ * @author bobj
+ */
+
+@Controller
+@RequestMapping( value = ADXController.RESOURCE_PATH )
+public class ADXController
+{
+    public static final String RESOURCE_PATH = "/dataValueSets";
+
+    private static final Log log = LogFactory.getLog( ADXController.class );
+
+    @Autowired
+    private ADXDataService adxService;
+
+    @RequestMapping( method = RequestMethod.POST, consumes = "application/xml" )
+    @PreAuthorize( "hasRole('ALL') or hasRole('F_DATAVALUE_ADD')" )
+    public void postXMLDataValueSet( ImportOptions importOptions,
+        HttpServletResponse response, InputStream in, Model model ) throws IOException
+    {
+        ImportSummaries importSummaries = adxService.postData( in, importOptions );
+        
+        log.debug( "Data values set saved" );
+
+        response.setContentType( CONTENT_TYPE_XML );
+        JacksonUtils.toXml( response.getOutputStream(), importSummaries );
+    }
+
+}

=== modified file 'dhis-2/dhis-web/dhis-web-ohie/src/main/resources/META-INF/dhis/webapi-ohie.xml'
--- dhis-2/dhis-web/dhis-web-ohie/src/main/resources/META-INF/dhis/webapi-ohie.xml	2015-05-11 07:10:34 +0000
+++ dhis-2/dhis-web/dhis-web-ohie/src/main/resources/META-INF/dhis/webapi-ohie.xml	2015-07-03 16:31:04 +0000
@@ -16,6 +16,8 @@
 
   <context:component-scan base-package="org.hisp.dhis.web.ohie.csd" />
 
+  <context:component-scan base-package="org.hisp.dhis.web.ohie.adx"  />
+
   <context:annotation-config />
 
   <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
@@ -100,5 +102,5 @@
       </list>
     </property>
   </bean>
-
+  
 </beans>