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 a387f492fc3e..f6774f033805 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 @@ -34,6 +34,7 @@ public enum ExceptionCodes implements ErrorHandler { API_VERSION_ALREADY_EXISTS(900252, "The API version already exists.", 409, "An API with version '%s' already exists for API '%s'"), API_PRODUCT_CONTEXT_ALREADY_EXISTS(900275, "The API Product context already exists.", 409, "An API Product with context '%s' already exists"), + API_PRODUCT_VERSION_ALREADY_EXISTS(900276, "The API Product version already exists.", 409, "An API Product with version '%s' already exists for API Product '%s'"), API_CONTEXT_MALFORMED_EXCEPTION(900253, "The API context is malformed.", 400, "'%s'"), API_ALREADY_EXISTS(900300, "The API already exists.", 409, "The API already exists"), diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIProduct.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIProduct.java index 44cecf63ea7a..b469919bbcb0 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIProduct.java +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIProduct.java @@ -132,7 +132,7 @@ public class APIProduct implements Serializable { * Used to set the workflow status in lifecycle state change workflow */ private String workflowStatus = null; - private boolean isDefaultVersion = false; + private Boolean isDefaultVersion = null; private boolean isPublishedDefaultVersion = false; public APIProduct(){} @@ -196,17 +196,17 @@ public String getTechnicalOwnerEmail() { public void setTechnicalOwnerEmail(String technicalOwnerEmail) { this.technicalOwnerEmail = technicalOwnerEmail; } - public void setDefaultVersion(boolean isDefaultVersion) { + public void setDefaultVersion(Boolean isDefaultVersion) { this.isDefaultVersion = isDefaultVersion; } public void setAsPublishedDefaultVersion(boolean value) { isPublishedDefaultVersion = value; } - public boolean isDefaultVersion() { + public Boolean isDefaultVersion() { return isDefaultVersion; } - public boolean isPublishedDefaultVersion() { + public Boolean isPublishedDefaultVersion() { return isPublishedDefaultVersion; } 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 1e988a5ebef6..aaaca12c5fd5 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 @@ -1932,17 +1932,26 @@ public API createNewAPIVersion(String existingApiId, String newVersion, Boolean public APIProduct createNewAPIProductVersion(String existingApiProductId, String newVersion, Boolean isDefaultVersion, String organization) throws APIManagementException { - APIProduct existingAPIProduct = getAPIProductbyUUID(existingApiProductId, organization); - if (existingAPIProduct == null) { - throw new APIMgtResourceNotFoundException("API Product not found for id " + existingApiProductId, - ExceptionCodes.from(ExceptionCodes.API_PRODUCT_NOT_FOUND, existingApiProductId)); + APIProductIdentifier apiProductIdentifier = APIUtil.getAPIProductIdentifierFromUUID(existingApiProductId); + if (apiProductIdentifier == null) { + throw new APIMgtResourceNotFoundException("Couldn't retrieve existing API Product with ID: " + + existingApiProductId, ExceptionCodes.from(ExceptionCodes.API_PRODUCT_NOT_FOUND, + existingApiProductId)); } - if (newVersion.equals(existingAPIProduct.getId().getVersion())) { + //Get all existing versions of APIProducts + Set apiProductVersions = getAPIVersions(apiProductIdentifier.getProviderName(), + apiProductIdentifier.getName(), organization); + + if (apiProductVersions.contains(newVersion)) { throw new APIMgtResourceAlreadyExistsException( - "Version " + newVersion + " exists for apiProduct " + existingAPIProduct.getId().getName()); + "Version " + newVersion + " exists for API product " + apiProductIdentifier.getName(), + ExceptionCodes.from(ExceptionCodes.API_PRODUCT_VERSION_ALREADY_EXISTS, newVersion, + apiProductIdentifier.getName())); } + APIProduct existingAPIProduct = getAPIProductbyUUID(existingApiProductId, organization); + APIProduct clonedAPIProduct = cloneExistingAPIProduct(existingAPIProduct); clonedAPIProduct.setOrganization(organization); APIProductIdentifier newApiProductId = new APIProductIdentifier( 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 776fc14b23e6..49dcff884515 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 @@ -5040,15 +5040,70 @@ public List getLifeCycleEvents(String uuid) throws APIManagement return events; } - public List makeKeysForwardCompatible(ApiTypeWrapper apiTypeWrapper, List oldAPIVersions, - List oldAPIProductVersions) + /** + * + * This method is used to copy the subscription new for new API Version + * + * @param apiTypeWrapper apiTypeWrapper + * @param oldAPIVersions oldAPIVersions + * @return List list of Subscribed APIs + * @throws APIManagementException APIManagementException + */ + public List makeKeysForwardCompatibleForNewAPIVersion(ApiTypeWrapper apiTypeWrapper, + List oldAPIVersions) throws APIManagementException { + int versionCount; + List subscribedAPISet = new ArrayList<>(); + + //if there are no previous versions, there is no need to copy subscriptions + versionCount = getNoOfVersionsToCopySubscription(apiTypeWrapper, oldAPIVersions, null); + if (versionCount == 0) { + return subscribedAPISet; + } + + String getSubscriptionDataQuery = SQLConstants.GET_SUBSCRIPTION_DATA_SQL.replaceAll("_API_VERSION_LIST_", + 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(apiTypeWrapper.getId().getProviderName())); + prepStmt.setString(2, apiTypeWrapper.getId().getName()); + int index = 3; + for (API oldAPI : oldAPIVersions) { + prepStmt.setString(index++, oldAPI.getId().getVersion()); + } + retrieveSubscriptionDataOfAPIs(apiTypeWrapper, oldAPIVersions, versionCount, subscribedAPISet, + connection, prepStmt); + connection.commit(); + } catch (SQLException e) { + connection.rollback(); + throw e; + } + } + } catch (SQLException e) { + handleException("Error when executing the SQL queries", e); + } + return subscribedAPISet; + } + + /** + * + * @param apiTypeWrapper apiTypeWrapper + * @param oldAPIProductVersions oldAPIProductVersions + * @return List list of Subscribed APIProducts + * @throws APIManagementException APIManagementException + */ + public List makeKeysForwardCompatibleForNewAPIProductVersion + (ApiTypeWrapper apiTypeWrapper, 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 - versionCount = getNoOfVersionsToCopySubscription(apiTypeWrapper, oldAPIVersions, oldAPIProductVersions); + versionCount = getNoOfVersionsToCopySubscription(apiTypeWrapper, null, oldAPIProductVersions); if (versionCount == 0) { return subscribedAPISet; } @@ -5065,17 +5120,10 @@ public List makeKeysForwardCompatible(ApiTypeWrapper apiTypeWrapp APIUtil.replaceEmailDomainBack(apiTypeWrapper.getId().getProviderName())); prepStmt.setString(2, apiTypeWrapper.getId().getName()); int index = 3; - if (!apiTypeWrapper.isAPIProduct()) { - for (API oldAPI : oldAPIVersions) { - prepStmt.setString(index++, oldAPI.getId().getVersion()); - } - } else { - for (APIProduct oldAPIProduct : oldAPIProductVersions) { + for (APIProduct oldAPIProduct : oldAPIProductVersions) { prepStmt.setString(index++, oldAPIProduct.getId().getVersion()); - } } - - retrieveSubscriptionData(apiTypeWrapper, oldAPIVersions, oldAPIProductVersions, versionCount, + retrieveSubscriptionDataOfAPIProducts(apiTypeWrapper, oldAPIProductVersions, versionCount, subscribedAPISet, connection, prepStmt); connection.commit(); } catch (SQLException e) { @@ -5089,7 +5137,34 @@ public List makeKeysForwardCompatible(ApiTypeWrapper apiTypeWrapp return subscribedAPISet; } - private void retrieveSubscriptionData(ApiTypeWrapper apiTypeWrapper, List oldAPIVersions, + private void retrieveSubscriptionDataOfAPIs(ApiTypeWrapper apiTypeWrapper, List oldAPIVersions, + 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--) { + oldApiTypeWrapperCopy = new ApiTypeWrapper(oldAPIVersions.get(i)); + addSubscriptionData(apiTypeWrapper, subscribedAPISet, connection, oldApiTypeWrapperCopy, + subscriptionData, addedApplications); + } + } + } + + private void retrieveSubscriptionDataOfAPIProducts(ApiTypeWrapper apiTypeWrapper, List oldAPIProductVersions, int versionCount, List subscribedAPISet, Connection connection, PreparedStatement prepStmt) throws SQLException, APIManagementException { ApiTypeWrapper oldApiTypeWrapperCopy; @@ -5109,65 +5184,67 @@ private void retrieveSubscriptionData(ApiTypeWrapper apiTypeWrapper, List o // 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)); - } + oldApiTypeWrapperCopy = new ApiTypeWrapper(oldAPIProductVersions.get(i)); + addSubscriptionData(apiTypeWrapper, subscribedAPISet, connection, oldApiTypeWrapperCopy, + subscriptionData, addedApplications); + } + } + } - 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 void addSubscriptionData(ApiTypeWrapper apiTypeWrapper, List subscribedAPISet, + Connection connection, ApiTypeWrapper oldApiTypeWrapperCopy, List subscriptionData, + List addedApplications) throws SQLException, APIManagementException { + 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()); } } } @@ -9702,7 +9779,6 @@ public void setDefaultVersion(ApiTypeWrapper apiTypeWrapper) throws APIManagemen } } } - } catch (SQLException e) { throw new APIManagementException("Error while retrieving apimgt connection", e, ExceptionCodes.INTERNAL_ERROR); 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 32019f2fd73a..ff933dbaa9c0 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 @@ -496,13 +496,15 @@ private static void makeAPIKeysForwardCompatible(APIProvider apiProvider, ApiTyp if (apiTypeWrapper.isAPIProduct()) { // Get the subscriptions from the latest api product version first Collections.sort(sortedAPIProducts, apiProductComparator); + SendNotification(apiMgtDAO.makeKeysForwardCompatibleForNewAPIProductVersion(apiTypeWrapper, sortedAPIProducts), + apiTypeWrapper.getOrganization()); + } else { // Get the subscriptions from the latest api version first Collections.sort(sortedAPIs, apiComparator); + SendNotification(apiMgtDAO.makeKeysForwardCompatibleForNewAPIVersion(apiTypeWrapper, sortedAPIs), + apiTypeWrapper.getOrganization()); } - - SendNotification(apiMgtDAO.makeKeysForwardCompatible(apiTypeWrapper, sortedAPIs, sortedAPIProducts), - apiTypeWrapper.getOrganization()); } private static void SendNotification(List subscribedAPIs, String 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 68b17c3cf4fe..237fdf077414 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 @@ -1841,6 +1841,8 @@ public static APIProduct addAPIProductWithGeneratedSwaggerDefinition(APIProductD apiProductDTO.setApiKeyHeader(APIConstants.API_KEY_HEADER_DEFAULT); } + apiProductDTO.setIsDefaultVersion(false); + //Remove the /{version} from the context. if (context.endsWith("/" + RestApiConstants.API_VERSION_PARAM)) { context = context.replace("/" + RestApiConstants.API_VERSION_PARAM, "");