diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/GeoLocationBasedService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/GeoLocationBasedService.java index 503b45c4ed..64a5566f69 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/GeoLocationBasedService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/GeoLocationBasedService.java @@ -250,12 +250,13 @@ public interface GeoLocationBasedService { name = "deviceId", value = "The registered device Id.", required = true) - @QueryParam("horizontalDivisions") int horizontalDivisions, - @QueryParam("verticalDivisions") int verticalDivisions, + //@QueryParam("horizontalDivisions") int horizontalDivisions, + //@QueryParam("verticalDivisions") int verticalDivisions, @QueryParam("minLat") double minLat, @QueryParam("maxLat") double maxLat, @QueryParam("minLong") double minLong, - @QueryParam("maxLong") double maxLong); + @QueryParam("maxLong") double maxLong, + @QueryParam("zoom") int zoom); /** diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/GeoLocationBasedServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/GeoLocationBasedServiceImpl.java index 7e24fd2b58..fa50719e74 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/GeoLocationBasedServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/GeoLocationBasedServiceImpl.java @@ -38,10 +38,15 @@ import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation; import org.wso2.carbon.device.mgt.common.geo.service.*; import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroupConstants; import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException; +import org.wso2.carbon.device.mgt.core.dao.DeviceDAO; import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceDetailsMgtException; import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceInformationManager; +import org.wso2.carbon.device.mgt.core.geo.GeoCluster; import org.wso2.carbon.device.mgt.core.geo.GeoGrid; import org.wso2.carbon.device.mgt.core.geo.GeoRectangle; +import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate; +import org.wso2.carbon.device.mgt.core.geo.geoHash.geoHashStrategy.GeoHashLengthStrategy; +import org.wso2.carbon.device.mgt.core.geo.geoHash.geoHashStrategy.ZoomGeoHashLengthStrategy; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService; import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil; @@ -178,18 +183,19 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService { @GET @Consumes("application/json") @Produces("application/json") - public Response getGeoDeviceLocations(@QueryParam("horizontalDivisions") int horizontalDivisions, - @QueryParam("verticalDivisions") int verticalDivisions, + public Response getGeoDeviceLocations(//@QueryParam("horizontalDivisions") int horizontalDivisions, + //@QueryParam("verticalDivisions") int verticalDivisions, @QueryParam("minLat") double minLat, @QueryParam("maxLat") double maxLat, @QueryParam("minLong") double minLong, - @QueryParam("maxLong") double maxLong) { + @QueryParam("maxLong") double maxLong, + @QueryParam("zoom") int zoom) { - DeviceManagementProviderService deviceManagementService = DeviceMgtAPIUtils.getDeviceManagementService(); + /*DeviceManagementProviderService deviceManagementService = DeviceMgtAPIUtils.getDeviceManagementService(); GeoGrid geoGrid = new GeoGrid(horizontalDivisions, verticalDivisions, minLat, maxLat, minLong, maxLong); try { - List devices = deviceManagementService.getAllDevices(); + List devices = deviceManagementService.getAllDevices(); ArrayList devicesInGeoGrid = geoGrid.getDevicesInGeoGrid(devices); List geoRectangles = geoGrid.placeDevicesInGeoRectangles(devicesInGeoGrid); Map> details = new HashMap<>(); @@ -222,14 +228,24 @@ public class GeoLocationBasedServiceImpl implements GeoLocationBasedService { rectangleDetails.put("count", Integer.toString(deviceCount)); rectangleDetails.put("deviceID", null); } + details.put(geoRectangle.getId().toString(), rectangleDetails); } - return Response.ok().entity(details).build(); + return Response.ok().entity(details).build();*/ + GeoHashLengthStrategy geoHashLengthStrategy= new ZoomGeoHashLengthStrategy(); + GeoCoordinate southWest = new GeoCoordinate(minLat, minLong); + GeoCoordinate northEast = new GeoCoordinate(maxLat, maxLong); + int geohashLength = geoHashLengthStrategy.getGeohashLength(southWest, northEast, zoom); + DeviceManagementProviderService deviceManagementService=DeviceMgtAPIUtils.getDeviceManagementService(); + List geoClusters = null; + try { + geoClusters = deviceManagementService.findGeoClusters(southWest, northEast, geohashLength); } catch (DeviceManagementException e) { String msg = "Error occurred "; log.error(msg, e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()).build(); } + return Response.ok().entity(geoClusters).build(); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java index c3fa26c20b..b4247966f9 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java @@ -24,6 +24,8 @@ import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.EnrolmentInfo.Status; import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.core.dto.DeviceType; +import org.wso2.carbon.device.mgt.core.geo.GeoCluster; +import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate; import java.util.Date; import java.util.HashMap; @@ -395,5 +397,16 @@ public interface DeviceDAO { List getDeviceEnrolledTenants() throws DeviceManagementDAOException; + + /** + * This method is used to retrieve the details of geoclusters formed relatively to the zoom level and map + * boundaries. + * + * @param southWest the coordinates of southWest corner of the map. + * @param northEast the coordinates of northEast corner of the map. + * @param tenantId tenant id. + * @return returns a list of enrolment info objects. + */ + List findGeoClusters(GeoCoordinate southWest, GeoCoordinate northEast, int geohashLength,int tenantId) throws DeviceManagementDAOException; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractDeviceDAOImpl.java index 214e050d90..df8fc22d5d 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/AbstractDeviceDAOImpl.java @@ -28,6 +28,8 @@ import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException; import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory; import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil; import org.wso2.carbon.device.mgt.core.dto.DeviceType; +import org.wso2.carbon.device.mgt.core.geo.GeoCluster; +import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate; import java.sql.Connection; import java.sql.PreparedStatement; @@ -1060,4 +1062,46 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO { return tenants; } + public List findGeoClusters(GeoCoordinate southWest, GeoCoordinate northEast, + int geohashLength, int tenantId) throws DeviceManagementDAOException { + Connection conn; + PreparedStatement stmt = null; + ResultSet rs = null; + List results = new ArrayList<>(); + try { + conn = this.getConnection(); + String sql ="SELECT AVG(DEVICE_LOCATION.LATITUDE) AS LATITUDE,AVG(DEVICE_LOCATION.LONGITUDE) AS LONGITUDE" + + ", MIN(DEVICE_LOCATION.LATITUDE) AS MIN_LATITUDE, MAX(DEVICE_LOCATION.LATITUDE) AS MAX_LATITUDE, " + + "MIN(DEVICE_LOCATION.LONGITUDE) AS MIN_LONGITUDE, MAX(DEVICE_LOCATION.LONGITUDE) AS MAX_LONGITUDE" + + ", SUBSTRING (DEVICE_LOCATION.GEO_HASH,1,?) AS GEOHASH_PREFIX, COUNT(*) AS COUNT FROM " + + "DM_DEVICE_LOCATION AS DEVICE_LOCATION,DM_DEVICE AS DEVICE WHERE DEVICE_LOCATION.LATITUDE BETWEEN" + + " ? AND ? AND DEVICE_LOCATION.LONGITUDE BETWEEN ? AND ? AND DEVICE.TENANT_ID=? AND " + + "DEVICE.ID=DEVICE_LOCATION.DEVICE_ID GROUP BY GEOHASH_PREFIX"; + stmt = conn.prepareStatement(sql); + stmt.setInt(1, geohashLength); + stmt.setDouble(2, southWest.getLatitude()); + stmt.setDouble(3, northEast.getLatitude()); + stmt.setDouble(4, southWest.getLongitude()); + stmt.setDouble(5, northEast.getLongitude()); + stmt.setDouble(6,tenantId); + rs = stmt.executeQuery(); + while (rs.next()) { + double latitude = rs.getDouble("LATITUDE"); + double longitude = rs.getDouble("LONGITUDE"); + double min_latitude = rs.getDouble("MIN_LATITUDE"); + double max_latitude = rs.getDouble("MAX_LATITUDE"); + double min_longitude = rs.getDouble("MIN_LONGITUDE"); + double max_longitude = rs.getDouble("MAX_LONGITUDE"); + long count = rs.getLong("COUNT"); + String geohashPrefix = rs.getString("GEOHASH_PREFIX"); + results.add(new GeoCluster(new GeoCoordinate(latitude, longitude), count, geohashPrefix)); + } + } catch (SQLException e) { + throw new DeviceManagementDAOException("Error occurred while retrieving information of " + + "Geo Clusters", e); + } finally { + DeviceManagementDAOUtil.cleanupResources(stmt, rs); + } + return results; + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/dao/impl/DeviceDetailsDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/dao/impl/DeviceDetailsDAOImpl.java index 0d45c19838..d18bac288f 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/dao/impl/DeviceDetailsDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/dao/impl/DeviceDetailsDAOImpl.java @@ -27,6 +27,7 @@ import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory; import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil; import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.DeviceDetailsDAO; import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.DeviceDetailsMgtDAOException; +import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoHashGenerator; import java.sql.Connection; import java.sql.PreparedStatement; @@ -228,7 +229,7 @@ public class DeviceDetailsDAOImpl implements DeviceDetailsDAO { try { conn = this.getConnection(); stmt = conn.prepareStatement("INSERT INTO DM_DEVICE_LOCATION (DEVICE_ID, LATITUDE, LONGITUDE, STREET1, " + - "STREET2, CITY, ZIP, STATE, COUNTRY, UPDATE_TIMESTAMP) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + "STREET2, CITY, ZIP, STATE, COUNTRY, GEO_HASH, UPDATE_TIMESTAMP) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?,?,?)"); stmt.setInt(1, deviceLocation.getDeviceId()); stmt.setDouble(2, deviceLocation.getLatitude()); stmt.setDouble(3, deviceLocation.getLongitude()); @@ -238,7 +239,8 @@ public class DeviceDetailsDAOImpl implements DeviceDetailsDAO { stmt.setString(7, deviceLocation.getZip()); stmt.setString(8, deviceLocation.getState()); stmt.setString(9, deviceLocation.getCountry()); - stmt.setLong(10, System.currentTimeMillis()); + stmt.setString(10, GeoHashGenerator.encodeGeohash(deviceLocation)); + stmt.setLong(11, System.currentTimeMillis()); stmt.execute(); } catch (SQLException e) { throw new DeviceDetailsMgtDAOException("Error occurred while adding the device location to database.", e); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/GeoCluster.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/GeoCluster.java new file mode 100644 index 0000000000..ace906a6be --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/GeoCluster.java @@ -0,0 +1,28 @@ +package org.wso2.carbon.device.mgt.core.geo; + +import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate; + +public class GeoCluster { + private GeoCoordinate coordinates; + private long count; + private String geohashPrefix; + private String deviceId; + + public GeoCluster(GeoCoordinate coordinates,long count,String geohashPrefix){ + this.coordinates=coordinates; + this.count=count; + this.geohashPrefix=geohashPrefix; + } + + public long getCount() { + return count; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } + + public String getDeviceId() { + return deviceId; + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/geoHash/GeoCoordinate.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/geoHash/GeoCoordinate.java new file mode 100644 index 0000000000..14decb0c71 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/geoHash/GeoCoordinate.java @@ -0,0 +1,19 @@ +package org.wso2.carbon.device.mgt.core.geo.geoHash; + +public class GeoCoordinate { + private double latitude; + private double longitude; + + public GeoCoordinate(double latitude, double longitude){ + this.latitude=latitude; + this.longitude=longitude; + } + + public double getLatitude() { + return latitude; + } + + public double getLongitude() { + return longitude; + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/geoHash/GeoHashGenerator.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/geoHash/GeoHashGenerator.java new file mode 100644 index 0000000000..21d3ac85e9 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/geoHash/GeoHashGenerator.java @@ -0,0 +1,92 @@ +package org.wso2.carbon.device.mgt.core.geo.geoHash; + +import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation; + +import java.util.HashMap; +import java.util.Map; + +public class GeoHashGenerator { + private static final String BASE_32 = "0123456789bcdefghjkmnpqrstuvwxyz"; + private static final int GEOHASH_LENGTH = 16; + + private GeoHashGenerator(){}; + + private static int divideRangeByValue(double value, double[] range) { + double mid = middle(range); + if (value >= mid) { + range[0] = mid; + return 1; + } else { + range[1] = mid; + return 0; + } + } + + private static void divideRangeByBit(int bit, double[] range) { + double mid = middle(range); + if (bit > 0) { + range[0] = mid; + } else { + range[1] = mid; + } + } + + private static double middle(double[] range) { + return (range[0] + range[1]) / 2; + } + + public static String encodeGeohash(double latitude, double longitude) { + int geohashLength=GEOHASH_LENGTH; + double[] latRange = new double[]{-90.0, 90.0}; + double[] lonRange = new double[]{-180.0, 180.0}; + boolean isEven = true; + int bit = 0; + int base32CharIndex = 0; + StringBuilder geohash = new StringBuilder(); + + while (geohash.length() < geohashLength) { + if (isEven) { + base32CharIndex = (base32CharIndex << 1) | divideRangeByValue(longitude, lonRange); + } else { + base32CharIndex = (base32CharIndex << 1) | divideRangeByValue(latitude, latRange); + } + + isEven = !isEven; + + if (bit < 4) { + bit++; + } else { + geohash.append(BASE_32.charAt(base32CharIndex)); + bit = 0; + base32CharIndex = 0; + } + } + + return geohash.toString(); + } + + public static String encodeGeohash(DeviceLocation deviceLocation) { + return encodeGeohash(deviceLocation.getLatitude(), deviceLocation.getLongitude()); + } + + public static GeoCoordinate decodeGeohash(String geohash) { + double[] latRange = new double[]{-90.0, 90.0}; + double[] lonRange = new double[]{-180.0, 180.0}; + boolean isEvenBit = true; + + for (int i = 0; i < geohash.length(); i++) { + int base32CharIndex = BASE_32.indexOf(geohash.charAt(i)); + for (int j = 4; j >= 0; j--) { + if (isEvenBit) { + divideRangeByBit((base32CharIndex >> j) & 1, lonRange); + } else { + divideRangeByBit((base32CharIndex >> j) & 1, latRange); + } + isEvenBit = !isEvenBit; + } + } + GeoCoordinate coordinates = new GeoCoordinate(middle(latRange),middle(lonRange)); + return coordinates; + } + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/geoHash/geoHashStrategy/GeoHashLengthStrategy.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/geoHash/geoHashStrategy/GeoHashLengthStrategy.java new file mode 100644 index 0000000000..7f03ba5cc3 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/geoHash/geoHashStrategy/GeoHashLengthStrategy.java @@ -0,0 +1,7 @@ +package org.wso2.carbon.device.mgt.core.geo.geoHash.geoHashStrategy; + +import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate; + +public interface GeoHashLengthStrategy { + int getGeohashLength(GeoCoordinate southWest, GeoCoordinate northEast, int zoom); +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/geoHash/geoHashStrategy/ZoomGeoHashLengthStrategy.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/geoHash/geoHashStrategy/ZoomGeoHashLengthStrategy.java new file mode 100644 index 0000000000..d6fa1bf74c --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/geo/geoHash/geoHashStrategy/ZoomGeoHashLengthStrategy.java @@ -0,0 +1,50 @@ +package org.wso2.carbon.device.mgt.core.geo.geoHash.geoHashStrategy; + +import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate; + +public class ZoomGeoHashLengthStrategy implements GeoHashLengthStrategy{ + + private int minGeohashLength = 1; + private int maxGeohashLength = 16; + private int minZoom = 1; + private int maxZoom = 17; + + @Override + public int getGeohashLength(GeoCoordinate southWest, GeoCoordinate northEast, int zoom) { + double a = minGeohashLength / Math.exp(minZoom / (maxZoom - minZoom) * Math.log(maxGeohashLength / minGeohashLength)); + double b = Math.log(maxGeohashLength / minGeohashLength) / (maxZoom - minZoom); + return (int) Math.max(minGeohashLength, Math.min(a * Math.exp(b * zoom), maxGeohashLength)); + } + + public void setMinGeohashLength(int minGeohashLength) { + this.minGeohashLength = minGeohashLength; + } + + public void setMaxGeohashLength(int maxGeohashLength) { + this.maxGeohashLength = maxGeohashLength; + } + + public void setMinZoom(int minZoom) { + this.minZoom = minZoom; + } + + public void setMaxZoom(int maxZoom) { + this.maxZoom = maxZoom; + } + + public int getMinGeohashLength() { + return minGeohashLength; + } + + public int getMaxGeohashLength() { + return maxGeohashLength; + } + + public int getMinZoom() { + return minZoom; + } + + public int getMaxZoom() { + return maxZoom; + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java index ff278493f9..a1ff76a3e7 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java @@ -36,7 +36,10 @@ import org.wso2.carbon.device.mgt.common.policy.mgt.PolicyMonitoringManager; import org.wso2.carbon.device.mgt.common.pull.notification.PullNotificationExecutionFailedException; import org.wso2.carbon.device.mgt.common.push.notification.NotificationStrategy; import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService; +import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException; import org.wso2.carbon.device.mgt.core.dto.DeviceType; +import org.wso2.carbon.device.mgt.core.geo.GeoCluster; +import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate; import java.util.Date; import java.util.HashMap; @@ -612,4 +615,7 @@ public interface DeviceManagementProviderService { throws PullNotificationExecutionFailedException; List getDeviceEnrolledTenants() throws DeviceManagementException; + + List findGeoClusters(GeoCoordinate southWest, GeoCoordinate northEast, + int geohashLength) throws DeviceManagementException; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java index 9ee72d040a..a3652faa16 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java @@ -70,6 +70,8 @@ import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.DeviceDetailsDAO; import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.DeviceDetailsMgtDAOException; import org.wso2.carbon.device.mgt.core.dto.DeviceType; import org.wso2.carbon.device.mgt.core.dto.DeviceTypeServiceIdentifier; +import org.wso2.carbon.device.mgt.core.geo.GeoCluster; +import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate; import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder; import org.wso2.carbon.device.mgt.core.internal.DeviceManagementServiceComponent; import org.wso2.carbon.device.mgt.core.internal.PluginInitializationListener; @@ -2517,4 +2519,29 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv private void removeDeviceFromCache(DeviceIdentifier deviceIdentifier) { DeviceCacheManagerImpl.getInstance().removeDeviceFromCache(deviceIdentifier, this.getTenantId()); } + + @Override + public List findGeoClusters(GeoCoordinate southWest, GeoCoordinate northEast, int geohashLength) throws DeviceManagementException { + if (log.isDebugEnabled()) { + log.debug("get information about geo clusters"); + } + try { + DeviceManagementDAOFactory.openConnection(); + return deviceDAO.findGeoClusters(southWest,northEast,geohashLength,this.getTenantId()); + } catch (DeviceManagementDAOException e) { + String msg = "Error occurred while retrieving the geo clusters."; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } catch (SQLException e) { + String msg = "Error occurred while opening a connection to the data source"; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } catch (Exception e) { + String msg = "Error occurred in findGeoClusters"; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } finally { + DeviceManagementDAOFactory.closeConnection(); + } + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/resources/sql/h2.sql b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/resources/sql/h2.sql index 686d0a6b3b..bbb21a6e55 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/resources/sql/h2.sql +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/resources/sql/h2.sql @@ -417,6 +417,7 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_LOCATION ( ZIP VARCHAR(10) NULL, STATE VARCHAR(45) NULL, COUNTRY VARCHAR(45) NULL, + GEO_HASH VARCHAR(45) NULL, UPDATE_TIMESTAMP BIGINT(15) NOT NULL, PRIMARY KEY (ID), CONSTRAINT DM_DEVICE_LOCATION_DEVICE @@ -426,6 +427,8 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_LOCATION ( ON UPDATE NO ACTION ); +CREATE INDEX DM_DEVICE_LOCATION_GEO_hashx ON DM_DEVICE_LOCATION(GEO_HASH ASC); + CREATE TABLE IF NOT EXISTS DM_DEVICE_DETAIL ( ID INT NOT NULL AUTO_INCREMENT, DEVICE_ID INT NOT NULL, diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/test/resources/sql-files/h2.sql b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/test/resources/sql-files/h2.sql index 686d0a6b3b..7bdbec7df2 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/test/resources/sql-files/h2.sql +++ b/components/device-mgt/org.wso2.carbon.device.mgt.extensions/src/test/resources/sql-files/h2.sql @@ -417,6 +417,7 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_LOCATION ( ZIP VARCHAR(10) NULL, STATE VARCHAR(45) NULL, COUNTRY VARCHAR(45) NULL, + GEO_HASH VARCHAR(45) NULL, UPDATE_TIMESTAMP BIGINT(15) NOT NULL, PRIMARY KEY (ID), CONSTRAINT DM_DEVICE_LOCATION_DEVICE diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/h2.sql b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/h2.sql index 686d0a6b3b..c3f777825e 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/h2.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/h2.sql @@ -417,6 +417,7 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_LOCATION ( ZIP VARCHAR(10) NULL, STATE VARCHAR(45) NULL, COUNTRY VARCHAR(45) NULL, + GEO_HASH VARCHAR(45) NULL, UPDATE_TIMESTAMP BIGINT(15) NOT NULL, PRIMARY KEY (ID), CONSTRAINT DM_DEVICE_LOCATION_DEVICE @@ -425,6 +426,7 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_LOCATION ( ON DELETE NO ACTION ON UPDATE NO ACTION ); +CREATE INDEX DM_DEVICE_LOCATION_GEO_hashx ON DM_DEVICE_LOCATION(GEO_HASH ASC); CREATE TABLE IF NOT EXISTS DM_DEVICE_DETAIL ( ID INT NOT NULL AUTO_INCREMENT, diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mssql.sql b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mssql.sql index 9168a38a46..fe20f1a6db 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mssql.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mssql.sql @@ -469,9 +469,11 @@ CREATE TABLE DM_DEVICE_LOCATION ( ZIP VARCHAR(10) NULL, STATE VARCHAR(45) NULL, COUNTRY VARCHAR(45) NULL, + GEO_HASH VARCHAR(45) NULL, UPDATE_TIMESTAMP BIGINT NOT NULL, PRIMARY KEY (ID), INDEX DM_DEVICE_LOCATION_DEVICE_idx (DEVICE_ID ASC), + INDEX DM_DEVICE_LOCATION_GEO_hashx (GEO_HASH ASC), CONSTRAINT DM_DEVICE_LOCATION_DEVICE FOREIGN KEY (DEVICE_ID) REFERENCES DM_DEVICE (ID) diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mysql.sql b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mysql.sql index b95cc4b2a8..29fe4ded33 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mysql.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/mysql.sql @@ -487,9 +487,11 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_LOCATION ( ZIP VARCHAR(10) NULL, STATE VARCHAR(45) NULL, COUNTRY VARCHAR(45) NULL, + GEO_HASH VARCHAR(45) NULL, UPDATE_TIMESTAMP BIGINT(15) NOT NULL, PRIMARY KEY (ID), INDEX DM_DEVICE_LOCATION_DEVICE_idx (DEVICE_ID ASC), + INDEX DM_DEVICE_LOCATION_GEO_hashx (GEO_HASH ASC), CONSTRAINT DM_DEVICE_LOCATION_DEVICE FOREIGN KEY (DEVICE_ID) REFERENCES DM_DEVICE (ID) diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/oracle.sql b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/oracle.sql index b889f47e48..7288dc0ab6 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/oracle.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/oracle.sql @@ -815,13 +815,16 @@ CREATE TABLE DM_DEVICE_LOCATION ( ZIP VARCHAR2(10) NULL, STATE VARCHAR2(45) NULL, COUNTRY VARCHAR2(45) NULL, + GEO_HASH VARCHAR(45) NULL, UPDATE_TIMESTAMP NUMBER(19) NOT NULL, - PRIMARY KEY (ID) - , + PRIMARY KEY (ID), CONSTRAINT DM_DEVICE_LOCATION_DEVICE FOREIGN KEY (DEVICE_ID) REFERENCES DM_DEVICE (ID) ) + +/ +CREATE INDEX DM_DEVICE_LOCATION_GEO_hashx ON DM_DEVICE_LOCATION(GEO_HASH ASC) / -- Generate ID using sequence and trigger diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/postgresql.sql b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/postgresql.sql index fd087509a4..5234302169 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/postgresql.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/dbscripts/cdm/postgresql.sql @@ -430,6 +430,7 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_LOCATION ( ZIP VARCHAR(10) NULL, STATE VARCHAR(45) NULL, COUNTRY VARCHAR(45) NULL, + GEO_HASH VARCHAR(45) NULL, UPDATE_TIMESTAMP BIGINT NOT NULL, CONSTRAINT DM_DEVICE_LOCATION_DEVICE FOREIGN KEY (DEVICE_ID) @@ -438,6 +439,7 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_LOCATION ( ON UPDATE NO ACTION ); +CREATE INDEX DM_DEVICE_LOCATION_GEO_hashx ON DM_DEVICE_LOCATION(GEO_HASH ASC); CREATE TABLE IF NOT EXISTS DM_DEVICE_DETAIL ( ID BIGSERIAL NOT NULL PRIMARY KEY,