diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/DeviceSubscriptionData.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/DeviceSubscriptionData.java new file mode 100644 index 00000000000..3afac36acde --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/DeviceSubscriptionData.java @@ -0,0 +1,80 @@ +/* Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved. + * + * Entgra (Pvt) Ltd. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.device.application.mgt.common; + +import org.wso2.carbon.device.mgt.common.Device; + +import java.sql.Timestamp; + +public class DeviceSubscriptionData { + + private String action; + private Timestamp actionTriggeredTimestamp; + private String actionTriggeredBy; + private String actionType; + private String status; + private Device device; + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + public Timestamp getActionTriggeredTimestamp() { + return actionTriggeredTimestamp; + } + + public void setActionTriggeredTimestamp(Timestamp actionTriggeredTimestamp) { + this.actionTriggeredTimestamp = actionTriggeredTimestamp; + } + + public String getActionTriggeredBy() { + return actionTriggeredBy; + } + + public void setActionTriggeredBy(String actionTriggeredBy) { + this.actionTriggeredBy = actionTriggeredBy; + } + + public String getActionType() { + return actionType; + } + + public void setActionType(String actionType) { + this.actionType = actionType; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Device getDevice() { + return device; + } + + public void setDevice(Device device) { + this.device = device; + } +} 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 77b21e688db..b4b55e6edb3 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 @@ -108,4 +108,18 @@ public interface SubscriptionManager { */ PaginationResult getAppInstalledCategories(int offsetValue, int limitValue, String appUUID, String subType) throws ApplicationManagementException; + + /** + * This method is responsible to provide application subscription data for given application release UUID. + * + * @param offsetValue offset + * @param limitValue limit + * @param appUUID application release UUID + * @return {@link PaginationResult} + * @throws ApplicationManagementException if offset or limit contains incorrect values, if it couldn't find an + * application release for given UUID, if an error occurred while getting device details of subscribed device ids, + * if an error occurred while getting subscription details of given application release UUID. + */ + PaginationResult getAppSubscriptionDetails(int offsetValue, int limitValue, String appUUID) + 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/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 ca294e7495e..9dc7a152db4 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 @@ -30,6 +30,7 @@ import org.wso2.carbon.apimgt.application.extension.exception.APIManagerExceptio import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.application.mgt.common.ApplicationInstallResponse; import org.wso2.carbon.device.application.mgt.common.ApplicationType; +import org.wso2.carbon.device.application.mgt.common.DeviceSubscriptionData; import org.wso2.carbon.device.application.mgt.common.DeviceTypes; import org.wso2.carbon.device.application.mgt.common.ExecutionStatus; import org.wso2.carbon.device.application.mgt.common.SubAction; @@ -315,6 +316,15 @@ public class SubscriptionManagerImpl implements SubscriptionManager { } } + /** + * THis method is responsible to validate application install or uninstall request. + * + * @param params params could be either list of {@link DeviceIdentifier} or list of username or list of group + * names or list or role names. + * @param subType Subscription type. i.e DEVICE or USER or ROLE or GROUP + * @param action performing action. i.e Install or Uninstall + * @throws BadRequestException if incompatible data is found with app install/uninstall request. + */ private void validateRequest(List params, String subType, String action) throws BadRequestException { if (params.isEmpty()) { String msg = "In order to install application release, you should provide list of subscribers. " @@ -338,7 +348,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager { } } - /*** + /** * This method perform given action (i.e APP INSTALL or APP UNINSTALL) on given set of devices. * * @param deviceType Application supported device type. @@ -424,7 +434,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager { return applicationInstallResponse; } - /*** + /** * Filter given devices and davide given list of device into two sets, those are already application installed * devices and application installable devices. * @@ -469,6 +479,13 @@ public class SubscriptionManagerImpl implements SubscriptionManager { return subscribingDeviceIdHolder; } + /** + * This method returns the application categories of a particular application + * + * @param id Application Id + * @return List of application categories. + * @throws ApplicationManagementException if error occurred while getting application categories from the DB. + */ private List getApplicationCategories(int id) throws ApplicationManagementException { List categories; int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true); @@ -528,6 +545,18 @@ public class SubscriptionManagerImpl implements SubscriptionManager { } } + /** + * This method is responsible to update subscription data. + * + * @param applicationReleaseId Application release Id + * @param activities List of {@link Activity} + * @param subscribingDeviceIdHolder Subscribing device id holder. + * @param params subscribers. If subscription is performed via user, group or role, params is a list of + * {@link String} + * @param subType Subscription type. i.e USER, GROUP, ROLE or DEVICE + * @param action performing action. ie INSTALL or UNINSTALL> + * @throws ApplicationManagementException if error occurred while getting or updating subscription data. + */ private void updateSubscriptions(int applicationReleaseId, List activities, SubscribingDeviceIdHolder subscribingDeviceIdHolder, List params, String subType, String action) throws ApplicationManagementException { @@ -685,6 +714,16 @@ public class SubscriptionManagerImpl implements SubscriptionManager { } } + /** + * This method constructs operation payload to install/uninstall an application. + * + * @param deviceType Device type + * @param application {@link Application} data. + * @param action Action is either ININSTALL or UNINSTALL + * @return {@link Operation} + * @throws ApplicationManagementException if unknown application type is found to generate operation payload or + * invalid action is found to generate operation payload. + */ private Operation generateOperationPayloadByDeviceType(String deviceType, Application application, String action) throws ApplicationManagementException { try { @@ -865,7 +904,6 @@ public class SubscriptionManagerImpl implements SubscriptionManager { throw new ApplicationManagementException(msg, e); } } catch (ApplicationManagementDAOException e) { - ConnectionManagerUtil.rollbackDBTransaction(); String msg = "Error occurred when get application release data for application" + " release UUID: " + appUUID; log.error(msg, e); @@ -881,8 +919,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager { } @Override - public PaginationResult getAppInstalledCategories(int offsetValue, int limitValue, - String appUUID, String subType) + public PaginationResult getAppInstalledCategories(int offsetValue, int limitValue, String appUUID, String subType) throws ApplicationManagementException { int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true); @@ -893,28 +930,24 @@ public class SubscriptionManagerImpl implements SubscriptionManager { .getAppWithRelatedRelease(appUUID, tenantId); int applicationReleaseId = applicationDTO.getApplicationReleaseDTOs().get(0).getId(); - int count = 0; - List SubscriptionList = new ArrayList<>(); + List subscriptionList = new ArrayList<>(); if (SubscriptionType.USER.toString().equalsIgnoreCase(subType)) { - SubscriptionList = subscriptionDAO + subscriptionList = subscriptionDAO .getAppSubscribedUsers(offsetValue, limitValue, applicationReleaseId, tenantId); } else if (SubscriptionType.ROLE.toString().equalsIgnoreCase(subType)) { - SubscriptionList = subscriptionDAO + subscriptionList = subscriptionDAO .getAppSubscribedRoles(offsetValue, limitValue, applicationReleaseId, tenantId); } else if (SubscriptionType.GROUP.toString().equalsIgnoreCase(subType)) { - SubscriptionList = subscriptionDAO + subscriptionList = subscriptionDAO .getAppSubscribedGroups(offsetValue, limitValue, applicationReleaseId, tenantId); } - count = SubscriptionList.size(); - paginationResult.setData(SubscriptionList); + int count = subscriptionList.size(); + paginationResult.setData(subscriptionList); paginationResult.setRecordsFiltered(count); paginationResult.setRecordsTotal(count); - return paginationResult; - } catch (ApplicationManagementDAOException e) { - ConnectionManagerUtil.rollbackDBTransaction(); String msg = "Error occurred when get application release data for application" + " release UUID: " + appUUID; log.error(msg, e); @@ -928,4 +961,97 @@ public class SubscriptionManagerImpl implements SubscriptionManager { ConnectionManagerUtil.closeDBConnection(); } } + + @Override + public PaginationResult getAppSubscriptionDetails(int offsetValue, int limitValue, String appUUID) + throws ApplicationManagementException { + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true); + DeviceManagementProviderService deviceManagementProviderService = HelperUtil + .getDeviceManagementProviderService(); + if (offsetValue < 0 || limitValue <= 0) { + String msg = "Found incompatible values for offset and limit. Hence please check the request and resend. " + + "Offset " + offsetValue + " limit " + limitValue; + log.error(msg); + throw new BadRequestException(msg); + } + + try { + ConnectionManagerUtil.openDBConnection(); + ApplicationDTO applicationDTO = this.applicationDAO.getAppWithRelatedRelease(appUUID, tenantId); + if (applicationDTO == null) { + String msg = "Couldn't find an application with application release which has UUID " + appUUID; + log.error(msg); + throw new NotFoundException(msg); + } + int applicationReleaseId = applicationDTO.getApplicationReleaseDTOs().get(0).getId(); + + List deviceSubscriptionDTOS = subscriptionDAO + .getDeviceSubscriptions(applicationReleaseId, tenantId); + if (deviceSubscriptionDTOS.isEmpty()) { + String msg = "Couldn't found an subscribed devices for application release id: " + applicationReleaseId; + log.info(msg); + } + List deviceIdList = deviceSubscriptionDTOS.stream().map(DeviceSubscriptionDTO::getDeviceId) + .collect(Collectors.toList()); + if (deviceIdList.isEmpty()) { + PaginationResult paginationResult = new PaginationResult(); + paginationResult.setData(deviceIdList); + paginationResult.setRecordsFiltered(0); + paginationResult.setRecordsTotal(0); + return paginationResult; + } + try { + //pass the device id list to device manager service method + PaginationResult paginationResult = deviceManagementProviderService + .getAppSubscribedDevices(offsetValue, limitValue, deviceIdList, null); + List deviceSubscriptionDataList = new ArrayList<>(); + + if (!paginationResult.getData().isEmpty()) { + List devices = (List) paginationResult.getData(); + for (Device device : devices) { + DeviceSubscriptionData deviceSubscriptionData = new DeviceSubscriptionData(); + for (DeviceSubscriptionDTO subscription : deviceSubscriptionDTOS) { + if (subscription.getDeviceId() == device.getId()) { + deviceSubscriptionData.setDevice(device); + if (subscription.isUnsubscribed()) { + deviceSubscriptionData.setAction(Constants.UNSUBSCRIBED); + deviceSubscriptionData.setActionTriggeredBy(subscription.getUnsubscribedBy()); + deviceSubscriptionData + .setActionTriggeredTimestamp(subscription.getUnsubscribedTimestamp()); + } else { + deviceSubscriptionData.setAction(Constants.SUBSCRIBED); + deviceSubscriptionData.setActionTriggeredBy(subscription.getSubscribedBy()); + deviceSubscriptionData + .setActionTriggeredTimestamp(subscription.getSubscribedTimestamp()); + } + deviceSubscriptionData.setActionType(subscription.getActionTriggeredFrom()); + deviceSubscriptionData.setStatus(subscription.getStatus()); + deviceSubscriptionDataList.add(deviceSubscriptionData); + break; + } + } + } + } + paginationResult.setData(deviceSubscriptionDataList); + return paginationResult; + } catch (DeviceManagementException e) { + String msg = "service error occurred while getting device data from the device management service. " + + "Device ids " + deviceIdList; + log.error(msg, e); + throw new ApplicationManagementException(msg, e); + } + } catch (ApplicationManagementDAOException e) { + String msg = "Error occurred when getting application release data for application release UUID: " + + appUUID; + log.error(msg, e); + throw new ApplicationManagementException(msg, e); + } catch (DBConnectionException e) { + String msg = "DB Connection error occurred while trying to get subscription data of application which has " + + "application release UUID " + appUUID; + log.error(msg, e); + throw new ApplicationManagementException(msg, e); + } finally { + ConnectionManagerUtil.closeDBConnection(); + } + } } 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 f42c4beefa4..0f58452f540 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 @@ -58,6 +58,9 @@ public class Constants { 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"; + public static final String SUBSCRIBED = "SUBSCRIBED"; + public static final String UNSUBSCRIBED = "UNSUBSCRIBED"; + /** * Database types supported by Application Management. 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/admin/ReviewManagementStoreAdminAPI.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/admin/ReviewManagementStoreAdminAPI.java index a1d7a77de15..359d633e043 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/admin/ReviewManagementStoreAdminAPI.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/admin/ReviewManagementStoreAdminAPI.java @@ -49,7 +49,7 @@ info = @Info( extensions = { @Extension(properties = { @ExtensionProperty(name = "name", value = "StoreReviewManagementAdminService"), - @ExtensionProperty(name = "context", value = "/api/application-mgt-store/v1.0/admin/review"), + @ExtensionProperty(name = "context", value = "/api/application-mgt-store/v1.0/admin/reviews"), }) } ), @@ -70,14 +70,13 @@ scopes = { @Path("/admin/reviews") @Api(value = "Store Review Management Admin API") -@Produces(MediaType.APPLICATION_JSON) public interface ReviewManagementStoreAdminAPI { String SCOPE = "scope"; @DELETE @Path("/{uuid}/{reviewId}") - @Produces(MediaType.APPLICATION_JSON) - @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.WILDCARD) + @Consumes(MediaType.WILDCARD) @ApiOperation( consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON, 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/admin/SubscriptionManagementAdminAPI.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/admin/SubscriptionManagementAdminAPI.java new file mode 100644 index 00000000000..904e6acdd6c --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/admin/SubscriptionManagementAdminAPI.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.wso2.carbon.device.application.mgt.store.api.services.admin; + +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.common.ErrorResponse; +import org.wso2.carbon.device.mgt.common.DeviceIdentifier; + +import javax.validation.Valid; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.List; + +/** + * API to handle subscription management related admin tasks. + */ +@SwaggerDefinition( + info = @Info( + version = "1.0.0", + title = "Subscription Management Admin Service", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = "name", value = "SubscriptionManagementAdminService"), + @ExtensionProperty(name = "context", value = "/api/application-mgt-store/v1.0/admin/subscription"), + }) + } + ), + tags = { + @Tag(name = "subscription_management, device_management", description = "Subscription Management " + + "related Admin APIs") + } +) +@Scopes( + scopes = { + @org.wso2.carbon.apimgt.annotations.api.Scope( + name = "View Application Subscriptions", + description = "View Application Subscriptions.", + key = "perm:admin:app:subscription:view", + permissions = {"/app-mgt/store/admin/subscription/view"} + ) + } +) +@Path("/admin/subscription") +@Api(value = "Subscription Management Admin API") +@Produces(MediaType.APPLICATION_JSON) +public interface SubscriptionManagementAdminAPI { + + String SCOPE = "scope"; + + @GET + @Path("/{uuid}") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @ApiOperation( + consumes = MediaType.APPLICATION_JSON, + produces = MediaType.APPLICATION_JSON, + httpMethod = "GET", + value = "Get subscription details of specific application.", + notes = "This will get the subscription details of specific application", + tags = "Subscription Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = SCOPE, value = "perm:app:subscription:view") + }) + } + ) + @ApiResponses( + value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully retrieved subscription details.", + response = List.class, + responseContainer = "List"), + @ApiResponse( + code = 404, + message = "Not Found. \n No Application found which has application release of UUID.", + response = ErrorResponse.class), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Error occurred while getting data", + response = ErrorResponse.class) + }) + Response getAppInstalledDevices( + @ApiParam( + name = "uuid", + value = "uuid of the application release.", + required = true) + @PathParam("uuid") String uuid, + @ApiParam( + name = "offset", + value = "The starting pagination index for the complete list of qualified items.", + defaultValue = "0") + @QueryParam("offset") int offset, + @ApiParam( + name = "limit", + value = "Provide how many device details you require from the starting pagination index/offset.", + defaultValue = "5") + @QueryParam("limit") int limit + ); +} 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/admin/ReviewManagementStoreAdminAPIImpl.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/admin/ReviewManagementStoreAdminAPIImpl.java index e0f594946c8..d2725e7d9ff 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/admin/ReviewManagementStoreAdminAPIImpl.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/admin/ReviewManagementStoreAdminAPIImpl.java @@ -18,9 +18,6 @@ package org.wso2.carbon.device.application.mgt.store.api.services.impl.admin; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.device.application.mgt.common.PaginationRequest; -import org.wso2.carbon.device.application.mgt.common.PaginationResult; -import org.wso2.carbon.device.application.mgt.common.Rating; import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException; import org.wso2.carbon.device.application.mgt.common.exception.ReviewManagementException; import org.wso2.carbon.device.application.mgt.common.services.ReviewManager; @@ -28,9 +25,12 @@ import org.wso2.carbon.device.application.mgt.core.exception.NotFoundException; import org.wso2.carbon.device.application.mgt.core.util.APIUtil; import org.wso2.carbon.device.application.mgt.store.api.services.admin.ReviewManagementStoreAdminAPI; +import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; /** @@ -44,6 +44,8 @@ public class ReviewManagementStoreAdminAPIImpl implements ReviewManagementStoreA @Override @DELETE @Path("/{uuid}/{reviewId}") + @Produces(MediaType.WILDCARD) + @Consumes(MediaType.WILDCARD) public Response deleteReview( @PathParam("uuid") String uuid, @PathParam("reviewId") int reviewId) { 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/admin/SubscriptionManagementAdminAPIImpl.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/admin/SubscriptionManagementAdminAPIImpl.java new file mode 100644 index 00000000000..5dde7a6a379 --- /dev/null +++ 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/admin/SubscriptionManagementAdminAPIImpl.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved. + * + * Entgra (Pvt) Ltd. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.device.application.mgt.store.api.services.impl.admin; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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.application.mgt.core.exception.BadRequestException; +import org.wso2.carbon.device.application.mgt.core.exception.NotFoundException; +import org.wso2.carbon.device.application.mgt.core.util.APIUtil; +import org.wso2.carbon.device.application.mgt.store.api.services.admin.SubscriptionManagementAdminAPI; +import org.wso2.carbon.device.mgt.common.PaginationResult; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Response; + +/** + * Implementation of Subscription Management related APIs. + */ +@Produces({"application/json"}) +@Path("/admin/subscription") +public class SubscriptionManagementAdminAPIImpl implements SubscriptionManagementAdminAPI { + + private static Log log = LogFactory.getLog(SubscriptionManagementAdminAPIImpl.class); + + @GET + @Consumes("application/json") + @Produces("application/json") + @Path("/{uuid}") + public Response getAppInstalledDevices( + @PathParam("uuid") String uuid, + @DefaultValue("0") + @QueryParam("offset") int offset, + @DefaultValue("5") + @QueryParam("limit") int limit) { + + try { + SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager(); + PaginationResult subscriptionData = subscriptionManager + .getAppSubscriptionDetails(offset, limit, uuid); + return Response.status(Response.Status.OK).entity(subscriptionData).build(); + } catch (NotFoundException e) { + String msg = "Application with application release UUID: " + uuid + " is not found"; + log.error(msg, e); + return Response.status(Response.Status.NOT_FOUND).entity(msg).build(); + } catch (BadRequestException e) { + String msg = "Found invalid payload for getting application which has UUID: " + uuid + + ". Hence verify the payload"; + log.error(msg, e); + return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); + } catch (ApplicationManagementException e) { + String msg = "Error occurred while getting app installed devices which has application release UUID of: " + + uuid; + log.error(msg, e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); + } + } +} diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/webapp/WEB-INF/cxf-servlet.xml b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/webapp/WEB-INF/cxf-servlet.xml index 3176ee95c77..3488f6e8bcf 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/webapp/WEB-INF/cxf-servlet.xml +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/webapp/WEB-INF/cxf-servlet.xml @@ -24,6 +24,7 @@ + @@ -55,6 +56,7 @@ + diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java index 5214baf9621..695a9766c81 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java @@ -576,8 +576,18 @@ public interface DeviceDAO { * @param limitValue limit value for get paginated request. * @param status status of the devices. * @return devices - subscribed device details list - * @throws {@link DeviceManagementDAOException} if connections establishment fails. + * @throws DeviceManagementDAOException if connections establishment fails. */ List getSubscribedDevices(int offsetValue, int limitValue, List deviceIds, int tenantId, String status) throws DeviceManagementDAOException; + + /** + * @param deviceIds device ids of the subscribed devices. + * @param tenantId tenant id + * @param status current status of the device. (e.g ACTIVE, REMOVED, etc) + * @return number of subscribed device count. + * @throws DeviceManagementDAOException if error occurred while processing the SQL statement. + */ + int getSubscribedDeviceCount(List deviceIds, int tenantId, String status) + throws DeviceManagementDAOException; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java index a902860015a..a4a50e0429f 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java @@ -18,6 +18,7 @@ package org.wso2.carbon.device.mgt.core.dao.impl.device; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.device.mgt.common.Device; @@ -645,6 +646,52 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl { } } + @Override + public int getSubscribedDeviceCount(List deviceIds, int tenantId, String status) + throws DeviceManagementDAOException { + try { + Connection conn = this.getConnection(); + int index = 1; + StringJoiner joiner = new StringJoiner(",", + "SELECT " + + "COUNT(e.DEVICE_ID) AS DEVICE_ID "+ + "FROM DM_ENROLMENT AS e, DM_DEVICE AS f "+ + "WHERE " + + "e.DEVICE_ID=f.ID AND " + + "e.DEVICE_ID IN (", ") AND e.TENANT_ID = ?"); + + deviceIds.stream().map(ignored -> "?").forEach(joiner::add); + String query = joiner.toString(); + + if (!StringUtils.isBlank(status)) { + query = query + " AND e.STATUS = ?"; + } + + try (PreparedStatement ps = conn.prepareStatement(query)) { + for (Integer deviceId : deviceIds) { + ps.setObject(index++, deviceId); + } + + ps.setInt(index++, tenantId); + if (!StringUtils.isBlank(status)) { + ps.setString(index, status); + } + + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + return rs.getInt("DEVICE_ID"); + } + return 0; + } + } + } catch (SQLException e) { + String msg = "Error occurred while retrieving information of all registered devices " + + "according to device ids and the limit area."; + log.error(msg, e); + throw new DeviceManagementDAOException(msg, e); + } + } + private Connection getConnection() throws SQLException { return DeviceManagementDAOFactory.getConnection(); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java index e467fac0cf8..a1e496513f5 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java @@ -18,6 +18,7 @@ package org.wso2.carbon.device.mgt.core.dao.impl.device; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.device.mgt.common.Device; @@ -648,6 +649,52 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl { } } + @Override + public int getSubscribedDeviceCount(List deviceIds, int tenantId, String status) + throws DeviceManagementDAOException { + try { + Connection conn = this.getConnection(); + int index = 1; + StringJoiner joiner = new StringJoiner(",", + "SELECT " + + "COUNT(e.DEVICE_ID) AS DEVICE_ID "+ + "FROM DM_ENROLMENT AS e, DM_DEVICE AS f "+ + "WHERE " + + "e.DEVICE_ID=f.ID AND " + + "e.DEVICE_ID IN (", ") AND e.TENANT_ID = ?"); + + deviceIds.stream().map(ignored -> "?").forEach(joiner::add); + String query = joiner.toString(); + + if (!StringUtils.isBlank(status)) { + query = query + " AND e.STATUS = ?"; + } + + try (PreparedStatement ps = conn.prepareStatement(query)) { + for (Integer deviceId : deviceIds) { + ps.setObject(index++, deviceId); + } + + ps.setInt(index++, tenantId); + if (!StringUtils.isBlank(status)) { + ps.setString(index, status); + } + + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + return rs.getInt("DEVICE_ID"); + } + return 0; + } + } + } catch (SQLException e) { + String msg = "Error occurred while retrieving information of all registered devices " + + "according to device ids and the limit area."; + log.error(msg, e); + throw new DeviceManagementDAOException(msg, e); + } + } + private Connection getConnection() throws SQLException { return DeviceManagementDAOFactory.getConnection(); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java index f8bb373174a..97f43c15542 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java @@ -18,6 +18,7 @@ package org.wso2.carbon.device.mgt.core.dao.impl.device; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.device.mgt.common.Device; @@ -628,6 +629,52 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl { } } + @Override + public int getSubscribedDeviceCount(List deviceIds, int tenantId, String status) + throws DeviceManagementDAOException { + try { + Connection conn = this.getConnection(); + int index = 1; + StringJoiner joiner = new StringJoiner(",", + "SELECT " + + "COUNT(e.DEVICE_ID) AS DEVICE_ID "+ + "FROM DM_ENROLMENT AS e, DM_DEVICE AS f "+ + "WHERE " + + "e.DEVICE_ID=f.ID AND " + + "e.DEVICE_ID IN (", ") AND e.TENANT_ID = ?"); + + deviceIds.stream().map(ignored -> "?").forEach(joiner::add); + String query = joiner.toString(); + + if (!StringUtils.isBlank(status)) { + query = query + " AND e.STATUS = ?"; + } + + try (PreparedStatement ps = conn.prepareStatement(query)) { + for (Integer deviceId : deviceIds) { + ps.setObject(index++, deviceId); + } + + ps.setInt(index++, tenantId); + if (!StringUtils.isBlank(status)) { + ps.setString(index, status); + } + + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + return rs.getInt("DEVICE_ID"); + } + return 0; + } + } + } catch (SQLException e) { + String msg = "Error occurred while retrieving information of all registered devices " + + "according to device ids and the limit area."; + log.error(msg, e); + throw new DeviceManagementDAOException(msg, e); + } + } + private Connection getConnection() throws SQLException { return DeviceManagementDAOFactory.getConnection(); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java index 1b9134343e9..1ee4657210f 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java @@ -18,6 +18,7 @@ package org.wso2.carbon.device.mgt.core.dao.impl.device; +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.device.mgt.common.Device; @@ -650,4 +651,50 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl { } return devices; } + + @Override + public int getSubscribedDeviceCount(List deviceIds, int tenantId, String status) + throws DeviceManagementDAOException { + try { + Connection conn = this.getConnection(); + int index = 1; + StringJoiner joiner = new StringJoiner(",", + "SELECT " + + "COUNT(e.DEVICE_ID) AS DEVICE_ID "+ + "FROM DM_ENROLMENT AS e, DM_DEVICE AS f "+ + "WHERE " + + "e.DEVICE_ID=f.ID AND " + + "e.DEVICE_ID IN (", ") AND e.TENANT_ID = ?"); + + deviceIds.stream().map(ignored -> "?").forEach(joiner::add); + String query = joiner.toString(); + + if (!StringUtils.isBlank(status)) { + query = query + " AND e.STATUS = ?"; + } + + try (PreparedStatement ps = conn.prepareStatement(query)) { + for (Integer deviceId : deviceIds) { + ps.setObject(index++, deviceId); + } + + ps.setInt(index++, tenantId); + if (!StringUtils.isBlank(status)) { + ps.setString(index, status); + } + + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + return rs.getInt("DEVICE_ID"); + } + return 0; + } + } + } catch (SQLException e) { + String msg = "Error occurred while retrieving information of all registered devices " + + "according to device ids and the limit area."; + log.error(msg, e); + throw new DeviceManagementDAOException(msg, e); + } + } } \ 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/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 a78de8cbc20..43bb5ba7132 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 @@ -802,9 +802,8 @@ public interface DeviceManagementProviderService { * @param limitValue limit value for get paginated request. * @param status status of the devices. * @return {@link PaginationResult} - * @throws {@link DeviceManagementException} if any service level or DAO level error occurs. + * @throws DeviceManagementException if any service level or DAO level error occurs. */ PaginationResult getAppSubscribedDevices(int offsetValue, int limitValue, - List devicesIds, String status) - throws DeviceManagementException; + List devicesIds, String status) 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 b700a53bdb4..794d679652f 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 @@ -3702,31 +3702,9 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } } - /** - * Wrap the device configuration data into DeviceConfiguration bean - * @param device Device queried using the properties - * @param tenantDomain tenant domain - * @param configurationEntries platformConfiguration list - * @param deviceOwner name of the device owner - * @return Wrapped {@link DeviceConfiguration} object with data - */ - private DeviceConfiguration wrapConfigurations(Device device, - String tenantDomain, - List configurationEntries, - String deviceOwner) { - DeviceConfiguration deviceConfiguration = new DeviceConfiguration(); - deviceConfiguration.setDeviceId(device.getDeviceIdentifier()); - deviceConfiguration.setDeviceType(device.getType()); - deviceConfiguration.setTenantDomain(tenantDomain); - deviceConfiguration.setConfigurationEntries(configurationEntries); - deviceConfiguration.setDeviceOwner(deviceOwner); - return deviceConfiguration; - } - @Override - public PaginationResult getAppSubscribedDevices(int offsetValue, int limitValue, - List devicesIds, String status) - throws DeviceManagementException { + public PaginationResult getAppSubscribedDevices(int offsetValue, int limitValue, List devicesIds, + String status) throws DeviceManagementException { int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true); if (log.isDebugEnabled()) { @@ -3739,8 +3717,16 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv DeviceManagementDAOFactory.openConnection(); subscribedDeviceDetails = deviceDAO .getSubscribedDevices(offsetValue, limitValue, devicesIds, tenantId, status); - count = subscribedDeviceDetails.size(); - + if (subscribedDeviceDetails.isEmpty()){ + paginationResult.setData(new ArrayList<>()); + paginationResult.setRecordsFiltered(0); + paginationResult.setRecordsTotal(0); + } + count = deviceDAO.getSubscribedDeviceCount(devicesIds, tenantId, status); + paginationResult.setData(getAllDeviceInfo(subscribedDeviceDetails)); + paginationResult.setRecordsFiltered(count); + paginationResult.setRecordsTotal(count); + return paginationResult; } catch (DeviceManagementDAOException e) { String msg = "Error occurred while retrieving device list for device ids " + devicesIds; log.error(msg, e); @@ -3752,9 +3738,26 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } finally { DeviceManagementDAOFactory.closeConnection(); } - paginationResult.setData(getAllDeviceInfo(subscribedDeviceDetails)); - paginationResult.setRecordsFiltered(count); - paginationResult.setRecordsTotal(count); - return paginationResult; + } + + /** + * Wrap the device configuration data into DeviceConfiguration bean + * @param device Device queried using the properties + * @param tenantDomain tenant domain + * @param configurationEntries platformConfiguration list + * @param deviceOwner name of the device owner + * @return Wrapped {@link DeviceConfiguration} object with data + */ + private DeviceConfiguration wrapConfigurations(Device device, + String tenantDomain, + List configurationEntries, + String deviceOwner) { + DeviceConfiguration deviceConfiguration = new DeviceConfiguration(); + deviceConfiguration.setDeviceId(device.getDeviceIdentifier()); + deviceConfiguration.setDeviceType(device.getType()); + deviceConfiguration.setTenantDomain(tenantDomain); + deviceConfiguration.setConfigurationEntries(configurationEntries); + deviceConfiguration.setDeviceOwner(deviceOwner); + return deviceConfiguration; } } diff --git a/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/conf/application-mgt.xml b/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/conf/application-mgt.xml index 8baa364de2a..a8f23258219 100644 --- a/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/conf/application-mgt.xml +++ b/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/conf/application-mgt.xml @@ -156,6 +156,7 @@ perm:admin:app:review:view perm:admin:app:publisher:update perm:admin:app:review:update + perm:admin:app:subscription:view perm:device-types:types perm:enterprise:modify perm:enterprise:view @@ -255,7 +256,7 @@ perm:device:enroll perm:geo-service:analytics-view perm:geo-service:alerts-manage - appm:rea + appm:read perm:devices:permanent-delete