From 566c9eb5dd847942a4f9b7882228f5270eb5af52 Mon Sep 17 00:00:00 2001 From: "tcdlpds@gmail.com" Date: Sun, 26 Apr 2020 00:12:54 +0530 Subject: [PATCH] Improve application searching logic --- .../mgt/common/response/Application.java | 14 ++ .../mgt/core/impl/ApplicationManagerImpl.java | 186 +++++++++++++----- .../ApplicationManagementPublisherAPI.java | 41 ---- ...pplicationManagementPublisherAdminAPI.java | 41 ++++ ...ApplicationManagementPublisherAPIImpl.java | 25 --- ...cationManagementPublisherAdminAPIImpl.java | 25 +++ 6 files changed, 212 insertions(+), 120 deletions(-) diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/response/Application.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/response/Application.java index 7f1c0200e4..778f7fc08d 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/response/Application.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/response/Application.java @@ -84,6 +84,12 @@ public class Application { value = "Application Rating") private double rating; + @ApiModelProperty(name = "isDeletableApp", value = "Is Deletable Application") + private boolean isDeletableApp; + + @ApiModelProperty(name = "isHideableApp", value = "Is Hideable application") + private boolean isHideableApp; + @ApiModelProperty(name = "applicationReleases", value = "List of application releases", required = true) @@ -156,6 +162,14 @@ public class Application { public void setRating(double rating) { this.rating = rating; } + public boolean isDeletableApp() { return isDeletableApp; } + + public void setDeletableApp(boolean deletableApp) { isDeletableApp = deletableApp; } + + public boolean isHideableApp() { return isHideableApp; } + + public void setHideableApp(boolean hideableApp) { isHideableApp = hideableApp; } + public boolean isAndroidEnterpriseApp() { return isAndroidEnterpriseApp; } public void setAndroidEnterpriseApp(boolean androidEnterpriseApp) { isAndroidEnterpriseApp = androidEnterpriseApp; } 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 872da89ae4..be8158585f 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 @@ -597,19 +597,13 @@ public class ApplicationManagerImpl implements ApplicationManager { @Override public ApplicationList getApplications(Filter filter) throws ApplicationManagementException { int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); - String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); ApplicationList applicationList = new ApplicationList(); - List appDTOs; List applications = new ArrayList<>(); - List filteredApplications = new ArrayList<>(); - DeviceType deviceType = null; + DeviceType deviceType; - //set default values - if (!StringUtils.isEmpty(filter.getDeviceType())) { + if (StringUtils.isNotBlank(filter.getDeviceType())) { deviceType = APIUtil.getDeviceTypeData(filter.getDeviceType()); - } - - if (deviceType == null) { + } else { deviceType = new DeviceType(); deviceType.setId(-1); } @@ -617,52 +611,50 @@ public class ApplicationManagerImpl implements ApplicationManager { try { ConnectionManagerUtil.openDBConnection(); validateFilter(filter); - appDTOs = applicationDAO.getApplications(filter, deviceType.getId(), tenantId); + List appDTOs = applicationDAO.getApplications(filter, deviceType.getId(), tenantId); for (ApplicationDTO applicationDTO : appDTOs) { - boolean isSearchingApp = true; - List filteringTags = filter.getTags(); - List filteringCategories = filter.getCategories(); - List filteringUnrestrictedRoles = filter.getUnrestrictedRoles(); - - if (!lifecycleStateManager.getEndState().equals(applicationDTO.getStatus())) { - //get application categories, tags and unrestricted roles. - List appUnrestrictedRoles = visibilityDAO - .getUnrestrictedRoles(applicationDTO.getId(), tenantId); - List appCategoryList = applicationDAO.getAppCategories(applicationDTO.getId(), tenantId); - List appTagList = applicationDAO.getAppTags(applicationDTO.getId(), tenantId); + if (lifecycleStateManager.getEndState().equals(applicationDTO.getStatus())) { + continue; + } - //Set application categories, tags and unrestricted roles to the application DTO. - applicationDTO.setUnrestrictedRoles(appUnrestrictedRoles); - applicationDTO.setAppCategories(appCategoryList); - applicationDTO.setTags(appTagList); - - if ((appUnrestrictedRoles.isEmpty() || hasUserRole(appUnrestrictedRoles, userName)) && ( - filteringUnrestrictedRoles == null || filteringUnrestrictedRoles.isEmpty() - || hasAppUnrestrictedRole(appUnrestrictedRoles, filteringUnrestrictedRoles, - userName))) { - if (filteringCategories != null && !filteringCategories.isEmpty()) { - isSearchingApp = filteringCategories.stream().anyMatch(appCategoryList::contains); - } - if (filteringTags != null && !filteringTags.isEmpty() && isSearchingApp) { - isSearchingApp = filteringTags.stream().anyMatch(appTagList::contains); - } - if (isSearchingApp) { - filteredApplications.add(applicationDTO); + //Set application categories, tags and unrestricted roles to the application DTO. + applicationDTO.setUnrestrictedRoles(visibilityDAO + .getUnrestrictedRoles(applicationDTO.getId(), tenantId)); + applicationDTO.setAppCategories(applicationDAO.getAppCategories(applicationDTO.getId(), tenantId)); + applicationDTO.setTags(applicationDAO.getAppTags(applicationDTO.getId(), tenantId)); + + if (isFilteringApp(applicationDTO, filter)) { + List filteredApplicationReleaseDTOs = new ArrayList<>(); + AtomicBoolean isDeletableApp = new AtomicBoolean(true); + for (ApplicationReleaseDTO applicationReleaseDTO : applicationDTO.getApplicationReleaseDTOs()) { + String appReleaseCurrentState = applicationReleaseDTO.getCurrentState(); + if (!lifecycleStateManager.getEndState().equals(appReleaseCurrentState)) { + if (isDeletableApp.get() && !lifecycleStateManager.isDeletableState(appReleaseCurrentState)) { + isDeletableApp.set(false); + } + filteredApplicationReleaseDTOs.add(applicationReleaseDTO); } } - } - List filteredApplicationReleaseDTOs = new ArrayList<>(); - for (ApplicationReleaseDTO applicationReleaseDTO : applicationDTO.getApplicationReleaseDTOs()) { - if (!applicationReleaseDTO.getCurrentState().equals(lifecycleStateManager.getEndState())) { - filteredApplicationReleaseDTOs.add(applicationReleaseDTO); + applicationDTO.setApplicationReleaseDTOs(filteredApplicationReleaseDTOs); + Application application = APIUtil.appDtoToAppResponse(applicationDTO); + + /* + * Load the entire application again if the searched application is either deletable or all the app + * releases are in the end state of the app lifecycle. App has to be reloaded because when searching + * applications it may not contains all the application releases of an application. + */ + if (isDeletableApp.get() || filteredApplicationReleaseDTOs.isEmpty()){ + ApplicationDTO entireApp = applicationDAO.getApplication(applicationDTO.getId(), tenantId); + if (filteredApplicationReleaseDTOs.isEmpty()){ + application.setHideableApp(isHideableApp(entireApp.getApplicationReleaseDTOs())); + } + if (isDeletableApp.get()) { + application.setDeletableApp(isDeletableApp(entireApp.getApplicationReleaseDTOs())); + } } + applications.add(application); } - applicationDTO.setApplicationReleaseDTOs(filteredApplicationReleaseDTOs); - } - - for (ApplicationDTO appDTO : filteredApplications) { - applications.add(APIUtil.appDtoToAppResponse(appDTO)); } Pagination pagination = new Pagination(); @@ -679,13 +671,9 @@ public class ApplicationManagerImpl implements ApplicationManager { + "requested filter."; log.error(msg, e); throw new ApplicationManagementException(msg, e); - } catch (UserStoreException e) { - String msg = "User-store exception while checking whether the user " + userName + " of tenant " + tenantId - + " has the publisher permission"; - log.error(msg, e); - throw new ApplicationManagementException(msg, e); } catch (ApplicationManagementDAOException e) { - String msg = "DAO exception while getting applications for the user " + userName + " of tenant " + tenantId; + String msg = + "DAO exception while getting applications of tenant " + tenantId + ". Filter: " + filter.toString(); log.error(msg, e); throw new ApplicationManagementException(msg, e); } finally { @@ -693,6 +681,96 @@ public class ApplicationManagerImpl implements ApplicationManager { } } + /** + * To check whether the application is filtering app or not + * + * @param applicationDTO Application DTO object + * @param filter Filter + * @return false if application doesn't satisfy filters, otherwise returns true. + * @throws ApplicationManagementException if error occurred while checking whether user has app unrestricted roles + * or filtering roles. + */ + private boolean isFilteringApp(ApplicationDTO applicationDTO, Filter filter) throws ApplicationManagementException { + String userName = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); + List filteringTags = filter.getTags(); + List filteringCategories = filter.getCategories(); + List filteringUnrestrictedRoles = filter.getUnrestrictedRoles(); + + List appUnrestrictedRoles = applicationDTO.getUnrestrictedRoles(); + List appCategoryList = applicationDTO.getAppCategories(); + List appTagList = applicationDTO.getTags(); + try { + if (!appUnrestrictedRoles.isEmpty() && !hasUserRole(appUnrestrictedRoles, userName)) { + return false; + } + if (filteringUnrestrictedRoles != null && !filteringUnrestrictedRoles.isEmpty() && !hasAppUnrestrictedRole( + appUnrestrictedRoles, filteringUnrestrictedRoles, userName)) { + return false; + } + if (filteringCategories != null && !filteringCategories.isEmpty() && filteringCategories.stream() + .noneMatch(appCategoryList::contains)) { + return false; + } + if (filteringTags != null && !filteringTags.isEmpty() && filteringTags.stream() + .noneMatch(appTagList::contains)) { + return false; + } + } catch (UserStoreException e) { + String msg = "User-store exception while checking whether the user " + userName + + " has permission to view application"; + log.error(msg, e); + throw new ApplicationManagementException(msg, e); + } + return true; + } + + /** + * To check whether the application is whether hideable or not + * + * @param applicationReleaseDTOs Application releases + * @return true if application releases are in hideable state (i.e Retired), otherwise returns false + * @throws ApplicationManagementException if error occurred while getting application release end state. + */ + private boolean isHideableApp(List applicationReleaseDTOs) + throws ApplicationManagementException { + try { + for (ApplicationReleaseDTO applicationReleaseDTO : applicationReleaseDTOs) { + if (!lifecycleStateManager.getEndState().equals(applicationReleaseDTO.getCurrentState())) { + return false; + } + } + } catch (LifecycleManagementException e) { + String msg = "Error occurred while testing application is whether hideable app or not."; + log.error(msg, e); + throw new ApplicationManagementException(msg, e); + } + return true; + } + + /** + * To check whether the application is whether deletable or not + * + * @param applicationReleaseDTOs Application releases + * @return true if application releases are in deletable state (i.e Created or Rejected), otherwise returns false + * @throws ApplicationManagementException if error occurred while checking whether the application release is in + * deletable state or not. + */ + private boolean isDeletableApp(List applicationReleaseDTOs) + throws ApplicationManagementException { + try { + for (ApplicationReleaseDTO applicationReleaseDTO : applicationReleaseDTOs) { + if (!lifecycleStateManager.isDeletableState(applicationReleaseDTO.getCurrentState())) { + return false; + } + } + } catch (LifecycleManagementException e) { + String msg = "Error occurred while testing application is whether deletable app or not."; + log.error(msg, e); + throw new ApplicationManagementException(msg, e); + } + return true; + } + @Override public List getApplications(List packageNames) throws ApplicationManagementException { int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/ApplicationManagementPublisherAPI.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/ApplicationManagementPublisherAPI.java index 85b62e60e5..1d969f0881 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/ApplicationManagementPublisherAPI.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/ApplicationManagementPublisherAPI.java @@ -616,47 +616,6 @@ public interface ApplicationManagementPublisherAPI { @Multipart(value = "screenshot3") Attachment screenshot3 ); - @PUT - @Consumes("application/json") - @Path("/retire/{appId}") - @ApiOperation( - consumes = MediaType.APPLICATION_JSON, - produces = MediaType.APPLICATION_JSON, - httpMethod = "PUT", - value = "Retire the application with the given UUID", - notes = "This will retire the application with the given UUID", - tags = "ApplicationDTO Management", - extensions = { - @Extension(properties = { - @ExtensionProperty(name = SCOPE, value = "perm:app:publisher:update") - }) - } - ) - @ApiResponses( - value = { - @ApiResponse( - code = 200, - message = "OK. \n Successfully deleted the application identified by UUID.", - response = List.class), - @ApiResponse( - code = 500, - message = "Internal Server Error. \n Error occurred while deleting the application.", - response = ErrorResponse.class), - @ApiResponse( - code = 403, - message = "Don't have permission to delete the application"), - @ApiResponse( - code = 404, - message = "Application not found"), - }) - Response retireApplication( - @ApiParam( - name = "UUID", - value = "Unique identifier of the ApplicationDTO", - required = true) - @PathParam("appId") int applicationId - ); - @PUT @Path("/image-artifacts/{uuid}") @Produces(MediaType.APPLICATION_JSON) diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/admin/ApplicationManagementPublisherAdminAPI.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/admin/ApplicationManagementPublisherAdminAPI.java index 8b3a1117f3..006528d561 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/admin/ApplicationManagementPublisherAdminAPI.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/admin/ApplicationManagementPublisherAdminAPI.java @@ -305,4 +305,45 @@ public interface ApplicationManagementPublisherAdminAPI { required = true) @PathParam("categoryName") String categoryName ); + + @PUT + @Consumes("application/json") + @Path("/retire/{appId}") + @ApiOperation( + consumes = MediaType.APPLICATION_JSON, + produces = MediaType.APPLICATION_JSON, + httpMethod = "PUT", + value = "Retire the application with the given UUID", + notes = "This will retire the application with the given UUID", + tags = "Application Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = SCOPE, value = "perm:admin:app:publisher:update") + }) + } + ) + @ApiResponses( + value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully deleted the application identified by UUID.", + response = List.class), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Error occurred while deleting the application.", + response = ErrorResponse.class), + @ApiResponse( + code = 403, + message = "Don't have permission to delete the application"), + @ApiResponse( + code = 404, + message = "Application not found"), + }) + Response retireApplication( + @ApiParam( + name = "UUID", + value = "Unique identifier of the ApplicationDTO", + required = true) + @PathParam("appId") int applicationId + ); } diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/impl/ApplicationManagementPublisherAPIImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/impl/ApplicationManagementPublisherAPIImpl.java index 5c6bcf3621..d9e0a321d1 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/impl/ApplicationManagementPublisherAPIImpl.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/impl/ApplicationManagementPublisherAPIImpl.java @@ -686,31 +686,6 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem } } - @PUT - @Path("/retire/{appId}") - public Response retireApplication( - @PathParam("appId") int applicationId) { - ApplicationManager applicationManager = APIUtil.getApplicationManager(); - try { - applicationManager.retireApplication(applicationId); - return Response.status(Response.Status.OK) - .entity("Successfully deleted the application for application ID: " + applicationId).build(); - } catch (NotFoundException e) { - String msg = - "Couldn't found application for application id: " + applicationId + " to delete the application"; - log.error(msg, e); - return Response.status(Response.Status.NOT_FOUND).entity(msg).build(); - } catch (ForbiddenException e) { - String msg = "You don't have require permission to delete the application which has ID " + applicationId; - log.error(msg, e); - return Response.status(Response.Status.FORBIDDEN).entity(msg).build(); - } catch (ApplicationManagementException e) { - String msg = "Error occurred while deleting the application: " + applicationId; - log.error(msg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); - } - } - @GET @Path("/life-cycle/state-changes/{uuid}") public Response getLifecycleStates( diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/impl/admin/ApplicationManagementPublisherAdminAPIImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/impl/admin/ApplicationManagementPublisherAdminAPIImpl.java index 1e84dd140e..e330a742e1 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/impl/admin/ApplicationManagementPublisherAdminAPIImpl.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/impl/admin/ApplicationManagementPublisherAdminAPIImpl.java @@ -187,4 +187,29 @@ public class ApplicationManagementPublisherAdminAPIImpl implements ApplicationMa return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); } } + + @PUT + @Path("/retire/{appId}") + public Response retireApplication( + @PathParam("appId") int applicationId) { + ApplicationManager applicationManager = APIUtil.getApplicationManager(); + try { + applicationManager.retireApplication(applicationId); + return Response.status(Response.Status.OK) + .entity("Successfully deleted the application for application ID: " + applicationId).build(); + } catch (NotFoundException e) { + String msg = + "Couldn't found application for application id: " + applicationId + " to delete the application"; + log.error(msg, e); + return Response.status(Response.Status.NOT_FOUND).entity(msg).build(); + } catch (ForbiddenException e) { + String msg = "You don't have require permission to delete the application which has ID " + applicationId; + log.error(msg, e); + return Response.status(Response.Status.FORBIDDEN).entity(msg).build(); + } catch (ApplicationManagementException e) { + String msg = "Error occurred while deleting the application: " + applicationId; + log.error(msg, e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); + } + } }