From 07abd78261b3e51aa2626e7e854cf4209b4d3061 Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Thu, 5 Dec 2019 08:21:07 +0530 Subject: [PATCH 01/18] Create endpoints to undeploy artifacts 4 new endpoints were created to delete each artifact and some minor changes were done to deploy of some of these artifacts. --- .../ArtifactAlreadyExistsException.java | 35 ++ .../AnalyticsArtifactsManagementService.java | 382 ++++++++++++++++-- ...alyticsArtifactsManagementServiceImpl.java | 347 ++++++++++++++-- 3 files changed, 699 insertions(+), 65 deletions(-) create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/exception/ArtifactAlreadyExistsException.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/exception/ArtifactAlreadyExistsException.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/exception/ArtifactAlreadyExistsException.java new file mode 100644 index 00000000000..78a75331cbf --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/exception/ArtifactAlreadyExistsException.java @@ -0,0 +1,35 @@ +package org.wso2.carbon.device.mgt.jaxrs.exception; + +public class ArtifactAlreadyExistsException extends Exception { + private static final long serialVersionUID = 6459451028947683202L; + private String message; + private Throwable cause; + + public ArtifactAlreadyExistsException(String message) { + this.message = message; + } + + public ArtifactAlreadyExistsException(String message, Throwable cause) { + super(message, cause); + this.message = message; + this.cause = cause; + } + + @Override + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public Throwable getCause() { + return cause; + } + + public void setCause(Throwable cause) { + this.cause = cause; + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/AnalyticsArtifactsManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/AnalyticsArtifactsManagementService.java index 7e5456dadd9..e2d5064a4d9 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/AnalyticsArtifactsManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/AnalyticsArtifactsManagementService.java @@ -39,6 +39,7 @@ import io.swagger.annotations.Tag; import javax.validation.Valid; import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; @@ -67,31 +68,49 @@ import javax.ws.rs.core.Response; name = "Create Event Stream Artifact", description = "Create Event Stream Artifact", key = "perm:analytics:artifacts:stream", - permissions = {"/device-mgt/analytics/artifacts/stream/add"} - ), + permissions = {"/device-mgt/analytics/artifacts/stream/add"}), + @Scope( + name = "Delete Stream Artifact", + description = "Delete Stream Artifact", + key = "perm:analytics:artifacts:stream:delete", + permissions = {"/device-mgt/analytics/artifacts/stream/delete"}), @Scope( name = "Create Event Receiver Artifact", description = "Create Event Receiver Artifact", key = "perm:analytics:artifacts:receiver", - permissions = {"/device-mgt/analytics/artifacts/receiver/add"} - ), + permissions = {"/device-mgt/analytics/artifacts/receiver/add"}), + @Scope( + name = "Delete Receiver Artifact", + description = "Delete Receiver Artifact", + key = "perm:analytics:artifacts:receiver:delete", + permissions = {"/device-mgt/analytics/artifacts/receiver/delete"}), @Scope( name = "Create Event Publisher Artifact", description = "Create Event Publisher Artifact", key = "perm:analytics:artifacts:publisher", - permissions = {"/device-mgt/analytics/artifacts/publisher/add"} - ), + permissions = {"/device-mgt/analytics/artifacts/publisher/add"}), + @Scope( + name = "Delete Publisher Artifact", + description = "Delete Publisher Artifact", + key = "perm:analytics:artifacts:publisher:delete", + permissions = {"/device-mgt/analytics/artifacts/publisher/delete"}), @Scope( name = "Create Siddhi Script Artifact", description = "Create Siddhi Script Artifact", key = "perm:analytics:artifacts:siddhi", - permissions = {"/device-mgt/analytics/artifacts/siddhi-script/add"} - ) + permissions = {"/device-mgt/analytics/artifacts/siddhi-script/add"}), + @Scope( + name = "Delete Siddhi Script Artifact", + description = "Delete Siddhi Script Artifact", + key = "perm:analytics:artifacts:siddhi:delete", + permissions = {"/device-mgt/analytics/artifacts/siddhi-script/delete"}) } ) -@Api(value = "Analytics Artifacts Management", description = "This API corresponds to services" + - " related to Analytics Artifacts management") +@Api( + value = "Analytics Artifacts Management", + description = "This API corresponds to services related to Analytics Artifacts management" +) @Path("/analytics/artifacts") @Consumes(MediaType.APPLICATION_JSON) public interface AnalyticsArtifactsManagementService { @@ -105,8 +124,10 @@ public interface AnalyticsArtifactsManagementService { tags = "Analytics Artifacts Management", extensions = { @Extension(properties = { - @ExtensionProperty(name = Constants.SCOPE, value = "perm:analytics:artifacts:stream") - }) + @ExtensionProperty( + name = Constants.SCOPE, + value = "perm:analytics:artifacts:stream" + )}) } ) @ApiResponses( @@ -137,17 +158,23 @@ public interface AnalyticsArtifactsManagementService { message = "Not Acceptable.\n The requested media type is not supported."), @ApiResponse( code = 500, - message = "Internal Server Error. \n Server error occurred while deploying the " + - "Stream Artifact.", + message = "Internal Server Error. \n Server error occurred while " + + "deploying the Stream Artifact.", response = ErrorResponse.class) } ) Response deployEventDefinitionAsString( - @ApiParam(name = "id", value = "Stream id(name:version).") + @ApiParam( + name = "id", + value = "Stream id(name:version).") @PathParam("id") String id, - @ApiParam(name = "isEdited", value = "This stream is being edited or created.") + @ApiParam( + name = "isEdited", + value = "This stream is being edited or created.") @QueryParam("isEdited") boolean isEdited, - @ApiParam(name = "stream", value = "Add the data to complete the EventStream object.", + @ApiParam( + name = "stream", + value = "Add the data to complete the EventStream object.", required = true) @Valid EventStream stream); @@ -160,8 +187,10 @@ public interface AnalyticsArtifactsManagementService { tags = "Analytics Artifacts Management", extensions = { @Extension(properties = { - @ExtensionProperty(name = Constants.SCOPE, value = "perm:analytics:artifacts:stream") - }) + @ExtensionProperty( + name = Constants.SCOPE, + value = "perm:analytics:artifacts:stream" + )}) } ) @ApiResponses( @@ -198,10 +227,74 @@ public interface AnalyticsArtifactsManagementService { } ) Response deployEventDefinitionAsDto( - @ApiParam(name = "stream", value = "Add the data to complete the EventStream object.", + @ApiParam( + name = "stream", + value = "Add the data to complete the EventStream object.", required = true) @Valid EventStream stream); + @DELETE + @Path("/stream/{name}/{version}/delete") + @ApiOperation( + httpMethod = "DELETE", + value = "Delete the Stream with id as {name}:{version}", + notes = "Use this api to delete an already deployed Stream", + tags = "Analytics Artifacts Management", + extensions = { + @Extension(properties = { + @ExtensionProperty( + name = Constants.SCOPE, + value = "perm:analytics:artifacts:stream:delete" + )}) + } + ) + @ApiResponses( + value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully deleted the Stream Artifact.", + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "The content type of the body"), + @ResponseHeader( + name = "ETag", + description = "Entity Tag of the response resource.\n" + + "Used by caches, or in conditional requests."), + @ResponseHeader( + name = "Last-Modified", + description = + "Date and time the resource was last modified.\n" + + "Used by caches, or in conditional requests.") + } + ), + @ApiResponse( + code = 400, + message = "Bad Request."), + @ApiResponse( + code = 406, + message = "Not Acceptable.\n" + + "The requested media type is not supported."), + @ApiResponse( + code = 500, + message = "Internal Server Error.\nServer error occurred while " + + "deleting the Stream Artifact.", + response = ErrorResponse.class) + } + ) + Response deleteStream( + @ApiParam( + name = "name", + value = "Stream name.", + required = true) + @PathParam("name") String name, + @ApiParam( + name = "version", + value = "Stream version.", + required = true) + @PathParam("version") String version + ); + @POST @Path("/receiver/{name}") @ApiOperation( @@ -211,8 +304,10 @@ public interface AnalyticsArtifactsManagementService { tags = "Analytics Artifacts Management", extensions = { @Extension(properties = { - @ExtensionProperty(name = Constants.SCOPE, value = "perm:analytics:artifacts:receiver") - }) + @ExtensionProperty( + name = Constants.SCOPE, + value = "perm:analytics:artifacts:receiver" + )}) } ) @ApiResponses( @@ -250,11 +345,17 @@ public interface AnalyticsArtifactsManagementService { } ) Response deployEventReceiverAsString( - @ApiParam(name = "name", value = "Receiver name.") + @ApiParam( + name = "name", + value = "Receiver name.") @PathParam("name") String name, - @ApiParam(name = "isEdited", value = "This stream is being edited or created.") + @ApiParam( + name = "isEdited", + value = "This stream is being edited or created.") @QueryParam("isEdited") boolean isEdited, - @ApiParam(name = "receiver", value = "Add the data to complete the EventReceiver object.", + @ApiParam( + name = "receiver", + value = "Add the data to complete the EventReceiver object.", required = true) @Valid Adapter receiver); @@ -267,8 +368,10 @@ public interface AnalyticsArtifactsManagementService { tags = "Analytics Artifacts Management", extensions = { @Extension(properties = { - @ExtensionProperty(name = Constants.SCOPE, value = "perm:analytics:artifacts:receiver") - }) + @ExtensionProperty( + name = Constants.SCOPE, + value = "perm:analytics:artifacts:receiver" + )}) } ) @ApiResponses( @@ -306,10 +409,74 @@ public interface AnalyticsArtifactsManagementService { } ) Response deployEventReceiverAsDto( - @ApiParam(name = "receiver", value = "Add the data to complete the Adapter object.", + @ApiParam( + name = "receiver", + value = "Add the data to complete the Adapter object.", required = true) @Valid Adapter receiver); + @DELETE + @Path("/receiver/{name}/delete") + @ApiOperation( + httpMethod = "DELETE", + value = "Delete a Receiver with the given name", + notes = "Use this api to delete an already deployed active or inactive Receiver", + tags = "Analytics Artifacts Management", + extensions = { + @Extension(properties = { + @ExtensionProperty( + name = Constants.SCOPE, + value = "perm:analytics:artifacts:receiver:delete" + )}) + } + ) + @ApiResponses( + value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully deleted the Receiver Artifact.", + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "The content type of the body" + ), + @ResponseHeader( + name = "ETag", + description = "Entity Tag of the response resource.\n" + + "Used by caches, or in conditional requests." + ), + @ResponseHeader( + name = "Last-Modified", + description = + "Date and time the resource was last modified.\n" + + "Used by caches, or in conditional requests." + ) + } + ), + @ApiResponse( + code = 400, + message = "Bad Request." + ), + @ApiResponse( + code = 406, + message = "Not Acceptable.\n" + + "The requested media type is not supported." + ), + @ApiResponse( + code = 500, + message = "Internal Server Error.\nServer error occurred while " + + "deleting the Receiver Artifact.", + response = ErrorResponse.class + ) + } + ) + Response deleteReceiver( + @ApiParam( + name = "name", + value = "Receiver name.", + required = true) + @PathParam("name") String name); + @POST @Path("/publisher/{name}") @ApiOperation( @@ -319,8 +486,10 @@ public interface AnalyticsArtifactsManagementService { tags = "Analytics Artifacts Management", extensions = { @Extension(properties = { - @ExtensionProperty(name = Constants.SCOPE, value = "perm:analytics:artifacts:publisher") - }) + @ExtensionProperty( + name = Constants.SCOPE, + value = "perm:analytics:artifacts:publisher" + )}) } ) @ApiResponses( @@ -358,11 +527,17 @@ public interface AnalyticsArtifactsManagementService { } ) Response deployEventPublisherAsString( - @ApiParam(name = "name", value = "Publisher name.") + @ApiParam( + name = "name", + value = "Publisher name.") @PathParam("name") String name, - @ApiParam(name = "isEdited", value = "This stream is being edited or created.") + @ApiParam( + name = "isEdited", + value = "This stream is being edited or created.") @QueryParam("isEdited") boolean isEdited, - @ApiParam(name = "publisher", value = "Add the data to complete the EventPublisher object.", + @ApiParam( + name = "publisher", + value = "Add the data to complete the EventPublisher object.", required = true) @Valid Adapter publisher); @@ -375,8 +550,10 @@ public interface AnalyticsArtifactsManagementService { tags = "Analytics Artifacts Management", extensions = { @Extension(properties = { - @ExtensionProperty(name = Constants.SCOPE, value = "perm:analytics:artifacts:publisher") - }) + @ExtensionProperty( + name = Constants.SCOPE, + value = "perm:analytics:artifacts:publisher" + )}) } ) @ApiResponses( @@ -414,10 +591,68 @@ public interface AnalyticsArtifactsManagementService { } ) Response deployEventPublisherAsDto( - @ApiParam(name = "publisher", value = "Add the data to complete the Adapter object.", + @ApiParam( + name = "publisher", + value = "Add the data to complete the Adapter object.", required = true) @Valid Adapter publisher); + @DELETE + @Path("/publisher/{name}/delete") + @ApiOperation( + httpMethod = "DELETE", + value = "Delete a Publisher with the given name", + notes = "Use this api to delete an already deployed active or inactive Publisher", + tags = "Analytics Artifacts Management", + extensions = { + @Extension(properties = { + @ExtensionProperty( + name = Constants.SCOPE, + value = "perm:analytics:artifacts:publisher:delete" + )}) + } + ) + @ApiResponses( + value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully deleted the Publisher Artifact.", + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "The content type of the body"), + @ResponseHeader( + name = "ETag", + description = "Entity Tag of the response resource.\n" + + "Used by caches, or in conditional requests."), + @ResponseHeader( + name = "Last-Modified", + description = + "Date and time the resource was last modified.\n" + + "Used by caches, or in conditional requests.") + } + ), + @ApiResponse( + code = 400, + message = "Bad Request."), + @ApiResponse( + code = 406, + message = "Not Acceptable.\n" + + "The requested media type is not supported."), + @ApiResponse( + code = 500, + message = "Internal Server Error.\nServer error occurred while " + + "deleting the Publisher Artifact.", + response = ErrorResponse.class) + } + ) + Response deletePublisher( + @ApiParam( + name = "name", + value = "Publisher name.", + required = true) + @PathParam("name") String name); + @POST @Path("/siddhi-script/{name}") @ApiOperation( @@ -427,8 +662,10 @@ public interface AnalyticsArtifactsManagementService { tags = "Analytics Artifacts Management", extensions = { @Extension(properties = { - @ExtensionProperty(name = Constants.SCOPE, value = "perm:analytics:artifacts:siddhi") - }) + @ExtensionProperty( + name = Constants.SCOPE, + value = "perm:analytics:artifacts:siddhi" + )}) } ) @ApiResponses( @@ -466,11 +703,74 @@ public interface AnalyticsArtifactsManagementService { } ) Response deploySiddhiExecutableScript( - @ApiParam(name = "name", value = "Siddhi Executable Script name.") + @ApiParam( + name = "name", + value = "Siddhi Executable Script name.") @PathParam("name") String name, - @ApiParam(name = "isEdited", value = "This stream is being edited or created.") + @ApiParam( + name = "isEdited", + value = "This stream is being edited or created.") @QueryParam("isEdited") boolean isEdited, - @ApiParam(name = "plan", value = "Add the data to complete the SiddhiExecutionPlan object.", + @ApiParam( + name = "plan", + value = "Add the data to complete the SiddhiExecutionPlan object.", required = true) @Valid SiddhiExecutionPlan plan); + + @DELETE + @Path("/siddhi-script/{name}/delete") + @ApiOperation( + httpMethod = "DELETE", + value = "Delete an already deployed Siddhi script", + notes = "Use this api to delete an already deployed active or inactive Siddhi script", + tags = "Analytics Artifacts Management", + extensions = { + @Extension(properties = { + @ExtensionProperty( + name = Constants.SCOPE, + value = "perm:analytics:artifacts:siddhi:delete" + ) + }) + } + ) + @ApiResponses( + value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully delete the Siddhi script Artifact.", + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "The content type of the body"), + @ResponseHeader( + name = "ETag", + description = "Entity Tag of the response resource.\n" + + "Used by caches, or in conditional requests."), + @ResponseHeader( + name = "Last-Modified", + description = + "Date and time the resource was last modified.\n" + + "Used by caches, or in conditional requests.") + } + ), + @ApiResponse( + code = 400, + message = "Bad Request."), + @ApiResponse( + code = 406, + message = "Not Acceptable.\n" + + "The requested media type is not supported."), + @ApiResponse( + code = 500, + message = "Internal Server Error.\nServer error occurred while " + + "deleting the Siddhi script Artifact.", + response = ErrorResponse.class) + } + ) + Response deleteSiddhiScript( + @ApiParam( + name = "name", + value = "Siddhi script name.", + required = true) + @PathParam("name") String name); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java index bdd7fdb4201..b6cdd9a6502 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java @@ -25,9 +25,11 @@ import org.wso2.carbon.device.mgt.jaxrs.beans.analytics.AdapterConfiguration; import org.wso2.carbon.device.mgt.jaxrs.beans.analytics.AdapterProperty; import org.wso2.carbon.device.mgt.jaxrs.beans.analytics.MessageFormat; import org.wso2.carbon.device.mgt.jaxrs.beans.analytics.SiddhiExecutionPlan; +import org.wso2.carbon.device.mgt.jaxrs.exception.ArtifactAlreadyExistsException; import org.wso2.carbon.device.mgt.jaxrs.exception.BadRequestException; import org.wso2.carbon.device.mgt.jaxrs.exception.ErrorDTO; import org.wso2.carbon.device.mgt.jaxrs.exception.InvalidExecutionPlanException; +import org.wso2.carbon.device.mgt.jaxrs.exception.NotFoundException; import org.wso2.carbon.device.mgt.jaxrs.service.api.AnalyticsArtifactsManagementService; import org.wso2.carbon.device.mgt.jaxrs.beans.analytics.Adapter; import org.wso2.carbon.device.mgt.jaxrs.beans.analytics.EventStream; @@ -52,6 +54,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.validation.Valid; +import javax.ws.rs.DELETE; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; @@ -76,36 +79,39 @@ public class AnalyticsArtifactsManagementServiceImpl @QueryParam("isEdited") boolean isEdited, @Valid EventStream stream) { String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); - EventStreamAdminServiceStub eventStreamAdminServiceStub = null; try { String streamDefinition = stream.getDefinition(); - eventStreamAdminServiceStub = DeviceMgtAPIUtils.getEventStreamAdminServiceStub(); - if (!isEdited) { - eventStreamAdminServiceStub.addEventStreamDefinitionAsString(streamDefinition); + if (deployStream(id, streamDefinition, isEdited)) { + return Response.ok().build(); } else { - if (eventStreamAdminServiceStub.getStreamDetailsForStreamId(id) != null) { - eventStreamAdminServiceStub.editEventStreamDefinitionAsString(streamDefinition, id); - } + String errMsg = "Failed to create the Stream artifact of id: " + id + + " for tenant domain: " + tenantDomain; + return Response.serverError().entity(errMsg).build(); } - return Response.ok().build(); + } catch (ArtifactAlreadyExistsException e) { + String errMsg = "Failed to create Stream artifact for tenant domain: " + tenantDomain; + log.error(errMsg, e); + return Response.status(Response.Status.BAD_REQUEST).entity(errMsg).build(); + } catch (NotFoundException e) { + String errMsg = "Failed to edit Stream artifact for tenant domain: " + tenantDomain; + log.error(errMsg, e); + return Response.status(Response.Status.NOT_FOUND).entity(errMsg).build(); } catch (AxisFault e) { String errMsg = "Failed to create event definitions for tenantDomain: " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); } catch (RemoteException e) { String errMsg = "Failed to connect with the remote services for tenantDomain: " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); } catch (JWTClientException e) { String errMsg = "Failed to generate jwt token for tenantDomain: " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); } catch (UserStoreException e) { String errMsg = "Failed to connect with the user store for tenantDomain: " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); - } finally { - cleanup(eventStreamAdminServiceStub); + return Response.serverError().entity(errMsg).build(); } } @@ -116,8 +122,16 @@ public class AnalyticsArtifactsManagementServiceImpl String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); try { validateStreamProperties(stream); - deployStream(stream); - return Response.ok().build(); + String name = stream.getName(); + String version = stream.getVersion(); + if (deployStream(stream)) { + return Response.ok().build(); + } else { + String errMsg = String.format("Failed to create the Stream artifact of id: %s:%s " + + "for tenant domain: %s", name, version, tenantDomain); + log.error(errMsg); + return Response.serverError().entity(errMsg).build(); + } } catch (BadRequestException e) { String errMsg = "Failed to deploy stream due to invalid payload"; log.error(errMsg, e); @@ -125,19 +139,58 @@ public class AnalyticsArtifactsManagementServiceImpl } catch (AxisFault e) { String errMsg = "Failed to create event definitions for tenant " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); } catch (RemoteException e) { String errMsg = "Failed to connect with the remote services for tenant " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); } catch (JWTClientException e) { String errMsg = "Failed to generate jwt token for tenant " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); } catch (UserStoreException e) { String errMsg = "Failed to connect with the user store for tenant " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); + } + } + + @Override + @DELETE + @Path("/stream/{name}/{version}/delete") + public Response deleteStream(@PathParam("name") String name, + @PathParam("version") String version) { + String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + try { + if (undeployStream(name, version)) { + return Response.ok().build(); + } else { + String errMsg = String.format("Failed to undeploy the Stream artifact of id: %s:%s " + + "for tenant domain: %s", name, version, tenantDomain); + log.error(errMsg); + return Response.serverError().entity(errMsg).build(); + } + } catch (NotFoundException e) { + String errMsg = String.format("Failed to undeploy Stream with id %s:%s for tenant %s" + , name, version, tenantDomain); + log.error(errMsg, e); + return Response.status(Response.Status.NOT_FOUND).entity(errMsg).build(); + } catch (AxisFault e) { + String errMsg = "Failed to create event definitions for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } catch (RemoteException e) { + String errMsg = "Failed to connect with the remote services for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } catch (JWTClientException e) { + String errMsg = "Failed to generate jwt token for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } catch (UserStoreException e) { + String errMsg = "Failed to connect with the user store for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); } } @@ -214,6 +267,39 @@ public class AnalyticsArtifactsManagementServiceImpl } } + @Override + @DELETE + @Path("/receiver/{name}/delete") + public Response deleteReceiver(@PathParam("name") String name) { + String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + try { + if (undeployAdapter(name, "Receiver")) { + return Response.ok().build(); + } else { + String errMsg = String.format("Failed to undeploy the Receiver artifact of name: %s" + + "for tenant domain: %s", name, tenantDomain); + log.error(errMsg); + return Response.serverError().entity(errMsg).build(); + } + } catch (AxisFault e) { + String errMsg = "Failed to delete event definitions for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } catch (RemoteException e) { + String errMsg = "Failed to connect with the remote services for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } catch (JWTClientException e) { + String errMsg = "Failed to generate jwt token for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } catch (UserStoreException e) { + String errMsg = "Failed to connect with the user store for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } + } + @Override @POST @Path("/publisher/{name}") @@ -287,6 +373,39 @@ public class AnalyticsArtifactsManagementServiceImpl } } + @Override + @DELETE + @Path("/publisher/{name}/delete") + public Response deletePublisher(@PathParam("name") String name) { + String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + try { + if (undeployAdapter(name, "Publisher")) { + return Response.ok().build(); + } else { + String errMsg = String.format("Failed to undeploy the Publisher artifact of name: %s" + + "for tenant domain: %s", name, tenantDomain); + log.error(errMsg); + return Response.serverError().entity(errMsg).build(); + } + } catch (AxisFault e) { + String errMsg = "Failed to delete event definitions for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } catch (RemoteException e) { + String errMsg = "Failed to connect with the remote services for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } catch (JWTClientException e) { + String errMsg = "Failed to generate jwt token for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } catch (UserStoreException e) { + String errMsg = "Failed to connect with the user store for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } + } + @Override @POST @Path("/siddhi-script/{name}") @@ -320,12 +439,77 @@ public class AnalyticsArtifactsManagementServiceImpl } } + @Override + @DELETE + @Path("/siddhi-script/{name}/delete") + public Response deleteSiddhiScript(@PathParam("name") String name) { + String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + try { + undeploySiddhiScript(name); + return Response.ok().build(); + } catch (AxisFault e) { + String errMsg = "Failed to delete event definitions for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } catch (RemoteException e) { + String errMsg = "Failed to connect with the remote services for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } catch (JWTClientException e) { + String errMsg = "Failed to generate jwt token for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } catch (UserStoreException e) { + String errMsg = "Failed to connect with the user store for tenant " + tenantDomain; + log.error(errMsg, e); + return Response.serverError().entity(errMsg).build(); + } + } + + /** + * Deploy Stream by passing a string to a stub + * + * @param streamId Stream name:version + * @param streamDefinition Stream that should be deployed + * @param isEdited Create a new stream or edit an existing one + * @return True if stream successfully created and false if not + * @throws RemoteException Exception that may occur during a remote method call + * @throws UserStoreException Exception that may occur during JWT token generation + * @throws JWTClientException Exception that may occur during connecting to client store + * @throws NotFoundException Exception that may occure if stream doesn't exist while editing + * @throws ArtifactAlreadyExistsException Exception that may occure if stream exist while creating + */ + private boolean deployStream(String streamId, String streamDefinition, boolean isEdited) + throws UserStoreException, JWTClientException, RemoteException, NotFoundException, + ArtifactAlreadyExistsException { + + EventStreamAdminServiceStub eventStreamAdminServiceStub = null; + try { + eventStreamAdminServiceStub = DeviceMgtAPIUtils.getEventStreamAdminServiceStub(); + if (isEdited) { + validateStreamId(streamId, eventStreamAdminServiceStub, true); + return eventStreamAdminServiceStub + .editEventStreamDefinitionAsString(streamDefinition, streamId); + } else { + validateStreamId(streamId, eventStreamAdminServiceStub, false); + return eventStreamAdminServiceStub.addEventStreamDefinitionAsString(streamDefinition); + } + } finally { + cleanup(eventStreamAdminServiceStub); + } + } + /** - * Set data to a Stream dto and deploy dto through a stub + * Deploy Stream by passing a DTO object to a stub * * @param stream Stream definition + * @return True if stream successfully created and false if not + * @throws RemoteException Exception that may occur during a remote method call + * @throws UserStoreException Exception that may occur during JWT token generation + * @throws JWTClientException Exception that may occur during connecting to client store + * @throws NotFoundException Exception that may occure if stream doesn't exist while editing */ - private void deployStream(EventStream stream) + private boolean deployStream(EventStream stream) throws RemoteException, UserStoreException, JWTClientException { EventStreamAdminServiceStub eventStreamAdminServiceStub = null; List metaData = stream.getMetaData(); @@ -350,9 +534,41 @@ public class AnalyticsArtifactsManagementServiceImpl } String streamId = stream.getName() + ":" + stream.getVersion(); if (eventStreamAdminServiceStub.getStreamDefinitionDto(streamId) != null) { - eventStreamAdminServiceStub.editEventStreamDefinitionAsDto(eventStreamDefinitionDto, streamId); + return eventStreamAdminServiceStub + .editEventStreamDefinitionAsDto(eventStreamDefinitionDto, streamId); } else { - eventStreamAdminServiceStub.addEventStreamDefinitionAsDto(eventStreamDefinitionDto); + return eventStreamAdminServiceStub + .addEventStreamDefinitionAsDto(eventStreamDefinitionDto); + } + } finally { + cleanup(eventStreamAdminServiceStub); + } + } + + /** + * Undeploy a stream artifact + * + * @param name Stream name + * @param version Stream version + * @return True if stream successfully created and false if not + * @throws RemoteException Exception that may occur during a remote method call + * @throws UserStoreException Exception that may occur during JWT token generation + * @throws JWTClientException Exception that may occur during connecting to client store + * @throws NotFoundException Exception that may occure if stream doesn't exist + */ + private boolean undeployStream(String name, String version) + throws RemoteException, UserStoreException, JWTClientException, NotFoundException { + EventStreamAdminServiceStub eventStreamAdminServiceStub = null; + try { + String streamId = String.format("%s:%s", name, version); + eventStreamAdminServiceStub = DeviceMgtAPIUtils.getEventStreamAdminServiceStub(); + if (eventStreamAdminServiceStub.getStreamDefinitionDto(streamId) != null) { + return eventStreamAdminServiceStub.removeEventStreamDefinition(name, version); + } else { + ErrorDTO error = new ErrorDTO(); + String msg = String.format("Stream wit id: %s not found", streamId); + error.setMessage(msg); + throw new NotFoundException(error); } } finally { cleanup(eventStreamAdminServiceStub); @@ -613,6 +829,37 @@ public class AnalyticsArtifactsManagementServiceImpl } } + /** + * @param name Adapter name + * @param type Adapter type(Receiver or Publisher) + * @return True if Adapter successfully created and false if not + * @throws RemoteException Exception that may occur during a remote method call + * @throws UserStoreException Exception that may occur during JWT token generation + * @throws JWTClientException Exception that may occur during connecting to client store + */ + private boolean undeployAdapter(String name, String type) + throws RemoteException, UserStoreException, JWTClientException { + if (type.equals("Receiver")) { + EventReceiverAdminServiceStub eventReceiverAdminServiceStub = null; + try { + eventReceiverAdminServiceStub = DeviceMgtAPIUtils.getEventReceiverAdminServiceStub(); + return eventReceiverAdminServiceStub + .undeployActiveEventReceiverConfiguration(name); + } finally { + cleanup(eventReceiverAdminServiceStub); + } + } else { + EventPublisherAdminServiceStub eventPublisherAdminServiceStub = null; + try { + eventPublisherAdminServiceStub = DeviceMgtAPIUtils.getEventPublisherAdminServiceStub(); + return eventPublisherAdminServiceStub + .undeployActiveEventPublisherConfiguration(name); + } finally { + cleanup(eventPublisherAdminServiceStub); + } + } + } + /** * Publish a siddhi execution plan using a stub * @@ -645,10 +892,60 @@ public class AnalyticsArtifactsManagementServiceImpl } } + /** + * Undeploy a Siddhi artifact + * + * @param name Siddhi script name + * @throws RemoteException Exception that may occur during a remote method call + * @throws UserStoreException Exception that may occur during JWT token generation + * @throws JWTClientException Exception that may occur during connecting to client store + */ + private void undeploySiddhiScript(String name) + throws RemoteException, UserStoreException, JWTClientException { + EventProcessorAdminServiceStub eventProcessorAdminServiceStub = null; + try { + eventProcessorAdminServiceStub = DeviceMgtAPIUtils.getEventProcessorAdminServiceStub(); + eventProcessorAdminServiceStub.undeployActiveExecutionPlan(name); + } finally { + cleanup(eventProcessorAdminServiceStub); + } + } + + /** + * @param streamId Stream name:version + * @param eventStreamAdminServiceStub stub used to mange Stream artifacts + * @param isEdited Create a new stream or edit an existing one + * @throws ArtifactAlreadyExistsException Exception that may occur if stream exist while creating + * @throws RemoteException Exception that may occur during a remote method call + */ + private void validateStreamId(String streamId, + EventStreamAdminServiceStub eventStreamAdminServiceStub, + boolean isEdited) + throws ArtifactAlreadyExistsException, RemoteException { + EventStreamDefinitionDto eventStreamDefinitionDto = eventStreamAdminServiceStub + .getStreamDefinitionDto(streamId); + if (isEdited) { + if (eventStreamDefinitionDto == null) { + String errMsg = String.format("Failed to edit Stream with id: %s. " + + "Stream not found", streamId); + ErrorDTO error = new ErrorDTO(); + error.setMessage(errMsg); + throw new NotFoundException(error); + } + } else { + if (eventStreamDefinitionDto != null) { + String errMsg = String.format("Failed to create Stream with id: %s. " + + "Stream already exists.", streamId); + throw new ArtifactAlreadyExistsException(errMsg); + } + } + } + /** * Validate stream properties * * @param stream EventStream object + * @throws BadRequestException Exception that may occur if property attributes invalid */ private void validateStreamProperties(EventStream stream) throws BadRequestException { if ((stream.getMetaData() == null || stream.getMetaData().isEmpty()) && @@ -665,6 +962,7 @@ public class AnalyticsArtifactsManagementServiceImpl * Validate adapter payload attributes * * @param adapterProperties Adapter payload attributes + * @throws BadRequestException Exception that may occur if adapter properties invalid */ private void validateAdapterProperties(List adapterProperties) throws BadRequestException { @@ -684,6 +982,7 @@ public class AnalyticsArtifactsManagementServiceImpl * - else continue * * @param adapterMappingConfiguration Adapter mapping attributes + * @throws BadRequestException Exception that may occur if adapter mapping properties invalid */ private void validateAdapterMapping(AdapterMappingConfiguration adapterMappingConfiguration) throws BadRequestException { From 867ea1d4235b1818a24da6114ba527a967f43388 Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Tue, 10 Dec 2019 05:11:38 +0530 Subject: [PATCH 02/18] Bring consuming media type to method level --- .../service/api/AnalyticsArtifactsManagementService.java | 7 ++++++- .../impl/AnalyticsArtifactsManagementServiceImpl.java | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/AnalyticsArtifactsManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/AnalyticsArtifactsManagementService.java index e2d5064a4d9..caacc59b39d 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/AnalyticsArtifactsManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/AnalyticsArtifactsManagementService.java @@ -112,10 +112,10 @@ import javax.ws.rs.core.Response; description = "This API corresponds to services related to Analytics Artifacts management" ) @Path("/analytics/artifacts") -@Consumes(MediaType.APPLICATION_JSON) public interface AnalyticsArtifactsManagementService { @POST + @Consumes(MediaType.APPLICATION_JSON) @Path("/stream/{id}") @ApiOperation( httpMethod = "POST", @@ -179,6 +179,7 @@ public interface AnalyticsArtifactsManagementService { @Valid EventStream stream); @POST + @Consumes(MediaType.APPLICATION_JSON) @Path("/stream") @ApiOperation( httpMethod = "POST", @@ -296,6 +297,7 @@ public interface AnalyticsArtifactsManagementService { ); @POST + @Consumes(MediaType.APPLICATION_JSON) @Path("/receiver/{name}") @ApiOperation( httpMethod = "POST", @@ -360,6 +362,7 @@ public interface AnalyticsArtifactsManagementService { @Valid Adapter receiver); @POST + @Consumes(MediaType.APPLICATION_JSON) @Path("/receiver") @ApiOperation( httpMethod = "POST", @@ -478,6 +481,7 @@ public interface AnalyticsArtifactsManagementService { @PathParam("name") String name); @POST + @Consumes(MediaType.APPLICATION_JSON) @Path("/publisher/{name}") @ApiOperation( httpMethod = "POST", @@ -542,6 +546,7 @@ public interface AnalyticsArtifactsManagementService { @Valid Adapter publisher); @POST + @Consumes(MediaType.APPLICATION_JSON) @Path("/publisher") @ApiOperation( httpMethod = "POST", diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java index b6cdd9a6502..a73baa90cb1 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java @@ -780,7 +780,6 @@ public class AnalyticsArtifactsManagementServiceImpl deployPublisherWithoutMapping(publisherName, eventStreamWithVersion, adapterType , eventPublisherAdminServiceStub, basicOutputAdapterPropertyDtos); } - } finally { cleanup(eventPublisherAdminServiceStub); } From 966a878e8e95ebb962a8122974c1442fdb003e42 Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Mon, 16 Dec 2019 16:32:48 +0530 Subject: [PATCH 03/18] Create permanant device type deletion --- .../DeviceTypeManagementAdminService.java | 63 ++++++++++-- .../DeviceManagementAdminServiceImpl.java | 2 +- .../DeviceTypeManagementAdminServiceImpl.java | 34 +++++-- .../DeviceTypeManagementAdminServiceTest.java | 29 ++++++ .../src/test/resources/testng.xml | 1 + .../device/mgt/core/dao/DeviceTypeDAO.java | 9 ++ .../mgt/core/dao/impl/DeviceTypeDAOImpl.java | 23 +++++ .../DeviceManagementProviderService.java | 14 ++- .../DeviceManagementProviderServiceImpl.java | 98 ++++++++++++++++++- 9 files changed, 255 insertions(+), 18 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java index b472b5832d6..efeaa393633 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java @@ -86,8 +86,6 @@ import javax.ws.rs.core.Response; @Api(value = "Device Type Management Administrative Service", description = "This an API intended to be used by " + "'internal' components to log in as an admin user and do a selected number of operations. " + "Further, this is strictly restricted to admin users only ") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) @Scopes( scopes = { @Scope( @@ -113,6 +111,7 @@ import javax.ws.rs.core.Response; public interface DeviceTypeManagementAdminService { @GET + @Produces(MediaType.APPLICATION_JSON) @ApiOperation( produces = MediaType.APPLICATION_JSON, httpMethod = "GET", @@ -164,6 +163,7 @@ public interface DeviceTypeManagementAdminService { Response getDeviceTypes(); @GET + @Produces(MediaType.APPLICATION_JSON) @Path("/{type}") @ApiOperation( produces = MediaType.APPLICATION_JSON, @@ -217,6 +217,8 @@ public interface DeviceTypeManagementAdminService { String type); @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) @ApiOperation( produces = MediaType.APPLICATION_JSON, httpMethod = "POST", @@ -262,6 +264,8 @@ public interface DeviceTypeManagementAdminService { required = true)DeviceType deviceType); @PUT + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) @Path("/{type}") @ApiOperation( produces = MediaType.APPLICATION_JSON, @@ -317,6 +321,8 @@ public interface DeviceTypeManagementAdminService { required = true) DeviceType deviceType); @POST + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) @Path("/{type}/configs") @ApiOperation( produces = MediaType.APPLICATION_JSON, @@ -372,8 +378,10 @@ public interface DeviceTypeManagementAdminService { PlatformConfiguration config); - @Path("/versions") @POST + @Path("/versions") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) @ApiOperation( produces = MediaType.APPLICATION_JSON, httpMethod = "POST", @@ -425,8 +433,9 @@ public interface DeviceTypeManagementAdminService { value = "The device type version details.", required = true) DeviceTypeVersionWrapper deviceTypeVersion); - @Path("/{deviceTypeName}/versions") @GET + @Produces(MediaType.APPLICATION_JSON) + @Path("/{deviceTypeName}/versions") @ApiOperation( produces = MediaType.APPLICATION_JSON, httpMethod = "GET", @@ -475,8 +484,10 @@ public interface DeviceTypeManagementAdminService { String deviceTypeName); - @Path("{deviceTypeName}/versions") @PUT + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @Path("{deviceTypeName}/versions") @ApiOperation( produces = MediaType.APPLICATION_JSON, httpMethod = "PUT", @@ -529,8 +540,8 @@ public interface DeviceTypeManagementAdminService { required = true) DeviceTypeVersionWrapper deviceTypeVersion); - @Path("{deviceTypeName}/versions/{version}") @DELETE + @Path("{deviceTypeName}/versions/{version}") @ApiOperation( produces = MediaType.APPLICATION_JSON, httpMethod = "DELETE", @@ -581,4 +592,44 @@ public interface DeviceTypeManagementAdminService { required = true) @PathParam("version")String version); + + @DELETE + @Path("{deviceType}/delete") + @ApiOperation( + httpMethod = "DELETE", + value = "Delete device type.", + notes = "This api will permanently delete an existing device type with everything " + + "it's related with.", + tags = "Device Type Management Administrative Service", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = Constants.SCOPE, value = "perm:admin:device-type") + }) + } + ) + @ApiResponses(value = { + @ApiResponse(code = 202, message = "ACCEPTED. \n Successfully deleted the device type.", + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "The content type of the body") + }), + @ApiResponse( + code = 401, + message = "Unauthorized.\n The unauthorized access to the requested resource.", + response = ErrorResponse.class), + @ApiResponse( + code = 406, + message = "Not Acceptable.\n The requested media type is not supported"), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Server error occurred while deleting device type.", + response = ErrorResponse.class) + }) + Response deleteDeviceType( + @ApiParam( + name = "deviceType", + value = "Device type name.", + required = true) + @PathParam("deviceType") String deviceType); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java index 9533c43a42a..360a41679f8 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java @@ -169,7 +169,7 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe DeviceManagementProviderService deviceManagementProviderService = DeviceMgtAPIUtils.getDeviceManagementService(); try { - if (!deviceManagementProviderService.deleteDevices(deviceIdentifiers)) { + if (!deviceManagementProviderService.deleteDevices(deviceIdentifiers, false)) { String msg = "Found un-deployed device type."; log.error(msg); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity( diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java index edae86a311b..e3bedfd816b 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java @@ -43,6 +43,7 @@ import org.wso2.carbon.device.mgt.common.configuration.mgt.PlatformConfiguration import org.wso2.carbon.device.mgt.common.spi.DeviceManagementService; import org.wso2.carbon.device.mgt.core.dto.DeviceType; import org.wso2.carbon.device.mgt.core.dto.DeviceTypeVersion; +import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceTypeVersionWrapper; import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; import org.wso2.carbon.device.mgt.jaxrs.service.api.admin.DeviceTypeManagementAdminService; @@ -63,16 +64,14 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; @Path("/admin/device-types") -@Produces(MediaType.APPLICATION_JSON) -@Consumes(MediaType.APPLICATION_JSON) public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagementAdminService { private static final Log log = LogFactory.getLog(DeviceTypeManagementAdminServiceImpl.class); private static final String DEVICETYPE_REGEX_PATTERN = "^[^ /]+$"; private static final Pattern patternMatcher = Pattern.compile(DEVICETYPE_REGEX_PATTERN); - @GET @Override + @GET public Response getDeviceTypes() { try { List deviceTypes = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceTypes(); @@ -188,8 +187,8 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen } @Override - @Path("{deviceTypeName}/versions") @POST + @Path("{deviceTypeName}/versions") public Response addDeviceTypeVersion(@PathParam("deviceTypeName") String deviceTypeName, DeviceTypeVersionWrapper versionWrapper) { if (versionWrapper != null && deviceTypeName != null && !deviceTypeName.isEmpty() @@ -229,9 +228,9 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen } } + @Override @GET @Path("/{deviceTypeName}/versions") - @Override public Response getDeviceTypeVersion(@PathParam("deviceTypeName") String deviceTypeName) { try { List deviceTypes = DeviceMgtAPIUtils.getDeviceManagementService() @@ -244,8 +243,8 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen } } - @PUT @Override + @PUT @Path("{deviceTypeName}/versions") public Response updateDeviceTypeVersion(@PathParam("deviceTypeName") String deviceTypeName, DeviceTypeVersionWrapper deviceTypeVersion) { @@ -284,8 +283,8 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen } } - @DELETE @Override + @DELETE @Path("{deviceTypeName}/versions/{version}") public Response deleteDeviceTypeVersion(@PathParam("deviceTypeName") String deviceTypeName, @PathParam("version") String version) { @@ -319,4 +318,25 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen } } + @Override + @DELETE + @Path("{deviceType}/delete") + public Response deleteDeviceType(@PathParam("deviceType") String deviceType) { + try { + DeviceManagementProviderService deviceManagementProviderService = + DeviceMgtAPIUtils.getDeviceManagementService(); + if (!deviceManagementProviderService.deleteDeviceType(deviceType)){ + String msg = "Error occurred while deleting device of type: " + deviceType; + log.error(msg); + return Response.serverError().entity(msg).build(); + } + return Response.status(Response.Status.ACCEPTED).entity( + "Device of type: " + deviceType + " permanently deleted.").build(); + } catch (DeviceManagementException e) { + String msg = "Error occurred while deleting device of type: " + deviceType; + log.error(msg, e); + return Response.serverError().entity(msg).build(); + } + } + } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java index ca151c7bd28..c26c0463ee4 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java @@ -216,4 +216,33 @@ public class DeviceTypeManagementAdminServiceTest { "The Response Status code should be 500."); Mockito.reset(deviceManagementProviderService); } + + @Test(description = "Test delete device type with correct request.") + public void testDeleteDeviceType() { + PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) + .toReturn(this.deviceManagementProviderService); + Response response = this.deviceTypeManagementAdminService.deleteDeviceType(TEST_DEVICE_TYPE); + Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); + } + + @Test(description = "Test delete device type when unavailable.") + public void testDeleteNonExistingDeviceType() throws DeviceManagementException { + PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) + .toReturn(this.deviceManagementProviderService); + Mockito.when(deviceManagementProviderService.getDeviceType(Mockito.anyString())).thenReturn(null); + Response response = this.deviceTypeManagementAdminService.deleteDeviceType(TEST_DEVICE_TYPE); + Assert.assertEquals(response.getStatus(), Response.Status.NOT_FOUND.getStatusCode()); + Mockito.reset(this.deviceManagementProviderService); + } + + @Test(description = "Test delete device type when DeviceManagementException is thrown.") + public void testDeleteDeviceTypeWithException() throws DeviceManagementException { + PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) + .toReturn(this.deviceManagementProviderService); + Mockito.when(this.deviceManagementProviderService.deleteDeviceType(TEST_DEVICE_TYPE)) + .thenThrow(new DeviceManagementException()); + Response response = this.deviceTypeManagementAdminService.deleteDeviceType(TEST_DEVICE_TYPE); + Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); + Mockito.reset(this.deviceManagementProviderService); + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/resources/testng.xml b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/resources/testng.xml index 8eef6324598..b3b9a2da444 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/resources/testng.xml +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/resources/testng.xml @@ -32,6 +32,7 @@ + diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceTypeDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceTypeDAO.java index 4ae4289993f..37bf726c38a 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceTypeDAO.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceTypeDAO.java @@ -128,4 +128,13 @@ public interface DeviceTypeDAO { DeviceTypeVersion getDeviceTypeVersion(int deviceTypeId, String version) throws DeviceManagementDAOException; + + /** + * Permanently remove a device type + * + * @param tenantId current tenant's id + * @param deviceTypeId device type id + * @throws DeviceManagementDAOException Might occur while executing database queries + */ + void deleteDeviceType(int tenantId, int deviceTypeId) 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/DeviceTypeDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/DeviceTypeDAOImpl.java index 35e92651908..66f9fced1a2 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/DeviceTypeDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/DeviceTypeDAOImpl.java @@ -411,6 +411,29 @@ public class DeviceTypeDAOImpl implements DeviceTypeDAO { } + @Override + public void deleteDeviceType(int tenantID, int deviceTypeId) throws DeviceManagementDAOException { + Connection conn; + PreparedStatement stmt = null; + try { + conn = getConnection(); + String sql = "DELETE FROM DM_DEVICE_TYPE" + + " WHERE" + + " ID = ?" + + " AND PROVIDER_TENANT_ID = ?"; + stmt = conn.prepareStatement(sql); + stmt.setInt(1, deviceTypeId); + stmt.setInt(2, tenantID); + stmt.execute(); + } catch (SQLException e) { + throw new DeviceManagementDAOException( + "Error occurred while deleting device type of id: " + deviceTypeId + + " for tenant: " + tenantID, e); + } finally { + DeviceManagementDAOUtil.cleanupResources(stmt, null); + } + } + 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/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 8765ed22e54..cdc5379ea7d 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 @@ -611,7 +611,7 @@ public interface DeviceManagementProviderService { boolean disenrollDevice(DeviceIdentifier deviceId) throws DeviceManagementException; - boolean deleteDevices(List deviceIdentifiers) throws DeviceManagementException, InvalidDeviceException; + boolean deleteDevices(List deviceIdentifiers, boolean transactionAlreadyExists) throws DeviceManagementException, InvalidDeviceException; boolean isEnrolled(DeviceIdentifier deviceId) throws DeviceManagementException; @@ -708,7 +708,7 @@ public interface DeviceManagementProviderService { */ boolean changeDeviceStatus(DeviceIdentifier deviceIdentifier, EnrolmentInfo.Status newStatus) throws DeviceManagementException; - + /** * This will handle add and update of device type services. * @param deviceManagementService @@ -771,6 +771,16 @@ public interface DeviceManagementProviderService { DeviceTypeVersion getDeviceTypeVersion(String deviceTypeName, String version) throws DeviceManagementException; + + /** + * Permanently delete a device type + * + * @param deviceTypeName device type name + * @return True if device type successfully removed + * @throws DeviceManagementException + */ + boolean deleteDeviceType(String deviceTypeName) throws DeviceManagementException; + /** * Retrieves a list of configurations of a specific device * using the device's properties 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 1efdb78a746..0c65a79fa84 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 @@ -153,7 +153,6 @@ import java.util.List; import java.util.Arrays; import java.util.Map; import java.util.Properties; -import java.util.Set; public class DeviceManagementProviderServiceImpl implements DeviceManagementProviderService, PluginInitializationListener { @@ -528,7 +527,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } @Override - public boolean deleteDevices(List deviceIdentifiers) throws DeviceManagementException, + public boolean deleteDevices(List deviceIdentifiers, boolean transactionAlreadyExists) throws DeviceManagementException, InvalidDeviceException { if (deviceIdentifiers == null || deviceIdentifiers.isEmpty()) { String msg = "Required values of device identifiers are not set to permanently delete device/s."; @@ -3584,6 +3583,101 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv return versions; } + @Override + public boolean deleteDeviceType(String deviceTypeName) throws DeviceManagementException { + int tenantId = getTenantId(); + List deviceIdentifiers; + List deviceTypeVersions; + boolean result; + + try { + if (deviceTypeName.isEmpty()) { + String msg = "Error, device type cannot be null or empty"; + log.error(msg); + return false; + } + DeviceManagementDAOFactory.beginTransaction(); + DeviceType deviceTypeObj = deviceTypeDAO.getDeviceType(deviceTypeName, tenantId); + if (deviceTypeObj == null) { + String msg = "Error, device of type: " + deviceTypeName + " does not exist"; + log.error(msg); + return false; + } + List devices = deviceDAO.getDevices(deviceTypeName, this.getTenantId()); + if (devices.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug("No devices found for the device type: " + deviceTypeName); + } + } else { + // dis-enroll devices + deviceIdentifiers = new ArrayList<>(); + for (Device device : devices) { + if (device.getEnrolmentInfo().getStatus().equals(EnrolmentInfo.Status.REMOVED)) { + if (log.isDebugEnabled()) { + log.debug("Device: " + device.getName() + " has already dis-enrolled"); + } + } else { + device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime()); + device.getEnrolmentInfo().setStatus(EnrolmentInfo.Status.REMOVED); + enrollmentDAO.updateEnrollment(device.getId(), device.getEnrolmentInfo(), + tenantId); + deviceDAO.updateDevice(device, tenantId); + } + deviceIdentifiers.add(device.getDeviceIdentifier()); + } + // delete devices + deleteDevices(deviceIdentifiers, true); + } + // remove device type versions + deviceTypeVersions = deviceTypeDAO.getDeviceTypeVersions( + deviceTypeObj.getId(), deviceTypeName); + if (deviceTypeVersions.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug("Device type: " + deviceTypeName + "doesn't have any type versions"); + } + } else { + for (DeviceTypeVersion deviceTypeVersion : deviceTypeVersions) { + result = deviceTypeDAO.isDeviceTypeVersionModifiable(deviceTypeObj.getId() + , deviceTypeVersion.getVersionName(), tenantId); + if (!result) { + DeviceManagementDAOFactory.rollbackTransaction(); + String msg = "Device type of: " + deviceTypeName + "is unauthorized to modify " + + "version"; + log.error(msg); + return false; + } + result = deviceTypeDAO.updateDeviceTypeVersion(deviceTypeVersion); + if (!result) { + DeviceManagementDAOFactory.rollbackTransaction(); + String msg = "Could not delete the version of device type: " + + deviceTypeName; + log.error(msg); + return false; + } + } + } + // delete device type + deviceTypeDAO.deleteDeviceType(tenantId, deviceTypeObj.getId()); + DeviceManagementDAOFactory.commitTransaction(); + } catch (InvalidDeviceException e) { + String msg = "Error occurred while deleting devices of type: " + deviceTypeName; + log.error(msg); + throw new DeviceManagementException(msg, e); + } catch (DeviceManagementDAOException e) { + DeviceManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred while deleting device type of: " + deviceTypeName; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } catch (TransactionManagementException e) { + String msg = "Error occurred while initiating transaction"; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } finally { + DeviceManagementDAOFactory.closeConnection(); + } + return true; + } + @Override public DeviceConfiguration getDeviceConfiguration(Map deviceProps) throws DeviceManagementException, DeviceNotFoundException, UnauthorizedDeviceAccessException, From 2e62acfafc5a7c533e1b9f6e56bd939558497025 Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Wed, 18 Dec 2019 14:02:18 +0530 Subject: [PATCH 04/18] Fix issue with deleting devices Already dis-enrolled devices won't be deleted due to attempting to create a new DAO connection while a one already exists for the same DAO Factory. This error will occur when starting a server with already dis-enrolled devices and by trying to delete them --- .../service/DeviceManagementProviderServiceImpl.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) 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 0c65a79fa84..a823a76bfb3 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 @@ -527,7 +527,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } @Override - public boolean deleteDevices(List deviceIdentifiers, boolean transactionAlreadyExists) throws DeviceManagementException, + public boolean deleteDevices(List deviceIdentifiers) throws DeviceManagementException, InvalidDeviceException { if (deviceIdentifiers == null || deviceIdentifiers.isEmpty()) { String msg = "Required values of device identifiers are not set to permanently delete device/s."; @@ -542,12 +542,12 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv List deviceCacheKeyList = new ArrayList<>(); int tenantId = this.getTenantId(); try { - DeviceManagementDAOFactory.beginTransaction(); + DeviceManagementDAOFactory.openConnection(); List existingDevices = deviceDAO.getDevicesByIdentifiers(deviceIdentifiers, tenantId); + DeviceManagementDAOFactory.closeConnection(); DeviceCacheKey deviceCacheKey; for (Device device : existingDevices) { if (!EnrolmentInfo.Status.REMOVED.equals(device.getEnrolmentInfo().getStatus())) { - DeviceManagementDAOFactory.rollbackTransaction(); String msg = "Device " + device.getDeviceIdentifier() + " of type " + device.getType() + " is not dis-enrolled to permanently delete the device"; log.error(msg); @@ -583,6 +583,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv if (log.isDebugEnabled()) { log.debug("Permanently deleting the details of devices : " + validDeviceIdentifiers); } + DeviceManagementDAOFactory.beginTransaction(); //deleting device from the core deviceDAO.deleteDevices(validDeviceIdentifiers, new ArrayList<>(deviceIds), enrollmentIds); for (Map.Entry entry : deviceManagerMap.entrySet()) { @@ -605,6 +606,10 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv log.debug("Successfully permanently deleted the details of devices : " + validDeviceIdentifiers); } return true; + } catch (SQLException e) { + String msg = "Error occurred while opening a connection to the data source"; + log.error(msg, e); + throw new DeviceManagementException(msg, e); } catch (TransactionManagementException e) { String msg = "Error occurred while initiating transaction"; log.error(msg, e); From 3f9dba93568fcf03f5f1aff3036da60b34f0c531 Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Wed, 18 Dec 2019 14:24:14 +0530 Subject: [PATCH 05/18] Complete implementation of device type permanent delete This service will do following modifications to achieve it's functionality, 1. Dis-enroll and delete all devices of a device type 2. Remove platform configuration of a device type 3. Delete the device type --- .../impl/admin/DeviceManagementAdminServiceImpl.java | 2 +- .../service/DeviceManagementProviderService.java | 6 +++--- .../service/DeviceManagementProviderServiceImpl.java | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java index 360a41679f8..9533c43a42a 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java @@ -169,7 +169,7 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe DeviceManagementProviderService deviceManagementProviderService = DeviceMgtAPIUtils.getDeviceManagementService(); try { - if (!deviceManagementProviderService.deleteDevices(deviceIdentifiers, false)) { + if (!deviceManagementProviderService.deleteDevices(deviceIdentifiers)) { String msg = "Found un-deployed device type."; log.error(msg); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity( 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 cdc5379ea7d..9246d2fc974 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 @@ -611,7 +611,7 @@ public interface DeviceManagementProviderService { boolean disenrollDevice(DeviceIdentifier deviceId) throws DeviceManagementException; - boolean deleteDevices(List deviceIdentifiers, boolean transactionAlreadyExists) throws DeviceManagementException, InvalidDeviceException; + boolean deleteDevices(List deviceIdentifiers) throws DeviceManagementException, InvalidDeviceException; boolean isEnrolled(DeviceIdentifier deviceId) throws DeviceManagementException; @@ -773,11 +773,11 @@ public interface DeviceManagementProviderService { DeviceManagementException; /** - * Permanently delete a device type + * Permanently delete a device type with all it's devices * * @param deviceTypeName device type name * @return True if device type successfully removed - * @throws DeviceManagementException + * @throws DeviceManagementException Will be thrown if any service level or DAO level error occurs */ boolean deleteDeviceType(String deviceTypeName) 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 a823a76bfb3..b7190c03aa9 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 @@ -3630,22 +3630,23 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } deviceIdentifiers.add(device.getDeviceIdentifier()); } + DeviceManagementDAOFactory.commitTransaction(); + DeviceManagementDAOFactory.closeConnection(); // delete devices - deleteDevices(deviceIdentifiers, true); + deleteDevices(deviceIdentifiers); + DeviceManagementDAOFactory.beginTransaction(); } // remove device type versions - deviceTypeVersions = deviceTypeDAO.getDeviceTypeVersions( - deviceTypeObj.getId(), deviceTypeName); + deviceTypeVersions = deviceTypeDAO.getDeviceTypeVersions(deviceTypeObj.getId(), deviceTypeName); if (deviceTypeVersions.isEmpty()) { if (log.isDebugEnabled()) { - log.debug("Device type: " + deviceTypeName + "doesn't have any type versions"); + log.debug("Device of type: " + deviceTypeName + "doesn't have any type versions"); } } else { for (DeviceTypeVersion deviceTypeVersion : deviceTypeVersions) { result = deviceTypeDAO.isDeviceTypeVersionModifiable(deviceTypeObj.getId() , deviceTypeVersion.getVersionName(), tenantId); if (!result) { - DeviceManagementDAOFactory.rollbackTransaction(); String msg = "Device type of: " + deviceTypeName + "is unauthorized to modify " + "version"; log.error(msg); @@ -3653,7 +3654,6 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } result = deviceTypeDAO.updateDeviceTypeVersion(deviceTypeVersion); if (!result) { - DeviceManagementDAOFactory.rollbackTransaction(); String msg = "Could not delete the version of device type: " + deviceTypeName; log.error(msg); From b3ff6ed7874b6355d1d09149a12cb819db4c5bda Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Wed, 18 Dec 2019 14:51:10 +0530 Subject: [PATCH 06/18] Remove unavailable tests --- .../org.wso2.carbon.device.mgt.api/src/test/resources/testng.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/resources/testng.xml b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/resources/testng.xml index b3b9a2da444..8eef6324598 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/resources/testng.xml +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/resources/testng.xml @@ -32,7 +32,6 @@ - From 7dcd2be02e96f6a201e3d08a93821a93889c520f Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Thu, 19 Dec 2019 11:40:20 +0530 Subject: [PATCH 07/18] Complete tests to remove devices --- .../DeviceTypeManagementAdminServiceTest.java | 45 ++++++++++++++----- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java index c26c0463ee4..3ee922c1f4b 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/test/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceTypeManagementAdminServiceTest.java @@ -15,6 +15,23 @@ * specific language governing permissions and limitations * under the License. */ +/* + * 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.mgt.jaxrs.service.impl; @@ -218,31 +235,35 @@ public class DeviceTypeManagementAdminServiceTest { } @Test(description = "Test delete device type with correct request.") - public void testDeleteDeviceType() { + public void testDeleteDeviceType() throws DeviceManagementException { PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) - .toReturn(this.deviceManagementProviderService); - Response response = this.deviceTypeManagementAdminService.deleteDeviceType(TEST_DEVICE_TYPE); - Assert.assertEquals(response.getStatus(), Response.Status.OK.getStatusCode()); + .toReturn(deviceManagementProviderService); + Mockito.when(deviceManagementProviderService. + deleteDeviceType(Mockito.anyString(), Mockito.any(DeviceType.class))). + thenReturn(true); + Response response = deviceTypeManagementAdminService.deleteDeviceType(TEST_DEVICE_TYPE); + Assert.assertEquals(response.getStatus(), Response.Status.ACCEPTED.getStatusCode()); } @Test(description = "Test delete device type when unavailable.") public void testDeleteNonExistingDeviceType() throws DeviceManagementException { PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) - .toReturn(this.deviceManagementProviderService); + .toReturn(deviceManagementProviderService); Mockito.when(deviceManagementProviderService.getDeviceType(Mockito.anyString())).thenReturn(null); - Response response = this.deviceTypeManagementAdminService.deleteDeviceType(TEST_DEVICE_TYPE); + Response response = deviceTypeManagementAdminService.deleteDeviceType(TEST_DEVICE_TYPE); Assert.assertEquals(response.getStatus(), Response.Status.NOT_FOUND.getStatusCode()); - Mockito.reset(this.deviceManagementProviderService); + Mockito.reset(deviceManagementProviderService); } @Test(description = "Test delete device type when DeviceManagementException is thrown.") public void testDeleteDeviceTypeWithException() throws DeviceManagementException { PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) - .toReturn(this.deviceManagementProviderService); - Mockito.when(this.deviceManagementProviderService.deleteDeviceType(TEST_DEVICE_TYPE)) - .thenThrow(new DeviceManagementException()); - Response response = this.deviceTypeManagementAdminService.deleteDeviceType(TEST_DEVICE_TYPE); + .toReturn(deviceManagementProviderService); + Mockito.when(deviceManagementProviderService. + deleteDeviceType(Mockito.anyString(), Mockito.any(DeviceType.class))). + thenThrow(new DeviceManagementException()); + Response response = deviceTypeManagementAdminService.deleteDeviceType(TEST_DEVICE_TYPE); Assert.assertEquals(response.getStatus(), Response.Status.INTERNAL_SERVER_ERROR.getStatusCode()); - Mockito.reset(this.deviceManagementProviderService); + Mockito.reset(deviceManagementProviderService); } } From 709af6795bc97a8792e706ec43c33a2a23751b0b Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Thu, 19 Dec 2019 11:41:21 +0530 Subject: [PATCH 08/18] Update licence --- .../device/mgt/core/dao/DeviceTypeDAO.java | 17 +++++++++++++++++ .../mgt/core/dao/impl/DeviceTypeDAOImpl.java | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceTypeDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceTypeDAO.java index 37bf726c38a..def5ee32ffa 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceTypeDAO.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceTypeDAO.java @@ -15,6 +15,23 @@ * specific language governing permissions and limitations * under the License. */ +/* + * 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.mgt.core.dao; import org.wso2.carbon.device.mgt.core.dto.DeviceType; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/DeviceTypeDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/DeviceTypeDAOImpl.java index 66f9fced1a2..5084428ce91 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/DeviceTypeDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/DeviceTypeDAOImpl.java @@ -15,6 +15,23 @@ * specific language governing permissions and limitations * under the License. */ +/* + * 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.mgt.core.dao.impl; import com.google.gson.Gson; From 426287fdc18303c7c0e2e509146751bc51f5f3fc Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Thu, 19 Dec 2019 11:44:32 +0530 Subject: [PATCH 09/18] Update service to check device type validation at service level and return a Not Found request, if device type doesn't exist --- .../DeviceTypeManagementAdminService.java | 6 +++--- .../DeviceTypeManagementAdminServiceImpl.java | 21 ++++++++++++------- .../DeviceManagementProviderService.java | 5 +++-- .../DeviceManagementProviderServiceImpl.java | 19 +++++++---------- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java index efeaa393633..22432abe94c 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java @@ -594,7 +594,7 @@ public interface DeviceTypeManagementAdminService { @DELETE - @Path("{deviceType}/delete") + @Path("{deviceTypeName}/delete") @ApiOperation( httpMethod = "DELETE", value = "Delete device type.", @@ -628,8 +628,8 @@ public interface DeviceTypeManagementAdminService { }) Response deleteDeviceType( @ApiParam( - name = "deviceType", + name = "deviceTypeName", value = "Device type name.", required = true) - @PathParam("deviceType") String deviceType); + @PathParam("deviceTypeName") String deviceTypeName); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java index e3bedfd816b..909f998d527 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java @@ -320,20 +320,27 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen @Override @DELETE - @Path("{deviceType}/delete") - public Response deleteDeviceType(@PathParam("deviceType") String deviceType) { + @Path("{deviceTypeName}/delete") + public Response deleteDeviceType(@PathParam("deviceTypeName") String deviceTypeName) { try { DeviceManagementProviderService deviceManagementProviderService = DeviceMgtAPIUtils.getDeviceManagementService(); - if (!deviceManagementProviderService.deleteDeviceType(deviceType)){ - String msg = "Error occurred while deleting device of type: " + deviceType; + DeviceType deviceType = deviceManagementProviderService.getDeviceType(deviceTypeName); + if (deviceType == null) { + String msg = "Error, device of type: " + deviceTypeName + " does not exist"; + log.error(msg); + return Response.status(Response.Status.NOT_FOUND).entity(msg).build(); + } + if (!deviceManagementProviderService.deleteDeviceType(deviceTypeName, deviceType)){ + String msg = "Error occurred while deleting device of type: " + deviceTypeName; log.error(msg); return Response.serverError().entity(msg).build(); } - return Response.status(Response.Status.ACCEPTED).entity( - "Device of type: " + deviceType + " permanently deleted.").build(); + return Response.status(Response.Status.ACCEPTED) + .entity("Device of type: " + deviceTypeName + " permanently deleted.") + .build(); } catch (DeviceManagementException e) { - String msg = "Error occurred while deleting device of type: " + deviceType; + String msg = "Error occurred while deleting device of type: " + deviceTypeName; log.error(msg, e); return Response.serverError().entity(msg).build(); } 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 9246d2fc974..20873499405 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 @@ -775,11 +775,12 @@ public interface DeviceManagementProviderService { /** * Permanently delete a device type with all it's devices * - * @param deviceTypeName device type name + * @param deviceTypeName Device type name + * @param deviceType Device type object * @return True if device type successfully removed * @throws DeviceManagementException Will be thrown if any service level or DAO level error occurs */ - boolean deleteDeviceType(String deviceTypeName) throws DeviceManagementException; + boolean deleteDeviceType(String deviceTypeName, DeviceType deviceType) throws DeviceManagementException; /** * Retrieves a list of configurations of a specific device 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 b7190c03aa9..0fb4f086a14 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 @@ -3589,25 +3589,20 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } @Override - public boolean deleteDeviceType(String deviceTypeName) throws DeviceManagementException { - int tenantId = getTenantId(); + public boolean deleteDeviceType(String deviceTypeName, DeviceType deviceType) + throws DeviceManagementException { List deviceIdentifiers; List deviceTypeVersions; boolean result; + int tenantId = getTenantId(); try { - if (deviceTypeName.isEmpty()) { + if (deviceTypeName.isEmpty() || deviceType == null) { String msg = "Error, device type cannot be null or empty"; log.error(msg); return false; } DeviceManagementDAOFactory.beginTransaction(); - DeviceType deviceTypeObj = deviceTypeDAO.getDeviceType(deviceTypeName, tenantId); - if (deviceTypeObj == null) { - String msg = "Error, device of type: " + deviceTypeName + " does not exist"; - log.error(msg); - return false; - } List devices = deviceDAO.getDevices(deviceTypeName, this.getTenantId()); if (devices.isEmpty()) { if (log.isDebugEnabled()) { @@ -3637,14 +3632,14 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv DeviceManagementDAOFactory.beginTransaction(); } // remove device type versions - deviceTypeVersions = deviceTypeDAO.getDeviceTypeVersions(deviceTypeObj.getId(), deviceTypeName); + deviceTypeVersions = deviceTypeDAO.getDeviceTypeVersions(deviceType.getId(), deviceTypeName); if (deviceTypeVersions.isEmpty()) { if (log.isDebugEnabled()) { log.debug("Device of type: " + deviceTypeName + "doesn't have any type versions"); } } else { for (DeviceTypeVersion deviceTypeVersion : deviceTypeVersions) { - result = deviceTypeDAO.isDeviceTypeVersionModifiable(deviceTypeObj.getId() + result = deviceTypeDAO.isDeviceTypeVersionModifiable(deviceType.getId() , deviceTypeVersion.getVersionName(), tenantId); if (!result) { String msg = "Device type of: " + deviceTypeName + "is unauthorized to modify " + @@ -3662,7 +3657,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } } // delete device type - deviceTypeDAO.deleteDeviceType(tenantId, deviceTypeObj.getId()); + deviceTypeDAO.deleteDeviceType(tenantId, deviceType.getId()); DeviceManagementDAOFactory.commitTransaction(); } catch (InvalidDeviceException e) { String msg = "Error occurred while deleting devices of type: " + deviceTypeName; From 1b26a8e2e7031353f4d975acd30e03bd6ae2c97e Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Fri, 20 Dec 2019 11:07:06 +0530 Subject: [PATCH 10/18] Update license --- .../ArtifactAlreadyExistsException.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/exception/ArtifactAlreadyExistsException.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/exception/ArtifactAlreadyExistsException.java index 78a75331cbf..aa56e0d30fe 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/exception/ArtifactAlreadyExistsException.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/exception/ArtifactAlreadyExistsException.java @@ -1,3 +1,20 @@ +/* + * 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.mgt.jaxrs.exception; public class ArtifactAlreadyExistsException extends Exception { From 2692c40467869af327d5813c584de98ab9075a28 Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Fri, 20 Dec 2019 11:08:09 +0530 Subject: [PATCH 11/18] Update response messages --- .../impl/AnalyticsArtifactsManagementServiceImpl.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java index a73baa90cb1..2958d5b3a0c 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java @@ -89,11 +89,13 @@ public class AnalyticsArtifactsManagementServiceImpl return Response.serverError().entity(errMsg).build(); } } catch (ArtifactAlreadyExistsException e) { - String errMsg = "Failed to create Stream artifact for tenant domain: " + tenantDomain; + String errMsg = "Failed to create Stream artifact for tenant domain: " + tenantDomain + + "Stream with id: "+ id + "already exists"; log.error(errMsg, e); return Response.status(Response.Status.BAD_REQUEST).entity(errMsg).build(); } catch (NotFoundException e) { - String errMsg = "Failed to edit Stream artifact for tenant domain: " + tenantDomain; + String errMsg = "Failed to edit Stream artifact for tenant domain: " + tenantDomain + + "Stream with id: "+ id + "doesn't exist"; log.error(errMsg, e); return Response.status(Response.Status.NOT_FOUND).entity(errMsg).build(); } catch (AxisFault e) { From 5ff23bec023ea778b27922354036b239bbc37c98 Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Fri, 20 Dec 2019 11:09:21 +0530 Subject: [PATCH 12/18] Update api paths with a leading forward slash --- .../api/admin/DeviceTypeManagementAdminService.java | 6 +++--- .../impl/admin/DeviceTypeManagementAdminServiceImpl.java | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java index 22432abe94c..355f40fea08 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java @@ -487,7 +487,7 @@ public interface DeviceTypeManagementAdminService { @PUT @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) - @Path("{deviceTypeName}/versions") + @Path("/{deviceTypeName}/versions") @ApiOperation( produces = MediaType.APPLICATION_JSON, httpMethod = "PUT", @@ -541,7 +541,7 @@ public interface DeviceTypeManagementAdminService { @DELETE - @Path("{deviceTypeName}/versions/{version}") + @Path("/{deviceTypeName}/versions/{version}") @ApiOperation( produces = MediaType.APPLICATION_JSON, httpMethod = "DELETE", @@ -594,7 +594,7 @@ public interface DeviceTypeManagementAdminService { @DELETE - @Path("{deviceTypeName}/delete") + @Path("/{deviceTypeName}/delete") @ApiOperation( httpMethod = "DELETE", value = "Delete device type.", diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java index 909f998d527..0ced60caf01 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java @@ -188,7 +188,7 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen @Override @POST - @Path("{deviceTypeName}/versions") + @Path("/{deviceTypeName}/versions") public Response addDeviceTypeVersion(@PathParam("deviceTypeName") String deviceTypeName, DeviceTypeVersionWrapper versionWrapper) { if (versionWrapper != null && deviceTypeName != null && !deviceTypeName.isEmpty() @@ -245,7 +245,7 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen @Override @PUT - @Path("{deviceTypeName}/versions") + @Path("/{deviceTypeName}/versions") public Response updateDeviceTypeVersion(@PathParam("deviceTypeName") String deviceTypeName, DeviceTypeVersionWrapper deviceTypeVersion) { if (deviceTypeVersion != null && deviceTypeVersion.getVersionName() == null || deviceTypeVersion @@ -285,7 +285,7 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen @Override @DELETE - @Path("{deviceTypeName}/versions/{version}") + @Path("/{deviceTypeName}/versions/{version}") public Response deleteDeviceTypeVersion(@PathParam("deviceTypeName") String deviceTypeName, @PathParam("version") String version) { if (version == null || version.isEmpty()) { @@ -320,7 +320,7 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen @Override @DELETE - @Path("{deviceTypeName}/delete") + @Path("/{deviceTypeName}/delete") public Response deleteDeviceType(@PathParam("deviceTypeName") String deviceTypeName) { try { DeviceManagementProviderService deviceManagementProviderService = From b76a838deaa6c7ae33a0393b3e6bf6e5352c9ccc Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Fri, 20 Dec 2019 11:10:08 +0530 Subject: [PATCH 13/18] Isolate dao transactions --- .../DeviceManagementProviderServiceImpl.java | 53 ++++++++++++++----- 1 file changed, 41 insertions(+), 12 deletions(-) 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 0fb4f086a14..35f627a08b8 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 @@ -540,11 +540,27 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv Map> deviceIdentifierMap = new HashMap<>(); Map deviceManagerMap = new HashMap<>(); List deviceCacheKeyList = new ArrayList<>(); + List existingDevices; int tenantId = this.getTenantId(); + try { DeviceManagementDAOFactory.openConnection(); - List existingDevices = deviceDAO.getDevicesByIdentifiers(deviceIdentifiers, tenantId); + existingDevices = deviceDAO.getDevicesByIdentifiers(deviceIdentifiers, tenantId); + } catch (DeviceManagementDAOException e) { + DeviceManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred while permanently deleting '" + deviceIdentifiers + + "' devices"; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } catch (SQLException e) { + String msg = "Error occurred while opening a connection to the data source"; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + }finally { DeviceManagementDAOFactory.closeConnection(); + } + + try { DeviceCacheKey deviceCacheKey; for (Device device : existingDevices) { if (!EnrolmentInfo.Status.REMOVED.equals(device.getEnrolmentInfo().getStatus())) { @@ -606,10 +622,6 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv log.debug("Successfully permanently deleted the details of devices : " + validDeviceIdentifiers); } return true; - } catch (SQLException e) { - String msg = "Error occurred while opening a connection to the data source"; - log.error(msg, e); - throw new DeviceManagementException(msg, e); } catch (TransactionManagementException e) { String msg = "Error occurred while initiating transaction"; log.error(msg, e); @@ -3597,14 +3609,14 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv int tenantId = getTenantId(); try { - if (deviceTypeName.isEmpty() || deviceType == null) { + if (deviceType == null || deviceTypeName.isEmpty()) { String msg = "Error, device type cannot be null or empty"; log.error(msg); return false; } DeviceManagementDAOFactory.beginTransaction(); List devices = deviceDAO.getDevices(deviceTypeName, this.getTenantId()); - if (devices.isEmpty()) { + if (devices == null || devices.isEmpty()) { if (log.isDebugEnabled()) { log.debug("No devices found for the device type: " + deviceTypeName); } @@ -3619,9 +3631,26 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } else { device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime()); device.getEnrolmentInfo().setStatus(EnrolmentInfo.Status.REMOVED); - enrollmentDAO.updateEnrollment(device.getId(), device.getEnrolmentInfo(), - tenantId); - deviceDAO.updateDevice(device, tenantId); + // different try blocks are used to isolate transactions + try { + enrollmentDAO.updateEnrollment(device.getId(), device.getEnrolmentInfo(), + tenantId); + } catch (DeviceManagementDAOException e) { + DeviceManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred while dis-enrolling device: " + + device.getName(); + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + try { + deviceDAO.updateDevice(device, tenantId); + } catch (DeviceManagementDAOException e) { + DeviceManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred while updating device: " + + device.getName(); + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } } deviceIdentifiers.add(device.getDeviceIdentifier()); } @@ -3629,11 +3658,11 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv DeviceManagementDAOFactory.closeConnection(); // delete devices deleteDevices(deviceIdentifiers); - DeviceManagementDAOFactory.beginTransaction(); } // remove device type versions + DeviceManagementDAOFactory.beginTransaction(); deviceTypeVersions = deviceTypeDAO.getDeviceTypeVersions(deviceType.getId(), deviceTypeName); - if (deviceTypeVersions.isEmpty()) { + if (deviceTypeVersions == null || deviceTypeVersions.isEmpty()) { if (log.isDebugEnabled()) { log.debug("Device of type: " + deviceTypeName + "doesn't have any type versions"); } From 1c2d1f52a057a13ddcc48079366c65925c5c4fcb Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Fri, 3 Jan 2020 08:26:34 +0530 Subject: [PATCH 14/18] Update device type delete service to reduce generality of the method by specifying different methods for each single responsibility --- .../DeviceManagementProviderService.java | 18 ++ .../DeviceManagementProviderServiceImpl.java | 156 +++++++++++------- 2 files changed, 117 insertions(+), 57 deletions(-) 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 20873499405..e593221869d 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 @@ -772,6 +772,24 @@ public interface DeviceManagementProviderService { DeviceTypeVersion getDeviceTypeVersion(String deviceTypeName, String version) throws DeviceManagementException; + /** + * Remove all versions of a device type + * + * @param deviceType Device type object + * @return True if device type versions are removed + * @throws DeviceManagementException Will be thrown if any service level or DAO level error occurs + */ + boolean deleteDeviceTypeVersions(DeviceType deviceType) + throws DeviceManagementException; + + /** + * Dis-enroll all devices passed + * + * @param devices List of devices to dis-enroll + * @throws DeviceManagementException Will be thrown if any service level or DAO level error occurs + */ + void disEnrollDevices(List devices) throws DeviceManagementException; + /** * Permanently delete a device type with all it's devices * 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 35f627a08b8..0174a8b93f3 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 @@ -153,6 +153,7 @@ import java.util.List; import java.util.Arrays; import java.util.Map; import java.util.Properties; +import java.util.stream.Collectors; public class DeviceManagementProviderServiceImpl implements DeviceManagementProviderService, PluginInitializationListener { @@ -3604,109 +3605,150 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv public boolean deleteDeviceType(String deviceTypeName, DeviceType deviceType) throws DeviceManagementException { List deviceIdentifiers; - List deviceTypeVersions; - boolean result; - int tenantId = getTenantId(); try { - if (deviceType == null || deviceTypeName.isEmpty()) { + if (deviceType == null || deviceTypeName == null || deviceTypeName.isEmpty()) { String msg = "Error, device type cannot be null or empty"; log.error(msg); return false; } - DeviceManagementDAOFactory.beginTransaction(); - List devices = deviceDAO.getDevices(deviceTypeName, this.getTenantId()); + List devices = getAllDevices(deviceTypeName, false); if (devices == null || devices.isEmpty()) { if (log.isDebugEnabled()) { log.debug("No devices found for the device type: " + deviceTypeName); } } else { // dis-enroll devices - deviceIdentifiers = new ArrayList<>(); - for (Device device : devices) { - if (device.getEnrolmentInfo().getStatus().equals(EnrolmentInfo.Status.REMOVED)) { - if (log.isDebugEnabled()) { - log.debug("Device: " + device.getName() + " has already dis-enrolled"); - } - } else { - device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime()); - device.getEnrolmentInfo().setStatus(EnrolmentInfo.Status.REMOVED); - // different try blocks are used to isolate transactions - try { - enrollmentDAO.updateEnrollment(device.getId(), device.getEnrolmentInfo(), - tenantId); - } catch (DeviceManagementDAOException e) { - DeviceManagementDAOFactory.rollbackTransaction(); - String msg = "Error occurred while dis-enrolling device: " + - device.getName(); - log.error(msg, e); - throw new DeviceManagementException(msg, e); - } - try { - deviceDAO.updateDevice(device, tenantId); - } catch (DeviceManagementDAOException e) { - DeviceManagementDAOFactory.rollbackTransaction(); - String msg = "Error occurred while updating device: " + - device.getName(); - log.error(msg, e); - throw new DeviceManagementException(msg, e); - } - } - deviceIdentifiers.add(device.getDeviceIdentifier()); - } - DeviceManagementDAOFactory.commitTransaction(); - DeviceManagementDAOFactory.closeConnection(); + disEnrollDevices(devices); // delete devices + deviceIdentifiers = devices.stream() + .map(Device::getDeviceIdentifier).collect(Collectors.toList()); deleteDevices(deviceIdentifiers); } // remove device type versions + if (!deleteDeviceTypeVersions(deviceType)){ + return false; + } + // delete device type DeviceManagementDAOFactory.beginTransaction(); - deviceTypeVersions = deviceTypeDAO.getDeviceTypeVersions(deviceType.getId(), deviceTypeName); + deviceTypeDAO.deleteDeviceType(getTenantId(), deviceType.getId()); + DeviceManagementDAOFactory.commitTransaction(); + } catch (InvalidDeviceException e) { + String msg = "Error occurred while deleting devices of type: " + deviceTypeName; + log.error(msg); + throw new DeviceManagementException(msg, e); + } catch (DeviceManagementDAOException e) { + DeviceManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred while deleting device type of: " + deviceTypeName; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } catch (TransactionManagementException e) { + String msg = "Error occurred while initiating transaction"; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } finally { + DeviceManagementDAOFactory.closeConnection(); + } + return true; + } + + @Override + public void disEnrollDevices(List devices) + throws DeviceManagementException { + int tenantId = getTenantId(); + + try { + DeviceManagementDAOFactory.beginTransaction(); + for (Device device : devices) { + if (device.getEnrolmentInfo().getStatus().equals(EnrolmentInfo.Status.REMOVED)) { + if (log.isDebugEnabled()) { + log.debug("Device: " + device.getName() + " has already dis-enrolled"); + } + } else { + device.getEnrolmentInfo().setDateOfLastUpdate(new Date().getTime()); + device.getEnrolmentInfo().setStatus(EnrolmentInfo.Status.REMOVED); + // different try blocks are used to isolate transactions + try { + enrollmentDAO.updateEnrollment(device.getId(), device.getEnrolmentInfo(), + tenantId); + } catch (DeviceManagementDAOException e) { + DeviceManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred while dis-enrolling device: " + + device.getName(); + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + try { + deviceDAO.updateDevice(device, tenantId); + } catch (DeviceManagementDAOException e) { + DeviceManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred while updating device: " + + device.getName(); + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + } + } + DeviceManagementDAOFactory.commitTransaction(); + } catch (TransactionManagementException e) { + String msg = "Error occurred while initiating transaction"; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } finally { + DeviceManagementDAOFactory.closeConnection(); + } + } + + @Override + public boolean deleteDeviceTypeVersions(DeviceType deviceType) + throws DeviceManagementException { + boolean result; + String deviceTypeName = deviceType.getName(); + try { + DeviceManagementDAOFactory.beginTransaction(); + List deviceTypeVersions = deviceTypeDAO + .getDeviceTypeVersions(deviceType.getId(), deviceTypeName); if (deviceTypeVersions == null || deviceTypeVersions.isEmpty()) { if (log.isDebugEnabled()) { - log.debug("Device of type: " + deviceTypeName + "doesn't have any type versions"); + log.debug("Device of type: " + deviceTypeName + "doesn't have any type " + + "versions"); } } else { for (DeviceTypeVersion deviceTypeVersion : deviceTypeVersions) { result = deviceTypeDAO.isDeviceTypeVersionModifiable(deviceType.getId() - , deviceTypeVersion.getVersionName(), tenantId); + , deviceTypeVersion.getVersionName(), getTenantId()); if (!result) { - String msg = "Device type of: " + deviceTypeName + "is unauthorized to modify " + - "version"; + String msg = "Device type of: " + deviceTypeName + "is unauthorized to " + + "modify version"; log.error(msg); return false; } + deviceTypeVersion.setVersionStatus("REMOVED"); result = deviceTypeDAO.updateDeviceTypeVersion(deviceTypeVersion); if (!result) { - String msg = "Could not delete the version of device type: " + - deviceTypeName; + String msg = "Could not delete the version of device type: " + deviceTypeName; log.error(msg); return false; } } + DeviceManagementDAOFactory.commitTransaction(); } - // delete device type - deviceTypeDAO.deleteDeviceType(tenantId, deviceType.getId()); - DeviceManagementDAOFactory.commitTransaction(); - } catch (InvalidDeviceException e) { - String msg = "Error occurred while deleting devices of type: " + deviceTypeName; - log.error(msg); + } catch (TransactionManagementException e) { + String msg = "Error occurred while initiating transaction"; + log.error(msg, e); throw new DeviceManagementException(msg, e); } catch (DeviceManagementDAOException e) { DeviceManagementDAOFactory.rollbackTransaction(); String msg = "Error occurred while deleting device type of: " + deviceTypeName; log.error(msg, e); throw new DeviceManagementException(msg, e); - } catch (TransactionManagementException e) { - String msg = "Error occurred while initiating transaction"; - log.error(msg, e); - throw new DeviceManagementException(msg, e); } finally { DeviceManagementDAOFactory.closeConnection(); } return true; } + @Override public DeviceConfiguration getDeviceConfiguration(Map deviceProps) throws DeviceManagementException, DeviceNotFoundException, UnauthorizedDeviceAccessException, From 9d7ad19f57275bb9d2581f15b35a7c823b8f1c1f Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Thu, 9 Jan 2020 10:37:26 +0530 Subject: [PATCH 15/18] Updates to method comments and swagger documentation --- .../AnalyticsArtifactsManagementService.java | 201 +++---------- ...alyticsArtifactsManagementServiceImpl.java | 279 ++++++++++++------ 2 files changed, 234 insertions(+), 246 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/AnalyticsArtifactsManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/AnalyticsArtifactsManagementService.java index caacc59b39d..9ff8ecc44d8 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/AnalyticsArtifactsManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/AnalyticsArtifactsManagementService.java @@ -138,24 +138,18 @@ public interface AnalyticsArtifactsManagementService { responseHeaders = { @ResponseHeader( name = "Content-Type", - description = "The content type of the body"), - @ResponseHeader( - name = "ETag", - description = "Entity Tag of the response resource.\n" + - "Used by caches, or in conditional requests."), - @ResponseHeader( - name = "Last-Modified", - description = - "Date and time the resource was last modified.\n" + - "Used by caches, or in conditional requests."), + description = "The content type of the body") } ), @ApiResponse( code = 400, - message = "Bad Request."), + message = "Bad Request. \n The resource to add already exists."), + @ApiResponse( + code = 404, + message = "Not Found. \n The resource to edit not available."), @ApiResponse( code = 406, - message = "Not Acceptable.\n The requested media type is not supported."), + message = "Not Acceptable. \n The requested media type is not supported."), @ApiResponse( code = 500, message = "Internal Server Error. \n Server error occurred while " + @@ -202,24 +196,15 @@ public interface AnalyticsArtifactsManagementService { responseHeaders = { @ResponseHeader( name = "Content-Type", - description = "The content type of the body"), - @ResponseHeader( - name = "ETag", - description = "Entity Tag of the response resource.\n" + - "Used by caches, or in conditional requests."), - @ResponseHeader( - name = "Last-Modified", - description = - "Date and time the resource was last modified.\n" + - "Used by caches, or in conditional requests."), + description = "The content type of the body") } ), @ApiResponse( code = 400, - message = "Bad Request."), + message = "Bad Request. \n The payload is invalid."), @ApiResponse( code = 406, - message = "Not Acceptable.\n The requested media type is not supported."), + message = "Not Acceptable. \n The requested media type is not supported."), @ApiResponse( code = 500, message = "Internal Server Error. \n Server error occurred while deploying the " + @@ -235,7 +220,7 @@ public interface AnalyticsArtifactsManagementService { @Valid EventStream stream); @DELETE - @Path("/stream/{name}/{version}/delete") + @Path("/stream/{name}/{version}") @ApiOperation( httpMethod = "DELETE", value = "Delete the Stream with id as {name}:{version}", @@ -257,28 +242,18 @@ public interface AnalyticsArtifactsManagementService { responseHeaders = { @ResponseHeader( name = "Content-Type", - description = "The content type of the body"), - @ResponseHeader( - name = "ETag", - description = "Entity Tag of the response resource.\n" + - "Used by caches, or in conditional requests."), - @ResponseHeader( - name = "Last-Modified", - description = - "Date and time the resource was last modified.\n" + - "Used by caches, or in conditional requests.") + description = "The content type of the body") } ), @ApiResponse( - code = 400, - message = "Bad Request."), + code = 404, + message = "Not Found. \n The resource to delete not available."), @ApiResponse( code = 406, - message = "Not Acceptable.\n" + - "The requested media type is not supported."), + message = "Not Acceptable. \n The requested media type is not supported."), @ApiResponse( code = 500, - message = "Internal Server Error.\nServer error occurred while " + + message = "Internal Server Error. \nServer error occurred while " + "deleting the Stream Artifact.", response = ErrorResponse.class) } @@ -320,25 +295,12 @@ public interface AnalyticsArtifactsManagementService { responseHeaders = { @ResponseHeader( name = "Content-Type", - description = "The content type of the body."), - @ResponseHeader( - name = "ETag", - description = "Entity Tag of the response resource.\n" + - "Used by caches, or in conditional requests."), - @ResponseHeader( - name = "Last-Modified", - description = - "Date and time the resource was last modified.\n" + - "Used by caches, or in conditional requests."), + description = "The content type of the body.") } ), - @ApiResponse( - code = 400, - message = - "Bad Request."), @ApiResponse( code = 406, - message = "Not Acceptable.\n The requested media type is not supported."), + message = "Not Acceptable. \n The requested media type is not supported."), @ApiResponse( code = 500, message = "Internal Server Error. \n Server error occurred while deploying the " + @@ -385,25 +347,16 @@ public interface AnalyticsArtifactsManagementService { responseHeaders = { @ResponseHeader( name = "Content-Type", - description = "The content type of the body."), - @ResponseHeader( - name = "ETag", - description = "Entity Tag of the response resource.\n" + - "Used by caches, or in conditional requests."), - @ResponseHeader( - name = "Last-Modified", - description = - "Date and time the resource was last modified.\n" + - "Used by caches, or in conditional requests."), + description = "The content type of the body.") } ), @ApiResponse( code = 400, message = - "Bad Request."), + "Bad Request. \n The payload is invalid."), @ApiResponse( code = 406, - message = "Not Acceptable.\n The requested media type is not supported."), + message = "Not Acceptable. \n The requested media type is not supported."), @ApiResponse( code = 500, message = "Internal Server Error. \n Server error occurred while deploying the " + @@ -419,7 +372,7 @@ public interface AnalyticsArtifactsManagementService { @Valid Adapter receiver); @DELETE - @Path("/receiver/{name}/delete") + @Path("/receiver/{name}") @ApiOperation( httpMethod = "DELETE", value = "Delete a Receiver with the given name", @@ -442,32 +395,16 @@ public interface AnalyticsArtifactsManagementService { @ResponseHeader( name = "Content-Type", description = "The content type of the body" - ), - @ResponseHeader( - name = "ETag", - description = "Entity Tag of the response resource.\n" + - "Used by caches, or in conditional requests." - ), - @ResponseHeader( - name = "Last-Modified", - description = - "Date and time the resource was last modified.\n" + - "Used by caches, or in conditional requests." ) } ), - @ApiResponse( - code = 400, - message = "Bad Request." - ), @ApiResponse( code = 406, - message = "Not Acceptable.\n" + - "The requested media type is not supported." + message = "Not Acceptable. \n The requested media type is not supported." ), @ApiResponse( code = 500, - message = "Internal Server Error.\nServer error occurred while " + + message = "Internal Server Error.\n Server error occurred while " + "deleting the Receiver Artifact.", response = ErrorResponse.class ) @@ -504,25 +441,12 @@ public interface AnalyticsArtifactsManagementService { responseHeaders = { @ResponseHeader( name = "Content-Type", - description = "The content type of the body."), - @ResponseHeader( - name = "ETag", - description = "Entity Tag of the response resource.\n" + - "Used by caches, or in conditional requests."), - @ResponseHeader( - name = "Last-Modified", - description = - "Date and time the resource was last modified.\n" + - "Used by caches, or in conditional requests."), + description = "The content type of the body.") } ), - @ApiResponse( - code = 400, - message = - "Bad Request."), @ApiResponse( code = 406, - message = "Not Acceptable.\n The requested media type is not supported."), + message = "Not Acceptable. \n The requested media type is not supported."), @ApiResponse( code = 500, message = "Internal Server Error. \n Server error occurred while deploying the " + @@ -569,16 +493,7 @@ public interface AnalyticsArtifactsManagementService { responseHeaders = { @ResponseHeader( name = "Content-Type", - description = "The content type of the body."), - @ResponseHeader( - name = "ETag", - description = "Entity Tag of the response resource.\n" + - "Used by caches, or in conditional requests."), - @ResponseHeader( - name = "Last-Modified", - description = - "Date and time the resource was last modified.\n" + - "Used by caches, or in conditional requests."), + description = "The content type of the body.") } ), @ApiResponse( @@ -587,7 +502,7 @@ public interface AnalyticsArtifactsManagementService { "Bad Request."), @ApiResponse( code = 406, - message = "Not Acceptable.\n The requested media type is not supported."), + message = "Not Acceptable. \n The requested media type is not supported."), @ApiResponse( code = 500, message = "Internal Server Error. \n Server error occurred while deploying the " + @@ -603,7 +518,7 @@ public interface AnalyticsArtifactsManagementService { @Valid Adapter publisher); @DELETE - @Path("/publisher/{name}/delete") + @Path("/publisher/{name}") @ApiOperation( httpMethod = "DELETE", value = "Delete a Publisher with the given name", @@ -625,28 +540,15 @@ public interface AnalyticsArtifactsManagementService { responseHeaders = { @ResponseHeader( name = "Content-Type", - description = "The content type of the body"), - @ResponseHeader( - name = "ETag", - description = "Entity Tag of the response resource.\n" + - "Used by caches, or in conditional requests."), - @ResponseHeader( - name = "Last-Modified", - description = - "Date and time the resource was last modified.\n" + - "Used by caches, or in conditional requests.") + description = "The content type of the body") } ), - @ApiResponse( - code = 400, - message = "Bad Request."), @ApiResponse( code = 406, - message = "Not Acceptable.\n" + - "The requested media type is not supported."), + message = "Not Acceptable. \n The requested media type is not supported."), @ApiResponse( code = 500, - message = "Internal Server Error.\nServer error occurred while " + + message = "Internal Server Error. \n Server error occurred while " + "deleting the Publisher Artifact.", response = ErrorResponse.class) } @@ -659,6 +561,7 @@ public interface AnalyticsArtifactsManagementService { @PathParam("name") String name); @POST + @Consumes(MediaType.APPLICATION_JSON) @Path("/siddhi-script/{name}") @ApiOperation( httpMethod = "POST", @@ -681,25 +584,12 @@ public interface AnalyticsArtifactsManagementService { responseHeaders = { @ResponseHeader( name = "Content-Type", - description = "The content type of the body."), - @ResponseHeader( - name = "ETag", - description = "Entity Tag of the response resource.\n" + - "Used by caches, or in conditional requests."), - @ResponseHeader( - name = "Last-Modified", - description = - "Date and time the resource was last modified.\n" + - "Used by caches, or in conditional requests."), + description = "The content type of the body.") } ), - @ApiResponse( - code = 400, - message = - "Bad Request."), @ApiResponse( code = 406, - message = "Not Acceptable.\n The requested media type is not supported."), + message = "Not Acceptable. \n The requested media type is not supported."), @ApiResponse( code = 500, message = "Internal Server Error. \n Server error occurred while " + @@ -723,7 +613,7 @@ public interface AnalyticsArtifactsManagementService { @Valid SiddhiExecutionPlan plan); @DELETE - @Path("/siddhi-script/{name}/delete") + @Path("/siddhi-script/{name}") @ApiOperation( httpMethod = "DELETE", value = "Delete an already deployed Siddhi script", @@ -742,32 +632,19 @@ public interface AnalyticsArtifactsManagementService { value = { @ApiResponse( code = 200, - message = "OK. \n Successfully delete the Siddhi script Artifact.", + message = "OK. \n Successfully deleted the Siddhi script Artifact.", responseHeaders = { @ResponseHeader( name = "Content-Type", - description = "The content type of the body"), - @ResponseHeader( - name = "ETag", - description = "Entity Tag of the response resource.\n" + - "Used by caches, or in conditional requests."), - @ResponseHeader( - name = "Last-Modified", - description = - "Date and time the resource was last modified.\n" + - "Used by caches, or in conditional requests.") + description = "The content type of the body") } ), - @ApiResponse( - code = 400, - message = "Bad Request."), @ApiResponse( code = 406, - message = "Not Acceptable.\n" + - "The requested media type is not supported."), + message = "Not Acceptable. \n The requested media type is not supported."), @ApiResponse( code = 500, - message = "Internal Server Error.\nServer error occurred while " + + message = "Internal Server Error.\n Server error occurred while " + "deleting the Siddhi script Artifact.", response = ErrorResponse.class) } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java index 2958d5b3a0c..be85aaa440a 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/AnalyticsArtifactsManagementServiceImpl.java @@ -82,20 +82,22 @@ public class AnalyticsArtifactsManagementServiceImpl try { String streamDefinition = stream.getDefinition(); if (deployStream(id, streamDefinition, isEdited)) { - return Response.ok().build(); + return Response.ok().entity("Stream artifact of id " + id + + " successfully deployed").build(); } else { String errMsg = "Failed to create the Stream artifact of id: " + id + " for tenant domain: " + tenantDomain; + log.error(errMsg); return Response.serverError().entity(errMsg).build(); } } catch (ArtifactAlreadyExistsException e) { String errMsg = "Failed to create Stream artifact for tenant domain: " + tenantDomain + - "Stream with id: "+ id + "already exists"; + "Stream with id: " + id + "already exists"; log.error(errMsg, e); return Response.status(Response.Status.BAD_REQUEST).entity(errMsg).build(); } catch (NotFoundException e) { String errMsg = "Failed to edit Stream artifact for tenant domain: " + tenantDomain + - "Stream with id: "+ id + "doesn't exist"; + "Stream with id: " + id + "doesn't exist"; log.error(errMsg, e); return Response.status(Response.Status.NOT_FOUND).entity(errMsg).build(); } catch (AxisFault e) { @@ -124,13 +126,13 @@ public class AnalyticsArtifactsManagementServiceImpl String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); try { validateStreamProperties(stream); - String name = stream.getName(); - String version = stream.getVersion(); + String id = stream.getName() + ":" + stream.getVersion(); if (deployStream(stream)) { - return Response.ok().build(); + return Response.ok().entity("Stream artifact of id " + id + + " successfully deployed").build(); } else { - String errMsg = String.format("Failed to create the Stream artifact of id: %s:%s " + - "for tenant domain: %s", name, version, tenantDomain); + String errMsg = "Failed to create the Stream artifact of id: " + id + + "for tenant domain: " + tenantDomain; log.error(errMsg); return Response.serverError().entity(errMsg).build(); } @@ -159,22 +161,23 @@ public class AnalyticsArtifactsManagementServiceImpl @Override @DELETE - @Path("/stream/{name}/{version}/delete") + @Path("/stream/{name}/{version}") public Response deleteStream(@PathParam("name") String name, @PathParam("version") String version) { String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); + String id = name + ":" + version; try { if (undeployStream(name, version)) { - return Response.ok().build(); + return Response.ok().entity("Stream artifact of id " + id + + " successfully deleted").build(); } else { - String errMsg = String.format("Failed to undeploy the Stream artifact of id: %s:%s " + - "for tenant domain: %s", name, version, tenantDomain); + String errMsg = "Failed to undeploy the Stream artifact of id: " + id + + "for tenant domain: " + tenantDomain; log.error(errMsg); return Response.serverError().entity(errMsg).build(); } } catch (NotFoundException e) { - String errMsg = String.format("Failed to undeploy Stream with id %s:%s for tenant %s" - , name, version, tenantDomain); + String errMsg = "Failed to undeploy Stream with id " + id + "for tenant " + tenantDomain; log.error(errMsg, e); return Response.status(Response.Status.NOT_FOUND).entity(errMsg).build(); } catch (AxisFault e) { @@ -199,11 +202,16 @@ public class AnalyticsArtifactsManagementServiceImpl @Override @POST @Path("/receiver/{name}") + /* + Ideally this method should validate the existence of receiver before creating or editing. But + EventReceiverAdminServiceStub haven't implemented the methods to support these validations. + Therefore a common server error response is returned by catching Axis Fault + */ public Response deployEventReceiverAsString(@PathParam("name") String name, @QueryParam("isEdited") boolean isEdited, @Valid Adapter receiver) { String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); - EventReceiverAdminServiceStub eventReceiverAdminServiceStub; + EventReceiverAdminServiceStub eventReceiverAdminServiceStub = null; try { String receiverDefinition = receiver.getDefinition(); eventReceiverAdminServiceStub = DeviceMgtAPIUtils.getEventReceiverAdminServiceStub(); @@ -212,29 +220,37 @@ public class AnalyticsArtifactsManagementServiceImpl } else { eventReceiverAdminServiceStub.editActiveEventReceiverConfiguration(receiverDefinition, name); } - return Response.ok().build(); + return Response.ok().entity("Receiver artifact of name " + name + + " successfully deployed").build(); } catch (AxisFault e) { String errMsg = "Failed to create event definitions for tenantDomain: " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); } catch (RemoteException e) { String errMsg = "Failed to connect with the remote services for tenantDomain: " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); } catch (JWTClientException e) { String errMsg = "Failed to generate jwt token for tenantDomain: " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); } catch (UserStoreException e) { String errMsg = "Failed to connect with the user store for tenantDomain: " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); + } finally { + cleanup(eventReceiverAdminServiceStub); } } @Override @POST @Path("/receiver") + /* + Ideally this method should validate the existence of receiver before creating or editing. But + EventReceiverAdminServiceStub haven't implemented the methods to support these validations. + Therefore a common server error response is returned by catching Axis Fault + */ public Response deployEventReceiverAsDto(@Valid Adapter receiver) { String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); try { @@ -245,7 +261,8 @@ public class AnalyticsArtifactsManagementServiceImpl validateAdapterMapping(adapterConfiguration.getAdapterMappingConfiguration()); } deployReceiver(receiver, customMapping, adapterConfiguration); - return Response.ok().build(); + return Response.ok().entity("Receiver artifact of name " + receiver.getAdapterName() + + " successfully deployed").build(); } catch (BadRequestException e) { String errMsg = "Failed to deploy receiver due to invalid payload"; log.error(errMsg, e); @@ -271,15 +288,21 @@ public class AnalyticsArtifactsManagementServiceImpl @Override @DELETE - @Path("/receiver/{name}/delete") + @Path("/receiver/{name}") + /* + Ideally this method should validate the existence of receiver before deleting. But + EventReceiverAdminServiceStub haven't implemented the methods to support these validations. + Therefore a common server error response is returned by catching Axis Fault + */ public Response deleteReceiver(@PathParam("name") String name) { String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); try { if (undeployAdapter(name, "Receiver")) { - return Response.ok().build(); + return Response.ok().entity("Receiver artifact of name " + name + + " successfully deleted").build(); } else { - String errMsg = String.format("Failed to undeploy the Receiver artifact of name: %s" + - "for tenant domain: %s", name, tenantDomain); + String errMsg = "Failed to undeploy the Receiver artifact of name: " + name + + "for tenant domain: " + tenantDomain; log.error(errMsg); return Response.serverError().entity(errMsg).build(); } @@ -305,11 +328,16 @@ public class AnalyticsArtifactsManagementServiceImpl @Override @POST @Path("/publisher/{name}") + /* + Ideally this method should validate the existence of publisher before creating or editing. But + EventPublisherAdminServiceStub haven't implemented the methods to support these validations. + Therefore a common server error response is returned by catching Axis Fault + */ public Response deployEventPublisherAsString(@PathParam("name") String name, @QueryParam("isEdited") boolean isEdited, @Valid Adapter publisher) { String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); - EventPublisherAdminServiceStub eventPublisherAdminServiceStub; + EventPublisherAdminServiceStub eventPublisherAdminServiceStub = null; try { String publisherDefinition = publisher.getDefinition(); eventPublisherAdminServiceStub = DeviceMgtAPIUtils.getEventPublisherAdminServiceStub(); @@ -318,29 +346,37 @@ public class AnalyticsArtifactsManagementServiceImpl } else { eventPublisherAdminServiceStub.editActiveEventPublisherConfiguration(publisherDefinition, name); } - return Response.ok().build(); + return Response.ok().entity("Publisher artifact of name " + name + + " successfully deployed").build(); } catch (AxisFault e) { String errMsg = "Failed to create event definitions for tenantDomain: " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); } catch (RemoteException e) { String errMsg = "Failed to connect with the remote services for tenantDomain: " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); } catch (JWTClientException e) { String errMsg = "Failed to generate jwt token for tenantDomain: " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); } catch (UserStoreException e) { String errMsg = "Failed to connect with the user store for tenantDomain: " + tenantDomain; log.error(errMsg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).build(); + return Response.serverError().entity(errMsg).build(); + } finally { + cleanup(eventPublisherAdminServiceStub); } } @Override @POST @Path("/publisher") + /* + Ideally this method should validate the existence of publisher before creating or editing. But + EventPublisherAdminServiceStub haven't implemented the methods to support these validations. + Therefore a common server error response is returned by catching Axis Fault + */ public Response deployEventPublisherAsDto(@Valid Adapter publisher) { String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); AdapterConfiguration adapterConfiguration = publisher.getAdapterConfiguration(); @@ -351,7 +387,8 @@ public class AnalyticsArtifactsManagementServiceImpl validateAdapterMapping(adapterConfiguration.getAdapterMappingConfiguration()); } deployPublisher(publisher, customMapping, adapterConfiguration); - return Response.ok().build(); + return Response.ok().entity("Publisher artifact of name " + publisher.getAdapterName() + + " successfully deployed").build(); } catch (BadRequestException e) { String errMsg = "Failed to deploy publisher due to invalid payload"; log.error(errMsg, e); @@ -377,15 +414,21 @@ public class AnalyticsArtifactsManagementServiceImpl @Override @DELETE - @Path("/publisher/{name}/delete") + @Path("/publisher/{name}") + /* + Ideally this method should validate the existence of publisher before deleting. But + EventPublisherAdminServiceStub haven't implemented the methods to support these validations. + Therefore a common server error response is returned by catching Axis Fault + */ public Response deletePublisher(@PathParam("name") String name) { String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); try { if (undeployAdapter(name, "Publisher")) { - return Response.ok().build(); + return Response.ok().entity("Publisher artifact of name " + name + + " successfully deleted").build(); } else { - String errMsg = String.format("Failed to undeploy the Publisher artifact of name: %s" + - "for tenant domain: %s", name, tenantDomain); + String errMsg = "Failed to undeploy the Publisher artifact of name: " + name + + "for tenant domain: " + tenantDomain; log.error(errMsg); return Response.serverError().entity(errMsg).build(); } @@ -411,13 +454,19 @@ public class AnalyticsArtifactsManagementServiceImpl @Override @POST @Path("/siddhi-script/{name}") + /* + Ideally this method should validate the existence of Siddhi script before creating or editing. But + EventProcessorAdminServiceStub haven't implemented the methods to support these validations. + Therefore a common server error response is returned by catching Axis Fault + */ public Response deploySiddhiExecutableScript(@PathParam("name") String name, @QueryParam("isEdited") boolean isEdited, @Valid SiddhiExecutionPlan plan) { String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); try { deploySiddhiExecutionPlan(name, isEdited, plan.getDefinition()); - return Response.ok().build(); + return Response.ok().entity("Siddhi script artifact of name " + name + + " successfully deleted").build(); } catch (InvalidExecutionPlanException e) { String errMsg = "Failed to deploy siddhi script due to invalid payload"; log.error(errMsg, e); @@ -443,12 +492,18 @@ public class AnalyticsArtifactsManagementServiceImpl @Override @DELETE - @Path("/siddhi-script/{name}/delete") + @Path("/siddhi-script/{name}") + /* + Ideally this method should validate the existence of Siddhi script before deleting. But + EventProcessorAdminServiceStub haven't implemented the methods to support these validations. + Therefore a common server error response is returned by catching Axis Fault + */ public Response deleteSiddhiScript(@PathParam("name") String name) { String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); try { undeploySiddhiScript(name); - return Response.ok().build(); + return Response.ok().entity("Publisher artifact of name " + name + + " successfully deleted").build(); } catch (AxisFault e) { String errMsg = "Failed to delete event definitions for tenant " + tenantDomain; log.error(errMsg, e); @@ -469,17 +524,24 @@ public class AnalyticsArtifactsManagementServiceImpl } /** - * Deploy Stream by passing a string to a stub + * Deploy Stream by passing data as string to a stub * * @param streamId Stream name:version * @param streamDefinition Stream that should be deployed * @param isEdited Create a new stream or edit an existing one * @return True if stream successfully created and false if not - * @throws RemoteException Exception that may occur during a remote method call - * @throws UserStoreException Exception that may occur during JWT token generation - * @throws JWTClientException Exception that may occur during connecting to client store - * @throws NotFoundException Exception that may occure if stream doesn't exist while editing - * @throws ArtifactAlreadyExistsException Exception that may occure if stream exist while creating + * @throws RemoteException Exception that may occur when a SOAP request is made + * through EventStreamAdminServiceStub and if communication + * gets interfered + * @throws UserStoreException Exception that may occur while getting user data from + * the client store for the specific tenant + * @throws JWTClientException Exception that may occur during creating a EventStreamAdminServiceStub + * instance, as a jwt based token client is used to generate a token + * for the tenant in the process + * @throws NotFoundException Exception that may occur if stream doesn't exist, + * when the method is called with isEdited flag as True + * @throws ArtifactAlreadyExistsException Exception that may occur if stream does exist, + * when the method is called with isEdited flag as False */ private boolean deployStream(String streamId, String streamDefinition, boolean isEdited) throws UserStoreException, JWTClientException, RemoteException, NotFoundException, @@ -502,14 +564,18 @@ public class AnalyticsArtifactsManagementServiceImpl } /** - * Deploy Stream by passing a DTO object to a stub + * Deploy Stream by passing data as a DTO object to a stub * * @param stream Stream definition * @return True if stream successfully created and false if not - * @throws RemoteException Exception that may occur during a remote method call - * @throws UserStoreException Exception that may occur during JWT token generation - * @throws JWTClientException Exception that may occur during connecting to client store - * @throws NotFoundException Exception that may occure if stream doesn't exist while editing + * @throws RemoteException Exception that may occur when a SOAP request is made + * through EventStreamAdminServiceStub and if communication + * gets interfered + * @throws UserStoreException Exception that may occur while getting user data from + * the client store for the specific tenant + * @throws JWTClientException Exception that may occur during creating a EventStreamAdminServiceStub + * instance, as a jwt based token client is used to generate a token + * for the tenant in the process */ private boolean deployStream(EventStream stream) throws RemoteException, UserStoreException, JWTClientException { @@ -553,10 +619,16 @@ public class AnalyticsArtifactsManagementServiceImpl * @param name Stream name * @param version Stream version * @return True if stream successfully created and false if not - * @throws RemoteException Exception that may occur during a remote method call - * @throws UserStoreException Exception that may occur during JWT token generation - * @throws JWTClientException Exception that may occur during connecting to client store - * @throws NotFoundException Exception that may occure if stream doesn't exist + * @throws RemoteException Exception that may occur when a SOAP request is made + * through EventStreamAdminServiceStub and if communication + * gets interfered + * @throws UserStoreException Exception that may occur while getting user data from + * the client store for the specific tenant + * @throws JWTClientException Exception that may occur during creating a EventStreamAdminServiceStub + * instance, as a jwt based token client is used to generate a token + * for the tenant in the process + * @throws NotFoundException Exception that may occur if stream doesn't exist, + * when the method is called with isEdited flag as True */ private boolean undeployStream(String name, String version) throws RemoteException, UserStoreException, JWTClientException, NotFoundException { @@ -578,14 +650,19 @@ public class AnalyticsArtifactsManagementServiceImpl } /** - * Set data to a receiver dto and deploy dto through a stub + * Deploy Receiver by passing data as a DTO object to a stub * * @param receiver Event Receiver adapter * @param customMapping Is Receiver mapped * @param adapterConfiguration Adapter property and mapping configuration - * @throws RemoteException Exception that may occur during a remote method call - * @throws UserStoreException Exception that may occur during JWT token generation - * @throws JWTClientException Exception that may occur during connecting to client store + * @throws RemoteException Exception that may occur when a SOAP request is made + * through EventReceiverAdminServiceStub and if communication + * gets interfered + * @throws UserStoreException Exception that may occur while getting user data from + * the client store for the specific tenant + * @throws JWTClientException Exception that may occur during creating a EventReceiverAdminServiceStub + * instance, as a jwt based token client is used to generate a token + * for the tenant in the process */ private void deployReceiver(Adapter receiver, boolean customMapping, AdapterConfiguration adapterConfiguration) @@ -660,14 +737,16 @@ public class AnalyticsArtifactsManagementServiceImpl } /** - * To deploy receiver if custom mapping is false + * Deploy Receiver by passing data as a DTO object to a stub when custom mapping is False * * @param receiverName Name of the receiver * @param eventStreamWithVersion Attached event stream of the receiver * @param adapterType Adapter type name * @param eventReceiverAdminServiceStub Stub to deploy receiver * @param basicInputAdapterPropertyDtos DTO to attach receiver data - * @throws RemoteException Exception that may occur during a remote method call + * @throws RemoteException Exception that may occur when a SOAP request is made + * through EventReceiverAdminServiceStub and if communication + * gets interfered */ private void deployReceiverWithoutMapping(String receiverName, String eventStreamWithVersion , String adapterType, EventReceiverAdminServiceStub eventReceiverAdminServiceStub @@ -694,14 +773,19 @@ public class AnalyticsArtifactsManagementServiceImpl } /** - * Set data to a publisher dto and deploy dto through a stub + * Deploy Publisher by passing data as a DTO object to a stub * * @param publisher Event Publisher adapter * @param customMapping Is Publisher mapped * @param adapterConfiguration Publisher property and mapping configuration - * @throws RemoteException Exception that may occur during a remote method call - * @throws UserStoreException Exception that may occur during JWT token generation - * @throws JWTClientException Exception that may occur during connecting to client store + * @throws RemoteException Exception that may occur when a SOAP request is made + * through EventPublisherAdminServiceStub and if communication + * gets interfered + * @throws UserStoreException Exception that may occur while getting user data from + * the client store for the specific tenant + * @throws JWTClientException Exception that may occur during creating a EventPublisherAdminServiceStub + * instance, as a jwt based token client is used to generate a token + * for the tenant in the process */ private void deployPublisher(Adapter publisher, boolean customMapping, AdapterConfiguration adapterConfiguration) @@ -788,14 +872,16 @@ public class AnalyticsArtifactsManagementServiceImpl } /** - * To deploy publisher if custom mapping is false + * Deploy Publisher by passing data as a DTO object to a stub when custom mapping is False * * @param publisherName Name of the publisher * @param eventStreamWithVersion Attached event stream of the publisher * @param adapterType Adapter type name * @param eventPublisherAdminServiceStub Stub to deploy publisher * @param basicOutputAdapterPropertyDtos DTO to attach publisher data - * @throws RemoteException Exception that may occur during a remote method call + * @throws RemoteException Exception that may occur when a SOAP request is made + * through EventPublisherAdminServiceStub and if communication + * gets interfered */ private void deployPublisherWithoutMapping(String publisherName, String eventStreamWithVersion , String adapterType, EventPublisherAdminServiceStub eventPublisherAdminServiceStub @@ -831,12 +917,19 @@ public class AnalyticsArtifactsManagementServiceImpl } /** + * Undeploy an active publisher or a receiver artifact + * * @param name Adapter name * @param type Adapter type(Receiver or Publisher) * @return True if Adapter successfully created and false if not - * @throws RemoteException Exception that may occur during a remote method call - * @throws UserStoreException Exception that may occur during JWT token generation - * @throws JWTClientException Exception that may occur during connecting to client store + * @throws RemoteException Exception that may occur when a SOAP request is made + * through EventReceiverAdminServiceStub or EventPublisherAdminServiceStub + * and if communication gets interfered + * @throws UserStoreException Exception that may occur while getting user data from + * the client store for the specific tenant + * @throws JWTClientException Exception that may occur during creating a EventReceiverAdminServiceStub or + * EventPublisherAdminServiceStub instance, as a jwt based token client + * is used to generate a token for the tenant in the process */ private boolean undeployAdapter(String name, String type) throws RemoteException, UserStoreException, JWTClientException { @@ -862,15 +955,21 @@ public class AnalyticsArtifactsManagementServiceImpl } /** - * Publish a siddhi execution plan using a stub + * Deploy Siddhi script by passing data as a DTO object to a stub * * @param name Plan name * @param isEdited Is plan edited * @param plan Plan data - * @throws RemoteException Exception that may occur during a remote method call - * @throws UserStoreException Exception that may occur during JWT token generation - * @throws JWTClientException Exception that may occur during connecting to client store - * @throws InvalidExecutionPlanException Exception that may occur if execution plan validation fails + * @throws RemoteException Exception that may occur when a SOAP request is made + * through EventProcessorAdminServiceStub and if communication + * gets interfered + * @throws UserStoreException Exception that may occur while getting user data from + * the client store for the specific tenant + * @throws JWTClientException Exception that may occur during creating a EventProcessorAdminServiceStub + * instance, as a jwt based token client is used to generate a + * token for the tenant in the process + * @throws InvalidExecutionPlanException Exception that may occur if Siddhi script validation fails + * due to having errors in the code */ private void deploySiddhiExecutionPlan(String name, boolean isEdited, String plan) throws RemoteException, UserStoreException, JWTClientException, @@ -894,12 +993,17 @@ public class AnalyticsArtifactsManagementServiceImpl } /** - * Undeploy a Siddhi artifact + * Undeploy an active Siddhi artifact * * @param name Siddhi script name - * @throws RemoteException Exception that may occur during a remote method call - * @throws UserStoreException Exception that may occur during JWT token generation - * @throws JWTClientException Exception that may occur during connecting to client store + * @throws RemoteException Exception that may occur when a SOAP request is made + * through EventProcessorAdminServiceStub and if communication + * gets interfered + * @throws UserStoreException Exception that may occur while getting user data from + * the client store for the specific tenant + * @throws JWTClientException Exception that may occur during creating a EventProcessorAdminServiceStub + * instance, as a jwt based token client is used to generate a + * token for the tenant in the process */ private void undeploySiddhiScript(String name) throws RemoteException, UserStoreException, JWTClientException { @@ -913,16 +1017,23 @@ public class AnalyticsArtifactsManagementServiceImpl } /** + * Validate if stream exists for update or if stream can be created + * * @param streamId Stream name:version * @param eventStreamAdminServiceStub stub used to mange Stream artifacts * @param isEdited Create a new stream or edit an existing one - * @throws ArtifactAlreadyExistsException Exception that may occur if stream exist while creating - * @throws RemoteException Exception that may occur during a remote method call + * @throws ArtifactAlreadyExistsException Will be thrown if stream with same id exists when isEdited + * is False + * @throws NotFoundException Will be thrown if stream with same id doesn't exist when + * isEdited is True + * @throws RemoteException Exception that may occur when a SOAP request is made + * through EventProcessorAdminServiceStub and if communication + * gets interfered while getting the stream definition */ private void validateStreamId(String streamId, EventStreamAdminServiceStub eventStreamAdminServiceStub, boolean isEdited) - throws ArtifactAlreadyExistsException, RemoteException { + throws ArtifactAlreadyExistsException, RemoteException, NotFoundException { EventStreamDefinitionDto eventStreamDefinitionDto = eventStreamAdminServiceStub .getStreamDefinitionDto(streamId); if (isEdited) { @@ -946,7 +1057,7 @@ public class AnalyticsArtifactsManagementServiceImpl * Validate stream properties * * @param stream EventStream object - * @throws BadRequestException Exception that may occur if property attributes invalid + * @throws BadRequestException Will be thrown if Stream has invalid properties */ private void validateStreamProperties(EventStream stream) throws BadRequestException { if ((stream.getMetaData() == null || stream.getMetaData().isEmpty()) && @@ -963,7 +1074,7 @@ public class AnalyticsArtifactsManagementServiceImpl * Validate adapter payload attributes * * @param adapterProperties Adapter payload attributes - * @throws BadRequestException Exception that may occur if adapter properties invalid + * @throws BadRequestException Will be thrown if Stream has invalid properties */ private void validateAdapterProperties(List adapterProperties) throws BadRequestException { @@ -983,7 +1094,7 @@ public class AnalyticsArtifactsManagementServiceImpl * - else continue * * @param adapterMappingConfiguration Adapter mapping attributes - * @throws BadRequestException Exception that may occur if adapter mapping properties invalid + * @throws BadRequestException Will be thrown if Stream has invalid properties */ private void validateAdapterMapping(AdapterMappingConfiguration adapterMappingConfiguration) throws BadRequestException { From 4a70d8e17d69bb8a5d63464393197ebd931bd5d6 Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Thu, 9 Jan 2020 11:17:22 +0530 Subject: [PATCH 16/18] Update service to remove /delete from url and to update swagger api annotations --- .../api/admin/DeviceTypeManagementAdminService.java | 7 +++++-- .../impl/admin/DeviceTypeManagementAdminServiceImpl.java | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java index 355f40fea08..a4c871aace3 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceTypeManagementAdminService.java @@ -594,7 +594,7 @@ public interface DeviceTypeManagementAdminService { @DELETE - @Path("/{deviceTypeName}/delete") + @Path("/{deviceTypeName}") @ApiOperation( httpMethod = "DELETE", value = "Delete device type.", @@ -618,9 +618,12 @@ public interface DeviceTypeManagementAdminService { code = 401, message = "Unauthorized.\n The unauthorized access to the requested resource.", response = ErrorResponse.class), + @ApiResponse( + code = 404, + message = "Not Found. \n Device type trying to delete does not exist"), @ApiResponse( code = 406, - message = "Not Acceptable.\n The requested media type is not supported"), + message = "Not Acceptable. \n The requested media type is not supported"), @ApiResponse( code = 500, message = "Internal Server Error. \n Server error occurred while deleting device type.", diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java index 0ced60caf01..7c3703ce13e 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceTypeManagementAdminServiceImpl.java @@ -320,7 +320,7 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen @Override @DELETE - @Path("/{deviceTypeName}/delete") + @Path("/{deviceTypeName}") public Response deleteDeviceType(@PathParam("deviceTypeName") String deviceTypeName) { try { DeviceManagementProviderService deviceManagementProviderService = From 4378feedde8285f1dd8ddf6de7d472348aa0f69d Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Thu, 9 Jan 2020 11:19:16 +0530 Subject: [PATCH 17/18] Change try catch positions and add error messages to required positions --- .../DeviceManagementProviderServiceImpl.java | 56 +++++++++++-------- 1 file changed, 32 insertions(+), 24 deletions(-) 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 0174a8b93f3..01948680e54 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 @@ -3606,37 +3606,45 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv throws DeviceManagementException { List deviceIdentifiers; - try { - if (deviceType == null || deviceTypeName == null || deviceTypeName.isEmpty()) { - String msg = "Error, device type cannot be null or empty"; - log.error(msg); - return false; + if (deviceType == null || StringUtils.isBlank(deviceTypeName)) { + String msg = "Error, device type cannot be null or empty or a blank space"; + log.error(msg); + return false; + } + List devices = getAllDevices(deviceTypeName, false); + if (devices == null || devices.isEmpty()) { + if (log.isDebugEnabled()) { + log.debug("No devices found for the device type: " + deviceTypeName); } - List devices = getAllDevices(deviceTypeName, false); - if (devices == null || devices.isEmpty()) { - if (log.isDebugEnabled()) { - log.debug("No devices found for the device type: " + deviceTypeName); + } else { + // dis-enroll devices + disEnrollDevices(devices); + // delete devices + deviceIdentifiers = devices.stream() + .map(Device::getDeviceIdentifier).collect(Collectors.toList()); + try { + if(!deleteDevices(deviceIdentifiers)){ + log.error("Failed to delete devices of device type: " + deviceTypeName); + return false; } - } else { - // dis-enroll devices - disEnrollDevices(devices); - // delete devices - deviceIdentifiers = devices.stream() - .map(Device::getDeviceIdentifier).collect(Collectors.toList()); - deleteDevices(deviceIdentifiers); - } - // remove device type versions - if (!deleteDeviceTypeVersions(deviceType)){ - return false; + } catch (InvalidDeviceException e) { + String msg = "Error occurred while deleting devices of type: " + deviceTypeName; + log.error(msg); + throw new DeviceManagementException(msg, e); } + } + + // remove device type versions + if (!deleteDeviceTypeVersions(deviceType)) { + log.error("Failed to delete device type vesions for device type: " + deviceTypeName); + return false; + } + + try { // delete device type DeviceManagementDAOFactory.beginTransaction(); deviceTypeDAO.deleteDeviceType(getTenantId(), deviceType.getId()); DeviceManagementDAOFactory.commitTransaction(); - } catch (InvalidDeviceException e) { - String msg = "Error occurred while deleting devices of type: " + deviceTypeName; - log.error(msg); - throw new DeviceManagementException(msg, e); } catch (DeviceManagementDAOException e) { DeviceManagementDAOFactory.rollbackTransaction(); String msg = "Error occurred while deleting device type of: " + deviceTypeName; From f6976800f5cdff1bf22ba336f727a7c6baaecac6 Mon Sep 17 00:00:00 2001 From: Yohan Avishke Date: Thu, 9 Jan 2020 11:20:13 +0530 Subject: [PATCH 18/18] Update try catch to use try with resources --- .../mgt/core/dao/impl/DeviceTypeDAOImpl.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/DeviceTypeDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/DeviceTypeDAOImpl.java index 5084428ce91..68a029c90ec 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/DeviceTypeDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/DeviceTypeDAOImpl.java @@ -431,23 +431,21 @@ public class DeviceTypeDAOImpl implements DeviceTypeDAO { @Override public void deleteDeviceType(int tenantID, int deviceTypeId) throws DeviceManagementDAOException { Connection conn; - PreparedStatement stmt = null; + String sql = "DELETE FROM DM_DEVICE_TYPE" + + " WHERE" + + " ID = ?" + + " AND PROVIDER_TENANT_ID = ?"; try { conn = getConnection(); - String sql = "DELETE FROM DM_DEVICE_TYPE" + - " WHERE" + - " ID = ?" + - " AND PROVIDER_TENANT_ID = ?"; - stmt = conn.prepareStatement(sql); - stmt.setInt(1, deviceTypeId); - stmt.setInt(2, tenantID); - stmt.execute(); + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setInt(1, deviceTypeId); + stmt.setInt(2, tenantID); + stmt.execute(); + } } catch (SQLException e) { throw new DeviceManagementDAOException( "Error occurred while deleting device type of id: " + deviceTypeId + " for tenant: " + tenantID, e); - } finally { - DeviceManagementDAOUtil.cleanupResources(stmt, null); } }