From 5b50cddea66f885a851c17cf3be890a865b187d9 Mon Sep 17 00:00:00 2001 From: achala piyarathna Date: Thu, 3 Oct 2019 15:51:41 +0000 Subject: [PATCH] Device Location history view feature --- .../react-app/package.json | 9 +- .../react-app/public/conf/config.json | 5 + .../react-app/public/css/leaflet.css | 636 ++++++++++++++++++ .../Geo/geo-custom-map/GeoCustomMap.js | 81 +++ .../Geo/geo-dashboard/GeoDashboard.css | 10 + .../Geo/geo-dashboard/GeoDashboard.js | 292 ++++++++ .../react-app/src/index.html | 1 + .../react-app/src/pages/Dashboard/Geo/Geo.js | 9 +- .../service/api/DeviceManagementService.java | 79 +++ .../impl/DeviceManagementServiceImpl.java | 77 ++- .../impl/DeviceManagementServiceImplTest.java | 37 +- .../device/mgt/common/PaginationRequest.java | 9 + .../common/device/details/DeviceLocation.java | 40 ++ .../device/details/DeviceLocationHistory.java | 164 +++++ .../carbon/device/mgt/core/dao/DeviceDAO.java | 12 + .../core/dao/impl/AbstractDeviceDAOImpl.java | 49 ++ .../dao/impl/device/GenericDeviceDAOImpl.java | 20 + .../dao/impl/device/OracleDeviceDAOImpl.java | 20 + .../impl/device/PostgreSQLDeviceDAOImpl.java | 20 + .../impl/device/SQLServerDeviceDAOImpl.java | 20 + .../dao/util/DeviceManagementDAOUtil.java | 21 + .../details/mgt/DeviceInformationManager.java | 3 + .../device/details/mgt/LocationCallback.java | 4 + .../details/mgt/dao/DeviceDetailsDAO.java | 12 + .../mgt/dao/impl/DeviceDetailsDAOImpl.java | 50 +- .../impl/DeviceInformationManagerImpl.java | 9 +- .../DeviceManagementProviderService.java | 13 + .../DeviceManagementProviderServiceImpl.java | 58 +- .../src/main/resources/dbscripts/cdm/h2.sql | 23 + .../main/resources/dbscripts/cdm/mssql.sql | 24 + .../main/resources/dbscripts/cdm/mysql.sql | 24 + .../main/resources/dbscripts/cdm/oracle.sql | 87 ++- .../resources/dbscripts/cdm/postgresql.sql | 22 + 33 files changed, 1884 insertions(+), 56 deletions(-) create mode 100644 components/device-mgt/io.entgra.device.mgt.ui/react-app/public/css/leaflet.css create mode 100644 components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Geo/geo-custom-map/GeoCustomMap.js create mode 100644 components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Geo/geo-dashboard/GeoDashboard.css create mode 100644 components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Geo/geo-dashboard/GeoDashboard.js create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/device/details/DeviceLocationHistory.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/LocationCallback.java diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/package.json b/components/device-mgt/io.entgra.device.mgt.ui/react-app/package.json index 31a539e7f6..3f4470ef19 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/package.json +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/package.json @@ -11,13 +11,18 @@ "bootstrap": "^4.3.1", "javascript-time-ago": "^2.0.1", "keymirror": "^0.1.1", + "leaflet": "^1.3.4", + "leaflet-routing-machine": "^3.2.12", "lodash.debounce": "^4.0.8", - "moment": "^2.24.0", + "moment": "latest", + "prop-types": "latest", "rc-viewer": "0.0.9", - "react-bootstrap": "^1.0.0-beta.12", + "react-advanced-datetimerange-picker": "^1.0.8", "react-highlight-words": "^0.16.0", "react-image-viewer-zoom": "^1.0.36", "react-infinite-scroller": "^1.2.4", + "react-leaflet": "^2.4.0", + "react-bootstrap": "^1.0.0-beta.12", "react-moment": "^0.9.2", "react-router": "^5.0.1", "react-router-config": "^5.0.1", diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/public/conf/config.json b/components/device-mgt/io.entgra.device.mgt.ui/react-app/public/conf/config.json index 0a78ea8abd..aa72ba06e4 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/public/conf/config.json +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/public/conf/config.json @@ -33,5 +33,10 @@ "color": "#008cc4", "theme": "filled" } + }, + "geoMap": { + "url": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", + "attribution": "© OpenStreetMap contributors", + "defaultZoomLevel": 16 } } diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/public/css/leaflet.css b/components/device-mgt/io.entgra.device.mgt.ui/react-app/public/css/leaflet.css new file mode 100644 index 0000000000..6f609e1180 --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/public/css/leaflet.css @@ -0,0 +1,636 @@ +/* required styles */ + +.leaflet-pane, +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-tile-container, +.leaflet-pane > svg, +.leaflet-pane > canvas, +.leaflet-zoom-box, +.leaflet-image-layer, +.leaflet-layer { + position: absolute; + left: 0; + top: 0; +} +.leaflet-container { + overflow: hidden; +} +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + -webkit-user-drag: none; +} +/* Safari renders non-retina tile on retina better with this, but Chrome is worse */ +.leaflet-safari .leaflet-tile { + image-rendering: -webkit-optimize-contrast; +} +/* hack that prevents hw layers "stretching" when loading new tiles */ +.leaflet-safari .leaflet-tile-container { + width: 1600px; + height: 1600px; + -webkit-transform-origin: 0 0; +} +.leaflet-marker-icon, +.leaflet-marker-shadow { + display: block; +} +/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */ +/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */ +.leaflet-container .leaflet-overlay-pane svg, +.leaflet-container .leaflet-marker-pane img, +.leaflet-container .leaflet-shadow-pane img, +.leaflet-container .leaflet-tile-pane img, +.leaflet-container img.leaflet-image-layer { + max-width: none !important; + max-height: none !important; +} + +.leaflet-container.leaflet-touch-zoom { + -ms-touch-action: pan-x pan-y; + touch-action: pan-x pan-y; +} +.leaflet-container.leaflet-touch-drag { + -ms-touch-action: pinch-zoom; + /* Fallback for FF which doesn't support pinch-zoom */ + touch-action: none; + touch-action: pinch-zoom; +} +.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom { + -ms-touch-action: none; + touch-action: none; +} +.leaflet-container { + -webkit-tap-highlight-color: transparent; +} +.leaflet-container a { + -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4); +} +.leaflet-tile { + filter: inherit; + visibility: hidden; +} +.leaflet-tile-loaded { + visibility: inherit; +} +.leaflet-zoom-box { + width: 0; + height: 0; + -moz-box-sizing: border-box; + box-sizing: border-box; + z-index: 800; +} +/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */ +.leaflet-overlay-pane svg { + -moz-user-select: none; +} + +.leaflet-pane { z-index: 400; } + +.leaflet-tile-pane { z-index: 200; } +.leaflet-overlay-pane { z-index: 400; } +.leaflet-shadow-pane { z-index: 500; } +.leaflet-marker-pane { z-index: 600; } +.leaflet-tooltip-pane { z-index: 650; } +.leaflet-popup-pane { z-index: 700; } + +.leaflet-map-pane canvas { z-index: 100; } +.leaflet-map-pane svg { z-index: 200; } + +.leaflet-vml-shape { + width: 1px; + height: 1px; +} +.lvml { + behavior: url(#default#VML); + display: inline-block; + position: absolute; +} + + +/* control positioning */ + +.leaflet-control { + position: relative; + z-index: 800; + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; +} +.leaflet-top, +.leaflet-bottom { + position: absolute; + z-index: 1000; + pointer-events: none; +} +.leaflet-top { + top: 0; +} +.leaflet-right { + right: 0; +} +.leaflet-bottom { + bottom: 0; +} +.leaflet-left { + left: 0; +} +.leaflet-control { + float: left; + clear: both; +} +.leaflet-right .leaflet-control { + float: right; +} +.leaflet-top .leaflet-control { + margin-top: 10px; +} +.leaflet-bottom .leaflet-control { + margin-bottom: 10px; +} +.leaflet-left .leaflet-control { + margin-left: 10px; +} +.leaflet-right .leaflet-control { + margin-right: 10px; +} + + +/* zoom and fade animations */ + +.leaflet-fade-anim .leaflet-tile { + will-change: opacity; +} +.leaflet-fade-anim .leaflet-popup { + opacity: 0; + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + -o-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; +} +.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { + opacity: 1; +} +.leaflet-zoom-animated { + -webkit-transform-origin: 0 0; + -ms-transform-origin: 0 0; + transform-origin: 0 0; +} +.leaflet-zoom-anim .leaflet-zoom-animated { + will-change: transform; +} +.leaflet-zoom-anim .leaflet-zoom-animated { + -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); + -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); + -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1); + transition: transform 0.25s cubic-bezier(0,0,0.25,1); +} +.leaflet-zoom-anim .leaflet-tile, +.leaflet-pan-anim .leaflet-tile { + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; +} + +.leaflet-zoom-anim .leaflet-zoom-hide { + visibility: hidden; +} + + +/* cursors */ + +.leaflet-interactive { + cursor: pointer; +} +.leaflet-grab { + cursor: -webkit-grab; + cursor: -moz-grab; +} +.leaflet-crosshair, +.leaflet-crosshair .leaflet-interactive { + cursor: crosshair; +} +.leaflet-popup-pane, +.leaflet-control { + cursor: auto; +} +.leaflet-dragging .leaflet-grab, +.leaflet-dragging .leaflet-grab .leaflet-interactive, +.leaflet-dragging .leaflet-marker-draggable { + cursor: move; + cursor: -webkit-grabbing; + cursor: -moz-grabbing; +} + +/* marker & overlays interactivity */ +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-image-layer, +.leaflet-pane > svg path, +.leaflet-tile-container { + pointer-events: none; +} + +.leaflet-marker-icon.leaflet-interactive, +.leaflet-image-layer.leaflet-interactive, +.leaflet-pane > svg path.leaflet-interactive { + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; +} + +/* visual tweaks */ + +.leaflet-container { + background: #ddd; + outline: 0; +} +.leaflet-container a { + color: #0078A8; +} +.leaflet-container a.leaflet-active { + outline: 2px solid orange; +} +.leaflet-zoom-box { + border: 2px dotted #38f; + background: rgba(255,255,255,0.5); +} + + +/* general typography */ +.leaflet-container { + font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; +} + + +/* general toolbar styles */ + +.leaflet-bar { + box-shadow: 0 1px 5px rgba(0,0,0,0.65); + border-radius: 4px; +} +.leaflet-bar a, +.leaflet-bar a:hover { + background-color: #fff; + border-bottom: 1px solid #ccc; + width: 26px; + height: 26px; + line-height: 26px; + display: block; + text-align: center; + text-decoration: none; + color: black; +} +.leaflet-bar a, +.leaflet-control-layers-toggle { + background-position: 50% 50%; + background-repeat: no-repeat; + display: block; +} +.leaflet-bar a:hover { + background-color: #f4f4f4; +} +.leaflet-bar a:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} +.leaflet-bar a:last-child { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom: none; +} +.leaflet-bar a.leaflet-disabled { + cursor: default; + background-color: #f4f4f4; + color: #bbb; +} + +.leaflet-touch .leaflet-bar a { + width: 30px; + height: 30px; + line-height: 30px; +} +.leaflet-touch .leaflet-bar a:first-child { + border-top-left-radius: 2px; + border-top-right-radius: 2px; +} +.leaflet-touch .leaflet-bar a:last-child { + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; +} + +/* zoom control */ + +.leaflet-control-zoom-in, +.leaflet-control-zoom-out { + font: bold 18px 'Lucida Console', Monaco, monospace; + text-indent: 1px; +} + +.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out { + font-size: 22px; +} + + +/* layers control */ + +.leaflet-control-layers { + box-shadow: 0 1px 5px rgba(0,0,0,0.4); + background: #fff; + border-radius: 5px; +} +.leaflet-control-layers-toggle { + background-image: url(images/layers.png); + width: 36px; + height: 36px; +} +.leaflet-retina .leaflet-control-layers-toggle { + background-image: url(images/layers-2x.png); + background-size: 26px 26px; +} +.leaflet-touch .leaflet-control-layers-toggle { + width: 44px; + height: 44px; +} +.leaflet-control-layers .leaflet-control-layers-list, +.leaflet-control-layers-expanded .leaflet-control-layers-toggle { + display: none; +} +.leaflet-control-layers-expanded .leaflet-control-layers-list { + display: block; + position: relative; +} +.leaflet-control-layers-expanded { + padding: 6px 10px 6px 6px; + color: #333; + background: #fff; +} +.leaflet-control-layers-scrollbar { + overflow-y: scroll; + overflow-x: hidden; + padding-right: 5px; +} +.leaflet-control-layers-selector { + margin-top: 2px; + position: relative; + top: 1px; +} +.leaflet-control-layers label { + display: block; +} +.leaflet-control-layers-separator { + height: 0; + border-top: 1px solid #ddd; + margin: 5px -10px 5px -6px; +} + +/* Default icon URLs */ +.leaflet-default-icon-path { + background-image: url(images/marker-icon.png); +} + + +/* attribution and scale controls */ + +.leaflet-container .leaflet-control-attribution { + background: #fff; + background: rgba(255, 255, 255, 0.7); + margin: 0; +} +.leaflet-control-attribution, +.leaflet-control-scale-line { + padding: 0 5px; + color: #333; +} +.leaflet-control-attribution a { + text-decoration: none; +} +.leaflet-control-attribution a:hover { + text-decoration: underline; +} +.leaflet-container .leaflet-control-attribution, +.leaflet-container .leaflet-control-scale { + font-size: 11px; +} +.leaflet-left .leaflet-control-scale { + margin-left: 5px; +} +.leaflet-bottom .leaflet-control-scale { + margin-bottom: 5px; +} +.leaflet-control-scale-line { + border: 2px solid #777; + border-top: none; + line-height: 1.1; + padding: 2px 5px 1px; + font-size: 11px; + white-space: nowrap; + overflow: hidden; + -moz-box-sizing: border-box; + box-sizing: border-box; + + background: #fff; + background: rgba(255, 255, 255, 0.5); +} +.leaflet-control-scale-line:not(:first-child) { + border-top: 2px solid #777; + border-bottom: none; + margin-top: -2px; +} +.leaflet-control-scale-line:not(:first-child):not(:last-child) { + border-bottom: 2px solid #777; +} + +.leaflet-touch .leaflet-control-attribution, +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + box-shadow: none; +} +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + border: 2px solid rgba(0,0,0,0.2); + background-clip: padding-box; +} + + +/* popup */ + +.leaflet-popup { + position: absolute; + text-align: center; + margin-bottom: 20px; +} +.leaflet-popup-content-wrapper { + padding: 1px; + text-align: left; + border-radius: 12px; +} +.leaflet-popup-content { + margin: 13px 19px; + line-height: 1.4; +} +.leaflet-popup-content p { + margin: 18px 0; +} +.leaflet-popup-tip-container { + width: 40px; + height: 20px; + position: absolute; + left: 50%; + margin-left: -20px; + overflow: hidden; + pointer-events: none; +} +.leaflet-popup-tip { + width: 17px; + height: 17px; + padding: 1px; + + margin: -10px auto 0; + + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + -o-transform: rotate(45deg); + transform: rotate(45deg); +} +.leaflet-popup-content-wrapper, +.leaflet-popup-tip { + background: white; + color: #333; + box-shadow: 0 3px 14px rgba(0,0,0,0.4); +} +.leaflet-container a.leaflet-popup-close-button { + position: absolute; + top: 0; + right: 0; + padding: 4px 4px 0 0; + border: none; + text-align: center; + width: 18px; + height: 14px; + font: 16px/14px Tahoma, Verdana, sans-serif; + color: #c3c3c3; + text-decoration: none; + font-weight: bold; + background: transparent; +} +.leaflet-container a.leaflet-popup-close-button:hover { + color: #999; +} +.leaflet-popup-scrolled { + overflow: auto; + border-bottom: 1px solid #ddd; + border-top: 1px solid #ddd; +} + +.leaflet-oldie .leaflet-popup-content-wrapper { + zoom: 1; +} +.leaflet-oldie .leaflet-popup-tip { + width: 24px; + margin: 0 auto; + + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; + filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); +} +.leaflet-oldie .leaflet-popup-tip-container { + margin-top: -1px; +} + +.leaflet-oldie .leaflet-control-zoom, +.leaflet-oldie .leaflet-control-layers, +.leaflet-oldie .leaflet-popup-content-wrapper, +.leaflet-oldie .leaflet-popup-tip { + border: 1px solid #999; +} + + +/* div icon */ + +.leaflet-div-icon { + background: #fff; + border: 1px solid #666; +} + + +/* Tooltip */ +/* Base styles for the element that has a tooltip */ +.leaflet-tooltip { + position: absolute; + padding: 6px; + background-color: #fff; + border: 1px solid #fff; + border-radius: 3px; + color: #222; + white-space: nowrap; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + pointer-events: none; + box-shadow: 0 1px 3px rgba(0,0,0,0.4); +} +.leaflet-tooltip.leaflet-clickable { + cursor: pointer; + pointer-events: auto; +} +.leaflet-tooltip-top:before, +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + position: absolute; + pointer-events: none; + border: 6px solid transparent; + background: transparent; + content: ""; +} + +/* Directions */ + +.leaflet-tooltip-bottom { + margin-top: 6px; +} +.leaflet-tooltip-top { + margin-top: -6px; +} +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-top:before { + left: 50%; + margin-left: -6px; +} +.leaflet-tooltip-top:before { + bottom: 0; + margin-bottom: -12px; + border-top-color: #fff; +} +.leaflet-tooltip-bottom:before { + top: 0; + margin-top: -12px; + margin-left: -6px; + border-bottom-color: #fff; +} +.leaflet-tooltip-left { + margin-left: -6px; +} +.leaflet-tooltip-right { + margin-left: 6px; +} +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + top: 50%; + margin-top: -6px; +} +.leaflet-tooltip-left:before { + right: 0; + margin-right: -12px; + border-left-color: #fff; +} +.leaflet-tooltip-right:before { + left: 0; + margin-left: -12px; + border-right-color: #fff; +} \ No newline at end of file diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Geo/geo-custom-map/GeoCustomMap.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Geo/geo-custom-map/GeoCustomMap.js new file mode 100644 index 0000000000..3c68ee0aaa --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Geo/geo-custom-map/GeoCustomMap.js @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, {Component, Fragment} from "react"; +import { + Map, + TileLayer, + Marker, + Polyline, Popup, Tooltip +} from "react-leaflet"; +import {withConfigContext} from "../../../context/ConfigContext"; + +class GeoCustomMap extends Component { + + constructor(props) { + super(props); + } + + /** + * Polyline draw for historical locations + * @param locationData - location data object + * @returns content + */ + polylineMarker = (locationData) => { + + const polyMarkers = locationData + .map(locationPoint => { + return [locationPoint.latitude, locationPoint.longitude] + }); + + return ( +
{ + + on the way + + }
+ ); + }; + + render() { + const locationData = this.props.locationData; + const config = this.props.context; + const attribution = config.geoMap.attribution; + const url = config.geoMap.url; + const startingPoint = [locationData[0].latitude, locationData[0].longitude]; + const zoom = config.geoMap.defaultZoomLevel; + return ( +
+ + + + {this.polylineMarker(locationData)} + + Starting Location + + + +
+ ); + } +} + +export default withConfigContext(GeoCustomMap); diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Geo/geo-dashboard/GeoDashboard.css b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Geo/geo-dashboard/GeoDashboard.css new file mode 100644 index 0000000000..abd20795db --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Geo/geo-dashboard/GeoDashboard.css @@ -0,0 +1,10 @@ +.leaflet-container { + align-content: center; + padding-top: 80px; + height: 550px; + width: 100%; +} + +.controllerDiv { + padding-bottom: 30px; +} \ No newline at end of file diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Geo/geo-dashboard/GeoDashboard.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Geo/geo-dashboard/GeoDashboard.js new file mode 100644 index 0000000000..63367f3afd --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Geo/geo-dashboard/GeoDashboard.js @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from "react"; +import moment from "moment"; +import DateTimeRangeContainer from "react-advanced-datetimerange-picker"; +import {Button, Select, message, notification, Tag, Tooltip, Empty} from "antd"; +import axios from "axios"; +import {withConfigContext} from "../../../context/ConfigContext"; +import GeoCustomMap from "../geo-custom-map/GeoCustomMap"; +import "./GeoDashboard.css"; + +class GeoDashboard extends React.Component { + + constructor(props) { + super(props); + let start = moment(new Date()); + let end = moment(start) + .add(5, "days") + .subtract(1, "minute"); + this.state = { + deviceData: [], + selectedDevice: '', + locationData: [], + // currentLocation: [], + loading: false, + start: start, + end: end, + buttonTooltip: "Fetch Locations", + }; + } + + componentDidMount() { + this.fetchDevices(); + // this.fetchCurrentLocation(); + } + + /** + * Call back on apply button in the date time picker + * @param startDate - start date + * @param endDate - end date + */ + applyCallback = (startDate, endDate) => { + console.log("Apply Callback"); + this.setState({ + start: startDate, + end: endDate + }); + }; + + /** + * Api call handle on fetch location date button + */ + handleApiCall = () => { + + if (this.state.selectedDevice && this.state.start && this.state.end) { + const toInMills = moment(this.state.end); + const fromInMills = moment(this.state.start); + const deviceType = this.state.selectedDevice.type; + const deviceId = this.state.selectedDevice.deviceIdentifier; + const config = this.props.context; + this.setState({loading: true}); + + axios.get(window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt + + "/devices/" + deviceType + "/" + deviceId + "/location-history?" + "from=" + fromInMills + "&to=" + + toInMills,).then(res => { + if (res.status === 200) { + const locationData = JSON.parse(res.data.data); + this.setState({ + loading: false, + locationData, + }); + } + }).catch((error) => { + if (error.hasOwnProperty("response") && error.response.status === 401) { + message.error('You are not logged in'); + window.location.href = window.location.origin + '/entgra/login'; + } else { + notification["error"]({ + message: "There was a problem", + duration: 0, + description: + "Error occurred while trying to fetch locations......", + }); + } + + this.setState({loading: false}); + console.log(error); + }); + } else { + notification["error"]({ + message: "There was a problem", + duration: 0, + description: + "Please provide a date range and a device.", + }); + } + }; + + /** + * Device dropdown list handler + * @param e - selected device data + */ + handleDeviceList = (e) => { + let selectedDevice = this.state.deviceData[e]; + this.setState({selectedDevice}) + }; + + /** + * render fetch location button + */ + fetchLocationButton = () => { + let flag; + let toolTip = ""; + if (this.state.selectedDevice === "") { + flag = true; + toolTip = "Please select a Device"; + } + return ( + + + ); + + }; + + /** + * fetches device data to populate the dropdown list + */ + fetchDevices = () => { + const config = this.props.context; + this.setState({loading: true}); + + axios.get( + window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt + + "/devices?excludeStatus=REMOVED",).then(res => { + if (res.status === 200) { + this.setState({ + loading: false, + deviceData: res.data.data.devices, + }); + } + + }).catch((error) => { + if (error.hasOwnProperty("response") && error.response.status === 401) { + message.error('You are not logged in'); + window.location.href = window.location.origin + '/entgra/login'; + } else { + notification["error"]({ + message: "There was a problem", + duration: 0, + description: + "Error occurred while trying to load devices.", + }); + } + + this.setState({loading: false}); + }); + }; + + /** + * Geo Dashboard controller + */ + controllerBar = () => { + + let now = new Date(); + let start = moment( + new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0) + ); + let end = moment(start) + .add(1, "days") + .subtract(1, "seconds"); + let ranges = { + "Today Only": [moment(start), moment(end)], + "Yesterday Only": [ + moment(start).subtract(1, "days"), + moment(end).subtract(1, "days") + ], + "3 Days": [moment(start).subtract(3, "days"), moment(end)], + "5 Days": [moment(start).subtract(5, "days"), moment(end)], + "1 Week": [moment(start).subtract(7, "days"), moment(end)], + "2 Weeks": [moment(start).subtract(14, "days"), moment(end)], + "1 Month": [moment(start).subtract(1, "months"), moment(end)], + }; + let local = { + format: "DD-MM-YYYY HH:mm", + sundayFirst: false + }; + let maxDate = moment(start).add(24, "hour"); + let value = + ` + ${this.state.start.format("DD-MM-YYYY HH:mm")} - ${this.state.end.format("DD-MM-YYYY HH:mm")} + `; + let {deviceData} = this.state; + + return ( +
+ + + + + + {this.fetchLocationButton()} +
+ ); + }; + + /** + * Creates color based tags on device status + * @param device - device object + */ + statusTag = (device) => { + + const status = device.enrolmentInfo.status.toLowerCase(); + let color = "#f9ca24"; + switch (status) { + case "active": + color = "#badc58"; + break; + case "created": + color = "#6ab04c"; + break; + case "inactive": + color = "#f9ca24"; + break; + case "blocked": + color = "#636e72"; + break; + } + + return {status} + }; + + render() { + const locationData = [...this.state.locationData]; + + return ( +
+ {this.controllerBar()} + {(locationData.length > 0) ? + + : + + } +
+ ); + } +} + +export default withConfigContext(GeoDashboard); diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/index.html b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/index.html index f2d81b221c..9f2c3027d7 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/index.html +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/index.html @@ -21,6 +21,7 @@ Entgra Device Management +
\ No newline at end of file diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Geo/Geo.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Geo/Geo.js index ad8b6a7756..f40df4ffc3 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Geo/Geo.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Geo/Geo.js @@ -25,7 +25,7 @@ import { Card } from "antd"; import {Link} from "react-router-dom"; -import DeviceTable from "../../../components/Devices/DevicesTable"; +import GeoDashboard from "../../../components/Geo/geo-dashboard/GeoDashboard"; const {Paragraph} = Typography; @@ -50,12 +50,11 @@ class Geo extends React.Component {

Geo

- Lorem ipsum dolor sit amet, est similique constituto at, quot inermis id mel, an - illud incorrupte nam. + Geo Location Service
-
- +
+
); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java index 1aa36ca78f..29c70b11a7 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java @@ -269,6 +269,13 @@ public interface DeviceManagementService { @QueryParam("ownership") @Size(max = 45) String ownership, + @ApiParam( + name = "excludeStatus", + value = "Provide the devices that excludes the given status", + required = false) + @QueryParam("excludeStatus") + @Size(max = 45) + String excludeStatus, @ApiParam( name = "status", value = "Provide the device status details, such as active or inactive.", @@ -476,6 +483,78 @@ public interface DeviceManagementService { @HeaderParam("If-Modified-Since") String ifModifiedSince); + @GET + @Path("/{deviceType}/{deviceId}/location-history") + @ApiOperation( + consumes = "application/json", + produces = "application/json", + httpMethod = "GET", + value = "Getting the Location Details of a Device", + notes = "Get the location details of a device during a define time period.", + response = Response.class, + tags = "Device Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:details") + }) + } + ) + @ApiResponses(value = { + @ApiResponse( + code = 200, + message = "OK.", + response = Response.class, + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "The content type of the body"), + @ResponseHeader( + name = "ETag", + description = "Entity Tag of the response resource.\n" + + "Used by caches, or in conditional requests."), + @ResponseHeader( + name = "Last-Modified", + description = "Date and time the resource was last modified.\n" + + "Used by caches, or in conditional requests."), + }), + @ApiResponse( + code = 400, + message = "Bad Request. \n Invalid Device Identifiers found.", + response = Response.class), + @ApiResponse( + code = 401, + message = "Unauthorized. \n Unauthorized request."), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Error on retrieving stats", + response = Response.class) + }) + Response getDeviceLocationInfo( + @ApiParam( + name = "device-type", + value = "The device type, such as ios, android, or windows.", + required = true) + @PathParam("deviceType") + @Size(max = 45) + String deviceType, + @ApiParam( + name = "deviceId", + value = "The device ID.", + required = true) + @PathParam("deviceId") String deviceId, + @ApiParam( + name = "from", + value = "Define the time to start getting the geo location history of the device in " + + "milliseconds.", + required = true) + @QueryParam("from") long from, + @ApiParam( + name = "to", + value = "Define the time to finish getting the geo location history of the device in " + + "milliseconds.", + required = true) + @QueryParam("to") long to); + @GET @Path("/type/any/id/{id}") @ApiOperation( diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java index 4cb9a661b2..6e190e5d46 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java @@ -42,13 +42,9 @@ import org.apache.commons.logging.LogFactory; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; -import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; -import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException; import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.Feature; import org.wso2.carbon.device.mgt.common.FeatureManager; -import org.wso2.carbon.device.mgt.common.exceptions.InvalidConfigurationException; -import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.PaginationResult; import org.wso2.carbon.device.mgt.common.app.mgt.Application; @@ -57,6 +53,11 @@ import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorization import org.wso2.carbon.device.mgt.common.authorization.DeviceAccessAuthorizationService; import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo; import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation; +import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistory; +import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException; +import org.wso2.carbon.device.mgt.common.exceptions.InvalidConfigurationException; +import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.operation.mgt.Activity; import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; @@ -80,6 +81,7 @@ import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; import org.wso2.carbon.device.mgt.jaxrs.beans.OperationList; import org.wso2.carbon.device.mgt.jaxrs.beans.OperationRequest; import org.wso2.carbon.device.mgt.jaxrs.service.api.DeviceManagementService; +import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.InputValidationException; import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil; import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils; import org.wso2.carbon.policy.mgt.common.PolicyManagementException; @@ -145,6 +147,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { @QueryParam("role") String role, @QueryParam("ownership") String ownership, @QueryParam("status") String status, + @QueryParam("excludeStatus") String excludeStatus, @QueryParam("groupId") int groupId, @QueryParam("since") String since, @HeaderParam("If-Modified-Since") String ifModifiedSince, @@ -186,6 +189,10 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { RequestValidationUtil.validateStatus(status); request.setStatus(status); } + if (excludeStatus != null && !excludeStatus.isEmpty()) { + RequestValidationUtil.validateStatus(excludeStatus); + request.setExcludeStatus(excludeStatus); + } if (groupId != 0) { request.setGroupId(groupId); } @@ -466,6 +473,68 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { return Response.status(Response.Status.OK).entity(device).build(); } + @Path("/{deviceType}/{deviceId}/location-history") + @GET + @Consumes("application/json") + @Produces("application/json") + public Response getDeviceLocationInfo(@PathParam("deviceType") String deviceType, + @PathParam("deviceId") String deviceId, + @QueryParam("from") long from, @QueryParam("to") long to) { + + List deviceLocationHistory; + String errorMessage; + + try { + RequestValidationUtil.validateDeviceIdentifier(deviceType, deviceId); + DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService(); + DeviceAccessAuthorizationService deviceAccessAuthorizationService = + DeviceMgtAPIUtils.getDeviceAccessAuthorizationService(); + String authorizedUser = CarbonContext.getThreadLocalCarbonContext().getUsername(); + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(deviceId, deviceType); + deviceIdentifier.setId(deviceId); + deviceIdentifier.setType(deviceType); + + if (deviceAccessAuthorizationService == null) { + errorMessage = "Device access authorization service is failed"; + log.error(errorMessage); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity( + new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(errorMessage).build()).build(); + } + if (!deviceAccessAuthorizationService.isUserAuthorized(deviceIdentifier, authorizedUser)) { + String msg = "User '" + authorizedUser + "' is not authorized to retrieve the given device id '" + + deviceId + "'"; + log.error(msg); + return Response.status(Response.Status.UNAUTHORIZED).entity( + new ErrorResponse.ErrorResponseBuilder().setCode(401l).setMessage(msg).build()).build(); + } + if (from == 0 || to == 0) { + errorMessage = "Invalid values for from/to"; + log.error(errorMessage); + return Response.status(Response.Status.BAD_REQUEST).entity( + new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage)).build(); + } + + deviceLocationHistory = dms.getDeviceLocationInfo(deviceIdentifier, from, to); + + } catch (DeviceManagementException e) { + errorMessage = "Error occurred while fetching the device information."; + log.error(errorMessage, e); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(errorMessage).build()).build(); + } catch (DeviceAccessAuthorizationException e) { + errorMessage = "Error occurred while checking the device authorization."; + log.error(errorMessage, e); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setCode(500l).setMessage(errorMessage).build()).build(); + } catch (InputValidationException e){ + errorMessage = "Invalid device Id or device type"; + log.error(errorMessage, e); + return Response.status(Response.Status.BAD_REQUEST).entity( + new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage)).build(); + } + return Response.status(Response.Status.OK).entity(deviceLocationHistory).build(); + } + @GET @Path("/type/any/id/{id}") @Override diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java index 57f71d18a6..63723e65d2 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImplTest.java @@ -105,6 +105,7 @@ public class DeviceManagementServiceImplTest { private static final String DEFAULT_ROLE = "admin"; private static final String DEFAULT_OWNERSHIP = "BYOD"; private static final String DEFAULT_STATUS = "ACTIVE"; + private static final String DEFAULT_EXCLUDED_STATUS = "REMOVE"; private static final String DEFAULT_DATE_FORMAT = "EEE, d MMM yyyy HH:mm:ss Z"; private DeviceManagementService deviceManagementService; private DeviceAccessAuthorizationService deviceAccessAuthorizationService; @@ -173,7 +174,7 @@ public class DeviceManagementServiceImplTest { .toReturn(this.deviceAccessAuthorizationService); Response response = this.deviceManagementService .getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, null, null, false, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, null, null, false, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode()); } @@ -190,19 +191,19 @@ public class DeviceManagementServiceImplTest { Response response = this.deviceManagementService .getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, null, null, false, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, null, null, false, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); response = this.deviceManagementService .getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, null, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, null, null, false, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, null, null, false, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); response = this.deviceManagementService .getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, null, null, null, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, null, null, false, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, null, null, false, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); response = this.deviceManagementService .getDevices(TEST_DEVICE_NAME, TEST_DEVICE_TYPE, null, null, null, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, null, null, true, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, null, null, true, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); } @@ -311,7 +312,7 @@ public class DeviceManagementServiceImplTest { .toReturn(null); Response response = this.deviceManagementService .getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, null, null, false, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, null, null, false, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); } @@ -329,11 +330,11 @@ public class DeviceManagementServiceImplTest { Response response = this.deviceManagementService .getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, null, null, false, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, null, null, false, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); response = this.deviceManagementService .getDevices(null, TEST_DEVICE_TYPE, null, DEFAULT_USERNAME, DEFAULT_ROLE, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, null, null, false, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, null, null, false, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); } @@ -352,8 +353,8 @@ public class DeviceManagementServiceImplTest { Mockito.when(this.deviceAccessAuthorizationService.isDeviceAdminUser()).thenReturn(false); Response response = this.deviceManagementService - .getDevices(null, TEST_DEVICE_TYPE, "newuser", null, DEFAULT_ROLE, DEFAULT_OWNERSHIP, DEFAULT_STATUS, 1, - null, null, false, 10, 5); + .getDevices(null, TEST_DEVICE_TYPE, "newuser", null, DEFAULT_ROLE, DEFAULT_OWNERSHIP, DEFAULT_EXCLUDED_STATUS, + DEFAULT_STATUS, 1, null, null, false, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.UNAUTHORIZED.getStatusCode()); Mockito.reset(this.deviceAccessAuthorizationService); } @@ -372,15 +373,15 @@ public class DeviceManagementServiceImplTest { Response response = this.deviceManagementService .getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, null, ifModifiedSince, false, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, null, ifModifiedSince, false, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.NOT_MODIFIED.getStatusCode()); response = this.deviceManagementService .getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, null, ifModifiedSince, true, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, null, ifModifiedSince, true, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.NOT_MODIFIED.getStatusCode()); response = this.deviceManagementService .getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, null, "ErrorModifiedSince", false, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, null, "ErrorModifiedSince", false, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode()); } @@ -398,15 +399,15 @@ public class DeviceManagementServiceImplTest { Response response = this.deviceManagementService .getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, since, null, false, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, since, null, false, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); response = this.deviceManagementService .getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, since, null, true, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, since, null, true, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); response = this.deviceManagementService .getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, "ErrorSince", null, false, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, "ErrorSince", null, false, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.BAD_REQUEST.getStatusCode()); } @@ -426,7 +427,7 @@ public class DeviceManagementServiceImplTest { Response response = this.deviceManagementService .getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, null, null, false, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, null, null, false, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); Mockito.reset(this.deviceManagementProviderService); } @@ -446,7 +447,7 @@ public class DeviceManagementServiceImplTest { Response response = this.deviceManagementService .getDevices(null, TEST_DEVICE_TYPE, DEFAULT_USERNAME, null, DEFAULT_ROLE, DEFAULT_OWNERSHIP, - DEFAULT_STATUS, 1, null, null, false, 10, 5); + DEFAULT_EXCLUDED_STATUS, DEFAULT_STATUS, 1, null, null, false, 10, 5); Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); Mockito.reset(this.deviceAccessAuthorizationService); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/PaginationRequest.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/PaginationRequest.java index dfda4b74a9..a7baf05ce8 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/PaginationRequest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/PaginationRequest.java @@ -33,6 +33,7 @@ public class PaginationRequest { private String owner; private String ownerPattern; private String status; + private String excludeStatus; private String deviceType; private String deviceName; private String ownership; @@ -85,6 +86,14 @@ public class PaginationRequest { this.status = status; } + public String getExcludeStatus() { + return excludeStatus; + } + + public void setExcludeStatus(String excludeStatus) { + this.excludeStatus = excludeStatus; + } + public String getDeviceType() { return deviceType; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/device/details/DeviceLocation.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/device/details/DeviceLocation.java index f1107091b0..71270b1683 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/device/details/DeviceLocation.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/device/details/DeviceLocation.java @@ -55,6 +55,46 @@ public class DeviceLocation implements Serializable { private String country; @ApiModelProperty(name = "updatedTime", value = "Update time of the device.", required = true) private Date updatedTime; + @ApiModelProperty(name = "altitude", value = "Device altitude.", required = true) + private Double altitude; + @ApiModelProperty(name = "speed", value = "Device speed.", required = true) + private Float speed; + @ApiModelProperty(name = "bearing", value = "Device bearing.", required = true) + private Float bearing; + @ApiModelProperty(name = "distance", value = "Device distance.", required = true) + private Double distance; + + public Double getDistance() { + return distance; + } + + public void setDistance(Double distance) { + this.distance = distance; + } + + public Double getAltitude() { + return altitude; + } + + public Float getSpeed() { + return speed; + } + + public void setSpeed(Float speed) { + this.speed = speed; + } + + public Float getBearing() { + return bearing; + } + + public void setBearing(Float bearing) { + this.bearing = bearing; + } + + public void setAltitude(Double altitude) { + this.altitude = altitude; + } public int getDeviceId() { return deviceId; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/device/details/DeviceLocationHistory.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/device/details/DeviceLocationHistory.java new file mode 100644 index 0000000000..e5d1af9681 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/device/details/DeviceLocationHistory.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.device.mgt.common.device.details; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +@ApiModel(value = "DeviceLocationHistory", description = "This class carries all information related to the device location History" + + "details provided by a device.") + +public class DeviceLocationHistory implements Serializable { + + @ApiModelProperty(name = "deviceId", value = "Device id", required = true) + private int deviceId; + @ApiModelProperty(name = "geoHash", value = "Geo Hash", required = true) + private String geoHash; + @ApiModelProperty(name = "deviceType", value = "Device type", required = true) + private String deviceType; + @ApiModelProperty(name = "deviceIdentifier", value = "Device Id Name", required = true) + private String deviceIdentifier; + @ApiModelProperty(name = "latitude", value = "Device GPS latitude.", required = true) + private Double latitude; + @ApiModelProperty(name = "longitude", value = "Device GPS longitude.", required = true) + private Double longitude; + @ApiModelProperty(name = "tenantId", value = "Tenant Id.", required = true) + private int tenantId; + @ApiModelProperty(name = "altitude", value = "Device altitude.", required = true) + private Double altitude; + @ApiModelProperty(name = "speed", value = "Device speed.", required = true) + private Float speed; + @ApiModelProperty(name = "bearing", value = "Device bearing.", required = true) + private Float bearing; + @ApiModelProperty(name = "distance", value = "Device distance.", required = true) + private Double distance; + @ApiModelProperty(name = "timestamp", value = "Timestamp.", required = true) + private Long timestamp; + @ApiModelProperty(name = "owner", value = "Owner.", required = true) + private String owner; + + public DeviceLocationHistory() { + } + + public String getGeoHash() { + return geoHash; + } + + public void setGeoHash(String geoHash) { + this.geoHash = geoHash; + } + + public String getDeviceType() { + return deviceType; + } + + public void setDeviceType(String deviceType) { + this.deviceType = deviceType; + } + + public int getDeviceId() { + return deviceId; + } + + public void setDeviceId(int deviceId) { + this.deviceId = deviceId; + } + + public String getDeviceIdentifier() { + return deviceIdentifier; + } + + public void setDeviceIdentifier(String deviceIdentifier) { + this.deviceIdentifier = deviceIdentifier; + } + + public Double getLatitude() { + return latitude; + } + + public void setLatitude(Double latitude) { + this.latitude = latitude; + } + + public Double getLongitude() { + return longitude; + } + + public void setLongitude(Double longitude) { + this.longitude = longitude; + } + + public int getTenantId() { + return tenantId; + } + + public void setTenantId(int tenantId) { + this.tenantId = tenantId; + } + + public Double getAltitude() { + return altitude; + } + + public void setAltitude(double altitude) { + this.altitude = altitude; + } + + public Float getSpeed() { + return speed; + } + + public void setSpeed(Float speed) { + this.speed = speed; + } + + public Float getBearing() { + return bearing; + } + + public void setBearing(Float bearing) { + this.bearing = bearing; + } + + public Double getDistance() { + return distance; + } + + public void setDistance(Double distance) { + this.distance = distance; + } + + public Long getTimestamp() { + return timestamp; + } + + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } +} 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 6bcdd52fec..54b2114a72 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 @@ -40,6 +40,7 @@ import org.wso2.carbon.device.mgt.common.DeviceIdentifier; 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.common.device.details.DeviceLocationHistory; import org.wso2.carbon.device.mgt.common.configuration.mgt.DevicePropertyInfo; import org.wso2.carbon.device.mgt.core.dto.DeviceType; import org.wso2.carbon.device.mgt.core.geo.GeoCluster; @@ -550,4 +551,15 @@ public interface DeviceDAO { int tenantId, String fromDate, String toDate) throws DeviceManagementDAOException; + + /** + * Retrieve device location information + * @param deviceIdentifier Device Identifier object + * @param from Specified start timestamp + * @param to Specified end timestamp + * @return + * @throws DeviceManagementDAOException + */ + List getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from, long to) + 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 2a69ef188d..1041d39911 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 @@ -42,6 +42,7 @@ import org.wso2.carbon.device.mgt.common.DeviceIdentifier; 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.common.device.details.DeviceLocationHistory; import org.wso2.carbon.device.mgt.common.configuration.mgt.DevicePropertyInfo; import org.wso2.carbon.device.mgt.core.dao.DeviceDAO; import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException; @@ -939,6 +940,8 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO { boolean isOwnershipProvided = false; String status = request.getStatus(); boolean isStatusProvided = false; + String excludeStatus = request.getExcludeStatus(); + boolean isExcludeStatusProvided = false; Date since = request.getSince(); boolean isSinceProvided = false; try { @@ -987,6 +990,11 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO { isStatusProvided = true; } + if (excludeStatus != null && !excludeStatus.isEmpty()) { + sql = sql + " AND e.STATUS != ?"; + isExcludeStatusProvided = true; + } + stmt = conn.prepareStatement(sql); stmt.setInt(1, tenantId); int paramIdx = 2; @@ -1012,6 +1020,9 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO { if (isStatusProvided) { stmt.setString(paramIdx++, request.getStatus()); } + if (isExcludeStatusProvided) { + stmt.setString(paramIdx++, excludeStatus); + } rs = stmt.executeQuery(); if (rs.next()) { deviceCount = rs.getInt("DEVICE_COUNT"); @@ -1574,6 +1585,44 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO { } @Override + public List getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from, long to) + throws DeviceManagementDAOException { + + Connection conn; + PreparedStatement stmt = null; + ResultSet rs = null; + List deviceLocationHistories = new ArrayList<>(); + try { + conn = this.getConnection(); + + String sql = + "SELECT DEVICE_ID, TENANT_ID, DEVICE_ID_NAME, DEVICE_TYPE_NAME, LATITUDE, LONGITUDE, SPEED, " + + "HEADING, TIMESTAMP, GEO_HASH, DEVICE_OWNER, DEVICE_ALTITUDE, DISTANCE " + + "FROM DM_DEVICE_HISTORY_LAST_SEVEN_DAYS " + + "WHERE DEVICE_ID_NAME = ? " + + "AND DEVICE_TYPE_NAME = ? " + + "AND TIMESTAMP >= ? " + + "AND TIMESTAMP <= ?"; + + stmt = conn.prepareStatement(sql); + stmt.setString(1, deviceIdentifier.getId()); + stmt.setString(2, deviceIdentifier.getType()); + stmt.setLong(3, from); + stmt.setLong(4, to); + rs = stmt.executeQuery(); + while (rs.next()) { + deviceLocationHistories.add(DeviceManagementDAOUtil.loadDeviceLocation(rs)); + } + } catch (SQLException e) { + String errMessage = "Error occurred while obtaining the DB connection to get device location information"; + log.error(errMessage, e); + throw new DeviceManagementDAOException(errMessage, e); + } finally { + DeviceManagementDAOUtil.cleanupResources(stmt, rs); + } + return deviceLocationHistories; + } + public void deleteDevices(List deviceIdentifiers, List deviceIds, List enrollmentIds) throws DeviceManagementDAOException { Connection conn; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java index 369085c3dd..7680e3f905 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java @@ -61,6 +61,8 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl { boolean isOwnershipProvided = false; String status = request.getStatus(); boolean isStatusProvided = false; + String excludeStatus = request.getExcludeStatus(); + boolean isExcludeStatusProvided = false; Date since = request.getSince(); boolean isSinceProvided = false; try { @@ -115,6 +117,11 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl { sql = sql + " AND e.STATUS = ?"; isStatusProvided = true; } + //Add the query for exclude status + if (excludeStatus != null && !excludeStatus.isEmpty()) { + sql = sql + " AND e.STATUS != ?"; + isExcludeStatusProvided = true; + } sql = sql + " LIMIT ?,?"; @@ -143,6 +150,9 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl { if (isStatusProvided) { stmt.setString(paramIdx++, status); } + if (isExcludeStatusProvided) { + stmt.setString(paramIdx++, excludeStatus); + } stmt.setInt(paramIdx++, request.getStartIndex()); stmt.setInt(paramIdx, request.getRowCount()); rs = stmt.executeQuery(); @@ -182,6 +192,8 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl { boolean isOwnershipProvided = false; String status = request.getStatus(); boolean isStatusProvided = false; + String excludeStatus = request.getExcludeStatus(); + boolean isExcludeStatusProvided = false; Date since = request.getSince(); boolean isSinceProvided = false; @@ -242,6 +254,11 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl { sql = sql + " AND e.STATUS = ?"; isStatusProvided = true; } + //Add the query for exclude status + if (excludeStatus != null && !excludeStatus.isEmpty()) { + sql = sql + " AND e.STATUS != ?"; + isExcludeStatusProvided = true; + } sql = sql + " LIMIT ?,?"; @@ -273,6 +290,9 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl { if (isStatusProvided) { stmt.setString(paramIdx++, status); } + if (isExcludeStatusProvided) { + stmt.setString(paramIdx++, excludeStatus); + } stmt.setInt(paramIdx++, request.getStartIndex()); stmt.setInt(paramIdx, request.getRowCount()); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java index 11d2896fc7..fd8156c50f 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java @@ -64,6 +64,8 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl { boolean isOwnershipProvided = false; String status = request.getStatus(); boolean isStatusProvided = false; + String excludeStatus = request.getExcludeStatus(); + boolean isExcludeStatusProvided = false; Date since = request.getSince(); boolean isSinceProvided = false; try { @@ -118,6 +120,11 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl { sql = sql + " AND e.STATUS = ?"; isStatusProvided = true; } + //Add the query for exclude status + if (excludeStatus != null && !excludeStatus.isEmpty()) { + sql = sql + " AND e.STATUS != ?"; + isExcludeStatusProvided = true; + } sql = sql + " ORDER BY ENROLMENT_ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY"; @@ -146,6 +153,9 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl { if (isStatusProvided) { stmt.setString(paramIdx++, status); } + if (isExcludeStatusProvided) { + stmt.setString(paramIdx++, excludeStatus); + } stmt.setInt(paramIdx++, request.getStartIndex()); stmt.setInt(paramIdx, request.getRowCount()); rs = stmt.executeQuery(); @@ -184,6 +194,8 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl { boolean isOwnershipProvided = false; String status = request.getStatus(); boolean isStatusProvided = false; + String excludeStatus = request.getExcludeStatus(); + boolean isExcludeStatusProvided = false; Date since = request.getSince(); boolean isSinceProvided = false; @@ -244,6 +256,11 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl { sql = sql + " AND e.STATUS = ?"; isStatusProvided = true; } + //Add the query for exclude status + if (excludeStatus != null && !excludeStatus.isEmpty()) { + sql = sql + " AND e.STATUS != ?"; + isExcludeStatusProvided = true; + } sql = sql + " ORDER BY ENROLMENT_ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY"; @@ -275,6 +292,9 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl { if (isStatusProvided) { stmt.setString(paramIdx++, status); } + if (isExcludeStatusProvided) { + stmt.setString(paramIdx++, excludeStatus); + } stmt.setInt(paramIdx++, request.getStartIndex()); stmt.setInt(paramIdx, request.getRowCount()); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java index b1dcc57390..fe80e47808 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java @@ -61,6 +61,8 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl { boolean isOwnershipProvided = false; String status = request.getStatus(); boolean isStatusProvided = false; + String excludeStatus = request.getExcludeStatus(); + boolean isExcludeStatusProvided = false; Date since = request.getSince(); boolean isSinceProvided = false; try { @@ -102,6 +104,11 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl { sql = sql + " AND e.STATUS = ?"; isStatusProvided = true; } + //Add the query for exclude status + if (excludeStatus != null && !excludeStatus.isEmpty()) { + sql = sql + " AND e.STATUS != ?"; + isExcludeStatusProvided = true; + } sql = sql + " LIMIT ? OFFSET ?"; @@ -127,6 +134,9 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl { if (isStatusProvided) { stmt.setString(paramIdx++, status); } + if (isExcludeStatusProvided) { + stmt.setString(paramIdx++, excludeStatus); + } stmt.setInt(paramIdx++, request.getRowCount()); stmt.setInt(paramIdx, request.getStartIndex()); rs = stmt.executeQuery(); @@ -165,6 +175,8 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl { boolean isOwnershipProvided = false; String status = request.getStatus(); boolean isStatusProvided = false; + String excludeStatus = request.getExcludeStatus(); + boolean isExcludeStatusProvided = false; Date since = request.getSince(); boolean isSinceProvided = false; @@ -225,6 +237,11 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl { sql = sql + " AND e.STATUS = ?"; isStatusProvided = true; } + //Add the query for exclude status + if (excludeStatus != null && !excludeStatus.isEmpty()) { + sql = sql + " AND e.STATUS != ?"; + isExcludeStatusProvided = true; + } sql = sql + " LIMIT ? OFFSET ?"; @@ -256,6 +273,9 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl { if (isStatusProvided) { stmt.setString(paramIdx++, status); } + if (isExcludeStatusProvided) { + stmt.setString(paramIdx++, excludeStatus); + } stmt.setInt(paramIdx, request.getRowCount()); stmt.setInt(paramIdx++, request.getStartIndex()); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java index 98cfae84ce..0bffa3af87 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java @@ -61,6 +61,8 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl { boolean isOwnershipProvided = false; String status = request.getStatus(); boolean isStatusProvided = false; + String excludeStatus = request.getExcludeStatus(); + boolean isExcludeStatusProvided = false; Date since = request.getSince(); boolean isSinceProvided = false; try { @@ -115,6 +117,11 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl { sql = sql + " AND e.STATUS = ?"; isStatusProvided = true; } + //Add the query for exclude status + if (excludeStatus != null && !excludeStatus.isEmpty()) { + sql = sql + " AND e.STATUS != ?"; + isExcludeStatusProvided = true; + } sql = sql + " ORDER BY ENROLMENT_ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY"; @@ -143,6 +150,9 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl { if (isStatusProvided) { stmt.setString(paramIdx++, status); } + if (isExcludeStatusProvided) { + stmt.setString(paramIdx++, excludeStatus); + } stmt.setInt(paramIdx++, request.getStartIndex()); stmt.setInt(paramIdx, request.getRowCount()); rs = stmt.executeQuery(); @@ -181,6 +191,8 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl { boolean isOwnershipProvided = false; String status = request.getStatus(); boolean isStatusProvided = false; + String excludeStatus = request.getExcludeStatus(); + boolean isExcludeStatusProvided = false; Date since = request.getSince(); boolean isSinceProvided = false; @@ -241,6 +253,11 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl { sql = sql + " AND e.STATUS = ?"; isStatusProvided = true; } + //Add the query for exclude status + if (excludeStatus != null && !excludeStatus.isEmpty()) { + sql = sql + " AND e.STATUS != ?"; + isExcludeStatusProvided = true; + } sql = sql + " ORDER BY ENROLMENT_ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY"; @@ -272,6 +289,9 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl { if (isStatusProvided) { stmt.setString(paramIdx++, status); } + if (isExcludeStatusProvided) { + stmt.setString(paramIdx++, excludeStatus); + } stmt.setInt(paramIdx++, request.getStartIndex()); stmt.setInt(paramIdx, request.getRowCount()); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/util/DeviceManagementDAOUtil.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/util/DeviceManagementDAOUtil.java index 6784943346..e92e2e814f 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/util/DeviceManagementDAOUtil.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/util/DeviceManagementDAOUtil.java @@ -23,6 +23,8 @@ import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo; +import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation; +import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistory; 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.internal.DeviceManagementDataHolder; @@ -245,4 +247,23 @@ public final class DeviceManagementDAOUtil { deviceInfo.setUpdatedTime(new java.util.Date(rs.getLong("UPDATE_TIMESTAMP"))); return deviceInfo; } + + public static DeviceLocationHistory loadDeviceLocation(ResultSet rs) throws SQLException { + DeviceLocationHistory deviceLocationHistory = new DeviceLocationHistory(); + deviceLocationHistory.setDeviceId(rs.getInt("DEVICE_ID")); + deviceLocationHistory.setDeviceIdentifier(rs.getString("DEVICE_ID_NAME")); + deviceLocationHistory.setTenantId(rs.getInt("TENANT_ID")); + deviceLocationHistory.setDeviceType(rs.getString("DEVICE_TYPE_NAME")); + deviceLocationHistory.setLatitude(rs.getDouble("LATITUDE")); + deviceLocationHistory.setLongitude(rs.getDouble("LONGITUDE")); + deviceLocationHistory.setSpeed(rs.getFloat("SPEED")); + deviceLocationHistory.setBearing(rs.getFloat("HEADING")); + deviceLocationHistory.setAltitude(rs.getDouble("DEVICE_ALTITUDE")); + deviceLocationHistory.setDistance(rs.getDouble("DISTANCE")); + deviceLocationHistory.setOwner(rs.getString("DEVICE_OWNER")); + deviceLocationHistory.setTimestamp(rs.getLong("TIMESTAMP")); + deviceLocationHistory.setGeoHash(rs.getString("GEO_HASH")); + return deviceLocationHistory; + } + } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/DeviceInformationManager.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/DeviceInformationManager.java index c20ac2b3c7..f9cc83fbab 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/DeviceInformationManager.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/DeviceInformationManager.java @@ -19,9 +19,12 @@ package org.wso2.carbon.device.mgt.core.device.details.mgt; +import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo; import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation; +import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException; import java.util.List; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/LocationCallback.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/LocationCallback.java new file mode 100644 index 0000000000..9bcb13dff4 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/LocationCallback.java @@ -0,0 +1,4 @@ +package org.wso2.carbon.device.mgt.core.device.details.mgt; + +public interface LocationCallback { +} 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/DeviceDetailsDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/dao/DeviceDetailsDAO.java index 576941918f..bdc44ec831 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/dao/DeviceDetailsDAO.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/dao/DeviceDetailsDAO.java @@ -19,6 +19,8 @@ package org.wso2.carbon.device.mgt.core.device.details.mgt.dao; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo; import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation; @@ -100,6 +102,16 @@ public interface DeviceDetailsDAO { */ void deleteDeviceLocation(int deviceId, int enrollmentId) throws DeviceDetailsMgtDAOException; + /** + * Add device location information to the database + * @param device Device object + * @param deviceLocation Device Location Object + * @param tenantId Tenant Id + * @throws DeviceDetailsMgtDAOException + */ + void addDeviceLocationInfo(Device device, DeviceLocation deviceLocation, int tenantId) + throws DeviceDetailsMgtDAOException; + // /** // * This method will add device application to database. // * @param deviceApplication - Device application 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 54fc1a4738..731c74b2e1 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 @@ -21,6 +21,8 @@ package org.wso2.carbon.device.mgt.core.device.details.mgt.dao.impl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.EnrolmentInfo; import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo; import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation; import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory; @@ -238,8 +240,9 @@ 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, GEO_HASH, UPDATE_TIMESTAMP, ENROLMENT_ID) " + - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + "STREET2, CITY, ZIP, STATE, COUNTRY, GEO_HASH, UPDATE_TIMESTAMP, ENROLMENT_ID, ALTITUDE, SPEED, BEARING, " + + "DISTANCE) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); stmt.setInt(1, deviceLocation.getDeviceId()); stmt.setDouble(2, deviceLocation.getLatitude()); stmt.setDouble(3, deviceLocation.getLongitude()); @@ -252,6 +255,10 @@ public class DeviceDetailsDAOImpl implements DeviceDetailsDAO { stmt.setString(10, GeoHashGenerator.encodeGeohash(deviceLocation)); stmt.setLong(11, System.currentTimeMillis()); stmt.setInt(12, enrollmentId); + stmt.setDouble(13, deviceLocation.getAltitude()); + stmt.setFloat(14, deviceLocation.getSpeed()); + stmt.setFloat(15, deviceLocation.getBearing()); + stmt.setDouble(16, deviceLocation.getDistance()); stmt.execute(); } catch (SQLException e) { throw new DeviceDetailsMgtDAOException("Error occurred while adding the device location to database.", e); @@ -317,6 +324,45 @@ public class DeviceDetailsDAOImpl implements DeviceDetailsDAO { } } + @Override + public void addDeviceLocationInfo(Device device, DeviceLocation deviceLocation, int tenantId) + throws DeviceDetailsMgtDAOException { + Connection conn; + PreparedStatement stmt = null; + String errMessage; + try { + conn = this.getConnection(); + stmt = conn.prepareStatement( + "INSERT INTO " + + "DM_DEVICE_HISTORY_LAST_SEVEN_DAYS " + + "(DEVICE_ID, DEVICE_ID_NAME, TENANT_ID, DEVICE_TYPE_NAME, LATITUDE, LONGITUDE, SPEED, HEADING, " + + "TIMESTAMP, GEO_HASH, DEVICE_OWNER, DEVICE_ALTITUDE, DISTANCE) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + + stmt.setInt(1, device.getId()); + stmt.setString(2, device.getDeviceIdentifier()); + stmt.setInt(3, tenantId); + stmt.setString(4, device.getType()); + stmt.setDouble(5, deviceLocation.getLatitude()); + stmt.setDouble(6, deviceLocation.getLongitude()); + stmt.setFloat(7, deviceLocation.getSpeed()); + stmt.setFloat(8, deviceLocation.getBearing()); + stmt.setLong(9, System.currentTimeMillis()); + stmt.setString(10, GeoHashGenerator.encodeGeohash(deviceLocation)); + stmt.setString(11, device.getEnrolmentInfo().getOwner()); + stmt.setDouble(12, deviceLocation.getAltitude()); + stmt.setDouble(13, deviceLocation.getDistance()); + stmt.execute(); + + } catch (SQLException e) { + errMessage = "Error occurred while updating the device location information to database."; + log.error(errMessage); + throw new DeviceDetailsMgtDAOException(errMessage, e); + } finally { + DeviceManagementDAOUtil.cleanupResources(stmt, null); + } + } + private Connection getConnection() throws SQLException { return DeviceManagementDAOFactory.getConnection(); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java index 2bd9914ca8..aa2c910709 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/device/details/mgt/impl/DeviceInformationManagerImpl.java @@ -54,7 +54,6 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager { private static final String LOCATION_EVENT_STREAM_DEFINITION = "org.wso2.iot.LocationStream"; private static final String DEVICE_INFO_EVENT_STREAM_DEFINITION = "org.wso2.iot.DeviceInfoStream"; - public DeviceInformationManagerImpl() { this.deviceDAO = DeviceManagementDAOFactory.getDeviceDAO(); this.deviceDetailsDAO = DeviceManagementDAOFactory.getDeviceDetailsDAO(); @@ -212,6 +211,8 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager { deviceLocation.setDeviceId(device.getId()); DeviceManagementDAOFactory.beginTransaction(); deviceDAO.updateDevice(device, CarbonContext.getThreadLocalCarbonContext().getTenantId()); + deviceDetailsDAO.addDeviceLocationInfo(device, deviceLocation, + CarbonContext.getThreadLocalCarbonContext().getTenantId()); deviceDetailsDAO.deleteDeviceLocation(deviceLocation.getDeviceId(), device.getEnrolmentInfo().getId()); deviceDetailsDAO.addDeviceLocation(deviceLocation, device.getEnrolmentInfo().getId()); if (DeviceManagerUtil.isPublishLocationResponseEnabled()) { @@ -219,7 +220,11 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager { Object[] payload = new Object[]{ deviceLocation.getUpdatedTime().getTime(), deviceLocation.getLatitude(), - deviceLocation.getLongitude() + deviceLocation.getLongitude(), + deviceLocation.getAltitude(), + deviceLocation.getSpeed(), + deviceLocation.getBearing(), + deviceLocation.getDistance() }; DeviceManagerUtil.getEventPublisherService().publishEvent( LOCATION_EVENT_STREAM_DEFINITION, "1.0.0", metaData, new Object[0], payload 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 979efa4d87..da1bddecae 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 @@ -55,6 +55,7 @@ import org.wso2.carbon.device.mgt.common.configuration.mgt.AmbiguousConfiguratio import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationManagementException; import org.wso2.carbon.device.mgt.common.configuration.mgt.DeviceConfiguration; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; +import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistory; import org.wso2.carbon.device.mgt.common.license.mgt.License; import org.wso2.carbon.device.mgt.common.operation.mgt.Activity; import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; @@ -715,6 +716,18 @@ public interface DeviceManagementProviderService { */ List getDeviceTypes() throws DeviceManagementException; + /** + * This retrieves the device location histories + * + * @param deviceIdentifier Device Identifier object + * @param from Specified start timestamp + * @param to Specified end timestamp + * @throws DeviceManagementException + * @return list of device's location histories + */ + List getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from, long to) + throws DeviceManagementException; + /** * This retrieves the device pull notification payload and passes to device type pull notification subscriber. * @throws PullNotificationExecutionFailedException 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 fa0ebc5d2b..abe8be5385 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 @@ -79,6 +79,7 @@ import org.wso2.carbon.device.mgt.common.configuration.mgt.DevicePropertyInfo; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo; import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation; +import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistory; import org.wso2.carbon.device.mgt.common.enrollment.notification.EnrollmentNotificationConfiguration; import org.wso2.carbon.device.mgt.common.enrollment.notification.EnrollmentNotifier; import org.wso2.carbon.device.mgt.common.enrollment.notification.EnrollmentNotifierException; @@ -2822,6 +2823,36 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } } + @Override + public List getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from, long to) + throws DeviceManagementException { + + if (log.isDebugEnabled()) { + log.debug("Get device location information"); + } + + List deviceLocationHistory; + String errMessage; + + try { + DeviceManagementDAOFactory.openConnection(); + deviceLocationHistory = deviceDAO.getDeviceLocationInfo(deviceIdentifier, from, to); + + } catch (DeviceManagementDAOException e) { + errMessage = "Error occurred in getDeviceLocationInfo"; + log.error(errMessage, e); + throw new DeviceManagementException(errMessage, e); + } catch (SQLException e) { + errMessage = "Error occurred while opening a connection to the data source"; + log.error(errMessage, e); + throw new DeviceManagementException(errMessage, e); + } finally { + DeviceManagementDAOFactory.closeConnection(); + } + + return deviceLocationHistory; + } + @Override public void notifyPullNotificationSubscriber(DeviceIdentifier deviceIdentifier, Operation operation) throws PullNotificationExecutionFailedException { @@ -3159,11 +3190,19 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } } + /** + * Extracting device location properties + * @param device Device object + */ private void extractDeviceLocationToUpdate(Device device) { List properties = device.getProperties(); if (properties != null) { String latitude = null; String longitude = null; + String altitude = null; + String speed = null; + String bearing = null; + String distance = null; for (Device.Property p : properties) { if (p.getName().equalsIgnoreCase("latitude")) { latitude = p.getValue(); @@ -3171,6 +3210,18 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv if (p.getName().equalsIgnoreCase("longitude")) { longitude = p.getValue(); } + if (p.getName().equalsIgnoreCase("altitude")) { + altitude = p.getValue(); + } + if (p.getName().equalsIgnoreCase("speed")) { + speed = p.getValue(); + } + if (p.getName().equalsIgnoreCase("bearing")) { + bearing = p.getValue(); + } + if (p.getName().equalsIgnoreCase("distance")) { + distance = p.getValue(); + } } if (latitude != null && longitude != null && !latitude.isEmpty() && !longitude.isEmpty()) { DeviceLocation deviceLocation = new DeviceLocation(); @@ -3178,8 +3229,12 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv deviceLocation.setDeviceIdentifier(new DeviceIdentifier(device.getDeviceIdentifier(), device.getType())); try { + deviceLocation.setAltitude(Double.parseDouble(altitude)); deviceLocation.setLatitude(Double.parseDouble(latitude)); deviceLocation.setLongitude(Double.parseDouble(longitude)); + deviceLocation.setDistance(Double.parseDouble(distance)); + deviceLocation.setSpeed(Float.parseFloat(speed)); + deviceLocation.setBearing(Float.parseFloat(bearing)); DeviceInformationManager deviceInformationManager = new DeviceInformationManagerImpl(); deviceInformationManager.addDeviceLocation(deviceLocation); } catch (Exception e) { @@ -3187,7 +3242,8 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv // a warning for reference. log.warn("Error occurred while trying to add '" + device.getType() + "' device '" + device.getDeviceIdentifier() + "' (id:'" + device.getId() + "') location (lat:" + latitude + - ", lon:" + longitude + ") due to:" + e.getMessage()); + ", lon:" + longitude + ", altitude: " + altitude + + ", speed: " + speed + ", bearing:" + bearing + ", distance: " + distance + ") due to:" + e.getMessage()); } } } 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 a89e966d28..88419e9082 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 @@ -458,6 +458,10 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_LOCATION ( COUNTRY VARCHAR(45) NULL, GEO_HASH VARCHAR(45) NULL, UPDATE_TIMESTAMP BIGINT(15) NOT NULL, + ALTITUDE DOUBLE NULL, + SPEED FLOAT NULL, + BEARING FLOAT NULL, + DISTANCE DOUBLE NULL, PRIMARY KEY (ID), CONSTRAINT DM_DEVICE_LOCATION_DEVICE FOREIGN KEY (DEVICE_ID) @@ -505,6 +509,25 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_DETAIL ( ON UPDATE NO ACTION ); +CREATE TABLE IF NOT EXISTS DM_DEVICE_HISTORY_LAST_SEVEN_DAYS +( + ID INTEGER AUTO_INCREMENT NOT NULL, + DEVICE_ID INT NOT NULL, + DEVICE_ID_NAME VARCHAR(255) NOT NULL, + TENANT_ID INT NOT NULL, + DEVICE_TYPE_NAME VARCHAR(45) NOT NULL, + LATITUDE DOUBLE NULL, + LONGITUDE DOUBLE NULL, + SPEED FLOAT NULL, + HEADING FLOAT NULL, + TIMESTAMP BIGINT(15) NOT NULL, + GEO_HASH VARCHAR(45) NULL, + DEVICE_OWNER VARCHAR(45) NULL, + DEVICE_ALTITUDE DOUBLE NULL, + DISTANCE DOUBLE NULL, + PRIMARY KEY (ID) +); + -- POLICY AND DEVICE GROUP MAPPING -- CREATE TABLE IF NOT EXISTS DM_DEVICE_GROUP_POLICY ( 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 7b1af45fbb..3023883547 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 @@ -507,6 +507,10 @@ CREATE TABLE DM_DEVICE_LOCATION ( COUNTRY VARCHAR(45) NULL, GEO_HASH VARCHAR(45) NULL, UPDATE_TIMESTAMP BIGINT NOT NULL, + ALTITUDE FLOAT NULL, + SPEED FLOAT NULL, + BEARING FLOAT NULL, + DISTANCE FLOAT NULL, PRIMARY KEY (ID), INDEX DM_DEVICE_LOCATION_DEVICE_idx (DEVICE_ID ASC), INDEX DM_DEVICE_LOCATION_GEO_hashx (GEO_HASH ASC), @@ -523,6 +527,26 @@ CREATE TABLE DM_DEVICE_LOCATION ( ON UPDATE NO ACTION ); +IF NOT EXISTS (SELECT * FROM SYS.OBJECTS WHERE OBJECT_ID = OBJECT_ID(N'[DBO].[DM_DEVICE_HISTORY_LAST_SEVEN_DAYS]') AND TYPE IN (N'U')) +CREATE TABLE IF NOT EXISTS DM_DEVICE_HISTORY_LAST_SEVEN_DAYS +( + ID INTEGER IDENTITY (1,1) NOT NULL, + DEVICE_ID INTEGER NOT NULL, + DEVICE_ID_NAME VARCHAR(255) NOT NULL, + TENANT_ID INTEGER NOT NULL, + DEVICE_TYPE_NAME VARCHAR(45) NOT NULL, + LATITUDE FLOAT NULL, + LONGITUDE FLOAT NULL, + SPEED FLOAT NULL, + HEADING FLOAT NULL, + TIMESTAMP BIGINT(15) NOT NULL, + GEO_HASH VARCHAR(45) NULL, + DEVICE_OWNER VARCHAR(45) NULL, + DEVICE_ALTITUDE FLOAT NULL, + DISTANCE FLOAT NULL, + PRIMARY KEY (ID) +); + IF NOT EXISTS (SELECT * FROM SYS.OBJECTS WHERE OBJECT_ID = OBJECT_ID(N'[DBO].[DM_DEVICE_DETAIL]') AND TYPE IN (N'U')) CREATE TABLE DM_DEVICE_DETAIL ( ID INTEGER IDENTITY(1,1) NOT NULL, 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 94f838a7b0..22c0b7ec9e 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 @@ -520,6 +520,10 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_LOCATION ( COUNTRY VARCHAR(45) NULL, GEO_HASH VARCHAR(45) NULL, UPDATE_TIMESTAMP BIGINT(15) NOT NULL, + ALTITUDE DOUBLE NULL, + SPEED FLOAT NULL, + BEARING FLOAT NULL, + DISTANCE DOUBLE NULL, PRIMARY KEY (ID), INDEX DM_DEVICE_LOCATION_DEVICE_idx (DEVICE_ID ASC), INDEX DM_DEVICE_LOCATION_GEO_hashx (GEO_HASH ASC), @@ -537,6 +541,26 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_LOCATION ( ) ENGINE = InnoDB; +CREATE TABLE IF NOT EXISTS DM_DEVICE_HISTORY_LAST_SEVEN_DAYS +( + ID INTEGER AUTO_INCREMENT NOT NULL, + DEVICE_ID INT NOT NULL, + DEVICE_ID_NAME VARCHAR(255) NOT NULL, + TENANT_ID INT NOT NULL, + DEVICE_TYPE_NAME VARCHAR(45) NOT NULL, + LATITUDE DOUBLE NULL, + LONGITUDE DOUBLE NULL, + SPEED FLOAT NULL, + HEADING FLOAT NULL, + TIMESTAMP BIGINT(15) NOT NULL, + GEO_HASH VARCHAR(45) NULL, + DEVICE_OWNER VARCHAR(45) NULL, + DEVICE_ALTITUDE DOUBLE NULL, + DISTANCE DOUBLE NULL, + PRIMARY KEY (ID) +) +ENGINE = InnoDB; + CREATE TABLE IF NOT EXISTS DM_DEVICE_DETAIL ( ID INT NOT NULL AUTO_INCREMENT, DEVICE_ID INT NOT NULL, 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 c626d1c4c6..e428ab2183 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 @@ -842,29 +842,34 @@ WHEN (NEW.ID IS NULL) END; / -CREATE TABLE DM_DEVICE_LOCATION ( - ID NUMBER(10) NOT NULL, - DEVICE_ID NUMBER(10) NOT NULL, - ENROLMENT_ID NUMBER(10) NOT NULL, - LATITUDE BINARY_DOUBLE NULL, - LONGITUDE BINARY_DOUBLE NULL, - STREET1 VARCHAR2(255) NULL, - STREET2 VARCHAR2(45) NULL, - CITY VARCHAR2(45) NULL, - 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), - CONSTRAINT DM_DEVICE_LOCATION_DEVICE - FOREIGN KEY (DEVICE_ID) - REFERENCES DM_DEVICE (ID), - CONSTRAINT DM_DEVICE_LOCATION_DM_ENROLLMENT - FOREIGN KEY (ENROLMENT_ID) - REFERENCES DM_ENROLMENT (ID) -) +CREATE TABLE DM_DEVICE_LOCATION +( + ID NUMBER(10) NOT NULL, + DEVICE_ID NUMBER(10) NOT NULL, + TENANT_ID NUMBER(10) NOT NULL, + LATITUDE BINARY_DOUBLE NULL, + LONGITUDE BINARY_DOUBLE NULL, + STREET1 VARCHAR2(255) NULL, + STREET2 VARCHAR2(45) NULL, + CITY VARCHAR2(45) NULL, + ZIP VARCHAR2(10) NULL, + STATE VARCHAR2(45) NULL, + COUNTRY VARCHAR2(45) NULL, + GEO_HASH VARCHAR(45) NULL, + UPDATE_TIMESTAMP NUMBER(19) NOT NULL, + ALTITUDE BINARY_DOUBLE NULL, + SPEED FLOAT NULL, + BEARING FLOAT NULL, + DISTANCE BINARY_DOUBLE NULL, + PRIMARY KEY (ID), + CONSTRAINT DM_DEVICE_LOCATION_DEVICE + FOREIGN KEY (DEVICE_ID) + REFERENCES DM_DEVICE (ID), + CONSTRAINT DM_DEVICE_LOCATION_DM_ENROLLMENT + FOREIGN KEY (ENROLMENT_ID) + REFERENCES DM_ENROLMENT (ID) +) / CREATE INDEX DM_DEVICE_LOCATION_GEO_hashx ON DM_DEVICE_LOCATION(GEO_HASH ASC) / @@ -880,6 +885,44 @@ WHEN (NEW.ID IS NULL) END; / +CREATE TABLE IF NOT EXISTS DM_DEVICE_HISTORY_LAST_SEVEN_DAYS +( + ID NUMBER(10) NOT NULL, + DEVICE_ID NUMBER(10) NOT NULL, + DEVICE_ID_NAME VARCHAR(255) NOT NULL, + ENROLMENT_ID NUMBER(10) NOT NULL, + DEVICE_TYPE_NAME VARCHAR(45) NOT NULL, + LATITUDE BINARY_DOUBLE NULL, + LONGITUDE BINARY_DOUBLE NULL, + SPEED FLOAT NULL, + HEADING FLOAT NULL, + TIMESTAMP BIGINT(15) NOT NULL, + GEO_HASH VARCHAR(45) NULL, + DEVICE_OWNER VARCHAR(45) NULL, + DEVICE_ALTITUDE BINARY_DOUBLE NULL, + DISTANCE BINARY_DOUBLE NULL, + PRIMARY KEY (ID) +) + / +CREATE INDEX DM_DEVICE_HISTORY_LAST_SEVEN_DAYS_GEO_hashx ON DM_DEVICE_HISTORY_LAST_SEVEN_DAYS (GEO_HASH ASC) + / + +-- Generate ID using sequence and trigger +CREATE SEQUENCE DM_DEVICE_HISTORY_LAST_SEVEN_DAYS_seq START WITH 1 INCREMENT BY 1 NOCACHE + / +CREATE +OR +REPLACE +TRIGGER DM_DEVICE_HISTORY_LAST_SEVEN_DAYS_seq_tr +BEFORE INSERT +ON DM_DEVICE_HISTORY_LAST_SEVEN_DAYS FOR EACH ROW +WHEN (NEW.ID IS NULL) + BEGIN +SELECT DM_DEVICE_HISTORY_LAST_SEVEN_DAYS_seq.NEXTVAL INTO :NEW.ID +FROM DUAL; +END; +/ + CREATE TABLE DM_DEVICE_DETAIL ( ID NUMBER(10) NOT NULL, DEVICE_ID NUMBER(10) NOT NULL, 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 24ded4d59b..27e674e5a3 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 @@ -461,6 +461,10 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_LOCATION ( COUNTRY VARCHAR(45) NULL, GEO_HASH VARCHAR(45) NULL, UPDATE_TIMESTAMP BIGINT NOT NULL, + ALTITUDE DOUBLE PRECISION NULL, + SPEED FLOAT NULL, + BEARING FLOAT NULL, + DISTANCE DOUBLE PRECISION NULL, CONSTRAINT DM_DEVICE_LOCATION_DEVICE FOREIGN KEY (DEVICE_ID) REFERENCES DM_DEVICE (ID) @@ -473,6 +477,24 @@ CREATE TABLE IF NOT EXISTS DM_DEVICE_LOCATION ( ON UPDATE NO ACTION ); +CREATE TABLE IF NOT EXISTS DM_DEVICE_HISTORY_LAST_SEVEN_DAYS +( + ID BIGSERIAL NOT NULL PRIMARY KEY, + DEVICE_ID INT NOT NULL, + DEVICE_ID_NAME VARCHAR(255) NOT NULL, + TENANT_ID INT NOT NULL, + DEVICE_TYPE_NAME VARCHAR(45) NOT NULL, + LATITUDE DOUBLE PRECISION NULL, + LONGITUDE DOUBLE PRECISION NULL, + SPEED FLOAT NULL, + HEADING FLOAT NULL, + TIMESTAMP BIGINT(15) NOT NULL, + GEO_HASH VARCHAR(45) NULL, + DEVICE_OWNER VARCHAR(45) NULL, + DEVICE_ALTITUDE DOUBLE PRECISION NULL, + DISTANCE DOUBLE PRECISION NULL, +); + CREATE INDEX DM_DEVICE_LOCATION_GEO_hashx ON DM_DEVICE_LOCATION(GEO_HASH ASC); CREATE TABLE IF NOT EXISTS DM_DEVICE_DETAIL (