← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 9307: FRED-API: Added new service, /facility-service/cql, allows for execution of CQL (command query la...

 

------------------------------------------------------------
revno: 9307
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Thu 2012-12-13 20:04:35 +0300
message:
  FRED-API: Added new service, /facility-service/cql, allows for execution of CQL (command query language) which are spatial queries (bbox, etc). Reference at http://udig.refractions.net/confluence/display/EN/Constraint+Query+Language. Post as text/plain with query in body.
removed:
  dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/ToFacilityConverter.java
  dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/ToOrganisationUnitConverter.java
added:
  dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/FacilityToOrganisationUnitConverter.java
  dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/FacilityToSimpleFeature.java
  dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/OrganisationUnitToFacilityConverter.java
  dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/OrganisationUnitToSimpleFeature.java
modified:
  dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/controller/FacilityServiceController.java
  dhis-2/dhis-web/dhis-web-api-fred/src/main/resources/META-INF/dhis/webapi-fred.xml
  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-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/controller/FacilityServiceController.java'
--- dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/controller/FacilityServiceController.java	2012-12-11 13:34:09 +0000
+++ dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/controller/FacilityServiceController.java	2012-12-13 17:04:35 +0000
@@ -27,6 +27,9 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import org.codehaus.jackson.map.ObjectMapper;
+import org.geotools.filter.text.cql2.CQL;
+import org.geotools.filter.text.cql2.CQLException;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.organisationunit.OrganisationUnitService;
 import org.hisp.dhis.web.webapi.v1.domain.Facility;
@@ -34,7 +37,10 @@
 import org.hisp.dhis.web.webapi.v1.utils.ValidationUtils;
 import org.hisp.dhis.web.webapi.v1.validation.group.Create;
 import org.hisp.dhis.web.webapi.v1.validation.group.Update;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.filter.Filter;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.core.convert.ConversionService;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpStatus;
@@ -51,14 +57,18 @@
 import javax.validation.Validator;
 import javax.validation.groups.Default;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
  */
-@Controller(value = "facility-service-controller-" + FredController.PREFIX)
-@RequestMapping(FacilityServiceController.RESOURCE_PATH)
-@PreAuthorize("hasRole('M_dhis-web-api-fred') or hasRole('ALL')")
+@Controller( value = "facility-service-controller-" + FredController.PREFIX )
+@RequestMapping( FacilityServiceController.RESOURCE_PATH )
+@PreAuthorize( "hasRole('M_dhis-web-api-fred') or hasRole('ALL')" )
 public class FacilityServiceController
 {
     public static final String RESOURCE_PATH = "/" + FredController.PREFIX + "/facility-service";
@@ -72,12 +82,16 @@
     @Autowired
     private ConversionService conversionService;
 
+    @Autowired
+    @Qualifier( "objectMapperFactoryBean" )
+    private ObjectMapper objectMapper;
+
     //--------------------------------------------------------------------------
     // EXTRA WEB METHODS
     //--------------------------------------------------------------------------
 
-    @RequestMapping(value = "/{id}/activate", method = RequestMethod.POST)
-    @PreAuthorize("hasRole('F_FRED_UPDATE') or hasRole('ALL')")
+    @RequestMapping( value = "/{id}/activate", method = RequestMethod.POST )
+    @PreAuthorize( "hasRole('F_FRED_UPDATE') or hasRole('ALL')" )
     public ResponseEntity<Void> activateFacility( @PathVariable String id )
     {
         OrganisationUnit organisationUnit = organisationUnitService.getOrganisationUnit( id );
@@ -93,8 +107,8 @@
         return new ResponseEntity<Void>( HttpStatus.NOT_FOUND );
     }
 
-    @RequestMapping(value = "/{id}/deactivate", method = RequestMethod.POST)
-    @PreAuthorize("hasRole('F_FRED_UPDATE') or hasRole('ALL')")
+    @RequestMapping( value = "/{id}/deactivate", method = RequestMethod.POST )
+    @PreAuthorize( "hasRole('F_FRED_UPDATE') or hasRole('ALL')" )
     public ResponseEntity<Void> deactivateFacility( @PathVariable String id )
     {
         OrganisationUnit organisationUnit = organisationUnitService.getOrganisationUnit( id );
@@ -110,7 +124,7 @@
         return new ResponseEntity<Void>( HttpStatus.NOT_FOUND );
     }
 
-    @RequestMapping(value = "/validate", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
+    @RequestMapping( value = "/validate", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE )
     public ResponseEntity<String> validateFacilityForCreate( @RequestBody Facility facility ) throws IOException
     {
         Set<ConstraintViolation<Facility>> constraintViolations = validator.validate( facility, Default.class, Create.class );
@@ -145,7 +159,7 @@
         }
     }
 
-    @RequestMapping(value = "/validate", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
+    @RequestMapping( value = "/validate", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE )
     public ResponseEntity<String> validateFacilityForUpdate( @RequestBody Facility facility ) throws IOException
     {
         Set<ConstraintViolation<Facility>> constraintViolations = validator.validate( facility, Default.class, Update.class );
@@ -193,4 +207,44 @@
             return new ResponseEntity<String>( json, headers, HttpStatus.UNPROCESSABLE_ENTITY );
         }
     }
+
+    @RequestMapping( value = "/cql", method = RequestMethod.POST, consumes = MediaType.TEXT_PLAIN_VALUE )
+    public ResponseEntity<String> cqlRequest( @RequestBody String cqlString ) throws IOException, CQLException
+    {
+        HttpHeaders headers = new HttpHeaders();
+        headers.add( "Content-Type", MediaType.APPLICATION_JSON_VALUE );
+
+        if ( cqlString == null || cqlString.isEmpty() )
+        {
+            return new ResponseEntity<String>( "{}", headers, HttpStatus.OK );
+        }
+
+        Filter filter = CQL.toFilter( cqlString );
+
+        List<OrganisationUnit> allOrganisationUnits = new ArrayList<OrganisationUnit>( organisationUnitService.getAllOrganisationUnits() );
+        List<Facility> facilities = new ArrayList<Facility>();
+
+        for ( OrganisationUnit organisationUnit : allOrganisationUnits )
+        {
+            if ( organisationUnit.getFeatureType() != null
+                && organisationUnit.getFeatureType().equals( OrganisationUnit.FEATURETYPE_POINT )
+                && organisationUnit.getCoordinates() != null && !organisationUnit.getCoordinates().isEmpty() )
+            {
+                SimpleFeature feature = conversionService.convert( organisationUnit, SimpleFeature.class );
+
+                if ( filter.evaluate( feature ) )
+                {
+                    Facility facility = conversionService.convert( organisationUnit, Facility.class );
+                    facilities.add( facility );
+                }
+            }
+        }
+
+        Map<String, Object> resultSet = new HashMap<String, Object>();
+        resultSet.put( "facilities", facilities );
+
+        String json = objectMapper.writeValueAsString( resultSet );
+
+        return new ResponseEntity<String>( json, headers, HttpStatus.OK );
+    }
 }

=== added file 'dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/FacilityToOrganisationUnitConverter.java'
--- dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/FacilityToOrganisationUnitConverter.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/FacilityToOrganisationUnitConverter.java	2012-12-13 17:04:35 +0000
@@ -0,0 +1,115 @@
+package org.hisp.dhis.web.webapi.v1.utils;
+
+/*
+ * Copyright (c) 2004-2012, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ *   list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import org.hisp.dhis.dataset.DataSet;
+import org.hisp.dhis.dataset.DataSetService;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.organisationunit.OrganisationUnitService;
+import org.hisp.dhis.web.webapi.v1.domain.Facility;
+import org.hisp.dhis.web.webapi.v1.domain.Identifier;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+
+import java.util.Collection;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+@Component
+public class FacilityToOrganisationUnitConverter implements Converter<Facility, OrganisationUnit>
+{
+    @Autowired
+    @Qualifier( "org.hisp.dhis.organisationunit.OrganisationUnitService" )
+    private OrganisationUnitService organisationUnitService;
+
+    @Autowired
+    @Qualifier( "org.hisp.dhis.dataset.DataSetService" )
+    private DataSetService dataSetService;
+
+    @Override
+    public OrganisationUnit convert( Facility facility )
+    {
+        OrganisationUnit organisationUnit = new OrganisationUnit();
+
+        organisationUnit.setUid( facility.getId() );
+        organisationUnit.setName( facility.getName() );
+
+        if ( facility.getName().length() > 49 )
+        {
+            organisationUnit.setShortName( facility.getName().substring( 0, 49 ) );
+        }
+        else
+        {
+            organisationUnit.setShortName( facility.getName() );
+        }
+
+        organisationUnit.setActive( facility.getActive() );
+        organisationUnit.setParent( organisationUnitService.getOrganisationUnit( (String) facility.getProperties().get( "parent" ) ) );
+
+        Collection<String> dataSets = (Collection<String>) facility.getProperties().get( "dataSets" );
+
+        if ( dataSets != null )
+        {
+            for ( String uid : dataSets )
+            {
+                DataSet dataSet = dataSetService.getDataSet( uid );
+                organisationUnit.getDataSets().add( dataSet );
+            }
+        }
+
+        if ( facility.getIdentifiers() != null )
+        {
+            for ( Identifier identifier : facility.getIdentifiers() )
+            {
+                // for now, this is the only known identifier
+                if ( identifier.getAgency().equalsIgnoreCase( Identifier.DHIS2_AGENCY )
+                    && identifier.getContext().equalsIgnoreCase( Identifier.DHIS2_CODE_CONTEXT ) )
+                {
+                    organisationUnit.setCode( identifier.getId() );
+                }
+            }
+        }
+
+        organisationUnit.setFeatureType( OrganisationUnit.FEATURETYPE_POINT );
+
+        try
+        {
+            GeoUtils.Coordinates coordinates = GeoUtils.parseCoordinates( facility.getCoordinates().toString() );
+            organisationUnit.setCoordinates( String.format( "[%f, %f]", coordinates.lng, coordinates.lat ) );
+        }
+        catch ( NumberFormatException err )
+        {
+            organisationUnit.setCoordinates( "" );
+        }
+
+        return organisationUnit;
+    }
+}

=== added file 'dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/FacilityToSimpleFeature.java'
--- dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/FacilityToSimpleFeature.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/FacilityToSimpleFeature.java	2012-12-13 17:04:35 +0000
@@ -0,0 +1,87 @@
+package org.hisp.dhis.web.webapi.v1.utils;
+
+/*
+ * 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 com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.GeometryFactory;
+import com.vividsolutions.jts.geom.Point;
+import org.geotools.data.DataUtilities;
+import org.geotools.feature.SchemaException;
+import org.geotools.feature.simple.SimpleFeatureBuilder;
+import org.geotools.geometry.jts.JTSFactoryFinder;
+import org.hisp.dhis.web.webapi.v1.domain.Facility;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+@Component
+public class FacilityToSimpleFeature implements Converter<Facility, SimpleFeature>
+{
+    private final GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
+
+    private final SimpleFeatureType featureType;
+
+    public FacilityToSimpleFeature() throws SchemaException
+    {
+        featureType = DataUtilities.createType( "Location",
+            "location:Point:srid=4326,id:String,name:String,active:Boolean" );
+    }
+
+    @Override
+    public SimpleFeature convert( Facility facility )
+    {
+        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder( featureType );
+
+        if ( facility.getCoordinates() != null && !facility.getCoordinates().isEmpty() )
+        {
+            Double lng = facility.getCoordinates().get( 0 );
+            Double lat = facility.getCoordinates().get( 1 );
+
+            if ( lng == null || lat == null )
+            {
+                return null;
+            }
+
+            Coordinate coordinate = new Coordinate( lng, lat );
+            Point point = geometryFactory.createPoint( coordinate );
+            featureBuilder.add( point );
+
+            featureBuilder.add( facility.getId() );
+            featureBuilder.add( facility.getName() );
+            featureBuilder.add( facility.getActive() );
+
+            return featureBuilder.buildFeature( null );
+        }
+
+        return null;
+    }
+}

=== added file 'dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/OrganisationUnitToFacilityConverter.java'
--- dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/OrganisationUnitToFacilityConverter.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/OrganisationUnitToFacilityConverter.java	2012-12-13 17:04:35 +0000
@@ -0,0 +1,133 @@
+package org.hisp.dhis.web.webapi.v1.utils;
+
+/*
+ * Copyright (c) 2004-2012, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ *   list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import org.hisp.dhis.dataset.DataSet;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.organisationunit.OrganisationUnitLevel;
+import org.hisp.dhis.organisationunit.OrganisationUnitService;
+import org.hisp.dhis.organisationunit.comparator.OrganisationUnitLevelComparator;
+import org.hisp.dhis.web.webapi.v1.controller.FacilityController;
+import org.hisp.dhis.web.webapi.v1.domain.Facility;
+import org.hisp.dhis.web.webapi.v1.domain.Identifier;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+@Component
+public class OrganisationUnitToFacilityConverter implements Converter<OrganisationUnit, Facility>
+{
+    @Autowired
+    private OrganisationUnitService organisationUnitService;
+
+    @Override
+    public Facility convert( OrganisationUnit organisationUnit )
+    {
+        Facility facility = new Facility();
+        facility.setId( organisationUnit.getUid() );
+        facility.setName( organisationUnit.getDisplayName() );
+        facility.setActive( organisationUnit.isActive() );
+        facility.setCreatedAt( organisationUnit.getCreated() );
+        facility.setUpdatedAt( organisationUnit.getLastUpdated() );
+        facility.setUrl( linkTo( FacilityController.class ).slash( facility.getId() ).toString() );
+
+        if ( organisationUnit.getFeatureType() != null && organisationUnit.getFeatureType().equalsIgnoreCase( "POINT" )
+            && organisationUnit.getCoordinates() != null )
+        {
+            try
+            {
+                GeoUtils.Coordinates coordinates = GeoUtils.parseCoordinates( organisationUnit.getCoordinates() );
+
+                facility.getCoordinates().add( coordinates.lng );
+                facility.getCoordinates().add( coordinates.lat );
+            }
+            catch ( NumberFormatException ignored )
+            {
+            }
+        }
+
+        if ( organisationUnit.getParent() != null )
+        {
+            facility.getProperties().put( "parent", organisationUnit.getParent().getUid() );
+        }
+
+        if ( organisationUnit.getCode() != null )
+        {
+            Identifier identifier = new Identifier();
+            identifier.setAgency( Identifier.DHIS2_AGENCY );
+            identifier.setContext( Identifier.DHIS2_CODE_CONTEXT );
+            identifier.setId( organisationUnit.getCode() );
+
+            facility.getIdentifiers().add( identifier );
+        }
+
+        List<String> dataSets = new ArrayList<String>();
+
+        for ( DataSet dataSet : organisationUnit.getDataSets() )
+        {
+            dataSets.add( dataSet.getUid() );
+        }
+
+        if ( !dataSets.isEmpty() )
+        {
+            facility.getProperties().put( "dataSets", dataSets );
+        }
+
+        facility.getProperties().put( "level", organisationUnit.getOrganisationUnitLevel() );
+
+        List<OrganisationUnitLevel> organisationUnitLevels = organisationUnitService.getOrganisationUnitLevels();
+        Collections.sort( organisationUnitLevels, new OrganisationUnitLevelComparator() );
+
+        // TODO this probably belongs in "meta": {}
+        List<Map<String, Object>> hierarchy = new ArrayList<Map<String, Object>>();
+        facility.getProperties().put( "hierarchy", hierarchy );
+
+        for ( OrganisationUnitLevel organisationUnitLevel : organisationUnitLevels )
+        {
+            Map<String, Object> level = new HashMap<String, Object>();
+
+            level.put( "name", organisationUnitLevel.getName() );
+            level.put( "level", organisationUnitLevel.getLevel() );
+
+            hierarchy.add( level );
+        }
+
+        return facility;
+    }
+}

=== added file 'dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/OrganisationUnitToSimpleFeature.java'
--- dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/OrganisationUnitToSimpleFeature.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/OrganisationUnitToSimpleFeature.java	2012-12-13 17:04:35 +0000
@@ -0,0 +1,86 @@
+package org.hisp.dhis.web.webapi.v1.utils;
+
+/*
+ * 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 com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.GeometryFactory;
+import com.vividsolutions.jts.geom.Point;
+import org.geotools.data.DataUtilities;
+import org.geotools.feature.SchemaException;
+import org.geotools.feature.simple.SimpleFeatureBuilder;
+import org.geotools.geometry.jts.JTSFactoryFinder;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.opengis.feature.simple.SimpleFeature;
+import org.opengis.feature.simple.SimpleFeatureType;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+@Component
+public class OrganisationUnitToSimpleFeature implements Converter<OrganisationUnit, SimpleFeature>
+{
+    private final GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
+
+    private final SimpleFeatureType featureType;
+
+    public OrganisationUnitToSimpleFeature() throws SchemaException
+    {
+        featureType = DataUtilities.createType( "Location",
+            "location:Point:srid=4326,id:String,name:String,active:Boolean" );
+    }
+
+    @Override
+    public SimpleFeature convert( OrganisationUnit organisationUnit )
+    {
+        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder( featureType );
+
+        if ( organisationUnit.getCoordinates() != null && !organisationUnit.getCoordinates().isEmpty() )
+        {
+            GeoUtils.Coordinates coordinates = GeoUtils.parseCoordinates( organisationUnit.getCoordinates(), GeoUtils.CoordinateOrder.COORDINATE_LNGLAT );
+
+            if ( coordinates.lng == null || coordinates.lat == null )
+            {
+                return null;
+            }
+
+            Coordinate coordinate = new Coordinate( coordinates.lng, coordinates.lat );
+            Point point = geometryFactory.createPoint( coordinate );
+            featureBuilder.add( point );
+
+            featureBuilder.add( organisationUnit.getUid() );
+            featureBuilder.add( organisationUnit.getName() );
+            featureBuilder.add( organisationUnit.isActive() );
+
+            return featureBuilder.buildFeature( null );
+        }
+
+        return null;
+    }
+}

=== removed file 'dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/ToFacilityConverter.java'
--- dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/ToFacilityConverter.java	2012-12-13 11:55:04 +0000
+++ dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/ToFacilityConverter.java	1970-01-01 00:00:00 +0000
@@ -1,133 +0,0 @@
-package org.hisp.dhis.web.webapi.v1.utils;
-
-/*
- * Copyright (c) 2004-2012, University of Oslo
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright notice, this
- *   list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright notice,
- *   this list of conditions and the following disclaimer in the documentation
- *   and/or other materials provided with the distribution.
- * * Neither the name of the HISP project nor the names of its contributors may
- *   be used to endorse or promote products derived from this software without
- *   specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-import org.hisp.dhis.dataset.DataSet;
-import org.hisp.dhis.organisationunit.OrganisationUnit;
-import org.hisp.dhis.organisationunit.OrganisationUnitLevel;
-import org.hisp.dhis.organisationunit.OrganisationUnitService;
-import org.hisp.dhis.organisationunit.comparator.OrganisationUnitLevelComparator;
-import org.hisp.dhis.web.webapi.v1.controller.FacilityController;
-import org.hisp.dhis.web.webapi.v1.domain.Facility;
-import org.hisp.dhis.web.webapi.v1.domain.Identifier;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.stereotype.Component;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
-
-/**
- * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
- */
-@Component
-public class ToFacilityConverter implements Converter<OrganisationUnit, Facility>
-{
-    @Autowired
-    private OrganisationUnitService organisationUnitService;
-
-    @Override
-    public Facility convert( OrganisationUnit organisationUnit )
-    {
-        Facility facility = new Facility();
-        facility.setId( organisationUnit.getUid() );
-        facility.setName( organisationUnit.getDisplayName() );
-        facility.setActive( organisationUnit.isActive() );
-        facility.setCreatedAt( organisationUnit.getCreated() );
-        facility.setUpdatedAt( organisationUnit.getLastUpdated() );
-        facility.setUrl( linkTo( FacilityController.class ).slash( facility.getId() ).toString() );
-
-        if ( organisationUnit.getFeatureType() != null && organisationUnit.getFeatureType().equalsIgnoreCase( "POINT" )
-            && organisationUnit.getCoordinates() != null )
-        {
-            try
-            {
-                GeoUtils.Coordinates coordinates = GeoUtils.parseCoordinates( organisationUnit.getCoordinates() );
-
-                facility.getCoordinates().add( coordinates.lng );
-                facility.getCoordinates().add( coordinates.lat );
-            }
-            catch ( NumberFormatException ignored )
-            {
-            }
-        }
-
-        if ( organisationUnit.getParent() != null )
-        {
-            facility.getProperties().put( "parent", organisationUnit.getParent().getUid() );
-        }
-
-        if ( organisationUnit.getCode() != null )
-        {
-            Identifier identifier = new Identifier();
-            identifier.setAgency( Identifier.DHIS2_AGENCY );
-            identifier.setContext( Identifier.DHIS2_CODE_CONTEXT );
-            identifier.setId( organisationUnit.getCode() );
-
-            facility.getIdentifiers().add( identifier );
-        }
-
-        List<String> dataSets = new ArrayList<String>();
-
-        for ( DataSet dataSet : organisationUnit.getDataSets() )
-        {
-            dataSets.add( dataSet.getUid() );
-        }
-
-        if ( !dataSets.isEmpty() )
-        {
-            facility.getProperties().put( "dataSets", dataSets );
-        }
-
-        facility.getProperties().put( "level", organisationUnit.getOrganisationUnitLevel() );
-
-        List<OrganisationUnitLevel> organisationUnitLevels = organisationUnitService.getOrganisationUnitLevels();
-        Collections.sort( organisationUnitLevels, new OrganisationUnitLevelComparator() );
-
-        // TODO this probably belongs in "meta": {}
-        List<Map<String, Object>> hierarchy = new ArrayList<Map<String, Object>>();
-        facility.getProperties().put( "hierarchy", hierarchy );
-
-        for ( OrganisationUnitLevel organisationUnitLevel : organisationUnitLevels )
-        {
-            Map<String, Object> level = new HashMap<String, Object>();
-
-            level.put( "name", organisationUnitLevel.getName() );
-            level.put( "level", organisationUnitLevel.getLevel() );
-
-            hierarchy.add( level );
-        }
-
-        return facility;
-    }
-}

=== removed file 'dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/ToOrganisationUnitConverter.java'
--- dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/ToOrganisationUnitConverter.java	2012-12-09 16:50:22 +0000
+++ dhis-2/dhis-web/dhis-web-api-fred/src/main/java/org/hisp/dhis/web/webapi/v1/utils/ToOrganisationUnitConverter.java	1970-01-01 00:00:00 +0000
@@ -1,115 +0,0 @@
-package org.hisp.dhis.web.webapi.v1.utils;
-
-/*
- * Copyright (c) 2004-2012, University of Oslo
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright notice, this
- *   list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright notice,
- *   this list of conditions and the following disclaimer in the documentation
- *   and/or other materials provided with the distribution.
- * * Neither the name of the HISP project nor the names of its contributors may
- *   be used to endorse or promote products derived from this software without
- *   specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-import org.hisp.dhis.dataset.DataSet;
-import org.hisp.dhis.dataset.DataSetService;
-import org.hisp.dhis.organisationunit.OrganisationUnit;
-import org.hisp.dhis.organisationunit.OrganisationUnitService;
-import org.hisp.dhis.web.webapi.v1.domain.Facility;
-import org.hisp.dhis.web.webapi.v1.domain.Identifier;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.core.convert.converter.Converter;
-import org.springframework.stereotype.Component;
-
-import java.util.Collection;
-
-/**
- * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
- */
-@Component
-public class ToOrganisationUnitConverter implements Converter<Facility, OrganisationUnit>
-{
-    @Autowired
-    @Qualifier( "org.hisp.dhis.organisationunit.OrganisationUnitService" )
-    private OrganisationUnitService organisationUnitService;
-
-    @Autowired
-    @Qualifier( "org.hisp.dhis.dataset.DataSetService" )
-    private DataSetService dataSetService;
-
-    @Override
-    public OrganisationUnit convert( Facility facility )
-    {
-        OrganisationUnit organisationUnit = new OrganisationUnit();
-
-        organisationUnit.setUid( facility.getId() );
-        organisationUnit.setName( facility.getName() );
-
-        if ( facility.getName().length() > 49 )
-        {
-            organisationUnit.setShortName( facility.getName().substring( 0, 49 ) );
-        }
-        else
-        {
-            organisationUnit.setShortName( facility.getName() );
-        }
-
-        organisationUnit.setActive( facility.getActive() );
-        organisationUnit.setParent( organisationUnitService.getOrganisationUnit( (String) facility.getProperties().get( "parent" ) ) );
-
-        Collection<String> dataSets = (Collection<String>) facility.getProperties().get( "dataSets" );
-
-        if ( dataSets != null )
-        {
-            for ( String uid : dataSets )
-            {
-                DataSet dataSet = dataSetService.getDataSet( uid );
-                organisationUnit.getDataSets().add( dataSet );
-            }
-        }
-
-        if ( facility.getIdentifiers() != null )
-        {
-            for ( Identifier identifier : facility.getIdentifiers() )
-            {
-                // for now, this is the only known identifier
-                if ( identifier.getAgency().equalsIgnoreCase( Identifier.DHIS2_AGENCY )
-                    && identifier.getContext().equalsIgnoreCase( Identifier.DHIS2_CODE_CONTEXT ) )
-                {
-                    organisationUnit.setCode( identifier.getId() );
-                }
-            }
-        }
-
-        organisationUnit.setFeatureType( OrganisationUnit.FEATURETYPE_POINT );
-
-        try
-        {
-            GeoUtils.Coordinates coordinates = GeoUtils.parseCoordinates( facility.getCoordinates().toString() );
-            organisationUnit.setCoordinates( String.format( "[%f, %f]", coordinates.lng, coordinates.lat ) );
-        }
-        catch ( NumberFormatException err )
-        {
-            organisationUnit.setCoordinates( "" );
-        }
-
-        return organisationUnit;
-    }
-}

=== modified file 'dhis-2/dhis-web/dhis-web-api-fred/src/main/resources/META-INF/dhis/webapi-fred.xml'
--- dhis-2/dhis-web/dhis-web-api-fred/src/main/resources/META-INF/dhis/webapi-fred.xml	2012-12-11 09:10:56 +0000
+++ dhis-2/dhis-web/dhis-web-api-fred/src/main/resources/META-INF/dhis/webapi-fred.xml	2012-12-13 17:04:35 +0000
@@ -18,8 +18,10 @@
   <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
     <property name="converters">
       <set>
-        <ref bean="toFacilityConverter" />
-        <ref bean="toOrganisationUnitConverter" />
+        <ref bean="facilityToOrganisationUnitConverter" />
+        <ref bean="facilityToSimpleFeature" />
+        <ref bean="organisationUnitToFacilityConverter" />
+        <ref bean="organisationUnitToSimpleFeature" />
       </set>
     </property>
   </bean>

=== modified file 'dhis-2/pom.xml'
--- dhis-2/pom.xml	2012-12-07 14:16:37 +0000
+++ dhis-2/pom.xml	2012-12-13 17:04:35 +0000
@@ -823,7 +823,7 @@
       <dependency>
         <groupId>org.geotools</groupId>
         <artifactId>gt-render</artifactId>
-        <version>8.0-M4</version>
+        <version>${geotools.version}</version>
         <exclusions>
           <exclusion>
             <groupId>xalan</groupId>
@@ -838,7 +838,7 @@
       <dependency>
         <groupId>org.geotools</groupId>
         <artifactId>gt-epsg-wkt</artifactId>
-        <version>8.0-M4</version>
+        <version>${geotools.version}</version>
         <exclusions>
           <exclusion>
             <groupId>commons-pool</groupId>
@@ -910,5 +910,6 @@
     <jackson.version>2.1.1</jackson.version>
     <camel.version>2.10.2</camel.version>
     <slf4j.version>1.6.6</slf4j.version>
+    <geotools.version>8.4</geotools.version>
   </properties>
 </project>