From 690eff6660931ac0d0907bba8670b3e5a6ca3c15 Mon Sep 17 00:00:00 2001 From: Madawa Soysa Date: Tue, 13 Feb 2018 15:19:12 +0530 Subject: [PATCH] Refactoring mobile application subscription API --- .../common/EnterpriseInstallationDetails.java | 85 +++++++++ .../mgt/common/InstallationDetails.java | 46 +---- .../common/services/ApplicationManager.java | 9 +- .../common/services/SubscriptionManager.java | 43 +++-- .../mgt/core/impl/ApplicationManagerImpl.java | 17 +- .../core/impl/SubscriptionManagerImpl.java | 143 ++++++++------- .../application/mgt/core/util/HelperUtil.java | 21 +++ .../mgt/store/api/beans/ErrorResponse.java | 1 + .../services/SubscriptionManagementAPI.java | 169 +++++++++++++++--- .../impl/SubscriptionManagementAPIImpl.java | 94 +++++++--- 10 files changed, 446 insertions(+), 182 deletions(-) create mode 100644 components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/EnterpriseInstallationDetails.java diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/EnterpriseInstallationDetails.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/EnterpriseInstallationDetails.java new file mode 100644 index 00000000000..6eac1a76ab2 --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/EnterpriseInstallationDetails.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018, 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.application.mgt.common; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +public class EnterpriseInstallationDetails { + + /** + * This enum represents the type of entities which an application can be installed on. + * + * e.g: An application can be installed on all the devices belong to a user or a specific device group. + */ + @ApiModel + public enum EnterpriseEntity { + USER, ROLE, DEVICE_GROUP + } + + @ApiModelProperty( + name = "applicationUUID", + value = "Application ID", + required = true, + example = "4354c752-109f-11e8-b642-0ed5f89f718b" + ) + private String applicationUUID; + + @ApiModelProperty( + name = "entityType", + value = "Enterprise entity type", + required = true, + example = "USER" + ) + private EnterpriseEntity entityType; + + @ApiModelProperty( + name = "entityValueList", + value = "List of users/roles or device groups.", + required = true, + example = "user1,user2, user3" + ) + private List entityValueList; + + public String getApplicationUUID() { + return applicationUUID; + } + + public void setApplicationUUID(String applicationUUID) { + this.applicationUUID = applicationUUID; + } + + public EnterpriseEntity getEntityType() { + return entityType; + } + + public void setEntityType(EnterpriseEntity entityType) { + this.entityType = entityType; + } + + public List getEntityValueList() { + return entityValueList; + } + + public void setEntityValueList(List entityValueList) { + this.entityValueList = entityValueList; + } +} diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/InstallationDetails.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/InstallationDetails.java index 75b484920a1..87601d6cc8c 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/InstallationDetails.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/InstallationDetails.java @@ -25,30 +25,16 @@ public class InstallationDetails { @ApiModelProperty( name = "applicationUUID", value = "Application ID", - required = true) + required = true + ) private String applicationUUID; - @ApiModelProperty( - name = "versionName", - value = "Version name", - required = true) - private String versionName; - @ApiModelProperty( - name = "userNameList", - value = "List of user names.", - required = true) - private List userNameList; - - @ApiModelProperty( - name = "roleNameList", - value = "List of role names.", - required = true) - private List roleNameList; @ApiModelProperty( name = "deviceIdentifiers", value = "List of device identifiers.", required = true, - dataType = "List[org.wso2.carbon.device.mgt.common.DeviceIdentifier]") + dataType = "List[org.wso2.carbon.device.mgt.common.DeviceIdentifier]" + ) private List deviceIdentifiers; public String getApplicationUUID() { @@ -59,30 +45,6 @@ public class InstallationDetails { this.applicationUUID = applicationUUID; } - public String getVersionName() { - return versionName; - } - - public void setVersionName(String versionName) { - this.versionName = versionName; - } - - public List getUserNameList() { - return userNameList; - } - - public void setUserNameList(List userNameList) { - this.userNameList = userNameList; - } - - public List getRoleNameList() { - return roleNameList; - } - - public void setRoleNameList(List roleNameList) { - this.roleNameList = roleNameList; - } - public List getDeviceIdentifiers() { return deviceIdentifiers; } diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/services/ApplicationManager.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/services/ApplicationManager.java index 8c10189a8f9..1dc480a8830 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/services/ApplicationManager.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/services/ApplicationManager.java @@ -18,10 +18,15 @@ */ package org.wso2.carbon.device.application.mgt.common.services; -import org.wso2.carbon.device.application.mgt.common.*; +import org.wso2.carbon.device.application.mgt.common.Application; +import org.wso2.carbon.device.application.mgt.common.ApplicationList; +import org.wso2.carbon.device.application.mgt.common.ApplicationRelease; +import org.wso2.carbon.device.application.mgt.common.Filter; +import org.wso2.carbon.device.application.mgt.common.LifecycleState; +import org.wso2.carbon.device.application.mgt.common.LifecycleStateTransition; +import org.wso2.carbon.device.application.mgt.common.UnrestrictedRole; import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException; import org.wso2.carbon.device.application.mgt.common.exception.LifecycleManagementException; -import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException; import java.util.List; 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 603ac480159..42386768db1 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 @@ -29,35 +29,42 @@ import java.util.List; public interface SubscriptionManager { /** * To install an application to given list of devices. - * @param applicationUUID Application ID - * @param deviceList Device list + * @param applicationUUID ID of the application to install + * @param deviceList list of device ID's to install the application * @return Failed Device List which the application was unable to install - * @throws ApplicationManagementException Application Management Exception + * @throws ApplicationManagementException if unable to install the application to the given devices */ - List installApplicationForDevices(String applicationUUID, String versionName, - List deviceList) + List installApplicationForDevices(String applicationUUID, List deviceList) throws ApplicationManagementException; /** * To install an application to given list of users. - * @param applicationUUID Application ID - * @param userList User list + * @param applicationUUID ID of the application to install + * @param userList list of users to install the application * @return Failed Device List which the application was unable to install - * @throws ApplicationManagementException Application Management Exception + * @throws ApplicationManagementException if unable to install the application to devices belong to given users */ - List installApplicationForUsers(String applicationUUID, - List userList, String versionName) + List installApplicationForUsers(String applicationUUID, List userList) throws ApplicationManagementException; /** - * To install an application to given list of users. - * @param applicationUUID Application ID - * @param roleList Role list + * To install an application to given list of roles. + * @param applicationUUID ID of the application to install + * @param roleList list of roles to install the application * @return Failed Device List which the application was unable to install - * @throws ApplicationManagementException Application Management Exception + * @throws ApplicationManagementException if unable to install the application to devices belong to given roles */ - List installApplicationForRoles(String applicationUUID, - List roleList, String versionName) + List installApplicationForRoles(String applicationUUID, List roleList) + throws ApplicationManagementException; + + /** + * To install an application to given list of roles. + * @param applicationUUID ID of the application to install + * @param deviceGroupList list of device groups to install the application + * @return Failed Device List which the application was unable to install + * @throws ApplicationManagementException if unable to install the application to devices belong to given groups + */ + List installApplicationForGroups(String applicationUUID, List deviceGroupList) throws ApplicationManagementException; /** @@ -67,8 +74,6 @@ public interface SubscriptionManager { * @return Failed Device List which the application was unable to uninstall * @throws ApplicationManagementException Application Management Exception */ - List uninstallApplication(String applicationUUID, - List deviceList) + List uninstallApplication(String applicationUUID, List deviceList) throws ApplicationManagementException; - } diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/ApplicationManagerImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/ApplicationManagerImpl.java index 3a8a791f834..0187525a0d9 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/ApplicationManagerImpl.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/ApplicationManagerImpl.java @@ -23,7 +23,15 @@ 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.application.mgt.common.*; +import org.wso2.carbon.device.application.mgt.common.AppLifecycleState; +import org.wso2.carbon.device.application.mgt.common.Application; +import org.wso2.carbon.device.application.mgt.common.ApplicationList; +import org.wso2.carbon.device.application.mgt.common.ApplicationRelease; +import org.wso2.carbon.device.application.mgt.common.Filter; +import org.wso2.carbon.device.application.mgt.common.LifecycleState; +import org.wso2.carbon.device.application.mgt.common.LifecycleStateTransition; +import org.wso2.carbon.device.application.mgt.common.UnrestrictedRole; +import org.wso2.carbon.device.application.mgt.common.User; import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException; import org.wso2.carbon.device.application.mgt.common.exception.DBConnectionException; import org.wso2.carbon.device.application.mgt.common.exception.LifecycleManagementException; @@ -38,16 +46,17 @@ import org.wso2.carbon.device.application.mgt.core.exception.NotFoundException; import org.wso2.carbon.device.application.mgt.core.exception.ValidationException; import org.wso2.carbon.device.application.mgt.core.internal.DataHolder; import org.wso2.carbon.device.application.mgt.core.util.ConnectionManagerUtil; -import org.wso2.carbon.device.mgt.core.dao.*; +import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException; +import org.wso2.carbon.device.mgt.core.dao.DeviceTypeDAO; import org.wso2.carbon.device.mgt.core.dto.DeviceType; import org.wso2.carbon.user.api.UserRealm; import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.utils.multitenancy.MultitenantUtils; -import java.util.ArrayList; -import java.util.List; import java.sql.Timestamp; +import java.util.ArrayList; import java.util.Date; +import java.util.List; /** * Default Concrete implementation of Application Management related implementations. 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 b6bb3f53493..e9d1375e60d 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 @@ -19,19 +19,27 @@ package org.wso2.carbon.device.application.mgt.core.impl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.application.mgt.common.ApplicationRelease; import org.wso2.carbon.device.application.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException; +import org.wso2.carbon.device.application.mgt.common.services.ApplicationManager; +import org.wso2.carbon.device.application.mgt.common.services.ApplicationReleaseManager; import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager; +import org.wso2.carbon.device.application.mgt.core.util.ApplicationManagementUtil; import org.wso2.carbon.device.application.mgt.core.util.HelperUtil; import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.DeviceManagementConstants; import org.wso2.carbon.device.mgt.common.DeviceManagementException; import org.wso2.carbon.device.mgt.common.InvalidDeviceException; import org.wso2.carbon.device.mgt.common.app.mgt.DeviceApplicationMapping; +import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup; +import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException; import org.wso2.carbon.device.mgt.common.operation.mgt.Operation; import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException; +import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory; import org.wso2.carbon.device.mgt.core.operation.mgt.ProfileOperation; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService; import java.util.ArrayList; import java.util.List; @@ -45,106 +53,103 @@ public class SubscriptionManagerImpl implements SubscriptionManager { private static final String INSTALL_APPLICATION = "INSTALL_APPLICATION"; @Override - public List installApplicationForDevices(String applicationUUID, String versionName, - List deviceList) - throws ApplicationManagementException { - return installApplication(applicationUUID, deviceList, versionName); + public List installApplicationForDevices(String applicationUUID, + List deviceList) throws ApplicationManagementException { + if (log.isDebugEnabled()) { + log.debug("Install application: " + applicationUUID + " to " + deviceList.size() + "devices."); + } + return installApplication(applicationUUID, deviceList); } @Override - public List installApplicationForUsers(String applicationUUID, List userList, - String versionName) throws ApplicationManagementException { - log.info("Install application: " + applicationUUID + " to: " + userList.size() + " users."); + public List installApplicationForUsers(String applicationUUID, List userList) + throws ApplicationManagementException { + if (log.isDebugEnabled()) { + log.debug("Install application: " + applicationUUID + " to " + userList.size() + " users."); + } List deviceList = new ArrayList<>(); for (String user : userList) { try { List devicesOfUser = HelperUtil.getDeviceManagementProviderService().getDevicesOfUser(user); for (Device device : devicesOfUser) { - deviceList.add(new DeviceIdentifier(device - .getDeviceIdentifier(), device.getType())); + deviceList.add(new DeviceIdentifier(device.getDeviceIdentifier(), device.getType())); + } + if (log.isDebugEnabled()) { + log.debug(devicesOfUser.size() + " found for the provided user list"); } } catch (DeviceManagementException e) { - log.error("Error when extracting the device list from user[" + user + "].", e); + throw new ApplicationManagementException("Error when extracting the device list of user[" + user + "].", + e); } } - return installApplication(applicationUUID, deviceList, versionName); + return installApplication(applicationUUID, deviceList); } @Override - public List installApplicationForRoles(String applicationUUID, List roleList, - String versionName) throws ApplicationManagementException { - log.info("Install application: " + applicationUUID + " to: " + roleList.size() + " roles."); + public List installApplicationForRoles(String applicationUUID, List roleList) + throws ApplicationManagementException { + if (log.isDebugEnabled()) { + log.debug("Install application: " + applicationUUID + " to " + roleList.size() + " roles."); + } List deviceList = new ArrayList<>(); for (String role : roleList) { try { List devicesOfRole = HelperUtil.getDeviceManagementProviderService().getAllDevicesOfRole(role); for (Device device : devicesOfRole) { - deviceList.add(new DeviceIdentifier(device - .getDeviceIdentifier(), device.getType())); + deviceList.add(new DeviceIdentifier(device.getDeviceIdentifier(), device.getType())); + } + if (log.isDebugEnabled()) { + log.debug(devicesOfRole.size() + " found for role: " + role); } } catch (DeviceManagementException e) { - log.error("Error when extracting the device list from role[" + role + "].", e); + throw new ApplicationManagementException( + "Error when extracting the device list from role[" + role + "].", e); + } + } + return installApplication(applicationUUID, deviceList); + } + + @Override + public List installApplicationForGroups(String applicationUUID, List deviceGroupList) + throws ApplicationManagementException { + if (log.isDebugEnabled()) { + log.debug("Install application: " + applicationUUID + " to " + deviceGroupList.size() + " groups."); + } + GroupManagementProviderService groupManagementProviderService = HelperUtil.getGroupManagementProviderService(); + List deviceList = new ArrayList<>(); + for (String groupName : deviceGroupList) { + try { + DeviceGroup deviceGroup = groupManagementProviderService.getGroup(groupName); + int deviceCount = groupManagementProviderService.getDeviceCount(deviceGroup.getGroupId()); + List devicesOfGroups = groupManagementProviderService + .getDevices(deviceGroup.getGroupId(), 0, deviceCount); + for (Device device : devicesOfGroups) { + deviceList.add(new DeviceIdentifier(device.getDeviceIdentifier(), device.getType())); + } + } catch (GroupManagementException e) { + throw new ApplicationManagementException( + "Error when extracting the device list from group[" + groupName + "].", e); } } - return installApplication(applicationUUID, deviceList, versionName); + return installApplication(applicationUUID, deviceList); } @Override - public List uninstallApplication(String applicationUUID, - List deviceList) + public List uninstallApplication(String applicationUUID, List deviceList) throws ApplicationManagementException { return null; } - private List installApplication(String applicationUUID, List deviceList, - String versionName) throws ApplicationManagementException { + private List installApplication(String applicationUUID, List deviceList) + throws ApplicationManagementException { + //todo: 1. get application and release. + ApplicationReleaseManager applicationReleaseManager = ApplicationManagementUtil + .getApplicationReleaseManagerInstance(); + ApplicationRelease applicationRelease = applicationReleaseManager.getReleaseByUuid(applicationUUID); + //todo: 2. check type and filter devices. + //todo: 3. generate url based on application attributes and app release attributes + + //Todo: check if app type is installable for all the device types: apk -> android, ipa -> ios, webclip -> both return null; -// List failedDeviceList = new ArrayList<>(deviceList); -// // Todo: try whether we can optimise this by sending bulk inserts to db -// // Todo: atomicity is not maintained as deveice managment provider service uses separate db connection. fix this?? -// log.info("Install application: " + applicationUUID + "[" + versionName + "]" + " to: " -// + deviceList.size() + " devices."); -// for (DeviceIdentifier device : deviceList) { -// org.wso2.carbon.device.mgt.common.DeviceIdentifier deviceIdentifier = new org.wso2.carbon.device.mgt -// .common.DeviceIdentifier(device.getId(), device.getType()); -// try { -// DeviceManagementProviderService dmpService = HelperUtil.getDeviceManagementProviderService(); -// if (!dmpService.isEnrolled(deviceIdentifier)) { -// log.error("Device with ID: [" + device.getId() + "] is not enrolled to install the application."); -// } else { -// if (log.isDebugEnabled()) { -// log.debug("Installing application to : " + device.getId()); -// } -// //Todo: generating one time download link for the application and put install operation to device. -// -// // put app install operation to the device -// ProfileOperation operation = new ProfileOperation(); -// operation.setCode(INSTALL_APPLICATION); -// operation.setType(Operation.Type.PROFILE); -// operation.setPayLoad("{'type':'enterprise', 'url':'http://10.100.5.76:8000/app-debug.apk', 'app':'" -// + applicationUUID + "'}"); -// List deviceIdentifiers = new ArrayList<>(); -// deviceIdentifiers.add(deviceIdentifier); -// dmpService.addOperation(DeviceManagementConstants.MobileDeviceTypes.MOBILE_DEVICE_TYPE_ANDROID, -// operation, deviceIdentifiers); -// -// DeviceApplicationMapping deviceApp = new DeviceApplicationMapping(); -// deviceApp.setDeviceIdentifier(device.getId()); -// deviceApp.setApplicationUUID(applicationUUID); -// deviceApp.setVersionName(versionName); -// deviceApp.setInstalled(false); -// dmpService.addDeviceApplicationMapping(deviceApp); -//// DeviceManagementDAOFactory.openConnection(); -//// ApplicationManagementDAOFactory.getSubscriptionDAO().addDeviceApplicationMapping(device.getId(), applicationUUID, false); -// failedDeviceList.remove(device); -// } -// } catch (DeviceManagementException | OperationManagementException | InvalidDeviceException e) { -// log.error("Error while installing application to device[" + deviceIdentifier.getId() + "]", e); -// } -// finally { -// DeviceManagementDAOFactory.closeConnection(); -// } -// } -// return failedDeviceList; } } diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/util/HelperUtil.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/util/HelperUtil.java index b1297dfa8bc..fbad305355f 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/util/HelperUtil.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/util/HelperUtil.java @@ -21,8 +21,11 @@ package org.wso2.carbon.device.application.mgt.core.util; 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.Device; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; +import org.wso2.carbon.device.mgt.core.service.GroupManagementProviderService; +import java.util.List; import java.util.UUID; /** @@ -33,6 +36,7 @@ public class HelperUtil { private static Log log = LogFactory.getLog(HelperUtil.class); private static DeviceManagementProviderService deviceManagementProviderService; + private static GroupManagementProviderService groupManagementProviderService; public static String generateApplicationUuid() { return UUID.randomUUID().toString(); @@ -56,4 +60,21 @@ public class HelperUtil { return deviceManagementProviderService; } + public static GroupManagementProviderService getGroupManagementProviderService() { + if (groupManagementProviderService == null) { + synchronized (HelperUtil.class) { + if (groupManagementProviderService == null) { + PrivilegedCarbonContext ctx = PrivilegedCarbonContext.getThreadLocalCarbonContext(); + groupManagementProviderService = (GroupManagementProviderService) ctx + .getOSGiService(GroupManagementProviderService.class, null); + if (groupManagementProviderService == null) { + String msg = "Group management provider service has not initialized."; + log.error(msg); + throw new IllegalStateException(msg); + } + } + } + } + return groupManagementProviderService; + } } 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/beans/ErrorResponse.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/beans/ErrorResponse.java index 7727b7a6954..3b78219b855 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/beans/ErrorResponse.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/beans/ErrorResponse.java @@ -21,6 +21,7 @@ package org.wso2.carbon.device.application.mgt.publisher.api.beans; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import org.wso2.carbon.device.application.mgt.publisher.api.beans.ErrorListItem; import java.util.ArrayList; import java.util.List; 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 fb6d0e24465..05b20d318e6 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 @@ -17,14 +17,28 @@ */ package org.wso2.carbon.device.application.mgt.publisher.api.services; -import io.swagger.annotations.*; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import io.swagger.annotations.Extension; +import io.swagger.annotations.ExtensionProperty; +import io.swagger.annotations.Info; +import io.swagger.annotations.SwaggerDefinition; +import io.swagger.annotations.Tag; import org.wso2.carbon.apimgt.annotations.api.Scopes; -import org.wso2.carbon.device.application.mgt.publisher.api.beans.ErrorResponse; import org.wso2.carbon.device.application.mgt.common.Application; +import org.wso2.carbon.device.application.mgt.common.EnterpriseInstallationDetails; import org.wso2.carbon.device.application.mgt.common.InstallationDetails; import javax.validation.Valid; -import javax.ws.rs.*; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -43,9 +57,8 @@ import javax.ws.rs.core.Response; } ), tags = { - @Tag(name = "subscription_management, device_management", description = "Subscription Management " + - "related " - + "APIs") + @Tag(name = "subscription_management, device_management", description = "Subscription Management " + + "related APIs") } ) @Scopes( @@ -82,7 +95,7 @@ public interface SubscriptionManagementAPI { produces = MediaType.APPLICATION_JSON, httpMethod = "POST", value = "Install an application", - notes = "This will install an application to a given list of devices/users/roles", + notes = "This will install an application to a given list of devices", tags = "Subscription Management", extensions = { @Extension(properties = { @@ -95,23 +108,73 @@ public interface SubscriptionManagementAPI { @ApiResponse( code = 200, message = "OK. \n Successfully installed the application.", - response = Application.class), + response = Application.class + ), @ApiResponse( code = 304, - message = "Not Modified. \n " + - "Empty body because the application is already installed."), + message = "Not Modified. \n Empty body because the application is already installed." + ), + @ApiResponse( + code = 404, + message = "Not Found. \n Application cannot be found to install." + ), @ApiResponse( code = 500, - message = "Internal Server Error. \n Error occurred while installing the application.", - response = ErrorResponse.class) + message = "Internal Server Error. \n Error occurred while installing the application." + ) }) Response installApplication( @ApiParam( name = "installationDetails", value = "The application ID and list of devices/users/roles", - required = true) + required = true + ) @Valid InstallationDetails installationDetails); + @POST + @Path("/enterprise-install-application") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @ApiOperation( + consumes = MediaType.APPLICATION_JSON, + produces = MediaType.APPLICATION_JSON, + httpMethod = "POST", + value = "Install an application to the devices belong to an enterprise entity", + notes = "This will install an application to a given list of groups/users/roles", + tags = "Subscription Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = SCOPE, value = "perm:subscription:install") + }) + } + ) + @ApiResponses( + value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully installed the application.", + response = Application.class + ), + @ApiResponse( + code = 304, + message = "Not Modified. \n Empty body because the application is already installed." + ), + @ApiResponse( + code = 404, + message = "Not Found. \n Application cannot be found to install." + ), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Error occurred while installing the application." + ) + }) + Response enterpriseInstallApplication( + @ApiParam( + name = "enterpriseInstallationDetails", + value = "The application ID and list of devices/users/roles", + required = true) + @Valid EnterpriseInstallationDetails enterpriseInstallationDetails); + @POST @Path("/uninstall-application") @Produces(MediaType.APPLICATION_JSON) @@ -121,7 +184,7 @@ public interface SubscriptionManagementAPI { produces = MediaType.APPLICATION_JSON, httpMethod = "POST", value = "Uninstall an application", - notes = "This will uninstall an application to a given list of devices/users/roles", + notes = "This will uninstall an application from given list of devices", tags = "Subscription Management", extensions = { @Extension(properties = { @@ -134,23 +197,73 @@ public interface SubscriptionManagementAPI { @ApiResponse( code = 200, message = "OK. \n Successfully uninstalled the application.", - response = Application.class), + response = Application.class + ), @ApiResponse( code = 304, - message = "Not Modified. \n " + - "Empty body because the application is already uninstalled."), + message = "Not Modified. \n Empty body because the application is already uninstalled." + ), + @ApiResponse( + code = 404, + message = "Not Found. \n Application cannot be found to uninstall." + ), @ApiResponse( code = 500, - message = "Internal Server Error. \n Error occurred while installing the application.", - response = ErrorResponse.class) + message = "Internal Server Error. \n Error occurred while uninstalling the application." + ) }) Response uninstallApplication( @ApiParam( name = "installationDetails", - value = "The application ID and list of devices/users/roles", + value = "The application ID and list of devices", required = true) @Valid InstallationDetails installationDetails); + @POST + @Path("/enterprise-uninstall-application") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @ApiOperation( + consumes = MediaType.APPLICATION_JSON, + produces = MediaType.APPLICATION_JSON, + httpMethod = "POST", + value = "Uninstall an application from the devices belong to an enterprise entity", + notes = "This will uninstall an application from devices belong to given list of groups/users/roles", + tags = "Subscription Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = SCOPE, value = "perm:subscription:uninstall") + }) + } + ) + @ApiResponses( + value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully uninstalled the application.", + response = Application.class + ), + @ApiResponse( + code = 304, + message = "Not Modified. \n Empty body because the application is already uninstalled." + ), + @ApiResponse( + code = 404, + message = "Not Found. \n Application cannot be found to uninstall." + ), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Error occurred while uninstalling the application." + ) + }) + Response enterpriseUninstallApplication( + @ApiParam( + name = "enterpriseInstallationDetails", + value = "The application ID and list of groups/users/roles", + required = true + ) + @Valid EnterpriseInstallationDetails enterpriseInstallationDetails); + @GET @Path("/application/{applicationUUID}/device/{deviceId}") @Produces(MediaType.APPLICATION_JSON) @@ -173,23 +286,27 @@ public interface SubscriptionManagementAPI { @ApiResponse( code = 200, message = "OK. \n Successfully installed the application.", - response = Application.class), + response = Application.class + ), @ApiResponse( code = 304, message = "Not Modified. \n " + - "Empty body because the application is already installed."), + "Empty body because the application is already installed." + ), @ApiResponse( code = 500, - message = "Internal Server Error. \n Error occurred while fetching the application.", - response = ErrorResponse.class) + message = "Internal Server Error. \n Error occurred while fetching the application." + ) }) Response getApplication( @ApiParam( name = "applicationUUID", - value = "Application ID") + value = "Application ID" + ) @QueryParam("applicationUUID") String applicationUUID, @ApiParam( name = "deviceId", - value = "The device ID") + value = "The device ID" + ) @QueryParam("deviceId") String deviceId); } 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 54d38779f7b..0a290fe6fbb 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 @@ -20,6 +20,8 @@ package org.wso2.carbon.device.application.mgt.store.api.services.impl; import io.swagger.annotations.ApiParam; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.device.application.mgt.common.EnterpriseInstallationDetails; +import org.wso2.carbon.device.application.mgt.publisher.api.beans.ErrorResponse; import org.wso2.carbon.device.application.mgt.store.api.APIUtil; import org.wso2.carbon.device.application.mgt.publisher.api.services.SubscriptionManagementAPI; import org.wso2.carbon.device.application.mgt.common.DeviceIdentifier; @@ -34,6 +36,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Response; import java.util.HashMap; import java.util.List; +import java.util.stream.Stream; /** * Implementation of Subscription Management related APIs. @@ -47,33 +50,78 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{ @Override @POST @Path("/install-application") - public Response installApplication(@ApiParam(name = "installationDetails", value = "The application ID and list" + - " the devices/users/roles", required = true) @Valid InstallationDetails installationDetails) { - Object result; + public Response installApplication(@ApiParam(name = "installationDetails", value = "Application ID and list of" + + "devices", required = true) @Valid InstallationDetails installationDetails) { SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager(); + String applicationUUID = installationDetails.getApplicationUUID(); + + if (applicationUUID.isEmpty() || installationDetails.getDeviceIdentifiers().isEmpty()) { + String msg = "Some or all data in the incoming request is empty. Therefore unable to proceed with the " + + "installation."; + log.error(msg); + return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); + } + try { - String applicationUUID = installationDetails.getApplicationUUID(); - String versionName = installationDetails.getVersionName(); - if (!installationDetails.getDeviceIdentifiers().isEmpty()) { - List deviceList = installationDetails.getDeviceIdentifiers(); - result = subscriptionManager.installApplicationForDevices(applicationUUID, versionName, deviceList); - } else if (!installationDetails.getUserNameList().isEmpty()) { - List userList = installationDetails.getUserNameList(); - result = subscriptionManager.installApplicationForUsers(applicationUUID, userList, versionName); - } else if (!installationDetails.getRoleNameList().isEmpty()) { - List roleList = installationDetails.getRoleNameList(); - result = subscriptionManager.installApplicationForRoles(applicationUUID, roleList, versionName); + List failedDevices = subscriptionManager.installApplicationForDevices(applicationUUID, + installationDetails.getDeviceIdentifiers()); + HashMap response = new HashMap<>(); + response.put("failedDevices", failedDevices); + return Response.status(Response.Status.OK).entity(response).build(); + } catch (ApplicationManagementException e) { + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Error occurred while installing the application for devices" + ": " + e.getMessage()) + .build(); + } + } + + @Override + public Response enterpriseInstallApplication(EnterpriseInstallationDetails enterpriseInstallationDetails) { + SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager(); + String msg; + String applicationUUID = enterpriseInstallationDetails.getApplicationUUID(); + EnterpriseInstallationDetails.EnterpriseEntity enterpriseEntity = enterpriseInstallationDetails.getEntityType(); + List entityValueList = enterpriseInstallationDetails.getEntityValueList(); + List failedDevices; + + if (applicationUUID.isEmpty()) { + msg = "Application UUID is empty in the incoming request. Therefore unable to proceed with the " + + "installation."; + log.error(msg); + return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); + } + + if (enterpriseEntity == null || entityValueList.isEmpty()) { + msg = "Some or all details of the entity is empty in the incoming request. Therefore unable to proceed " + + "with the installation."; + log.error(msg); + return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); + } + + try{ + if (EnterpriseInstallationDetails.EnterpriseEntity.USER.equals(enterpriseEntity)) { + failedDevices = subscriptionManager + .installApplicationForUsers(applicationUUID, entityValueList); + } else if (EnterpriseInstallationDetails.EnterpriseEntity.ROLE.equals(enterpriseEntity)) { + failedDevices = subscriptionManager + .installApplicationForRoles(applicationUUID, entityValueList); + } else if (EnterpriseInstallationDetails.EnterpriseEntity.DEVICE_GROUP.equals(enterpriseEntity)) { + failedDevices = subscriptionManager + .installApplicationForGroups(applicationUUID, entityValueList); } else { - result = "Missing request data!"; - return Response.status(Response.Status.BAD_REQUEST).entity(result).build(); + msg = "Entity type does not match either USER, ROLE or DEVICE_GROUP. Therefore unable to proceed with " + + "the installation"; + log.error(msg); + return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); } + HashMap response = new HashMap<>(); - response.put("failedDevices", result); + response.put("failedDevices", failedDevices); return Response.status(Response.Status.OK).entity(response).build(); } catch (ApplicationManagementException e) { - String msg = "Error occurred while installing the application"; - log.error(msg, e); - return Response.status(Response.Status.BAD_REQUEST).build(); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Error occurred while installing the application for devices" + ": " + e.getMessage()) + .build(); } } @@ -83,6 +131,12 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{ return null; } + @Override + public Response enterpriseUninstallApplication( + EnterpriseInstallationDetails enterpriseInstallationDetails) { + return null; + } + @Override public Response getApplication(@ApiParam(name = "applicationUUID", value = "Application ID") String applicationUUID, @ApiParam(name = "deviceId", value = "The device ID")