← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 15089: Applied patch from James Chang. Adds support for identifying organisation units based on coordina...

 

------------------------------------------------------------
revno: 15089
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Tue 2014-04-29 11:26:28 +0200
message:
  Applied patch from James Chang. Adds support for identifying organisation units based on coordinates/location through web api.
added:
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/filter/OrganisationUnitPolygonCoveringCoordinateFilter.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/organisationunit/OrganisationUnitLocationController.java
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java
  dhis-2/dhis-support/dhis-support-system/pom.xml
  dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/GeoUtils.java
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/organisationunit/OrganisationUnitController.java
  dhis-2/pom.xml


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java	2014-04-28 18:23:49 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/organisationunit/OrganisationUnitService.java	2014-04-29 09:26:28 +0000
@@ -388,7 +388,21 @@
      * 
      * @return collection of objects.
      */
-    Collection<OrganisationUnit> getWithinCoordinateArea( double longitude, double latitude, double distance );
+    Collection<OrganisationUnit> getOrganisationUnitWithinDistance( double longitude, double latitude, double distance );
+
+    /**
+     * Retrieves the orgunit(s) by coordinate.
+     * 
+     * @param longitude The longitude of the location.
+     * @param latitude The latitude of the location.
+     * @param topOrgUnitUid Optional. Uid of the search top level org unit (ex.
+     *        Country level orgunit)
+     * @param targetLevel Optional. The level being searched.
+     * 
+     * @return collection of objects.
+     */
+    Collection<OrganisationUnit> getOrganisationUnitByCoordinate( double longitude, double latitude, String topOrgUnitUid,
+        Integer targetLevel );
     
     boolean isInUserHierarchy( OrganisationUnit organisationUnit );
     

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java	2014-04-28 18:23:49 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/organisationunit/DefaultOrganisationUnitService.java	2014-04-29 09:26:28 +0000
@@ -29,12 +29,14 @@
  */
 
 import com.google.common.collect.Maps;
+
 import org.apache.commons.collections.CollectionUtils;
 import org.hisp.dhis.common.IdentifiableObjectUtils;
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.hierarchy.HierarchyViolationException;
 import org.hisp.dhis.i18n.I18nService;
 import org.hisp.dhis.organisationunit.comparator.OrganisationUnitLevelComparator;
+import org.hisp.dhis.system.filter.OrganisationUnitPolygonCoveringCoordinateFilter;
 import org.hisp.dhis.system.util.ConversionUtils;
 import org.hisp.dhis.system.util.Filter;
 import org.hisp.dhis.system.util.FilterUtils;
@@ -840,9 +842,14 @@
         return organisationUnitLevelStore.getMaxLevels();
     }
 
-    public Collection<OrganisationUnit> getWithinCoordinateArea( double longitude, double latitude, double distance )
+    /**
+     * Get all the Organisation Units within the distance of a coordinate.
+     */
+    public Collection<OrganisationUnit> getOrganisationUnitWithinDistance( double longitude, double latitude,
+        double distance )
     {
-        Collection<OrganisationUnit> objects = organisationUnitStore.getWithinCoordinateArea( GeoUtils.getBoxShape( longitude, latitude, distance ) );
+        Collection<OrganisationUnit> objects = organisationUnitStore.getWithinCoordinateArea( GeoUtils.getBoxShape(
+            longitude, latitude, distance ) );
 
         // Go through the list and remove the ones located outside radius
         
@@ -869,6 +876,77 @@
         return objects;
     }
 
+    /**
+     * Get lowest level/target level Organisation Units that includes the coordinates.
+     */
+    public Collection<OrganisationUnit> getOrganisationUnitByCoordinate( double longitude, double latitude,
+        String topOrgUnitUid, Integer targetLevel )
+    {
+        Collection<OrganisationUnit> orgUnits = new ArrayList<OrganisationUnit>();
+
+        if ( GeoUtils.checkGeoJsonPointValid( longitude, latitude ) )
+        {
+            OrganisationUnit topOrgUnit = null;
+
+            if ( topOrgUnitUid != null && !topOrgUnitUid.isEmpty() )
+            {
+                topOrgUnit = getOrganisationUnit( topOrgUnitUid );
+            }
+            else
+            {
+                // Get top search point through top level org unit which contains coordinate
+                
+                Collection<OrganisationUnit> orgUnitsTopLevel = getTopLevelOrgUnitWithPoint( longitude, latitude, 1,
+                    getNumberOfOrganisationalLevels() - 1 );
+
+                if ( orgUnitsTopLevel.size() == 1 )
+                {
+                    topOrgUnit = orgUnitsTopLevel.iterator().next();
+                }
+            }
+
+            // Search children org units to get the lowest level org unit that contains coordinate
+            
+            if ( topOrgUnit != null )
+            {
+                Collection<OrganisationUnit> orgUnitChildren = new ArrayList<OrganisationUnit>();
+
+                if ( targetLevel != null )
+                {
+                    orgUnitChildren = getOrganisationUnitsAtLevel( targetLevel, topOrgUnit );
+                }
+                else
+                {
+                    orgUnitChildren = getOrganisationUnitWithChildren( topOrgUnit.getId() );
+                }
+
+                FilterUtils.filter( orgUnitChildren, new OrganisationUnitPolygonCoveringCoordinateFilter( longitude, latitude ) );
+                
+                // Get org units with lowest level
+                
+                int bottomLevel = topOrgUnit.getLevel();
+
+                for ( OrganisationUnit ou : orgUnitChildren )
+                {
+                    if ( ou.getLevel() > bottomLevel )
+                    {
+                        bottomLevel = ou.getLevel();
+                    }
+                }
+
+                for ( OrganisationUnit ou : orgUnitChildren )
+                {
+                    if ( ou.getLevel() == bottomLevel )
+                    {
+                        orgUnits.add( ou );
+                    }
+                }
+            }
+        }
+
+        return orgUnits;
+    }
+
     // -------------------------------------------------------------------------
     // Version
     // -------------------------------------------------------------------------
@@ -878,4 +956,28 @@
     {
         versionService.updateVersion( VersionService.ORGANISATIONUNIT_VERSION );
     }
+
+    // -------------------------------------------------------------------------
+    // Supportive methods
+    // -------------------------------------------------------------------------
+
+    /**
+     * Searches organisation units until finding one with polygon containing point.
+     */
+    private List<OrganisationUnit> getTopLevelOrgUnitWithPoint( double longitude, double latitude, 
+        int searchLevel, int stopLevel )
+    {
+        for ( int i = searchLevel; i <= stopLevel; i++ )
+        {
+            List<OrganisationUnit> unitsAtLevel = new ArrayList<OrganisationUnit>( getOrganisationUnitsAtLevel( i ) );
+            FilterUtils.filter( unitsAtLevel, new OrganisationUnitPolygonCoveringCoordinateFilter( longitude, latitude ) );
+            
+            if ( unitsAtLevel.size() > 0 )
+            {
+                return unitsAtLevel;
+            }
+        }
+
+        return new ArrayList<OrganisationUnit>();
+    }
 }

=== modified file 'dhis-2/dhis-support/dhis-support-system/pom.xml'
--- dhis-2/dhis-support/dhis-support-system/pom.xml	2014-04-22 15:46:19 +0000
+++ dhis-2/dhis-support/dhis-support-system/pom.xml	2014-04-29 09:26:28 +0000
@@ -58,8 +58,12 @@
     <dependency>
       <groupId>org.geotools</groupId>
       <artifactId>gt-referencing</artifactId>
-    </dependency>
-    
+    </dependency> 
+	<dependency>
+	  <groupId>org.geotools</groupId>
+	  <artifactId>gt-geojson</artifactId>
+	</dependency>   
+	    
     <!-- Other -->
     
     <dependency>

=== added file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/filter/OrganisationUnitPolygonCoveringCoordinateFilter.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/filter/OrganisationUnitPolygonCoveringCoordinateFilter.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/filter/OrganisationUnitPolygonCoveringCoordinateFilter.java	2014-04-29 09:26:28 +0000
@@ -0,0 +1,65 @@
+package org.hisp.dhis.system.filter;
+
+/*
+ * 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 org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.system.util.Filter;
+import org.hisp.dhis.system.util.GeoUtils;
+
+public class OrganisationUnitPolygonCoveringCoordinateFilter
+    implements Filter<OrganisationUnit>
+{    
+    private double longitude;
+    private double latitude;
+    
+    public OrganisationUnitPolygonCoveringCoordinateFilter( double longitude, double latitude )
+    {
+        this.longitude = longitude;
+        this.latitude = latitude;
+    }
+    
+    @Override
+    public boolean retain( OrganisationUnit unit )
+    {
+        String featureType = unit.getFeatureType();
+        String coordinate = unit.getCoordinates();
+
+        if ( featureType != null
+            && coordinate != null
+            && !coordinate.isEmpty()
+            && ( featureType.equals( OrganisationUnit.FEATURETYPE_POLYGON )
+            || featureType.equals( OrganisationUnit.FEATURETYPE_MULTIPOLYGON ) )
+            && GeoUtils.checkPointWithMultiPolygon( longitude, latitude, unit.getCoordinates(), featureType ) )
+        {
+            return true;
+        }
+        
+        return false;
+    }
+}

=== modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/GeoUtils.java'
--- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/GeoUtils.java	2014-04-18 07:35:00 +0000
+++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/GeoUtils.java	2014-04-29 09:26:28 +0000
@@ -29,8 +29,16 @@
  */
 
 import java.awt.geom.Point2D;
+import java.io.IOException;
+import java.io.StringReader;
 
+import org.geotools.geojson.geom.GeometryJSON;
 import org.geotools.referencing.GeodeticCalculator;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+
+import com.vividsolutions.jts.geom.MultiPolygon;
+import com.vividsolutions.jts.geom.Point;
+import com.vividsolutions.jts.geom.Polygon;
 
 /**
  * @author Lars Helge Overland
@@ -93,5 +101,76 @@
         calc.setDestinationGeographicPoint( to);
         
         return calc.getOrthodromicDistance();
-    }    
+    }
+
+    /**
+     * Get GeometryJSON point.
+     */
+    public static Point getGeoJsonPoint( double longitude, double latitude )
+        throws IOException
+    {
+        Point point = null;
+
+        GeometryJSON gtjson = new GeometryJSON();
+
+        point = gtjson.readPoint( new StringReader( "{\"type\":\"Point\", \"coordinates\":[" + longitude + ","
+            + latitude + "]}" ) );
+
+        return point;
+    }
+
+    /**
+     * Check if GeometryJSON point created with this coordinate is valid.
+     */
+    public static boolean checkGeoJsonPointValid( double longitude, double latitude )
+    {
+        try
+        {
+            return getGeoJsonPoint( longitude, latitude ).isValid();
+        }
+        catch ( Exception ex )
+        {
+            return false;
+        }
+    }
+
+    /**
+     * Check if the point coordinate falls within the polygon/MultiPolygon Shape
+     */
+    public static boolean checkPointWithMultiPolygon( double longitude, double latitude, 
+        String multiPolygonJson, String featureType )
+    {
+        try
+        {
+            boolean contains = false;
+
+            GeometryJSON gtjson = new GeometryJSON();
+
+            Point point = getGeoJsonPoint( longitude, latitude );
+
+            if ( point != null && point.isValid() )
+            {
+                if ( featureType.compareTo( OrganisationUnit.FEATURETYPE_POLYGON ) == 0 )
+                {
+                    Polygon polygon = gtjson.readPolygon( new StringReader( 
+                        "{\"type\":\"Polygon\", \"coordinates\":" + multiPolygonJson + "}" ) );
+
+                    contains = polygon.contains( point );
+                }
+                else if ( featureType.compareTo( OrganisationUnit.FEATURETYPE_MULTIPOLYGON ) == 0 )
+                {
+                    MultiPolygon multiPolygon = gtjson.readMultiPolygon( new StringReader(
+                        "{\"type\":\"MultiPolygon\", \"coordinates\":" + multiPolygonJson + "}" ) );
+
+                    contains = multiPolygon.contains( point );
+                }
+            }
+
+            return contains;
+        }
+        catch ( Exception ex )
+        {
+            return false;
+        }
+    }
 }

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/organisationunit/OrganisationUnitController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/organisationunit/OrganisationUnitController.java	2014-04-18 07:35:00 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/organisationunit/OrganisationUnitController.java	2014-04-29 09:26:28 +0000
@@ -28,19 +28,22 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
 import org.hisp.dhis.api.controller.AbstractCrudController;
 import org.hisp.dhis.api.controller.WebMetaData;
 import org.hisp.dhis.api.controller.WebOptions;
 import org.hisp.dhis.api.controller.exception.NotFoundException;
 import org.hisp.dhis.api.utils.WebUtils;
-import org.hisp.dhis.attribute.Attribute;
-import org.hisp.dhis.attribute.AttributeValue;
 import org.hisp.dhis.common.Pager;
 import org.hisp.dhis.dxf2.metadata.MetaData;
-import org.hisp.dhis.dxf2.utils.JacksonUtils;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
-import org.hisp.dhis.organisationunit.OrganisationUnitGroup;
-import org.hisp.dhis.organisationunit.OrganisationUnitGroupSet;
 import org.hisp.dhis.organisationunit.OrganisationUnitService;
 import org.hisp.dhis.organisationunit.comparator.OrganisationUnitByLevelComparator;
 import org.hisp.dhis.user.CurrentUserService;
@@ -54,14 +57,6 @@
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 /**
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
  */
@@ -269,46 +264,4 @@
         return StringUtils.uncapitalize( getEntitySimpleName() );
     }
 
-    @RequestMapping(value = "/withinRange", method = RequestMethod.GET, produces = { "*/*", "application/json" })
-    public void getEntitiesWithinRange( @RequestParam Double longitude, @RequestParam Double latitude,
-        @RequestParam Double distance, @RequestParam(required = false) String orgUnitGroupSetId,
-        Model model, HttpServletRequest request, HttpServletResponse response ) throws Exception
-    {
-        List<OrganisationUnit> entityList = new ArrayList<OrganisationUnit>( organisationUnitService.getWithinCoordinateArea( longitude, latitude, distance ) );
-
-        for ( OrganisationUnit orgunit : entityList )
-        {
-            Set<AttributeValue> attributeValues = orgunit.getAttributeValues();
-            attributeValues.clear();
-
-            if ( orgUnitGroupSetId != null ) // Add org unit group symbol into attr
-            {
-                for ( OrganisationUnitGroup orgunitGroup : orgunit.getGroups() )
-                {
-                    if ( orgunitGroup.getGroupSet() != null )
-                    {
-                        OrganisationUnitGroupSet orgunitGroupSet = orgunitGroup.getGroupSet();
-
-                        if ( orgunitGroupSet.getUid().compareTo( orgUnitGroupSetId ) == 0 )
-                        {
-                            AttributeValue attributeValue = new AttributeValue();
-                            attributeValue.setAttribute( new Attribute( "OrgUnitGroupSymbol", "OrgUnitGroupSymbol" ) );
-                            attributeValue.setValue( orgunitGroup.getSymbol() );
-
-                            attributeValues.add( attributeValue );
-                        }
-                    }
-                }
-            }
-
-            orgunit.setAttributeValues( attributeValues );
-
-            // Clear out all data not needed for this task
-            orgunit.removeAllDataSets();
-            orgunit.removeAllUsers();
-            orgunit.removeAllOrganisationUnitGroups();
-        }
-
-        JacksonUtils.toJson( response.getOutputStream(), entityList );
-    }
 }

=== added file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/organisationunit/OrganisationUnitLocationController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/organisationunit/OrganisationUnitLocationController.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/organisationunit/OrganisationUnitLocationController.java	2014-04-29 09:26:28 +0000
@@ -0,0 +1,179 @@
+package org.hisp.dhis.api.controller.organisationunit;
+
+/*
+ * Copyright (c) 2004-2013, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the HISP project nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.hisp.dhis.attribute.Attribute;
+import org.hisp.dhis.attribute.AttributeValue;
+import org.hisp.dhis.dxf2.utils.JacksonUtils;
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.organisationunit.OrganisationUnitGroup;
+import org.hisp.dhis.organisationunit.OrganisationUnitGroupSet;
+import org.hisp.dhis.organisationunit.OrganisationUnitService;
+import org.hisp.dhis.system.filter.OrganisationUnitPolygonCoveringCoordinateFilter;
+import org.hisp.dhis.system.util.FilterUtils;
+import org.hisp.dhis.user.CurrentUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+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 org.springframework.web.bind.annotation.RequestParam;
+
+/**
+ * @author James Chang <jamesbchang@xxxxxxxxx>
+ */
+@Controller
+@RequestMapping( value = OrganisationUnitLocationController.RESOURCE_PATH )
+public class OrganisationUnitLocationController
+{
+    public static final String RESOURCE_PATH = "/organisationUnitLocations";
+    
+    private static final String ORGUNIGROUP_SYMBOL = "orgUnitGroupSymbol";
+
+    @Autowired
+    private OrganisationUnitService organisationUnitService;
+
+    @Autowired
+    private CurrentUserService currentUserService;
+
+    /**
+     * Get Organisation Units within a distance from a location
+     */
+    @RequestMapping( value = "/withinRange", method = RequestMethod.GET, produces = { "*/*", "application/json" } )
+    public void getEntitiesWithinRange( 
+        @RequestParam Double longitude, 
+        @RequestParam Double latitude, 
+        @RequestParam Double distance, 
+        @RequestParam( required = false ) String orgUnitGroupSetId, 
+        Model model, HttpServletRequest request, HttpServletResponse response )
+        throws Exception
+    {
+        List<OrganisationUnit> entityList = new ArrayList<OrganisationUnit>(
+            organisationUnitService.getOrganisationUnitWithinDistance( longitude, latitude, distance ) );
+
+        for ( OrganisationUnit orgunit : entityList )
+        {
+            Set<AttributeValue> attributeValues = orgunit.getAttributeValues();
+            attributeValues.clear();
+
+            if ( orgUnitGroupSetId != null )
+            {
+                for ( OrganisationUnitGroup orgunitGroup : orgunit.getGroups() )
+                {
+                    if ( orgunitGroup.getGroupSet() != null )
+                    {
+                        OrganisationUnitGroupSet orgunitGroupSet = orgunitGroup.getGroupSet();
+
+                        if ( orgunitGroupSet.getUid().compareTo( orgUnitGroupSetId ) == 0 )
+                        {
+                            AttributeValue attributeValue = new AttributeValue();
+                            attributeValue.setAttribute( new Attribute( ORGUNIGROUP_SYMBOL, ORGUNIGROUP_SYMBOL ) );
+                            attributeValue.setValue( orgunitGroup.getSymbol() );
+                            attributeValues.add( attributeValue );
+                        }
+                    }
+                }
+            }
+
+            orgunit.setAttributeValues( attributeValues );
+
+            // Clear out all data not needed for this task
+            
+            orgunit.removeAllDataSets();
+            orgunit.removeAllUsers();
+            orgunit.removeAllOrganisationUnitGroups();
+        }
+
+        JacksonUtils.toJson( response.getOutputStream(), entityList );
+    }
+
+    /**
+     * Get lowest level Org Units that includes the location in their polygon shape.  
+     */
+    @RequestMapping( value = "/orgUnitByLocation", method = RequestMethod.GET, produces = { "*/*", "application/json" } )
+    public void getParentByLocation( 
+        @RequestParam Double longitude, 
+        @RequestParam Double latitude,
+        @RequestParam(required=false) String topOrgUnit,
+        @RequestParam(required=false) Integer targetLevel,
+        @RequestParam Map<String, String> parameters, 
+        Model model, HttpServletRequest request, HttpServletResponse response )
+        throws Exception
+    {
+        List<OrganisationUnit> entityList = new ArrayList<OrganisationUnit>(
+            organisationUnitService.getOrganisationUnitByCoordinate( longitude, latitude, topOrgUnit, targetLevel ) );
+
+        // Remove unrelated details and output in JSON format
+        
+        for ( OrganisationUnit orgunit : entityList )
+        {
+            Set<AttributeValue> attributeValues = orgunit.getAttributeValues();
+            attributeValues.clear();
+            orgunit.removeAllDataSets();
+            orgunit.removeAllUsers();
+            orgunit.removeAllOrganisationUnitGroups();
+        }
+
+        JacksonUtils.toJson( response.getOutputStream(), entityList );
+    }
+
+    /**
+     * Check if the location lies within the organisation unit boundary
+     */
+    @RequestMapping( value = "/locationWithinOrgUnitBoundary", method = RequestMethod.GET, produces = { "*/*", "application/json" } )
+    public void checkLocationWithinOrgUnit( 
+        @RequestParam String orgUnitUid, 
+        @RequestParam Double longitude, 
+        @RequestParam Double latitude, 
+        Model model, HttpServletRequest request, HttpServletResponse response )
+        throws Exception
+    {
+        boolean withinOrgUnit = false;
+
+        Collection<OrganisationUnit> orgUnits = new ArrayList<OrganisationUnit>();
+        orgUnits.add( organisationUnitService.getOrganisationUnit( orgUnitUid ) );
+        FilterUtils.filter( orgUnits, new OrganisationUnitPolygonCoveringCoordinateFilter( longitude, latitude ) );
+        
+        if ( !orgUnits.isEmpty() )
+        {
+            withinOrgUnit = true;
+        }
+
+        JacksonUtils.toJson( response.getOutputStream(), withinOrgUnit );
+    }
+}

=== modified file 'dhis-2/pom.xml'
--- dhis-2/pom.xml	2014-04-29 08:09:29 +0000
+++ dhis-2/pom.xml	2014-04-29 09:26:28 +0000
@@ -929,6 +929,11 @@
         <artifactId>gt-referencing</artifactId>
         <version>${geotools.version}</version>
       </dependency>
+	<dependency>
+	  <groupId>org.geotools</groupId>
+	  <artifactId>gt-geojson</artifactId>
+	  <version>${geotools.version}</version>
+	</dependency>   
 
       <!-- JAXB -->
       <dependency>