From b8a2bba622b05bb91a372526d7b9bfcbad8f8f88 Mon Sep 17 00:00:00 2001 From: hiranyakavishani Date: Wed, 4 Oct 2023 17:55:10 +0530 Subject: [PATCH] Refactoring lifecycle flow in APIProduct versioning --- .../carbon/apimgt/impl/APIProviderImpl.java | 2 +- .../carbon/apimgt/impl/dao/ApiMgtDAO.java | 247 +++++++++++------ .../utils/APIProductVersionComparator.java | 61 +++++ .../apimgt/impl/utils/LifeCycleUtils.java | 258 +++++++++++++----- 4 files changed, 422 insertions(+), 146 deletions(-) create mode 100644 components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIProductVersionComparator.java 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 c47ca07b61b0..fe7f1f0b2489 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 @@ -5470,7 +5470,6 @@ public Map searchPaginatedAPIProducts(String searchQuery, String publisherAPIInfo.getApiProductName(), publisherAPIInfo.getVersion())); mappedAPI.setUuid(publisherAPIInfo.getId()); mappedAPI.setState(publisherAPIInfo.getState()); - mappedAPI.setContext(publisherAPIInfo.getContext()); mappedAPI.setApiSecurity(publisherAPIInfo.getApiSecurity()); mappedAPI.setThumbnailUrl(publisherAPIInfo.getThumbnail()); mappedAPI.setBusinessOwner(publisherAPIInfo.getBusinessOwner()); @@ -5478,6 +5477,7 @@ public Map searchPaginatedAPIProducts(String searchQuery, String mappedAPI.setTechnicalOwner(publisherAPIInfo.getTechnicalOwner()); mappedAPI.setTechnicalOwnerEmail(publisherAPIInfo.getTechnicalOwnerEmail()); mappedAPI.setMonetizationEnabled(publisherAPIInfo.getMonetizationStatus()); + mappedAPI.setContextTemplate(publisherAPIInfo.getContext()); populateDefaultVersion(mappedAPI); populateAPIStatus(mappedAPI); productList.add(mappedAPI); diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/ApiMgtDAO.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/ApiMgtDAO.java index 408fe2d5d12a..776fc14b23e6 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/ApiMgtDAO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/ApiMgtDAO.java @@ -2077,7 +2077,7 @@ public Set getSubscribersOfAPI(APIIdentifier identifier) throws APIM * @return Set of subscribers * @throws APIManagementException if failed to get subscribers for given provider */ - public Set getSubscribersOfAPIWithoutDuplicates(APIIdentifier identifier, + public Set getSubscribersOfAPIWithoutDuplicates(Identifier identifier, Map subscriberMap) throws APIManagementException { Set subscribers = new HashSet(); @@ -2086,7 +2086,7 @@ public Set getSubscribersOfAPIWithoutDuplicates(APIIdentifier identi PreparedStatement ps = connection.prepareStatement(SQLConstants.GET_SUBSCRIBERS_OF_API_SQL);) { ps.setString(1, APIUtil.replaceEmailDomainBack(identifier.getProviderName())); - ps.setString(2, identifier.getApiName()); + ps.setString(2, identifier.getName()); ps.setString(3, identifier.getVersion()); try (ResultSet resultSet = ps.executeQuery()) { @@ -2101,7 +2101,7 @@ public Set getSubscribersOfAPIWithoutDuplicates(APIIdentifier identi } } } catch (SQLException e) { - handleException("Failed to get subscribers for :" + identifier.getApiName(), e); + handleException("Failed to get subscribers for :" + identifier.getName(), e); } return subscribers; } @@ -5040,93 +5040,43 @@ public List getLifeCycleEvents(String uuid) throws APIManagement return events; } - public List makeKeysForwardCompatible(ApiTypeWrapper apiTypeWrapper, List oldAPIVersions) throws APIManagementException { + public List makeKeysForwardCompatible(ApiTypeWrapper apiTypeWrapper, List oldAPIVersions, + List oldAPIProductVersions) + throws APIManagementException { + int versionCount = 0; List subscribedAPISet = new ArrayList<>(); + ApiTypeWrapper oldApiTypeWrapperCopy; + //if there are no previous versions, there is no need to copy subscriptions - if (oldAPIVersions == null || oldAPIVersions.isEmpty()) { + versionCount = getNoOfVersionsToCopySubscription(apiTypeWrapper, oldAPIVersions, oldAPIProductVersions); + if (versionCount == 0) { return subscribedAPISet; } + String getSubscriptionDataQuery = SQLConstants.GET_SUBSCRIPTION_DATA_SQL.replaceAll("_API_VERSION_LIST_", - String.join(",", Collections.nCopies(oldAPIVersions.size(), "?"))); - APIIdentifier apiIdentifier = apiTypeWrapper.getApi().getId(); + String.join(",", Collections.nCopies(versionCount, "?"))); + try { // Retrieve all the existing subscription for the old version try (Connection connection = APIMgtDBUtil.getConnection()) { connection.setAutoCommit(false); try (PreparedStatement prepStmt = connection.prepareStatement(getSubscriptionDataQuery)) { - prepStmt.setString(1, APIUtil.replaceEmailDomainBack(apiIdentifier.getProviderName())); - prepStmt.setString(2, apiIdentifier.getApiName()); + prepStmt.setString(1, + APIUtil.replaceEmailDomainBack(apiTypeWrapper.getId().getProviderName())); + prepStmt.setString(2, apiTypeWrapper.getId().getName()); int index = 3; - for (API oldAPI : oldAPIVersions) { - prepStmt.setString(index++, oldAPI.getId().getVersion()); - } - try (ResultSet rs = prepStmt.executeQuery()) { - List subscriptionData = new ArrayList(); - while (rs.next() && !(APIConstants.SubscriptionStatus.ON_HOLD.equals(rs.getString("SUB_STATUS" - )))) { - int subscriptionId = rs.getInt("SUBSCRIPTION_ID"); - String tierId = rs.getString("TIER_ID"); - int applicationId = rs.getInt("APPLICATION_ID"); - String apiVersion = rs.getString("VERSION"); - String subscriptionStatus = rs.getString("SUB_STATUS"); - SubscriptionInfo info = new SubscriptionInfo(subscriptionId, tierId, applicationId, - apiVersion, subscriptionStatus); - subscriptionData.add(info); + if (!apiTypeWrapper.isAPIProduct()) { + for (API oldAPI : oldAPIVersions) { + prepStmt.setString(index++, oldAPI.getId().getVersion()); } - // To keep track of already added subscriptions (apps) - List addedApplications = new ArrayList<>(); - for (int i = oldAPIVersions.size() - 1; i >= 0; i--) { - API oldAPI = oldAPIVersions.get(i); - for (SubscriptionInfo info : subscriptionData) { - try { - if (info.getApiVersion().equals(oldAPI.getId().getVersion()) && - !addedApplications.contains(info.getApplicationId())) { - String subscriptionStatus; - if (APIConstants.SubscriptionStatus.BLOCKED.equalsIgnoreCase(info.getSubscriptionStatus())) { - subscriptionStatus = APIConstants.SubscriptionStatus.BLOCKED; - } else if (APIConstants.SubscriptionStatus.UNBLOCKED.equalsIgnoreCase(info.getSubscriptionStatus())) { - subscriptionStatus = APIConstants.SubscriptionStatus.UNBLOCKED; - } else if (APIConstants.SubscriptionStatus.PROD_ONLY_BLOCKED.equalsIgnoreCase(info.getSubscriptionStatus())) { - subscriptionStatus = APIConstants.SubscriptionStatus.PROD_ONLY_BLOCKED; - } else if (APIConstants.SubscriptionStatus.REJECTED.equalsIgnoreCase(info.getSubscriptionStatus())) { - subscriptionStatus = APIConstants.SubscriptionStatus.REJECTED; - } else { - subscriptionStatus = APIConstants.SubscriptionStatus.ON_HOLD; - } - apiTypeWrapper.setTier(info.getTierId()); - Application application = getLightweightApplicationById(connection, - info.getApplicationId()); - String subscriptionUUID = UUID.randomUUID().toString(); - int subscriptionId = addSubscription(connection, apiTypeWrapper, application, - subscriptionStatus, apiIdentifier.getProviderName(), subscriptionUUID); - if (subscriptionId == -1) { - String msg = - "Unable to add a new subscription for the API: " + apiIdentifier.getName() + - ":v" + apiIdentifier.getVersion(); - log.error(msg); - throw new APIManagementException(msg); - } - SubscribedAPI subscribedAPI = new SubscribedAPI(subscriptionUUID); - subscribedAPI.setApplication(application); - subscribedAPI.setTier(new Tier(info.getTierId())); - subscribedAPI.setOrganization(apiTypeWrapper.getOrganization()); - subscribedAPI.setIdentifier(apiTypeWrapper); - subscribedAPI.setSubStatus(subscriptionStatus); - subscribedAPI.setSubscriptionId(subscriptionId); - addedApplications.add(info.getApplicationId()); - subscribedAPISet.add(subscribedAPI); - } - // catching the exception because when copy the api without the option "require - // re-subscription" - // need to go forward rather throwing the exception - } catch (SubscriptionAlreadyExistingException e) { - log.error("Error while adding subscription " + e.getMessage(), e); - } catch (SubscriptionBlockedException e) { - log.info("Subscription is blocked: " + e.getMessage()); - } - } + } else { + for (APIProduct oldAPIProduct : oldAPIProductVersions) { + prepStmt.setString(index++, oldAPIProduct.getId().getVersion()); } } + + retrieveSubscriptionData(apiTypeWrapper, oldAPIVersions, oldAPIProductVersions, versionCount, + subscribedAPISet, connection, prepStmt); connection.commit(); } catch (SQLException e) { connection.rollback(); @@ -5139,6 +5089,103 @@ public List makeKeysForwardCompatible(ApiTypeWrapper apiTypeWrapp return subscribedAPISet; } + private void retrieveSubscriptionData(ApiTypeWrapper apiTypeWrapper, List oldAPIVersions, + List oldAPIProductVersions, int versionCount, List subscribedAPISet, + Connection connection, PreparedStatement prepStmt) throws SQLException, APIManagementException { + ApiTypeWrapper oldApiTypeWrapperCopy; + try (ResultSet rs = prepStmt.executeQuery()) { + List subscriptionData = new ArrayList(); + while (rs.next() && !(APIConstants.SubscriptionStatus.ON_HOLD.equals( + rs.getString("SUB_STATUS")))) { + int subscriptionId = rs.getInt("SUBSCRIPTION_ID"); + String tierId = rs.getString("TIER_ID"); + int applicationId = rs.getInt("APPLICATION_ID"); + String apiVersion = rs.getString("VERSION"); + String subscriptionStatus = rs.getString("SUB_STATUS"); + SubscriptionInfo info = new SubscriptionInfo(subscriptionId, tierId, applicationId, + apiVersion, subscriptionStatus); + subscriptionData.add(info); + } + // To keep track of already added subscriptions (apps) + List addedApplications = new ArrayList<>(); + for (int i = versionCount - 1; i >= 0; i--) { + if (!apiTypeWrapper.isAPIProduct()) { + oldApiTypeWrapperCopy = new ApiTypeWrapper(oldAPIVersions.get(i)); + } else { + oldApiTypeWrapperCopy = new ApiTypeWrapper(oldAPIProductVersions.get(i)); + } + + for (SubscriptionInfo info : subscriptionData) { + try { + if (info.getApiVersion().equals(oldApiTypeWrapperCopy.getId() + .getVersion()) && !addedApplications.contains(info.getApplicationId())) { + String subscriptionStatus; + if (APIConstants.SubscriptionStatus.BLOCKED.equalsIgnoreCase( + info.getSubscriptionStatus())) { + subscriptionStatus = APIConstants.SubscriptionStatus.BLOCKED; + } else if (APIConstants.SubscriptionStatus.UNBLOCKED.equalsIgnoreCase( + info.getSubscriptionStatus())) { + subscriptionStatus = APIConstants.SubscriptionStatus.UNBLOCKED; + } else if (APIConstants.SubscriptionStatus.PROD_ONLY_BLOCKED.equalsIgnoreCase( + info.getSubscriptionStatus())) { + subscriptionStatus = APIConstants.SubscriptionStatus.PROD_ONLY_BLOCKED; + } else if (APIConstants.SubscriptionStatus.REJECTED.equalsIgnoreCase( + info.getSubscriptionStatus())) { + subscriptionStatus = APIConstants.SubscriptionStatus.REJECTED; + } else { + subscriptionStatus = APIConstants.SubscriptionStatus.ON_HOLD; + } + apiTypeWrapper.setTier(info.getTierId()); + Application application = getLightweightApplicationById(connection, + info.getApplicationId()); + String subscriptionUUID = UUID.randomUUID().toString(); + int subscriptionId = addSubscription(connection, apiTypeWrapper, application, + subscriptionStatus, oldApiTypeWrapperCopy.getId().getProviderName(), + subscriptionUUID); + if (subscriptionId == -1) { + String msg = "Unable to add a new subscription for the API: " + + oldApiTypeWrapperCopy.getName() + ":v" + oldApiTypeWrapperCopy.getId() + .getVersion(); + log.error(msg); + throw new APIManagementException(msg); + } + SubscribedAPI subscribedAPI = new SubscribedAPI(subscriptionUUID); + subscribedAPI.setApplication(application); + subscribedAPI.setTier(new Tier(info.getTierId())); + subscribedAPI.setOrganization(apiTypeWrapper.getOrganization()); + subscribedAPI.setIdentifier(apiTypeWrapper); + subscribedAPI.setSubStatus(subscriptionStatus); + subscribedAPI.setSubscriptionId(subscriptionId); + addedApplications.add(info.getApplicationId()); + subscribedAPISet.add(subscribedAPI); + } + // catching the exception because when copy the api without the option "require + // re-subscription" + // need to go forward rather throwing the exception + } catch (SubscriptionAlreadyExistingException e) { + log.error("Error while adding subscription " + e.getMessage(), e); + } catch (SubscriptionBlockedException e) { + log.info("Subscription is blocked: " + e.getMessage()); + } + } + } + } + } + + private int getNoOfVersionsToCopySubscription(ApiTypeWrapper apiTypeWrapper, List oldAPIVersions, + List oldAPIProductVersions) { + int count = 0; + if (!apiTypeWrapper.isAPIProduct()) { + if (oldAPIVersions != null && !oldAPIVersions.isEmpty()) + count = oldAPIVersions.size(); + } else { + if (oldAPIProductVersions != null && !oldAPIProductVersions.isEmpty()) { + count = oldAPIProductVersions.size(); + } + } + return count; + } + private int addSubscription(Connection connection, ApiTypeWrapper apiTypeWrapper, Application application, String subscriptionStatus, String subscriber) throws APIManagementException, SQLException { @@ -16192,6 +16239,54 @@ public List getAllAPIVersions(String apiName, String apiProvider) throws AP return apiVersions; } + + /** + * Return ids of the versions for the given name for the given provider + * + * @param apiProductName apiProduct name + * @param apiProvider provider + * @return set ids + * @throws APIManagementException + */ + public List getAllAPIProductVersions(String apiProductName, String apiProvider) + throws APIManagementException { + + List apiProductVersions = new ArrayList(); + + try (Connection connection = APIMgtDBUtil.getConnection(); + PreparedStatement statement = connection.prepareStatement(SQLConstants.GET_API_VERSIONS_UUID)) { + statement.setString(1, APIUtil.replaceEmailDomainBack(apiProvider)); + statement.setString(2, apiProductName); + ResultSet resultSet = statement.executeQuery(); + + while (resultSet.next()) { + String version = resultSet.getString("API_VERSION"); + String status = resultSet.getString("STATUS"); + String versionTimestamp = resultSet.getString("VERSION_COMPARABLE"); + String context = resultSet.getString("CONTEXT"); + String contextTemplate = resultSet.getString("CONTEXT_TEMPLATE"); + + String uuid = resultSet.getString("API_UUID"); + if (!APIConstants.API_PRODUCT.equals(resultSet.getString("API_TYPE"))) { + // skip api products + continue; + } + APIProduct apiProduct = new APIProduct(new APIProductIdentifier(apiProvider, apiProductName, + version, uuid)); + apiProduct.setUuid(uuid); + apiProduct.setState(status); + apiProduct.setVersionTimestamp(versionTimestamp); + apiProduct.setContext(context); + apiProduct.setContextTemplate(contextTemplate); + apiProductVersions.add(apiProduct); + } + } catch (SQLException e) { + handleException("Error while retrieving versions for apiProduct " + apiProductName + + " for the provider " + apiProvider, e); + } + return apiProductVersions; + } + /** * Get count of the revisions created for a particular API. * diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIProductVersionComparator.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIProductVersionComparator.java new file mode 100644 index 000000000000..e31ec41bf606 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIProductVersionComparator.java @@ -0,0 +1,61 @@ +/* + * Copyright WSO2 Inc. + * + * Licensed 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.apimgt.impl.utils; + +import org.wso2.carbon.apimgt.api.model.API; +import org.wso2.carbon.apimgt.api.model.APIProduct; + +import java.io.Serializable; +import java.util.Comparator; + +/** + *

Compares APIs by their versions. This comparator supports following version string + * format.

+ *
    + *
  • VersionString := VersionToken+
  • + *
  • VersionToken := VersionNumber | VersionSuffix | VersionNumber VersionSuffix
  • + *
  • VersionNumber := [0-9]+
  • + *
  • VersionSuffix := ~(0-9) AnyChar*
  • + *
+ *

Some example version strings supported by the comparator are given below.

+ *
    + *
  • 1.5
  • + *
  • 2.1.1
  • + *
  • 2.1.2b
  • + *
  • 1.3-SNAPSHOT
  • + *
  • 2.0.0.wso2v4
  • + *
+ *

Version matching is carried out by comparing the version strings token by token. Version + * numbers are compared in the conventional manner and the suffixes are compared + * lexicographically.

+ */ +public class APIProductVersionComparator implements Comparator,Serializable { + + private APIVersionStringComparator stringComparator = new APIVersionStringComparator(); + + @Override + public int compare(APIProduct apiProduct1, APIProduct apiProduct2) { + if (apiProduct1.getId().getProviderName().equals(apiProduct2.getId().getProviderName()) && + apiProduct1.getId().getName().equals(apiProduct2.getId().getName())) { + return stringComparator.compare(apiProduct1.getId().getVersion(), apiProduct2.getId().getVersion()); + } else { + APIProductNameComparator apiproductNameComparator = new APIProductNameComparator(); + return apiproductNameComparator.compare(apiProduct1, apiProduct2); + } + + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/LifeCycleUtils.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/LifeCycleUtils.java index 352b353bfbd0..65abd1339ec1 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/LifeCycleUtils.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/LifeCycleUtils.java @@ -62,23 +62,21 @@ public static void changeLifecycle(String user, APIProvider apiProvider, String String uuid = apiTypeWrapper.getUuid(); String currentStatus = apiTypeWrapper.getStatus(); targetStatus = LCManagerFactory.getInstance().getLCManager().getStateForTransition(action); - apiPersistence.changeAPILifeCycle(new Organization(orgId), apiTypeWrapper.getUuid(), targetStatus); - if (!apiTypeWrapper.isAPIProduct()) { - API api = apiTypeWrapper.getApi(); - api.setOrganization(orgId); - changeLifeCycle(apiProvider, api, currentStatus, targetStatus, checklist, orgId); - //Sending Notifications to existing subscribers - if (APIConstants.PUBLISHED.equals(targetStatus)) { - sendEmailNotification(api, orgId); - } - } else { - APIProduct apiProduct = apiTypeWrapper.getApiProduct(); - apiProduct.setOrganization(orgId); - changeLifecycle(apiProvider, apiProduct, currentStatus, targetStatus); + + // Update lifecycle state in the registry + UpdateLifeCycleState(apiProvider, orgId, apiTypeWrapper, checklist, targetStatus, currentStatus); + + //Sending Notifications to existing subscribers + if (APIConstants.PUBLISHED.equals(targetStatus)) { + sendEmailNotification(apiTypeWrapper, orgId); } + + // Change the lifecycle state in the database addLCStateChangeInDatabase(user, apiTypeWrapper, currentStatus, targetStatus, uuid); - // Event need to be sent after database status update. - sendLCStateChangeNotification(apiName, apiType, apiContext, apiTypeWrapper.getId().getVersion(), targetStatus, apiTypeWrapper.getId().getProviderName(), + + // Add LC state change event to the event queue + sendLCStateChangeNotification(apiName, apiType, apiContext, apiTypeWrapper.getId().getVersion(), targetStatus, + apiTypeWrapper.getId().getProviderName(), apiTypeWrapper.getId().getId(), uuid, orgId); // Remove revisions and subscriptions after API retire @@ -102,6 +100,19 @@ public static void changeLifecycle(String user, APIProvider apiProvider, String } } + private static void UpdateLifeCycleState(APIProvider apiProvider, String orgId, ApiTypeWrapper apiTypeWrapper, + Map checklist, String targetStatus, String currentStatus) throws APIManagementException { + if (!apiTypeWrapper.isAPIProduct()) { + API api = apiTypeWrapper.getApi(); + api.setOrganization(orgId); + changeAPILifeCycle(apiProvider, api, currentStatus, targetStatus, checklist); + } else { + APIProduct apiProduct = apiTypeWrapper.getApiProduct(); + apiProduct.setOrganization(orgId); + changeAPIProductLifecycle(apiProvider, apiProduct, currentStatus, targetStatus, checklist); + } + } + /** * Update the lifecycle of API Product in registry * @@ -110,7 +121,8 @@ public static void changeLifecycle(String user, APIProvider apiProvider, String * @param targetState Target state of the API Product * @throws APIManagementException Exception when updating the lc state of API Product */ - private static void changeLifecycle(APIProvider apiProvider, APIProduct apiProduct, String currentState, String targetState) + private static void changeAPIProductLifecycle(APIProvider apiProvider, APIProduct apiProduct, String currentState, + String targetState, Map checklist) throws APIManagementException { if (targetState != null) { @@ -126,10 +138,13 @@ private static void changeLifecycle(APIProvider apiProvider, APIProduct apiProdu } else { throw new APIManagementException("Invalid Lifecycle status provided for default APIExecutor"); } + + // If the API status is CREATED/PROTOTYPED ,check for check list items of lifecycle + executeLifeCycleChecklist(apiProvider, new ApiTypeWrapper(apiProduct), currentState, targetState, checklist); } - private static void changeLifeCycle(APIProvider apiProvider, API api, String currentState, String targetState, - Map checklist, String organization) + private static void changeAPILifeCycle(APIProvider apiProvider, API api, String currentState, String targetState, + Map checklist) throws APIManagementException { String oldStatus = currentState.toUpperCase(); @@ -176,8 +191,8 @@ private static void changeLifeCycle(APIProvider apiProvider, API api, String cur api.getOrganization()); API otherApi = apiProvider.getLightweightAPIByUUID(uuid, api.getOrganization()); APIEvent apiEvent = new APIEvent(UUID.randomUUID().toString(), System.currentTimeMillis(), - APIConstants.EventType.API_UPDATE.name(), APIUtil.getInternalOrganizationId(organization), - organization, + APIConstants.EventType.API_UPDATE.name(), + APIUtil.getInternalOrganizationId(api.getOrganization()), api.getOrganization(), otherApi.getId().getApiName(), otherApi.getId().getId(), otherApi.getUuid(), version, api.getType(), otherApi.getContext(), otherApi.getId().getProviderName(), otherApi.getStatus()); @@ -197,7 +212,6 @@ private static void changeLifeCycle(APIProvider apiProvider, API api, String cur // update api related information for state change updateAPIforStateChange(LifeCycleUtils.apiPersistence, api, currentState, newStatus); - if (log.isDebugEnabled()) { String logMessage = "API related information successfully updated. API Name: " + api.getId().getApiName() + ", API Version " + api.getId().getVersion() + ", API Context: " @@ -208,6 +222,21 @@ private static void changeLifeCycle(APIProvider apiProvider, API api, String cur throw new APIManagementException("Invalid Lifecycle status for default APIExecutor :" + targetState); } + // If the API status is CREATED/PROTOTYPED ,check for check list items of lifecycle + executeLifeCycleChecklist(apiProvider, new ApiTypeWrapper(api), currentState, targetState, checklist); + } + + + private static void executeLifeCycleChecklist(APIProvider apiProvider, ApiTypeWrapper apiTypeWrapper, + String currentState, String targetState, Map checklist) throws APIManagementException { + + String oldStatus = currentState.toUpperCase(); + String newStatus = (null != targetState) ? targetState.toUpperCase() : null; + + boolean isCurrentCreatedOrPrototyped = APIConstants.CREATED.equals(oldStatus) + || APIConstants.PROTOTYPED.equals(oldStatus); + boolean isStateTransitionToPublished = isCurrentCreatedOrPrototyped && APIConstants.PUBLISHED.equals(newStatus); + boolean deprecateOldVersions = false; boolean makeKeysForwardCompatible = true; // If the API status is CREATED/PROTOTYPED ,check for check list items of lifecycle @@ -224,23 +253,65 @@ private static void changeLifeCycle(APIProvider apiProvider, API api, String cur if (isStateTransitionToPublished) { if (makeKeysForwardCompatible) { - makeAPIKeysForwardCompatible(apiProvider, api); + makeAPIKeysForwardCompatible(apiProvider, apiTypeWrapper); } if (deprecateOldVersions) { - String provider = APIUtil.replaceEmailDomain(api.getId().getProviderName()); - String apiName = api.getId().getName(); - List apiList = getAPIVersionsByProviderAndName(provider, apiName, api.getOrganization()); - APIVersionComparator versionComparator = new APIVersionComparator(); - for (API oldAPI : apiList) { - if (oldAPI.getId().getApiName().equals(api.getId().getApiName()) - && versionComparator.compare(oldAPI, api) < 0 - && (APIConstants.PUBLISHED.equals(oldAPI.getStatus()))) { - apiProvider.changeLifeCycleStatus(organization, new ApiTypeWrapper( - apiProvider.getAPIbyUUID(oldAPI.getUuid(), organization)), - APIConstants.API_LC_ACTION_DEPRECATE, null); + deprecateOldVersions(apiProvider, apiTypeWrapper); + } + } + } + + private static void deprecateOldVersions(APIProvider apiProvider, ApiTypeWrapper apiTypeWrapper) + throws APIManagementException { + + String provider = APIUtil.replaceEmailDomain(apiTypeWrapper.getId().getProviderName()); + if (apiTypeWrapper.isAPIProduct()) { + deprecateOldAPIProductVersions(apiProvider, apiTypeWrapper.getApiProduct(), provider); + } else { + deprecateOldAPIVersions(apiProvider, apiTypeWrapper.getApi(), provider); + } + } + + private static void deprecateOldAPIVersions(APIProvider apiProvider, API api, String provider) + throws APIManagementException { + String apiName = api.getId().getName(); + if (log.isDebugEnabled()) { + log.debug("Deprecating old versions of API " + apiName + " of provider " + provider); + } + + List apiList = getAPIVersionsByProviderAndName(provider, apiName); + APIVersionComparator versionComparator = new APIVersionComparator(); + for (API oldAPI : apiList) { + if (oldAPI.getId().getApiName().equals(api.getId().getName()) + && versionComparator.compare(oldAPI, api) < 0 + && (APIConstants.PUBLISHED.equals(oldAPI.getStatus()))) { + apiProvider.changeLifeCycleStatus(api.getOrganization(), new ApiTypeWrapper( + apiProvider.getAPIbyUUID(oldAPI.getUuid(), api.getOrganization())), + APIConstants.API_LC_ACTION_DEPRECATE, null); + + } + } + } + + private static void deprecateOldAPIProductVersions(APIProvider apiProvider, APIProduct apiProduct, String provider) + throws APIManagementException { + String apiProductName = apiProduct.getId().getName(); + if (log.isDebugEnabled()) { + log.debug( + "Deprecating old versions of APIProduct " + apiProductName + " of provider " + provider); + } + + List apiProductList = getAPIProductVersionsByProviderAndName(provider, apiProductName); + APIProductVersionComparator versionComparator = new APIProductVersionComparator(); + for (APIProduct oldAPIProduct : apiProductList) { + if (oldAPIProduct.getId().getName() + .equals(apiProduct.getId().getName()) && versionComparator.compare(oldAPIProduct, apiProduct) < 0 + && (APIConstants.PUBLISHED.equals( + oldAPIProduct.getState()))) { + apiProvider.changeLifeCycleStatus(apiProduct.getOrganization(), new ApiTypeWrapper( + apiProvider.getAPIbyUUID(oldAPIProduct.getUuid(), + apiProduct.getOrganization())), APIConstants.API_LC_ACTION_DEPRECATE, null); - } - } } } } @@ -248,10 +319,11 @@ private static void changeLifeCycle(APIProvider apiProvider, API api, String cur /** * This method used to send notifications to the previous subscribers of older versions of a given API * - * @param api API object. + * @param apiTypeWrapper apiTypeWrapper object. * @throws APIManagementException */ - private static void sendEmailNotification(API api, String organization) throws APIManagementException { + private static void sendEmailNotification(ApiTypeWrapper apiTypeWrapper, String organization) + throws APIManagementException { try { JSONObject tenantConfig = APIUtil.getTenantConfig(organization); @@ -264,16 +336,16 @@ private static void sendEmailNotification(API api, String organization) throws A if (JavaUtils.isTrueExplicitly(isNotificationEnabled)) { Map subscriberMap = new HashMap<>(); - List apiIdentifiers = getOldPublishedAPIList(api); - for (APIIdentifier oldAPI : apiIdentifiers) { + List identifiers = getOldPublishedAPIOrAPIProductList(apiTypeWrapper); + + for (Identifier identifier : identifiers) { Properties prop = new Properties(); - prop.put(NotifierConstants.API_KEY, oldAPI); - prop.put(NotifierConstants.NEW_API_KEY, api.getId()); + prop.put(NotifierConstants.API_KEY, identifier); + prop.put(NotifierConstants.NEW_API_KEY, apiTypeWrapper.getId()); - Set subscribersOfAPI = apiMgtDAO.getSubscribersOfAPIWithoutDuplicates(oldAPI, + Set subscribersOfAPI = apiMgtDAO.getSubscribersOfAPIWithoutDuplicates(identifier, subscriberMap); prop.put(NotifierConstants.SUBSCRIBERS_PER_API, subscribersOfAPI); - NotificationDTO notificationDTO = new NotificationDTO(prop, NotifierConstants.NOTIFICATION_TYPE_NEW_VERSION); notificationDTO.setTenantID(tenantId); @@ -340,52 +412,100 @@ private static void extractRecommendationDetails(API api, String organization) { /** * This method returns a list of previous versions of a given API * - * @param api + * @param apiTypeWrapper apiTypeWrapper object. * @return oldPublishedAPIList * @throws APIManagementException */ - private static List getOldPublishedAPIList(API api) throws APIManagementException { - List oldPublishedAPIList = new ArrayList(); - List apiList = getAPIVersionsByProviderAndName(api.getId().getProviderName(), api.getId().getName(), - api.getOrganization()); + private static List getOldPublishedAPIOrAPIProductList(ApiTypeWrapper apiTypeWrapper) + throws APIManagementException { + List oldPublishedAPIList = new ArrayList(); APIVersionComparator versionComparator = new APIVersionComparator(); - for (API oldAPI : apiList) { - if (oldAPI.getId().getApiName().equals(api.getId().getApiName()) && - versionComparator.compare(oldAPI, api) < 0 && - (oldAPI.getStatus().equals(APIConstants.PUBLISHED))) { - oldPublishedAPIList.add(oldAPI.getId()); + APIProductVersionComparator apiProductVersionComparator = new APIProductVersionComparator(); + + if (apiTypeWrapper.isAPIProduct()) { + List apiList; + apiList = getAPIVersionsByProviderAndName(apiTypeWrapper.getId().getProviderName(), + apiTypeWrapper.getId().getName()); + for (API oldAPI : apiList) { + if (oldAPI.getId().getApiName().equals(apiTypeWrapper.getId().getName()) && versionComparator.compare( + oldAPI, apiTypeWrapper.getApi()) < 0 && (oldAPI.getStatus().equals(APIConstants.PUBLISHED))) { + oldPublishedAPIList.add(oldAPI.getId()); + } + } + } else { + List apiProductList = getAPIProductVersionsByProviderAndName( + apiTypeWrapper.getId().getProviderName(), apiTypeWrapper.getId().getName()); + + for (APIProduct oldAPIProduct : apiProductList) { + if (oldAPIProduct.getId().getName() + .equals(apiTypeWrapper.getId().getName()) && apiProductVersionComparator.compare(oldAPIProduct, + apiTypeWrapper.getApiProduct()) < 0 && (oldAPIProduct.getState() + .equals(APIConstants.PUBLISHED))) { + oldPublishedAPIList.add(oldAPIProduct.getId()); + } } } - return oldPublishedAPIList; } - private static List getAPIVersionsByProviderAndName(String provider, String apiName, String organization) + private static List getAPIVersionsByProviderAndName(String provider, String apiName) throws APIManagementException { return apiMgtDAO.getAllAPIVersions(apiName, provider); } - private static void makeAPIKeysForwardCompatible(APIProvider apiProvider, API api) throws APIManagementException { - String provider = api.getId().getProviderName(); - String apiName = api.getId().getApiName(); - Set versions = apiProvider.getAPIVersions(provider, apiName, api.getOrganization()); - APIVersionComparator comparator = new APIVersionComparator(); + private static List getAPIProductVersionsByProviderAndName(String provider, String apiProductName) + throws APIManagementException { + return apiMgtDAO.getAllAPIProductVersions(apiProductName, provider); + } + + private static void makeAPIKeysForwardCompatible(APIProvider apiProvider, ApiTypeWrapper apiTypeWrapper) + throws APIManagementException { + + String provider = apiTypeWrapper.getId().getProviderName(); + String apiName = apiTypeWrapper.getId().getName(); + Set versions = apiProvider.getAPIVersions(provider, apiName, apiTypeWrapper.getOrganization()); + APIVersionComparator apiComparator = new APIVersionComparator(); + APIProductVersionComparator apiProductComparator = new APIProductVersionComparator(); + List sortedAPIs = new ArrayList(); + List sortedAPIProducts = new ArrayList(); for (String version : versions) { - if (version.equals(api.getId().getVersion())) { + if (version.equals(apiTypeWrapper.getId().getVersion())) { continue; } - API otherApi = new API(new APIIdentifier(provider, apiName, version));//getAPI(new APIIdentifier(provider, apiName, version)); - if (comparator.compare(otherApi, api) < 0 && !APIConstants.RETIRED.equals(otherApi.getStatus())) { - sortedAPIs.add(otherApi); + if (!apiTypeWrapper.isAPIProduct()) { + API otherApi = new API(new APIIdentifier(provider, apiName, version)); + if (apiComparator.compare(otherApi, apiTypeWrapper.getApi()) < 0 && + !APIConstants.RETIRED.equals(otherApi.getStatus())) { + sortedAPIs.add(otherApi); + } + } else { + APIProduct otherAPIProduct = new APIProduct(new APIProductIdentifier(provider, apiName, version)); + if (apiProductComparator.compare(otherAPIProduct, apiTypeWrapper.getApiProduct()) < 0 && + !APIConstants.RETIRED.equals(otherAPIProduct.getState())) { + sortedAPIProducts.add(otherAPIProduct); + } } } - // Get the subscriptions from the latest api version first - Collections.sort(sortedAPIs, comparator); - List subscribedAPIS = apiMgtDAO.makeKeysForwardCompatible(new ApiTypeWrapper(api), sortedAPIs); - for (SubscribedAPI subscribedAPI : subscribedAPIS) { - SubscriptionEvent subscriptionEvent = new SubscriptionEvent(APIConstants.EventType.SUBSCRIPTIONS_CREATE.name(), subscribedAPI, APIUtil.getInternalOrganizationId(api.getOrganization()), api.getOrganization()); + if (apiTypeWrapper.isAPIProduct()) { + // Get the subscriptions from the latest api product version first + Collections.sort(sortedAPIProducts, apiProductComparator); + } else { + // Get the subscriptions from the latest api version first + Collections.sort(sortedAPIs, apiComparator); + } + + SendNotification(apiMgtDAO.makeKeysForwardCompatible(apiTypeWrapper, sortedAPIs, sortedAPIProducts), + apiTypeWrapper.getOrganization()); + } + + private static void SendNotification(List subscribedAPIs, String organization) + throws APIManagementException { + for (SubscribedAPI subscribedAPI : subscribedAPIs) { + SubscriptionEvent subscriptionEvent = new SubscriptionEvent( + APIConstants.EventType.SUBSCRIPTIONS_CREATE.name(), subscribedAPI, + APIUtil.getInternalOrganizationId(organization), organization); APIUtil.sendNotification(subscriptionEvent, APIConstants.NotifierType.SUBSCRIPTIONS.name()); } }