Improving application subscription API

Changing the DeviceIdentifier bean to the same as org.wso2.carbon.device.mgt.common.DeviceIdentifier and implement the install app device.

Adding an ApplicationInstallResponse as the response to respond with more information to the application install request.

related to wso2/product-iots#1688
feature/appm-store/pbac
Madawa Soysa 7 years ago
parent f66ff60ada
commit debe93cb03

@ -58,6 +58,7 @@
org.apache.commons.codec.binary;version="${commons-codec.wso2.osgi.version.range}",
org.wso2.carbon.device.mgt.core.dto.*;version="${carbon.device.mgt.version}",
org.wso2.carbon.device.mgt.core.dao.*;version="${carbon.device.mgt.version}",
org.wso2.carbon.device.mgt.common.operation.mgt.*;version="${carbon.device.mgt.version}",
org.w3c.dom,
org.json,
org.xml.sax,
@ -114,6 +115,10 @@
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.core</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.common</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,71 @@
/*
* 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.ApiModelProperty;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.mgt.common.operation.mgt.Activity;
import java.util.List;
public class ApplicationInstallResponse {
@ApiModelProperty(
name = "successfulDevices",
value = "List of successful devices",
dataType = "List[org.wso2.carbon.device.mgt.common.DeviceIdentifier]"
)
private List<DeviceIdentifier> successfulDevices;
@ApiModelProperty(
name = "failedDevices",
value = "List of failed devices",
dataType = "List[org.wso2.carbon.device.mgt.common.DeviceIdentifier]"
)
private List<DeviceIdentifier> failedDevices;
@ApiModelProperty(
name = "activity",
value = "Activity corresponding to the operation"
)
private Activity activity;
public List<DeviceIdentifier> getSuccessfulDevices() {
return successfulDevices;
}
public void setSuccessfulDevices(List<DeviceIdentifier> successfulDevices) {
this.successfulDevices = successfulDevices;
}
public List<DeviceIdentifier> getFailedDevices() {
return failedDevices;
}
public void setFailedDevices(List<DeviceIdentifier> failedDevices) {
this.failedDevices = failedDevices;
}
public Activity getActivity() {
return activity;
}
public void setActivity(Activity activity) {
this.activity = activity;
}
}

@ -1,71 +0,0 @@
/*
* Copyright (c) 2014, 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;
@ApiModel(value = "DeviceIdentifier", description = "This contains device details that is used to identify a device " +
"uniquely.")
public class DeviceIdentifier {
@ApiModelProperty(
name = "id",
value = "Identity of the device.",
required = true,
example = "d24f870f390352a4")
private String id;
@ApiModelProperty(
name = "type",
value = "Type of the device.",
required = true,
example = "android")
private String type;
public DeviceIdentifier() {}
public DeviceIdentifier(String id, String type) {
this.id = id;
this.type = type;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type.trim();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return "deviceId {" +
"id='" + id + '\'' +
", type='" + type + '\'' +
'}';
}
}

@ -18,6 +18,7 @@
package org.wso2.carbon.device.application.mgt.common;
import io.swagger.annotations.ApiModelProperty;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import java.util.List;

@ -18,8 +18,9 @@
*/
package org.wso2.carbon.device.application.mgt.common.services;
import org.wso2.carbon.device.application.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.application.mgt.common.ApplicationInstallResponse;
import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import java.util.List;
@ -31,40 +32,40 @@ public interface SubscriptionManager {
* To install an application to given list of devices.
* @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
* @return {@link ApplicationInstallResponse} object which contains installed application and devices
* @throws ApplicationManagementException if unable to install the application to the given devices
*/
List<DeviceIdentifier> installApplicationForDevices(String applicationUUID, List<DeviceIdentifier> deviceList)
ApplicationInstallResponse installApplicationForDevices(String applicationUUID, List<DeviceIdentifier> deviceList)
throws ApplicationManagementException;
/**
* To install an application to given list of users.
* @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
* @return {@link ApplicationInstallResponse} object which contains installed application and devices
* @throws ApplicationManagementException if unable to install the application to devices belong to given users
*/
List<DeviceIdentifier> installApplicationForUsers(String applicationUUID, List<String> userList)
ApplicationInstallResponse installApplicationForUsers(String applicationUUID, List<String> userList)
throws ApplicationManagementException;
/**
* 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
* @return {@link ApplicationInstallResponse} object which contains installed application and devices
* @throws ApplicationManagementException if unable to install the application to devices belong to given roles
*/
List<DeviceIdentifier> installApplicationForRoles(String applicationUUID, List<String> roleList)
ApplicationInstallResponse installApplicationForRoles(String applicationUUID, List<String> 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
* @return {@link ApplicationInstallResponse} object which contains installed application and devices
* @throws ApplicationManagementException if unable to install the application to devices belong to given groups
*/
List<DeviceIdentifier> installApplicationForGroups(String applicationUUID, List<String> deviceGroupList)
ApplicationInstallResponse installApplicationForGroups(String applicationUUID, List<String> deviceGroupList)
throws ApplicationManagementException;
/**

@ -42,7 +42,7 @@
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>1.4.0</version>
<version>3.0.1</version>
<extensions>true</extensions>
<configuration>
<instructions>

@ -19,30 +19,31 @@ 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.Application;
import org.wso2.carbon.device.application.mgt.common.ApplicationInstallResponse;
import org.wso2.carbon.device.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.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.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 org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* This is the default implementation for the Subscription Manager.
@ -53,7 +54,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
private static final String INSTALL_APPLICATION = "INSTALL_APPLICATION";
@Override
public List<DeviceIdentifier> installApplicationForDevices(String applicationUUID,
public ApplicationInstallResponse installApplicationForDevices(String applicationUUID,
List<DeviceIdentifier> deviceList) throws ApplicationManagementException {
if (log.isDebugEnabled()) {
log.debug("Install application: " + applicationUUID + " to " + deviceList.size() + "devices.");
@ -62,7 +63,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
}
@Override
public List<DeviceIdentifier> installApplicationForUsers(String applicationUUID, List<String> userList)
public ApplicationInstallResponse installApplicationForUsers(String applicationUUID, List<String> userList)
throws ApplicationManagementException {
if (log.isDebugEnabled()) {
log.debug("Install application: " + applicationUUID + " to " + userList.size() + " users.");
@ -86,7 +87,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
}
@Override
public List<DeviceIdentifier> installApplicationForRoles(String applicationUUID, List<String> roleList)
public ApplicationInstallResponse installApplicationForRoles(String applicationUUID, List<String> roleList)
throws ApplicationManagementException {
if (log.isDebugEnabled()) {
log.debug("Install application: " + applicationUUID + " to " + roleList.size() + " roles.");
@ -110,7 +111,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
}
@Override
public List<DeviceIdentifier> installApplicationForGroups(String applicationUUID, List<String> deviceGroupList)
public ApplicationInstallResponse installApplicationForGroups(String applicationUUID, List<String> deviceGroupList)
throws ApplicationManagementException {
if (log.isDebugEnabled()) {
log.debug("Install application: " + applicationUUID + " to " + deviceGroupList.size() + " groups.");
@ -140,16 +141,92 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
return null;
}
private List<DeviceIdentifier> installApplication(String applicationUUID, List<DeviceIdentifier> deviceList)
private ApplicationInstallResponse installApplication(String applicationUUID, List<DeviceIdentifier> 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;
DeviceManagementProviderService deviceManagementProviderService = HelperUtil
.getDeviceManagementProviderService();
ApplicationManager applicationManager = ApplicationManagementUtil.getApplicationManagerInstance();
Application application = applicationManager.getApplicationByRelease(applicationUUID);
ApplicationInstallResponse response = validateDevices(deviceList, application.getType());
Map<String, List<DeviceIdentifier>> deviceTypeIdentifierMap = response.getSuccessfulDevices().stream()
.collect(Collectors.groupingBy(DeviceIdentifier::getType));
for(Map.Entry<String, List<DeviceIdentifier>> entry: deviceTypeIdentifierMap.entrySet()) {
Operation operation = generateOperationPayloadByDeviceType(entry.getKey(), application);
try {
Activity activity = deviceManagementProviderService
.addOperation(entry.getKey(), operation, entry.getValue());
response.setActivity(activity);
} catch (OperationManagementException e) {
throw new ApplicationManagementException("Error occurred while adding the application install"
+ " operation to devices" , e);
} catch (InvalidDeviceException e) {
//This exception should not occur because the validation has already been done.
throw new ApplicationManagementException("The list of device identifiers are invalid");
}
}
//todo: add device application mapping
return response;
}
private Operation generateOperationPayloadByDeviceType(String deviceType, Application application) {
ProfileOperation operation = new ProfileOperation();
operation.setCode(INSTALL_APPLICATION);
operation.setType(Operation.Type.PROFILE);
//todo: generate operation payload correctly for all types of devices.
operation.setPayLoad(
"{'type':'enterprise', 'url':'" + application.getApplicationReleases().get(0).getAppStoredLoc()
+ "', 'app':'" + application.getApplicationReleases().get(0).getUuid() + "'}");
return operation;
}
/**
* Validates the preconditions which is required to satisfy from the device which is required to install the
* application.
*
* This method check two preconditions whether the application type is compatible to install in the device and
* whether the device is enrolled in the system.
*
* @param deviceIdentifierList List of {@link DeviceIdentifier} which the validation happens
* @param appPlatform type of the application
* @return {@link ApplicationInstallResponse} which contains compatible and incompatible device identifiers
*/
private ApplicationInstallResponse validateDevices(List<DeviceIdentifier> deviceIdentifierList,
String appPlatform) {
ApplicationInstallResponse applicationInstallResponse = new ApplicationInstallResponse();
List<DeviceIdentifier> failedDevices = new ArrayList<>();
List<DeviceIdentifier> compatibleDevices = new ArrayList<>();
for (DeviceIdentifier deviceIdentifier : deviceIdentifierList) {
try {
if (appPlatform == null || !(appPlatform.equals("WEB_CLIP") || appPlatform
.equals(deviceIdentifier.getType()))) {
log.error("Device with ID: [" + deviceIdentifier.getId() + "] of type: ["
+ deviceIdentifier.getType() + "] is not compatible with the application of type: ["
+ appPlatform + "]");
failedDevices.add(deviceIdentifier);
continue;
}
if (!DeviceManagerUtil.isValidDeviceIdentifier(deviceIdentifier)) {
log.error("Device with ID: [" + deviceIdentifier.getId() + "] is not valid to install the "
+ "application.");
applicationInstallResponse.getFailedDevices().add(deviceIdentifier);
}
} catch (DeviceManagementException e) {
log.error("Error occurred while validating the device: [" + deviceIdentifier.getId() + "]", e);
failedDevices.add(deviceIdentifier);
}
compatibleDevices.add(deviceIdentifier);
}
applicationInstallResponse.setFailedDevices(failedDevices);
applicationInstallResponse.setSuccessfulDevices(compatibleDevices);
return applicationInstallResponse;
}
}

@ -163,6 +163,10 @@
<artifactId>org.wso2.carbon.device.application.mgt.common</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.mgt.common</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>

@ -29,6 +29,7 @@ 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.common.Application;
import org.wso2.carbon.device.application.mgt.common.ApplicationInstallResponse;
import org.wso2.carbon.device.application.mgt.common.EnterpriseInstallationDetails;
import org.wso2.carbon.device.application.mgt.common.InstallationDetails;
@ -107,8 +108,8 @@ public interface SubscriptionManagementAPI {
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully installed the application.",
response = Application.class
message = "OK. \n Successfully sent the install application operation.",
response = ApplicationInstallResponse.class
),
@ApiResponse(
code = 304,
@ -152,8 +153,8 @@ public interface SubscriptionManagementAPI {
value = {
@ApiResponse(
code = 200,
message = "OK. \n Successfully installed the application.",
response = Application.class
message = "OK. \n Successfully sent the install application operation.",
response = ApplicationInstallResponse.class
),
@ApiResponse(
code = 304,

@ -20,14 +20,14 @@ 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.ApplicationInstallResponse;
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;
import org.wso2.carbon.device.application.mgt.common.InstallationDetails;
import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException;
import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager;
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
import javax.validation.Valid;
import javax.ws.rs.POST;
@ -36,7 +36,6 @@ 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.
@ -63,10 +62,8 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
}
try {
List<DeviceIdentifier> failedDevices = subscriptionManager.installApplicationForDevices(applicationUUID,
ApplicationInstallResponse response= subscriptionManager.installApplicationForDevices(applicationUUID,
installationDetails.getDeviceIdentifiers());
HashMap<String, Object> 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)
@ -82,7 +79,7 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
String applicationUUID = enterpriseInstallationDetails.getApplicationUUID();
EnterpriseInstallationDetails.EnterpriseEntity enterpriseEntity = enterpriseInstallationDetails.getEntityType();
List<String> entityValueList = enterpriseInstallationDetails.getEntityValueList();
List<DeviceIdentifier> failedDevices;
ApplicationInstallResponse response;
if (applicationUUID.isEmpty()) {
msg = "Application UUID is empty in the incoming request. Therefore unable to proceed with the "
@ -100,14 +97,11 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
try{
if (EnterpriseInstallationDetails.EnterpriseEntity.USER.equals(enterpriseEntity)) {
failedDevices = subscriptionManager
.installApplicationForUsers(applicationUUID, entityValueList);
response = subscriptionManager.installApplicationForUsers(applicationUUID, entityValueList);
} else if (EnterpriseInstallationDetails.EnterpriseEntity.ROLE.equals(enterpriseEntity)) {
failedDevices = subscriptionManager
.installApplicationForRoles(applicationUUID, entityValueList);
response = subscriptionManager.installApplicationForRoles(applicationUUID, entityValueList);
} else if (EnterpriseInstallationDetails.EnterpriseEntity.DEVICE_GROUP.equals(enterpriseEntity)) {
failedDevices = subscriptionManager
.installApplicationForGroups(applicationUUID, entityValueList);
response = subscriptionManager.installApplicationForGroups(applicationUUID, entityValueList);
} else {
msg = "Entity type does not match either USER, ROLE or DEVICE_GROUP. Therefore unable to proceed with "
+ "the installation";
@ -115,8 +109,6 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
return Response.status(Response.Status.BAD_REQUEST).entity(msg).build();
}
HashMap<String, Object> 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)

Loading…
Cancel
Save