diff --git a/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.device.type.deployer/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/deployer/config/PushNotificationProvider.java b/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.device.type.deployer/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/deployer/config/PushNotificationProvider.java index 43aee84397..59e6e68b7b 100644 --- a/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.device.type.deployer/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/deployer/config/PushNotificationProvider.java +++ b/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.device.type.deployer/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/deployer/config/PushNotificationProvider.java @@ -59,6 +59,8 @@ public class PushNotificationProvider { protected ConfigProperties configProperties; @XmlAttribute(name = "type") protected String type; + @XmlAttribute(name = "isScheduled") + protected boolean isScheduled; /** * Gets the value of the fileBasedProperties property. @@ -124,4 +126,30 @@ public class PushNotificationProvider { this.type = value; } + /** + * Gets the value of the isScheduled property. + * This property will be used to determine whether to use scheduler task to send push notification + * If true push notification will be sent using scheduler task + * If false push notifications will be sent immediately. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public boolean isScheduled() { + return isScheduled; + } + + /** + * Sets the value of the isScheduled property. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public void setScheduled(boolean scheduled) { + isScheduled = scheduled; + } } diff --git a/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.device.type.deployer/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/deployer/template/DeviceTypeManagerService.java b/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.device.type.deployer/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/deployer/template/DeviceTypeManagerService.java index bf05136bc0..fc28c446e8 100644 --- a/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.device.type.deployer/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/deployer/template/DeviceTypeManagerService.java +++ b/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.device.type.deployer/src/main/java/org/wso2/carbon/device/mgt/extensions/device/type/deployer/template/DeviceTypeManagerService.java @@ -20,7 +20,12 @@ package org.wso2.carbon.device.mgt.extensions.device.type.deployer.template; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.device.mgt.common.*; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.DeviceManager; +import org.wso2.carbon.device.mgt.common.InitialOperationConfig; +import org.wso2.carbon.device.mgt.common.MonitoringOperation; +import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig; +import org.wso2.carbon.device.mgt.common.ProvisioningConfig; import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManager; import org.wso2.carbon.device.mgt.common.configuration.mgt.ConfigurationEntry; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; @@ -111,7 +116,8 @@ public class DeviceTypeManagerService implements DeviceManagementService { for (Property property : pushNotificationProvider.getConfigProperties().getProperty()) { staticProps.put(property.getName(), property.getValue()); } - pushNotificationConfig = new PushNotificationConfig(pushNotificationProvider.getType(), staticProps); + pushNotificationConfig = new PushNotificationConfig(pushNotificationProvider.getType(), + pushNotificationProvider.isScheduled(), staticProps); } else { try { PlatformConfiguration deviceTypeConfig = deviceManager.getConfiguration(); @@ -120,7 +126,8 @@ public class DeviceTypeManagerService implements DeviceManagementService { if (configuration.size() > 0) { Map properties = this.getConfigProperty(configuration); pushNotificationConfig = new PushNotificationConfig( - pushNotificationProvider.getType(), properties); + pushNotificationProvider.getType(), pushNotificationProvider.isScheduled(), + properties); } } } catch (DeviceManagementException e) { diff --git a/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.push.notification.provider.fcm/src/main/java/org/wso2/carbon/device/mgt/extensions/push/notification/provider/fcm/FCMNotificationStrategy.java b/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.push.notification.provider.fcm/src/main/java/org/wso2/carbon/device/mgt/extensions/push/notification/provider/fcm/FCMNotificationStrategy.java index 6dd66f0836..da488c5435 100644 --- a/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.push.notification.provider.fcm/src/main/java/org/wso2/carbon/device/mgt/extensions/push/notification/provider/fcm/FCMNotificationStrategy.java +++ b/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.push.notification.provider.fcm/src/main/java/org/wso2/carbon/device/mgt/extensions/push/notification/provider/fcm/FCMNotificationStrategy.java @@ -42,7 +42,7 @@ public class FCMNotificationStrategy implements NotificationStrategy { private static final String FCM_API_KEY = "fcmAPIKey"; private static final int TIME_TO_LIVE = 60; private static final int HTTP_STATUS_CODE_OK = 200; - private PushNotificationConfig config; + private final PushNotificationConfig config; public FCMNotificationStrategy(PushNotificationConfig config) { this.config = config; @@ -133,4 +133,9 @@ public class FCMNotificationStrategy implements NotificationStrategy { return fcmToken; } + @Override + public PushNotificationConfig getConfig() { + return config; + } + } diff --git a/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.push.notification.provider.mqtt/src/main/java/org/wso2/carbon/device/mgt/extensions/push/notification/provider/mqtt/MQTTNotificationStrategy.java b/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.push.notification.provider.mqtt/src/main/java/org/wso2/carbon/device/mgt/extensions/push/notification/provider/mqtt/MQTTNotificationStrategy.java index 93be818999..8af53af6b2 100644 --- a/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.push.notification.provider.mqtt/src/main/java/org/wso2/carbon/device/mgt/extensions/push/notification/provider/mqtt/MQTTNotificationStrategy.java +++ b/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.push.notification.provider.mqtt/src/main/java/org/wso2/carbon/device/mgt/extensions/push/notification/provider/mqtt/MQTTNotificationStrategy.java @@ -45,8 +45,10 @@ public class MQTTNotificationStrategy implements NotificationStrategy { private static final String MQTT_ADAPTER_TOPIC = "mqtt.adapter.topic"; private String mqttAdapterName; private static final Log log = LogFactory.getLog(MQTTNotificationStrategy.class); + private final PushNotificationConfig config; public MQTTNotificationStrategy(PushNotificationConfig config) { + this.config = config; OutputEventAdapterConfiguration adapterConfig = new OutputEventAdapterConfiguration(); adapterConfig.setType(MQTTAdapterConstants.MQTT_ADAPTER_TYPE); mqttAdapterName = config.getProperty(MQTTAdapterConstants.MQTT_ADAPTER_PROPERTY_NAME); @@ -137,5 +139,10 @@ public class MQTTNotificationStrategy implements NotificationStrategy { MQTTDataHolder.getInstance().getOutputEventAdapterService().destroy(mqttAdapterName); } + @Override + public PushNotificationConfig getConfig() { + return config; + } + } diff --git a/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.push.notification.provider.xmpp/src/main/java/org/wso2/carbon/device/mgt/extensions/push/notification/provider/xmpp/XMPPNotificationStrategy.java b/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.push.notification.provider.xmpp/src/main/java/org/wso2/carbon/device/mgt/extensions/push/notification/provider/xmpp/XMPPNotificationStrategy.java index 0d7229a193..af3a1c6c4b 100644 --- a/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.push.notification.provider.xmpp/src/main/java/org/wso2/carbon/device/mgt/extensions/push/notification/provider/xmpp/XMPPNotificationStrategy.java +++ b/components/device-mgt-extensions/org.wso2.carbon.device.mgt.extensions.push.notification.provider.xmpp/src/main/java/org/wso2/carbon/device/mgt/extensions/push/notification/provider/xmpp/XMPPNotificationStrategy.java @@ -45,10 +45,12 @@ public class XMPPNotificationStrategy implements NotificationStrategy { private String xmppAdapterName; private static final Log log = LogFactory.getLog(XMPPNotificationStrategy.class); private String subDomain; + private final PushNotificationConfig config; public XMPPNotificationStrategy(PushNotificationConfig config) { + this.config = config; OutputEventAdapterConfiguration outputEventAdapterConfiguration = new OutputEventAdapterConfiguration(); xmppAdapterName = config.getProperty(XMPPAdapterConstants.XMPP_ADAPTER_PROPERTY_NAME); outputEventAdapterConfiguration.setName(xmppAdapterName); @@ -106,4 +108,8 @@ public class XMPPNotificationStrategy implements NotificationStrategy { XMPPDataHolder.getInstance().getOutputEventAdapterService().destroy(xmppAdapterName); } + @Override + public PushNotificationConfig getConfig() { + return config; + } } 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 8c8818f736..ce548628b9 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 @@ -21,6 +21,7 @@ import org.wso2.carbon.device.mgt.common.*; import org.wso2.carbon.device.mgt.common.push.notification.NotificationStrategy; import java.util.List; +import java.util.Map; /** * This represents the Device Operation management functionality which should be implemented by diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/push/notification/NotificationStrategy.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/push/notification/NotificationStrategy.java index bce041a2f2..c1f7e37da7 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/push/notification/NotificationStrategy.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/push/notification/NotificationStrategy.java @@ -31,4 +31,10 @@ public interface NotificationStrategy { */ void undeploy(); + /** + * Provides push notification configuration + * + */ + PushNotificationConfig getConfig(); + } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/push/notification/PushNotificationConfig.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/push/notification/PushNotificationConfig.java index 56cb65648e..6b9e9f9f3e 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/push/notification/PushNotificationConfig.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/push/notification/PushNotificationConfig.java @@ -26,11 +26,13 @@ import java.util.Map; public class PushNotificationConfig { private String type; + private boolean isScheduled; Map properties; - public PushNotificationConfig(String type, Map properties) { + public PushNotificationConfig(String type, boolean isScheduled, Map properties) { this.type = type; this.properties = properties; + this.isScheduled = isScheduled; } @XmlElement(name = "Type", required = true) @@ -38,6 +40,11 @@ public class PushNotificationConfig { return type; } + @XmlElement(name = "isScheduled") + public boolean isScheduled() { + return isScheduled; + } + public Map getProperties() { return properties; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java index a1749b8f31..15df1e4435 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java @@ -86,4 +86,13 @@ public final class DeviceManagementConstants { public static final String ACTIVITY = "ACTIVITY_"; } + public static final class PushNotifications { + private PushNotifications() { + throw new AssertionError(); + } + public static final int DEFAULT_SCHEDULER_TASK_INITIAL_DELAY = 60000; + public static final int DEFAULT_BATCH_DELAY_MILLS = 60000; + public static final int DEFAULT_BATCH_SIZE = 1000; + } + } 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 20e4eba5c2..cc9a6256a6 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 @@ -20,6 +20,7 @@ package org.wso2.carbon.device.mgt.core.config; import org.wso2.carbon.device.mgt.core.config.identity.IdentityConfigurations; import org.wso2.carbon.device.mgt.core.config.pagination.PaginationConfiguration; import org.wso2.carbon.device.mgt.core.config.policy.PolicyConfiguration; +import org.wso2.carbon.device.mgt.core.config.push.notification.PushNotificationConfiguration; import org.wso2.carbon.device.mgt.core.config.task.TaskConfiguration; import javax.xml.bind.annotation.XmlElement; @@ -39,7 +40,7 @@ public final class DeviceManagementConfig { private IdentityConfigurations identityConfigurations; private PolicyConfiguration policyConfiguration; private PaginationConfiguration paginationConfiguration; - private List pushNotificationProviders; + private PushNotificationConfiguration pushNotificationConfiguration; @XmlElement(name = "ManagementRepository", required = true) @@ -79,16 +80,6 @@ public final class DeviceManagementConfig { this.taskConfiguration = taskConfiguration; } - @XmlElementWrapper(name = "PushNotificationProviders", required = true) - @XmlElement(name = "Provider", required = true) - public List getPushNotificationProviders() { - return pushNotificationProviders; - } - - public void setPushNotificationProviders(List pushNotificationProviders) { - this.pushNotificationProviders = pushNotificationProviders; - } - @XmlElement(name = "PaginationConfiguration", required = true) public PaginationConfiguration getPaginationConfiguration() { return paginationConfiguration; @@ -98,5 +89,13 @@ public final class DeviceManagementConfig { this.paginationConfiguration = paginationConfiguration; } + @XmlElement(name = "PushNotificationConfiguration", required = true) + public PushNotificationConfiguration getPushNotificationConfiguration() { + return pushNotificationConfiguration; + } + + public void setPushNotificationConfiguration(PushNotificationConfiguration pushNotificationConfiguration) { + this.pushNotificationConfiguration = pushNotificationConfiguration; + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/push/notification/PushNotificationConfiguration.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/push/notification/PushNotificationConfiguration.java new file mode 100644 index 0000000000..58ec787668 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/push/notification/PushNotificationConfiguration.java @@ -0,0 +1,82 @@ +/* +* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +* +* WSO2 Inc. 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.push.notification; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.List; + +/** + * This class is for Push notification related Configurations + */ +@XmlRootElement(name = "PushNotificationConfiguration") +public class PushNotificationConfiguration { + + private int schedulerBatchSize; + private int schedulerBatchDelayMills; + private int schedulerTaskInitialDelay; + private boolean schedulerTaskEnabled; + private List pushNotificationProviders; + + @XmlElement(name = "SchedulerBatchSize", required = true) + public int getSchedulerBatchSize() { + return schedulerBatchSize; + } + + public void setSchedulerBatchSize(int schedulerBatchSize) { + this.schedulerBatchSize = schedulerBatchSize; + } + + @XmlElement(name = "SchedulerBatchDelayMills", required = true) + public int getSchedulerBatchDelayMills() { + return schedulerBatchDelayMills; + } + + public void setSchedulerBatchDelayMills(int schedulerBatchDelayMills) { + this.schedulerBatchDelayMills = schedulerBatchDelayMills; + } + + @XmlElement(name = "SchedulerTaskInitialDelay", required = true) + public int getSchedulerTaskInitialDelay() { + return schedulerTaskInitialDelay; + } + + public void setSchedulerTaskInitialDelay(int schedulerTaskInitialDelay) { + this.schedulerTaskInitialDelay = schedulerTaskInitialDelay; + } + + @XmlElement(name = "SchedulerTaskEnabled", required = true) + public boolean isSchedulerTaskEnabled() { + return schedulerTaskEnabled; + } + + public void setSchedulerTaskEnabled(boolean schedulerTaskEnabled) { + this.schedulerTaskEnabled = schedulerTaskEnabled; + } + + @XmlElementWrapper(name = "PushNotificationProviders", required = true) + @XmlElement(name = "Provider", required = true) + public List getPushNotificationProviders() { + return pushNotificationProviders; + } + + public void setPushNotificationProviders(List pushNotificationProviders) { + this.pushNotificationProviders = pushNotificationProviders; + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dto/operation/mgt/Operation.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dto/operation/mgt/Operation.java index c61b2d304f..3b5322bbf7 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dto/operation/mgt/Operation.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dto/operation/mgt/Operation.java @@ -35,6 +35,10 @@ public class Operation implements Serializable { REPEAT, NO_REPEAT, PAUSE_SEQUENCE, STOP_SEQUENCE } + public enum PushNotificationStatus { + SCHEDULED, COMPLETED + } + private String code; private Properties properties; private Type type; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementServiceComponent.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementServiceComponent.java index 7930aab2b3..0c1a62471d 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementServiceComponent.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/internal/DeviceManagementServiceComponent.java @@ -48,6 +48,7 @@ import org.wso2.carbon.device.mgt.core.operation.mgt.OperationManagerImpl; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOFactory; import org.wso2.carbon.device.mgt.core.permission.mgt.PermissionManagerServiceImpl; import org.wso2.carbon.device.mgt.core.push.notification.mgt.PushNotificationProviderRepository; +import org.wso2.carbon.device.mgt.core.push.notification.mgt.task.PushNotificationSchedulerTask; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderServiceImpl; import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService; @@ -62,6 +63,9 @@ import org.wso2.carbon.utils.ConfigurationContextService; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; /** * @scr.component name="org.wso2.carbon.device.manager" immediate="true" @@ -151,7 +155,8 @@ public class DeviceManagementServiceComponent { this.initOperationsManager(); PushNotificationProviderRepository pushNotificationRepo = new PushNotificationProviderRepository(); - List pushNotificationProviders = config.getPushNotificationProviders(); + List pushNotificationProviders = config.getPushNotificationConfiguration() + .getPushNotificationProviders(); if (pushNotificationProviders != null) { for (String pushNoteProvider : pushNotificationProviders) { pushNotificationRepo.addProvider(pushNoteProvider); @@ -176,6 +181,36 @@ public class DeviceManagementServiceComponent { /* This is a workaround to initialize all Device Management Service Providers after the initialization * of Device Management Service component in order to avoid bundle start up order related complications */ notifyStartupListeners(); + if (log.isDebugEnabled()) { + log.debug("Push notification batch enabled : " + config.getPushNotificationConfiguration() + .isSchedulerTaskEnabled()); + } + // Start Push Notification Scheduler Task + if (config.getPushNotificationConfiguration().isSchedulerTaskEnabled()) { + if (config.getPushNotificationConfiguration().getSchedulerBatchSize() <= 0) { + log.error("Push notification batch size cannot be 0 or less than 0. Setting default batch size " + + "to:" + DeviceManagementConstants.PushNotifications.DEFAULT_BATCH_SIZE); + config.getPushNotificationConfiguration().setSchedulerBatchSize(DeviceManagementConstants + .PushNotifications.DEFAULT_BATCH_SIZE); + } + if (config.getPushNotificationConfiguration().getSchedulerBatchDelayMills() <= 0) { + log.error("Push notification batch delay cannot be 0 or less than 0. Setting default batch delay " + + "milliseconds to" + DeviceManagementConstants.PushNotifications.DEFAULT_BATCH_DELAY_MILLS); + config.getPushNotificationConfiguration().setSchedulerBatchDelayMills(DeviceManagementConstants + .PushNotifications.DEFAULT_BATCH_DELAY_MILLS); + } + if (config.getPushNotificationConfiguration().getSchedulerTaskInitialDelay() < 0) { + log.error("Push notification initial delay cannot be less than 0. Setting default initial " + + "delay milliseconds to" + DeviceManagementConstants.PushNotifications + .DEFAULT_SCHEDULER_TASK_INITIAL_DELAY); + config.getPushNotificationConfiguration().setSchedulerTaskInitialDelay(DeviceManagementConstants + .PushNotifications.DEFAULT_SCHEDULER_TASK_INITIAL_DELAY); + } + ScheduledExecutorService pushNotificationExecutor = Executors.newSingleThreadScheduledExecutor(); + pushNotificationExecutor.scheduleWithFixedDelay(new PushNotificationSchedulerTask(), config + .getPushNotificationConfiguration().getSchedulerTaskInitialDelay(), config + .getPushNotificationConfiguration().getSchedulerBatchDelayMills(), TimeUnit.MILLISECONDS); + } if (log.isDebugEnabled()) { log.debug("Device management core bundle has been successfully initialized"); } @@ -269,7 +304,7 @@ public class DeviceManagementServiceComponent { try { if (log.isDebugEnabled()) { log.debug("Setting Device Management Service Provider: '" + - deviceManagementService.getType() + "'"); + deviceManagementService.getType() + "'"); } synchronized (LOCK) { deviceManagers.add(deviceManagementService); @@ -278,10 +313,10 @@ public class DeviceManagementServiceComponent { } } log.info("Device Type deployed successfully : " + deviceManagementService.getType() + " for tenant " - + deviceManagementService.getProvisioningConfig().getProviderTenantDomain()); + + deviceManagementService.getProvisioningConfig().getProviderTenantDomain()); } catch (Throwable e) { log.error("Failed to register device management service for device type" + deviceManagementService.getType() + - " for tenant " + deviceManagementService.getProvisioningConfig().getProviderTenantDomain(), e); + " for tenant " + deviceManagementService.getProvisioningConfig().getProviderTenantDomain(), e); } } 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 e79d95c5cc..41530bfb48 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 @@ -40,6 +40,7 @@ import org.wso2.carbon.device.mgt.common.push.notification.NotificationContext; import org.wso2.carbon.device.mgt.common.push.notification.NotificationStrategy; import org.wso2.carbon.device.mgt.common.push.notification.PushNotificationExecutionFailedException; import org.wso2.carbon.device.mgt.core.DeviceManagementConstants; +import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager; import org.wso2.carbon.device.mgt.core.dao.DeviceDAO; import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException; import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory; @@ -130,7 +131,7 @@ public class OperationManagerImpl implements OperationManager { DeviceIDHolder deviceAuthorizationResult = this.authorizeDevices(operation, validDeviceIds); List authorizedDeviceList = deviceAuthorizationResult.getValidDeviceIDList(); if (authorizedDeviceList.size() <= 0) { - log.info("User : " + getUser() + " is not authorized to perform operations on given device-list."); + log.warn("User : " + getUser() + " is not authorized to perform operations on given device-list."); Activity activity = new Activity(); //Send the operation statuses only for admin triggered operations String deviceType = validDeviceIds.get(0).getType(); @@ -145,6 +146,16 @@ public class OperationManagerImpl implements OperationManager { int operationId = this.lookupOperationDAO(operation).addOperation(operationDto); boolean isScheduledOperation = this.isTaskScheduledOperation(operation, deviceIds); boolean isNotRepeated = false; + boolean isScheduled = false; + + // check whether device list is greater than batch size notification strategy has enable to send push + // notification using scheduler task + if (DeviceConfigurationManager.getInstance().getDeviceManagementConfig(). + getPushNotificationConfiguration().getSchedulerBatchSize() < authorizedDeviceList.size() && + notificationStrategy != null) { + isScheduled = notificationStrategy.getConfig().isScheduled(); + } + boolean hasExistingTaskOperation; int enrolmentId; if (org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation.Control.NO_REPEAT == operationDto. @@ -161,7 +172,7 @@ public class OperationManagerImpl implements OperationManager { if (isScheduledOperation) { hasExistingTaskOperation = operationDAO.updateTaskOperation(enrolmentId, operationCode); if (!hasExistingTaskOperation) { - operationMappingDAO.addOperationMapping(operationId, enrolmentId); + operationMappingDAO.addOperationMapping(operationId, enrolmentId, isScheduled); } } else if (isNotRepeated) { operationDAO.updateEnrollmentOperationsStatus(enrolmentId, operationCode, @@ -169,17 +180,27 @@ public class OperationManagerImpl implements OperationManager { Operation.Status.PENDING, org.wso2.carbon.device.mgt.core.dto.operation.mgt. Operation.Status.REPEATED); - operationMappingDAO.addOperationMapping(operationId, enrolmentId); + operationMappingDAO.addOperationMapping(operationId, enrolmentId, isScheduled); } else { - operationMappingDAO.addOperationMapping(operationId, enrolmentId); + operationMappingDAO.addOperationMapping(operationId, enrolmentId, isScheduled); } - if (notificationStrategy != null) { + /* + If notification strategy has not enable to send push notification using scheduler task + we will send notification immediately + */ + if (notificationStrategy != null && !isScheduled) { try { + if (log.isDebugEnabled()) { + log.debug("Sending push notification to " + deviceId + " from add operation method."); + } notificationStrategy.execute(new NotificationContext(deviceId, operation)); + operationMappingDAO.updateOperationMapping(operationId, enrolmentId, org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation.PushNotificationStatus.COMPLETED); } catch (PushNotificationExecutionFailedException e) { log.error("Error occurred while sending push notifications to " + deviceId.getType() + " device carrying id '" + deviceId + "'", e); + // Reschedule if push notification failed. + operationMappingDAO.updateOperationMapping(operationId, enrolmentId, org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation.PushNotificationStatus.SCHEDULED); } } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/OperationMapping.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/OperationMapping.java new file mode 100644 index 0000000000..6f42a78d15 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/OperationMapping.java @@ -0,0 +1,73 @@ +/* +* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +* +* WSO2 Inc. 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.mgt; + +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation; + +/** + * Class for represent operation mapping + */ +public class OperationMapping { + + private DeviceIdentifier deviceIdentifier; + private int operationId; + private int tenantId; + private Operation.Status status; + private Operation.PushNotificationStatus pushNotificationStatus; + + public int getOperationId() { + return operationId; + } + + public void setOperationId(int operationId) { + this.operationId = operationId; + } + + public int getTenantId() { + return tenantId; + } + + public void setTenantId(int tenantId) { + this.tenantId = tenantId; + } + + public DeviceIdentifier getDeviceIdentifier() { + return deviceIdentifier; + } + + public void setDeviceIdentifier(DeviceIdentifier deviceIdentifier) { + this.deviceIdentifier = deviceIdentifier; + } + + public Operation.Status getStatus() { + return status; + } + + public void setStatus(Operation.Status status) { + this.status = status; + } + + public Operation.PushNotificationStatus getPushNotificationStatus() { + return pushNotificationStatus; + } + + public void setPushNotificationStatus(Operation.PushNotificationStatus pushNotificationStatus) { + this.pushNotificationStatus = pushNotificationStatus; + } +} 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 d8c6b78987..5e3848cf9b 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 @@ -20,10 +20,12 @@ package org.wso2.carbon.device.mgt.core.operation.mgt.dao; import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.operation.mgt.Activity; +import org.wso2.carbon.device.mgt.core.operation.mgt.OperationMapping; import org.wso2.carbon.device.mgt.common.operation.mgt.OperationResponse; import org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation; import java.util.List; +import java.util.Map; public interface OperationDAO { @@ -80,4 +82,15 @@ public interface OperationDAO { boolean resetAttemptCount(int enrolmentId) throws OperationManagementDAOException; + /** + * This method provides operation mappings for given status + * @param opStatus Operation status + * @param pushNotificationStatus Push notification Status + * @param limit Limit for no devices + * @return Tenant based operation mappings list + * @throws OperationManagementDAOException + */ + Map> getOperationMappingsByStatus(Operation.Status opStatus, Operation.PushNotificationStatus pushNotificationStatus, + int limit) throws OperationManagementDAOException; + } \ 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/mgt/dao/OperationMappingDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/OperationMappingDAO.java index d132794100..72d02ec9bc 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/OperationMappingDAO.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/OperationMappingDAO.java @@ -18,10 +18,20 @@ */ package org.wso2.carbon.device.mgt.core.operation.mgt.dao; +import org.wso2.carbon.device.mgt.core.operation.mgt.OperationMapping; +import org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation; + +import java.util.List; + public interface OperationMappingDAO { - void addOperationMapping(int operationId, Integer deviceIds) throws OperationManagementDAOException; + void addOperationMapping(int operationId, Integer deviceId, boolean isScheduled) throws OperationManagementDAOException; + + void removeOperationMapping(int operationId, Integer deviceId) throws OperationManagementDAOException; - void removeOperationMapping(int operationId, Integer deviceIds) throws OperationManagementDAOException; + void updateOperationMapping(int operationId, Integer deviceId, Operation.PushNotificationStatus pushNotificationStatus) throws + OperationManagementDAOException; + void updateOperationMapping(List operationMappingList) 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 c70a2a87aa..3e50f49800 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 @@ -26,18 +26,30 @@ 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.OperationResponse; import org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.core.operation.mgt.OperationMapping; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationDAO; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOException; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOFactory; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOUtil; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.util.OperationDAOUtil; -import java.io.*; -import java.sql.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; +import java.util.Map; /** * This class holds the generic implementation of OperationDAO which can be used to support ANSI db syntax. @@ -162,8 +174,8 @@ public class GenericOperationDAOImpl implements OperationDAO { try { Connection connection = OperationManagementDAOFactory.getConnection(); String query = "SELECT EOM.ID FROM DM_ENROLMENT_OP_MAPPING AS EOM INNER JOIN DM_OPERATION DM " + - "ON DM.ID = EOM.OPERATION_ID WHERE EOM.ENROLMENT_ID = ? AND DM.OPERATION_CODE = ? AND " + - "EOM.STATUS = ?;"; + "ON DM.ID = EOM.OPERATION_ID WHERE EOM.ENROLMENT_ID = ? AND DM.OPERATION_CODE = ? AND " + + "EOM.STATUS = ?;"; stmt = connection.prepareStatement(query); stmt.setInt(1, enrolmentId); stmt.setString(2, operationCode); @@ -176,7 +188,7 @@ public class GenericOperationDAOImpl implements OperationDAO { } if (id != 0) { stmt = connection.prepareStatement("UPDATE DM_ENROLMENT_OP_MAPPING SET UPDATED_TIMESTAMP = ? " + - "WHERE ID = ?"); + "WHERE ID = ?"); stmt.setLong(1, System.currentTimeMillis() / 1000); stmt.setInt(2, id); stmt.executeUpdate(); @@ -184,7 +196,7 @@ public class GenericOperationDAOImpl implements OperationDAO { } } catch (SQLException e) { throw new OperationManagementDAOException("Error occurred while update device mapping operation status " + - "metadata", e); + "metadata", e); } finally { OperationManagementDAOUtil.cleanupResources(stmt); } @@ -420,14 +432,13 @@ public class GenericOperationDAOImpl implements OperationDAO { "WHERE opm.UPDATED_TIMESTAMP > ? \n" + "AND de.TENANT_ID = ? \n"; - if(timestamp == 0){ + if (timestamp == 0) { sql += "ORDER BY opm.OPERATION_ID LIMIT ? OFFSET ?;"; - }else{ + } else { sql += "ORDER BY opm.UPDATED_TIMESTAMP asc LIMIT ? OFFSET ?"; } - stmt = conn.prepareStatement(sql); stmt.setLong(1, timestamp); @@ -1068,7 +1079,7 @@ public class GenericOperationDAOImpl implements OperationDAO { try { conn = OperationManagementDAOFactory.getConnection(); String query = "UPDATE DM_POLICY_COMPLIANCE_STATUS SET ATTEMPTS = 0, LAST_REQUESTED_TIME = ? " + - "WHERE ENROLMENT_ID = ? AND TENANT_ID = ?"; + "WHERE ENROLMENT_ID = ? AND TENANT_ID = ?"; stmt = conn.prepareStatement(query); stmt.setTimestamp(1, currentTimestamp); stmt.setInt(2, enrolmentId); @@ -1082,4 +1093,45 @@ public class GenericOperationDAOImpl implements OperationDAO { } return status; } + + @Override + public Map> getOperationMappingsByStatus(Operation.Status opStatus, Operation.PushNotificationStatus pushNotificationStatus, + int limit) throws OperationManagementDAOException { + PreparedStatement stmt = null; + ResultSet rs = null; + Connection conn; + OperationMapping operationMapping; + Map> operationMappingsTenantMap = new HashMap<>(); + try { + conn = OperationManagementDAOFactory.getConnection(); + String sql = "SELECT op.ENROLMENT_ID, op.OPERATION_ID, dt.NAME ,d.TENANT_ID FROM DM_DEVICE d, " + + "DM_ENROLMENT_OP_MAPPING op, DM_DEVICE_TYPE dt WHERE op.STATUS = ? AND " + + "op.PUSH_NOTIFICATION_STATUS = ? AND d.DEVICE_TYPE_ID = dt.ID AND d.ID=op.ENROLMENT_ID ORDER BY " + + "op.OPERATION_ID LIMIT ?"; + stmt = conn.prepareStatement(sql); + stmt.setString(1, opStatus.toString()); + stmt.setString(2, pushNotificationStatus.toString()); + stmt.setInt(3, limit); + rs = stmt.executeQuery(); + while (rs.next()) { + int tenantID = rs.getInt("TENANT_ID"); + List operationMappings = operationMappingsTenantMap.get(tenantID); + if (operationMappings == null) { + operationMappings = new LinkedList<>(); + operationMappingsTenantMap.put(tenantID, operationMappings); + } + operationMapping = new OperationMapping(); + operationMapping.setOperationId(rs.getInt("OPERATION_ID")); + operationMapping.setDeviceIdentifier(new DeviceIdentifier(String.valueOf(rs.getInt("ENROLMENT_ID")), + rs.getString("NAME"))); + operationMapping.setTenantId(tenantID); + operationMappings.add(operationMapping); + } + } catch (SQLException e) { + throw new OperationManagementDAOException("SQL error while getting operation mappings from database. ", e); + } finally { + OperationManagementDAOUtil.cleanupResources(stmt, rs); + } + return operationMappingsTenantMap; + } } 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/OperationMappingDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/impl/OperationMappingDAOImpl.java index 17492d4026..0846813fdf 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/impl/OperationMappingDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/impl/OperationMappingDAOImpl.java @@ -19,6 +19,7 @@ package org.wso2.carbon.device.mgt.core.operation.mgt.dao.impl; import org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.core.operation.mgt.OperationMapping; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOException; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOFactory; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOUtil; @@ -27,23 +28,30 @@ import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationMappingDAO; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.util.List; public class OperationMappingDAOImpl implements OperationMappingDAO { @Override - public void addOperationMapping(int operationId, Integer deviceId) throws OperationManagementDAOException { + public void addOperationMapping(int operationId, Integer deviceId, boolean isScheduled) throws + OperationManagementDAOException { PreparedStatement stmt = null; try { - long time = System.currentTimeMillis()/1000; + long time = System.currentTimeMillis() / 1000; Connection conn = OperationManagementDAOFactory.getConnection(); - String sql = "INSERT INTO DM_ENROLMENT_OP_MAPPING(ENROLMENT_ID, OPERATION_ID, STATUS, CREATED_TIMESTAMP, " + - "UPDATED_TIMESTAMP) VALUES (?, ?, ?, ?, ?)"; + String sql = "INSERT INTO DM_ENROLMENT_OP_MAPPING(ENROLMENT_ID, OPERATION_ID, STATUS, " + + "PUSH_NOTIFICATION_STATUS, CREATED_TIMESTAMP, UPDATED_TIMESTAMP) VALUES (?, ?, ?, ?, ?, ?)"; stmt = conn.prepareStatement(sql); stmt.setInt(1, deviceId); stmt.setInt(2, operationId); stmt.setString(3, Operation.Status.PENDING.toString()); - stmt.setLong(4, time); + if (isScheduled) { + stmt.setString(4, Operation.PushNotificationStatus.SCHEDULED.toString()); + } else { + stmt.setString(4, Operation.PushNotificationStatus.COMPLETED.toString()); + } stmt.setLong(5, time); + stmt.setLong(6, time); stmt.executeUpdate(); } catch (SQLException e) { throw new OperationManagementDAOException("Error occurred while persisting device operation mappings", e); @@ -54,13 +62,13 @@ public class OperationMappingDAOImpl implements OperationMappingDAO { @Override public void removeOperationMapping(int operationId, - Integer deviceIds) throws OperationManagementDAOException { + Integer deviceId) throws OperationManagementDAOException { PreparedStatement stmt = null; try { Connection conn = OperationManagementDAOFactory.getConnection(); String sql = "DELETE FROM DM_ENROLMENT_OP_MAPPING WHERE ENROLMENT_ID = ? AND OPERATION_ID = ?"; stmt = conn.prepareStatement(sql); - stmt.setInt(1, 0); + stmt.setInt(1, deviceId); stmt.setInt(2, operationId); stmt.executeUpdate(); } catch (SQLException e) { @@ -70,4 +78,55 @@ public class OperationMappingDAOImpl implements OperationMappingDAO { } } + @Override + public void updateOperationMapping(int operationId, Integer deviceId, Operation.PushNotificationStatus pushNotificationStatus) throws OperationManagementDAOException { + PreparedStatement stmt = null; + try { + Connection conn = OperationManagementDAOFactory.getConnection(); + String sql = "UPDATE DM_ENROLMENT_OP_MAPPING SET PUSH_NOTIFICATION_STATUS = ? WHERE ENROLMENT_ID = ? and " + + "OPERATION_ID = ?"; + stmt = conn.prepareStatement(sql); + stmt.setString(1, pushNotificationStatus.toString()); + stmt.setInt(2, deviceId); + stmt.setInt(3, operationId); + stmt.executeUpdate(); + } catch (SQLException e) { + throw new OperationManagementDAOException("Error occurred while updating device operation mappings", e); + } finally { + OperationManagementDAOUtil.cleanupResources(stmt, null); + } + } + + @Override + public void updateOperationMapping(List operationMappingList) throws + OperationManagementDAOException { + PreparedStatement stmt = null; + try { + Connection conn = OperationManagementDAOFactory.getConnection(); + String sql = "UPDATE DM_ENROLMENT_OP_MAPPING SET PUSH_NOTIFICATION_STATUS = ? WHERE ENROLMENT_ID = ? and " + + "OPERATION_ID = ?"; + stmt = conn.prepareStatement(sql); + if (conn.getMetaData().supportsBatchUpdates()) { + for (OperationMapping operationMapping : operationMappingList) { + stmt.setString(1, operationMapping.getPushNotificationStatus().toString()); + stmt.setInt(2, Integer.parseInt(operationMapping.getDeviceIdentifier().getId())); + stmt.setInt(3, operationMapping.getOperationId()); + stmt.addBatch(); + } + stmt.executeBatch(); + } else { + for (OperationMapping operationMapping : operationMappingList) { + stmt.setString(1, operationMapping.getPushNotificationStatus().toString()); + stmt.setInt(2, Integer.parseInt(operationMapping.getDeviceIdentifier().getId())); + stmt.setInt(3, operationMapping.getOperationId()); + stmt.executeUpdate(); + } + } + } catch (SQLException e) { + throw new OperationManagementDAOException("Error occurred while updating device operation mappings as " + + "batch ", e); + } finally { + OperationManagementDAOUtil.cleanupResources(stmt, null); + } + } } 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/operation/OracleOperationDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/impl/operation/OracleOperationDAOImpl.java index 2591a267ba..321a13e46c 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/impl/operation/OracleOperationDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/impl/operation/OracleOperationDAOImpl.java @@ -25,6 +25,7 @@ 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.OperationResponse; import org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.core.operation.mgt.OperationMapping; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOException; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOFactory; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOUtil; @@ -37,7 +38,10 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; +import java.util.Map; /** * This class holds the implementation of OperationDAO which can be used to support Oracle db syntax. @@ -135,7 +139,7 @@ public class OracleOperationDAOImpl extends GenericOperationDAOImpl { @Override public void updateEnrollmentOperationsStatus(int enrolmentId, String operationCode, - Operation.Status existingStatus, Operation.Status newStatus) throws OperationManagementDAOException { + Operation.Status existingStatus, Operation.Status newStatus) throws OperationManagementDAOException { PreparedStatement stmt = null; ResultSet rs = null; try { @@ -361,4 +365,46 @@ public class OracleOperationDAOImpl extends GenericOperationDAOImpl { } return 0; } + + + @Override + public Map> getOperationMappingsByStatus(Operation.Status opStatus, Operation.PushNotificationStatus pushNotificationStatus, + int limit) throws OperationManagementDAOException { + PreparedStatement stmt = null; + ResultSet rs = null; + OperationMapping operationMapping; + Map> operationMappingsTenantMap = new HashMap<>(); + try { + Connection conn = OperationManagementDAOFactory.getConnection(); + String sql = "SELECT op.ENROLMENT_ID, op.OPERATION_ID, dt.NAME ,d.TENANT_ID FROM DM_DEVICE d, " + + "DM_ENROLMENT_OP_MAPPING op, DM_DEVICE_TYPE dt WHERE op.STATUS = ? AND op" + + ".PUSH_NOTIFICATION_STATUS = ? AND d.DEVICE_TYPE_ID = dt.ID AND d.ID=op.ENROLMENT_ID AND ROWNUM" + + " <= ? ORDER BY op.OPERATION_ID"; + + stmt = conn.prepareStatement(sql); + stmt.setString(1, opStatus.toString()); + stmt.setString(2, pushNotificationStatus.toString()); + stmt.setInt(3, limit); + rs = stmt.executeQuery(); + while (rs.next()) { + int tenantID = rs.getInt("TENANT_ID"); + List operationMappings = operationMappingsTenantMap.get(tenantID); + if (operationMappings == null) { + operationMappings = new LinkedList<>(); + operationMappingsTenantMap.put(tenantID, operationMappings); + } + operationMapping = new OperationMapping(); + operationMapping.setOperationId(rs.getInt("OPERATION_ID")); + operationMapping.setDeviceIdentifier(new DeviceIdentifier(String.valueOf(rs.getInt("ENROLMENT_ID")), + rs.getString("NAME"))); + operationMapping.setTenantId(tenantID); + operationMappings.add(operationMapping); + } + } catch (SQLException e) { + throw new OperationManagementDAOException("SQL error while getting operation mappings from database. ", e); + } finally { + OperationManagementDAOUtil.cleanupResources(stmt, rs); + } + return operationMappingsTenantMap; + } } \ 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/mgt/dao/impl/operation/SQLServerOperationDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/impl/operation/SQLServerOperationDAOImpl.java index b98ca93f7b..d19a5b151b 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/impl/operation/SQLServerOperationDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/operation/mgt/dao/impl/operation/SQLServerOperationDAOImpl.java @@ -25,6 +25,7 @@ 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.OperationResponse; import org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.core.operation.mgt.OperationMapping; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOException; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOFactory; import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOUtil; @@ -37,7 +38,10 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; +import java.util.Map; /** * This class holds the implementation of OperationDAO which can be used to support SQLServer db syntax. @@ -264,4 +268,43 @@ public class SQLServerOperationDAOImpl extends GenericOperationDAOImpl { return activities; } + @Override + public Map> getOperationMappingsByStatus(Operation.Status opStatus, Operation.PushNotificationStatus pushNotificationStatus, + int limit) throws OperationManagementDAOException { + PreparedStatement stmt = null; + ResultSet rs = null; + OperationMapping operationMapping; + Map> operationMappingsTenantMap = new HashMap<>(); + try { + Connection conn = OperationManagementDAOFactory.getConnection(); + String sql = "SELECT op.ENROLMENT_ID, op.OPERATION_ID, dt.NAME ,d.TENANT_ID FROM DM_DEVICE d, " + + "DM_ENROLMENT_OP_MAPPING op, DM_DEVICE_TYPE dt WHERE op.STATUS = ? AND op" + + ".PUSH_NOTIFICATION_STATUS = ? AND d.DEVICE_TYPE_ID = dt.ID " + + "AND d.ID=op.ENROLMENT_ID ORDER BY op.OPERATION_ID OFFSET ? ROWS FETCH NEXT ? ROWS ONLY"; + stmt = conn.prepareStatement(sql); + stmt.setString(1, opStatus.toString()); + stmt.setString(2, pushNotificationStatus.toString()); + stmt.setInt(3, limit); + rs = stmt.executeQuery(); + while (rs.next()) { + int tenantID = rs.getInt("TENANT_ID"); + List operationMappings = operationMappingsTenantMap.get(tenantID); + if (operationMappings == null) { + operationMappings = new LinkedList<>(); + operationMappingsTenantMap.put(tenantID, operationMappings); + } + operationMapping = new OperationMapping(); + operationMapping.setOperationId(rs.getInt("OPERATION_ID")); + operationMapping.setDeviceIdentifier(new DeviceIdentifier(String.valueOf(rs.getInt("ENROLMENT_ID")), + rs.getString("NAME"))); + operationMapping.setTenantId(tenantID); + operationMappings.add(operationMapping); + } + } catch (SQLException e) { + throw new OperationManagementDAOException("SQL error while getting operation mappings from database. ", e); + } finally { + OperationManagementDAOUtil.cleanupResources(stmt, rs); + } + return operationMappingsTenantMap; + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/push/notification/mgt/task/PushNotificationSchedulerTask.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/push/notification/mgt/task/PushNotificationSchedulerTask.java new file mode 100644 index 0000000000..3ac4126f30 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/push/notification/mgt/task/PushNotificationSchedulerTask.java @@ -0,0 +1,127 @@ +/* +* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +* +* WSO2 Inc. 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.push.notification.mgt.task; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.context.PrivilegedCarbonContext; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.TransactionManagementException; +import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; +import org.wso2.carbon.device.mgt.common.push.notification.NotificationContext; +import org.wso2.carbon.device.mgt.common.push.notification.NotificationStrategy; +import org.wso2.carbon.device.mgt.common.push.notification.PushNotificationExecutionFailedException; +import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager; +import org.wso2.carbon.device.mgt.core.dto.operation.mgt.Operation; +import org.wso2.carbon.device.mgt.core.internal.DeviceManagementDataHolder; +import org.wso2.carbon.device.mgt.core.operation.mgt.OperationMapping; +import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationDAO; +import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOException; +import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationManagementDAOFactory; +import org.wso2.carbon.device.mgt.core.operation.mgt.dao.OperationMappingDAO; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * ${{@link PushNotificationSchedulerTask}} is for sending push notifications for given device batch. + */ +public class PushNotificationSchedulerTask implements Runnable { + + private static Log log = LogFactory.getLog(PushNotificationSchedulerTask.class); + private final OperationDAO operationDAO = OperationManagementDAOFactory.getOperationDAO(); + private final OperationMappingDAO operationMappingDAO = OperationManagementDAOFactory.getOperationMappingDAO(); + private final DeviceManagementProviderService provider = DeviceManagementDataHolder.getInstance() + .getDeviceManagementProvider(); + + @Override + public void run() { + try { + Map> operationMappingsTenantMap = new HashMap<>(); + List operationsCompletedList = new LinkedList<>(); + if (log.isDebugEnabled()) { + log.debug("Push notification job started"); + } + try { + //Get next available operation list per device batch + OperationManagementDAOFactory.openConnection(); + operationMappingsTenantMap = operationDAO.getOperationMappingsByStatus(Operation.Status + .PENDING, Operation.PushNotificationStatus.SCHEDULED, DeviceConfigurationManager.getInstance() + .getDeviceManagementConfig().getPushNotificationConfiguration().getSchedulerBatchSize()); + } catch (OperationManagementDAOException e) { + log.error("Unable to retrieve scheduled pending operations for task.", e); + } finally { + OperationManagementDAOFactory.closeConnection(); + } + // Sending push notification to each device + for (List operationMappings : operationMappingsTenantMap.values()) { + for (OperationMapping operationMapping : operationMappings) { + try { + if (log.isDebugEnabled()) { + log.debug("Sending push notification for operationId :" + operationMapping.getOperationId() + + "to deviceId : " + operationMapping.getDeviceIdentifier().getId()); + } + // Set tenant id and domain + PrivilegedCarbonContext.startTenantFlow(); + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(operationMapping.getTenantId(), true); + // Get notification strategy for given device type + NotificationStrategy notificationStrategy = provider.getNotificationStrategyByDeviceType + (operationMapping.getDeviceIdentifier().getType()); + // Send the push notification on given strategy + notificationStrategy.execute(new NotificationContext(operationMapping.getDeviceIdentifier(), + provider.getOperation(operationMapping.getDeviceIdentifier().getType(), operationMapping + .getOperationId()))); + operationMapping.setPushNotificationStatus(Operation.PushNotificationStatus.COMPLETED); + operationsCompletedList.add(operationMapping); + } catch (DeviceManagementException e) { + log.error("Error occurred while getting notification strategy for operation mapping " + + operationMapping.getDeviceIdentifier().getType(), e); + } catch (OperationManagementException e) { + log.error("Unable to get the operation for operation " + operationMapping.getOperationId(), e); + } catch (PushNotificationExecutionFailedException e) { + log.error("Error occurred while sending push notification to operation: " + operationMapping + .getOperationId(), e); + } finally { + PrivilegedCarbonContext.endTenantFlow(); + } + } + } + // Update push notification status to competed for operations which already sent + if (operationsCompletedList.size() > 0) { + try { + OperationManagementDAOFactory.beginTransaction(); + operationMappingDAO.updateOperationMapping(operationsCompletedList); + OperationManagementDAOFactory.commitTransaction(); + } catch (TransactionManagementException | OperationManagementDAOException e) { + OperationManagementDAOFactory.rollbackTransaction(); + log.error("Error occurred while updating operation mappings for sent notifications ", e); + } finally { + OperationManagementDAOFactory.closeConnection(); + } + } + if (log.isDebugEnabled()) { + log.debug("Push notification job running completed."); + } + } catch (Throwable cause) { + log.error("PushNotificationSchedulerTask failed due to " + cause); + } + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java index a48cb423c8..9117468541 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java @@ -32,6 +32,7 @@ import org.wso2.carbon.device.mgt.common.operation.mgt.Activity; import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; import org.wso2.carbon.device.mgt.common.policy.mgt.PolicyMonitoringManager; +import org.wso2.carbon.device.mgt.common.push.notification.NotificationStrategy; import java.util.Date; import java.util.HashMap; @@ -130,7 +131,8 @@ public interface DeviceManagementProviderService { /** * This method returns the list of device owned by a user of given device type. - * @param userName user name. + * + * @param userName user name. * @param deviceType device type name * @return * @throws DeviceManagementException @@ -210,13 +212,21 @@ public interface DeviceManagementProviderService { * This method is used to check whether the device is enrolled with the give user. * * @param deviceId identifier of the device that needs to be checked against the user. - * @param user username of the device owner. - * + * @param user username of the device owner. * @return true if the user owns the device else will return false. * @throws DeviceManagementException If some unusual behaviour is observed while fetching the device. */ boolean isEnrolled(DeviceIdentifier deviceId, String user) throws DeviceManagementException; + /** + * This method is used to get notification strategy for given device type + * + * @param deviceType Device type + * @return Notification Strategy for device type + * @throws DeviceManagementException + */ + NotificationStrategy getNotificationStrategyByDeviceType(String deviceType) throws DeviceManagementException; + License getLicense(String deviceType, String languageCode) throws DeviceManagementException; void addLicense(String deviceType, License license) throws DeviceManagementException; @@ -239,6 +249,7 @@ public interface DeviceManagementProviderService { /** * Returns the device of specified id. + * * @param deviceId device Id * @return Device returns null when device is not avaialble. * @throws DeviceManagementException diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java index f89fe627c3..6672311c3d 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 @@ -23,7 +23,21 @@ import org.apache.commons.logging.LogFactory; import org.wso2.carbon.CarbonConstants; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext; -import org.wso2.carbon.device.mgt.common.*; +import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.DeviceManagementException; +import org.wso2.carbon.device.mgt.common.DeviceManager; +import org.wso2.carbon.device.mgt.common.DeviceNotFoundException; +import org.wso2.carbon.device.mgt.common.DeviceTypeIdentifier; +import org.wso2.carbon.device.mgt.common.EnrolmentInfo; +import org.wso2.carbon.device.mgt.common.FeatureManager; +import org.wso2.carbon.device.mgt.common.InitialOperationConfig; +import org.wso2.carbon.device.mgt.common.InvalidDeviceException; +import org.wso2.carbon.device.mgt.common.MonitoringOperation; +import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig; +import org.wso2.carbon.device.mgt.common.PaginationRequest; +import org.wso2.carbon.device.mgt.common.PaginationResult; +import org.wso2.carbon.device.mgt.common.TransactionManagementException; import org.wso2.carbon.device.mgt.common.app.mgt.Application; import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration; import org.wso2.carbon.device.mgt.common.device.details.DeviceInfo; @@ -37,7 +51,9 @@ import org.wso2.carbon.device.mgt.common.license.mgt.LicenseManagementException; import org.wso2.carbon.device.mgt.common.operation.mgt.Activity; import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; +import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManager; import org.wso2.carbon.device.mgt.common.policy.mgt.PolicyMonitoringManager; +import org.wso2.carbon.device.mgt.common.push.notification.NotificationStrategy; import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService; import org.wso2.carbon.device.mgt.core.DeviceManagementConstants; import org.wso2.carbon.device.mgt.core.DeviceManagementPluginRepository; @@ -307,7 +323,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv return enrolmentInfos; } - @Override + @Override public boolean disenrollDevice(DeviceIdentifier deviceId) throws DeviceManagementException { DeviceManager deviceManager = this.getDeviceManager(deviceId.getType()); if (deviceManager == null) { @@ -649,7 +665,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv device.setDeviceInfo(info); } catch (DeviceDetailsMgtDAOException e) { log.error("Error occurred while retrieving advance info of '" + device.getType() + - "' that carries the id '" + device.getDeviceIdentifier() + "'"); + "' that carries the id '" + device.getDeviceIdentifier() + "'"); } catch (SQLException e) { log.error("Error occurred while opening a connection to the data source", e); } finally { @@ -663,7 +679,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv device.setApplications(applications); } catch (DeviceManagementDAOException e) { log.error("Error occurred while retrieving the application list of '" + device.getType() + "', " + - "which carries the id '" + device.getId() + "'", e); + "which carries the id '" + device.getId() + "'", e); } catch (SQLException e) { log.error("Error occurred while opening a connection to the data source", e); } finally { @@ -674,7 +690,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv if (deviceManager == null) { if (log.isDebugEnabled()) { log.debug("Device Manager associated with the device type '" + device.getType() + "' is null. " + - "Therefore, not attempting method 'isEnrolled'"); + "Therefore, not attempting method 'isEnrolled'"); } devices.add(device); continue; @@ -689,6 +705,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } return devices; } + @Override public List getAllDevices(String deviceType) throws DeviceManagementException { List devices = new ArrayList<>(); @@ -779,7 +796,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv try { EmailContext ctx = new EmailContext.EmailContextBuilder(new ContentProviderInfo(templateName, params), - metaInfo.getRecipients()).build(); + metaInfo.getRecipients()).build(); DeviceManagementDataHolder.getInstance().getEmailSenderService().sendEmail(ctx); } catch (EmailSendingFailedException ex) { throw new DeviceManagementException("Error occurred while sending enrollment invitation", ex); @@ -1958,6 +1975,17 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv return false; } + @Override + public NotificationStrategy getNotificationStrategyByDeviceType(String deviceType) throws DeviceManagementException { + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); + OperationManager operationManager = pluginRepository.getOperationManager(deviceType, tenantId); + if (operationManager != null) { + return operationManager.getNotificationStrategy(); + } else { + throw new DeviceManagementException("Cannot find operation manager for given device type :" + deviceType); + } + } + /** * Change device status. * @@ -2007,7 +2035,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv throw new DeviceManagementException("Error occurred while opening a connection to the data source", e); } catch (DeviceManagementDAOException e) { throw new DeviceManagementException("Error occurred while updating the enrollment information device for" + - "id '" + deviceId + "' ." , e); + "id '" + deviceId + "' .", e); } finally { try { DeviceManagementDAOFactory.getConnection().setAutoCommit(isAutoCommit); @@ -2085,7 +2113,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv List deviceIdentifiers = new ArrayList<>(); deviceIdentifiers.add(deviceIdentifier); if (init != null) { - List initialOperations = init.getOperations(); + List initialOperations = init.getOperations(); for (String str : initialOperations) { CommandOperation operation = new CommandOperation(); diff --git a/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/enforcement/DelegationTask.java b/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/enforcement/DelegationTask.java index dea10f5fac..adccce9723 100644 --- a/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/enforcement/DelegationTask.java +++ b/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/enforcement/DelegationTask.java @@ -29,6 +29,7 @@ import org.wso2.carbon.policy.mgt.common.PolicyManagementException; import org.wso2.carbon.policy.mgt.core.cache.impl.PolicyCacheManagerImpl; import org.wso2.carbon.policy.mgt.core.internal.PolicyManagementDataHolder; import org.wso2.carbon.policy.mgt.core.mgt.PolicyManager; +import org.wso2.carbon.policy.mgt.core.mgt.bean.UpdatedPolicyDeviceListBean; import org.wso2.carbon.policy.mgt.core.mgt.impl.PolicyManagerImpl; import java.util.ArrayList; @@ -54,7 +55,8 @@ public class DelegationTask implements Task { try { PolicyManager policyManager = new PolicyManagerImpl(); - List deviceTypes = policyManager.applyChangesMadeToPolicies(); + UpdatedPolicyDeviceListBean updatedPolicyDeviceList = policyManager.applyChangesMadeToPolicies(); + List deviceTypes = updatedPolicyDeviceList.getChangedDeviceTypes(); PolicyCacheManagerImpl.getInstance().rePopulateCache(); @@ -78,7 +80,8 @@ public class DelegationTask implements Task { // } } if (!toBeNotified.isEmpty()) { - PolicyEnforcementDelegator enforcementDelegator = new PolicyEnforcementDelegatorImpl(toBeNotified); + PolicyEnforcementDelegator enforcementDelegator = new PolicyEnforcementDelegatorImpl + (toBeNotified, updatedPolicyDeviceList.getUpdatedPolicyIds()); enforcementDelegator.delegate(); } } catch (DeviceManagementException e) { diff --git a/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/enforcement/PolicyEnforcementDelegatorImpl.java b/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/enforcement/PolicyEnforcementDelegatorImpl.java index 9a3bcfa894..fa02314460 100644 --- a/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/enforcement/PolicyEnforcementDelegatorImpl.java +++ b/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/enforcement/PolicyEnforcementDelegatorImpl.java @@ -44,8 +44,9 @@ public class PolicyEnforcementDelegatorImpl implements PolicyEnforcementDelegato private static final Log log = LogFactory.getLog(PolicyEnforcementDelegatorImpl.class); private List devices; + private List updatedPolicyIds; - public PolicyEnforcementDelegatorImpl(List devices) { + public PolicyEnforcementDelegatorImpl(List devices, List updatedPolicyIds) { log.info("Policy re-enforcing stared due to change of the policies."); @@ -56,6 +57,7 @@ public class PolicyEnforcementDelegatorImpl implements PolicyEnforcementDelegato } } this.devices = devices; + this.updatedPolicyIds = updatedPolicyIds; } @@ -66,12 +68,22 @@ public class PolicyEnforcementDelegatorImpl implements PolicyEnforcementDelegato identifier.setId(device.getDeviceIdentifier()); identifier.setType(device.getType()); + Policy devicePolicy = this.getAppliedPolicyToDevice(identifier); Policy policy = this.getEffectivePolicy(identifier); List deviceIdentifiers = new ArrayList<>(); deviceIdentifiers.add(identifier); if (policy != null) { - this.addPolicyRevokeOperation(deviceIdentifiers); - this.addPolicyOperation(deviceIdentifiers, policy); + /* + We add policy operation for the device if, + 1) Device does not have any policy or + 2) New Policy or + 3) Device existing policy has changed + */ + if (devicePolicy == null || devicePolicy.getId() != policy.getId() || updatedPolicyIds.contains + (policy.getId())) { + this.addPolicyRevokeOperation(deviceIdentifiers); + this.addPolicyOperation(deviceIdentifiers, policy); + } } else { //This means all the applicable policies have been removed from device. Hence calling a policy revoke. this.addPolicyRevokeOperation(deviceIdentifiers); @@ -154,4 +166,22 @@ public class PolicyEnforcementDelegatorImpl implements PolicyEnforcementDelegato policyRevokeOperation.setType(Operation.Type.COMMAND); return policyRevokeOperation; } + + /** + * Provides the applied policy for give device + * + * @param identifier Device Identifier + * @return Applied Policy + * @throws PolicyDelegationException exception throws when retrieving applied policy for given device + */ + public Policy getAppliedPolicyToDevice(DeviceIdentifier identifier) throws PolicyDelegationException { + try { + PolicyManagerService policyManagerService = new PolicyManagerServiceImpl(); + return policyManagerService.getAppliedPolicyToDevice(identifier); + } catch (PolicyManagementException e) { + String msg = "Error occurred while retrieving the applied policy for devices."; + log.error(msg, e); + throw new PolicyDelegationException(msg, e); + } + } } diff --git a/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/mgt/PolicyManager.java b/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/mgt/PolicyManager.java index 8f18a89ffd..68c57b5049 100644 --- a/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/mgt/PolicyManager.java +++ b/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/mgt/PolicyManager.java @@ -21,6 +21,7 @@ import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.mgt.common.policy.mgt.Policy; import org.wso2.carbon.policy.mgt.common.PolicyManagementException; +import org.wso2.carbon.policy.mgt.core.mgt.bean.UpdatedPolicyDeviceListBean; import java.util.HashMap; import java.util.List; @@ -67,7 +68,7 @@ public interface PolicyManager { void addAppliedPolicyFeaturesToDevice(DeviceIdentifier deviceIdentifier, Policy policy) throws PolicyManagementException; - List applyChangesMadeToPolicies() throws PolicyManagementException; + UpdatedPolicyDeviceListBean applyChangesMadeToPolicies() throws PolicyManagementException; void addAppliedPolicyToDevice(DeviceIdentifier deviceIdentifier, Policy policy) throws PolicyManagementException; diff --git a/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/mgt/bean/UpdatedPolicyDeviceListBean.java b/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/mgt/bean/UpdatedPolicyDeviceListBean.java new file mode 100644 index 0000000000..2071d1ff5b --- /dev/null +++ b/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/mgt/bean/UpdatedPolicyDeviceListBean.java @@ -0,0 +1,65 @@ +/* +* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +* +* WSO2 Inc. 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.policy.mgt.core.mgt.bean; + +import org.wso2.carbon.device.mgt.common.policy.mgt.Policy; +import org.wso2.carbon.device.mgt.core.dto.DeviceType; + + +import java.util.List; + +/** + * This class stores list of updated policies and list of changed devices for Policy Manager + */ +public class UpdatedPolicyDeviceListBean { + + private List updatedPolicies; + private List updatedPolicyIds; + private List changedDeviceTypes; + + public UpdatedPolicyDeviceListBean(List updatedPolicies, List updatedPolicyIds, List + deviceTypes) { + this.updatedPolicies = updatedPolicies; + this.updatedPolicyIds = updatedPolicyIds; + this.changedDeviceTypes = deviceTypes; + } + + public List getUpdatedPolicies() { + return updatedPolicies; + } + + public void setUpdatedPolicies(List updatedPolicies) { + this.updatedPolicies = updatedPolicies; + } + + public List getUpdatedPolicyIds() { + return updatedPolicyIds; + } + + public void setUpdatedPolicyIds(List updatedPolicyIds) { + this.updatedPolicyIds = updatedPolicyIds; + } + + public List getChangedDeviceTypes() { + return changedDeviceTypes; + } + + public void setChangedDeviceTypes(List changedDeviceTypes) { + this.changedDeviceTypes = changedDeviceTypes; + } +} diff --git a/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/mgt/impl/PolicyManagerImpl.java b/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/mgt/impl/PolicyManagerImpl.java index 3614f75697..b8c0efd98f 100644 --- a/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/mgt/impl/PolicyManagerImpl.java +++ b/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/mgt/impl/PolicyManagerImpl.java @@ -39,6 +39,7 @@ import org.wso2.carbon.policy.mgt.core.cache.impl.PolicyCacheManagerImpl; import org.wso2.carbon.policy.mgt.core.dao.*; import org.wso2.carbon.policy.mgt.core.mgt.PolicyManager; import org.wso2.carbon.policy.mgt.core.mgt.ProfileManager; +import org.wso2.carbon.policy.mgt.core.mgt.bean.UpdatedPolicyDeviceListBean; import org.wso2.carbon.policy.mgt.core.util.PolicyManagerUtil; import java.sql.SQLException; @@ -830,15 +831,15 @@ public class PolicyManagerImpl implements PolicyManager { } @Override - public List applyChangesMadeToPolicies() throws PolicyManagementException { + public UpdatedPolicyDeviceListBean applyChangesMadeToPolicies() throws PolicyManagementException { List changedDeviceTypes = new ArrayList<>(); + List updatedPolicies = new ArrayList<>(); + List updatedPolicyIds = new ArrayList<>(); try { //HashMap map = policyDAO.getUpdatedPolicyIdandDeviceTypeId(); - List updatedPolicies = new ArrayList<>(); // List activePolicies = new ArrayList<>(); // List inactivePolicies = new ArrayList<>(); - List updatedPolicyIds = new ArrayList<>(); // List allPolicies = this.getPolicies(); List allPolicies = PolicyCacheManagerImpl.getInstance().getAllPolicies(); @@ -867,7 +868,7 @@ public class PolicyManagerImpl implements PolicyManager { } finally { PolicyManagementDAOFactory.closeConnection(); } - return changedDeviceTypes; + return new UpdatedPolicyDeviceListBean(updatedPolicies, updatedPolicyIds, changedDeviceTypes); } diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/conf/cdm-config.xml b/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/conf/cdm-config.xml index 42a0372076..99d5473b46 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/conf/cdm-config.xml +++ b/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/conf/cdm-config.xml @@ -25,12 +25,18 @@ - - org.wso2.carbon.device.mgt.extensions.push.notification.provider.fcm.FCMBasedPushNotificationProvider - - org.wso2.carbon.device.mgt.extensions.push.notification.provider.mqtt.MQTTBasedPushNotificationProvider - org.wso2.carbon.device.mgt.extensions.push.notification.provider.xmpp.XMPPBasedPushNotificationProvider - + + 1000 + 60000 + 60000 + true + + org.wso2.carbon.device.mgt.extensions.push.notification.provider.fcm.FCMBasedPushNotificationProvider + + org.wso2.carbon.device.mgt.extensions.push.notification.provider.mqtt.MQTTBasedPushNotificationProvider + org.wso2.carbon.device.mgt.extensions.push.notification.provider.xmpp.XMPPBasedPushNotificationProvider + + https://localhost:9443 admin diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/h2.sql b/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/h2.sql index 498a439c07..e63c647b37 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/h2.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/h2.sql @@ -114,6 +114,7 @@ CREATE TABLE IF NOT EXISTS DM_ENROLMENT_OP_MAPPING ( ENROLMENT_ID INTEGER NOT NULL, OPERATION_ID INTEGER NOT NULL, STATUS VARCHAR(50) NULL, + PUSH_NOTIFICATION_STATUS VARCHAR(50) NULL, CREATED_TIMESTAMP INT NOT NULL, UPDATED_TIMESTAMP INT NOT NULL, PRIMARY KEY (ID), diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/mssql.sql b/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/mssql.sql index ed33177429..a2c7d4dea3 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/mssql.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/mssql.sql @@ -148,6 +148,7 @@ CREATE TABLE DM_ENROLMENT_OP_MAPPING ( ENROLMENT_ID INTEGER NOT NULL, OPERATION_ID INTEGER NOT NULL, STATUS VARCHAR(50) NULL, + PUSH_NOTIFICATION_STATUS VARCHAR(50) NULL, CREATED_TIMESTAMP BIGINT NOT NULL, UPDATED_TIMESTAMP BIGINT NOT NULL, PRIMARY KEY (ID), diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/mysql.sql b/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/mysql.sql index 6bec98fc5b..6de158c415 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/mysql.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/mysql.sql @@ -128,6 +128,7 @@ CREATE TABLE IF NOT EXISTS DM_ENROLMENT_OP_MAPPING ( ENROLMENT_ID INTEGER NOT NULL, OPERATION_ID INTEGER NOT NULL, STATUS VARCHAR(50) NULL, + PUSH_NOTIFICATION_STATUS VARCHAR(50) NULL, CREATED_TIMESTAMP INTEGER NOT NULL, UPDATED_TIMESTAMP INTEGER NOT NULL, PRIMARY KEY (ID), diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/oracle.sql b/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/oracle.sql index 4bd5f55de9..31b7d60fe4 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/oracle.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/oracle.sql @@ -210,6 +210,7 @@ CREATE TABLE DM_ENROLMENT_OP_MAPPING ( ENROLMENT_ID NUMBER(10) NOT NULL, OPERATION_ID NUMBER(10) NOT NULL, STATUS VARCHAR2(50) NULL, + PUSH_NOTIFICATION_STATUS VARCHAR2(50) NULL, CREATED_TIMESTAMP NUMBER(14) NOT NULL, UPDATED_TIMESTAMP NUMBER(14) NOT NULL, PRIMARY KEY (ID), diff --git a/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/postgresql.sql b/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/postgresql.sql index a4f07d7781..6c1fc86a91 100644 --- a/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/postgresql.sql +++ b/features/device-mgt/org.wso2.carbon.device.mgt.server.feature/src/main/resources/dbscripts/cdm/postgresql.sql @@ -115,6 +115,7 @@ CREATE TABLE IF NOT EXISTS DM_ENROLMENT_OP_MAPPING ( ENROLMENT_ID INTEGER NOT NULL, OPERATION_ID INTEGER NOT NULL, STATUS VARCHAR(50) NULL, + PUSH_NOTIFICATION_STATUS VARCHAR(50) NULL, CREATED_TIMESTAMP INTEGER NOT NULL, UPDATED_TIMESTAMP INTEGER NOT NULL, CONSTRAINT fk_dm_device_operation_mapping_device FOREIGN KEY (ENROLMENT_ID) REFERENCES