From ff01047836ac4eaba57e75b7a060ddf076bc96c5 Mon Sep 17 00:00:00 2001 From: HeshanSudarshana Date: Mon, 18 Sep 2023 07:22:49 +0530 Subject: [PATCH] Optimize existing API import flows with less update calls --- .../carbon/apimgt/impl/APIProviderImpl.java | 11 +-- .../v1/common/mappings/ImportUtils.java | 19 ++-- .../common/mappings/PublisherCommonUtils.java | 97 ++++++++++++++++--- 3 files changed, 95 insertions(+), 32 deletions(-) diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java index af9804416ead..b5257ed9199f 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIProviderImpl.java @@ -841,14 +841,6 @@ public API updateAPI(API api, API existingAPI) throws APIManagementException { apiLogObject.put(APIConstants.AuditLogConstants.CONTEXT, api.getContext()); apiLogObject.put(APIConstants.AuditLogConstants.VERSION, api.getId().getVersion()); apiLogObject.put(APIConstants.AuditLogConstants.PROVIDER, api.getId().getProviderName()); - try { - api.setCreatedTime(existingAPI.getCreatedTime()); - apiPersistenceInstance.updateAPI(new Organization(organization), APIMapper.INSTANCE.toPublisherApi(api)); - } catch (APIPersistenceException e) { - throw new APIManagementException("Error while updating API details", e); - } - APIUtil.logAuditMessage(APIConstants.AuditLogConstants.API, apiLogObject.toString(), - APIConstants.AuditLogConstants.UPDATED, this.username); //Validate Transports validateAndSetTransports(api); @@ -859,7 +851,8 @@ public API updateAPI(API api, API existingAPI) throws APIManagementException { } catch (APIPersistenceException e) { throw new APIManagementException("Error while updating API details", e); } - + APIUtil.logAuditMessage(APIConstants.AuditLogConstants.API, apiLogObject.toString(), + APIConstants.AuditLogConstants.UPDATED, this.username); //notify key manager with API update registerOrUpdateResourceInKeyManager(api, tenantDomain); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/ImportUtils.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/ImportUtils.java index bdf8a466ab60..758925f4537b 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/ImportUtils.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/ImportUtils.java @@ -279,8 +279,8 @@ public static API importApi(String extractedFolderPath, APIDTO importedApiDTO, B setOperationsToDTO(importedApiDTO, validationResponse); } targetApi.setOrganization(organization); - importedApi = PublisherCommonUtils - .updateApi(targetApi, importedApiDTO, RestApiCommonUtil.getLoggedInUserProvider(), tokenScopes); + importedApi = PublisherCommonUtils.updateApiAndDefinition(targetApi, importedApiDTO, + RestApiCommonUtil.getLoggedInUserProvider(), tokenScopes, validationResponse); } else { if (targetApi == null && Boolean.TRUE.equals(overwrite)) { log.info("Cannot find : " + importedApiDTO.getName() + "-" + importedApiDTO.getVersion() @@ -293,6 +293,14 @@ public static API importApi(String extractedFolderPath, APIDTO importedApiDTO, B importedApi = PublisherCommonUtils .addAPIWithGeneratedSwaggerDefinition(importedApiDTO, ImportExportConstants.OAS_VERSION_3, importedApiDTO.getProvider(), organization); + // Add/update swagger content except for streaming APIs and GraphQL APIs + if (!PublisherCommonUtils.isStreamingAPI(importedApiDTO) + && !APIConstants.APITransportType.GRAPHQL.toString().equalsIgnoreCase(apiType)) { + // Add the validated swagger separately since the UI does the same procedure + PublisherCommonUtils.updateSwagger(importedApi.getUuid(), validationResponse, false, + organization); + importedApi = apiProvider.getAPIbyUUID(importedApi.getUuid(), currentTenantDomain); + } } else { importedApi = PublisherCommonUtils.importAsyncAPIWithDefinition(validationResponse, Boolean.FALSE, importedApiDTO, null, currentTenantDomain, apiProvider); @@ -317,13 +325,6 @@ public static API importApi(String extractedFolderPath, APIDTO importedApiDTO, B // Retrieving the life cycle actions to do the lifecycle state change explicitly later lifecycleActions = getLifeCycleActions(currentStatus, targetStatus); - // Add/update swagger content except for streaming APIs and GraphQL APIs - if (!PublisherCommonUtils.isStreamingAPI(importedApiDTO) - && !APIConstants.APITransportType.GRAPHQL.toString().equalsIgnoreCase(apiType)) { - // Add the validated swagger separately since the UI does the same procedure - PublisherCommonUtils.updateSwagger(importedApi.getUuid(), validationResponse, false, organization); - importedApi = apiProvider.getAPIbyUUID(importedApi.getUuid(), currentTenantDomain); - } // Add the GraphQL schema if (APIConstants.APITransportType.GRAPHQL.toString().equalsIgnoreCase(apiType)) { importedApi.setOrganization(organization); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/PublisherCommonUtils.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/PublisherCommonUtils.java index 4bb028a323da..a33cd065bb03 100755 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/PublisherCommonUtils.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/common/mappings/PublisherCommonUtils.java @@ -112,6 +112,36 @@ public class PublisherCommonUtils { private static final Log log = LogFactory.getLog(PublisherCommonUtils.class); public static final String SESSION_TIMEOUT_CONFIG_KEY = "sessionTimeOut"; + + /** + * Update API and API definition. + * + * @param originalAPI existing API + * @param apiDtoToUpdate DTO object with updated API data + * @param apiProvider API Provider + * @param tokenScopes token scopes + * @param response response of the API definition validation + * @return updated API + * @throws APIManagementException If an error occurs while updating the API and API definition + * @throws ParseException If an error occurs while parsing the endpoint configuration + * @throws CryptoException If an error occurs while encrypting the secret key of API + * @throws FaultGatewaysException If an error occurs while updating manage of an existing API + */ + public static API updateApiAndDefinition(API originalAPI, APIDTO apiDtoToUpdate, APIProvider apiProvider, + String[] tokenScopes, APIDefinitionValidationResponse response) + throws APIManagementException, ParseException, CryptoException, FaultGatewaysException { + + API apiToUpdate = prepareForUpdateApi(originalAPI, apiDtoToUpdate, apiProvider, tokenScopes); + String organization = RestApiCommonUtil.getLoggedInUserTenantDomain(); + if (!PublisherCommonUtils.isStreamingAPI(apiDtoToUpdate) && !APIConstants.APITransportType.GRAPHQL.toString() + .equalsIgnoreCase(apiDtoToUpdate.getType().toString())) { + prepareForUpdateSwagger(originalAPI.getUuid(), response, false, apiProvider, organization, + response.getParser(), apiToUpdate); + } + apiProvider.updateAPI(apiToUpdate, originalAPI); + return apiProvider.getAPIbyUUID(originalAPI.getUuid(), originalAPI.getOrganization()); + } + /** * Update an API. * @@ -127,6 +157,28 @@ public class PublisherCommonUtils { public static API updateApi(API originalAPI, APIDTO apiDtoToUpdate, APIProvider apiProvider, String[] tokenScopes) throws ParseException, CryptoException, APIManagementException, FaultGatewaysException { + API apiToUpdate = prepareForUpdateApi(originalAPI, apiDtoToUpdate, apiProvider, tokenScopes); + apiProvider.updateAPI(apiToUpdate, originalAPI); + + return apiProvider.getAPIbyUUID(originalAPI.getUuid(), originalAPI.getOrganization()); + // TODO use returend api + } + + /** + * Prepare for API object before updating the API. + * + * @param originalAPI Existing API + * @param apiDtoToUpdate New API DTO to update + * @param apiProvider API Provider + * @param tokenScopes Scopes of the token + * @throws ParseException If an error occurs while parsing the endpoint configuration + * @throws CryptoException If an error occurs while encrypting the secret key of API + * @throws APIManagementException If an error occurs while updating the API + */ + private static API prepareForUpdateApi(API originalAPI, APIDTO apiDtoToUpdate, APIProvider apiProvider, + String[] tokenScopes) + throws APIManagementException, ParseException, CryptoException { + APIIdentifier apiIdentifier = originalAPI.getId(); // Validate if the USER_REST_API_SCOPES is not set in WebAppAuthenticator when scopes are validated if (tokenScopes == null) { @@ -359,10 +411,7 @@ public static API updateApi(API originalAPI, APIDTO apiDtoToUpdate, APIProvider } apiToUpdate.setOrganization(originalAPI.getOrganization()); - apiProvider.updateAPI(apiToUpdate, originalAPI); - - return apiProvider.getAPIbyUUID(originalAPI.getUuid(), originalAPI.getOrganization()); - // TODO use returend api + return apiToUpdate; } /** @@ -1343,6 +1392,36 @@ public static String updateSwagger(String apiId, APIDefinitionValidationResponse //this will fail if user does not have access to the API or the API does not exist API existingAPI = apiProvider.getAPIbyUUID(apiId, organization); APIDefinition oasParser = response.getParser(); + prepareForUpdateSwagger(apiId, response, isServiceAPI, apiProvider, organization, oasParser, existingAPI); + + //Update API is called to update URITemplates and scopes of the API + API unModifiedAPI = apiProvider.getAPIbyUUID(apiId, organization); + existingAPI.setStatus(unModifiedAPI.getStatus()); + apiProvider.updateAPI(existingAPI, unModifiedAPI); + + //retrieves the updated swagger definition + String apiSwagger = apiProvider.getOpenAPIDefinition(apiId, organization); // TODO see why we need to get it + // instead of passing same + return oasParser.getOASDefinitionForPublisher(existingAPI, apiSwagger); + } + + /** + * Prepare the API object before updating swagger. + * + * @param apiId API Id + * @param response response of a swagger definition validation call + * @param isServiceAPI whether the API is a service API or not + * @param apiProvider API Provider + * @param organization tenant domain + * @param oasParser OASParser for the API definition + * @param existingAPI existing API + * @throws APIManagementException when error occurred updating swagger + */ + private static void prepareForUpdateSwagger(String apiId, APIDefinitionValidationResponse response, + boolean isServiceAPI, APIProvider apiProvider, String organization, + APIDefinition oasParser, API existingAPI) + throws APIManagementException { + String apiDefinition = response.getJsonContent(); if (isServiceAPI) { apiDefinition = oasParser.copyVendorExtensions(existingAPI.getSwaggerDefinition(), apiDefinition); @@ -1390,20 +1469,10 @@ public static String updateSwagger(String apiId, APIDefinitionValidationResponse existingAPI.setScopes(scopes); PublisherCommonUtils.validateScopes(existingAPI); - //Update API is called to update URITemplates and scopes of the API - API unModifiedAPI = apiProvider.getAPIbyUUID(apiId, organization); - existingAPI.setStatus(unModifiedAPI.getStatus()); - apiProvider.updateAPI(existingAPI, unModifiedAPI); SwaggerData swaggerData = new SwaggerData(existingAPI); - String updatedApiDefinition = oasParser.populateCustomManagementInfo(apiDefinition, swaggerData); apiProvider.saveSwaggerDefinition(existingAPI, updatedApiDefinition, organization); existingAPI.setSwaggerDefinition(updatedApiDefinition); - - //retrieves the updated swagger definition - String apiSwagger = apiProvider.getOpenAPIDefinition(apiId, organization); // TODO see why we need to get it - // instead of passing same - return oasParser.getOASDefinitionForPublisher(existingAPI, apiSwagger); } /**