mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Merge branch 'geo-backend' into 'master'
Move device location history grouping logic to the backend Closes product-iots#343 See merge request entgra/carbon-device-mgt!468
This commit is contained in:
commit
da5c7e307f
@ -150,7 +150,7 @@ class App extends React.Component {
|
||||
<ConfigContext.Provider value={this.state.config}>
|
||||
<div>
|
||||
<Switch>
|
||||
<Redirect exact from="/entgra" to="/entgra/reports" />
|
||||
<Redirect exact from="/entgra" to="/entgra/devices" />
|
||||
{this.props.routes.map(route => (
|
||||
<RouteWithSubRoutes key={route.path} {...route} />
|
||||
))}
|
||||
|
||||
@ -65,7 +65,7 @@ const routes = [
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/geo',
|
||||
path: '/entgra/geo/history/:deviceType/:deviceIdentifier',
|
||||
component: Geo,
|
||||
exact: true,
|
||||
},
|
||||
|
||||
@ -20,7 +20,6 @@ import React from 'react';
|
||||
import { Layout, Menu, Icon } from 'antd';
|
||||
import { Switch, Link } from 'react-router-dom';
|
||||
import RouteWithSubRoutes from '../../components/RouteWithSubRoutes';
|
||||
import { Redirect } from 'react-router';
|
||||
import './styles.css';
|
||||
import { withConfigContext } from '../../components/ConfigContext';
|
||||
import Logout from './components/Logout';
|
||||
@ -92,26 +91,6 @@ class Home extends React.Component {
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
</SubMenu>
|
||||
<SubMenu
|
||||
key="geo"
|
||||
title={
|
||||
<span>
|
||||
<Icon type="environment" />
|
||||
<span>Geo</span>
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<Menu.Item key="singleDevice">
|
||||
<Link to="/entgra/geo">
|
||||
<span>Single Device View</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="deviceGroup">
|
||||
<Link to="#">
|
||||
<span>Device Group View</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Item key="reports">
|
||||
<Link to="/entgra/reports">
|
||||
<Icon type="bar-chart" />
|
||||
@ -198,7 +177,6 @@ class Home extends React.Component {
|
||||
|
||||
<Content>
|
||||
<Switch>
|
||||
<Redirect exact from="/entgra/devices" to="/entgra/reports" />
|
||||
{this.state.routes.map(route => (
|
||||
<RouteWithSubRoutes key={route.path} {...route} />
|
||||
))}
|
||||
|
||||
@ -33,6 +33,7 @@ import TimeAgo from 'javascript-time-ago';
|
||||
import en from 'javascript-time-ago/locale/en';
|
||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
||||
import BulkActionBar from './components/BulkActionBar';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
let config = null;
|
||||
|
||||
@ -126,6 +127,20 @@ const columns = [
|
||||
},
|
||||
// todo add filtering options
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
dataIndex: 'deviceIdentifier',
|
||||
key: 'actions',
|
||||
// eslint-disable-next-line react/display-name
|
||||
render: (data, row) => {
|
||||
const { type, deviceIdentifier } = row;
|
||||
return (
|
||||
<Link to={`/entgra/geo/history/${type}/${deviceIdentifier}`}>
|
||||
<Icon type="environment" /> Location History
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const getTimeAgo = time => {
|
||||
|
||||
@ -57,62 +57,44 @@ class CustomMap extends Component {
|
||||
|
||||
/**
|
||||
* Polyline draw for historical locations
|
||||
* @param locationData - location data object
|
||||
* @param locationHistorySnapshots - location data object
|
||||
* @returns content
|
||||
*/
|
||||
polylineMarker = locationData => {
|
||||
const locationPoints = [...locationData];
|
||||
polylineMarker = locationHistorySnapshots => {
|
||||
const polyLines = [];
|
||||
|
||||
while (locationPoints.length > 0) {
|
||||
// Array to store positions for next polyline
|
||||
const positions = [];
|
||||
// Make a copy of remaining location points
|
||||
const cachedLocationPoints = [...locationPoints];
|
||||
// Iterate the remaining cached locations
|
||||
for (let i = 0; i < cachedLocationPoints.length; i++) {
|
||||
positions.push([
|
||||
cachedLocationPoints[i].latitude,
|
||||
cachedLocationPoints[i].longitude,
|
||||
]);
|
||||
const currentPoint = cachedLocationPoints[i];
|
||||
// Remove the current location from the locationPoints
|
||||
locationPoints.shift();
|
||||
if (i < cachedLocationPoints.length - 1) {
|
||||
const nextPoint = cachedLocationPoints[i + 1];
|
||||
// Draw a dashed line for long for location points with long interval
|
||||
if (
|
||||
nextPoint.timestamp - currentPoint.timestamp >
|
||||
this.props.context.geoMap.timeout * 1000
|
||||
) {
|
||||
// Create a dashed line
|
||||
polyLines.push(
|
||||
<Polyline
|
||||
key={polyLines.length}
|
||||
color="#414042"
|
||||
positions={[
|
||||
[currentPoint.latitude, currentPoint.longitude],
|
||||
[nextPoint.latitude, nextPoint.longitude],
|
||||
]}
|
||||
smoothFactor={10}
|
||||
weight={5}
|
||||
dashArray="7"
|
||||
/>,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create a polyline from provided positions
|
||||
locationHistorySnapshots.forEach(locationHistorySnapshots => {
|
||||
polyLines.push(
|
||||
<Polyline
|
||||
key={polyLines.length}
|
||||
color="#414042"
|
||||
positions={positions}
|
||||
positions={locationHistorySnapshots.map(snapshot => {
|
||||
return [snapshot.latitude, snapshot.longitude];
|
||||
})}
|
||||
smoothFactor={10}
|
||||
weight={5}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
for (let i = 1; i < locationHistorySnapshots.length; i++) {
|
||||
const startPosition = locationHistorySnapshots[i][0];
|
||||
const endingPosition =
|
||||
locationHistorySnapshots[i - 1][
|
||||
locationHistorySnapshots[i - 1].length - 1
|
||||
];
|
||||
polyLines.push(
|
||||
<Polyline
|
||||
key={polyLines.length}
|
||||
color="#414042"
|
||||
positions={[
|
||||
[startPosition.latitude, startPosition.longitude],
|
||||
[endingPosition.latitude, endingPosition.longitude],
|
||||
]}
|
||||
smoothFactor={10}
|
||||
weight={5}
|
||||
dashArray="7"
|
||||
/>,
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@ -125,22 +107,23 @@ class CustomMap extends Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const locationData = this.props.locationData;
|
||||
const locationHistorySnapshots = this.props.locationHistorySnapshots;
|
||||
const config = this.props.context;
|
||||
const attribution = config.geoMap.attribution;
|
||||
const url = config.geoMap.url;
|
||||
const startingPoint = [locationData[0].latitude, locationData[0].longitude];
|
||||
const endPoint = [
|
||||
locationData[locationData.length - 1].latitude,
|
||||
locationData[locationData.length - 1].longitude,
|
||||
];
|
||||
const firstSnapshot = locationHistorySnapshots[0][0];
|
||||
const lastSnapshotList =
|
||||
locationHistorySnapshots[locationHistorySnapshots.length - 1];
|
||||
const lastSnapshot = lastSnapshotList[lastSnapshotList.length - 1];
|
||||
const startingPoint = [firstSnapshot.latitude, firstSnapshot.longitude];
|
||||
const endPoint = [lastSnapshot.latitude, lastSnapshot.longitude];
|
||||
const zoom = config.geoMap.defaultZoomLevel;
|
||||
return (
|
||||
<div style={{ backgroundColor: '#ffffff', borderRadius: 5, padding: 5 }}>
|
||||
<Map center={startingPoint} zoom={zoom}>
|
||||
<TileLayer url={url} attribution={attribution} />
|
||||
<Fragment>
|
||||
{this.polylineMarker(locationData)}
|
||||
{this.polylineMarker(locationHistorySnapshots)}
|
||||
<Marker icon={pinStart} position={startingPoint}>
|
||||
<Popup keepInView={true}>Start</Popup>
|
||||
<Tooltip direction="top" permanent={true}>
|
||||
|
||||
@ -18,16 +18,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import moment from 'moment';
|
||||
import {
|
||||
Button,
|
||||
Select,
|
||||
message,
|
||||
notification,
|
||||
Tag,
|
||||
Tooltip,
|
||||
Empty,
|
||||
DatePicker,
|
||||
} from 'antd';
|
||||
import { message, notification, Empty, DatePicker } from 'antd';
|
||||
import axios from 'axios';
|
||||
import { withConfigContext } from '../../../../../../components/ConfigContext';
|
||||
import GeoCustomMap from '../CustomMap';
|
||||
@ -53,7 +44,7 @@ class GeoDashboard extends React.Component {
|
||||
this.state = {
|
||||
deviceData: [],
|
||||
selectedDevice: '',
|
||||
locationData: [],
|
||||
locationHistorySnapshots: [],
|
||||
loading: false,
|
||||
start: start,
|
||||
end: end,
|
||||
@ -62,119 +53,23 @@ class GeoDashboard extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchDevices();
|
||||
// this.fetchCurrentLocation();
|
||||
this.fetchLocationHistory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call back on apply button in the date time picker
|
||||
* @param startDate - start date
|
||||
* @param endDate - end date
|
||||
*/
|
||||
applyCallback = (dates, dateStrings) => {
|
||||
console.log('Apply Callback');
|
||||
this.setState({
|
||||
start: dateStrings[0],
|
||||
end: dateStrings[1],
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 (
|
||||
<Tooltip placement="rightBottom" title={toolTip}>
|
||||
<Button disabled={flag} onClick={this.handleApiCall}>
|
||||
Fetch Locations
|
||||
</Button>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* fetches device data to populate the dropdown list
|
||||
*/
|
||||
fetchDevices = () => {
|
||||
fetchLocationHistory = () => {
|
||||
const toInMills = moment(this.state.end);
|
||||
const fromInMills = moment(this.state.start);
|
||||
const config = this.props.context;
|
||||
this.setState({ loading: true });
|
||||
|
||||
@ -183,14 +78,21 @@ class GeoDashboard extends React.Component {
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/devices?status=ACTIVE&status=INACTIVE&status=UNCLAIMED&status=UNREACHABLE&status=SUSPENDED&' +
|
||||
'status=DISENROLLMENT_REQUESTED&status=BLOCKED&status=CREATED',
|
||||
'/devices/' +
|
||||
this.props.deviceType +
|
||||
'/' +
|
||||
this.props.deviceIdentifier +
|
||||
'/location-history?' +
|
||||
'from=' +
|
||||
fromInMills +
|
||||
'&to=' +
|
||||
toInMills,
|
||||
)
|
||||
.then(res => {
|
||||
if (res.status === 200) {
|
||||
this.setState({
|
||||
loading: false,
|
||||
deviceData: res.data.data.devices,
|
||||
locationHistorySnapshots: res.data.data.locationHistorySnapshots,
|
||||
});
|
||||
}
|
||||
})
|
||||
@ -202,11 +104,12 @@ class GeoDashboard extends React.Component {
|
||||
notification.error({
|
||||
message: 'There was a problem',
|
||||
duration: 0,
|
||||
description: 'Error occurred while trying to load devices.',
|
||||
description: 'Error occurred while trying to fetch locations......',
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({ loading: false });
|
||||
console.log(error);
|
||||
});
|
||||
};
|
||||
|
||||
@ -235,76 +138,29 @@ class GeoDashboard extends React.Component {
|
||||
'1 Month': [moment(start).subtract(1, 'months'), moment(end)],
|
||||
};
|
||||
|
||||
let { deviceData } = this.state;
|
||||
|
||||
return (
|
||||
<div className="controllerDiv">
|
||||
<RangePicker
|
||||
ranges={ranges}
|
||||
style={{ marginRight: 20 }}
|
||||
style={{ marginRight: 20, width: 400 }}
|
||||
showTime
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
defaultValue={[this.state.start, this.state.end]}
|
||||
onChange={this.applyCallback}
|
||||
onOk={this.fetchLocationHistory}
|
||||
size="large"
|
||||
/>
|
||||
|
||||
<Select
|
||||
showSearch
|
||||
style={{ width: 220, marginRight: 20 }}
|
||||
placeholder="Select a Device"
|
||||
optionFilterProp="children"
|
||||
onChange={this.handleDeviceList}
|
||||
filterOption={(input, option) =>
|
||||
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >=
|
||||
0
|
||||
}
|
||||
>
|
||||
{deviceData.map((device, index) => (
|
||||
<Select.Option key={index} value={index}>
|
||||
{device.name + ' '}
|
||||
{this.statusTag(device)}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
{this.fetchLocationButton()}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 <Tag color={color}>{status}</Tag>;
|
||||
};
|
||||
|
||||
render() {
|
||||
const locationData = [...this.state.locationData];
|
||||
|
||||
const { locationHistorySnapshots } = this.state;
|
||||
return (
|
||||
<div className="container">
|
||||
{this.controllerBar()}
|
||||
{locationData.length > 0 ? (
|
||||
<GeoCustomMap locationData={locationData} />
|
||||
{locationHistorySnapshots.length > 0 ? (
|
||||
<GeoCustomMap locationHistorySnapshots={locationHistorySnapshots} />
|
||||
) : (
|
||||
<Empty />
|
||||
)}
|
||||
|
||||
@ -32,6 +32,7 @@ class Geo extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { deviceIdentifier, deviceType } = this.props.match.params;
|
||||
return (
|
||||
<div>
|
||||
<PageHeader style={{ paddingTop: 0 }}>
|
||||
@ -41,11 +42,14 @@ class Geo extends React.Component {
|
||||
<Icon type="home" /> Home
|
||||
</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Geo</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/entgra">Devices</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>{`Location History - ${deviceType} / ${deviceIdentifier}`}</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap">
|
||||
<h3>Geo</h3>
|
||||
<Paragraph>Geo Location Service</Paragraph>
|
||||
<h3>Location History </h3>
|
||||
<Paragraph>{`${deviceType} / ${deviceIdentifier}`}</Paragraph>
|
||||
</div>
|
||||
</PageHeader>
|
||||
<div
|
||||
@ -56,7 +60,10 @@ class Geo extends React.Component {
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<GeoDashboard />
|
||||
<GeoDashboard
|
||||
deviceIdentifier={deviceIdentifier}
|
||||
deviceType={deviceType}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -36,6 +36,8 @@
|
||||
|
||||
package org.wso2.carbon.device.mgt.jaxrs.service.impl;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import org.apache.commons.httpclient.HttpStatus;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
@ -46,6 +48,8 @@ import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
|
||||
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.MonitoringOperation;
|
||||
import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig;
|
||||
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;
|
||||
@ -56,6 +60,7 @@ import org.wso2.carbon.device.mgt.common.device.details.DeviceData;
|
||||
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.device.details.DeviceLocationHistorySnapshot;
|
||||
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;
|
||||
@ -494,8 +499,8 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
|
||||
@PathParam("deviceId") String deviceId,
|
||||
@QueryParam("from") long from, @QueryParam("to") long to) {
|
||||
|
||||
List<DeviceLocationHistory> deviceLocationHistory;
|
||||
String errorMessage;
|
||||
DeviceLocationHistory deviceLocationHistory = new DeviceLocationHistory();
|
||||
|
||||
try {
|
||||
RequestValidationUtil.validateDeviceIdentifier(deviceType, deviceId);
|
||||
@ -521,7 +526,46 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
|
||||
new ErrorResponse.ErrorResponseBuilder().setCode(400l).setMessage(errorMessage)).build();
|
||||
}
|
||||
|
||||
deviceLocationHistory = dms.getDeviceLocationInfo(deviceIdentifier, from, to);
|
||||
List<List<DeviceLocationHistorySnapshot>> locationHistorySnapshotList = new ArrayList<>();
|
||||
// Get the location history snapshots for the given period
|
||||
List<DeviceLocationHistorySnapshot> deviceLocationHistorySnapshots = dms.getDeviceLocationInfo(deviceIdentifier, from, to);
|
||||
|
||||
OperationMonitoringTaskConfig operationMonitoringTaskConfig = dms.getDeviceMonitoringConfig(deviceType);
|
||||
int taskFrequency = operationMonitoringTaskConfig.getFrequency();
|
||||
int operationRecurrentTimes = 0;
|
||||
|
||||
List<MonitoringOperation> monitoringOperations = operationMonitoringTaskConfig.getMonitoringOperation();
|
||||
for (MonitoringOperation monitoringOperation :
|
||||
monitoringOperations) {
|
||||
if (monitoringOperation.getTaskName().equals("DEVICE_LOCATION")) {
|
||||
operationRecurrentTimes = monitoringOperation.getRecurrentTimes();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Device Location operation frequency in milliseconds. Adding 100000 ms as an error
|
||||
long operationFrequency = taskFrequency * operationRecurrentTimes + 100000;
|
||||
|
||||
Queue<DeviceLocationHistorySnapshot> deviceLocationHistorySnapshotsQueue = new LinkedList<>(deviceLocationHistorySnapshots);
|
||||
|
||||
while (deviceLocationHistorySnapshotsQueue.size() > 0) {
|
||||
List<DeviceLocationHistorySnapshot> snapshots = new ArrayList<>();
|
||||
// Make a copy of remaining snapshots
|
||||
List<DeviceLocationHistorySnapshot> cachedSnapshots = new ArrayList<>(deviceLocationHistorySnapshotsQueue);
|
||||
|
||||
for (int i = 0; i < cachedSnapshots.size(); i++) {
|
||||
DeviceLocationHistorySnapshot currentSnapshot = deviceLocationHistorySnapshotsQueue.poll();
|
||||
snapshots.add(currentSnapshot);
|
||||
if (deviceLocationHistorySnapshotsQueue.size() > 0) {
|
||||
DeviceLocationHistorySnapshot nextSnapshot = deviceLocationHistorySnapshotsQueue.peek();
|
||||
if (nextSnapshot.getUpdatedTime().getTime() - currentSnapshot.getUpdatedTime().getTime() > operationFrequency) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
locationHistorySnapshotList.add(snapshots);
|
||||
}
|
||||
deviceLocationHistory.setLocationHistorySnapshots(locationHistorySnapshotList);
|
||||
|
||||
|
||||
} catch (DeviceManagementException e) {
|
||||
errorMessage = "Error occurred while fetching the device information.";
|
||||
|
||||
@ -18,147 +18,18 @@
|
||||
|
||||
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.")
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DeviceLocationHistory implements Serializable {
|
||||
private List<List<DeviceLocationHistorySnapshot>> locationHistorySnapshots = new ArrayList<>();
|
||||
|
||||
@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 List<List<DeviceLocationHistorySnapshot>> getLocationHistorySnapshots() {
|
||||
return locationHistorySnapshots;
|
||||
}
|
||||
|
||||
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;
|
||||
public void setLocationHistorySnapshots(List<List<DeviceLocationHistorySnapshot>> locationHistorySnapshots) {
|
||||
this.locationHistorySnapshots = locationHistorySnapshots;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 DeviceLocationHistorySnapshot extends DeviceLocation implements Serializable {
|
||||
|
||||
@ApiModelProperty(name = "geoHash", value = "Geo Hash", required = true)
|
||||
private String geoHash;
|
||||
@ApiModelProperty(name = "tenantId", value = "Tenant Id.", required = true)
|
||||
private int tenantId;
|
||||
@ApiModelProperty(name = "owner", value = "Owner.", required = true)
|
||||
private String owner;
|
||||
|
||||
public DeviceLocationHistorySnapshot() {
|
||||
}
|
||||
|
||||
public String getGeoHash() {
|
||||
return geoHash;
|
||||
}
|
||||
|
||||
public void setGeoHash(String geoHash) {
|
||||
this.geoHash = geoHash;
|
||||
}
|
||||
|
||||
public int getTenantId() {
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
public void setTenantId(int tenantId) {
|
||||
this.tenantId = tenantId;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
}
|
||||
@ -41,9 +41,9 @@ 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.Count;
|
||||
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.common.device.details.DeviceData;
|
||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
|
||||
import org.wso2.carbon.device.mgt.core.dto.DeviceType;
|
||||
import org.wso2.carbon.device.mgt.core.geo.GeoCluster;
|
||||
import org.wso2.carbon.device.mgt.core.geo.geoHash.GeoCoordinate;
|
||||
@ -595,7 +595,7 @@ public interface DeviceDAO {
|
||||
* @return
|
||||
* @throws DeviceManagementDAOException
|
||||
*/
|
||||
List<DeviceLocationHistory> getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from, long to)
|
||||
List<DeviceLocationHistorySnapshot> getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from, long to)
|
||||
throws DeviceManagementDAOException;
|
||||
|
||||
/**
|
||||
|
||||
@ -46,6 +46,7 @@ import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.configuration.mgt.DevicePropertyInfo;
|
||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceData;
|
||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistory;
|
||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
|
||||
import org.wso2.carbon.device.mgt.core.dao.DeviceDAO;
|
||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
|
||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
|
||||
@ -1800,13 +1801,13 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeviceLocationHistory> getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from, long to)
|
||||
public List<DeviceLocationHistorySnapshot> getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from, long to)
|
||||
throws DeviceManagementDAOException {
|
||||
|
||||
Connection conn;
|
||||
PreparedStatement stmt = null;
|
||||
ResultSet rs = null;
|
||||
List<DeviceLocationHistory> deviceLocationHistories = new ArrayList<>();
|
||||
List<DeviceLocationHistorySnapshot> deviceLocationHistories = new ArrayList<>();
|
||||
try {
|
||||
conn = this.getConnection();
|
||||
|
||||
|
||||
@ -17,14 +17,15 @@
|
||||
*/
|
||||
package org.wso2.carbon.device.mgt.core.dao.util;
|
||||
|
||||
import java.util.Date;
|
||||
import org.apache.commons.logging.Log;
|
||||
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.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.common.device.details.DeviceLocationHistorySnapshot;
|
||||
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;
|
||||
@ -248,12 +249,13 @@ public final class DeviceManagementDAOUtil {
|
||||
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"));
|
||||
public static DeviceLocationHistorySnapshot loadDeviceLocation(ResultSet rs) throws SQLException {
|
||||
DeviceLocationHistorySnapshot deviceLocationHistory = new DeviceLocationHistorySnapshot();
|
||||
DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
|
||||
deviceIdentifier.setId(rs.getString("DEVICE_ID_NAME"));
|
||||
deviceIdentifier.setType(rs.getString("DEVICE_TYPE_NAME"));
|
||||
deviceLocationHistory.setDeviceIdentifier(deviceIdentifier);
|
||||
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"));
|
||||
@ -261,7 +263,7 @@ public final class DeviceManagementDAOUtil {
|
||||
deviceLocationHistory.setAltitude(rs.getDouble("DEVICE_ALTITUDE"));
|
||||
deviceLocationHistory.setDistance(rs.getDouble("DISTANCE"));
|
||||
deviceLocationHistory.setOwner(rs.getString("DEVICE_OWNER"));
|
||||
deviceLocationHistory.setTimestamp(rs.getLong("TIMESTAMP"));
|
||||
deviceLocationHistory.setUpdatedTime(new Date(rs.getLong("TIMESTAMP")));
|
||||
deviceLocationHistory.setGeoHash(rs.getString("GEO_HASH"));
|
||||
return deviceLocationHistory;
|
||||
}
|
||||
|
||||
@ -268,6 +268,8 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager {
|
||||
} else {
|
||||
deviceDetailsDAO.updateDeviceLocation(deviceLocation, device.getEnrolmentInfo().getId());
|
||||
}
|
||||
deviceDetailsDAO.addDeviceLocationInfo(device, deviceLocation,
|
||||
CarbonContext.getThreadLocalCarbonContext().getTenantId());
|
||||
if (DeviceManagerUtil.isPublishLocationResponseEnabled()) {
|
||||
Object[] metaData = {device.getDeviceIdentifier(), device.getEnrolmentInfo().getOwner(), device.getType()};
|
||||
Object[] payload = new Object[]{
|
||||
|
||||
@ -46,6 +46,7 @@ import org.wso2.carbon.device.mgt.common.MonitoringOperation;
|
||||
import org.wso2.carbon.device.mgt.common.StartupOperationConfig;
|
||||
import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig;
|
||||
import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceNotFoundException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
|
||||
@ -56,7 +57,6 @@ 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.device.details.DeviceData;
|
||||
import org.wso2.carbon.device.mgt.common.license.mgt.License;
|
||||
import org.wso2.carbon.device.mgt.common.operation.mgt.Activity;
|
||||
@ -765,7 +765,7 @@ public interface DeviceManagementProviderService {
|
||||
* @throws DeviceManagementException
|
||||
* @return list of device's location histories
|
||||
*/
|
||||
List<DeviceLocationHistory> getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from, long to)
|
||||
List<DeviceLocationHistorySnapshot> getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from, long to)
|
||||
throws DeviceManagementException;
|
||||
|
||||
/**
|
||||
|
||||
@ -64,6 +64,7 @@ import org.wso2.carbon.device.mgt.common.DevicePropertyNotification;
|
||||
import org.wso2.carbon.device.mgt.common.DeviceEnrollmentInfoNotification;
|
||||
import org.wso2.carbon.device.mgt.common.DeviceNotification;
|
||||
import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistorySnapshot;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceNotFoundException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
|
||||
@ -81,7 +82,6 @@ import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration
|
||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceData;
|
||||
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;
|
||||
@ -3013,14 +3013,14 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeviceLocationHistory> getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from, long to)
|
||||
public List<DeviceLocationHistorySnapshot> getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from, long to)
|
||||
throws DeviceManagementException {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Get device location information");
|
||||
}
|
||||
|
||||
List<DeviceLocationHistory> deviceLocationHistory;
|
||||
List<DeviceLocationHistorySnapshot> deviceLocationHistory;
|
||||
String errMessage;
|
||||
|
||||
try {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user