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 0000000000..aa56e0d30f --- /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,52 @@ +/* + * 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 { + 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 7e5456dadd..9ff8ecc44d 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,36 +68,54 @@ 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 { @POST + @Consumes(MediaType.APPLICATION_JSON) @Path("/stream/{id}") @ApiOperation( httpMethod = "POST", @@ -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( @@ -117,41 +138,42 @@ 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 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); @POST + @Consumes(MediaType.APPLICATION_JSON) @Path("/stream") @ApiOperation( httpMethod = "POST", @@ -160,8 +182,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( @@ -172,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 " + @@ -198,11 +213,66 @@ 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}") + @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") + } + ), + @ApiResponse( + 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."), + @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 + @Consumes(MediaType.APPLICATION_JSON) @Path("/receiver/{name}") @ApiOperation( httpMethod = "POST", @@ -211,8 +281,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( @@ -223,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 " + @@ -250,15 +309,22 @@ 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); @POST + @Consumes(MediaType.APPLICATION_JSON) @Path("/receiver") @ApiOperation( httpMethod = "POST", @@ -267,8 +333,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( @@ -279,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 " + @@ -306,11 +365,60 @@ 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}") + @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" + ) + } + ), + @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 the Receiver Artifact.", + response = ErrorResponse.class + ) + } + ) + Response deleteReceiver( + @ApiParam( + name = "name", + value = "Receiver name.", + required = true) + @PathParam("name") String name); + @POST + @Consumes(MediaType.APPLICATION_JSON) @Path("/publisher/{name}") @ApiOperation( httpMethod = "POST", @@ -319,8 +427,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( @@ -331,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 " + @@ -358,15 +455,22 @@ 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); @POST + @Consumes(MediaType.APPLICATION_JSON) @Path("/publisher") @ApiOperation( httpMethod = "POST", @@ -375,8 +479,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( @@ -387,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( @@ -405,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 " + @@ -414,11 +511,57 @@ 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}") + @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") + } + ), + @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 the Publisher Artifact.", + response = ErrorResponse.class) + } + ) + Response deletePublisher( + @ApiParam( + name = "name", + value = "Publisher name.", + required = true) + @PathParam("name") String name); + @POST + @Consumes(MediaType.APPLICATION_JSON) @Path("/siddhi-script/{name}") @ApiOperation( httpMethod = "POST", @@ -427,8 +570,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( @@ -439,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 " + @@ -466,11 +598,61 @@ 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}") + @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 deleted the Siddhi script Artifact.", + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "The content type of the body") + } + ), + @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 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/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 b472b5832d..a4c871aace 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,47 @@ public interface DeviceTypeManagementAdminService { required = true) @PathParam("version")String version); + + @DELETE + @Path("/{deviceTypeName}") + @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 = 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"), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Server error occurred while deleting device type.", + response = ErrorResponse.class) + }) + Response deleteDeviceType( + @ApiParam( + name = "deviceTypeName", + value = "Device type name.", + required = true) + @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/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 bdd7fdb420..be85aaa440 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,43 @@ 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().entity("Stream artifact of id " + id + + " successfully deployed").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; + log.error(errMsg); + return Response.serverError().entity(errMsg).build(); } - return Response.ok().build(); + } catch (ArtifactAlreadyExistsException e) { + 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 + + "Stream with id: " + id + "doesn't exist"; + 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 +126,16 @@ public class AnalyticsArtifactsManagementServiceImpl String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); try { validateStreamProperties(stream); - deployStream(stream); - return Response.ok().build(); + String id = stream.getName() + ":" + stream.getVersion(); + if (deployStream(stream)) { + 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 (BadRequestException e) { String errMsg = "Failed to deploy stream due to invalid payload"; log.error(errMsg, e); @@ -125,30 +143,75 @@ 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}") + 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().entity("Stream artifact of id " + id + + " successfully deleted").build(); + } else { + 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 = "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) { + 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(); } } @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(); @@ -157,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 { @@ -190,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); @@ -214,14 +286,58 @@ public class AnalyticsArtifactsManagementServiceImpl } } + @Override + @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().entity("Receiver artifact of name " + name + + " successfully deleted").build(); + } else { + String errMsg = "Failed to undeploy the Receiver artifact of name: " + name + + "for tenant domain: " + 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}") + /* + 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(); @@ -230,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(); @@ -263,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); @@ -287,16 +412,61 @@ public class AnalyticsArtifactsManagementServiceImpl } } + @Override + @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().entity("Publisher artifact of name " + name + + " successfully deleted").build(); + } else { + String errMsg = "Failed to undeploy the Publisher artifact of name: " + name + + "for tenant domain: " + 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}") + /* + 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); @@ -320,12 +490,94 @@ public class AnalyticsArtifactsManagementServiceImpl } } + @Override + @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().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); + 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(); + } + } + /** - * Set data to a Stream dto and deploy dto through 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 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, + 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); + } + } + + /** + * 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 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 void deployStream(EventStream stream) + private boolean deployStream(EventStream stream) throws RemoteException, UserStoreException, JWTClientException { EventStreamAdminServiceStub eventStreamAdminServiceStub = null; List metaData = stream.getMetaData(); @@ -350,9 +602,11 @@ 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); @@ -360,14 +614,55 @@ public class AnalyticsArtifactsManagementServiceImpl } /** - * Set data to a receiver dto and deploy dto through a stub + * 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 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 { + 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); + } + } + + /** + * 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) @@ -442,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 @@ -476,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) @@ -564,21 +866,22 @@ public class AnalyticsArtifactsManagementServiceImpl deployPublisherWithoutMapping(publisherName, eventStreamWithVersion, adapterType , eventPublisherAdminServiceStub, basicOutputAdapterPropertyDtos); } - } finally { cleanup(eventPublisherAdminServiceStub); } } /** - * 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 @@ -614,15 +917,59 @@ public class AnalyticsArtifactsManagementServiceImpl } /** - * Publish a siddhi execution plan using a stub + * 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 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 { + 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); + } + } + } + + /** + * 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, @@ -645,10 +992,72 @@ public class AnalyticsArtifactsManagementServiceImpl } } + /** + * Undeploy an active Siddhi artifact + * + * @param name Siddhi script name + * @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 { + EventProcessorAdminServiceStub eventProcessorAdminServiceStub = null; + try { + eventProcessorAdminServiceStub = DeviceMgtAPIUtils.getEventProcessorAdminServiceStub(); + eventProcessorAdminServiceStub.undeployActiveExecutionPlan(name); + } finally { + cleanup(eventProcessorAdminServiceStub); + } + } + + /** + * 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 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, NotFoundException { + 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 Will be thrown if Stream has invalid properties */ private void validateStreamProperties(EventStream stream) throws BadRequestException { if ((stream.getMetaData() == null || stream.getMetaData().isEmpty()) && @@ -665,6 +1074,7 @@ public class AnalyticsArtifactsManagementServiceImpl * Validate adapter payload attributes * * @param adapterProperties Adapter payload attributes + * @throws BadRequestException Will be thrown if Stream has invalid properties */ private void validateAdapterProperties(List adapterProperties) throws BadRequestException { @@ -684,6 +1094,7 @@ public class AnalyticsArtifactsManagementServiceImpl * - else continue * * @param adapterMappingConfiguration Adapter mapping attributes + * @throws BadRequestException Will be thrown if Stream has invalid properties */ private void validateAdapterMapping(AdapterMappingConfiguration adapterMappingConfiguration) throws BadRequestException { 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 edae86a311..7c3703ce13 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,9 +243,9 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen } } - @PUT @Override - @Path("{deviceTypeName}/versions") + @PUT + @Path("/{deviceTypeName}/versions") public Response updateDeviceTypeVersion(@PathParam("deviceTypeName") String deviceTypeName, DeviceTypeVersionWrapper deviceTypeVersion) { if (deviceTypeVersion != null && deviceTypeVersion.getVersionName() == null || deviceTypeVersion @@ -284,9 +283,9 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen } } - @DELETE @Override - @Path("{deviceTypeName}/versions/{version}") + @DELETE + @Path("/{deviceTypeName}/versions/{version}") public Response deleteDeviceTypeVersion(@PathParam("deviceTypeName") String deviceTypeName, @PathParam("version") String version) { if (version == null || version.isEmpty()) { @@ -319,4 +318,32 @@ public class DeviceTypeManagementAdminServiceImpl implements DeviceTypeManagemen } } + @Override + @DELETE + @Path("/{deviceTypeName}") + public Response deleteDeviceType(@PathParam("deviceTypeName") String deviceTypeName) { + try { + DeviceManagementProviderService deviceManagementProviderService = + DeviceMgtAPIUtils.getDeviceManagementService(); + 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: " + deviceTypeName + " permanently deleted.") + .build(); + } catch (DeviceManagementException e) { + 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.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 ca151c7bd2..3ee922c1f4 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; @@ -216,4 +233,37 @@ 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() throws DeviceManagementException { + PowerMockito.stub(PowerMockito.method(DeviceMgtAPIUtils.class, "getDeviceManagementService")) + .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(deviceManagementProviderService); + Mockito.when(deviceManagementProviderService.getDeviceType(Mockito.anyString())).thenReturn(null); + Response response = deviceTypeManagementAdminService.deleteDeviceType(TEST_DEVICE_TYPE); + Assert.assertEquals(response.getStatus(), Response.Status.NOT_FOUND.getStatusCode()); + 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(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(deviceManagementProviderService); + } } 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 4ae4289993..def5ee32ff 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; @@ -128,4 +145,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 35e9265190..68a029c90e 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; @@ -411,6 +428,27 @@ public class DeviceTypeDAOImpl implements DeviceTypeDAO { } + @Override + public void deleteDeviceType(int tenantID, int deviceTypeId) throws DeviceManagementDAOException { + Connection conn; + String sql = "DELETE FROM DM_DEVICE_TYPE" + + " WHERE" + + " ID = ?" + + " AND PROVIDER_TENANT_ID = ?"; + try { + conn = getConnection(); + 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); + } + } + 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 8765ed22e5..e593221869 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 @@ -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,35 @@ 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 + * + * @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, DeviceType deviceType) 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 1efdb78a74..01948680e5 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,7 @@ import java.util.List; import java.util.Arrays; import java.util.Map; import java.util.Properties; -import java.util.Set; +import java.util.stream.Collectors; public class DeviceManagementProviderServiceImpl implements DeviceManagementProviderService, PluginInitializationListener { @@ -541,14 +541,30 @@ 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(); + 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 { - DeviceManagementDAOFactory.beginTransaction(); - List existingDevices = deviceDAO.getDevicesByIdentifiers(deviceIdentifiers, tenantId); 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); @@ -584,6 +600,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()) { @@ -3584,6 +3601,162 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv return versions; } + @Override + public boolean deleteDeviceType(String deviceTypeName, DeviceType deviceType) + throws DeviceManagementException { + List deviceIdentifiers; + + 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); + } + } 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; + } + } 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 (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"); + } + } else { + for (DeviceTypeVersion deviceTypeVersion : deviceTypeVersions) { + result = deviceTypeDAO.isDeviceTypeVersionModifiable(deviceType.getId() + , deviceTypeVersion.getVersionName(), getTenantId()); + if (!result) { + 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; + log.error(msg); + return false; + } + } + DeviceManagementDAOFactory.commitTransaction(); + } + } 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); + } finally { + DeviceManagementDAOFactory.closeConnection(); + } + return true; + } + + @Override public DeviceConfiguration getDeviceConfiguration(Map deviceProps) throws DeviceManagementException, DeviceNotFoundException, UnauthorizedDeviceAccessException,