diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/services/SubscriptionManager.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/services/SubscriptionManager.java
index bc2eaabc47..4c64d8c4fa 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/services/SubscriptionManager.java
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/services/SubscriptionManager.java
@@ -33,24 +33,43 @@ import java.util.Properties;
* This interface manages all the operations related with ApplicationDTO Subscription.
*/
public interface SubscriptionManager {
+
/**
* Performs bulk subscription operation for a given application and a subscriber list.
- * @param applicationUUID UUID of the application to subscribe/unsubscribe
- * @param params list of subscribers. This list can be of either
- * {@link DeviceIdentifier} if {@param subType} is equal
- * to DEVICE or
- * {@link String} if {@param subType} is USER, ROLE or GROUP
- * @param subType subscription type. E.g. DEVICE, USER, ROLE, GROUP
{@see {
- * @param action subscription action. E.g. INSTALL/UNINSTALL
{@see {
- * @param generic type of the method.
- * @return {@link ApplicationInstallResponse}
- * @throws ApplicationManagementException if error occurs when subscribing to the given application
- * @link org.wso2.carbon.device.application.mgt.common.SubscriptionType}}
- * @link org.wso2.carbon.device.application.mgt.common.SubAction}}
- * @param properties
+ * @param applicationUUID UUID of the application to subscribe/unsubscribe
+ * @param params list of subscribers.
+ * This list can be of either {@link DeviceIdentifier} if {@param subType} is equal to
+ * DEVICE or {@link String} if {@param subType} is USER, ROLE or GROUP
+ * @param subType subscription type. E.g. DEVICE, USER, ROLE, GROUP
+ * @param action subscription action. E.g. INSTALL/UNINSTALL
+ * @param generic type of the method.
+ * @param properties Application properties that need to be sent with operation payload to the device
+ * @return {@link ApplicationInstallResponse}
+ * @throws ApplicationManagementException if error occurs when subscribing to the given application
+ */
+ ApplicationInstallResponse performBulkAppOperation(String applicationUUID, List params, String subType,
+ String action, Properties properties)
+ throws ApplicationManagementException;
+
+ /**
+ * Performs bulk subscription operation for a given application and a subscriber list.
+ * @param applicationUUID UUID of the application to subscribe/unsubscribe
+ * @param params list of subscribers.
+ * This list can be of either {@link DeviceIdentifier} if {@param subType} is equal to
+ * DEVICE or {@link String} if {@param subType} is USER, ROLE or GROUP
+ * @param subType subscription type. E.g. DEVICE, USER, ROLE, GROUP
+ * @param action subscription action. E.g. INSTALL/UNINSTALL
+ * @param generic type of the method.
+ * @param properties Application properties that need to be sent with operation payload to the device
+ * @param isOperationReExecutingDisabled To prevent adding the application subscribing operation to devices that are
+ * already subscribed application successfully.
+ * @return {@link ApplicationInstallResponse}
+ * @throws ApplicationManagementException if error occurs when subscribing to the given application
*/
ApplicationInstallResponse performBulkAppOperation(String applicationUUID, List params, String subType,
- String action, Properties properties) throws ApplicationManagementException;
+ String action, Properties properties,
+ boolean isOperationReExecutingDisabled)
+ throws ApplicationManagementException;
/**
* Create an entry related to the scheduled task in the database.
@@ -119,7 +138,7 @@ public interface SubscriptionManager {
* This is used in enterprise app installing policy.
*
* @param deviceIdentifier Device identifiers
- * @param releaseUUID UUIs of applicatios
+ * @param apps Applications
* @throws ApplicationManagementException if error occurred while installing given applications into the given
* device
*/
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/SubscriptionManagerImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/SubscriptionManagerImpl.java
index 2de1094c1f..5d2f3c6d6b 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/SubscriptionManagerImpl.java
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/SubscriptionManagerImpl.java
@@ -121,7 +121,16 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
@Override
public ApplicationInstallResponse performBulkAppOperation(String applicationUUID, List params,
- String subType, String action, Properties properties) throws ApplicationManagementException {
+ String subType, String action, Properties properties)
+ throws ApplicationManagementException {
+ return performBulkAppOperation(applicationUUID, params, subType, action, properties, false);
+ }
+
+ @Override
+ public ApplicationInstallResponse performBulkAppOperation(String applicationUUID, List params,
+ String subType, String action, Properties properties,
+ boolean isOperationReExecutingDisabled)
+ throws ApplicationManagementException {
if (log.isDebugEnabled()) {
log.debug("Install application release which has UUID " + applicationUUID + " to " + params.size()
+ " users.");
@@ -134,7 +143,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
params);
ApplicationInstallResponse applicationInstallResponse = performActionOnDevices(
applicationSubscriptionInfo.getAppSupportingDeviceTypeName(), applicationSubscriptionInfo.getDevices(),
- applicationDTO, subType, applicationSubscriptionInfo.getSubscribers(), action, properties);
+ applicationDTO, subType, applicationSubscriptionInfo.getSubscribers(), action, properties, isOperationReExecutingDisabled);
applicationInstallResponse.setErrorDeviceIdentifiers(applicationSubscriptionInfo.getErrorDeviceIdentifiers());
return applicationInstallResponse;
@@ -617,12 +626,17 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
* @param subType Subscription type (i.e USER, ROLE, GROUP or DEVICE)
* @param subscribers Subscribers
* @param action Performing action. (i.e INSTALL or UNINSTALL)
+ * @param isOperationReExecutingDisabled To prevent adding the application subscribing operation to devices that are
+ * already subscribed application successfully.
* @return {@link ApplicationInstallResponse}
- * @throws ApplicationManagementException if error occured when adding operation on device or updating subscription
+ * @throws ApplicationManagementException if error occurred when adding operation on device or updating subscription
* data.
*/
private ApplicationInstallResponse performActionOnDevices(String deviceType, List devices,
- ApplicationDTO applicationDTO, String subType, List subscribers, String action, Properties properties)
+ ApplicationDTO applicationDTO, String subType,
+ List subscribers, String action,
+ Properties properties,
+ boolean isOperationReExecutingDisabled)
throws ApplicationManagementException {
//Get app subscribing info of each device
@@ -637,15 +651,19 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) {
deviceIdentifiers.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstallableDevices().keySet()));
deviceIdentifiers.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppReInstallableDevices().keySet()));
- deviceIdentifiers.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstalledDevices().keySet()));
- } else {
- if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action)) {
+ if (!isOperationReExecutingDisabled) {
deviceIdentifiers.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstalledDevices().keySet()));
- deviceIdentifiers
- .addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppReUnInstallableDevices().keySet()));
- ignoredDeviceIdentifiers
- .addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstallableDevices().keySet()));
}
+ } else if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action)) {
+ deviceIdentifiers.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstalledDevices().keySet()));
+ deviceIdentifiers
+ .addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppReUnInstallableDevices().keySet()));
+ ignoredDeviceIdentifiers
+ .addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstallableDevices().keySet()));
+ } else {
+ String msg = "Found invalid Action: " + action + ". Hence, terminating the application subscribing.";
+ log.error(msg);
+ throw new ApplicationManagementException(msg);
}
if (deviceIdentifiers.isEmpty()) {
@@ -717,15 +735,14 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
} else {
if (deviceSubscriptionDTO.isUnsubscribed()) {
if (!Operation.Status.COMPLETED.toString().equals(deviceSubscriptionDTO.getStatus())) {
- /*We can't ensure whether app is uninstalled successfully or not hence allow to perform both
- install and uninstall operations*/
+ /*If the uninstalling operation has failed, we can't ensure whether the app is uninstalled
+ successfully or not. Therefore, allowing to perform both install and uninstall operations*/
subscribingDeviceIdHolder.getAppReUnInstallableDevices()
.put(deviceIdentifier, device.getId());
}
subscribingDeviceIdHolder.getAppReInstallableDevices().put(deviceIdentifier, device.getId());
} else {
- if (!deviceSubscriptionDTO.isUnsubscribed() && Operation.Status.COMPLETED.toString()
- .equals(deviceSubscriptionDTO.getStatus())) {
+ if (Operation.Status.COMPLETED.toString().equals(deviceSubscriptionDTO.getStatus())) {
subscribingDeviceIdHolder.getAppInstalledDevices().put(deviceIdentifier, device.getId());
} else {
subscribingDeviceIdHolder.getAppReInstallableDevices()
@@ -960,11 +977,11 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
ConnectionManagerUtil.openDBConnection();
return this.subscriptionDAO.getDeviceSubscriptions(deviceIds, appReleaseId, tenantId);
} catch (ApplicationManagementDAOException e) {
- String msg = "Error occured when getting device subscriptions for given device IDs";
+ String msg = "Error occurred when getting device subscriptions for given device IDs";
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} catch (DBConnectionException e) {
- String msg = "Error occured while getting database connection for getting device subscriptions.";
+ String msg = "Error occurred while getting database connection for getting device subscriptions.";
log.error(msg, e);
throw new ApplicationManagementException(msg, e);
} finally {
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/task/ScheduledAppSubscriptionTask.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/task/ScheduledAppSubscriptionTask.java
index d8f491e37d..2a4e03d205 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/task/ScheduledAppSubscriptionTask.java
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/task/ScheduledAppSubscriptionTask.java
@@ -42,7 +42,7 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class ScheduledAppSubscriptionTask extends RandomlyAssignedScheduleTask {
- private static Log log = LogFactory.getLog(ScheduledAppSubscriptionTask.class);
+ private static final Log log = LogFactory.getLog(ScheduledAppSubscriptionTask.class);
private static final String TASK_NAME = "SCHEDULE_APP_SUBSCRIPTION";
private SubscriptionManager subscriptionManager;
@@ -55,6 +55,7 @@ public class ScheduledAppSubscriptionTask extends RandomlyAssignedScheduleTask {
private String tenantDomain;
private String taskName;
private int tenantId;
+ private boolean isOperationReExecutingDisabled;
@Override
public void setProperties(Map map) {
@@ -67,6 +68,7 @@ public class ScheduledAppSubscriptionTask extends RandomlyAssignedScheduleTask {
this.tenantDomain = map.get(Constants.TENANT_DOMAIN);
this.tenantId = Integer.parseInt(map.get(Constants.TENANT_ID));
this.taskName = map.get(Constants.TASK_NAME);
+ this.isOperationReExecutingDisabled = Boolean.parseBoolean(map.get(Constants.OPERATION_RE_EXECUtING));
}
@Override
@@ -108,7 +110,7 @@ public class ScheduledAppSubscriptionTask extends RandomlyAssignedScheduleTask {
try {
Properties properties = new Gson().fromJson(payload, Properties.class);
subscriptionManager.performBulkAppOperation(this.application, subscriberList,
- this.subscriptionType, this.action, properties);
+ this.subscriptionType, this.action, properties, isOperationReExecutingDisabled);
subscriptionDTO.setStatus(ExecutionStatus.EXECUTED);
} catch (ApplicationManagementException e) {
log.error(
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/task/ScheduledAppSubscriptionTaskManager.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/task/ScheduledAppSubscriptionTaskManager.java
index b274b1850f..f68c213ebc 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/task/ScheduledAppSubscriptionTaskManager.java
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/task/ScheduledAppSubscriptionTaskManager.java
@@ -71,10 +71,14 @@ public class ScheduledAppSubscriptionTaskManager {
* @param action action subscription action. E.g. {@code INSTALL/UNINSTALL}
* {@see {@link SubAction}}
* @param timestamp timestamp to schedule the application subscription
+ * @param properties Properties sending to the device via operation
+ * @param isOperationReExecutingDisabled To prevent adding the application subscribing
+ * already subscribed application successfully.
* @throws ApplicationOperationTaskException if error occurred while scheduling the subscription
*/
public void scheduleAppSubscriptionTask(String applicationUUID, List> subscribers,
- SubscriptionType subscriptionType, SubAction action, long timestamp, Properties properties)
+ SubscriptionType subscriptionType, SubAction action, long timestamp,
+ Properties properties, boolean isOperationReExecutingDisabled)
throws ApplicationOperationTaskException {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date(timestamp * 1000));
@@ -107,14 +111,15 @@ public class ScheduledAppSubscriptionTaskManager {
taskProperties.put(Constants.APP_UUID, applicationUUID);
taskProperties.put(Constants.TENANT_DOMAIN, carbonContext.getTenantDomain(true));
taskProperties.put(Constants.SUBSCRIBER, carbonContext.getUsername());
+ taskProperties.put(Constants.OPERATION_RE_EXECUtING, String.valueOf(isOperationReExecutingDisabled));
String subscribersString;
if (SubscriptionType.DEVICE.equals(subscriptionType)) {
subscribersString = new Gson().toJson(subscribers);
- taskProperties.put(Constants.SUBSCRIBERS, subscribersString);
} else {
subscribersString = subscribers.stream().map(String.class::cast).collect(Collectors.joining(","));
- taskProperties.put(Constants.SUBSCRIBERS, subscribersString);
}
+ taskProperties.put(Constants.SUBSCRIBERS, subscribersString);
+
if(properties != null) {
String payload = new Gson().toJson(properties);
taskProperties.put(Constants.PAYLOAD, payload);
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/util/Constants.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/util/Constants.java
index 27498f77bb..845789ec21 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/util/Constants.java
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/util/Constants.java
@@ -60,6 +60,7 @@ public class Constants {
public static final String APP_UUID = "APP_UUID";
public static final String APP_PROPERTIES = "APP_PROPERTIES";
public static final String SUBSCRIBER = "SUBSCRIBER";
+ public static final String OPERATION_RE_EXECUtING = "OPERATION_RE_EXECUtING";
public static final String TENANT_DOMAIN = "TENANT_DOMAIN";
public static final String TENANT_ID = "__TENANT_ID_PROP__";
public static final String TASK_NAME = "TASK_NAME";
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/SubscriptionManagementAPI.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/SubscriptionManagementAPI.java
index 174b6921ee..b0d91fdf89 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/SubscriptionManagementAPI.java
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/SubscriptionManagementAPI.java
@@ -193,7 +193,12 @@ public interface SubscriptionManagementAPI {
name = "block-uninstall",
value = "App removal status of the install operation"
)
- @QueryParam("block-uninstall") Boolean isUninstallBlocked
+ @QueryParam("block-uninstall") Boolean isUninstallBlocked,
+ @ApiParam(
+ name = "disable-operation-re-executing",
+ value = "Disable Operation re-executing"
+ )
+ @QueryParam("disable-operation-re-executing") boolean isOperationReExecutingDisabled
);
@POST
diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/impl/SubscriptionManagementAPIImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/impl/SubscriptionManagementAPIImpl.java
index 4a51353997..473694714d 100644
--- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/impl/SubscriptionManagementAPIImpl.java
+++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/impl/SubscriptionManagementAPIImpl.java
@@ -123,22 +123,24 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
@PathParam("action") String action,
@Valid List subscribers,
@QueryParam("timestamp") long timestamp,
- @QueryParam("block-uninstall") Boolean isUninstallBlocked
+ @QueryParam("block-uninstall") Boolean isUninstallBlocked,
+ @QueryParam("disable-operation-re-executing") boolean isOperationReExecutingDisabled
) {
Properties properties = new Properties();
- if(isUninstallBlocked != null) {
+ if (isUninstallBlocked != null) {
properties.put(MDMAppConstants.AndroidConstants.IS_BLOCK_UNINSTALL, isUninstallBlocked);
}
try {
if (0 == timestamp) {
SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager();
- ApplicationInstallResponse response = subscriptionManager
- .performBulkAppOperation(uuid, subscribers, subType, action, properties);
+ ApplicationInstallResponse response =
+ subscriptionManager.performBulkAppOperation(uuid, subscribers, subType, action, properties,
+ isOperationReExecutingDisabled);
return Response.status(Response.Status.OK).entity(response).build();
} else {
return scheduleApplicationOperationTask(uuid, subscribers,
SubscriptionType.valueOf(subType.toUpperCase()), SubAction.valueOf(action.toUpperCase()),
- timestamp, properties);
+ timestamp, properties, isOperationReExecutingDisabled);
}
} catch (NotFoundException e) {
String msg = "Couldn't found an application release for UUID: " + uuid + ". Hence, verify the payload";
@@ -252,6 +254,28 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
}
}
+ /**
+ * Schedule the application subscription for the given timestamp
+ *
+ * @param applicationUUID UUID of the application to install
+ * @param subscribers list of subscribers. This list can be of
+ * either {@link org.wso2.carbon.device.mgt.common.DeviceIdentifier} if {@param subType} is
+ * equal to DEVICE or {@link String} if {@param subType} is USER, ROLE or GROUP
+ * @param subType subscription type. E.g. DEVICE, USER, ROLE, GROUP
+ * {@see {@link org.wso2.carbon.device.application.mgt.common.SubscriptionType}}
+ * @param subAction action subscription action. E.g. INSTALL/UNINSTALL
+ * {@see {@link org.wso2.carbon.device.application.mgt.common.SubAction}}
+ * @param payload Properties sending to the device via operation
+ * @param timestamp timestamp to schedule the application subscription
+ * @return {@link Response} of the operation
+ */
+ private Response scheduleApplicationOperationTask(String applicationUUID, List> subscribers,
+ SubscriptionType subType, SubAction subAction, long timestamp,
+ Properties payload) {
+ return scheduleApplicationOperationTask(applicationUUID, subscribers, subType, subAction, timestamp, payload,
+ false);
+ }
+
/**
* Schedule the application subscription for the given timestamp
*
@@ -264,14 +288,18 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
* @param subAction action subscription action. E.g. INSTALL/UNINSTALL
* {@see {@link org.wso2.carbon.device.application.mgt.common.SubAction}}
* @param timestamp timestamp to schedule the application subscription
+ * @param payload Properties sending to the device via operation
+ * @param isOperationReExecutingDisabled To prevent adding the application subscribing operation to devices that are
+ * already subscribed application successfully.
* @return {@link Response} of the operation
*/
private Response scheduleApplicationOperationTask(String applicationUUID, List> subscribers,
- SubscriptionType subType, SubAction subAction, long timestamp, Properties payload) {
+ SubscriptionType subType, SubAction subAction, long timestamp,
+ Properties payload, boolean isOperationReExecutingDisabled) {
try {
ScheduledAppSubscriptionTaskManager subscriptionTaskManager = new ScheduledAppSubscriptionTaskManager();
subscriptionTaskManager.scheduleAppSubscriptionTask(applicationUUID, subscribers, subType, subAction,
- timestamp, payload);
+ timestamp, payload, isOperationReExecutingDisabled);
} catch (ApplicationOperationTaskException e) {
String msg = "Error occurred while scheduling the application install operation";
log.error(msg, e);