From df5cdb524030e7f996f3c50a81366e8c8623d0f6 Mon Sep 17 00:00:00 2001 From: Shamalka Navod Date: Thu, 10 Nov 2022 15:36:55 +0000 Subject: [PATCH] Fix traccar issues (#5) * Fix traccar client thredpool issue * Refactor traccar implementation * Fix traccar loading issue Co-authored-by: shamalka Reviewed-on: https://repository.entgra.net/community/device-mgt-core/pulls/5 Co-authored-by: Shamalka Navod Co-committed-by: Shamalka Navod --- .../impl/DeviceManagementServiceImpl.java | 25 +- .../mgt/jaxrs/util/DeviceMgtAPIUtils.java | 14 + .../core/dao/impl/tracker/TrackerDAOImpl.java | 35 +- .../details/mgt/dao/DeviceDetailsDAO.java | 11 + .../mgt/dao/impl/DeviceDetailsDAOImpl.java | 22 + .../impl/DeviceInformationManagerImpl.java | 45 +- .../DeviceManagementProviderServiceImpl.java | 9 +- .../api/service/DeviceAPIClientService.java | 22 + .../api/service/TraccarClientFactory.java | 802 ++++++++++++++++++ .../api/service/addons/TraccarClientImpl.java | 9 +- .../impl/DeviceAPIClientServiceImpl.java | 95 ++- .../config/operation/traccar-config.xml | 4 +- .../main/resources/conf/traccar-config.xml | 4 +- 13 files changed, 1014 insertions(+), 83 deletions(-) create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/TraccarClientFactory.java 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 ccbf8aafed6..b8c626cb415 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 @@ -102,6 +102,7 @@ import org.wso2.carbon.device.mgt.core.search.mgt.SearchManagerService; import org.wso2.carbon.device.mgt.core.search.mgt.SearchMgtException; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService; +import org.wso2.carbon.device.mgt.core.traccar.api.service.DeviceAPIClientService; import org.wso2.carbon.device.mgt.core.traccar.api.service.impl.DeviceAPIClientServiceImpl; import org.wso2.carbon.device.mgt.core.traccar.common.TraccarHandlerConstants; import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil; @@ -492,7 +493,8 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { if (HttpReportingUtil.isTrackerEnabled()) { String currentUser = CarbonContext.getThreadLocalCarbonContext().getUsername(); - JSONObject obj = new JSONObject(DeviceAPIClientServiceImpl.returnUser(currentUser)); + DeviceAPIClientService deviceAPIClientService = DeviceMgtAPIUtils.getDeviceAPIClientService(); + JSONObject obj = new JSONObject(deviceAPIClientService.returnUser(currentUser)); if (obj.has("error")) { return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(obj.getString("error")).build(); @@ -530,21 +532,23 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { } int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); + TrackerDeviceInfo trackerDevice; for (Device device : devices.getList()) { - TrackerDeviceInfo trackerDevice = DeviceAPIClientServiceImpl - .getTrackerDevice(device.getId(), tenantId); - int traccarDeviceId = trackerDevice.getTraccarDeviceId(); - boolean getPermission = DeviceAPIClientServiceImpl.getUserIdofPermissionByDeviceIdNUserId(traccarDeviceId, userId); - traccarValidIdList.add(traccarDeviceId); - if (!getPermission) { - DeviceAPIClientServiceImpl.addTrackerUserDevicePermission(userId, traccarDeviceId); + trackerDevice = deviceAPIClientService.getTrackerDevice(device.getId(), tenantId); + if(trackerDevice != null) { + int traccarDeviceId = trackerDevice.getTraccarDeviceId(); + boolean getPermission = deviceAPIClientService.getUserIdofPermissionByDeviceIdNUserId(traccarDeviceId, userId); + traccarValidIdList.add(traccarDeviceId); + if (!getPermission) { + deviceAPIClientService.addTrackerUserDevicePermission(userId, traccarDeviceId); + } } } //Remove necessary List getAllUserDevices = - DeviceAPIClientServiceImpl.getUserIdofPermissionByUserIdNIdList(userId, traccarValidIdList); + deviceAPIClientService.getUserIdofPermissionByUserIdNIdList(userId, traccarValidIdList); for (TrackerPermissionInfo getAllUserDevice : getAllUserDevices) { - DeviceAPIClientServiceImpl.removeTrackerUserDevicePermission( + deviceAPIClientService.removeTrackerUserDevicePermission( getAllUserDevice.getTraccarUserId(), getAllUserDevice.getTraccarDeviceId(), TraccarHandlerConstants.Types.REMOVE_TYPE_SINGLE); @@ -570,6 +574,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { log.error(msg, e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); } + /*Get Device Id List*/ return Response.status(Response.Status.OK).entity(obj.getString("token")).build(); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/util/DeviceMgtAPIUtils.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/util/DeviceMgtAPIUtils.java index 8861833f5aa..92bc2790d49 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/util/DeviceMgtAPIUtils.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/util/DeviceMgtAPIUtils.java @@ -87,6 +87,7 @@ import org.wso2.carbon.device.mgt.core.privacy.PrivacyComplianceProvider; import org.wso2.carbon.device.mgt.core.search.mgt.SearchManagerService; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService; +import org.wso2.carbon.device.mgt.core.traccar.api.service.DeviceAPIClientService; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceTypeVersionWrapper; import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; import org.wso2.carbon.device.mgt.jaxrs.beans.OperationStatusBean; @@ -592,6 +593,19 @@ public class DeviceMgtAPIUtils { return analyticsDataAPI; } + public static DeviceAPIClientService getDeviceAPIClientService() { + DeviceAPIClientService deviceAPIClientService; + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + deviceAPIClientService = (DeviceAPIClientService) ctx.getOSGiService( + DeviceAPIClientService.class, null); + if (deviceAPIClientService == null) { + String msg = "Device API Client service not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + return deviceAPIClientService; + } + public static int getTenantId(String tenantDomain) throws DeviceManagementException { RealmService realmService = (RealmService) PrivilegedCarbonContext.getThreadLocalCarbonContext().getOSGiService(RealmService.class, null); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/tracker/TrackerDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/tracker/TrackerDAOImpl.java index 43d21b4d0e9..034ecbff779 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/tracker/TrackerDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/tracker/TrackerDAOImpl.java @@ -18,6 +18,7 @@ package org.wso2.carbon.device.mgt.core.dao.impl.tracker; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.device.mgt.common.TrackerDeviceInfo; @@ -26,6 +27,7 @@ import org.wso2.carbon.device.mgt.common.TrackerPermissionInfo; import org.wso2.carbon.device.mgt.core.dao.TrackerManagementDAOFactory; import org.wso2.carbon.device.mgt.core.dao.TrackerManagementDAOException; import org.wso2.carbon.device.mgt.core.dao.TrackerDAO; +import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil; import org.wso2.carbon.device.mgt.core.dao.util.TrackerManagementDAOUtil; import org.wso2.carbon.device.mgt.core.traccar.common.TraccarHandlerConstants; @@ -104,27 +106,34 @@ public class TrackerDAOImpl implements TrackerDAO { @Override public TrackerDeviceInfo getTrackerDevice(int deviceId, int tenantId) throws TrackerManagementDAOException { - PreparedStatement stmt = null; - ResultSet rs = null; + TrackerDeviceInfo trackerDeviceInfo = null; try { Connection conn = TrackerManagementDAOFactory.getConnection(); - String sql = "SELECT ID, TRACCAR_DEVICE_ID, DEVICE_ID, TENANT_ID, STATUS FROM DM_EXT_DEVICE_MAPPING WHERE " + - "DEVICE_ID = ? AND TENANT_ID = ? ORDER BY ID DESC LIMIT 1"; - stmt = conn.prepareStatement(sql); - stmt.setInt(1, deviceId); - stmt.setInt(2, tenantId); - rs = stmt.executeQuery(); - if (rs.next()) { - return TrackerManagementDAOUtil.loadTrackerDevice(rs); + String sql = "SELECT " + + "DM_EXT_DEVICE_MAPPING.ID, " + + "DM_EXT_DEVICE_MAPPING.TRACCAR_DEVICE_ID, " + + "DM_EXT_DEVICE_MAPPING.DEVICE_ID, " + + "DM_EXT_DEVICE_MAPPING.TENANT_ID, " + + "DM_EXT_DEVICE_MAPPING.STATUS " + + "FROM DM_EXT_DEVICE_MAPPING " + + "JOIN DM_DEVICE ON DM_EXT_DEVICE_MAPPING.DEVICE_ID=DM_DEVICE.ID " + + "WHERE DM_EXT_DEVICE_MAPPING.DEVICE_ID = ? AND DM_EXT_DEVICE_MAPPING.TENANT_ID = ? " + + "ORDER BY DM_EXT_DEVICE_MAPPING.ID DESC LIMIT 1"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setInt(1, deviceId); + stmt.setInt(2, tenantId); + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + trackerDeviceInfo = TrackerManagementDAOUtil.loadTrackerDevice(rs); + } + } } - return null; } catch (SQLException e) { String msg = "Error occurred while retrieving data from the trackerDevice table "; log.error(msg, e); throw new TrackerManagementDAOException(msg, e); - } finally { - TrackerManagementDAOUtil.cleanupResources(stmt, rs); } + return trackerDeviceInfo; } @Override 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 d3a30b0a507..10c7a9f34f8 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 @@ -99,6 +99,17 @@ public interface DeviceDetailsDAO { */ DeviceLocation getDeviceLocation(int deviceId, int enrollmentId) throws DeviceDetailsMgtDAOException; + + /** + * This method will return the device location exist or not + * @param deviceId - id of the device. + * @param enrollmentId - enrolment id of the device. + * @return - if device location exist + * @throws DeviceDetailsMgtDAOException if SQL error occurred while processing the query. + */ + boolean hasLocations(int deviceId, int enrollmentId) throws DeviceDetailsMgtDAOException; + + /** * This method will delete the device location from the database. * @param deviceId 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 ff17b026f4f..535a1cbb081 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 @@ -25,6 +25,7 @@ import org.apache.commons.logging.LogFactory; import org.wso2.carbon.device.mgt.common.Device; 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 org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory; import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil; import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.DeviceDetailsDAO; @@ -378,6 +379,27 @@ public class DeviceDetailsDAOImpl implements DeviceDetailsDAO { } } + @Override + public boolean hasLocations(int deviceId, int enrollmentId) throws + DeviceDetailsMgtDAOException { + try { + Connection conn = this.getConnection(); + String sql = "SELECT DEVICE_ID FROM DM_DEVICE_LOCATION WHERE DEVICE_ID = ? AND ENROLMENT_ID = ? " + + "LIMIT 1"; + ResultSet rs; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setInt(1, deviceId); + stmt.setInt(2, enrollmentId); + rs = stmt.executeQuery(); + return rs.next(); + } + } catch (SQLException e) { + String msg = "Error occurred while fetching the location of the registered devices."; + log.error(msg, e); + throw new DeviceDetailsMgtDAOException(msg, e); + } + } + @Override public void deleteDeviceLocation(int deviceId, int enrollmentId) throws DeviceDetailsMgtDAOException { 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 e9e5b0aaf5c..585074894df 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 @@ -403,10 +403,14 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager { } } else { if(!HttpReportingUtil.isLocationPublishing()) { - log.info("Location publishing is disabled"); + if (log.isDebugEnabled()) { + log.debug("Location publishing is disabled"); + } } if (!HttpReportingUtil.isTrackerEnabled()) { - log.info("Traccar is disabled"); + if (log.isDebugEnabled()) { + log.info("Traccar is disabled"); + } } } //Tracker update GPS Location @@ -435,17 +439,46 @@ public class DeviceInformationManagerImpl implements DeviceInformationManager { DeviceLocation mostRecentDeviceLocation = deviceLocations.get(deviceLocations.size() - 1); mostRecentDeviceLocation.setDeviceId(device.getId()); DeviceManagementDAOFactory.beginTransaction(); - DeviceLocation previousLocation = deviceDetailsDAO.getDeviceLocation(device.getId(), + boolean previousLocation = deviceDetailsDAO.hasLocations(device.getId(), device.getEnrolmentInfo().getId()); - if (previousLocation == null) { - deviceDetailsDAO.addDeviceLocation(mostRecentDeviceLocation, device.getEnrolmentInfo().getId()); - } else { + if (previousLocation) { deviceDetailsDAO.updateDeviceLocation(mostRecentDeviceLocation, device.getEnrolmentInfo().getId()); + } else { + deviceDetailsDAO.addDeviceLocation(mostRecentDeviceLocation, device.getEnrolmentInfo().getId()); } deviceDetailsDAO.addDeviceLocationsInfo(device, deviceLocations, CarbonContext.getThreadLocalCarbonContext().getTenantId()); + for (DeviceLocation deviceLocation: deviceLocations) { + //Tracker update GPS Location + if (HttpReportingUtil.isLocationPublishing() && HttpReportingUtil.isTrackerEnabled()) { + try { + DeviceManagementDataHolder.getInstance().getDeviceAPIClientService() + .updateLocation(device, deviceLocation, CarbonContext.getThreadLocalCarbonContext().getTenantId()); + } catch (ExecutionException e) { + log.error("ExecutionException : " + e); + //throw new RuntimeException(e); + // NOTE: Exception was not thrown due to being conflicted with non-traccar features + } catch (InterruptedException e) { + log.error("InterruptedException : " + e); + //throw new RuntimeException(e); + // NOTE: Exception was not thrown due to being conflicted with non-traccar features + } + } else { + if(!HttpReportingUtil.isLocationPublishing()) { + if (log.isDebugEnabled()) { + log.debug("Location publishing is disabled"); + } + } + if (!HttpReportingUtil.isTrackerEnabled()) { + if (log.isDebugEnabled()) { + log.info("Traccar is disabled"); + } + } + } + } + DeviceManagementDAOFactory.commitTransaction(); } catch (TransactionManagementException e) { throw new DeviceDetailsMgtException("Transactional error occurred while adding the device location " + 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 c777ea87995..2f0439f8ca7 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 @@ -3981,9 +3981,12 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv deviceLocation.setBearing(Float.parseFloat(bearing)); deviceInformationManager.addDeviceLocation(device, deviceLocation); } catch (DeviceDetailsMgtException e) { - //We are not failing the execution since this is not critical for the functionality. But logging as - // a warning for reference. - //Exception was not thrown due to being conflicted with non-traccar features + /*** + * NOTE: + * We are not failing the execution since this is not critical for the functionality. But logging as + * a warning for reference. + * Exception was not thrown due to being conflicted with non-traccar features + */ log.warn("Error occurred while trying to add '" + device.getType() + "' device '" + device.getDeviceIdentifier() + "' (id:'" + device.getId() + "') location (lat:" + latitude + ", lon:" + longitude + ", altitude: " + altitude + diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/DeviceAPIClientService.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/DeviceAPIClientService.java index 605d4f7a46b..73aca76059b 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/DeviceAPIClientService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/DeviceAPIClientService.java @@ -20,10 +20,14 @@ package org.wso2.carbon.device.mgt.core.traccar.api.service; import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.TrackerDeviceInfo; +import org.wso2.carbon.device.mgt.common.TrackerPermissionInfo; import org.wso2.carbon.device.mgt.common.device.details.DeviceLocation; import org.wso2.carbon.device.mgt.common.exceptions.TrackerAlreadyExistException; import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup; import org.wso2.carbon.device.mgt.core.dao.TrackerManagementDAOException; + +import java.util.List; import java.util.concurrent.ExecutionException; public interface DeviceAPIClientService { @@ -81,4 +85,22 @@ public interface DeviceAPIClientService { */ void deleteGroup(int groupId, int tenantId) throws TrackerManagementDAOException, ExecutionException, InterruptedException; + + String returnUser(String username); + + TrackerDeviceInfo getTrackerDevice(int deviceId, int tenantId) throws + TrackerManagementDAOException; + + boolean getUserIdofPermissionByDeviceIdNUserId(int deviceId, int userId) throws + TrackerManagementDAOException; + + void addTrackerUserDevicePermission(int userId, int deviceId) throws + TrackerManagementDAOException, ExecutionException, InterruptedException; + + List getUserIdofPermissionByUserIdNIdList(int userId, List NotInDeviceIdList) throws + TrackerManagementDAOException; + + void removeTrackerUserDevicePermission(int userId, int deviceId, int removeType) throws + TrackerManagementDAOException, ExecutionException, InterruptedException; + } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/TraccarClientFactory.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/TraccarClientFactory.java new file mode 100644 index 00000000000..193bdb211c1 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/TraccarClientFactory.java @@ -0,0 +1,802 @@ +/* + * Copyright (c) 2022, 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.core.traccar.api.service; + +import okhttp3.ConnectionPool; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONArray; +import org.json.JSONObject; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.TrackerDeviceInfo; +import org.wso2.carbon.device.mgt.common.TrackerGroupInfo; +import org.wso2.carbon.device.mgt.common.TrackerPermissionInfo; +import org.wso2.carbon.device.mgt.common.exceptions.TransactionManagementException; +import org.wso2.carbon.device.mgt.common.exceptions.TrackerAlreadyExistException; +import org.wso2.carbon.device.mgt.core.dao.TrackerManagementDAOException; +import org.wso2.carbon.device.mgt.core.dao.TrackerDAO; +import org.wso2.carbon.device.mgt.core.dao.TrackerManagementDAOFactory; +import org.wso2.carbon.device.mgt.core.traccar.api.service.TraccarClient; +import org.wso2.carbon.device.mgt.core.traccar.api.service.impl.DeviceAPIClientServiceImpl; +import org.wso2.carbon.device.mgt.core.traccar.common.TraccarHandlerConstants; +import org.wso2.carbon.device.mgt.core.traccar.common.beans.TraccarDevice; +import org.wso2.carbon.device.mgt.core.traccar.common.beans.TraccarGroups; +import org.wso2.carbon.device.mgt.core.traccar.common.beans.TraccarPosition; +import org.wso2.carbon.device.mgt.core.traccar.common.beans.TraccarUser; +import org.wso2.carbon.device.mgt.core.traccar.common.config.TraccarGateway; +import org.wso2.carbon.device.mgt.core.traccar.common.util.TraccarUtil; +import org.wso2.carbon.device.mgt.core.traccar.core.config.TraccarConfigurationManager; +import org.wso2.carbon.device.mgt.core.util.HttpReportingUtil; + +import java.io.IOException; +import java.sql.SQLException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.Random; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class TraccarClientFactory { + + private static TraccarClientFactory INSTANCE; + private static final Log log = LogFactory.getLog(TraccarClientFactory.class); + private static final int THREAD_POOL_SIZE = 50; + private final OkHttpClient client; + private final ExecutorService executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE); + final TraccarGateway traccarGateway = getTraccarGateway(); + final String endpoint = traccarGateway.getPropertyByName(TraccarHandlerConstants.TraccarConfig.ENDPOINT).getValue(); + final String authorization = traccarGateway.getPropertyByName(TraccarHandlerConstants.TraccarConfig.AUTHORIZATION).getValue(); + final String authorizationKey = traccarGateway.getPropertyByName(TraccarHandlerConstants.TraccarConfig.AUTHORIZATION_KEY).getValue(); + final String defaultPort = traccarGateway.getPropertyByName(TraccarHandlerConstants.TraccarConfig.DEFAULT_PORT).getValue(); + final String locationUpdatePort = traccarGateway.getPropertyByName(TraccarHandlerConstants.TraccarConfig.LOCATION_UPDATE_PORT).getValue(); + + final String username = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); + private final TrackerDAO trackerDAO; + + /** + * This is the private constructor method as this class is a singleton + */ + private TraccarClientFactory() { + client = new OkHttpClient.Builder() + .connectTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .readTimeout(45, TimeUnit.SECONDS) + .connectionPool(new ConnectionPool(100, 50, TimeUnit.SECONDS)) + .build(); + this.trackerDAO = TrackerManagementDAOFactory.getTrackerDAO(); + } + + /** + * This method is used to initiate a singleton instance of this class. + * + * @return TraccarClientFactory instance + */ + public static TraccarClientFactory getInstance() { + if(INSTANCE == null) { + INSTANCE = new TraccarClientFactory(); + } + return INSTANCE; + } + + private class OkHttpClientThreadPool implements Callable { + final String publisherUrlWithContext; + final JSONObject payload; + private final String method; + private String authorizeKey; + private String serverUri; + + private OkHttpClientThreadPool(String publisherUrlWithContext, JSONObject payload, String method, + String authorizeKey, String serverUri) { + this.publisherUrlWithContext = publisherUrlWithContext; + this.payload = payload; + this.method = method; + this.authorizeKey = authorizeKey; + this.serverUri = serverUri; + } + + @Override + public String call() throws IOException { + RequestBody requestBody; + Request.Builder builder = new Request.Builder(); + Request request; + Response response; + + if (Objects.equals(method, TraccarHandlerConstants.Methods.POST)) { + requestBody = RequestBody.create(payload.toString(), MediaType.parse("application/json; charset=utf-8")); + builder = builder.post(requestBody); + } else if (Objects.equals(method, TraccarHandlerConstants.Methods.PUT)) { + requestBody = RequestBody.create(payload.toString(), MediaType.parse("application/json; charset=utf-8")); + builder = builder.put(requestBody); + } else if (Objects.equals(method, TraccarHandlerConstants.Methods.DELETE)) { + if (publisherUrlWithContext.contains("permission")) { + requestBody = RequestBody.create(payload.toString(), MediaType.parse("application/json; charset=utf-8")); + builder = builder.delete(requestBody); + } else { + builder = builder.delete(); + } + } + + request = builder.url(serverUri + publisherUrlWithContext).addHeader(authorization, authorizeKey).build(); + response = client.newCall(request).execute(); + return response.body().string(); + } + } + + public String fetchAllUsers() throws ExecutionException, InterruptedException { + String url = defaultPort + "/api/users"; + + Future result = executor.submit(new OkHttpClientThreadPool(url, null, TraccarHandlerConstants.Methods.GET, + authorizedKey(HttpReportingUtil.trackerUser(), HttpReportingUtil.trackerPassword()), + serverUrl(HttpReportingUtil.trackerServer()))); + return result.get(); + } + + public String fetchUserInfo(String userName) throws ExecutionException, InterruptedException { + String allUsers = fetchAllUsers(); //get all users + JSONArray fetchAllUsers = new JSONArray(allUsers); //loop users + for (int i = 0; i < fetchAllUsers.length(); i++) { + // if login is null then check the name or if login is not null then check the login + if (fetchAllUsers.getJSONObject(i).isNull("login")) { + if (Objects.equals(fetchAllUsers.getJSONObject(i).getString("name"), userName)) { + return fetchAllUsers.getJSONObject(i).toString(); + } + } else { + if (Objects.equals(fetchAllUsers.getJSONObject(i).getString("login"), userName) || + Objects.equals(fetchAllUsers.getJSONObject(i).getString("name"), userName)) { + return fetchAllUsers.getJSONObject(i).toString(); + } + } + } + return TraccarHandlerConstants.Types.USER_NOT_FOUND; + } + + public String returnUser(String userName) throws TrackerManagementDAOException { + try { + String result = fetchUserInfo(userName); + Date today = new Date(); + LocalDateTime tomorrow = LocalDateTime.from(today.toInstant().atZone(ZoneId.of("UTC"))).plusDays(1); + String token = DeviceAPIClientServiceImpl.generateRandomString(TraccarHandlerConstants.Types.TRACCAR_TOKEN); + + TraccarUser traccarUser = new TraccarUser(); + traccarUser.setToken(token); + + if (Objects.equals(result, TraccarHandlerConstants.Types.USER_NOT_FOUND)) { + //create user + log.info("Creating a user on Traccar client"); + traccarUser.setName(userName); + traccarUser.setLogin(userName); + traccarUser.setEmail(userName); + traccarUser.setPassword(DeviceAPIClientServiceImpl.generateRandomString(TraccarHandlerConstants.Types.DEFAULT_RANDOM)); + traccarUser.setDeviceLimit(-1); + traccarUser.setExpirationTime(tomorrow.toString()); + DeviceAPIClientServiceImpl.createUser(traccarUser); + } else { + //update user + log.info("Updating the user on Traccar client"); + JSONObject obj = new JSONObject(result); + + traccarUser.setId(obj.getInt("id")); + traccarUser.setName(obj.getString("name")); + if (!obj.isNull("login")) { + traccarUser.setLogin(obj.getString("login")); + } + traccarUser.setEmail(obj.getString("email")); + traccarUser.setDeviceLimit(obj.getInt("deviceLimit")); + traccarUser.setUserLimit(obj.getInt("userLimit")); + traccarUser.setAdministrator(obj.getBoolean("administrator")); + traccarUser.setDisabled(obj.getBoolean("disabled")); + traccarUser.setReadonly(obj.getBoolean("readonly")); + if (!obj.getBoolean("administrator")) { + traccarUser.setExpirationTime(tomorrow.toString()); + } else if (!obj.isNull("expirationTime")) { + traccarUser.setExpirationTime(obj.getString("expirationTime")); + } + DeviceAPIClientServiceImpl.updateUser(traccarUser, obj.getInt("id")); + } + result = fetchUserInfo(userName); + return result; + } catch (InterruptedException | ExecutionException e) { + JSONObject obj = new JSONObject(); + String msg = "Error occurred while executing enrollment status of the device."; + obj.put("error", msg); + obj.put("e", e); + log.error(msg, e); + return obj.toString(); + } + } + + public String createUser(TraccarUser traccarUser) throws ExecutionException, InterruptedException { + String url = defaultPort + "/api/users"; + JSONObject payload = TraccarUtil.TraccarUserPayload(traccarUser); + + Future res = executor.submit(new OkHttpClientThreadPool(url, payload, TraccarHandlerConstants.Methods.POST, + authorizedKey(HttpReportingUtil.trackerUser(), HttpReportingUtil.trackerPassword()), + serverUrl(HttpReportingUtil.trackerServer()))); + return res.get(); + } + + public String updateUser(TraccarUser traccarUser, int userId) throws ExecutionException, InterruptedException { + String url = defaultPort + "/api/users/" + userId; + JSONObject payload = TraccarUtil.TraccarUserPayload(traccarUser); + + Future res = executor.submit(new OkHttpClientThreadPool(url, payload, TraccarHandlerConstants.Methods.PUT, + authorizedKey(HttpReportingUtil.trackerUser(), HttpReportingUtil.trackerPassword()), + serverUrl(HttpReportingUtil.trackerServer()))); + return res.get(); + } + + public void setPermission(int userId, int deviceId) + throws ExecutionException, InterruptedException, TrackerManagementDAOException { + JSONObject payload = new JSONObject(); + payload.put("userId", userId); + payload.put("deviceId", deviceId); + + String url = defaultPort + "/api/permissions"; + + Future res = executor.submit(new OkHttpClientThreadPool(url, payload, TraccarHandlerConstants.Methods.POST, + authorizedKey(HttpReportingUtil.trackerUser(), HttpReportingUtil.trackerPassword()), + serverUrl(HttpReportingUtil.trackerServer()))); + String result = res.get(); + + if (("").equals(result)) { + try { + TrackerManagementDAOFactory.beginTransaction(); + trackerDAO.addTrackerUserDevicePermission(userId, deviceId); + TrackerManagementDAOFactory.commitTransaction(); + } catch (TrackerManagementDAOException e) { + TrackerManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred while mapping with deviceId ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } catch (TransactionManagementException e) { + TrackerManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred establishing the DB connection ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } finally { + TrackerManagementDAOFactory.closeConnection(); + } + } else { + String msg = "Couldn't add the permission record: " + result; + log.error(msg); + throw new TrackerManagementDAOException(msg); + } + } + + public void removePermission(int userId, int deviceId, int removeType) + throws TrackerManagementDAOException, ExecutionException, InterruptedException { + JSONObject payload = new JSONObject(); + payload.put("userId", userId); + payload.put("deviceId", deviceId); + + String url = defaultPort + "/api/permissions"; + + Future res = executor.submit(new OkHttpClientThreadPool(url, payload, TraccarHandlerConstants.Methods.DELETE, + authorizedKey(HttpReportingUtil.trackerUser(), HttpReportingUtil.trackerPassword()), + serverUrl(HttpReportingUtil.trackerServer()))); + + if (res.get() != null) { + try { + TrackerManagementDAOFactory.beginTransaction(); + trackerDAO.removeTrackerUserDevicePermission(deviceId, userId, removeType); + TrackerManagementDAOFactory.commitTransaction(); + } catch (TrackerManagementDAOException e) { + TrackerManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred while mapping with deviceId ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } catch (TransactionManagementException e) { + TrackerManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred establishing the DB connection ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } finally { + TrackerManagementDAOFactory.closeConnection(); + } + } else { + String msg = "Error occured while removing permission."; + log.error(msg); + throw new TrackerManagementDAOException(msg); + } + } + + public List getUserIdofPermissionByUserIdNIdList(int userId, List NotInDeviceIdList) + throws TrackerManagementDAOException { + try { + TrackerManagementDAOFactory.openConnection(); + return trackerDAO.getUserIdofPermissionByUserIdNIdList(userId, NotInDeviceIdList); + } catch (TrackerManagementDAOException e) { + String msg = "Error occurred while mapping with deviceId ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } catch (SQLException e) { + String msg = "Error occurred establishing the DB connection ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } finally { + TrackerManagementDAOFactory.closeConnection(); + } + } + + public TrackerDeviceInfo getTrackerDevice(int deviceId, int tenantId) throws TrackerManagementDAOException { + try { + TrackerManagementDAOFactory.openConnection(); + TrackerDeviceInfo trackerDeviceInfo = trackerDAO.getTrackerDevice(deviceId, tenantId); + if(trackerDeviceInfo == null) { + String msg = "No tracker device is found upon the device ID of: " + deviceId; + if (log.isDebugEnabled()) { + log.debug(msg); + } + return null; + } else { + return trackerDeviceInfo; + } + } catch (SQLException e) { + String msg = "Error occurred establishing the DB connection ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } catch (TrackerManagementDAOException e) { + String msg = "Could not add new device location"; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } finally { + TrackerManagementDAOFactory.closeConnection(); + } + } + + public boolean getUserIdofPermissionByDeviceIdNUserId(int deviceId, int userId) + throws TrackerManagementDAOException { + Boolean result = false; + try { + TrackerManagementDAOFactory.openConnection(); + result = trackerDAO.getUserIdofPermissionByDeviceIdNUserId(deviceId, userId); + } catch (TrackerManagementDAOException e) { + String msg = "Error occurred while mapping with deviceId ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } catch (SQLException e) { + String msg = "Error occurred establishing the DB connection ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } finally { + TrackerManagementDAOFactory.closeConnection(); + } + return result; + } + + /** + * Add Traccar Device operation. + * + * @param traccarDevice with DeviceName UniqueId, Status, Disabled LastUpdate, PositionId, GroupId + * Model, Contact, Category, fenceIds + * @throws TrackerManagementDAOException Failed while add Traccar Device the operation + */ + public void addDevice(TraccarDevice traccarDevice, int tenantId) throws + TrackerManagementDAOException, TrackerAlreadyExistException, ExecutionException, InterruptedException { + TrackerDeviceInfo trackerDeviceInfo = null; + try { + TrackerManagementDAOFactory.openConnection(); + trackerDeviceInfo = trackerDAO.getTrackerDevice(traccarDevice.getId(), tenantId); + } catch (TrackerManagementDAOException e) { + String msg = "Error occurred while mapping with deviceId ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } catch (SQLException e) { + String msg = "Error occurred establishing the DB connection ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } finally { + TrackerManagementDAOFactory.closeConnection(); + } + + if (trackerDeviceInfo == null) { + //add the device + String url = defaultPort + "/api/devices"; + JSONObject payload = TraccarUtil.TraccarDevicePayload(traccarDevice); + + Future res = executor.submit(new OkHttpClientThreadPool(url, payload, TraccarHandlerConstants.Methods.POST, + authorizedKey(HttpReportingUtil.trackerUser(), HttpReportingUtil.trackerPassword()), + serverUrl(HttpReportingUtil.trackerServer()))); + String result = res.get(); + log.info("Device " + traccarDevice.getDeviceIdentifier() + " has been added to Traccar."); + if (res.isDone() && result.charAt(0) == '{') { + JSONObject obj = new JSONObject(result); + if (obj.has("id")) { + int traccarDeviceId = obj.getInt("id"); + int deviceId = traccarDevice.getId(); + log.info("TraccarDeviceId - " + traccarDeviceId); + try { + TrackerManagementDAOFactory.beginTransaction(); + trackerDAO.addTrackerDevice(traccarDeviceId, deviceId, tenantId); + trackerDeviceInfo = trackerDAO.getTrackerDevice(deviceId, tenantId); + if (trackerDeviceInfo != null && trackerDeviceInfo.getStatus() == 0) { + trackerDAO.updateTrackerDeviceIdANDStatus(trackerDeviceInfo.getTraccarDeviceId(), deviceId, tenantId, 1); + } + TrackerManagementDAOFactory.commitTransaction(); + } catch (TrackerManagementDAOException e) { + TrackerManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred while mapping with deviceId ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } catch (TransactionManagementException e) { + TrackerManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred establishing the DB connection ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } finally { + TrackerManagementDAOFactory.closeConnection(); + } + + JSONObject returnUserInfo = new JSONObject(returnUser(username)); + setPermission(returnUserInfo.getInt("id"), traccarDeviceId); + } + } + } else { + String msg = "The device already exist"; + log.error(msg); + throw new TrackerAlreadyExistException(msg); + } + } + + /** + * Add Device GPS Location operation. + * + * @param deviceInfo with DeviceIdentifier, Timestamp, Lat, Lon, Bearing, Speed, ignition + */ + public void updateLocation(TraccarDevice device, TraccarPosition deviceInfo, int tenantId) throws + TrackerManagementDAOException, TrackerAlreadyExistException, ExecutionException, InterruptedException { + TrackerDeviceInfo trackerDeviceInfo = null; + try { + TrackerManagementDAOFactory.openConnection(); + trackerDeviceInfo = trackerDAO.getTrackerDevice(device.getId(), tenantId); + } catch (SQLException e) { + String msg = "Error occurred establishing the DB connection ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } catch (TrackerManagementDAOException e) { + String msg = "Could not add new device location"; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } finally { + TrackerManagementDAOFactory.closeConnection(); + } + + + //check if the device is already exist before updating the location + if (trackerDeviceInfo == null) { + //add device if not exist + addDevice(device, tenantId); + } else { + //Update Location + if (log.isDebugEnabled()) { + log.info("Updating Location of the device: " + device.getId()); + } + String url = locationUpdatePort + "/?id=" + deviceInfo.getDeviceIdentifier() + + "×tamp=" + deviceInfo.getTimestamp() + "&lat=" + deviceInfo.getLat() + + "&lon=" + deviceInfo.getLon() + "&bearing=" + deviceInfo.getBearing() + + "&speed=" + deviceInfo.getSpeed() + "&ignition=true"; + + executor.submit(new OkHttpClientThreadPool(url, null, TraccarHandlerConstants.Methods.GET, + authorizedKey(HttpReportingUtil.trackerUser(), HttpReportingUtil.trackerPassword()), + Objects.requireNonNull(HttpReportingUtil.trackerServer()).split(":")[0] + ":" + + Objects.requireNonNull(HttpReportingUtil.trackerServer()).split(":")[1] + ":")); + } + } + + /** + * Dis-enroll a Device operation. + * + * @param deviceId identified via deviceIdentifier + * @throws TrackerManagementDAOException Failed while dis-enroll a Traccar Device operation + */ + public void disEnrollDevice(int deviceId, int tenantId) throws TrackerManagementDAOException, ExecutionException, InterruptedException { + TrackerDeviceInfo trackerDeviceInfo = null; + List trackerPermissionInfo = null; + try { + TrackerManagementDAOFactory.beginTransaction(); + try { + TrackerManagementDAOFactory.openConnection(); + trackerDeviceInfo = trackerDAO.getTrackerDevice(deviceId, tenantId); + if (trackerDeviceInfo != null) { + trackerDAO.removeTrackerDevice(deviceId, tenantId); + TrackerManagementDAOFactory.commitTransaction(); + trackerPermissionInfo = trackerDAO.getUserIdofPermissionByDeviceId(trackerDeviceInfo.getTraccarDeviceId()); + } else { + String msg = "Tracker device for device id " + deviceId + " not found"; + log.error(msg); + throw new TrackerManagementDAOException(msg); + } + } catch (SQLException e) { + String msg = "Error occurred establishing the DB connection ."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } catch (TrackerManagementDAOException e) { + String msg = "Could not add new device location"; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } finally { + TrackerManagementDAOFactory.closeConnection(); + } + } catch (TransactionManagementException e) { + TrackerManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred establishing the DB connection"; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } + log.info("Disenrolling Device with device id " + deviceId + " from traccar client"); + //Delete from traccar + if (trackerDeviceInfo != null) { + + if (trackerPermissionInfo.size() > 0) { + String url = defaultPort + "/api/devices/" + trackerPermissionInfo.get(0).getTraccarDeviceId(); + + executor.submit(new OkHttpClientThreadPool(url, null, TraccarHandlerConstants.Methods.DELETE, + authorizedKey(HttpReportingUtil.trackerUser(), HttpReportingUtil.trackerPassword()), + serverUrl(HttpReportingUtil.trackerServer()))); + } else { + String msg = "Tracker permission mapping info not found"; + log.error(msg); + throw new TrackerManagementDAOException(msg); + } + //remove permissions + try { + removePermission( + trackerPermissionInfo.get(0).getTraccarUserId(), + trackerPermissionInfo.get(0).getTraccarDeviceId(), + TraccarHandlerConstants.Types.REMOVE_TYPE_MULTIPLE); + } catch (ExecutionException e) { + String msg = "Error occured while removing tacker permissions "; + log.error(msg); + throw new ExecutionException(msg, e); + } + } else { + String msg = "Tracker device not found"; + log.error(msg); + throw new TrackerManagementDAOException(msg); + } + } + + /** + * Add Traccar Device operation. + * + * @param groupInfo with groupName + * @throws TrackerManagementDAOException Failed while add Traccar Device the operation + */ + public void addGroup(TraccarGroups groupInfo, int groupId, int tenantId) throws + TrackerManagementDAOException, TrackerAlreadyExistException, ExecutionException, InterruptedException { + TrackerGroupInfo trackerGroupInfo = null; + try { + TrackerManagementDAOFactory.openConnection(); + trackerGroupInfo = trackerDAO.getTrackerGroup(groupId, tenantId); + if (trackerGroupInfo != null) { + String msg = "The group already exit"; + log.error(msg); + throw new TrackerAlreadyExistException(msg); + } + } catch (TrackerManagementDAOException e) { + String msg = "Error occurred while mapping with groupId."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } catch (SQLException e) { + String msg = "Error occurred establishing the DB connection."; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } finally { + TrackerManagementDAOFactory.closeConnection(); + } + + JSONObject payload = new JSONObject(); + payload.put("name", groupInfo.getName()); + payload.put("attributes", new JSONObject()); + + String url = defaultPort + "/api/groups"; + + Future res = executor.submit(new OkHttpClientThreadPool(url, payload, TraccarHandlerConstants.Methods.POST, + authorizedKey(HttpReportingUtil.trackerUser(), HttpReportingUtil.trackerPassword()), + serverUrl(HttpReportingUtil.trackerServer()))); + String result = res.get(); + log.info("Group " + trackerGroupInfo.getGroupId() + " has been added to Traccar."); + if (res.isDone() && result.charAt(0) == '{') { + JSONObject obj = new JSONObject(result); + if (obj.has("id")) { + int traccarGroupId = obj.getInt("id"); + try { + TrackerManagementDAOFactory.beginTransaction(); + trackerDAO.addTrackerGroup(traccarGroupId, groupId, tenantId); + trackerGroupInfo = trackerDAO.getTrackerGroup(groupId, tenantId); + if (trackerGroupInfo.getStatus() == 0) { + trackerDAO.updateTrackerGroupIdANDStatus(trackerGroupInfo.getTraccarGroupId(), groupId, tenantId, 1); + TrackerManagementDAOFactory.commitTransaction(); + } + } catch (TransactionManagementException e) { + String msg = "Error occurred establishing the DB connection. "; + log.error(msg, e); + TrackerManagementDAOFactory.rollbackTransaction(); + throw new TrackerManagementDAOException(msg, e); + } catch (TrackerManagementDAOException e) { + TrackerManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred while mapping with deviceId. "; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } finally { + TrackerManagementDAOFactory.closeConnection(); + } + } else { + // TODO: Assumed the error message change if wrong + log.error("Response does not contains the key id: " + result); + } + } else { + // TODO: Assumed the error message change if wrong + log.error("Response does not contains a JSON object " + result); + } + } + + /** + * update Traccar Group operation. + * + * @param groupInfo with groupName + * @throws TrackerManagementDAOException Failed while add Traccar Device the operation + */ + public void updateGroup(TraccarGroups groupInfo, int groupId, int tenantId) throws + TrackerManagementDAOException, TrackerAlreadyExistException, ExecutionException, InterruptedException { + TrackerGroupInfo res = null; + try { + TrackerManagementDAOFactory.openConnection(); + res = trackerDAO.getTrackerGroup(groupId, tenantId); + } catch (SQLException e) { + String msg = "Error occurred establishing the DB connection. "; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } catch (TrackerManagementDAOException e) { + String msg = "Could not find traccar group details. "; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } finally { + TrackerManagementDAOFactory.closeConnection(); + } + + if ((res == null) || (res.getTraccarGroupId() == 0)) { + //add a new traccar group + addGroup(groupInfo, groupId, tenantId); + } else if (res != null && (res.getTraccarGroupId() != 0 && res.getStatus() == 0)) { + //update the traccargroupId and status + try { + TrackerManagementDAOFactory.beginTransaction(); + trackerDAO.updateTrackerGroupIdANDStatus(res.getTraccarGroupId(), groupId, tenantId, 1); + TrackerManagementDAOFactory.commitTransaction(); + } catch (TrackerManagementDAOException e) { + TrackerManagementDAOFactory.rollbackTransaction(); + String msg = "Could not update the traccar group. "; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } catch (TransactionManagementException e) { + TrackerManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred establishing the DB connection. "; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } finally { + TrackerManagementDAOFactory.closeConnection(); + } + } else { + JSONObject obj = new JSONObject(res); + JSONObject payload = new JSONObject(); + payload.put("id", obj.getInt("traccarGroupId")); + payload.put("name", groupInfo.getName()); + payload.put("attributes", new JSONObject()); + + String url = defaultPort + "/api/groups/" + obj.getInt("traccarGroupId"); + + executor.submit(new OkHttpClientThreadPool(url, payload, TraccarHandlerConstants.Methods.PUT, + authorizedKey(HttpReportingUtil.trackerUser(), HttpReportingUtil.trackerPassword()), + serverUrl(HttpReportingUtil.trackerServer()))); + } + } + + /** + * Add Traccar Device operation. + * + * @param groupId + * @throws TrackerManagementDAOException Failed while add Traccar Device the operation + */ + public void deleteGroup(int groupId, int tenantId) throws TrackerManagementDAOException, ExecutionException, InterruptedException { + TrackerGroupInfo res = null; + JSONObject obj = null; + try { + TrackerManagementDAOFactory.beginTransaction(); + res = trackerDAO.getTrackerGroup(groupId, tenantId); + if (res != null) { + obj = new JSONObject(res); + if (obj != null) { + trackerDAO.removeTrackerGroup(obj.getInt("id")); + String url = defaultPort + "/api/groups/" + obj.getInt("traccarGroupId"); + executor.submit(new OkHttpClientThreadPool(url, null, TraccarHandlerConstants.Methods.DELETE, + authorizedKey(HttpReportingUtil.trackerUser(), HttpReportingUtil.trackerPassword()), + serverUrl(HttpReportingUtil.trackerServer()))); + TrackerManagementDAOFactory.commitTransaction(); + } else { + String msg = "Tracker group JSON object is null"; + log.error(msg); + throw new TrackerManagementDAOException(msg); + } + } else { + String msg = "Tracker group not found"; + log.error(msg); + throw new TrackerManagementDAOException(msg); + } + } catch (TransactionManagementException e) { + TrackerManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred establishing the DB connection. "; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } catch (TrackerManagementDAOException e) { + TrackerManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred while mapping with groupId. "; + log.error(msg, e); + throw new TrackerManagementDAOException(msg, e); + } finally { + TrackerManagementDAOFactory.closeConnection(); + } + } + + public String generateRandomString(int len) { + String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + Random rnd = new Random(); + return IntStream.range(0, len).mapToObj(i -> String.valueOf(chars.charAt(rnd.nextInt(chars.length())))).collect(Collectors.joining()); + } + + private TraccarGateway getTraccarGateway() { + return TraccarConfigurationManager.getInstance().getTraccarConfig().getTraccarGateway( + TraccarHandlerConstants.TraccarConfig.GATEWAY_NAME); + } + + public String authorizedKey(String trackerUser, String trackerPassword) { + String newAuthorizationKey = authorizationKey; + if (trackerUser != null && trackerPassword != null) { + newAuthorizationKey = trackerUser + ':' + trackerPassword; + + byte[] result = newAuthorizationKey.getBytes(); + byte[] res = Base64.encodeBase64(result); + newAuthorizationKey = "Basic " + new String(res); + } + return newAuthorizationKey; + } + + public String serverUrl(String serverUrl) { + if (serverUrl != null) { + return serverUrl; + } else { + return endpoint; + } + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/addons/TraccarClientImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/addons/TraccarClientImpl.java index 526de67f616..0e9264a325c 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/addons/TraccarClientImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/addons/TraccarClientImpl.java @@ -403,6 +403,7 @@ public class TraccarClientImpl implements TraccarClient { authorizedKey(HttpReportingUtil.trackerUser(), HttpReportingUtil.trackerPassword()), serverUrl(HttpReportingUtil.trackerServer()))); String result = res.get(); + log.info("Device " + traccarDevice.getDeviceIdentifier() + " has been added to Traccar."); if (result.charAt(0) == '{') { JSONObject obj = new JSONObject(result); if (obj.has("id")) { @@ -465,6 +466,7 @@ public class TraccarClientImpl implements TraccarClient { TrackerManagementDAOFactory.closeConnection(); } + //check if the device is already exist before updating the location if (trackerDeviceInfo == null) { //add device if not exist @@ -481,7 +483,8 @@ public class TraccarClientImpl implements TraccarClient { executor.submit(new OkHttpClientThreadPool(url, null, TraccarHandlerConstants.Methods.GET, authorizedKey(HttpReportingUtil.trackerUser(), HttpReportingUtil.trackerPassword()), - "http://localhost:")); + Objects.requireNonNull(HttpReportingUtil.trackerServer()).split(":")[0] + ":" + + Objects.requireNonNull(HttpReportingUtil.trackerServer()).split(":")[1] + ":")); } } @@ -579,8 +582,8 @@ public class TraccarClientImpl implements TraccarClient { authorizedKey(HttpReportingUtil.trackerUser(), HttpReportingUtil.trackerPassword()), serverUrl(HttpReportingUtil.trackerServer()))); String result = res.get(); - - if (result.charAt(0) == '{') { + log.info("Group " + trackerGroupInfo.getGroupId() + " has been added to Traccar."); + if (res.isDone() && result.charAt(0) == '{') { JSONObject obj = new JSONObject(result); if (obj.has("id")) { int traccarGroupId = obj.getInt("id"); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/impl/DeviceAPIClientServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/impl/DeviceAPIClientServiceImpl.java index f1f71cb99a8..9095f3dd5b8 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/impl/DeviceAPIClientServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/traccar/api/service/impl/DeviceAPIClientServiceImpl.java @@ -30,7 +30,7 @@ import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup; import org.wso2.carbon.device.mgt.common.exceptions.TrackerAlreadyExistException; import org.wso2.carbon.device.mgt.core.dao.TrackerManagementDAOException; import org.wso2.carbon.device.mgt.core.traccar.api.service.DeviceAPIClientService; -import org.wso2.carbon.device.mgt.core.traccar.api.service.addons.TraccarClientImpl; +import org.wso2.carbon.device.mgt.core.traccar.api.service.TraccarClientFactory; import org.wso2.carbon.device.mgt.core.traccar.common.beans.TraccarDevice; import org.wso2.carbon.device.mgt.core.traccar.common.beans.TraccarGroups; import org.wso2.carbon.device.mgt.core.traccar.common.beans.TraccarPosition; @@ -43,9 +43,10 @@ import java.util.concurrent.ExecutionException; public class DeviceAPIClientServiceImpl implements DeviceAPIClientService { private static final Log log = LogFactory.getLog(DeviceAPIClientServiceImpl.class); + TraccarClientFactory client = TraccarClientFactory.getInstance(); + @Override public void addDevice(Device device, int tenantId) throws ExecutionException, InterruptedException { - TraccarClientImpl client = new TraccarClientImpl(); String lastUpdatedTime = String.valueOf((new Date().getTime())); TraccarDevice traccarDevice = new TraccarDevice(device.getId(), device.getName(), device.getDeviceIdentifier(), "online", "false", lastUpdatedTime, "", "", "", "", @@ -61,8 +62,8 @@ public class DeviceAPIClientServiceImpl implements DeviceAPIClientService { } } + @Override public void updateLocation(Device device, DeviceLocation deviceLocation, int tenantId) throws ExecutionException, InterruptedException { - TraccarClientImpl client = new TraccarClientImpl(); TraccarPosition traccarPosition = new TraccarPosition(device.getDeviceIdentifier(), deviceLocation.getUpdatedTime().getTime(), deviceLocation.getLatitude(), deviceLocation.getLongitude(), @@ -83,8 +84,8 @@ public class DeviceAPIClientServiceImpl implements DeviceAPIClientService { } } + @Override public void disEnrollDevice(int deviceId, int tenantId) throws ExecutionException, InterruptedException{ - TraccarClientImpl client = new TraccarClientImpl(); try { client.disEnrollDevice(deviceId, tenantId); } catch (TrackerManagementDAOException e) { @@ -93,86 +94,92 @@ public class DeviceAPIClientServiceImpl implements DeviceAPIClientService { } } + @Override public void addGroup(DeviceGroup group, int groupId, int tenantId) throws TrackerManagementDAOException, TrackerAlreadyExistException, ExecutionException, InterruptedException { - TraccarClientImpl client = new TraccarClientImpl(); TraccarGroups traccarGroups = new TraccarGroups(group.getName()); client.addGroup(traccarGroups, groupId, tenantId); } + @Override public void updateGroup(DeviceGroup group, int groupId, int tenantId) throws TrackerManagementDAOException, TrackerAlreadyExistException, ExecutionException, InterruptedException { - TraccarClientImpl client = new TraccarClientImpl(); TraccarGroups traccarGroups = new TraccarGroups(group.getName()); client.updateGroup(traccarGroups, groupId, tenantId); } + @Override public void deleteGroup(int groupId, int tenantId) throws TrackerManagementDAOException, ExecutionException, InterruptedException { - TraccarClientImpl client = new TraccarClientImpl(); client.deleteGroup(groupId, tenantId); } - public static String fetchUserInfo(String userName) throws ExecutionException, InterruptedException { - TraccarClientImpl client = new TraccarClientImpl(); - return client.fetchUserInfo(userName); + @Override + public String returnUser(String username) { + TraccarClientFactory client = TraccarClientFactory.getInstance(); + try { + return client.returnUser(username); + } catch (TrackerManagementDAOException e) { + JSONObject obj = new JSONObject(); + String msg = "Error occurred while creating a user: "+ e; + obj.put("error", msg); + return obj.toString(); + } } - public static TrackerDeviceInfo getTrackerDevice(int deviceId, int tenantId) throws + @Override + public TrackerDeviceInfo getTrackerDevice(int deviceId, int tenantId) throws TrackerManagementDAOException { - TraccarClientImpl client = new TraccarClientImpl(); + TraccarClientFactory client = TraccarClientFactory.getInstance(); return client.getTrackerDevice(deviceId, tenantId); } - public static boolean getUserIdofPermissionByDeviceIdNUserId(int deviceId, int userId) throws + @Override + public boolean getUserIdofPermissionByDeviceIdNUserId(int deviceId, int userId) throws TrackerManagementDAOException { - TraccarClientImpl client = new TraccarClientImpl(); + TraccarClientFactory client = TraccarClientFactory.getInstance(); return client.getUserIdofPermissionByDeviceIdNUserId(deviceId, userId); } - public static String createUser(TraccarUser traccarUser) throws ExecutionException, InterruptedException { - TraccarClientImpl client = new TraccarClientImpl(); - return client.createUser(traccarUser); + @Override + public void addTrackerUserDevicePermission(int userId, int deviceId) throws + TrackerManagementDAOException, ExecutionException, InterruptedException { + TraccarClientFactory client = TraccarClientFactory.getInstance(); + client.setPermission(userId, deviceId); } - public static String updateUser(TraccarUser traccarUser, int userId) throws - ExecutionException, InterruptedException { - TraccarClientImpl client = new TraccarClientImpl(); - return client.updateUser(traccarUser, userId); + @Override + public List getUserIdofPermissionByUserIdNIdList(int userId, List NotInDeviceIdList) throws + TrackerManagementDAOException { + TraccarClientFactory client = TraccarClientFactory.getInstance(); + return client.getUserIdofPermissionByUserIdNIdList(userId, NotInDeviceIdList); } - public static String returnUser(String userName) { - TraccarClientImpl client = new TraccarClientImpl(); - try { - return client.returnUser(userName); - } catch (TrackerManagementDAOException e) { - JSONObject obj = new JSONObject(); - String msg = "Error occurred while creating a user: "+ e; - obj.put("error", msg); - return obj.toString(); - } + @Override + public void removeTrackerUserDevicePermission(int userId, int deviceId, int removeType) throws + TrackerManagementDAOException, ExecutionException, InterruptedException { + TraccarClientFactory client = TraccarClientFactory.getInstance(); + client.removePermission(userId, deviceId, removeType); } - public static void addTrackerUserDevicePermission(int userId, int deviceId) throws - TrackerManagementDAOException, ExecutionException, InterruptedException { - TraccarClientImpl client = new TraccarClientImpl(); - client.setPermission(userId, deviceId); + public static String fetchUserInfo(String userName) throws ExecutionException, InterruptedException { + TraccarClientFactory client = TraccarClientFactory.getInstance(); + return client.fetchUserInfo(userName); } - public static void removeTrackerUserDevicePermission(int userId, int deviceId, int removeType) throws - TrackerManagementDAOException, ExecutionException, InterruptedException { - TraccarClientImpl client = new TraccarClientImpl(); - client.removePermission(userId, deviceId, removeType); + public static String createUser(TraccarUser traccarUser) throws ExecutionException, InterruptedException { + TraccarClientFactory client = TraccarClientFactory.getInstance(); + return client.createUser(traccarUser); } - public static List getUserIdofPermissionByUserIdNIdList(int userId, List NotInDeviceIdList) throws - TrackerManagementDAOException { - TraccarClientImpl client = new TraccarClientImpl(); - return client.getUserIdofPermissionByUserIdNIdList(userId, NotInDeviceIdList); + public static String updateUser(TraccarUser traccarUser, int userId) throws + ExecutionException, InterruptedException { + TraccarClientFactory client = TraccarClientFactory.getInstance(); + return client.updateUser(traccarUser, userId); } public static String generateRandomString(int len) { - TraccarClientImpl client = new TraccarClientImpl(); + TraccarClientFactory client = TraccarClientFactory.getInstance(); return client.generateRandomString(len); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/resources/config/operation/traccar-config.xml b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/resources/config/operation/traccar-config.xml index 3521695b04e..7a6de290f2e 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/resources/config/operation/traccar-config.xml +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/test/resources/config/operation/traccar-config.xml @@ -27,8 +27,8 @@ sample http://localhost: - - 5055 + 4385 + 8085 Authorization Basic YWRtaW46YWRtaW4= diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf/traccar-config.xml b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf/traccar-config.xml index 3521695b04e..7a6de290f2e 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf/traccar-config.xml +++ b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf/traccar-config.xml @@ -27,8 +27,8 @@ sample http://localhost: - - 5055 + 4385 + 8085 Authorization Basic YWRtaW46YWRtaW4=