diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java index bb34498e4ab6..17801bc44cde 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/ExceptionCodes.java @@ -533,6 +533,8 @@ public enum ExceptionCodes implements ErrorHandler { "Required attributes(s) %s for api policy specification %s are either missing or empty"), OPERATION_POLICY_NOT_FOUND(902010, "API Policy Not Found", 404, "Requested api policy with id '%s' not found"), + CUSTOM_BACKEND_NOT_FOUND(903250, "Custom Backend not found", + 404, "Requested Custom Backend with id '%s' not found"), OPERATION_POLICY_ALREADY_EXISTS(903001, "The API Policy already exists.", 409, "An Operation Policy with name '%s' and version '%s' already exists"), diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml index d22fd1138b3a..79bd4ead7bd3 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/publisher-api.yaml @@ -487,6 +487,71 @@ paths: -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/am/publisher/v4/apis/7a2298c4-c905-403f-8fac-38c73301631f/topics"' + /apis/{apiId}/custom-backend/{customBackendId}/content: + get: + tags: + - APIs + summary: Get Sequence of Custom Backend + description: This operation can be used to get Sequence of the Custom Backend + operationId: getCustomBackendDataContent + parameters: + - name: type + in: query + description: | + Type of the Endpoint. + SANDBOX or PRODUCTION + required: true + schema: + maxLength: 15 + type: string + - $ref: '#/components/parameters/customBackendId' + - $ref: '#/components/parameters/apiId' + responses: + 200: + description: | + OK. + Requested API Custom Backend is returned + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modifed the last time. + Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/zip: + schema: + type: string + format: binary + 304: + description: | + Not Modified. + Empty body because the client has already the latest version of the requested resource (Will be supported in future). + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apim:api_view + - apim:api_manage + - apim:api_import_export + - apim:api_product_import_export + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/am/publisher/v4/apis/7a2298c4-c905-403f-8fac-38c73301631f/custom-backend/7a2298c4-c915-483f-8fac-38c73301631f/content"' /apis/{apiId}/custom-backend/{customBackendId}: get: @@ -496,6 +561,15 @@ paths: description: This operation can be used to get Custom Backend data of the API operationId: getCustomBackendData parameters: + - name: type + in: query + description: | + Type of the Endpoint. + SANDBOX or PRODUCTION + required: true + schema: + maxLength: 15 + type: string - $ref: '#/components/parameters/customBackendId' - $ref: '#/components/parameters/apiId' responses: @@ -550,6 +624,15 @@ paths: description: This operation can be used to remove the Custom Backend of the API operationId: customBackendDelete parameters: + - name: type + in: query + description: | + Type of the Endpoint. + SANDBOX or PRODUCTION + required: true + schema: + maxLength: 15 + type: string - $ref: '#/components/parameters/apiId' - $ref: '#/components/parameters/If-Match' - $ref: '#/components/parameters/customBackendId' diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/ApisApi.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/ApisApi.java index 5d28889e9975..4d5d394e9796 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/ApisApi.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/ApisApi.java @@ -395,8 +395,8 @@ public Response createNewAPIVersion( @NotNull @Size(max=30) @ApiParam(value = "V @ApiResponse(code = 404, message = "Not Found. The specified resource does not exist.", response = ErrorDTO.class), @ApiResponse(code = 409, message = "Conflict. Specified resource already exists.", response = ErrorDTO.class), @ApiResponse(code = 412, message = "Precondition Failed. The request has not been performed because one of the preconditions is not met.", response = ErrorDTO.class) }) - public Response customBackendDelete(@ApiParam(value = "**API ID** consisting of the **UUID** of the API. ",required=true) @PathParam("apiId") String apiId, @ApiParam(value = "Custom Backend ID ",required=true) @PathParam("customBackendId") String customBackendId, @ApiParam(value = "Validator for conditional requests; based on ETag. " )@HeaderParam("If-Match") String ifMatch) throws APIManagementException{ - return delegate.customBackendDelete(apiId, customBackendId, ifMatch, securityContext); + public Response customBackendDelete( @NotNull @Size(max=15) @ApiParam(value = "Type of the Endpoint. SANDBOX or PRODUCTION ",required=true) @QueryParam("type") String type, @ApiParam(value = "**API ID** consisting of the **UUID** of the API. ",required=true) @PathParam("apiId") String apiId, @ApiParam(value = "Custom Backend ID ",required=true) @PathParam("customBackendId") String customBackendId, @ApiParam(value = "Validator for conditional requests; based on ETag. " )@HeaderParam("If-Match") String ifMatch) throws APIManagementException{ + return delegate.customBackendDelete(type, apiId, customBackendId, ifMatch, securityContext); } @PUT @@ -1349,8 +1349,29 @@ public Response getAuditReportOfAPI(@ApiParam(value = "**API ID** consisting of @ApiResponse(code = 304, message = "Not Modified. Empty body because the client has already the latest version of the requested resource (Will be supported in future). ", response = Void.class), @ApiResponse(code = 404, message = "Not Found. The specified resource does not exist.", response = ErrorDTO.class), @ApiResponse(code = 406, message = "Not Acceptable. The requested media type is not supported.", response = ErrorDTO.class) }) - public Response getCustomBackendData(@ApiParam(value = "Custom Backend ID ",required=true) @PathParam("customBackendId") String customBackendId, @ApiParam(value = "**API ID** consisting of the **UUID** of the API. ",required=true) @PathParam("apiId") String apiId) throws APIManagementException{ - return delegate.getCustomBackendData(customBackendId, apiId, securityContext); + public Response getCustomBackendData( @NotNull @Size(max=15) @ApiParam(value = "Type of the Endpoint. SANDBOX or PRODUCTION ",required=true) @QueryParam("type") String type, @ApiParam(value = "Custom Backend ID ",required=true) @PathParam("customBackendId") String customBackendId, @ApiParam(value = "**API ID** consisting of the **UUID** of the API. ",required=true) @PathParam("apiId") String apiId) throws APIManagementException{ + return delegate.getCustomBackendData(type, customBackendId, apiId, securityContext); + } + + @GET + @Path("/{apiId}/custom-backend/{customBackendId}/content") + + @Produces({ "application/zip", "application/json" }) + @ApiOperation(value = "Get Sequence of Custom Backend", notes = "This operation can be used to get Sequence of the Custom Backend", response = File.class, authorizations = { + @Authorization(value = "OAuth2Security", scopes = { + @AuthorizationScope(scope = "apim:api_view", description = "View API"), + @AuthorizationScope(scope = "apim:api_manage", description = "Manage all API related operations"), + @AuthorizationScope(scope = "apim:api_import_export", description = "Import and export APIs related operations"), + @AuthorizationScope(scope = "apim:api_product_import_export", description = "Import and export API Products related operations") + }) + }, tags={ "APIs", }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK. Requested API Custom Backend is returned ", response = File.class), + @ApiResponse(code = 304, message = "Not Modified. Empty body because the client has already the latest version of the requested resource (Will be supported in future). ", response = Void.class), + @ApiResponse(code = 404, message = "Not Found. The specified resource does not exist.", response = ErrorDTO.class), + @ApiResponse(code = 406, message = "Not Acceptable. The requested media type is not supported.", response = ErrorDTO.class) }) + public Response getCustomBackendDataContent( @NotNull @Size(max=15) @ApiParam(value = "Type of the Endpoint. SANDBOX or PRODUCTION ",required=true) @QueryParam("type") String type, @ApiParam(value = "Custom Backend ID ",required=true) @PathParam("customBackendId") String customBackendId, @ApiParam(value = "**API ID** consisting of the **UUID** of the API. ",required=true) @PathParam("apiId") String apiId) throws APIManagementException{ + return delegate.getCustomBackendDataContent(type, customBackendId, apiId, securityContext); } @GET diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/ApisApiService.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/ApisApiService.java index 1e44fdae9483..8eb458cd143a 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/ApisApiService.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/ApisApiService.java @@ -80,7 +80,7 @@ public interface ApisApiService { public Response createAPI(APIDTO APIDTO, String openAPIVersion, MessageContext messageContext) throws APIManagementException; public Response createAPIRevision(String apiId, APIRevisionDTO apIRevisionDTO, MessageContext messageContext) throws APIManagementException; public Response createNewAPIVersion(String newVersion, String apiId, Boolean defaultVersion, String serviceVersion, MessageContext messageContext) throws APIManagementException; - public Response customBackendDelete(String apiId, String customBackendId, String ifMatch, MessageContext messageContext) throws APIManagementException; + public Response customBackendDelete(String type, String apiId, String customBackendId, String ifMatch, MessageContext messageContext) throws APIManagementException; public Response customBackendUpdate(String apiId, String ifMatch, InputStream sequenceInputStream, Attachment sequenceDetail, String type, MessageContext messageContext) throws APIManagementException; public Response deleteAPI(String apiId, String ifMatch, MessageContext messageContext) throws APIManagementException; public Response deleteAPIClientCertificateByAlias(String alias, String apiId, MessageContext messageContext) throws APIManagementException; @@ -128,7 +128,8 @@ public interface ApisApiService { public Response getAmazonResourceNamesOfAPI(String apiId, MessageContext messageContext) throws APIManagementException; public Response getAuditReportOfAPI(String apiId, String accept, MessageContext messageContext) throws APIManagementException; public Response getCommentOfAPI(String commentId, String apiId, String xWSO2Tenant, String ifNoneMatch, Boolean includeCommenterInfo, Integer replyLimit, Integer replyOffset, MessageContext messageContext) throws APIManagementException; - public Response getCustomBackendData(String customBackendId, String apiId, MessageContext messageContext) throws APIManagementException; + public Response getCustomBackendData(String type, String customBackendId, String apiId, MessageContext messageContext) throws APIManagementException; + public Response getCustomBackendDataContent(String type, String customBackendId, String apiId, MessageContext messageContext) throws APIManagementException; public Response getGeneratedMockScriptsOfAPI(String apiId, String ifNoneMatch, MessageContext messageContext) throws APIManagementException; public Response getGraphQLPolicyComplexityOfAPI(String apiId, MessageContext messageContext) throws APIManagementException; public Response getGraphQLPolicyComplexityTypesOfAPI(String apiId, MessageContext messageContext) throws APIManagementException; diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApisApiServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApisApiServiceImpl.java index 8b89e2f42dff..310fef21aacd 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApisApiServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApisApiServiceImpl.java @@ -163,32 +163,51 @@ public Response getAllAPIs(Integer limit, Integer offset, String sortBy, String return null; } - @Override public Response getCustomBackendData(String customBackendId, String apiId, MessageContext messageContext) - throws APIManagementException { + @Override public Response getCustomBackendData(String type, String customBackendId, String apiId, + MessageContext messageContext) throws APIManagementException { APIProvider apiProvider = RestApiCommonUtil.getLoggedInUserProvider(); //validate if api exists CommonUtils.validateAPIExistence(apiId); - String type = "SANDBOX"; Map endpointConfig = apiProvider.getCustomBackendOfAPIByUUID(customBackendId, apiId, type, - true); + false); + + if(endpointConfig != null) { + throw new APIMgtResourceNotFoundException("Couldn't retrieve an existing Custom Backend with ID: " + + customBackendId + " for API " + apiId, + ExceptionCodes.from(ExceptionCodes.CUSTOM_BACKEND_NOT_FOUND, customBackendId)); + } CustomBackendDTO backendDTO = new CustomBackendDTO(); backendDTO.setSequenceName(endpointConfig.get("sequence_name").toString()); backendDTO.setSequenceId(endpointConfig.get("sequence_id").toString()); backendDTO.setSequenceType(endpointConfig.get("type").toString()); return Response.ok().entity(backendDTO).build(); } + @Override + public Response getCustomBackendDataContent(String type, String customBackendId, String apiId, MessageContext messageContext) throws APIManagementException { + APIProvider apiProvider = RestApiCommonUtil.getLoggedInUserProvider(); + CommonUtils.validateAPIExistence(apiId); + + InputStream seq = apiProvider.getCustomBackendSequenceOfAPIByUUID(apiId, customBackendId, type); + if(seq != null) { + throw new APIMgtResourceNotFoundException("Couldn't retrieve an existing Custom Backend with ID: " + + customBackendId + " for API " + apiId, + ExceptionCodes.from(ExceptionCodes.CUSTOM_BACKEND_NOT_FOUND, customBackendId)); + } + String seqName = APIUtil.getCustomBackendName(apiId, type); + File file = RestApiPublisherUtils.exportCustomBackendData(seq, seqName); + return Response.ok(file).header(RestApiConstants.HEADER_CONTENT_DISPOSITION, + "attachment; filename=\"" + file.getName() + "\"").build(); + } - @Override public Response customBackendDelete(String apiId, String customBackendId, String ifMatch, + @Override public Response customBackendDelete(String type, String apiId, String customBackendId, String ifMatch, MessageContext messageContext) throws APIManagementException { APIProvider apiProvider = RestApiCommonUtil.getLoggedInUserProvider(); - //validate if api exists CommonUtils.validateAPIExistence(apiId); - String type = "SANDBOX"; apiProvider.deleteCustomBackendByID(apiId, customBackendId, type); - return Response.ok().entity(null).build(); + return Response.ok().build(); } @Override diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/utils/RestApiPublisherUtils.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/utils/RestApiPublisherUtils.java index 5b6fc2826a0b..ea9df05bae06 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/utils/RestApiPublisherUtils.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/utils/RestApiPublisherUtils.java @@ -46,6 +46,7 @@ import org.wso2.carbon.apimgt.rest.api.common.RestApiConstants; import org.wso2.carbon.apimgt.rest.api.publisher.v1.common.mappings.PublisherCommonUtils; import org.wso2.carbon.apimgt.rest.api.util.utils.RestApiUtil; +import org.wso2.carbon.utils.FileUtil; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -277,6 +278,24 @@ public static String getContentType(Attachment fileDetail) { return fileContentType; } + public static File exportCustomBackendData(InputStream seq, String seqName) throws APIManagementException { + File exportFolder = null; + try { + exportFolder = CommonUtil.createTempDirectoryFromName(seqName + "_" + "Custom-Backend"); + String exportCustomBackendBasePath = exportFolder.toString(); + String archivePath = exportCustomBackendBasePath.concat(File.separator + seqName); + CommonUtil.createDirectory(archivePath); + String customBackendName = + archivePath + File.separator + seqName + APIConstants.SYNAPSE_POLICY_DEFINITION_EXTENSION_XML; + CommonUtil.writeFile(customBackendName, IOUtils.toString(seq)); + CommonUtil.archiveDirectory(exportCustomBackendBasePath); + FileUtils.deleteQuietly(new File(exportCustomBackendBasePath)); + return new File(exportCustomBackendBasePath + APIConstants.ZIP_FILE_EXTENSION); + } catch (APIImportExportException | IOException ex) { + throw new APIManagementException("Error when exporting Custom Backend: " + seqName, ex); + } + } + public static File exportOperationPolicyData(OperationPolicyData policyData, String format) throws APIManagementException { diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/resources/publisher-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/resources/publisher-api.yaml index d22fd1138b3a..79bd4ead7bd3 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/resources/publisher-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/resources/publisher-api.yaml @@ -487,6 +487,71 @@ paths: -H "Content-Type: application/json" -d @data.json "https://127.0.0.1:9443/api/am/publisher/v4/apis/7a2298c4-c905-403f-8fac-38c73301631f/topics"' + /apis/{apiId}/custom-backend/{customBackendId}/content: + get: + tags: + - APIs + summary: Get Sequence of Custom Backend + description: This operation can be used to get Sequence of the Custom Backend + operationId: getCustomBackendDataContent + parameters: + - name: type + in: query + description: | + Type of the Endpoint. + SANDBOX or PRODUCTION + required: true + schema: + maxLength: 15 + type: string + - $ref: '#/components/parameters/customBackendId' + - $ref: '#/components/parameters/apiId' + responses: + 200: + description: | + OK. + Requested API Custom Backend is returned + headers: + ETag: + description: | + Entity Tag of the response resource. Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Last-Modified: + description: | + Date and time the resource has been modifed the last time. + Used by caches, or in conditional requests (Will be supported in future). + schema: + type: string + Content-Type: + description: | + The content type of the body. + schema: + type: string + content: + application/zip: + schema: + type: string + format: binary + 304: + description: | + Not Modified. + Empty body because the client has already the latest version of the requested resource (Will be supported in future). + content: {} + 404: + $ref: '#/components/responses/NotFound' + 406: + $ref: '#/components/responses/NotAcceptable' + security: + - OAuth2Security: + - apim:api_view + - apim:api_manage + - apim:api_import_export + - apim:api_product_import_export + x-code-samples: + - lang: Curl + source: 'curl -k -H "Authorization: Bearer ae4eae22-3f65-387b-a171-d37eaa366fa8" + "https://127.0.0.1:9443/api/am/publisher/v4/apis/7a2298c4-c905-403f-8fac-38c73301631f/custom-backend/7a2298c4-c915-483f-8fac-38c73301631f/content"' /apis/{apiId}/custom-backend/{customBackendId}: get: @@ -496,6 +561,15 @@ paths: description: This operation can be used to get Custom Backend data of the API operationId: getCustomBackendData parameters: + - name: type + in: query + description: | + Type of the Endpoint. + SANDBOX or PRODUCTION + required: true + schema: + maxLength: 15 + type: string - $ref: '#/components/parameters/customBackendId' - $ref: '#/components/parameters/apiId' responses: @@ -550,6 +624,15 @@ paths: description: This operation can be used to remove the Custom Backend of the API operationId: customBackendDelete parameters: + - name: type + in: query + description: | + Type of the Endpoint. + SANDBOX or PRODUCTION + required: true + schema: + maxLength: 15 + type: string - $ref: '#/components/parameters/apiId' - $ref: '#/components/parameters/If-Match' - $ref: '#/components/parameters/customBackendId'