From 4ed28820c88050ed3a63e6cc98f9c8fbcd4583bc Mon Sep 17 00:00:00 2001 From: Amalka Subasinghe Date: Mon, 24 Jan 2022 03:56:25 +0000 Subject: [PATCH] operation timeout feature --- .../operation/mgt/OperationManager.java | 2 + .../core/config/DeviceManagementConfig.java | 11 ++ .../operation/timeout/OperationTimeout.java | 79 ++++++++ .../OperationTimeoutConfiguration.java | 38 ++++ .../internal/DeviceManagementDataHolder.java | 11 ++ .../DeviceTaskManagerServiceComponent.java | 49 +++++ .../operation/mgt/OperationManagerImpl.java | 15 ++ .../core/operation/mgt/dao/OperationDAO.java | 3 + .../mgt/dao/impl/GenericOperationDAOImpl.java | 135 ++++++++++++++ .../task/OperationTimeoutTaskException.java | 62 +++++++ .../OperationTimeoutTaskManagerService.java | 59 ++++++ .../task/impl/OperationTimeoutTask.java | 106 +++++++++++ ...perationTimeoutTaskManagerServiceImpl.java | 172 ++++++++++++++++++ .../src/main/resources/conf/cdm-config.xml | 4 + .../repository/conf/cdm-config.xml.j2 | 29 +++ 15 files changed, 775 insertions(+) create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/operation/timeout/OperationTimeout.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/operation/timeout/OperationTimeoutConfiguration.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/OperationTimeoutTaskException.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/OperationTimeoutTaskManagerService.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/impl/OperationTimeoutTask.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/impl/OperationTimeoutTaskManagerServiceImpl.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/operation/mgt/OperationManager.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/operation/mgt/OperationManager.java index 63333de165c..ec00986a47b 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/operation/mgt/OperationManager.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/operation/mgt/OperationManager.java @@ -154,4 +154,6 @@ public interface OperationManager { */ boolean isOperationExist(DeviceIdentifier deviceId, int operationId) throws OperationManagementException; + List getActivities(List deviceTypes, String operationCode, long updatedSince, String operationStatus) + throws OperationManagementException; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/DeviceManagementConfig.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/DeviceManagementConfig.java index 4b8adcc3570..ebdfa35bfc3 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/DeviceManagementConfig.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/DeviceManagementConfig.java @@ -24,6 +24,7 @@ import org.wso2.carbon.device.mgt.core.config.archival.ArchivalConfiguration; import org.wso2.carbon.device.mgt.core.config.cache.CertificateCacheConfiguration; import org.wso2.carbon.device.mgt.core.config.cache.DeviceCacheConfiguration; import org.wso2.carbon.device.mgt.core.config.cache.GeoFenceCacheConfiguration; +import org.wso2.carbon.device.mgt.core.config.operation.timeout.OperationTimeoutConfiguration; import org.wso2.carbon.device.mgt.core.event.config.EventOperationTaskConfiguration; import org.wso2.carbon.device.mgt.core.config.geo.location.GeoLocationConfiguration; import org.wso2.carbon.device.mgt.core.config.identity.IdentityConfigurations; @@ -66,6 +67,7 @@ public final class DeviceManagementConfig { private ArchivalConfiguration archivalConfiguration; private EnrollmentNotificationConfiguration enrollmentNotificationConfiguration; private DefaultRoles defaultRoles; + private OperationTimeoutConfiguration operationTimeoutConfiguration; @XmlElement(name = "ManagementRepository", required = true) public DeviceManagementConfigRepository getDeviceManagementConfigRepository() { @@ -243,5 +245,14 @@ public final class DeviceManagementConfig { public DefaultRoles getDefaultRoles() { return defaultRoles; } public void setDefaultRoles(DefaultRoles defaultRoles) { this.defaultRoles = defaultRoles; } + + @XmlElement(name = "OperationTimeoutConfigurations", required = true) + public OperationTimeoutConfiguration getOperationTimeoutConfiguration() { + return operationTimeoutConfiguration; + } + + public void setOperationTimeoutConfiguration(OperationTimeoutConfiguration operationTimeoutConfiguration) { + this.operationTimeoutConfiguration = operationTimeoutConfiguration; + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/operation/timeout/OperationTimeout.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/operation/timeout/OperationTimeout.java new file mode 100644 index 00000000000..f9f9302770e --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/operation/timeout/OperationTimeout.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2022, Entgra (Pvt) Ltd. (http://www.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.config.operation.timeout; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; + +@XmlRootElement(name = "OperationTimeout") +public class OperationTimeout { + + private String code; + private int timeout; + private List deviceTypes; + private String initialStatus; + private String nextStatus; + + public String getCode() { + return code; + } + + @XmlElement(name = "Code", required = true) + public void setCode(String code) { + this.code = code; + } + + public int getTimeout() { + return timeout; + } + + @XmlElement(name = "Timeout", required = true) + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + public List getDeviceTypes() { + return deviceTypes; + } + + @XmlElementWrapper(name = "DeviceTypes", required = true) + @XmlElement(name = "DeviceType", required = true) + public void setDeviceTypes(List deviceTypes) { + this.deviceTypes = deviceTypes; + } + + public String getInitialStatus() { + return initialStatus; + } + + @XmlElement(name = "InitialStatus", required = true) + public void setInitialStatus(String initialStatus) { + this.initialStatus = initialStatus; + } + + public String getNextStatus() { + return nextStatus; + } + + @XmlElement(name = "NextStatus", required = true) + public void setNextStatus(String nextStatus) { + this.nextStatus = nextStatus; + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/operation/timeout/OperationTimeoutConfiguration.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/operation/timeout/OperationTimeoutConfiguration.java new file mode 100644 index 00000000000..a2777eda404 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/operation/timeout/OperationTimeoutConfiguration.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022, Entgra (Pvt) Ltd. (http://www.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.config.operation.timeout; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; + +@XmlRootElement(name = "OperationTimeoutConfigurations") +public class OperationTimeoutConfiguration { + private List operationTimeoutList; + + public List getOperationTimeoutList() { + return operationTimeoutList; + } + + @XmlElementWrapper(name = "OperationTimeouts", required = true) + @XmlElement(name = "OperationTimeout", required = false) + public void setOperationTimeoutList(List operationTimeoutList) { + this.operationTimeoutList = operationTimeoutList; + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementDataHolder.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementDataHolder.java index 818df70b490..5cb1a1c9ab6 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementDataHolder.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementDataHolder.java @@ -34,6 +34,7 @@ import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceInformationManag import org.wso2.carbon.device.mgt.core.dto.DeviceType; import org.wso2.carbon.device.mgt.core.dto.DeviceTypeServiceIdentifier; import org.wso2.carbon.device.mgt.core.geo.task.GeoFenceEventOperationManager; +import org.wso2.carbon.device.mgt.core.operation.timeout.task.OperationTimeoutTaskManagerService; import org.wso2.carbon.device.mgt.core.privacy.PrivacyComplianceProvider; import org.wso2.carbon.device.mgt.core.push.notification.mgt.PushNotificationProviderRepository; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; @@ -81,6 +82,7 @@ public class DeviceManagementDataHolder { private GeoLocationProviderService geoLocationProviderService; private GeoFenceEventOperationManager geoFenceEventOperationManager; private ExecutorService eventConfigExecutors; + private OperationTimeoutTaskManagerService operationTimeoutTaskManagerService; private final Map deviceStatusTaskPluginConfigs = Collections.synchronizedMap( new HashMap<>()); @@ -338,4 +340,13 @@ public class DeviceManagementDataHolder { public void setEventConfigExecutors(ExecutorService eventConfigExecutors) { this.eventConfigExecutors = eventConfigExecutors; } + + public OperationTimeoutTaskManagerService getOperationTimeoutTaskManagerService() { + return operationTimeoutTaskManagerService; + } + + public void setOperationTimeoutTaskManagerService( + OperationTimeoutTaskManagerService operationTimeoutTaskManagerService) { + this.operationTimeoutTaskManagerService = operationTimeoutTaskManagerService; + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceTaskManagerServiceComponent.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceTaskManagerServiceComponent.java index 489a29c72c2..a7cba70a35a 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceTaskManagerServiceComponent.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceTaskManagerServiceComponent.java @@ -26,7 +26,12 @@ import org.wso2.carbon.device.mgt.common.DeviceStatusTaskPluginConfig; import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig; import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager; import org.wso2.carbon.device.mgt.core.config.DeviceManagementConfig; +import org.wso2.carbon.device.mgt.core.config.operation.timeout.OperationTimeout; +import org.wso2.carbon.device.mgt.core.config.operation.timeout.OperationTimeoutConfiguration; import org.wso2.carbon.device.mgt.core.dto.DeviceType; +import org.wso2.carbon.device.mgt.core.operation.timeout.task.OperationTimeoutTaskException; +import org.wso2.carbon.device.mgt.core.operation.timeout.task.OperationTimeoutTaskManagerService; +import org.wso2.carbon.device.mgt.core.operation.timeout.task.impl.OperationTimeoutTaskManagerServiceImpl; import org.wso2.carbon.device.mgt.core.status.task.DeviceStatusTaskException; import org.wso2.carbon.device.mgt.core.status.task.DeviceStatusTaskManagerService; import org.wso2.carbon.device.mgt.core.status.task.impl.DeviceStatusTaskManagerServiceImpl; @@ -66,6 +71,10 @@ public class DeviceTaskManagerServiceComponent { if (deviceManagementConfig != null && deviceManagementConfig.getDeviceStatusTaskConfig().isEnabled()) { startDeviceStatusMonitoringTask(componentContext.getBundleContext()); } + + if (deviceManagementConfig != null && deviceManagementConfig.getOperationTimeoutConfiguration() != null) { + startOperationTimeoutTask(componentContext.getBundleContext()); + } } catch (Throwable e) { log.error("Error occurred while initializing device task manager service.", e); } @@ -102,6 +111,27 @@ public class DeviceTaskManagerServiceComponent { } } + private void startOperationTimeoutTask(BundleContext bundleContext) { + OperationTimeoutTaskManagerService operationTimeoutTaskManagerService = + new OperationTimeoutTaskManagerServiceImpl(); + DeviceManagementDataHolder.getInstance().setOperationTimeoutTaskManagerService( + operationTimeoutTaskManagerService); + bundleContext.registerService(OperationTimeoutTaskManagerService.class, + operationTimeoutTaskManagerService, null); + + OperationTimeoutConfiguration configuration = deviceManagementConfig.getOperationTimeoutConfiguration(); + + for (OperationTimeout operationTimeout : configuration.getOperationTimeoutList()) { + try { + operationTimeoutTaskManagerService.startTask(operationTimeout); + } catch (OperationTimeoutTaskException e) { + log.error("Error while starting the operation timeout task for device type (s) : " + + operationTimeout.getDeviceTypes() + ", operation code : " + + operationTimeout.getInitialStatus()); + } + } + } + @SuppressWarnings("unused") protected void deactivate(ComponentContext componentContext) { try { @@ -109,6 +139,9 @@ public class DeviceTaskManagerServiceComponent { if (deviceManagementConfig != null && deviceManagementConfig.getDeviceStatusTaskConfig().isEnabled()) { stopDeviceStatusMonitoringTask(); } + if (deviceManagementConfig != null && deviceManagementConfig.getOperationTimeoutConfiguration() != null) { + stopOperationTimeoutTask(); + } } catch (Throwable e) { log.error("Error occurred while shutting down device task manager service.", e); } @@ -143,6 +176,22 @@ public class DeviceTaskManagerServiceComponent { } } + private void stopOperationTimeoutTask() { + OperationTimeoutTaskManagerService operationTimeoutTaskManagerService = + DeviceManagementDataHolder.getInstance().getOperationTimeoutTaskManagerService(); + OperationTimeoutConfiguration configuration = deviceManagementConfig.getOperationTimeoutConfiguration(); + + for (OperationTimeout operationTimeout : configuration.getOperationTimeoutList()) { + try { + operationTimeoutTaskManagerService.stopTask(operationTimeout); + } catch (OperationTimeoutTaskException e) { + log.error("Error while stopping the operation timeout task for device type (s) : " + + operationTimeout.getDeviceTypes() + ", operation code : " + + operationTimeout.getInitialStatus()); + } + } + } + protected void setTaskService(TaskService taskService) { if (log.isDebugEnabled()) { log.debug("Setting the task service."); diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/OperationManagerImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/OperationManagerImpl.java index 32615eb5e25..27882f4fbd3 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/OperationManagerImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/OperationManagerImpl.java @@ -1587,4 +1587,19 @@ public class OperationManagerImpl implements OperationManager { OperationManagementDAOFactory.closeConnection(); } } + + @Override + public List getActivities(List deviceTypes, String operationCode, long updatedSince, String operationStatus) + throws OperationManagementException { + try { + OperationManagementDAOFactory.openConnection(); + return operationDAO.getActivities(deviceTypes, operationCode, updatedSince, operationStatus); + } catch (SQLException e) { + throw new OperationManagementException("Error occurred while opening a connection to the data source.", e); + } catch (OperationManagementDAOException e) { + throw new OperationManagementException("Error occurred while getting the activity list.", e); + } finally { + OperationManagementDAOFactory.closeConnection(); + } + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/OperationDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/OperationDAO.java index 26e4f20ef86..6d54790c02c 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/OperationDAO.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/OperationDAO.java @@ -101,6 +101,9 @@ public interface OperationDAO { Map> getOperationMappingsByStatus(Operation.Status opStatus, Operation.PushNotificationStatus pushNotificationStatus, int limit) throws OperationManagementDAOException; + List getActivities(List deviceTypes, String operationCode, long updatedSince, String operationStatus) + throws OperationManagementDAOException; + List getActivities(ActivityPaginationRequest activityPaginationRequest) throws OperationManagementDAOException; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/impl/GenericOperationDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/impl/GenericOperationDAOImpl.java index 3723bb488f1..f6f7e4b0cca 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/impl/GenericOperationDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/impl/GenericOperationDAOImpl.java @@ -1723,6 +1723,141 @@ public class GenericOperationDAOImpl implements OperationDAO { return operationMappingsTenantMap; } + + public List getActivities(List deviceTypes, String operationCode, long updatedSince, String operationStatus) + throws OperationManagementDAOException { + try { + + Connection conn = OperationManagementDAOFactory.getConnection(); + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); + StringBuilder sql = new StringBuilder("SELECT " + + " eom.ENROLMENT_ID," + + " eom.CREATED_TIMESTAMP," + + " eom.UPDATED_TIMESTAMP," + + " eom.OPERATION_ID," + + " eom.OPERATION_CODE," + + " eom.INITIATED_BY," + + " eom.TYPE," + + " eom.STATUS," + + " eom.DEVICE_ID," + + " eom.DEVICE_IDENTIFICATION," + + " eom.DEVICE_TYPE," + + " opr.ID AS OP_RES_ID," + + " opr.RECEIVED_TIMESTAMP," + + " opr.OPERATION_RESPONSE," + + " opr.IS_LARGE_RESPONSE " + + "FROM " + + " DM_ENROLMENT_OP_MAPPING eom " + + "LEFT JOIN " + + " DM_DEVICE_OPERATION_RESPONSE opr ON opr.EN_OP_MAP_ID = eom.ID " + + "INNER JOIN " + + " (SELECT DISTINCT OPERATION_ID FROM DM_ENROLMENT_OP_MAPPING WHERE TENANT_ID = ? "); + + + if (deviceTypes != null && !deviceTypes.isEmpty()) { + sql.append("AND DEVICE_TYPE IN ("); + for (int i = 0; i < deviceTypes.size() - 1; i++) { + sql.append("?, "); + } + sql.append("?) "); + } + + if (operationCode != null) { + sql.append("AND OPERATION_CODE = ? "); + } + + if (updatedSince != 0) { + sql.append("AND UPDATED_TIMESTAMP < ? "); + } + + if (operationStatus != null) { + sql.append("AND STATUS = ? "); + } + + sql.append("ORDER BY OPERATION_ID ASC ) eom_ordered " + + "ON eom_ordered.OPERATION_ID = eom.OPERATION_ID WHERE eom.TENANT_ID = ? "); + + if (deviceTypes != null && !deviceTypes.isEmpty()) { + sql.append("AND DEVICE_TYPE IN ("); + for (int i = 0; i < deviceTypes.size() - 1; i++) { + sql.append("?, "); + } + sql.append("?) "); + } + + if (operationCode != null) { + sql.append("AND eom.OPERATION_CODE = ? "); + } + + if (updatedSince != 0) { + sql.append("AND eom.UPDATED_TIMESTAMP < ? "); + } + + if (operationStatus != null) { + sql.append("AND eom.STATUS = ? "); + } + + sql.append("ORDER BY eom.OPERATION_ID, eom.UPDATED_TIMESTAMP"); + + int index = 1; + try (PreparedStatement stmt = conn.prepareStatement(sql.toString())) { + stmt.setInt(index++, tenantId); + + if (deviceTypes != null && !deviceTypes.isEmpty()) { + for (String deviceId : deviceTypes) { + stmt.setString(index++, deviceId); + } + } + + if (operationCode != null) { + stmt.setString(index++, operationCode); + } + + if (updatedSince != 0) { + stmt.setLong(index++, updatedSince); + } + + if (operationStatus != null) { + stmt.setString(index++, operationStatus); + } + + stmt.setInt(index++, tenantId); + + if (deviceTypes != null && !deviceTypes.isEmpty()) { + for (String deviceId : deviceTypes) { + stmt.setString(index++, deviceId); + } + } + + if (operationCode != null) { + stmt.setString(index++, operationCode); + } + + if (updatedSince != 0) { + stmt.setLong(index++, updatedSince); + } + + if (operationStatus != null) { + stmt.setString(index, operationStatus); + } + + try (ResultSet rs = stmt.executeQuery()) { + ActivityHolder activityHolder = OperationDAOUtil.getActivityHolder(rs); + List largeResponseIDs = activityHolder.getLargeResponseIDs(); + List activities = activityHolder.getActivityList(); + if (!largeResponseIDs.isEmpty()) { + populateLargeOperationResponses(activities, largeResponseIDs); + } + return activities; + } + } + } catch (SQLException e) { + String msg = "Error occurred while getting the operation details from the database."; + log.error(msg, e); + throw new OperationManagementDAOException(msg, e); + } + } + @Override public List getActivities(ActivityPaginationRequest activityPaginationRequest) throws OperationManagementDAOException { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/OperationTimeoutTaskException.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/OperationTimeoutTaskException.java new file mode 100644 index 00000000000..c6a561ca3be --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/OperationTimeoutTaskException.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2022, Entgra (Pvt) Ltd. (http://www.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.operation.timeout.task; + +/** + * This exception class defines the custom exceptions thrown by the OperationTimeoutTask related components. + */ +public class OperationTimeoutTaskException extends Exception { + + private static final long serialVersionUID = -31222242646464497L; + + private String errorMessage; + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public OperationTimeoutTaskException(String msg, Exception nestedEx) { + super(msg, nestedEx); + setErrorMessage(msg); + } + + public OperationTimeoutTaskException(String message, Throwable cause) { + super(message, cause); + setErrorMessage(message); + } + + public OperationTimeoutTaskException(String msg) { + super(msg); + setErrorMessage(msg); + } + + public OperationTimeoutTaskException() { + super(); + } + + public OperationTimeoutTaskException(Throwable cause) { + super(cause); + } + +} + diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/OperationTimeoutTaskManagerService.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/OperationTimeoutTaskManagerService.java new file mode 100644 index 00000000000..f605fd3ee69 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/OperationTimeoutTaskManagerService.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022, Entgra (Pvt) Ltd. (http://www.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.operation.timeout.task; + +import org.wso2.carbon.device.mgt.core.config.operation.timeout.OperationTimeout; + +/** + * This interface defines the methods that should be implemented by the management service of OperationTimeoutTask + */ +public interface OperationTimeoutTaskManagerService { + + /** + * This method will start the task + * @param config + * @throws OperationTimeoutTaskException + */ + void startTask(OperationTimeout config) + throws OperationTimeoutTaskException; + + /** + * This method will stop the task. + * @param config + * @throws OperationTimeoutTaskException + */ + void stopTask(OperationTimeout config) + throws OperationTimeoutTaskException; + + /** + * This will update the task frequency which it runs. + * + * @param config + * @throws OperationTimeoutTaskException + */ + void updateTask(OperationTimeout config) + throws OperationTimeoutTaskException; + + /** + * This will check weather the task is scheduled. + * @return + * @throws OperationTimeoutTaskException + */ + boolean isTaskScheduled(OperationTimeout config) throws OperationTimeoutTaskException; +} \ No newline at end of file diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/impl/OperationTimeoutTask.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/impl/OperationTimeoutTask.java new file mode 100644 index 00000000000..2ee7e320328 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/impl/OperationTimeoutTask.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2022, Entgra (Pvt) Ltd. (http://www.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.operation.timeout.task.impl; + +import com.google.gson.Gson; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.operation.mgt.Activity; +import org.wso2.carbon.device.mgt.common.operation.mgt.ActivityStatus; +import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; +import org.wso2.carbon.device.mgt.core.config.operation.timeout.OperationTimeout; +import org.wso2.carbon.device.mgt.core.dto.DeviceType; +import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder; +import org.wso2.carbon.device.mgt.core.task.impl.DynamicPartitionedScheduleTask; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class OperationTimeoutTask extends DynamicPartitionedScheduleTask { + + private static final Log log = LogFactory.getLog(OperationTimeoutTask.class); + private OperationTimeout operationTimeoutConfig; + + @Override + public void setProperties(Map properties) { + super.setProperties(properties); + String operationTimeoutTaskConfigStr = properties + .get(OperationTimeoutTaskManagerServiceImpl.OPERATION_TIMEOUT_TASK_CONFIG); + Gson gson = new Gson(); + operationTimeoutConfig = gson.fromJson(operationTimeoutTaskConfigStr, OperationTimeout.class); + } + + @Override + public String getProperty(String name) { + return super.getProperty(name); + } + + @Override + public void refreshContext() { + super.refreshContext(); + } + + @Override + protected void setup() { + + } + + @Override + protected void executeDynamicTask() { + try { + + long timeMillis = System.currentTimeMillis() - operationTimeoutConfig.getTimeout() * 60 * 1000; + List deviceTypes = new ArrayList<>(); + if (operationTimeoutConfig.getDeviceTypes().size() == 1 && + "ALL".equals(operationTimeoutConfig.getDeviceTypes().get( 0))) { + try { + List deviceTypeList = DeviceManagementDataHolder.getInstance() + .getDeviceManagementProvider().getDeviceTypes(); + for (DeviceType deviceType : deviceTypeList) { + deviceTypes.add(deviceType.getName()); + } + } catch (DeviceManagementException e) { + log.error("Error occurred while reading device types", e); + } + } else { + deviceTypes = operationTimeoutConfig.getDeviceTypes(); + } + List activities = DeviceManagementDataHolder.getInstance().getOperationManager() + .getActivities(deviceTypes, operationTimeoutConfig.getCode(), timeMillis, + operationTimeoutConfig.getInitialStatus()); + for (Activity activity : activities) { + for (ActivityStatus activityStatus : activity.getActivityStatus()) { + String operationId = activity.getActivityId().replace("ACTIVITY_", ""); + Operation operation = DeviceManagementDataHolder.getInstance().getOperationManager() + .getOperation(Integer.parseInt(operationId)); + operation.setStatus(Operation.Status.valueOf(operationTimeoutConfig.getNextStatus())); + DeviceManagementDataHolder.getInstance().getOperationManager() + .updateOperation(activityStatus.getDeviceIdentifier(), operation); + } + } + + } catch (OperationManagementException e) { + String msg = "Error occurred while retrieving operations."; + log.error(msg, e); + } + } + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/impl/OperationTimeoutTaskManagerServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/impl/OperationTimeoutTaskManagerServiceImpl.java new file mode 100644 index 00000000000..b438b9215a2 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/timeout/task/impl/OperationTimeoutTaskManagerServiceImpl.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2022, Entgra (Pvt) Ltd. (http://www.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.operation.timeout.task.impl; + +import com.google.gson.Gson; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.mgt.core.config.operation.timeout.OperationTimeout; +import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder; +import org.wso2.carbon.device.mgt.core.operation.timeout.task.OperationTimeoutTaskException; +import org.wso2.carbon.device.mgt.core.operation.timeout.task.OperationTimeoutTaskManagerService; +import org.wso2.carbon.ntask.common.TaskException; +import org.wso2.carbon.ntask.core.TaskInfo; +import org.wso2.carbon.ntask.core.TaskManager; +import org.wso2.carbon.ntask.core.service.TaskService; + +import java.util.HashMap; +import java.util.Map; + +public class OperationTimeoutTaskManagerServiceImpl implements OperationTimeoutTaskManagerService { + + private static final Log log = LogFactory.getLog(OperationTimeoutTaskManagerServiceImpl.class); + + public static final String OPERATION_TIMEOUT_TASK = "OPERATION_TIMEOUT_TASK"; + static final String DEVICE_TYPES = "DEVICE_TYPES"; + static final String OPERATION_TIMEOUT_TASK_CONFIG = "OPERATION_TIMEOUT_TASK_CONFIG"; + static final String INITIAL_STATUS = "INITIAL_STATUS"; + private static final String TASK_CLASS = OperationTimeoutTask.class.getName(); + + @Override + public void startTask(OperationTimeout config) + throws OperationTimeoutTaskException { + log.info("Operation timeout task adding for device type(s) : " + config.getDeviceTypes() + + ", operation code : " + config.getInitialStatus()); + + try { + TaskService taskService = DeviceManagementDataHolder.getInstance().getTaskService(); + taskService.registerTaskType(OPERATION_TIMEOUT_TASK); + + if (log.isDebugEnabled()) { + log.debug("Operation timeout task is started for the device type(s) : " + config.getDeviceTypes() + + ", operation code : " + config.getInitialStatus()); + log.debug( + "Operation timeout task is at frequency of : " + config.getTimeout() + " minutes"); + } + + TaskManager taskManager = taskService.getTaskManager(OPERATION_TIMEOUT_TASK); + + TaskInfo.TriggerInfo triggerInfo = new TaskInfo.TriggerInfo(); + //Convert to milli seconds + triggerInfo.setIntervalMillis(config.getTimeout() * 60 * 1000); + triggerInfo.setRepeatCount(-1); + + Gson gson = new Gson(); + String operationTimeoutConfig = gson.toJson(config); + + Map properties = new HashMap<>(); + + String deviceTypes = StringUtils.join(config.getDeviceTypes(), "_"); + properties.put(DEVICE_TYPES, deviceTypes); + properties.put(INITIAL_STATUS, config.getInitialStatus()); + properties.put(OPERATION_TIMEOUT_TASK_CONFIG, operationTimeoutConfig); + + String taskName = OPERATION_TIMEOUT_TASK + "_" + config.getInitialStatus() + "_" + deviceTypes; + + if (!taskManager.isTaskScheduled(taskName)) { + TaskInfo taskInfo = new TaskInfo(taskName, TASK_CLASS, properties, triggerInfo); + taskManager.registerTask(taskInfo); + taskManager.rescheduleTask(taskInfo.getName()); + } else { + throw new OperationTimeoutTaskException( + "Operation Timeout task is already started for the device type(s) : " + config.getDeviceTypes() + + ", operation code : " + config.getInitialStatus()); + } + } catch (TaskException e) { + throw new OperationTimeoutTaskException("Error occurred while creating the Operation timeout task " + + "for the device type(s) : " + config.getDeviceTypes() + ", operation code : " + config + .getInitialStatus(), e); + } + } + + @Override + public void stopTask(OperationTimeout config) + throws OperationTimeoutTaskException { + try { + TaskService taskService = DeviceManagementDataHolder.getInstance().getTaskService(); + String deviceTypes = StringUtils.join(config.getDeviceTypes(), "_"); + String taskName = OPERATION_TIMEOUT_TASK + "_" + config.getInitialStatus() + "_" + deviceTypes; + if (taskService != null && taskService.isServerInit()) { + TaskManager taskManager = taskService.getTaskManager(OPERATION_TIMEOUT_TASK); + taskManager.deleteTask(taskName); + } + } catch (TaskException e) { + throw new OperationTimeoutTaskException("Error occurred while deleting the Operation timeout task " + + "for the device type(s) : " + config.getDeviceTypes() + ", operation code : " + config + .getInitialStatus(), e); + } + } + + @Override + public void updateTask(OperationTimeout config) + throws OperationTimeoutTaskException { + try { + TaskService taskService = DeviceManagementDataHolder.getInstance().getTaskService(); + TaskManager taskManager = taskService.getTaskManager(OPERATION_TIMEOUT_TASK); + String deviceTypes = StringUtils.join(config.getDeviceTypes(), "_"); + String taskName = OPERATION_TIMEOUT_TASK + "_" + config.getInitialStatus() + "_" + deviceTypes; + + if (taskManager.isTaskScheduled(taskName)) { + taskManager.deleteTask(taskName); + TaskInfo.TriggerInfo triggerInfo = new TaskInfo.TriggerInfo(); + triggerInfo.setIntervalMillis(config.getTimeout() * 60 * 1000); + triggerInfo.setRepeatCount(-1); + + Map properties = new HashMap<>(); + properties.put(DEVICE_TYPES, deviceTypes); + properties.put(INITIAL_STATUS, config.getInitialStatus()); + + Gson gson = new Gson(); + String deviceStatusTaskConfigs = gson.toJson(config); + properties.put(OPERATION_TIMEOUT_TASK_CONFIG, deviceStatusTaskConfigs); + + TaskInfo taskInfo = new TaskInfo(taskName, TASK_CLASS, properties, triggerInfo); + + taskManager.registerTask(taskInfo); + taskManager.rescheduleTask(taskInfo.getName()); + } else { + throw new OperationTimeoutTaskException( + "Operation timeout task has not been started for this device-type the device type(s) : " + + config.getDeviceTypes() + ", operation code : " + config.getInitialStatus() + + ". Please start the task first."); + } + + } catch (TaskException e) { + throw new OperationTimeoutTaskException("Error occurred while updating the Operation timeout task " + + "for the device type(s) : " + config.getDeviceTypes() + ", operation code : " + + config.getInitialStatus(), e); + } + } + + @Override + public boolean isTaskScheduled(OperationTimeout config) throws OperationTimeoutTaskException { + String deviceTypes = StringUtils.join(config.getDeviceTypes(), "_"); + String taskName = OPERATION_TIMEOUT_TASK + "_" + config.getInitialStatus() + "_" + deviceTypes; + TaskService taskService = DeviceManagementDataHolder.getInstance().getTaskService(); + TaskManager taskManager; + try { + taskManager = taskService.getTaskManager(OPERATION_TIMEOUT_TASK); + return taskManager.isTaskScheduled(taskName); + } catch (TaskException e) { + throw new OperationTimeoutTaskException("Error occurred while checking the task schedule status " + + "of the Operation timeout task for the device type(s) : " + config.getDeviceTypes() + + ", operation code : " + config.getInitialStatus(), e); + } + } +} diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf/cdm-config.xml b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf/cdm-config.xml index d15901005e5..50e3afd8245 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf/cdm-config.xml +++ b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf/cdm-config.xml @@ -178,5 +178,9 @@ + + + + diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf_templates/templates/repository/conf/cdm-config.xml.j2 b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf_templates/templates/repository/conf/cdm-config.xml.j2 index 78b0fafd8a4..19feedc4b12 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf_templates/templates/repository/conf/cdm-config.xml.j2 +++ b/features/device-mgt/org.wso2.carbon.device.mgt.basics.feature/src/main/resources/conf_templates/templates/repository/conf/cdm-config.xml.j2 @@ -311,5 +311,34 @@ + + + + + + + + + + + + {% if device_mgt_conf.operation_timeout_conf is defined %} + {% for timeout_conf in device_mgt_conf.operation_timeout_conf %} + + + {% for device_type in timeout_conf.device_types %} + {{device_type}} + {% endfor %} + + + {{timeout_conf.code}} + {{timeout_conf.initial_status}} + {{timeout_conf.timeout}} + {{timeout_conf.next_status}} + + {% endfor %} + {% endif%} + +