diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.api/pom.xml index c04dcc2c83dc..604cae3a98df 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.api/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.api/pom.xml @@ -11,7 +11,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/APIProvider.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/APIProvider.java index e6ae3800b951..028fd054b660 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/APIProvider.java +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/APIProvider.java @@ -1701,6 +1701,15 @@ Map searchPaginatedAPIProducts(String searchQuery, String tenant */ String getSecuritySchemeOfAPI(String uuid, String organization) throws APIManagementException; + /** + * Returns whether subscription validation is disabled for an API + * + * @param uuid UUID of the API + * @return whether subscription validation is disabled + * @throws APIManagementException if failed get API from APIIdentifier + */ + boolean isSubscriptionValidationDisabled(String uuid) throws APIManagementException; + /** * Returns details of an API * @param uuid UUID of the API's registry artifact 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 e271b47a6724..a5033939ff01 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 @@ -630,6 +630,111 @@ public enum ExceptionCodes implements ErrorHandler { ENDPOINT_SECURITY_TYPE_NOT_DEFINED(903214, "Endpoint security type not defined", 400, "Endpoint security type not defined for the %s endpoint", false), + ADDITIONAL_PROPERTIES_CANNOT_BE_NULL(903215, "'additionalProperties' is required and should " + + "not be null", 400, + "The field 'additionalProperties' is required and should not be null"), + + ADDITIONAL_PROPERTIES_PARSE_ERROR(903216, "Error while parsing 'additionalProperties'", 400, + "Error while parsing 'additionalProperties'", true), + + ENDPOINT_SECURITY_CRYPTO_EXCEPTION(903217, "Error while encrypting the secret key of API", 500, + "%s"), + + OPENAPI_RETRIEVAL_ERROR(903218, "Error while retrieving the OAS definition", 500, + "Error while retrieving the OAS definition for API with UUID %s"), + + ASYNCAPI_RETRIEVAL_ERROR(903219, "Error while retrieving the Async API definition", 500, + "Error while retrieving the Async API definition for API with UUID %s"), + + ERROR_RETRIEVING_API(903220, "Failed to get API", 500, "Failed to get API with UUID %s"), + + ERROR_CHANGING_REGISTRY_LIFECYCLE_STATE(903221, "Error changing registry lifecycle state", 500, + "Error changing registry lifecycle state for API/API Product with UUID %s"), + + UN_AUTHORIZED_TO_VIEW_MODIFY_API(903222, "User is not authorized to view or modify the api", + 403, "User %s is not authorized to view or modify the api"), + + FAILED_PUBLISHING_API_NO_ENDPOINT_SELECTED(903223, "Failed to publish service to API store. No endpoint selected", + 400, "Failed to publish service to API store. No endpoint selected for API with UUID %s"), + + FAILED_PUBLISHING_API_NO_TIERS_SELECTED(903224, "Failed to publish service to API store. No Tiers selected", + 400, "Failed to publish service to API store. No Tiers selected for API with UUID %s"), + + THIRD_PARTY_API_REVISION_CREATION_UNSUPPORTED(903225, "Creating API Revisions is not supported " + + "for third party APIs", 400,"Creating API Revisions is not supported for third party APIs: %s"), + + THIRD_PARTY_API_REVISION_DEPLOYMENT_UNSUPPORTED(903226, "Deploying API Revisions is not supported " + + "for third party APIs", 400,"Deploying API Revisions is not supported for third party APIs: %s"), + + RETIRED_API_REVISION_DEPLOYMENT_UNSUPPORTED(903227, "Deploying API Revisions is not supported for retired APIs", + 400, "Deploying API Revisions is not supported for retired APIs. ApiId: %s"), + + REVISION_NOT_FOUND_FOR_REVISION_NUMBER(903228, "No revision found", 404, + "No revision found for revision number %s"), + + ERROR_PROCESSING_DIRECTORY_TO_IMPORT(903229, "Error extracting and processing the directory", 500, + "Error extracting and processing the directory to be imported", true), + + IMPORT_ERROR_INVALID_GRAPHQL_SCHEMA(903230, "Error occurred while importing the API. Invalid " + + "GraphQL schema definition found", 400, "Invalid GraphQL schema definition " + + "found. %s"), + + IMPORT_ERROR_INVALID_ASYNC_API_SCHEMA(903231, "Error occurred while importing the API. " + + "Invalid AsyncAPI definition found.", 400, "Invalid AsyncAPI definition found. %s"), + + NO_VHOSTS_DEFINED_FOR_ENVIRONMENT(903232, "No VHosts defined for the environment", 400, + "No VHosts defined for the environment: %s"), + + PROVIDED_GATEWAY_ENVIRONMENT_NOT_FOUND(903233, "Gateway environment not found", 400, + "Provided gateway environment %s is not found"), + + UNSUPPORTED_AND_ALLOWED_LIFECYCLE_ACTIONS(903234, "Unsupported state change action", 400, + "Lifecycle state change action %s is not allowed for this API. Allowed actions are %s"), + + NO_CORRESPONDING_RESOURCE_FOUND_IN_API(903235, "No corresponding resource found in API", 400, + "API with id %s does not have a resource %s with http method %s"), + + ERROR_PARSING_MONETIZATION_PROPERTIES(903237, "Error when parsing monetization properties", + 400, "Error when parsing monetization properties"), + + API_NAME_CANNOT_BE_NULL(903238, "API name is required", 400, + "API name is required and cannot be null"), + + API_NAME_ILLEGAL_CHARACTERS(903239, "API name contains illegal characters", 400, + "API name %s contains one or more illegal characters from (%s)"), + + API_VERSION_CANNOT_BE_NULL(903240, "API version is required", 400, + "API version is required and cannot be null"), + + API_VERSION_ILLEGAL_CHARACTERS(903241, "API version contains illegal characters", 400, + "API version %s contains one or more illegal characters from (%s)"), + + UNSUPPORTED_CONTEXT(903242, "Unsupported context", 400, + "Unsupported context %s"), + + ERROR_PARSING_ENDPOINT_CONFIG(903243, "Error when parsing endpoint configuration", + 400, "Error when parsing endpoint configuration"), + + NOT_IN_OPEN_API_FORMAT(903244, "Not in Open API format", + 400, "The API definition is not in Open API format"), + + PARAMETER_NOT_PROVIDED_FOR_DOCUMENTATION(903245, "Parameter value missing", 400, + "Some of the mandatory parameter values were missing. %s"), + + INVALID_API_RESOURCES_FOR_API_PRODUCT(903246, "Cannot find API resources for some API Product " + + "resources.", 404, "Some of the resources in the API Product are not found as API resources. %s"), + + INVALID_ADDITIONAL_PROPERTIES_WITH_ERROR(903247, "Invalid additional properties", 400, + "Invalid additional properties for API: %s:%s Error: %s"), + + TIER_NAME_INVALID_WITH_TIER_INFO(903248, "The tier name is invalid.", 400, + "The tier name(s) %s are invalid"), + + LENGTH_EXCEEDS_ERROR(903249, "Character length exceeds the allowable limit", 400, "%s"), + + ROLE_OF_SCOPE_DOES_NOT_EXIST(903250, "Role does not exist", 404, + "Role %s does not exist"), + OPERATION_OR_RESOURCE_TYPE_OR_METHOD_NOT_DEFINED(902031, "Operation type/http method is not specified for the operation/resource", 400, "Operation type/http method is not specified for the operation/resource: %s", false), diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIDefinitionContentSearchResult.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIDefinitionContentSearchResult.java new file mode 100644 index 000000000000..fa763f50e569 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/APIDefinitionContentSearchResult.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. 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.apimgt.api.model; + +/** + * This model is used to represent the API defintion content search results. + */ +public class APIDefinitionContentSearchResult { + + private String id; + private String name; + private String apiUuid; + private String apiName; + private String apiContext; + private String apiVersion; + private String apiProvider; + private String apiType; + private String associatedType; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getApiUuid() { + return apiUuid; + } + + public void setApiUuid(String apiUuid) { + this.apiUuid = apiUuid; + } + + public String getApiName() { + return apiName; + } + + public void setApiName(String apiName) { + this.apiName = apiName; + } + + public String getApiVersion() { + return apiVersion; + } + + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + + public String getApiProvider() { + return apiProvider; + } + + public void setApiProvider(String apiProvider) { + this.apiProvider = apiProvider; + } + + public String getApiType() { + return apiType; + } + + public void setApiType(String apiType) { + this.apiType = apiType; + } + + public String getAssociatedType() { + return associatedType; + } + + public void setAssociatedType(String associatedType) { + this.associatedType = associatedType; + } + + public String getApiContext() { + return apiContext; + } + + public void setApiContext(String apiContext) { + this.apiContext = apiContext; + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/subscription/API.java b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/subscription/API.java index c4de719c865f..211f685b915c 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/subscription/API.java +++ b/components/apimgt/org.wso2.carbon.apimgt.api/src/main/java/org/wso2/carbon/apimgt/api/model/subscription/API.java @@ -46,6 +46,7 @@ public class API implements CacheableEntity { private String revision; private String organization; private Set apiPolicies = new HashSet<>(); + private boolean isSubscriptionValidationDisabled = false; private AIConfiguration aiConfiguration; public String getRevision() { @@ -216,6 +217,14 @@ public Set getApiPolicies() { return apiPolicies; } + public boolean isSubscriptionValidationDisabled() { + return isSubscriptionValidationDisabled; + } + + public void setSubscriptionValidationDisabled(boolean subscriptionValidationDisabled) { + isSubscriptionValidationDisabled = subscriptionValidationDisabled; + } + public AIConfiguration getAiConfiguration() { return aiConfiguration; } diff --git a/components/apimgt/org.wso2.carbon.apimgt.broker.lifecycle/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.broker.lifecycle/pom.xml index e173bcf3926f..c1278788eedf 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.broker.lifecycle/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.broker.lifecycle/pom.xml @@ -4,7 +4,7 @@ apimgt org.wso2.carbon.apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.cache.invalidation/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.cache.invalidation/pom.xml index 2ce05ebdba4e..d2872f4b1a89 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.cache.invalidation/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.cache.invalidation/pom.xml @@ -19,7 +19,7 @@ apimgt org.wso2.carbon.apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT 4.0.0 diff --git a/components/apimgt/org.wso2.carbon.apimgt.cleanup.service/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.cleanup.service/pom.xml index 363521d784aa..f3f5e75ed700 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.cleanup.service/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.cleanup.service/pom.xml @@ -19,7 +19,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.common.analytics/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.common.analytics/pom.xml index 4a19d7488caa..9ea85438df17 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.common.analytics/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.common.analytics/pom.xml @@ -3,7 +3,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml 4.0.0 diff --git a/components/apimgt/org.wso2.carbon.apimgt.common.gateway/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.common.gateway/pom.xml index 3c8c6352bf0c..003bb249e9c9 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.common.gateway/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.common.gateway/pom.xml @@ -3,7 +3,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml 4.0.0 diff --git a/components/apimgt/org.wso2.carbon.apimgt.common.jms/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.common.jms/pom.xml index a43a72ae158a..7feeb98d0756 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.common.jms/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.common.jms/pom.xml @@ -4,7 +4,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml 4.0.0 diff --git a/components/apimgt/org.wso2.carbon.apimgt.core/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.core/pom.xml index 8297429507e5..a03ff6d8d237 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.core/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.core/pom.xml @@ -5,7 +5,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.devops.impl/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.devops.impl/pom.xml index 2541fb858cd3..a0e5a1453b44 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.devops.impl/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.devops.impl/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.eventing.hub/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.eventing.hub/pom.xml index 7d6e937b25f0..b2b77fd3df50 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.eventing.hub/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.eventing.hub/pom.xml @@ -20,7 +20,7 @@ apimgt org.wso2.carbon.apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.eventing/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.eventing/pom.xml index c6c663a4f634..d74336cd0f4a 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.eventing/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.eventing/pom.xml @@ -20,7 +20,7 @@ apimgt org.wso2.carbon.apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.gateway/pom.xml index bc9eeb4b4736..02a22f91a6db 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.gateway/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.gateway/pom.xml @@ -19,7 +19,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/throttling/APIThrottleConstants.java b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/throttling/APIThrottleConstants.java index 94cbfc040ad7..eac3e5f8108c 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/throttling/APIThrottleConstants.java +++ b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/throttling/APIThrottleConstants.java @@ -47,10 +47,19 @@ public class APIThrottleConstants { public static final String API_THROTTLE_OUT_HANDLER = "_throttle_out_handler_"; public static final String HARD_THROTTLING_CONFIGURATION = "hard_throttling_limits"; public static final String PRODUCTION_HARD_LIMIT = "PRODUCTION_HARD_LIMIT"; + public static final String PRODUCTION_HARD_LIMIT_TOTAL_TOKEN = "PRODUCTION_HARD_LIMIT_TOTAL_TOKEN"; + public static final String PRODUCTION_HARD_LIMIT_COMPLETION_TOKEN = "PRODUCTION_HARD_LIMIT_COMPLETION_TOKEN"; + public static final String PRODUCTION_HARD_LIMIT_PROMPT_TOKEN = "PRODUCTION_HARD_LIMIT_PROMPT_TOKEN"; public static final String SUBSCRIPTION_BURST_LIMIT = "SUBSCRIPTION_BURST_LIMIT"; public static final String APPLICATION_BURST_LIMIT = "APPLICATION_BURST_LIMIT"; public static final String APPLICATION_BURST_LIMIT_EXCEEDED = "APPLICATION_BURST_LIMIT_EXCEED"; public static final String SANDBOX_HARD_LIMIT = "SANDBOX_HARD_LIMIT"; + public static final String SANDBOX_HARD_LIMIT_TOTAL_TOKEN = "SANDBOX_HARD_LIMIT_TOTAL_TOKEN"; + public static final String SANDBOX_HARD_LIMIT_PROMPT_TOKEN = "SANDBOX_HARD_LIMIT_PROMPT_TOKEN"; + public static final String SANDBOX_HARD_LIMIT_COMPLETION_TOKEN = "SANDBOX_HARD_LIMIT_COMPLETION_TOKEN"; + public static final String TOTAL_TOKENS = "TOTAL_TOKENS"; + public static final String PROMPT_TOKENS = "PROMPT_TOKENS"; + public static final String COMPLETION_TOKENS = "COMPLETION_TOKENS"; public static final String THROTTLED_OUT_REASON = APIConstants.THROTTLE_OUT_REASON_KEY; public static final String THROTTLED_NEXT_ACCESS_TIMESTAMP = "NEXT_ACCESS_TIME"; public static final String THROTTLED_NEXT_ACCESS_TIME = "NEXT_ACCESS_UTC_TIME"; diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/throttling/ThrottleHandler.java b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/throttling/ThrottleHandler.java index b1fc4cac42b6..54eeeec329f8 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/throttling/ThrottleHandler.java +++ b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/throttling/ThrottleHandler.java @@ -80,9 +80,12 @@ import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.TimeZone; import javax.xml.stream.XMLStreamException; +import static org.wso2.carbon.apimgt.api.APIConstants.AIAPIConstants.*; + /** * This class is Handling new throttling check. This class will use inside each API as throttle handler. @@ -504,6 +507,74 @@ clientIp, getThrottleDataHolder().getKeyTemplateMap(), synCtx)) { return isThrottled; } + /** + * This method is responsible for sending non-throttle events to the throttling engine. This method will send + * backend throttling events to the synapse throttler and Subscription level throttling events to the CEP + * + * @param synCtx Synapse message context that contains message details. + * @return + */ + private void sendNonThrottleEventToThrottlingEngine(MessageContext synCtx) { + String resourceLevelThrottleKey = ""; + String resourceLevelTier = ""; + String applicationLevelThrottleKey; + String applicationLevelTier; + String apiLevelThrottleKey; + String apiLevelTier; + String subscriptionLevelThrottleKey; + String subscriptionLevelTier; + String authorizedUser; + + String subscriberTenantDomain = ""; + String apiTenantDomain = getTenantDomain(); + + + String apiContext = (String) synCtx.getProperty(RESTConstants.REST_API_CONTEXT); + String apiVersion = (String) synCtx.getProperty(RESTConstants.SYNAPSE_REST_API_VERSION); + apiContext = apiContext != null ? apiContext : ""; + apiVersion = apiVersion != null ? apiVersion : ""; + + List verbInfoDTOList = (List) synCtx.getProperty(APIConstants.VERB_INFO_DTO); + AuthenticationContext authenticationContext = APISecurityUtils.getAuthenticationContext(synCtx); + + if (authenticationContext != null) { + String applicationId = authenticationContext.getApplicationId();; + authorizedUser = authenticationContext.getUsername(); + + if (!StringUtils.contains(authorizedUser, apiTenantDomain)) { + authorizedUser = authenticationContext.getUsername() + "@" + apiTenantDomain; + } + subscriberTenantDomain = authenticationContext.getSubscriberTenantDomain(); + applicationLevelThrottleKey = applicationId + ":" + authorizedUser; + apiLevelThrottleKey = apiContext + ":" + apiVersion; + applicationLevelTier = authenticationContext.getApplicationTier(); + subscriptionLevelTier = authenticationContext.getTier(); + apiLevelTier = authenticationContext.getApiTier(); + subscriptionLevelThrottleKey = getSubscriptionLevelThrottleKey(subscriptionLevelTier, + authenticationContext, apiContext, apiVersion); + + if (Boolean.parseBoolean(isTokenBasedThrottlingEnabled)) { + //If backend token based throttling is enabled for AI APIs, we need to publish the throttling events + // to synapse throttler + isHardLimitThrottled(synCtx, authenticationContext, apiContext, apiVersion); + } + for (VerbInfoDTO verbInfo : verbInfoDTOList) { + resourceLevelThrottleKey = verbInfo.getRequestKey(); + resourceLevelTier = verbInfo.getThrottling(); + ServiceReferenceHolder.getInstance().getThrottleDataPublisher(). + publishNonThrottledEvent(applicationLevelThrottleKey, + applicationLevelTier, apiLevelThrottleKey, apiLevelTier, + subscriptionLevelThrottleKey, subscriptionLevelTier, + resourceLevelThrottleKey, resourceLevelTier, + authorizedUser, apiContext, + apiVersion, subscriberTenantDomain, apiTenantDomain, + applicationId, + synCtx, authenticationContext); + } + } + } + + private String getSubscriptionLevelThrottleKey(String subscriptionLevelTier, AuthenticationContext authContext, String apiContext, String apiVersion) { @@ -618,8 +689,56 @@ public boolean handleRequest(MessageContext messageContext) { @MethodStats public boolean handleResponse(MessageContext messageContext) { - if (ExtensionListenerUtil.preProcessResponse(messageContext, type)) { - return ExtensionListenerUtil.postProcessResponse(messageContext, type); + if (((Axis2MessageContext) messageContext).getAxis2MessageContext().getProperty(AI_API_RESPONSE_METADATA) != null) { + Timer timer3 = getTimer(MetricManager.name( + APIConstants.METRICS_PREFIX, this.getClass().getSimpleName(), THROTTLE_MAIN)); + Timer.Context context3 = timer3.start(); + TracingSpan throttleLatencyTracingSpan = null; + TelemetrySpan throttleLatencySpan = null; + if (TelemetryUtil.telemetryEnabled()) { + TelemetrySpan responseLatencySpan = + (TelemetrySpan) messageContext.getProperty(APIMgtGatewayConstants.RESOURCE_SPAN); + TelemetryTracer tracer = ServiceReferenceHolder.getInstance().getTelemetryTracer(); + throttleLatencySpan = TelemetryUtil.startSpan(APIMgtGatewayConstants.THROTTLE_LATENCY, + responseLatencySpan, tracer); + } else if (Util.tracingEnabled()) { + TracingSpan responseLatencySpan = + (TracingSpan) messageContext.getProperty(APIMgtGatewayConstants.RESOURCE_SPAN); + TracingTracer tracer = Util.getGlobalTracer(); + throttleLatencyTracingSpan = Util.startSpan(APIMgtGatewayConstants.THROTTLE_LATENCY, + responseLatencySpan, tracer); + } + long executionStartTime = System.currentTimeMillis(); + if (!ExtensionListenerUtil.preProcessResponse(messageContext, type)) { + return false; + } + try { + sendNonThrottleEventToThrottlingEngine(messageContext); + return ExtensionListenerUtil.postProcessResponse(messageContext, type); + } catch (Exception e) { + if (TelemetryUtil.telemetryEnabled()) { + TelemetryUtil.setTag(throttleLatencySpan, APIMgtGatewayConstants.ERROR, + APIMgtGatewayConstants.THROTTLE_HANDLER_ERROR); + } else if (Util.tracingEnabled()) { + Util.setTag(throttleLatencyTracingSpan, APIMgtGatewayConstants.ERROR, + APIMgtGatewayConstants.THROTTLE_HANDLER_ERROR); + } + throw e; + } finally { + messageContext.setProperty(APIMgtGatewayConstants.THROTTLING_LATENCY, + System.currentTimeMillis() - executionStartTime); + context3.stop(); + if (TelemetryUtil.telemetryEnabled()) { + TelemetryUtil.finishSpan(throttleLatencySpan); + } else if (Util.tracingEnabled()) { + Util.finishSpan(throttleLatencyTracingSpan); + } + } + + } else { + if (ExtensionListenerUtil.preProcessResponse(messageContext, type)) { + return ExtensionListenerUtil.postProcessResponse(messageContext, type); + } } return false; } @@ -1036,10 +1155,9 @@ private void initThrottleForHardLimitThrottling() { tempThrottle = ThrottleFactory.createMediatorThrottle( PolicyEngine.getPolicy(hardThrottlingPolicy)); ThrottleConfiguration newThrottleConfig = tempThrottle.getThrottleConfiguration(ThrottleConstants - .ROLE_BASED_THROTTLE_KEY); - ThrottleContext hardThrottling = ThrottleContextFactory.createThrottleContext(ThrottleConstants - .ROLE_BASE, - newThrottleConfig); + .ROLE_BASED_THROTTLE_KEY); + ThrottleContext hardThrottling = ThrottleContextFactory. + createThrottleContext(ThrottleConstants.ROLE_BASE, newThrottleConfig); tempThrottle.addThrottleContext(APIThrottleConstants.HARD_THROTTLING_CONFIGURATION, hardThrottling); if (throttle != null) { throttle.addThrottleContext(APIThrottleConstants.HARD_THROTTLING_CONFIGURATION, hardThrottling); @@ -1103,9 +1221,9 @@ public boolean isSubscriptionLevelSpike(MessageContext synCtx, String throttleKe if (subscriptionLevelSpikeArrestThrottleContext != null && authContext.getKeyType() != null) { org.apache.axis2.context.MessageContext axis2MC = ((Axis2MessageContext) synCtx). - getAxis2MessageContext(); - ConfigurationContext cc = axis2MC.getConfigurationContext(); - subscriptionLevelSpikeArrestThrottleContext.setConfigurationContext(cc); + getAxis2MessageContext(); + ConfigurationContext cc = axis2MC.getConfigurationContext(); + subscriptionLevelSpikeArrestThrottleContext.setConfigurationContext(cc); subscriptionLevelSpikeArrestThrottleContext.setThrottleId(id + APIThrottleConstants.SUBSCRIPTION_BURST_LIMIT); AccessInformation info = getAccessInformation(subscriptionLevelSpikeArrestThrottleContext, @@ -1172,21 +1290,59 @@ public boolean validateCustomPolicy(String userID, String appKey, String resourc private OMElement createHardThrottlingPolicy() { if (StringUtils.isEmpty(productionMaxCount) && - StringUtils.isEmpty(sandboxMaxCount)) { + StringUtils.isEmpty(sandboxMaxCount) && !Boolean.getBoolean(isTokenBasedThrottlingEnabled)) { return null; } OMElement parsedPolicy = null; StringBuilder policy = new StringBuilder(APIThrottleConstants.WS_THROTTLE_POLICY_HEADER); - if (productionMaxCount != null && productionUnitTime != null) { - policy.append(createPolicyForRole(APIThrottleConstants.PRODUCTION_HARD_LIMIT, productionUnitTime, - productionMaxCount)); + if (productionUnitTime != null) { + if (productionMaxCount != null) { + policy.append(createPolicyForRole(APIThrottleConstants.PRODUCTION_HARD_LIMIT, productionUnitTime, + productionMaxCount)); + } + if (isTokenBasedThrottlingEnabled != null) { + if (productionMaxTotalTokenCount != null) { + policy.append(createPolicyForRole(APIThrottleConstants.PRODUCTION_HARD_LIMIT_TOTAL_TOKEN, + productionUnitTime, + productionMaxTotalTokenCount)); + } + if (productionMaxCompletionTokenCount != null) { + policy.append(createPolicyForRole(APIThrottleConstants.PRODUCTION_HARD_LIMIT_COMPLETION_TOKEN, + productionUnitTime, + productionMaxCompletionTokenCount)); + } + if (productionMaxPromptTokenCount != null) { + policy.append(createPolicyForRole(APIThrottleConstants.PRODUCTION_HARD_LIMIT_PROMPT_TOKEN, + productionUnitTime, + productionMaxPromptTokenCount)); + } + } } - if (sandboxMaxCount != null && sandboxUnitTime != null) { - policy.append(createPolicyForRole(APIThrottleConstants.SANDBOX_HARD_LIMIT, sandboxUnitTime, - sandboxMaxCount)); + if (sandboxUnitTime != null) { + if (sandboxMaxCount != null) { + policy.append(createPolicyForRole(APIThrottleConstants.SANDBOX_HARD_LIMIT, sandboxUnitTime, + sandboxMaxCount)); + } + if (isTokenBasedThrottlingEnabled != null) { + if (Long.parseLong(sandboxMaxTotalTokenCount) != 0) { + policy.append(createPolicyForRole(APIThrottleConstants.SANDBOX_HARD_LIMIT_TOTAL_TOKEN, + sandboxUnitTime, + sandboxMaxTotalTokenCount)); + } + if (sandboxMaxCompletionTokenCount != null) { + policy.append(createPolicyForRole(APIThrottleConstants.SANDBOX_HARD_LIMIT_COMPLETION_TOKEN, + sandboxUnitTime, + sandboxMaxCompletionTokenCount)); + } + if (sandboxMaxPromptTokenCount != null) { + policy.append(createPolicyForRole(APIThrottleConstants.SANDBOX_HARD_LIMIT_PROMPT_TOKEN, + sandboxUnitTime, + sandboxMaxPromptTokenCount)); + } + } } policy.append(APIThrottleConstants.WS_THROTTLE_POLICY_BOTTOM); @@ -1212,55 +1368,166 @@ private String createPolicyForRole(String roleId, String unitTime, String maxCou " \n"; } + /** + * This method will check if coming request is hitting hard limits. + * + * @param synCtx synapse message context which contains message data + * @param authContext authentication context which contains authentication data + * @param apiContext api context of the request + * @param apiVersion api version of the request + * @return true if message is throttled else false + */ private boolean isHardLimitThrottled(MessageContext synCtx, AuthenticationContext authContext, String apiContext, String apiVersion) { - boolean status = false; - if (StringUtils.isNotEmpty(sandboxMaxCount) || StringUtils.isNotEmpty(productionMaxCount)) { - ThrottleContext hardThrottleContext = throttle.getThrottleContext(APIThrottleConstants.HARD_THROTTLING_CONFIGURATION); - try { - org.apache.axis2.context.MessageContext axis2MC = ((Axis2MessageContext) synCtx).getAxis2MessageContext(); - ConfigurationContext cc = axis2MC.getConfigurationContext(); - apiContext = apiContext != null ? apiContext : ""; - apiVersion = apiVersion != null ? apiVersion : ""; - - if (hardThrottleContext != null && authContext.getKeyType() != null) { - String throttleKey = apiContext + ':' + apiVersion + ':' + authContext.getKeyType(); - AccessInformation info = null; - hardThrottleContext.setConfigurationContext(cc); - if (APIConstants.API_KEY_TYPE_PRODUCTION.equals(authContext.getKeyType())) { - hardThrottleContext.setThrottleId(id + APIThrottleConstants.PRODUCTION_HARD_LIMIT); - info = getAccessInformation(hardThrottleContext, throttleKey, APIThrottleConstants.PRODUCTION_HARD_LIMIT); - } else if (APIConstants.API_KEY_TYPE_SANDBOX.equals(authContext.getKeyType())) { - hardThrottleContext.setThrottleId(id + APIThrottleConstants.SANDBOX_HARD_LIMIT); - info = getAccessInformation(hardThrottleContext, throttleKey, APIThrottleConstants.SANDBOX_HARD_LIMIT); - } + if (StringUtils.isEmpty(sandboxMaxCount) && StringUtils.isEmpty(productionMaxCount)) { + return false; + } - if (log.isDebugEnabled()) { - log.debug("Throttle by hard limit " + throttleKey); - log.debug("Allowed = " + (info != null ? info.isAccessAllowed() : "false")); - } + ThrottleContext hardThrottleContext = throttle.getThrottleContext(APIThrottleConstants.HARD_THROTTLING_CONFIGURATION); + if (hardThrottleContext == null || authContext.getKeyType() == null) { + return false; + } - if (info != null && !info.isAccessAllowed()) { - synCtx.setProperty(APIThrottleConstants.THROTTLED_OUT_REASON, APIThrottleConstants - .HARD_LIMIT_EXCEEDED); - log.info("Hard Throttling limit exceeded."); - status = true; - } - } + try { + org.apache.axis2.context.MessageContext axis2MC = ((Axis2MessageContext) synCtx).getAxis2MessageContext(); + hardThrottleContext.setConfigurationContext(axis2MC.getConfigurationContext()); + + String throttleKey = generateThrottleKey(apiContext, apiVersion, authContext.getKeyType()); + Map llmMetadata = (Map) axis2MC.getProperty(AI_API_RESPONSE_METADATA); + if (APIConstants.API_KEY_TYPE_PRODUCTION.equals(authContext.getKeyType())) { + return checkProductionLimit(synCtx, hardThrottleContext, throttleKey, llmMetadata); + } else if (APIConstants.API_KEY_TYPE_SANDBOX.equals(authContext.getKeyType())) { + return checkSandboxLimit(synCtx, hardThrottleContext, throttleKey, llmMetadata); + } + } catch (ThrottleException e) { + handleThrottleException(synCtx, e); + return true; + } - } catch (ThrottleException e) { - log.warn("Exception occurred while performing role " + - "based throttling", e); - synCtx.setProperty(APIThrottleConstants.THROTTLED_OUT_REASON, APIThrottleConstants.HARD_LIMIT_EXCEEDED); - status = true; + return false; + } + + /** + * Generates a throttle key based on API context, version, and key type. + */ + private String generateThrottleKey(String apiContext, String apiVersion, String keyType) { + return (apiContext != null ? apiContext : "") + ':' + + (apiVersion != null ? apiVersion : "") + ':' + keyType; + } + + /** + * Checks hard limits for production key type. + * @param synCtx synapse message context which contains message data + * @param hardThrottleContext throttle context for hard throttling + * @param throttleKey throttle key + * @param llmMetadata metadata from LLM provider + * @return true if message is throttled else false + */ + private boolean checkProductionLimit(MessageContext synCtx, ThrottleContext hardThrottleContext, + String throttleKey, Map llmMetadata) throws ThrottleException { + if (productionMaxCount != null && isAccessBlocked(synCtx, hardThrottleContext, throttleKey, + APIThrottleConstants.PRODUCTION_HARD_LIMIT, 1L)) { + return true; + } + return checkLlmMetadataLimits(synCtx, hardThrottleContext, throttleKey, llmMetadata, + APIThrottleConstants.PRODUCTION_HARD_LIMIT_PROMPT_TOKEN, + APIThrottleConstants.PRODUCTION_HARD_LIMIT_COMPLETION_TOKEN, + APIThrottleConstants.PRODUCTION_HARD_LIMIT_TOTAL_TOKEN); + } + + /** + * Checks hard limits for sandbox key type. + * @param synCtx synapse message context which contains message data + * @param hardThrottleContext throttle context for hard throttling + * @param throttleKey throttle key + * @param llmMetadata metadata from LLM provider + * @return true if message is throttled else false + */ + private boolean checkSandboxLimit(MessageContext synCtx, ThrottleContext hardThrottleContext, + String throttleKey, Map llmMetadata) throws ThrottleException { + if (sandboxMaxCount != null && isAccessBlocked(synCtx, hardThrottleContext, throttleKey, + APIThrottleConstants.SANDBOX_HARD_LIMIT, 1L)) { + return true; + } + return checkLlmMetadataLimits(synCtx, hardThrottleContext, throttleKey, llmMetadata, + APIThrottleConstants.SANDBOX_HARD_LIMIT_PROMPT_TOKEN, + APIThrottleConstants.SANDBOX_HARD_LIMIT_COMPLETION_TOKEN, + APIThrottleConstants.SANDBOX_HARD_LIMIT_TOTAL_TOKEN); + } + + /** + * Checks LLM metadata limits for prompt, completion, and total tokens. + */ + private boolean checkLlmMetadataLimits(MessageContext synCtx, ThrottleContext hardThrottleContext, String throttleKey, + Map llmMetadata, String promptTokenLimit, String completionTokenLimit, + String totalTokenLimit) throws ThrottleException { + if (llmMetadata != null && synCtx.isResponse()) { + if (Objects.nonNull(llmMetadata.get(LLM_PROVIDER_SERVICE_METADATA_PROMPT_TOKEN_COUNT)) && + isAccessBlocked(synCtx, hardThrottleContext, throttleKey, promptTokenLimit, + Long.valueOf(llmMetadata.get(LLM_PROVIDER_SERVICE_METADATA_PROMPT_TOKEN_COUNT)))) { + log.info("Hard throttling limit reached due to exceeding prompt token count."); + return true; + } + if (Objects.nonNull(llmMetadata.get(LLM_PROVIDER_SERVICE_METADATA_COMPLETION_TOKEN_COUNT)) && + isAccessBlocked(synCtx, hardThrottleContext, throttleKey, completionTokenLimit, + Long.valueOf(llmMetadata.get(LLM_PROVIDER_SERVICE_METADATA_COMPLETION_TOKEN_COUNT)))) { + log.info("Hard throttling limit reached due to exceeding completion token count."); + return true; + } + if (Objects.nonNull(llmMetadata.get(LLM_PROVIDER_SERVICE_METADATA_TOTAL_TOKEN_COUNT)) && + isAccessBlocked(synCtx, hardThrottleContext, throttleKey, totalTokenLimit, + Long.valueOf(llmMetadata.get(LLM_PROVIDER_SERVICE_METADATA_TOTAL_TOKEN_COUNT)))) { + log.info("Hard throttling limit reached due to exceeding total token count."); + return true; + } + } else if (llmMetadata != null && !synCtx.isResponse()) { + if (Objects.nonNull(llmMetadata.get(LLM_PROVIDER_SERVICE_METADATA_PROMPT_TOKEN_COUNT)) && + isAccessBlocked(synCtx, hardThrottleContext, throttleKey, promptTokenLimit, 0L)) { + log.info("Hard throttling limit reached due to exceeding prompt token count."); + return true; + } else if (Objects.nonNull(llmMetadata.get(LLM_PROVIDER_SERVICE_METADATA_COMPLETION_TOKEN_COUNT)) && + isAccessBlocked(synCtx, hardThrottleContext, throttleKey, completionTokenLimit, 0L)) { + log.info("Hard throttling limit reached due to exceeding completion token count."); + return true; + } else if (Objects.nonNull(llmMetadata.get(LLM_PROVIDER_SERVICE_METADATA_TOTAL_TOKEN_COUNT)) && + isAccessBlocked(synCtx, hardThrottleContext, throttleKey, totalTokenLimit, 0L)) { + log.info("Hard throttling limit reached due to exceeding total token count."); + return true; } } - return status; + return false; + } + + /** + * Checks if access is allowed based on the throttle context and throttle key. + */ + private boolean isAccessBlocked(MessageContext synCtx, ThrottleContext hardThrottleContext, String throttleKey, + String throttleLimit, Long tokenCount) throws ThrottleException { + hardThrottleContext.setThrottleId(id + throttleLimit); + AccessInformation info = getAccessInformation(hardThrottleContext, throttleKey, throttleLimit, tokenCount); + if (info != null && !info.isAccessAllowed()) { + synCtx.setProperty(APIThrottleConstants.THROTTLED_OUT_REASON, APIThrottleConstants.HARD_LIMIT_EXCEEDED); + return true; + } + return false; + } + + /** + * Handles throttle exceptions. + */ + private void handleThrottleException(MessageContext synCtx, ThrottleException e) { + log.warn("Exception occurred while performing role-based throttling", e); + synCtx.setProperty(APIThrottleConstants.THROTTLED_OUT_REASON, APIThrottleConstants.HARD_LIMIT_EXCEEDED); + } + + protected AccessInformation getAccessInformation(ThrottleContext hardThrottleContext, String throttleKey, + String productionHardLimit) throws ThrottleException { + return roleBasedAccessController.canAccess(hardThrottleContext, throttleKey, productionHardLimit); } - protected AccessInformation getAccessInformation(ThrottleContext hardThrottleContext, String throttleKey, String productionHardLimit) throws ThrottleException { - return roleBasedAccessController.canAccess(hardThrottleContext, throttleKey, - productionHardLimit); + protected AccessInformation getAccessInformation(ThrottleContext hardThrottleContext, String throttleKey, + String productionHardLimit, Long tokenCount) throws ThrottleException { + return roleBasedAccessController.canAccess(hardThrottleContext, throttleKey, productionHardLimit, tokenCount); } public String getSandboxMaxCount() { diff --git a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/throttling/publisher/DataProcessAndPublishingAgent.java b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/throttling/publisher/DataProcessAndPublishingAgent.java index e8a1c2ba4464..57f7dcfe85aa 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/throttling/publisher/DataProcessAndPublishingAgent.java +++ b/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/throttling/publisher/DataProcessAndPublishingAgent.java @@ -34,6 +34,8 @@ import java.util.regex.Pattern; import javax.xml.stream.XMLStreamException; +import static org.wso2.carbon.apimgt.api.APIConstants.AIAPIConstants.*; + /** * This class is responsible for executing data publishing logic. This class implements runnable interface and * need to execute using thread pool executor. Primary task of this class it is accept message context as parameter @@ -68,6 +70,9 @@ public class DataProcessAndPublishingAgent implements Runnable { String apiName; String appId; String ipAddress; + Long totalTokens; + Long promptTokens; + Long completionTokens; Map headersMap; Map customPropertyMap; private AuthenticationContext authenticationContext; @@ -103,6 +108,9 @@ public void clearDataReference() { this.apiName = null; this.ipAddress = null; this.headersMap = null; + this.totalTokens = null; + this.promptTokens = null; + this.completionTokens = null; this.messageSizeInBytes = 0; this.customPropertyMap = Collections.emptyMap(); } @@ -138,6 +146,9 @@ public void setDataReference(String applicationLevelThrottleKey, String applicat this.appId = appId; this.apiName = GatewayUtils.getAPINameFromContextAndVersion(messageContext); this.messageSizeInBytes = 0; + this.totalTokens = null; + this.promptTokens = null; + this.completionTokens = null; ArrayList list = (ArrayList) messageContext.getProperty(APIConstants.VERB_INFO_DTO); boolean isVerbInfoContentAware = false; @@ -201,6 +212,15 @@ public void setDataReference(String applicationLevelThrottleKey, String applicat } } } + + if (messageContext.getProperty(AI_API_RESPONSE_METADATA) != null) { + Map responseMetadata = (Map) messageContext.getProperty(AI_API_RESPONSE_METADATA); + if (responseMetadata != null) { + totalTokens = Long.parseLong(responseMetadata.get(LLM_PROVIDER_SERVICE_METADATA_TOTAL_TOKEN_COUNT)); + promptTokens = Long.parseLong(responseMetadata.get(LLM_PROVIDER_SERVICE_METADATA_PROMPT_TOKEN_COUNT)); + completionTokens = Long.parseLong(responseMetadata.get(LLM_PROVIDER_SERVICE_METADATA_COMPLETION_TOKEN_COUNT)); + } + } } public void run() { @@ -282,6 +302,16 @@ public void run() { } + if (totalTokens != null) { + jsonObMap.put(APIThrottleConstants.TOTAL_TOKENS, totalTokens); + } + if (promptTokens != null) { + jsonObMap.put(APIThrottleConstants.PROMPT_TOKENS, promptTokens); + } + if (completionTokens != null) { + jsonObMap.put(APIThrottleConstants.COMPLETION_TOKENS, completionTokens); + } + Object[] objects = new Object[]{messageContext.getMessageID(), this.applicationLevelThrottleKey, this.applicationLevelTier, this.apiLevelThrottleKey, this.apiLevelTier, diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.impl/pom.xml index 1d43551bf40e..6e6543f925b4 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/pom.xml @@ -12,7 +12,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java index 40f5c70dbf7f..2147876f2c7f 100755 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConstants.java @@ -136,6 +136,8 @@ public final class APIConstants { public static final String API_TENANT_CONF_DEFAULT_SUBSCRIPTION_TIER = "DefaultSubscriptionLevelTier"; public static final String API_TENANT_CONF_EXPOSE_ENDPOINT_PASSWORD = "ExposeEndpointPassword"; + public static final String API_TENANT_CONF_ALLOW_SUBSCRIPTION_VALIDATION_DISABLING + = "AllowSubscriptionValidationDisabling"; public static final String API_CATEGORY_FREE = "Free"; @@ -755,6 +757,7 @@ private Permissions() { public static final String API_WEBSUB_GATEWAY_ENDPOINT = "GatewayWebSubEndpoint"; public static final String API_GATEWAY_TYPE = "GatewayType"; public static final String API_GATEWAY_TYPE_SYNAPSE = "Synapse"; + public static final String API_GATEWAY_TYPE_ENVOY = "Envoy"; public static final String API_GATEWAY_TYPE_REGULAR = "Regular"; public static final String API_GATEWAY_TYPE_APK = "APK"; public static final String API_GATEWAY_VIRTUAL_HOSTS = "VirtualHosts"; @@ -821,6 +824,8 @@ private Permissions() { API_KEY_VALIDATOR + "EnableProvisionedAppValidation"; public static final String API_KEY_SUBSCRIPTION_VALIDATION_ENABLED = API_KEY_VALIDATOR + "EnableAPIKeySubscriptionValidation"; + public static final String ALLOW_SUBSCRIPTION_VALIDATION_DISABLING = API_KEY_VALIDATOR + + "AllowSubscriptionValidationDisabling"; public static final String KEY_MANAGER_OAUTH2_SCOPES_REST_API_BASE_PATH = "/api/identity/oauth2/v1.0/scopes"; public static final String KEY_MANAGER_OAUTH2_SCOPES_SCOPE_NAME_PARAM = "{scope_name}"; public static final String KEY_MANAGER_OAUTH2_SCOPES_REST_API_SCOPE_NAME = "/name/" @@ -981,6 +986,10 @@ private Permissions() { public static final String BASIC_AUTH_APPLICATION_OWNER = " BasicAuthApplicationOwner"; public static final String MUTUAL_SSL_AUTH_APPLICATION_NAME = "MutualSSLAuthApplication"; public static final String MUTUAL_SSL_AUTH_APPLICATION_OWNER = "MutualSSLAuthApplicationOwner"; + public static final String SUBSCRIPTIONLESS_APPLICATION_NAME = "SubscriptionLessApplication"; + public static final String SUBSCRIPTIONLESS_APPLICATION_OWNER = "SubscriptionLessApplicationOwner"; + public static final String SUBSCRIPTIONLESS_APPLICATION_DESCRIPTION = "This application is used to internally" + + " subscribe to APIs when subscription validation is disabled"; public static final QName POLICY_ELEMENT = new QName("http://schemas.xmlsoap.org/ws/2004/09/policy", "Policy"); @@ -1242,6 +1251,7 @@ public static class SubscriptionValidationResources { public static final String APPLICATIONS = "/applications"; public static final String SUBSCRIPTIONS = "/subscriptions"; public static final String SUBSCRIBERS = "/subscribers"; + public static final String SUBSCRIBE_INTERNAL = "/subscribe-internal"; public static final String APPLICATION_KEY_MAPPINGS = "/application-key-mappings"; public static final String APPLICATION_POLICIES = "/application-policies"; public static final String API_POLICIES = "/api-policies"; @@ -1343,7 +1353,7 @@ public static class AccessTokenConstants { public static final String REST_METHOD = "REST_METHOD"; // GraphQL related constants - public static final String API_TYPE = "API_TYPE"; + public static final String API_TYPE = "ApiType"; public static final String HTTP_VERB = "HTTP_VERB"; public static final String GRAPHQL_API = "GRAPHQL"; public static final String GRAPHQL_SUBSCRIPTION_REQUEST = "isGraphqlSubscriptionRequest"; @@ -1835,6 +1845,9 @@ private ConfigParameters() { public static final String REGISTRY_RESOURCE_URL_PREFIX = "/registry/resource/_system/governance/apimgt/applicationdata/provider/"; + public static final String APPLICATION_DATA_RESOURCE_URL_PREFIX = + "/apimgt/applicationdata/provider/"; + public enum RegistryResourceTypesForUI { TAG_THUMBNAIL } @@ -1923,11 +1936,13 @@ public enum RegistryResourceTypesForUI { public static final String DEFAULT_SUB_POLICY_BRONZE = "Bronze"; public static final String DEFAULT_SUB_POLICY_UNLIMITED = "Unlimited"; public static final String DEFAULT_SUB_POLICY_UNAUTHENTICATED = "Unauthenticated"; + public static final String DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS = "DefaultSubscriptionless"; public static final String DEFAULT_SUB_POLICY_ASYNC_GOLD = "AsyncGold"; public static final String DEFAULT_SUB_POLICY_ASYNC_SILVER = "AsyncSilver"; public static final String DEFAULT_SUB_POLICY_ASYNC_BRONZE = "AsyncBronze"; public static final String DEFAULT_SUB_POLICY_ASYNC_UNLIMITED = "AsyncUnlimited"; + public static final String DEFAULT_SUB_POLICY_ASYNC_SUBSCRIPTIONLESS = "AsyncDefaultSubscriptionless"; public static final String DEFAULT_SUB_POLICY_ASYNC_WH_GOLD = "AsyncWHGold"; public static final String DEFAULT_SUB_POLICY_ASYNC_WH_SILVER = "AsyncWHSilver"; @@ -1939,11 +1954,15 @@ public enum RegistryResourceTypesForUI { public static final String DEFAULT_SUB_POLICY_BRONZE_DESC = "Allows 1000 requests per minute"; public static final String DEFAULT_SUB_POLICY_UNLIMITED_DESC = "Allows unlimited requests"; public static final String DEFAULT_SUB_POLICY_UNAUTHENTICATED_DESC = "Allows 500 request(s) per minute"; + public static final String DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS_DESC = + "Allows 10000 requests per minute when subscription validation is disabled"; public static final String DEFAULT_SUB_POLICY_ASYNC_GOLD_DESC = "Allows 50000 events per day"; public static final String DEFAULT_SUB_POLICY_ASYNC_SILVER_DESC = "Allows 25000 events per day"; public static final String DEFAULT_SUB_POLICY_ASYNC_BRONZE_DESC = "Allows 5000 events per day"; public static final String DEFAULT_SUB_POLICY_ASYNC_UNLIMITED_DESC = "Allows unlimited events"; + public static final String DEFAULT_SUB_POLICY_ASYNC_SUBSCRIPTIONLESS_DESC = + "Allows 10000 events per day when subscription validation is disabled"; public static final String DEFAULT_SUB_POLICY_ASYNC_WH_GOLD_DESC = "Allows 10000 events per month and " + "1000 active subscriptions"; @@ -2081,6 +2100,7 @@ public static class AdvancedThrottleConstants { public static final String TRUE = "true"; public static final String ADD = "add"; public static final String ENABLE_POLICY_DEPLOYMENT = "EnablePolicyDeployment"; + public static final String ENABLE_POLICY_RECREATE = "EnablePolicyRecreationOnStartup"; } /** diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConsumerImpl.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConsumerImpl.java index 6b4d9db2efca..ee11eef9817a 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConsumerImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIConsumerImpl.java @@ -46,6 +46,7 @@ import org.wso2.carbon.apimgt.api.dto.KeyManagerConfigurationDTO; import org.wso2.carbon.apimgt.api.dto.KeyManagerPermissionConfigurationDTO; import org.wso2.carbon.apimgt.api.model.API; +import org.wso2.carbon.apimgt.api.model.APIDefinitionContentSearchResult; import org.wso2.carbon.apimgt.api.model.APIIdentifier; import org.wso2.carbon.apimgt.api.model.APIKey; import org.wso2.carbon.apimgt.api.model.APIProduct; @@ -117,6 +118,7 @@ import org.wso2.carbon.apimgt.impl.utils.APIVersionComparator; import org.wso2.carbon.apimgt.impl.utils.ApplicationUtils; import org.wso2.carbon.apimgt.impl.utils.ContentSearchResultNameComparator; +import org.wso2.carbon.apimgt.impl.utils.SimpleContentSearchResultNameComparator; import org.wso2.carbon.apimgt.impl.utils.VHostUtils; import org.wso2.carbon.apimgt.impl.workflow.ApplicationDeletionApprovalWorkflowExecutor; import org.wso2.carbon.apimgt.impl.workflow.ApplicationRegistrationSimpleWorkflowExecutor; @@ -137,6 +139,7 @@ import org.wso2.carbon.apimgt.persistence.dto.DocumentSearchContent; import org.wso2.carbon.apimgt.persistence.dto.Organization; import org.wso2.carbon.apimgt.persistence.dto.SearchContent; +import org.wso2.carbon.apimgt.persistence.dto.APIDefSearchContent; import org.wso2.carbon.apimgt.persistence.dto.UserContext; import org.wso2.carbon.apimgt.persistence.exceptions.APIPersistenceException; import org.wso2.carbon.apimgt.persistence.exceptions.OASPersistenceException; @@ -4166,6 +4169,7 @@ public Map searchPaginatedContent(String searchQuery, String org Map result = new HashMap(); SortedSet apiSet = new TreeSet(new APINameComparator()); SortedSet apiProductSet = new TreeSet(new APIProductNameComparator()); + List defSearchList = new ArrayList<>(); int totalLength = 0; String userame = (userNameWithoutChange != null) ? userNameWithoutChange : username; @@ -4193,23 +4197,36 @@ public Map searchPaginatedContent(String searchQuery, String org docItem.getApiVersion())); api.setUuid(docItem.getApiUUID()); docMap.put(doc, api); + } else if (item instanceof APIDefSearchContent) { + APIDefSearchContent definitionItem = (APIDefSearchContent) item; + APIDefinitionContentSearchResult apiDefSearchResult = new APIDefinitionContentSearchResult(); + apiDefSearchResult.setId(definitionItem.getId()); + apiDefSearchResult.setName(definitionItem.getName()); + apiDefSearchResult.setApiUuid(definitionItem.getApiUUID()); + apiDefSearchResult.setApiName(definitionItem.getApiName()); + apiDefSearchResult.setApiContext(definitionItem.getApiContext()); + apiDefSearchResult.setApiProvider(definitionItem.getApiProvider()); + apiDefSearchResult.setApiVersion(definitionItem.getApiVersion()); + apiDefSearchResult.setApiType(definitionItem.getApiType()); + apiDefSearchResult.setAssociatedType(definitionItem.getAssociatedType()); //API or API product + defSearchList.add(apiDefSearchResult); } else if ("API".equals(item.getType())) { - DevPortalSearchContent publiserAPI = (DevPortalSearchContent) item; - API api = new API(new APIIdentifier(publiserAPI.getProvider(), publiserAPI.getName(), - publiserAPI.getVersion())); - api.setUuid(publiserAPI.getId()); - api.setContext(publiserAPI.getContext()); - api.setContextTemplate(publiserAPI.getContext()); - api.setStatus(publiserAPI.getStatus()); - api.setBusinessOwner(publiserAPI.getBusinessOwner()); - api.setBusinessOwnerEmail(publiserAPI.getBusinessOwnerEmail()); - api.setTechnicalOwner(publiserAPI.getTechnicalOwner()); - api.setTechnicalOwnerEmail(publiserAPI.getTechnicalOwnerEmail()); - api.setMonetizationEnabled(publiserAPI.getMonetizationStatus()); - api.setAdvertiseOnly(publiserAPI.getAdvertiseOnly()); - api.setRating(APIUtil.getAverageRating(publiserAPI.getId())); - api.setDescription(publiserAPI.getDescription()); - api.setType(publiserAPI.getTransportType()); + DevPortalSearchContent publisherAPI = (DevPortalSearchContent) item; + API api = new API(new APIIdentifier(publisherAPI.getProvider(), publisherAPI.getName(), + publisherAPI.getVersion())); + api.setUuid(publisherAPI.getId()); + api.setContext(publisherAPI.getContext()); + api.setContextTemplate(publisherAPI.getContext()); + api.setStatus(publisherAPI.getStatus()); + api.setBusinessOwner(publisherAPI.getBusinessOwner()); + api.setBusinessOwnerEmail(publisherAPI.getBusinessOwnerEmail()); + api.setTechnicalOwner(publisherAPI.getTechnicalOwner()); + api.setTechnicalOwnerEmail(publisherAPI.getTechnicalOwnerEmail()); + api.setMonetizationEnabled(publisherAPI.getMonetizationStatus()); + api.setAdvertiseOnly(publisherAPI.getAdvertiseOnly()); + api.setRating(APIUtil.getAverageRating(publisherAPI.getId())); + api.setDescription(publisherAPI.getDescription()); + api.setType(publisherAPI.getTransportType()); apiSet.add(api); } else if ("APIProduct".equals(item.getType())) { DevPortalSearchContent devAPIProduct = (DevPortalSearchContent) item; @@ -4232,10 +4249,11 @@ public Map searchPaginatedContent(String searchQuery, String org compoundResult.addAll(apiSet); compoundResult.addAll(docMap.entrySet()); compoundResult.addAll(apiProductSet); - compoundResult.sort(new ContentSearchResultNameComparator()); + compoundResult.addAll(defSearchList); + compoundResult.sort(new SimpleContentSearchResultNameComparator()); result.put("length", sResults.getTotalCount()); } else { - result.put("length", compoundResult.size()); + result.put("length", 0); } } catch (APIPersistenceException e) { throw new APIManagementException("Error while searching content ", e); diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIManagerConfiguration.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIManagerConfiguration.java index 1923ad13344a..be0efa53a4f2 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIManagerConfiguration.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/APIManagerConfiguration.java @@ -1233,6 +1233,11 @@ private void setThrottleProperties(OMElement element) { if (enablePolicyDeployElement != null) { throttleProperties.setEnablePolicyDeployment(Boolean.parseBoolean(enablePolicyDeployElement.getText())); } + OMElement enablePolicyRecreateElement = throttleConfigurationElement + .getFirstChildWithName(new QName(APIConstants.AdvancedThrottleConstants.ENABLE_POLICY_RECREATE)); + if (enablePolicyRecreateElement != null) { + throttleProperties.setEnablePolicyRecreate(Boolean.parseBoolean(enablePolicyRecreateElement.getText())); + } // Check subscription spike arrest enable OMElement enabledSubscriptionLevelSpikeArrestElement = throttleConfigurationElement .getFirstChildWithName(new QName(APIConstants.AdvancedThrottleConstants @@ -1497,6 +1502,13 @@ private void setThrottleProperties(OMElement element) { defaultThrottleTierLimits.put(APIConstants.DEFAULT_SUB_POLICY_UNAUTHENTICATED, Long.parseLong(unauthenticatedTierElement.getText())); } + + OMElement subscriptionlessTierElement = subscriptionPolicyLimits.getFirstChildWithName(new + QName(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS)); + if (subscriptionlessTierElement != null) { + defaultThrottleTierLimits.put(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS, + Long.parseLong(subscriptionlessTierElement.getText())); + } } OMElement applicationPolicyLimits = defaultTierLimits 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 38575c2ee22e..c0292daa29cd 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 @@ -56,6 +56,7 @@ import org.wso2.carbon.apimgt.api.dto.UserApplicationAPIUsage; import org.wso2.carbon.apimgt.api.model.AIEndpointConfiguration; import org.wso2.carbon.apimgt.api.model.API; +import org.wso2.carbon.apimgt.api.model.APIDefinitionContentSearchResult; import org.wso2.carbon.apimgt.api.model.APIIdentifier; import org.wso2.carbon.apimgt.api.model.APIInfo; import org.wso2.carbon.apimgt.api.model.APIProduct; @@ -166,6 +167,7 @@ import org.wso2.carbon.apimgt.impl.utils.APIVersionStringComparator; import org.wso2.carbon.apimgt.impl.utils.ContentSearchResultNameComparator; import org.wso2.carbon.apimgt.impl.utils.LifeCycleUtils; +import org.wso2.carbon.apimgt.impl.utils.SimpleContentSearchResultNameComparator; import org.wso2.carbon.apimgt.impl.workflow.APIStateWorkflowDTO; import org.wso2.carbon.apimgt.impl.workflow.WorkflowConstants; import org.wso2.carbon.apimgt.impl.workflow.WorkflowException; @@ -173,6 +175,7 @@ import org.wso2.carbon.apimgt.impl.workflow.WorkflowExecutorFactory; import org.wso2.carbon.apimgt.impl.workflow.WorkflowStatus; import org.wso2.carbon.apimgt.impl.wsdl.WSDLProcessor; +import org.wso2.carbon.apimgt.persistence.dto.APIDefSearchContent; import org.wso2.carbon.apimgt.persistence.dto.DocumentContent; import org.wso2.carbon.apimgt.persistence.dto.DocumentSearchContent; import org.wso2.carbon.apimgt.persistence.dto.DocumentSearchResult; @@ -2162,8 +2165,10 @@ public API createNewAPIVersion(String existingApiId, String newVersion, Boolean ExceptionCodes.from(ExceptionCodes.API_NOT_FOUND, existingApiId)); } if (newVersion.equals(existingAPI.getId().getVersion())) { - throw new APIMgtResourceAlreadyExistsException( - "Version " + newVersion + " exists for api " + existingAPI.getId().getApiName()); + String errorMessage = "Version " + newVersion + " exists for api " + existingAPI.getId().getApiName(); + throw new APIMgtResourceAlreadyExistsException(errorMessage, + ExceptionCodes.from(ExceptionCodes.API_VERSION_ALREADY_EXISTS, newVersion, + existingAPI.getId().getApiName())); } if (APIUtil.isSequenceDefined(existingAPI.getInSequence()) || APIUtil.isSequenceDefined(existingAPI.getOutSequence()) || APIUtil.isSequenceDefined(existingAPI.getFaultSequence())) { @@ -3232,6 +3237,7 @@ public void updateAPIProductSwagger(String productId, Map checklist) throws APIManagementException{ APIStateChangeResponse response = new APIStateChangeResponse(); + String uuid = null; try { PrivilegedCarbonContext.startTenantFlow(); PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(this.username); @@ -3244,7 +3250,6 @@ public APIStateChangeResponse changeLifeCycleStatus(String orgId, ApiTypeWrapper String apiType; String apiVersion; String currentStatus; - String uuid; int apiOrApiProductId; boolean isApiProduct = apiTypeWrapper.isAPIProduct(); String workflowType; @@ -3309,7 +3314,8 @@ public APIStateChangeResponse changeLifeCycleStatus(String orgId, ApiTypeWrapper APIConstants.AuditLogConstants.LIFECYCLE_CHANGED, this.username); } } catch (APIPersistenceException e) { - handleException("Error while accessing persistence layer", e); + throw new APIManagementException("Error while accessing persistence layer", e, + ExceptionCodes.from(ExceptionCodes.ERROR_CHANGING_REGISTRY_LIFECYCLE_STATE, uuid)); } finally { PrivilegedCarbonContext.endTenantFlow(); } @@ -4544,9 +4550,10 @@ private static void validateAPIProductContextTemplate(APIProduct product) throws //Validate if the API Product has an unsupported context before executing the query String invalidContext = "/" + APIConstants.VERSION_PLACEHOLDER; if (invalidContext.equals(contextTemplate)) { - throw new APIManagementException( - "Cannot add API Product : " + product.getId() + " with unsupported context : " - + contextTemplate); + String errorMessage = "Cannot add API Product : " + product.getId() + " with unsupported context : " + + contextTemplate; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.UNSUPPORTED_CONTEXT, contextTemplate)); } } @@ -4714,9 +4721,13 @@ public Map> updateAPIProduct(APIProduct product) uriTemplate.setId(templateMap.get(key).getId()); } else { - throw new APIManagementException("API with id " + apiProductResource.getApiId() + String errorMessage = "API with id " + apiProductResource.getApiId() + " does not have a resource " + uriTemplate.getUriTemplate() - + " with http method " + uriTemplate.getHTTPVerb()); + + " with http method " + uriTemplate.getHTTPVerb(); + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.NO_CORRESPONDING_RESOURCE_FOUND_IN_API, + apiProductResource.getApiId(), uriTemplate.getUriTemplate(), + uriTemplate.getHTTPVerb())); } } } @@ -4741,7 +4752,9 @@ public Map> updateAPIProduct(APIProduct product) JSONObject jsonObj = (JSONObject) parser.parse(gson.toJson(newMonetizationProperties)); product.setMonetizationProperties(jsonObj); } catch (ParseException e) { - throw new APIManagementException("Error when parsing monetization properties ", e); + String errorMessage = "Error when parsing monetization properties "; + throw new APIManagementException(errorMessage, e, + ExceptionCodes.ERROR_PARSING_MONETIZATION_PROPERTIES); } } } @@ -4817,18 +4830,24 @@ private void validateApiLifeCycleForApiProducts(API api) throws APIManagementExc private void validateApiProductInfo(APIProduct product) throws APIManagementException { String apiName = product.getId().getName(); if (apiName == null) { - handleException("API Name is required."); + throw new APIManagementException("API Name is required.", ExceptionCodes.API_NAME_CANNOT_BE_NULL); } else if (containsIllegals(apiName)) { - handleException("API Name contains one or more illegal characters " + - "( " + APIConstants.REGEX_ILLEGAL_CHARACTERS_FOR_API_METADATA + " )"); + String errorMessage = "API Name contains one or more illegal characters ( " + + APIConstants.REGEX_ILLEGAL_CHARACTERS_FOR_API_METADATA + " )"; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.API_NAME_ILLEGAL_CHARACTERS, apiName, + APIConstants.REGEX_ILLEGAL_CHARACTERS_FOR_API_METADATA)); } String apiVersion = product.getId().getVersion(); if (apiVersion == null) { - handleException("API Version is required."); + throw new APIManagementException("API Version is required.", ExceptionCodes.API_VERSION_CANNOT_BE_NULL); } else if (containsIllegals(apiVersion)) { - handleException("API Version contains one or more illegal characters " + - "( " + APIConstants.REGEX_ILLEGAL_CHARACTERS_FOR_API_METADATA + " )"); + String errorMessage = "API Version contains one or more illegal characters ( " + + APIConstants.REGEX_ILLEGAL_CHARACTERS_FOR_API_METADATA + " )"; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.API_VERSION_ILLEGAL_CHARACTERS, apiVersion, + APIConstants.REGEX_ILLEGAL_CHARACTERS_FOR_API_METADATA)); } if (!hasValidLength(apiName, APIConstants.MAX_LENGTH_API_NAME) @@ -5336,6 +5355,12 @@ public String getSecuritySchemeOfAPI(String uuid, String organization) throws AP } } + @Override + public boolean isSubscriptionValidationDisabled(String uuid) throws APIManagementException { + String status = apiMgtDAO.getSubscriptionValidationStatus(uuid); + return !"ENABLED".equalsIgnoreCase(status); + } + @Override public API getAPIbyUUID(String uuid, String organization) throws APIManagementException { Organization org = new Organization(organization); @@ -5375,13 +5400,17 @@ public API getAPIbyUUID(String uuid, String organization) throws APIManagementEx throw new APIMgtResourceNotFoundException(msg); } } catch (APIPersistenceException e) { - throw new APIManagementException("Failed to get API", e); + throw new APIManagementException("Failed to get API", e, + ExceptionCodes.from(ExceptionCodes.ERROR_RETRIEVING_API, uuid)); } catch (OASPersistenceException e) { - throw new APIManagementException("Error while retrieving the OAS definition", e); + throw new APIManagementException("Error while retrieving the OAS definition", e, + ExceptionCodes.from(ExceptionCodes.OPENAPI_RETRIEVAL_ERROR, uuid)); } catch (ParseException e) { - throw new APIManagementException("Error while parsing the OAS definition", e); + throw new APIManagementException("Error while parsing the OAS definition", e, + ExceptionCodes.from(ExceptionCodes.OPENAPI_PARSE_EXCEPTION, uuid)); } catch (AsyncSpecPersistenceException e) { - throw new APIManagementException("Error while retrieving the Async API definition", e); + throw new APIManagementException("Error while retrieving the Async API definition", e, + ExceptionCodes.from(ExceptionCodes.ASYNCAPI_RETRIEVAL_ERROR, uuid)); } } @@ -5704,7 +5733,7 @@ public API getLightweightAPIByUUID(String uuid, String organization) throws APIM } } catch (APIPersistenceException e) { String msg = "Failed to get API with uuid " + uuid; - throw new APIManagementException(msg, e); + throw new APIManagementException(msg, e, ExceptionCodes.from(ExceptionCodes.ERROR_RETRIEVING_API, uuid)); } } @@ -5781,6 +5810,7 @@ public Map searchPaginatedContent(String searchQuery, String org Map result = new HashMap(); SortedSet apiSet = new TreeSet(new APINameComparator()); SortedSet apiProductSet = new TreeSet(new APIProductNameComparator()); + List defSearchList = new ArrayList<>(); String userame = userNameWithoutChange; Organization org = new Organization(organization); @@ -5849,14 +5879,28 @@ public Map searchPaginatedContent(String searchQuery, String org api.setUuid(docItem.getApiUUID()); productDocMap.put(doc, api); } + } else if (item instanceof APIDefSearchContent) { + APIDefSearchContent definitionItem = (APIDefSearchContent) item; + APIDefinitionContentSearchResult apiDefSearchResult = new APIDefinitionContentSearchResult(); + apiDefSearchResult.setId(definitionItem.getId()); + apiDefSearchResult.setName(definitionItem.getName()); + apiDefSearchResult.setApiUuid(definitionItem.getApiUUID()); + apiDefSearchResult.setApiName(definitionItem.getApiName()); + apiDefSearchResult.setApiContext(definitionItem.getApiContext()); + apiDefSearchResult.setApiProvider(definitionItem.getApiProvider()); + apiDefSearchResult.setApiVersion(definitionItem.getApiVersion()); + apiDefSearchResult.setApiType(definitionItem.getApiType()); + apiDefSearchResult.setAssociatedType(definitionItem.getAssociatedType()); //API or API product + defSearchList.add(apiDefSearchResult); } } compoundResult.addAll(apiSet); compoundResult.addAll(apiProductSet); compoundResult.addAll(docMap.entrySet()); compoundResult.addAll(productDocMap.entrySet()); - compoundResult.sort(new ContentSearchResultNameComparator()); - result.put("length", results.getTotalCount() ); + compoundResult.addAll(defSearchList); + compoundResult.sort(new SimpleContentSearchResultNameComparator()); + result.put("length", results.getTotalCount()); } else { result.put("length", compoundResult.size() ); } @@ -5928,8 +5972,9 @@ protected void checkAccessControlPermission(String userNameWithTenantDomain, Str return; } } - - throw new APIManagementException(APIConstants.UN_AUTHORIZED_ERROR_MESSAGE + " view or modify the api"); + String errorMessage = APIConstants.UN_AUTHORIZED_ERROR_MESSAGE + " view or modify the api"; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.UN_AUTHORIZED_TO_VIEW_MODIFY_API, username)); } } 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 421584e3f931..4b7b20a2fcf0 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 @@ -5591,8 +5591,10 @@ public int addAPI(API api, int tenantId, String organization) throws APIManageme prepStmt.setString(12, organization); prepStmt.setString(13, api.getGatewayVendor()); prepStmt.setString(14, api.getVersionTimestamp()); - prepStmt.setInt(15, api.isEgress()); - prepStmt.setString(16, api.getSubtype()); + prepStmt.setString(15, + APIUtil.setSubscriptionValidationStatusBeforeInsert(api.getAvailableTiers())); + prepStmt.setInt(16, api.isEgress()); + prepStmt.setString(17, api.getSubtype()); prepStmt.execute(); rs = prepStmt.getGeneratedKeys(); @@ -7134,7 +7136,9 @@ public void updateAPI(API api, String username) throws APIManagementException { prepStmt.setString(6, api.getApiLevelPolicy()); prepStmt.setString(7, api.getType()); prepStmt.setString(8, api.getGatewayVendor()); - prepStmt.setString(9, api.getUuid()); + prepStmt.setString(9, + APIUtil.setSubscriptionValidationStatusBeforeInsert(api.getAvailableTiers())); + prepStmt.setString(10, api.getUuid()); prepStmt.execute(); if (api.isDefaultVersion() ^ api.getId().getVersion().equals(previousDefaultVersion)) { //A change has @@ -15375,6 +15379,8 @@ public void addAPIProduct(APIProduct apiProduct, String organization) throws API prepStmtAddAPIProduct.setString(12, organization); prepStmtAddAPIProduct.setString(13, apiProduct.getGatewayVendor()); prepStmtAddAPIProduct.setString(14, apiProduct.getVersionTimestamp()); + prepStmtAddAPIProduct.setString(15, + APIUtil.setSubscriptionValidationStatusBeforeInsert(apiProduct.getAvailableTiers())); prepStmtAddAPIProduct.setInt(15, apiProduct.isEgress()); prepStmtAddAPIProduct.execute(); @@ -15776,10 +15782,12 @@ public void updateAPIProduct(APIProduct product, String username) throws APIMana ps.setString(2, username); ps.setTimestamp(3, new Timestamp(System.currentTimeMillis())); ps.setString(4, product.getGatewayVendor()); + ps.setString(5, + APIUtil.setSubscriptionValidationStatusBeforeInsert(product.getAvailableTiers())); APIProductIdentifier identifier = product.getId(); - ps.setString(5, identifier.getName()); - ps.setString(6, APIUtil.replaceEmailDomainBack(identifier.getProviderName())); - ps.setString(7, identifier.getVersion()); + ps.setString(6, identifier.getName()); + ps.setString(7, APIUtil.replaceEmailDomainBack(identifier.getProviderName())); + ps.setString(8, identifier.getVersion()); ps.executeUpdate(); int productId = getAPIID(product.getUuid(), conn); @@ -16229,6 +16237,24 @@ public BotDetectionData getBotDetectionAlertSubscription(String field, String va return alertSubscription; } + public String getSubscriptionValidationStatus(String apiUuid) throws APIManagementException { + String status = null; + String query = SQLConstants.GET_SUBSCRIPTION_VALIDATION_STATUS_SQL; + + try (Connection connection = APIMgtDBUtil.getConnection(); + PreparedStatement ps = connection.prepareStatement(query)) { + ps.setString(1, apiUuid); + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + status = rs.getString("SUB_VALIDATION"); + } + } + } catch (SQLException e) { + handleException("Error while retrieving subscription validation status for API: " + apiUuid, e); + } + return status; + } + /** * Persist revoked jwt signatures to database. * diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/SubscriptionValidationDAO.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/SubscriptionValidationDAO.java index 5094cd699d25..f8e50ba52464 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/SubscriptionValidationDAO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/SubscriptionValidationDAO.java @@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.TokenBaseThrottlingCountHolder; +import org.wso2.carbon.apimgt.api.SubscriptionAlreadyExistingException; import org.wso2.carbon.apimgt.api.dto.ConditionDTO; import org.wso2.carbon.apimgt.api.dto.ConditionGroupDTO; import org.wso2.carbon.apimgt.api.model.AIConfiguration; @@ -62,10 +63,13 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.Hashtable; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import static org.wso2.carbon.apimgt.impl.APIConstants.POLICY_ENABLED_FOR_ANALYTICS; @@ -1610,4 +1614,94 @@ public List getAllApisByLabel(String gatewayLabel, Boolean expand) { } return apiList; } + + public String getApplicationSubscriber(String uuid) throws APIManagementException { + String subscriber = ""; + String query = SQLConstants.GET_APPLICATION_BY_UUID_SQL; + try (Connection connection = APIMgtDBUtil.getConnection()) { + try (PreparedStatement ps = connection.prepareStatement(query)) { + ps.setString(1, uuid); + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + subscriber = rs.getString("USER_ID"); + } + } + } + } catch (SQLException e) { + throw new APIManagementException("Error while getting subscriber info", e); + } + return subscriber; + } + + public Map subscribeToAPI(int apiId, int appId, String tier, String subscriber) + throws APIManagementException { + Map subscriptionDetails = new HashMap<>(); + int subscriptionId = -1; + String subscriptionUUID = UUID.randomUUID().toString(); + + String checkDuplicateQuery = SQLConstants.CHECK_EXISTING_SUBSCRIPTION_API_SQL; + String sqlQuery = SQLConstants.ADD_SUBSCRIPTION_SQL; + + try (Connection connection = APIMgtDBUtil.getConnection()) { + connection.setAutoCommit(false); + try (PreparedStatement ps = connection.prepareStatement(checkDuplicateQuery)) { + ps.setInt(1, apiId); + ps.setInt(2, appId); + try (ResultSet resultSet = ps.executeQuery()) { + //If the subscription already exists + if (resultSet.next()) { + String subStatus = resultSet.getString("SUB_STATUS"); + String subCreationStatus = resultSet.getString("SUBS_CREATE_STATE"); + if ((APIConstants.SubscriptionStatus.UNBLOCKED.equals(subStatus) || + APIConstants.SubscriptionStatus.ON_HOLD.equals(subStatus) || + APIConstants.SubscriptionStatus.REJECTED.equals(subStatus)) && + APIConstants.SubscriptionCreatedStatus.SUBSCRIBE.equals(subCreationStatus)) { + + throw new SubscriptionAlreadyExistingException( + String.format("Subscription already exists for API/API Prouct %s in Application %s", + apiId, appId)); + } + } + } + } + + String subscriptionIDColumn = "SUBSCRIPTION_ID"; + if (connection.getMetaData().getDriverName().contains("PostgreSQL")) { + subscriptionIDColumn = "subscription_id"; + } + try (PreparedStatement preparedStForInsert = connection.prepareStatement(sqlQuery, + new String[]{subscriptionIDColumn})) { + preparedStForInsert.setString(1, tier); + preparedStForInsert.setString(10, tier); + preparedStForInsert.setInt(2, apiId); + preparedStForInsert.setInt(3, appId); + preparedStForInsert.setString(4, APIConstants.SubscriptionStatus.UNBLOCKED); + preparedStForInsert.setString(5, APIConstants.SubscriptionCreatedStatus.SUBSCRIBE); + preparedStForInsert.setString(6, subscriber); + + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + preparedStForInsert.setTimestamp(7, timestamp); + preparedStForInsert.setTimestamp(8, timestamp); + preparedStForInsert.setString(9, subscriptionUUID); + + preparedStForInsert.executeUpdate(); + try (ResultSet rs = preparedStForInsert.getGeneratedKeys()) { + while (rs.next()) { + subscriptionId = Integer.parseInt(rs.getString(1)); + } + connection.commit(); + } catch (SQLException e) { + connection.rollback(); + throw new APIManagementException("Error while adding subscription for API/API Product " + apiId + + " in Application " + appId, e); + } + } + } catch (SQLException e) { + throw new APIManagementException("Error while adding subscription for API/API Product " + apiId + + " in Application " + appId, e); + } + subscriptionDetails.put("id", subscriptionId); + subscriptionDetails.put("uuid", subscriptionUUID); + return subscriptionDetails; + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/constants/SQLConstants.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/constants/SQLConstants.java index c695042aecbb..b84beea2b21e 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/constants/SQLConstants.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/dao/constants/SQLConstants.java @@ -459,6 +459,7 @@ public class SQLConstants { " WHERE SUBS.SUBS_CREATE_STATE ='" + APIConstants.SubscriptionCreatedStatus.SUBSCRIBE + "'" + " AND SUBS.APPLICATION_ID = APP.APPLICATION_ID" + " AND API.API_ID = SUBS.API_ID" + + " AND API.SUB_VALIDATION = 'ENABLED'" + " AND APP.APPLICATION_ID = ?" + " AND API.ORGANIZATION = ?"; @@ -964,6 +965,9 @@ public class SQLConstants { " ORDER BY " + " APP.NAME"; + public static final String GET_SUBSCRIPTION_VALIDATION_STATUS_SQL = + " SELECT SUB_VALIDATION FROM AM_API WHERE API_UUID = ?"; + public static final String GET_API_RATING_SQL = "SELECT RATING FROM AM_API_RATINGS WHERE API_ID= ? AND SUBSCRIBER_ID=? "; @@ -1471,8 +1475,8 @@ public class SQLConstants { public static final String ADD_API_SQL = " INSERT INTO AM_API (API_PROVIDER,API_NAME,API_VERSION,CONTEXT,CONTEXT_TEMPLATE,CREATED_BY," + "CREATED_TIME,API_TIER,API_TYPE,API_UUID,STATUS,ORGANIZATION,GATEWAY_VENDOR,VERSION_COMPARABLE," + - "IS_EGRESS, API_SUBTYPE)" + - " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; + "SUB_VALIDATION, IS_EGRESS, API_SUBTYPE)" + + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; public static final String GET_GATEWAY_TYPE_SQL_BY_UUID = "SELECT API.GATEWAY_TYPE FROM AM_API API WHERE API.API_UUID = ?"; @@ -1707,7 +1711,8 @@ public class SQLConstants { " UPDATED_TIME = ?, " + " API_TIER = ?, " + " API_TYPE = ?, " + - " GATEWAY_VENDOR = ? " + + " GATEWAY_VENDOR = ?, " + + " SUB_VALIDATION = ? " + " WHERE " + " API_UUID = ? "; @@ -2810,7 +2815,8 @@ public class SQLConstants { " API_TIER=?," + " UPDATED_BY=?," + " UPDATED_TIME=?," + - " GATEWAY_VENDOR=?" + + " GATEWAY_VENDOR=?," + + " SUB_VALIDATION=?" + " WHERE" + " API_NAME=? AND API_PROVIDER=? AND API_VERSION=? AND API_TYPE='" + APIConstants.API_PRODUCT +"'"; @@ -2829,7 +2835,7 @@ public class SQLConstants { public static final String ADD_API_PRODUCT = "INSERT INTO " + "AM_API(API_PROVIDER, API_NAME, API_VERSION, " + "CONTEXT, CONTEXT_TEMPLATE, API_TIER, CREATED_BY, CREATED_TIME, API_TYPE, API_UUID, STATUS, " + - "ORGANIZATION, GATEWAY_VENDOR, VERSION_COMPARABLE, IS_EGRESS) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?, ?)"; + "ORGANIZATION, GATEWAY_VENDOR, VERSION_COMPARABLE, SUB_VALIDATION, IS_EGRESS) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; public static final String GET_RESOURCES_OF_PRODUCT = "SELECT API_UM.URL_MAPPING_ID, API_UM.URL_PATTERN, API_UM.HTTP_METHOD, API_UM.AUTH_SCHEME, " + diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/definitions/OASParserUtil.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/definitions/OASParserUtil.java index 83f7b3471dc9..dfbef31f08b8 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/definitions/OASParserUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/definitions/OASParserUtil.java @@ -274,7 +274,8 @@ public static String updateAPIProductSwaggerOperations(Map defaultThrottleTierLimits = new HashMap(); + private boolean enablePolicyRecreate; private TrafficManager trafficManager; public boolean isEnabledSubscriptionLevelSpikeArrest() { return enabledSubscriptionLevelSpikeArrest; @@ -170,6 +171,14 @@ public void setDefaultThrottleTierLimits(Map defaultThrottleTierLi this.defaultThrottleTierLimits = defaultThrottleTierLimits; } + public boolean isEnablePolicyRecreate() { + return enablePolicyRecreate; + } + + public void setEnablePolicyRecreate(boolean enablePolicyRecreate) { + this.enablePolicyRecreate = enablePolicyRecreate; + } + public static class DataPublisher { private String type = "Binary"; private String receiverUrlGroup = "tcp://localhost:9611"; diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/indexing/indexer/GraphQLAPIDefinitionIndexer.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/indexing/indexer/GraphQLAPIDefinitionIndexer.java new file mode 100644 index 000000000000..784fac2f56a3 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/indexing/indexer/GraphQLAPIDefinitionIndexer.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. 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.apimgt.impl.indexing.indexer; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.solr.common.SolrException; +import org.wso2.carbon.apimgt.api.APIManagementException; +import org.wso2.carbon.apimgt.impl.APIConstants; +import org.wso2.carbon.apimgt.impl.utils.IndexerUtil; +import org.wso2.carbon.governance.api.util.GovernanceUtils; +import org.wso2.carbon.registry.core.Registry; +import org.wso2.carbon.registry.core.RegistryConstants; +import org.wso2.carbon.registry.core.Resource; +import org.wso2.carbon.registry.core.exceptions.RegistryException; +import org.wso2.carbon.registry.core.utils.RegistryUtils; +import org.wso2.carbon.registry.indexing.AsyncIndexer; +import org.wso2.carbon.registry.indexing.IndexingManager; +import org.wso2.carbon.registry.indexing.solr.IndexDocument; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * This is the graphql definition indexer introduced to .graphgl definition artifacts for unified content search. + */ +public class GraphQLAPIDefinitionIndexer extends PlainTextIndexer { + public static final Log log = LogFactory.getLog(GraphQLAPIDefinitionIndexer.class); + + @Override + public IndexDocument getIndexedDocument(AsyncIndexer.File2Index fileData) throws SolrException, RegistryException { + Registry registry = GovernanceUtils + .getGovernanceSystemRegistry(IndexingManager.getInstance().getRegistry(fileData.tenantId)); + String definitionResourcePath = + fileData.path.substring(RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH.length()); + + // If the file is not a graphql definition file in provider path do not index + if (!definitionResourcePath.contains(APIConstants.APPLICATION_DATA_RESOURCE_URL_PREFIX) + || !definitionResourcePath.contains(APIConstants.GRAPHQL_SCHEMA_FILE_EXTENSION)) { + return null; + } + + // Extract only required info (types) from graphql definition to index + String schemaString = RegistryUtils.decodeBytes(fileData.data); + String definitionString = IndexerUtil.getTypesFromGraphQLSchemaString(schemaString); + fileData.data = definitionString.getBytes(); + + IndexDocument indexDocument = super.getIndexedDocument(fileData); + IndexDocument newIndexDocument = indexDocument; + + if (log.isDebugEnabled()) { + log.debug("Executing GraphQL file indexer for resource at " + definitionResourcePath); + } + + Resource definitionResource = null; + Map> fields = indexDocument.getFields(); + + if (registry.resourceExists(definitionResourcePath)) { + definitionResource = registry.get(definitionResourcePath); + } + + if (definitionResource != null) { + try { + IndexerUtil.fetchRequiredDetailsFromAssociatedAPI(registry, definitionResource, fields); + newIndexDocument = + new IndexDocument(fileData.path, null, + indexDocument.getRawContent(), indexDocument.getTenantId()); + fields.put(APIConstants.DOCUMENT_INDEXER_INDICATOR, Arrays.asList("true")); + newIndexDocument.setFields(fields); + } catch (APIManagementException e) { + //error occurred while fetching details from API, but continuing indexing + log.error("Error while updating indexed document.", e); + } + } + + return newIndexDocument; + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/indexing/indexer/RESTAsyncAPIDefinitionIndexer.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/indexing/indexer/RESTAsyncAPIDefinitionIndexer.java new file mode 100644 index 000000000000..4208fb6a4c6b --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/indexing/indexer/RESTAsyncAPIDefinitionIndexer.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. 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.apimgt.impl.indexing.indexer; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.solr.common.SolrException; +import org.wso2.carbon.apimgt.api.APIManagementException; +import org.wso2.carbon.apimgt.impl.APIConstants; +import org.wso2.carbon.apimgt.impl.utils.IndexerUtil; +import org.wso2.carbon.governance.api.util.GovernanceUtils; +import org.wso2.carbon.registry.core.Registry; +import org.wso2.carbon.registry.core.RegistryConstants; +import org.wso2.carbon.registry.core.Resource; +import org.wso2.carbon.registry.core.exceptions.RegistryException; +import org.wso2.carbon.registry.core.utils.RegistryUtils; +import org.wso2.carbon.registry.indexing.AsyncIndexer.File2Index; +import org.wso2.carbon.registry.indexing.IndexingManager; +import org.wso2.carbon.registry.indexing.solr.IndexDocument; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * This is indexer introduced to index swagger,async api artifacts for unified content search. + */ +public class RESTAsyncAPIDefinitionIndexer extends PlainTextIndexer { + public static final Log log = LogFactory.getLog(RESTAsyncAPIDefinitionIndexer.class); + + @Override + public IndexDocument getIndexedDocument(File2Index fileData) throws SolrException, RegistryException { + Registry registry = GovernanceUtils + .getGovernanceSystemRegistry(IndexingManager.getInstance().getRegistry(fileData.tenantId)); + String definitionResourcePath = fileData.path + .substring(RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH.length()); + + // If the file is not a def file in provider path, do not index + if (!definitionResourcePath.contains(APIConstants.APPLICATION_DATA_RESOURCE_URL_PREFIX) + || !(definitionResourcePath.contains(APIConstants.OPENAPI_MASTER_JSON) + || definitionResourcePath.contains(APIConstants.API_ASYNCAPI_DEFINITION_RESOURCE_NAME))) { + return null; + } + + // Filter out only values from the swagger, async json files for indexing + String jsonAsString = RegistryUtils.decodeBytes(fileData.data); + String valuesString = IndexerUtil.getValuesFromJsonString(jsonAsString); + fileData.data = valuesString.getBytes(); + fileData.mediaType = "application/json"; + + IndexDocument indexDocument = super.getIndexedDocument(fileData); + IndexDocument newIndexDocument = indexDocument; + + if (log.isDebugEnabled()) { + log.debug("Executing json api definition indexer for resource at " + definitionResourcePath); + } + + Resource resource = null; + Map> fields = indexDocument.getFields(); + + if (registry.resourceExists(definitionResourcePath)) { + resource = registry.get(definitionResourcePath); + } + + if (resource != null) { + try { + IndexerUtil.fetchRequiredDetailsFromAssociatedAPI(registry, resource, fields); + newIndexDocument = + new IndexDocument(fileData.path, null, + indexDocument.getRawContent(), indexDocument.getTenantId()); + fields.put(APIConstants.DOCUMENT_INDEXER_INDICATOR, Arrays.asList("true")); + newIndexDocument.setFields(fields); + } catch (APIManagementException e) { + //error occurred while fetching details from API, but continuing indexing + log.error("Error while updating indexed document.", e); + } + } + + return newIndexDocument; + } + +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/indexing/indexer/SOAPAPIDefinitionIndexer.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/indexing/indexer/SOAPAPIDefinitionIndexer.java new file mode 100644 index 000000000000..343f356eacba --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/indexing/indexer/SOAPAPIDefinitionIndexer.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. 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.apimgt.impl.indexing.indexer; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.solr.common.SolrException; +import org.wso2.carbon.apimgt.api.APIManagementException; +import org.wso2.carbon.apimgt.impl.APIConstants; +import org.wso2.carbon.apimgt.impl.utils.IndexerUtil; +import org.wso2.carbon.governance.api.util.GovernanceUtils; +import org.wso2.carbon.registry.core.Registry; +import org.wso2.carbon.registry.core.RegistryConstants; +import org.wso2.carbon.registry.core.Resource; +import org.wso2.carbon.registry.core.exceptions.RegistryException; +import org.wso2.carbon.registry.indexing.AsyncIndexer; +import org.wso2.carbon.registry.indexing.IndexingManager; +import org.wso2.carbon.registry.indexing.solr.IndexDocument; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * This indexer is introduced to index .wsdl files for unified content search. + */ +public class SOAPAPIDefinitionIndexer extends PlainTextIndexer { + + public static final Log log = LogFactory.getLog(SOAPAPIDefinitionIndexer.class); + + @Override + public IndexDocument getIndexedDocument(AsyncIndexer.File2Index fileData) throws SolrException, RegistryException { + Registry registry = GovernanceUtils + .getGovernanceSystemRegistry(IndexingManager.getInstance().getRegistry(fileData.tenantId)); + String definitionResourcePath = + fileData.path.substring(RegistryConstants.GOVERNANCE_REGISTRY_BASE_PATH.length()); + + + // If the file is not a wsdl definition file in provider path do not index + if (!definitionResourcePath.contains(APIConstants.APPLICATION_DATA_RESOURCE_URL_PREFIX) + || !definitionResourcePath.contains(APIConstants.WSDL_EXTENSION)) { + return null; + } + + // Extract only required data before indexing + String contentString = IndexerUtil.getContentFromXMLData(fileData.data); + fileData.data = contentString.getBytes(); + + IndexDocument indexDocument = super.getIndexedDocument(fileData); + IndexDocument newIndexDocument = indexDocument; + + if (log.isDebugEnabled()) { + log.debug("Executing WSDL file indexer for resource at " + definitionResourcePath); + } + + Resource definitionResource = null; + Map> fields = indexDocument.getFields(); + + if (registry.resourceExists(definitionResourcePath)) { + definitionResource = registry.get(definitionResourcePath); + } + + if (definitionResource != null) { + try { + IndexerUtil.fetchRequiredDetailsFromAssociatedAPI(registry, definitionResource, fields); + newIndexDocument = + new IndexDocument(fileData.path, null, + indexDocument.getRawContent(), indexDocument.getTenantId()); + fields.put(APIConstants.DOCUMENT_INDEXER_INDICATOR, Arrays.asList("true")); + newIndexDocument.setFields(fields); + } catch (APIManagementException e) { + //error occurred while fetching details from API, but continuing indexing + log.error("Error while updating indexed document.", e); + } + } + + return newIndexDocument; + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java index ab764ab491c1..4af0ebda42c3 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java @@ -2814,16 +2814,19 @@ public static void validateCharacterLengthOfAPIParams(String apiName, String con throws APIManagementException { if (!hasValidLength(apiName, APIConstants.MAX_LENGTH_API_NAME)) { - throw new APIManagementException("API name exceeds allowed character length", - ExceptionCodes.LENGTH_EXCEEDS); + String errorMessage = "API name exceeds allowed character length"; + throw new APIManagementException(errorMessage, ExceptionCodes.from(ExceptionCodes.LENGTH_EXCEEDS_ERROR, + errorMessage + " of " + APIConstants.MAX_LENGTH_API_NAME)); } if (!hasValidLength(context, APIConstants.MAX_LENGTH_CONTEXT)) { - throw new APIManagementException("API context exceeds allowed character length", - ExceptionCodes.LENGTH_EXCEEDS); + String errorMessage = "API context exceeds allowed character length"; + throw new APIManagementException(errorMessage, ExceptionCodes.from(ExceptionCodes.LENGTH_EXCEEDS_ERROR, + errorMessage + " of " + APIConstants.MAX_LENGTH_CONTEXT)); } if (!hasValidLength(provider, APIConstants.MAX_LENGTH_PROVIDER)) { - throw new APIManagementException("API provider name exceeds allowed character length", - ExceptionCodes.LENGTH_EXCEEDS); + String errorMessage = "API provider name exceeds allowed character length"; + throw new APIManagementException(errorMessage, ExceptionCodes.from(ExceptionCodes.LENGTH_EXCEEDS_ERROR, + errorMessage + " of " + APIConstants.MAX_LENGTH_PROVIDER)); } } @@ -2866,13 +2869,15 @@ public static void validateAPIContext(String context, String apiName) throws API if (context == null || context.isEmpty()) { errorMsg = errorMsg + " For API " + apiName + ", context cannot be empty or null"; log.error(errorMsg); - throw new APIManagementException(errorMsg); + throw new APIManagementException(errorMsg, + ExceptionCodes.from(ExceptionCodes.API_CONTEXT_MALFORMED_EXCEPTION, errorMsg)); } if (context.endsWith("/")) { errorMsg = errorMsg + " For API " + apiName + ", context " + context + " cannot end with /"; log.error(errorMsg); - throw new APIManagementException(errorMsg); + throw new APIManagementException(errorMsg, + ExceptionCodes.from(ExceptionCodes.API_CONTEXT_MALFORMED_EXCEPTION, errorMsg)); } Matcher matcher = pattern.matcher(context); @@ -2885,15 +2890,17 @@ public static void validateAPIContext(String context, String apiName) throws API for (String param : split) { if (param != null && !APIConstants.VERSION_PLACEHOLDER.equals(param)) { if (param.contains(APIConstants.VERSION_PLACEHOLDER)) { - errorMsg = errorMsg + " For API " + apiName + - ", {version} cannot exist as a substring of a sub-context"; + errorMsg = errorMsg + " For API " + apiName + ", {version} cannot exist as a substring of a " + + "sub-context"; log.error(errorMsg); - throw new APIManagementException(errorMsg); + throw new APIManagementException(errorMsg, + ExceptionCodes.from(ExceptionCodes.API_CONTEXT_MALFORMED_EXCEPTION, errorMsg)); } else if (param.contains("{") || param.contains("}")) { - errorMsg = errorMsg + " For API " + apiName + - ", { or } cannot exist as a substring of a sub-context"; + errorMsg = errorMsg + " For API " + apiName + ", { or } cannot exist as a substring of a " + + "sub-context"; log.error(errorMsg); - throw new APIManagementException(errorMsg); + throw new APIManagementException(errorMsg, + ExceptionCodes.from(ExceptionCodes.API_CONTEXT_MALFORMED_EXCEPTION, errorMsg)); } } } @@ -2903,12 +2910,14 @@ public static void validateAPIContext(String context, String apiName) throws API if (!isBalanced) { errorMsg = errorMsg + " Unbalanced parenthesis cannot be used in context " + context + " for API " + apiName; - throw new APIManagementException(errorMsg); + throw new APIManagementException(errorMsg, + ExceptionCodes.from(ExceptionCodes.API_CONTEXT_MALFORMED_EXCEPTION, errorMsg)); } } else { - errorMsg = errorMsg + " Special characters cannot be used in context " + context + " for API "+ apiName; + errorMsg = errorMsg + " Special characters cannot be used in context " + context + " for API " + apiName; log.error(errorMsg); - throw new APIManagementException(errorMsg); + throw new APIManagementException(errorMsg, + ExceptionCodes.from(ExceptionCodes.API_CONTEXT_MALFORMED_EXCEPTION, errorMsg)); } } @@ -5320,6 +5329,22 @@ private static boolean isUnlimitedTierPaid(String tenantDomain) throws APIManage return false; } + public static boolean isSubscriptionValidationDisablingAllowed(String tenantDomain) throws APIManagementException { + APIManagerConfiguration config = ServiceReferenceHolder.getInstance().getAPIManagerConfigurationService() + .getAPIManagerConfiguration(); + boolean subValidationDisablingAllowedGlobal = Boolean.parseBoolean(config.getFirstProperty( + APIConstants.ALLOW_SUBSCRIPTION_VALIDATION_DISABLING)); + boolean subValidationDisablingAllowedTenant = false; + JSONObject apiTenantConfig = getTenantConfig(tenantDomain); + if (apiTenantConfig != null) { + Object value = apiTenantConfig.get(APIConstants.API_TENANT_CONF_ALLOW_SUBSCRIPTION_VALIDATION_DISABLING); + if (value != null) { + subValidationDisablingAllowedTenant = Boolean.parseBoolean(value.toString()); + } + } + return subValidationDisablingAllowedGlobal || subValidationDisablingAllowedTenant; + } + public static Map getTiers(String organization) throws APIManagementException { int requestedTenantId = getInternalOrganizationId(organization); @@ -6044,13 +6069,12 @@ private static boolean isDefaultQuotaPolicyContentAware(Policy policy) { public static void addDefaultTenantAdvancedThrottlePolicies(String tenantDomain, int tenantId) throws APIManagementException { ApiMgtDAO apiMgtDAO = ApiMgtDAO.getInstance(); + boolean recreate = ServiceReferenceHolder.getInstance().getAPIManagerConfigurationService().getAPIManagerConfiguration() + .getThrottleProperties().isEnablePolicyRecreate(); - /* Check if 'Unlimited' policy is available in AM_POLICY_APPLICATION table, to determine whether the default policies are loaded - into the database at least once. If yes, default policies won't be added to database again. */ - - if (apiMgtDAO.isPolicyExist(PolicyConstants.POLICY_LEVEL_APP, tenantId, APIConstants.DEFAULT_APP_POLICY_UNLIMITED)) { - log.debug( - "Default Throttling Policies are not written into the database again, as they were added once at initial server startup"); + if (!recreate) { + log.debug("Default Throttling Policies are not written into the database again, " + + "as they were added once at initial server startup"); return; } @@ -6130,13 +6154,19 @@ public static void addDefaultTenantAdvancedThrottlePolicies(String tenantDomain, defualtLimits.get(APIConstants.DEFAULT_SUB_POLICY_GOLD) : 5000; long unauthenticatedTierLimit = defualtLimits.containsKey(APIConstants.DEFAULT_APP_POLICY_FIFTY_REQ_PER_MIN) ? defualtLimits.get(APIConstants.DEFAULT_SUB_POLICY_UNAUTHENTICATED) : 500; + long subscriptionlessTierLimit = defualtLimits.containsKey(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS) ? + defualtLimits.get(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS) : 100000; + //Adding Subscription level policies - long[] requestCountSubPolicies = new long[]{goldTierLimit, silverTierLimit, bronzeTierLimit, unauthenticatedTierLimit, Integer.MAX_VALUE}; + long[] requestCountSubPolicies = new long[]{goldTierLimit, silverTierLimit, bronzeTierLimit, + unauthenticatedTierLimit, subscriptionlessTierLimit, Integer.MAX_VALUE}; String[] subPolicies = new String[]{APIConstants.DEFAULT_SUB_POLICY_GOLD, APIConstants.DEFAULT_SUB_POLICY_SILVER, - APIConstants.DEFAULT_SUB_POLICY_BRONZE, APIConstants.DEFAULT_SUB_POLICY_UNAUTHENTICATED, APIConstants.DEFAULT_SUB_POLICY_UNLIMITED}; + APIConstants.DEFAULT_SUB_POLICY_BRONZE, APIConstants.DEFAULT_SUB_POLICY_UNAUTHENTICATED, + APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS, APIConstants.DEFAULT_SUB_POLICY_UNLIMITED}; String[] subPolicyDecs = new String[]{ APIConstants.DEFAULT_SUB_POLICY_GOLD_DESC, APIConstants.DEFAULT_SUB_POLICY_SILVER_DESC, - APIConstants.DEFAULT_SUB_POLICY_BRONZE_DESC, APIConstants.DEFAULT_SUB_POLICY_UNAUTHENTICATED_DESC, APIConstants.DEFAULT_SUB_POLICY_UNLIMITED_DESC}; + APIConstants.DEFAULT_SUB_POLICY_BRONZE_DESC, APIConstants.DEFAULT_SUB_POLICY_UNAUTHENTICATED_DESC, + APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS_DESC, APIConstants.DEFAULT_SUB_POLICY_UNLIMITED_DESC}; for (int i = 0; i < subPolicies.length; i++) { policyName = subPolicies[i]; boolean needDeployment = false; @@ -6185,12 +6215,15 @@ public static void addDefaultTenantAdvancedThrottlePolicies(String tenantDomain, } //Adding Event based subscription level policies for async policies (WS & SSE) - long[] eventCountSubPolicyValues = new long[]{50000, 25000, 5000, Integer.MAX_VALUE}; - String[] eventCountSubPolicyNames = new String[]{APIConstants.DEFAULT_SUB_POLICY_ASYNC_GOLD, APIConstants.DEFAULT_SUB_POLICY_ASYNC_SILVER, - APIConstants.DEFAULT_SUB_POLICY_ASYNC_BRONZE, APIConstants.DEFAULT_SUB_POLICY_ASYNC_UNLIMITED}; + long[] eventCountSubPolicyValues = new long[]{50000, 25000, 5000, 10000, Integer.MAX_VALUE}; + String[] eventCountSubPolicyNames = new String[]{APIConstants.DEFAULT_SUB_POLICY_ASYNC_GOLD, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_SILVER, APIConstants.DEFAULT_SUB_POLICY_ASYNC_BRONZE, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_SUBSCRIPTIONLESS, APIConstants.DEFAULT_SUB_POLICY_ASYNC_UNLIMITED}; String[] eventCountSubPolicyDescriptions = new String[]{ APIConstants.DEFAULT_SUB_POLICY_ASYNC_GOLD_DESC, APIConstants.DEFAULT_SUB_POLICY_ASYNC_SILVER_DESC, - APIConstants.DEFAULT_SUB_POLICY_ASYNC_BRONZE_DESC, APIConstants.DEFAULT_SUB_POLICY_ASYNC_UNLIMITED_DESC}; + APIConstants.DEFAULT_SUB_POLICY_ASYNC_BRONZE_DESC, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_SUBSCRIPTIONLESS_DESC, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_UNLIMITED_DESC}; for (int i = 0; i < eventCountSubPolicyNames.length; i++) { policyName = eventCountSubPolicyNames[i]; @@ -8876,7 +8909,8 @@ public static Map setEndpointSecurityForAPIProduct(API } return endpointSecurityMap; } catch (ParseException e) { - throw new APIManagementException("Error while parsing Endpoint Config json", e); + String errorMessage = "Error while parsing Endpoint Config json"; + throw new APIManagementException(errorMessage, e, ExceptionCodes.ERROR_PARSING_ENDPOINT_CONFIG); } } @@ -10218,6 +10252,22 @@ public static void initializeVelocityContext(VelocityEngine velocityEngine){ velocityEngine.setProperty("runtime.conversion.handler", "none"); } + /** + * Get the subscription validation stats before inserting the API + * + * @param tiers Available business plans for the API + * @return true if the subscription validation is enabled + */ + public static String setSubscriptionValidationStatusBeforeInsert(Set tiers) { + if (tiers != null && tiers.size() == 1) { + Tier tier = tiers.iterator().next(); + if(tier.getName().contains(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS)) { + return "DISABLED"; + } + } + return "ENABLED"; + } + /** * Handles gateway vendor for APK before insert DB operations. * diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/IndexerUtil.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/IndexerUtil.java new file mode 100644 index 000000000000..d6aeced1f1e6 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/IndexerUtil.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. 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.apimgt.impl.utils; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONArray; +import org.json.JSONObject; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.wso2.carbon.apimgt.api.APIManagementException; +import org.wso2.carbon.apimgt.api.model.graphql.queryanalysis.GraphqlSchemaType; +import org.wso2.carbon.apimgt.impl.APIConstants; +import org.wso2.carbon.apimgt.impl.definitions.GraphQLSchemaDefinition; +import org.wso2.carbon.governance.api.generic.GenericArtifactManager; +import org.wso2.carbon.governance.api.generic.dataobjects.GenericArtifact; +import org.wso2.carbon.registry.core.Registry; +import org.wso2.carbon.registry.core.Resource; +import org.wso2.carbon.registry.core.exceptions.RegistryException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.ByteArrayInputStream; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Utility class for Indexers. + */ +public class IndexerUtil { + private static final Log log = LogFactory.getLog(IndexerUtil.class); + + /** + * Method to fetch API details for a given resource. + * + * @param registry Registry + * @param resource Resource + * @param fields Fields list + * @throws RegistryException on failure + * @throws APIManagementException on failure + */ + public static void fetchRequiredDetailsFromAssociatedAPI(Registry registry, Resource resource, + Map> fields) + throws RegistryException, APIManagementException { + String resourceFilePath = resource.getPath(); + String apiPath = resourceFilePath.substring(0, resourceFilePath.lastIndexOf('/') + 1) + + APIConstants.API_KEY; + if (registry.resourceExists(apiPath)) { + Resource apiResource = registry.get(apiPath); + GenericArtifactManager apiArtifactManager = APIUtil.getArtifactManager(registry, APIConstants.API_KEY); + GenericArtifact apiArtifact = apiArtifactManager.getGenericArtifact(apiResource.getUUID()); + String apiStatus = apiArtifact.getAttribute(APIConstants.API_OVERVIEW_STATUS).toLowerCase(); + String publisherRoles = apiResource.getProperty(APIConstants.PUBLISHER_ROLES); + fields.put(APIConstants.API_OVERVIEW_STATUS, Arrays.asList(apiStatus)); + fields.put(APIConstants.PUBLISHER_ROLES, Arrays.asList(publisherRoles)); + } else { + log.warn("API does not exist at " + apiPath); + } + } + + + /** + * This method can be used to filter out the json values, excluding keys from the json files + * + * @param jsonAsString JSON string + * @return values string + */ + public static String getValuesFromJsonString(String jsonAsString) { + JSONObject jsonObject = new JSONObject(jsonAsString); + StringBuilder values = new StringBuilder(); + extractJsonValues(jsonObject, values); + return values.toString().trim(); + } + + /** + * Extract json values as a string from JSON object recursively + * + * @param json json object + * @param values StringBuilder values + */ + private static void extractJsonValues(Object json, StringBuilder values) { + if (json instanceof JSONObject) { + JSONObject jsonObject = (JSONObject) json; + Iterator keys = jsonObject.keys(); + while (keys.hasNext()) { + String key = keys.next(); + extractJsonValues(jsonObject.get(key), values); + } + } else if (json instanceof JSONArray) { + JSONArray jsonArray = (JSONArray) json; + for (int i = 0; i < jsonArray.length(); i++) { + extractJsonValues(jsonArray.get(i), values); + } + } else { + values.append(json.toString()).append(" "); + } + } + + /** + * This method is used to extract types from graphql schema + * + * @param schemaString Schema String + * @return definition string + */ + public static String getTypesFromGraphQLSchemaString(String schemaString) { + List types = new GraphQLSchemaDefinition() + .extractGraphQLTypeList(schemaString); + StringBuilder definitionString = new StringBuilder(); + + for (GraphqlSchemaType type : types) { + definitionString.append(type.getType()).append(" "); + definitionString.append(String.join(" ", type.getFieldList())); + } + return definitionString.toString(); + } + + /** + * This method returns string content extracted from XML data + * + * @param xmlData xml data bytes + * @return string content + */ + public static String getContentFromXMLData(byte[] xmlData) { + try { + DocumentBuilderFactory factory = APIUtil.getSecuredDocumentBuilder(); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document doc = builder.parse(new ByteArrayInputStream(xmlData)); + doc.getDocumentElement().normalize(); + return extractTextAndAttributesFromElement(doc.getDocumentElement()); + } catch (Exception e) { + log.error("Error while parsing XML data", e); + return ""; + } + } + + /** + * This method is used to recursively extract text and attributes as a string + * + * @param element Doc element + * @return text and attributes string + */ + + private static String extractTextAndAttributesFromElement(Element element) { + StringBuilder text = new StringBuilder(); + + // Extract attributes from the element + NamedNodeMap attributes = element.getAttributes(); + for (int i = 0; i < attributes.getLength(); i++) { + Node attr = attributes.item(i); + text.append(attr.getNodeName()).append("=").append(attr.getNodeValue()).append(" "); + } + + // Extract text from child nodes + NodeList nodeList = element.getChildNodes(); + for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + // Recursively extract text and attributes + text.append(extractTextAndAttributesFromElement((Element) node)).append(" "); + } else if (node.getNodeType() == Node.TEXT_NODE) { + // Append text directly + text.append(node.getTextContent().trim()).append(" "); + } + } + return text.toString().trim(); + } + +} + 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 33377a0ece13..2340fe2c7459 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 @@ -6,6 +6,7 @@ import org.json.simple.JSONObject; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.APIProvider; +import org.wso2.carbon.apimgt.api.ExceptionCodes; import org.wso2.carbon.apimgt.api.model.*; import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO; @@ -168,10 +169,14 @@ private static void changeAPILifeCycle(APIProvider apiProvider, API api, String || api.isAdvertiseOnly() && (api.getApiExternalProductionEndpoint() != null || api.getApiExternalSandboxEndpoint() != null)) { if ((isOauthProtected && (tiers == null || tiers.size() == 0)) && !api.isAdvertiseOnly()) { - throw new APIManagementException("Failed to publish service to API store. No Tiers selected"); + throw new APIManagementException("Failed to publish service to API store. No Tiers selected", + ExceptionCodes.from(ExceptionCodes.FAILED_PUBLISHING_API_NO_TIERS_SELECTED, + api.getUuid())); } } else { - throw new APIManagementException("Failed to publish service to API store. No endpoint selected"); + throw new APIManagementException("Failed to publish service to API store. No endpoint selected", + ExceptionCodes.from(ExceptionCodes.FAILED_PUBLISHING_API_NO_ENDPOINT_SELECTED, + api.getUuid())); } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/SimpleContentSearchResultNameComparator.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/SimpleContentSearchResultNameComparator.java new file mode 100644 index 000000000000..511c71283804 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/SimpleContentSearchResultNameComparator.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. 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.apimgt.impl.utils; + +import org.wso2.carbon.apimgt.api.model.API; +import org.wso2.carbon.apimgt.api.model.APIDefinitionContentSearchResult; +import org.wso2.carbon.apimgt.api.model.APIProduct; +import org.wso2.carbon.apimgt.api.model.Documentation; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +/** + * This new class can be used instead of old ContentSearchResultNameComparator. This is written in an expandable + * manner unlike ContentSearchResultNameComparator class. + */ +public class SimpleContentSearchResultNameComparator implements Comparator { + + APINameComparator nameComparator = new APINameComparator(); + APIProductNameComparator productNameComparator = new APIProductNameComparator(); + + @Override + public int compare(Object o1, Object o2) { + + // Handle simple API, APIProduct comparisons + if (o1 instanceof API && o2 instanceof API) { + API api1 = (API) o1; + API api2 = (API) o2; + return nameComparator.compare(api1, api2); + } else if (o1 instanceof APIProduct && o2 instanceof APIProduct) { + APIProduct apiProduct1 = (APIProduct) o1; + APIProduct apiProduct2 = (APIProduct) o2; + return productNameComparator.compare(apiProduct1, apiProduct2); + } + + // Handle other comparisons + Object[] objects = {o1, o2}; + List names = new ArrayList<>(); + + for (Object obj : objects) { + if (obj instanceof API) { + API api = (API) obj; + names.add(api.getId().getName()); + } else if (obj instanceof APIProduct) { + APIProduct product = (APIProduct) obj; + names.add(product.getId().getName()); + } else if (obj instanceof APIDefinitionContentSearchResult) { + APIDefinitionContentSearchResult defSearch = (APIDefinitionContentSearchResult) obj; + names.add(defSearch.getApiName()); + } else if (obj instanceof Map.Entry) { + Map.Entry entry = (Map.Entry) obj; + if (entry.getKey() instanceof Documentation) { + Map.Entry docEntry = (Map.Entry) entry; + names.add(docEntry.getKey().getName()); + } + } + } + return names.get(0).compareToIgnoreCase(names.get(1)); + + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/resources/tenant/tenant-conf.json b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/resources/tenant/tenant-conf.json index 9558e6ed49e9..6e9b19463b84 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/resources/tenant/tenant-conf.json +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/resources/tenant/tenant-conf.json @@ -416,5 +416,6 @@ "SignUpRoles": [ "Internal/subscriber" ] - } + }, + "AllowSubscriptionValidationDisabling": false } diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/resources/tenant/tenant-config-schema.json b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/resources/tenant/tenant-config-schema.json index 15a16d8cb013..b28b19837c09 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/resources/tenant/tenant-config-schema.json +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/resources/tenant/tenant-config-schema.json @@ -1341,6 +1341,16 @@ }, "LinterCustomRules": { "required": ["rules"] + }, + "AllowSubscriptionValidationDisabling": { + "$id": "#/properties/AllowSubscriptionValidationDisabling", + "type": "boolean", + "title": "AllowSubscriptionValidationDisabling schema", + "description": "This property is used to specify whether to allow subscription validation disabling or not.", + "default": false, + "examples": [ + true, false + ] } }, "additionalProperties": true diff --git a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/utils/APIUtilTierTest.java b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/utils/APIUtilTierTest.java index 47d485b92e4c..ff1ce9d9a1d0 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/utils/APIUtilTierTest.java +++ b/components/apimgt/org.wso2.carbon.apimgt.impl/src/test/java/org/wso2/carbon/apimgt/impl/utils/APIUtilTierTest.java @@ -434,11 +434,12 @@ public void testAddDefaultSuperTenantAdvancedThrottlePoliciesSubLevel() throws E String[] subPolicies = new String[]{APIConstants.DEFAULT_SUB_POLICY_GOLD, APIConstants.DEFAULT_SUB_POLICY_SILVER, APIConstants.DEFAULT_SUB_POLICY_BRONZE, APIConstants.DEFAULT_SUB_POLICY_UNAUTHENTICATED, - APIConstants.DEFAULT_SUB_POLICY_UNLIMITED, APIConstants.DEFAULT_SUB_POLICY_ASYNC_GOLD, - APIConstants.DEFAULT_SUB_POLICY_ASYNC_SILVER, APIConstants.DEFAULT_SUB_POLICY_ASYNC_BRONZE, - APIConstants.DEFAULT_SUB_POLICY_ASYNC_UNLIMITED, APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_GOLD, - APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_SILVER, APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_BRONZE, - APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_UNLIMITED}; + APIConstants.DEFAULT_SUB_POLICY_UNLIMITED, APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_GOLD, APIConstants.DEFAULT_SUB_POLICY_ASYNC_SILVER, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_BRONZE, APIConstants.DEFAULT_SUB_POLICY_ASYNC_UNLIMITED, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_SUBSCRIPTIONLESS, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_GOLD, APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_SILVER, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_BRONZE, APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_UNLIMITED}; for (String policy : subPolicies) { Mockito.when( @@ -616,11 +617,12 @@ public void testAddDefaultTenantAdvancedThrottlePoliciesSubLevel() throws Except String[] policies = new String[]{APIConstants.DEFAULT_SUB_POLICY_GOLD, APIConstants.DEFAULT_SUB_POLICY_SILVER, APIConstants.DEFAULT_SUB_POLICY_BRONZE, APIConstants.DEFAULT_SUB_POLICY_UNAUTHENTICATED, - APIConstants.DEFAULT_SUB_POLICY_UNLIMITED, APIConstants.DEFAULT_SUB_POLICY_ASYNC_GOLD, - APIConstants.DEFAULT_SUB_POLICY_ASYNC_SILVER, APIConstants.DEFAULT_SUB_POLICY_ASYNC_BRONZE, - APIConstants.DEFAULT_SUB_POLICY_ASYNC_UNLIMITED, APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_GOLD, - APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_SILVER, APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_BRONZE, - APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_UNLIMITED}; + APIConstants.DEFAULT_SUB_POLICY_UNLIMITED, APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_GOLD, APIConstants.DEFAULT_SUB_POLICY_ASYNC_SILVER, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_BRONZE, APIConstants.DEFAULT_SUB_POLICY_ASYNC_UNLIMITED, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_SUBSCRIPTIONLESS, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_GOLD, APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_SILVER, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_BRONZE, APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_UNLIMITED}; for (String policy : policies) { Mockito.when( @@ -649,11 +651,12 @@ public void testAddDefaultTenantAdvancedThrottlePoliciesSubLevelAlreadyAdded() t String[] policies = new String[]{APIConstants.DEFAULT_SUB_POLICY_GOLD, APIConstants.DEFAULT_SUB_POLICY_SILVER, APIConstants.DEFAULT_SUB_POLICY_BRONZE, APIConstants.DEFAULT_SUB_POLICY_UNAUTHENTICATED, - APIConstants.DEFAULT_SUB_POLICY_UNLIMITED, APIConstants.DEFAULT_SUB_POLICY_ASYNC_GOLD, - APIConstants.DEFAULT_SUB_POLICY_ASYNC_SILVER, APIConstants.DEFAULT_SUB_POLICY_ASYNC_BRONZE, - APIConstants.DEFAULT_SUB_POLICY_ASYNC_UNLIMITED, APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_GOLD, - APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_SILVER, APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_BRONZE, - APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_UNLIMITED}; + APIConstants.DEFAULT_SUB_POLICY_UNLIMITED, APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_GOLD, APIConstants.DEFAULT_SUB_POLICY_ASYNC_SILVER, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_BRONZE, APIConstants.DEFAULT_SUB_POLICY_ASYNC_UNLIMITED, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_SUBSCRIPTIONLESS, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_GOLD, APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_SILVER, + APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_BRONZE, APIConstants.DEFAULT_SUB_POLICY_ASYNC_WH_UNLIMITED}; for (String policy : policies) { Mockito.when( @@ -923,6 +926,7 @@ private void mockPolicyRetrieval(ApiMgtDAO apiMgtDAO) throws Exception { ThrottleProperties throttleProperties = Mockito.mock(ThrottleProperties.class); Map defaultLimits = new HashMap<>(); Mockito.when(throttleProperties.getDefaultThrottleTierLimits()).thenReturn(defaultLimits); + Mockito.when(throttleProperties.isEnablePolicyRecreate()).thenReturn(true); Mockito.when(apiManagerConfiguration.getThrottleProperties()).thenReturn(throttleProperties); Mockito.when(apiManagerConfigurationService.getAPIManagerConfiguration()).thenReturn(apiManagerConfiguration); Mockito.when(serviceReferenceHolder.getAPIManagerConfigurationService()) diff --git a/components/apimgt/org.wso2.carbon.apimgt.internal.service/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.internal.service/pom.xml index 3795470a3a43..40f9c4a5df17 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.internal.service/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.internal.service/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/gen/java/org/wso2/carbon/apimgt/internal/service/SubscribeInternalApi.java b/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/gen/java/org/wso2/carbon/apimgt/internal/service/SubscribeInternalApi.java new file mode 100644 index 000000000000..147eb2676dae --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/gen/java/org/wso2/carbon/apimgt/internal/service/SubscribeInternalApi.java @@ -0,0 +1,51 @@ +package org.wso2.carbon.apimgt.internal.service; + +import org.wso2.carbon.apimgt.internal.service.dto.APIDTO; +import org.wso2.carbon.apimgt.internal.service.dto.ErrorDTO; +import org.wso2.carbon.apimgt.internal.service.dto.SubscriptionDTO; +import org.wso2.carbon.apimgt.internal.service.SubscribeInternalApiService; +import org.wso2.carbon.apimgt.internal.service.impl.SubscribeInternalApiServiceImpl; +import org.wso2.carbon.apimgt.api.APIManagementException; + +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.SecurityContext; +import javax.inject.Inject; + +import io.swagger.annotations.*; +import java.io.InputStream; + +import org.apache.cxf.jaxrs.ext.MessageContext; +import org.apache.cxf.jaxrs.ext.multipart.Attachment; +import org.apache.cxf.jaxrs.ext.multipart.Multipart; + +import java.util.Map; +import java.util.List; +import javax.validation.constraints.*; +@Path("/subscribe-internal") + +@Api(description = "the subscribe-internal API") + +@Produces({ "application/json" }) + + +public class SubscribeInternalApi { + + @Context MessageContext securityContext; + +SubscribeInternalApiService delegate = new SubscribeInternalApiServiceImpl(); + + + @POST + + + @Produces({ "application/json" }) + @ApiOperation(value = "Subscribe to a subscription validation disabled API", notes = "This will allow creating subscriptions from applications to APIs which have subscription validation disabled. ", response = SubscriptionDTO.class, tags={ "Subscription Validation" }) + @ApiResponses(value = { + @ApiResponse(code = 201, message = "Subscription created successfully", response = SubscriptionDTO.class), + @ApiResponse(code = 200, message = "Unexpected error", response = ErrorDTO.class) }) + public Response subscribeToAPI(@ApiParam(value = "This is used to specify the tenant domain, where the resource need to be retrieved from. " ,required=true)@HeaderParam("xWSO2Tenant") String xWSO2Tenant, @ApiParam(value = "Application ID of the subscription ") @QueryParam("appId") Integer appId, @ApiParam(value = "Application UUID ") @QueryParam("appUuid") String appUuid, @ApiParam(value = "The API object" ) APIDTO api) throws APIManagementException{ + return delegate.subscribeToAPI(xWSO2Tenant, appId, appUuid, api, securityContext); + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/gen/java/org/wso2/carbon/apimgt/internal/service/SubscribeInternalApiService.java b/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/gen/java/org/wso2/carbon/apimgt/internal/service/SubscribeInternalApiService.java new file mode 100644 index 000000000000..0f72de322a11 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/gen/java/org/wso2/carbon/apimgt/internal/service/SubscribeInternalApiService.java @@ -0,0 +1,26 @@ +package org.wso2.carbon.apimgt.internal.service; + +import org.wso2.carbon.apimgt.internal.service.*; +import org.wso2.carbon.apimgt.internal.service.dto.*; + +import org.apache.cxf.jaxrs.ext.MessageContext; +import org.apache.cxf.jaxrs.ext.multipart.Attachment; +import org.apache.cxf.jaxrs.ext.multipart.Multipart; + +import org.wso2.carbon.apimgt.api.APIManagementException; + +import org.wso2.carbon.apimgt.internal.service.dto.APIDTO; +import org.wso2.carbon.apimgt.internal.service.dto.ErrorDTO; +import org.wso2.carbon.apimgt.internal.service.dto.SubscriptionDTO; + +import java.util.List; + +import java.io.InputStream; + +import javax.ws.rs.core.Response; +import javax.ws.rs.core.SecurityContext; + + +public interface SubscribeInternalApiService { + public Response subscribeToAPI(String xWSO2Tenant, Integer appId, String appUuid, APIDTO api, MessageContext messageContext) throws APIManagementException; +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/gen/java/org/wso2/carbon/apimgt/internal/service/dto/APIDTO.java b/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/gen/java/org/wso2/carbon/apimgt/internal/service/dto/APIDTO.java index 51ff37c49366..ae278434ffaa 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/gen/java/org/wso2/carbon/apimgt/internal/service/dto/APIDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/gen/java/org/wso2/carbon/apimgt/internal/service/dto/APIDTO.java @@ -35,6 +35,7 @@ public class APIDTO { private List apiPolicies = new ArrayList<>(); private List urlMappings = new ArrayList<>(); private String securityScheme = null; + private Boolean isSubscriptionValidationDisabled = false; private AIConfigurationDTO aiConfiguration = null; /** @@ -286,6 +287,24 @@ public void setSecurityScheme(String securityScheme) { this.securityScheme = securityScheme; } + /** + * Whether subscription validation is disabled. + **/ + public APIDTO isSubscriptionValidationDisabled(Boolean isSubscriptionValidationDisabled) { + this.isSubscriptionValidationDisabled = isSubscriptionValidationDisabled; + return this; + } + + + @ApiModelProperty(example = "false", value = "Whether subscription validation is disabled.") + @JsonProperty("isSubscriptionValidationDisabled") + public Boolean isIsSubscriptionValidationDisabled() { + return isSubscriptionValidationDisabled; + } + public void setIsSubscriptionValidationDisabled(Boolean isSubscriptionValidationDisabled) { + this.isSubscriptionValidationDisabled = isSubscriptionValidationDisabled; + } + /** **/ public APIDTO aiConfiguration(AIConfigurationDTO aiConfiguration) { @@ -293,7 +312,7 @@ public APIDTO aiConfiguration(AIConfigurationDTO aiConfiguration) { return this; } - + @ApiModelProperty(value = "") @JsonProperty("aiConfiguration") public AIConfigurationDTO getAiConfiguration() { @@ -327,12 +346,13 @@ public boolean equals(java.lang.Object o) { Objects.equals(apiPolicies, API.apiPolicies) && Objects.equals(urlMappings, API.urlMappings) && Objects.equals(securityScheme, API.securityScheme) && + Objects.equals(isSubscriptionValidationDisabled, API.isSubscriptionValidationDisabled) && Objects.equals(aiConfiguration, API.aiConfiguration); } @Override public int hashCode() { - return Objects.hash(uuid, apiId, provider, name, version, context, policy, apiType, status, organization, isDefaultVersion, apiPolicies, urlMappings, securityScheme, aiConfiguration); + return Objects.hash(uuid, apiId, provider, name, version, context, policy, apiType, status, organization, isDefaultVersion, apiPolicies, urlMappings, securityScheme, isSubscriptionValidationDisabled, aiConfiguration); } @Override @@ -354,6 +374,7 @@ public String toString() { sb.append(" apiPolicies: ").append(toIndentedString(apiPolicies)).append("\n"); sb.append(" urlMappings: ").append(toIndentedString(urlMappings)).append("\n"); sb.append(" securityScheme: ").append(toIndentedString(securityScheme)).append("\n"); + sb.append(" isSubscriptionValidationDisabled: ").append(toIndentedString(isSubscriptionValidationDisabled)).append("\n"); sb.append(" aiConfiguration: ").append(toIndentedString(aiConfiguration)).append("\n"); sb.append("}"); return sb.toString(); diff --git a/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/main/java/org/wso2/carbon/apimgt/internal/service/impl/SubscribeInternalApiServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/main/java/org/wso2/carbon/apimgt/internal/service/impl/SubscribeInternalApiServiceImpl.java new file mode 100644 index 000000000000..39e6d75ee56b --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/main/java/org/wso2/carbon/apimgt/internal/service/impl/SubscribeInternalApiServiceImpl.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. 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.apimgt.internal.service.impl; + +import org.wso2.carbon.apimgt.api.APIManagementException; +import org.wso2.carbon.apimgt.impl.APIConstants; +import org.wso2.carbon.apimgt.impl.dao.SubscriptionValidationDAO; +import org.wso2.carbon.apimgt.impl.notifier.events.SubscriptionEvent; +import org.wso2.carbon.apimgt.impl.utils.APIUtil; +import org.wso2.carbon.apimgt.internal.service.*; +import org.apache.cxf.jaxrs.ext.MessageContext; +import org.wso2.carbon.apimgt.internal.service.dto.APIDTO; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; + +import java.util.Map; +import java.util.UUID; + +import javax.ws.rs.core.Response; + + +public class SubscribeInternalApiServiceImpl implements SubscribeInternalApiService { + + public Response subscribeToAPI(String xWSO2Tenant, Integer appId, String appUuid, APIDTO api, + MessageContext messageContext) { + SubscriptionValidationDAO subscriptionValidationDAO = new SubscriptionValidationDAO(); + Map subDetails = null; + String synchronizeKey = api.getUuid() + ":" + appUuid; + String defaultTier = APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS; + String apiType = api.getApiType(); + int apiId = api.getApiId(); + + if ("WS".equals(apiType) || "WEBSUB".equals(apiType) || "SSE".equals(apiType)) { + defaultTier = APIConstants.DEFAULT_SUB_POLICY_ASYNC_SUBSCRIPTIONLESS; + } + try { + String subscriber = subscriptionValidationDAO.getApplicationSubscriber(appUuid); + String subscriberTenant = MultitenantUtils.getTenantDomain(subscriber); + int tenantId = APIUtil.getTenantId(subscriberTenant); + synchronized (synchronizeKey.intern()) { + subDetails = subscriptionValidationDAO + .subscribeToAPI(apiId, appId, defaultTier, subscriber); + } + int subscriptionId = (int) subDetails.get("id"); + String subscriptionUuid = (String) subDetails.get("uuid"); + SubscriptionEvent subscriptionEvent = new SubscriptionEvent(UUID.randomUUID().toString(), + System.currentTimeMillis(), APIConstants.EventType.SUBSCRIPTIONS_CREATE.name(), tenantId, + subscriberTenant, subscriptionId, subscriptionUuid, apiId, api.getUuid(), + appId, appUuid, defaultTier, APIConstants.SubscriptionStatus.UNBLOCKED, + api.getName(), api.getVersion()); + APIUtil.sendNotification(subscriptionEvent, APIConstants.NotifierType.SUBSCRIPTIONS.name()); + } catch (APIManagementException e) { + Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); + } + return Response.ok().entity(subDetails).build(); + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/main/java/org/wso2/carbon/apimgt/internal/service/utils/SubscriptionValidationDataUtil.java b/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/main/java/org/wso2/carbon/apimgt/internal/service/utils/SubscriptionValidationDataUtil.java index d1f906db1f0d..4b5bd7b52251 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/main/java/org/wso2/carbon/apimgt/internal/service/utils/SubscriptionValidationDataUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/main/java/org/wso2/carbon/apimgt/internal/service/utils/SubscriptionValidationDataUtil.java @@ -21,11 +21,14 @@ import edu.emory.mathcs.backport.java.util.Arrays; import org.apache.commons.lang3.StringUtils; import org.apache.cxf.jaxrs.ext.MessageContext; +import org.wso2.carbon.apimgt.api.APIConsumer; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.TokenBaseThrottlingCountHolder; +import org.wso2.carbon.apimgt.api.APIProvider; import org.wso2.carbon.apimgt.api.dto.ConditionDTO; import org.wso2.carbon.apimgt.api.model.AIConfiguration; import org.wso2.carbon.apimgt.api.model.AIEndpointConfiguration; +import org.wso2.carbon.apimgt.api.model.ApiTypeWrapper; import org.wso2.carbon.apimgt.api.model.OperationPolicy; import org.wso2.carbon.apimgt.api.model.Scope; import org.wso2.carbon.apimgt.api.model.policy.AIAPIQuotaLimit; @@ -59,6 +62,7 @@ public class SubscriptionValidationDataUtil { private static APIDTO fromAPItoDTO(API model) throws APIManagementException { APIDTO apidto = null; + APIProvider apiProvider = RestApiCommonUtil.getLoggedInUserProvider(); if (model != null) { apidto = new APIDTO(); apidto.setUuid(model.getApiUUID()); @@ -76,9 +80,11 @@ private static APIDTO fromAPItoDTO(API model) throws APIManagementException { // The security schema is necessary only for the websocket APIs. To prevent unnecessary registry calls, // it has been excluded from other APIs, thus reducing operational costs. if(model.getApiType() != null && model.getApiType().equals("WS")) { - apidto.setSecurityScheme(RestApiCommonUtil.getLoggedInUserProvider(). + apidto.setSecurityScheme(apiProvider. getSecuritySchemeOfAPI(model.getApiUUID(), model.getOrganization())); } + apidto.setIsSubscriptionValidationDisabled(apiProvider + .isSubscriptionValidationDisabled(model.getApiUUID())); Map urlMappings = model.getAllResources(); List urlMappingsDTO = new ArrayList<>(); for (URLMapping urlMapping : urlMappings.values()) { @@ -147,6 +153,7 @@ private static APIDTO fromAPItoDTO(API model) throws APIManagementException { public static APIListDTO fromAPIToAPIListDTO(API model) throws APIManagementException { APIListDTO apiListdto = new APIListDTO(); + APIProvider apiProvider = RestApiCommonUtil.getLoggedInUserProvider(); if (model != null) { APIDTO apidto = new APIDTO(); apidto.setUuid(model.getApiUUID()); @@ -160,8 +167,9 @@ public static APIListDTO fromAPIToAPIListDTO(API model) throws APIManagementExce apidto.setStatus(model.getStatus()); apidto.setIsDefaultVersion(model.isDefaultVersion()); apidto.setOrganization(model.getOrganization()); - apidto.setSecurityScheme(RestApiCommonUtil.getLoggedInUserProvider(). - getSecuritySchemeOfAPI(model.getApiUUID(), model.getOrganization())); + apidto.setSecurityScheme(apiProvider.getSecuritySchemeOfAPI(model.getApiUUID(), model.getOrganization())); + apidto.setIsSubscriptionValidationDisabled(apiProvider + .isSubscriptionValidationDisabled(model.getApiUUID())); Map urlMappings = model.getAllResources(); List urlMappingsDTO = new ArrayList<>(); for (URLMapping urlMapping : urlMappings.values()) { @@ -621,4 +629,9 @@ public static GlobalPolicyListDTO fromGlobalPolicyToGlobalPolicyListDTO(List + diff --git a/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/main/webapp/WEB-INF/web.xml b/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/main/webapp/WEB-INF/web.xml index 627f9c863a24..49b6bd6e4311 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/main/webapp/WEB-INF/web.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.internal.service/src/main/webapp/WEB-INF/web.xml @@ -57,6 +57,8 @@ org.wso2.carbon.apimgt.internal.service.ApiLoggingConfigsApi, org.wso2.carbon.apimgt.internal.service.CorrelationConfigsApi, org.wso2.carbon.apimgt.internal.service.GatewayPolicyArtifactsApi, + org.wso2.carbon.apimgt.internal.service.SubscribeInternalApi + org.wso2.carbon.apimgt.internal.service.GatewayPolicyArtifactsApi, org.wso2.carbon.apimgt.internal.service.LlmProvidersApi diff --git a/components/apimgt/org.wso2.carbon.apimgt.internal.service/swagger.json b/components/apimgt/org.wso2.carbon.apimgt.internal.service/swagger.json index dfe5c5b50eb8..e1be56dc3f78 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.internal.service/swagger.json +++ b/components/apimgt/org.wso2.carbon.apimgt.internal.service/swagger.json @@ -256,6 +256,55 @@ } } }, + "/subscribe-internal" : { + "post" : { + "tags" : [ "Subscription Validation" ], + "summary" : "Subscribe to a subscription validation disabled API", + "description" : "This will allow creating subscriptions from applications to APIs which have\nsubscription validation disabled.\n", + "operationId" : "subscribeToAPI", + "parameters" : [ { + "name" : "xWSO2Tenant", + "in" : "header", + "description" : "This is used to specify the tenant domain, where the resource need to be\n retrieved from.\n", + "required" : true, + "type" : "string" + }, { + "name" : "appId", + "in" : "query", + "description" : "Application ID of the subscription\n", + "required" : false, + "type" : "integer" + }, { + "name" : "appUuid", + "in" : "query", + "description" : "Application UUID\n", + "required" : false, + "type" : "string" + }, { + "in" : "body", + "name" : "api", + "description" : "The API object", + "required" : false, + "schema" : { + "$ref" : "#/definitions/API" + } + } ], + "responses" : { + "201" : { + "description" : "Subscription created successfully", + "schema" : { + "$ref" : "#/definitions/Subscription" + } + }, + "default" : { + "description" : "Unexpected error", + "schema" : { + "$ref" : "#/definitions/Error" + } + } + } + } + }, "/subscription-policies" : { "get" : { "tags" : [ "Subscription Validation" ], @@ -1289,6 +1338,12 @@ "example" : "Oauth2,api_key", "description" : "Available authentication methods of the API." }, + "isSubscriptionValidationDisabled" : { + "type" : "boolean", + "example" : false, + "description" : "Whether subscription validation is disabled.", + "default" : false + }, "aiConfiguration" : { "$ref" : "#/definitions/AIConfiguration" } diff --git a/components/apimgt/org.wso2.carbon.apimgt.jms.listener/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.jms.listener/pom.xml index 3242ebfa1d83..ed5ef3e4afa4 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.jms.listener/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.jms.listener/pom.xml @@ -4,7 +4,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml 4.0.0 diff --git a/components/apimgt/org.wso2.carbon.apimgt.keymgt.client/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.keymgt.client/pom.xml index e7456f4ad016..dcecda758003 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.keymgt.client/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.keymgt.client/pom.xml @@ -16,7 +16,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.keymgt/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.keymgt/pom.xml index 4a966dc959b3..4b5cba2d1de5 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.keymgt/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.keymgt/pom.xml @@ -16,7 +16,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/handlers/AbstractKeyValidationHandler.java b/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/handlers/AbstractKeyValidationHandler.java index cbf3dbf6cd96..e22562c825be 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/handlers/AbstractKeyValidationHandler.java +++ b/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/handlers/AbstractKeyValidationHandler.java @@ -253,6 +253,7 @@ private APIKeyValidationInfoDTO validateSubscriptionDetails(APIKeyValidationInfo ApplicationKeyMapping key = null; Application app = null; Subscription sub = null; + boolean isSubValidationDisabled = false; SubscriptionDataStore datastore = SubscriptionDataHolder.getInstance() .getTenantSubscriptionStore(apiTenantDomain); @@ -260,6 +261,14 @@ private APIKeyValidationInfoDTO validateSubscriptionDetails(APIKeyValidationInfo if (datastore != null) { api = datastore.getApiByContextAndVersion(context, version); if (api != null) { + isSubValidationDisabled = api.isSubscriptionValidationDisabled(); + if (isSubValidationDisabled) { + if (log.isDebugEnabled()) { + log.debug("Subscription validation is disabled for the API " + api.getApiName()); + } + return validateSubscriptionDetailsWhenDisabled(infoDTO, apiTenantDomain, tenantId, + datastore, api, consumerKey, keyManager); + } key = datastore.getKeyMappingByKeyAndKeyManager(consumerKey, keyManager); if (key != null) { app = datastore.getApplicationById(key.getApplicationId()); @@ -370,6 +379,157 @@ private APIKeyValidationInfoDTO validateSubscriptionDetails(APIKeyValidationInfo return infoDTO; } + private APIKeyValidationInfoDTO validateSubscriptionDetailsWhenDisabled(APIKeyValidationInfoDTO infoDTO, + String apiTenantDomain, int tenantId, SubscriptionDataStore datastore, API api, String consumerKey, + String keyManager) { + ApplicationKeyMapping key = null; + Application app = null; + Subscription sub = null; + + // Create the default key and subscription objects + ApplicationKeyMapping defaultKey = new ApplicationKeyMapping(); + defaultKey.setKeyType(APIConstants.API_KEY_TYPE_PRODUCTION); + Subscription defaultSub = new Subscription(); + defaultSub.setPolicyId(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS); + + key = datastore.getKeyMappingByKeyAndKeyManager(consumerKey, keyManager, true); + if (key != null) { + app = datastore.getApplicationById(key.getApplicationId(), true); + if (app != null) { + sub = datastore.getSubscriptionById(app.getId(), api.getApiId(), true); + if (sub != null) { + if (log.isDebugEnabled()) { + log.debug("All information is retrieved from the inmemory data store."); + } + } else { + if (log.isDebugEnabled()) { + log.debug("Valid subscription not found for appId " + app.getId() + " and apiId " + + api.getApiId()); + } + // Subscribe internally from the relevant app using the default subscription plan + datastore.subscribeToAPIInternally(api, app, apiTenantDomain); + } + } else { + if (log.isDebugEnabled()) { + log.debug("Application not found in the datastore for id " + key.getApplicationId()); + } + } + } else { + if (log.isDebugEnabled()) { + log.debug( + "Application keymapping not found in the datastore for id consumerKey " + consumerKey); + } + + } + + if (key == null) { + key = defaultKey; + } + if (app == null) { + app = getDefaultApplication(apiTenantDomain); + } + if (sub == null) { + sub = defaultSub; + } + + validateWhenDisabled(infoDTO, apiTenantDomain, tenantId, datastore, api, key, app, sub); + + return infoDTO; + } + + private APIKeyValidationInfoDTO validateWhenDisabled(APIKeyValidationInfoDTO infoDTO, String apiTenantDomain, + int tenantId, SubscriptionDataStore datastore, API api, ApplicationKeyMapping key, Application app, + Subscription sub) { + String type = key.getKeyType(); + infoDTO.setTier(sub.getPolicyId()); + infoDTO.setSubscriber(app.getSubName()); + if (app.getId() != null) { + infoDTO.setApplicationId(app.getId().toString()); + } + infoDTO.setApiName(api.getApiName()); + infoDTO.setApiVersion(api.getApiVersion()); + infoDTO.setApiPublisher(api.getApiProvider()); + infoDTO.setApplicationName(app.getName()); + // We need to override the original application policy as the requests might get throttled out + // unintentionally otherwise due to the internal subscription. + infoDTO.setApplicationTier(APIConstants.DEFAULT_APP_POLICY_UNLIMITED); + infoDTO.setApplicationUUID(app.getUUID()); + if (app.getGroupIds() != null) { + infoDTO.setApplicationGroupIds(app.getGroupIds().stream() + .map(GroupId::getGroupId).collect(Collectors.toSet())); + } + infoDTO.setAppAttributes(app.getAttributes()); + infoDTO.setType(type); + + // Advanced Level Throttling Related Properties + String apiTier = api.getApiTier(); + String subscriberTenant = MultitenantUtils.getTenantDomain(app.getSubName()); + + SubscriptionPolicy subPolicy = datastore.getSubscriptionPolicyByName(sub.getPolicyId(), + tenantId); + if (subPolicy == null) { + try { + subPolicy = new SubscriptionDataLoaderImpl() + .getSubscriptionPolicy(sub.getPolicyId(), apiTenantDomain); + datastore.addOrUpdateSubscriptionPolicy(subPolicy); + } catch (DataLoadingException e) { + log.error("Error while loading SubscriptionPolicy"); + } + } + ApiPolicy apiPolicy = datastore.getApiPolicyByName(api.getApiTier(), tenantId); + + boolean isContentAware = false; + int spikeArrest = 0; + String spikeArrestUnit = null; + int applicationSpikeArrest = 0; + String applicationSpikeArrestUnit = null; + boolean stopOnQuotaReach = false; + int graphQLMaxDepth = 0; + int graphQLMaxComplexity = 0; + + if (subPolicy != null) { + if (subPolicy.isContentAware() || (apiPolicy != null && apiPolicy.isContentAware())) { + isContentAware = true; + } + if (subPolicy.getRateLimitCount() > 0) { + spikeArrest = subPolicy.getRateLimitCount(); + } + if (subPolicy.getRateLimitTimeUnit() != null) { + spikeArrestUnit = subPolicy.getRateLimitTimeUnit(); + } + stopOnQuotaReach = subPolicy.isStopOnQuotaReach(); + if (subPolicy.getGraphQLMaxDepth() > 0) { + graphQLMaxDepth = subPolicy.getGraphQLMaxDepth(); + } + if (subPolicy.getGraphQLMaxComplexity() > 0) { + graphQLMaxComplexity = subPolicy.getGraphQLMaxComplexity(); + } + } + infoDTO.setContentAware(isContentAware); + + // TODO this must implement as a part of throttling implementation. + String apiLevelThrottlingKey = "api_level_throttling_key"; + + List list = new ArrayList<>(); + list.add(apiLevelThrottlingKey); + infoDTO.setSpikeArrestLimit(spikeArrest); + infoDTO.setSpikeArrestUnit(spikeArrestUnit); + infoDTO.setApplicationSpikeArrestLimit(applicationSpikeArrest); + infoDTO.setStopOnQuotaReach(stopOnQuotaReach); + infoDTO.setSubscriberTenantDomain(subscriberTenant); + infoDTO.setGraphQLMaxDepth(graphQLMaxDepth); + infoDTO.setGraphQLMaxComplexity(graphQLMaxComplexity); + if (apiTier != null && !apiTier.trim().isEmpty()) { + infoDTO.setApiTier(apiTier); + } + // We also need to set throttling data list associated with given API. This need to have + // policy id and + // condition id list for all throttling tiers associated with this API. + infoDTO.setThrottlingDataList(list); + infoDTO.setAuthorized(true); + return infoDTO; + } + private APIKeyValidationInfoDTO validate(APIKeyValidationInfoDTO infoDTO, String apiTenantDomain, int tenantId, SubscriptionDataStore datastore, API api, ApplicationKeyMapping key, Application app, Subscription sub) { String subscriptionStatus = sub.getSubscriptionState(); @@ -623,4 +783,14 @@ protected long getTimeStampSkewInSeconds() { return OAuthServerConfiguration.getInstance().getTimeStampSkewInSeconds(); } + + private Application getDefaultApplication(String apiTenantDomain) { + Application defaultApp = new Application(); + defaultApp.setName(APIConstants.SUBSCRIPTIONLESS_APPLICATION_NAME); + defaultApp.setUUID(APIConstants.SUBSCRIPTIONLESS_APPLICATION_NAME); + defaultApp.setSubName(APIConstants.SUBSCRIPTIONLESS_APPLICATION_OWNER); + defaultApp.setPolicy(APIConstants.DEFAULT_APP_POLICY_UNLIMITED); + defaultApp.setOrganization(apiTenantDomain); + return defaultApp; + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/SubscriptionDataLoader.java b/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/SubscriptionDataLoader.java index fbcc0db7de12..66dd515111b2 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/SubscriptionDataLoader.java +++ b/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/SubscriptionDataLoader.java @@ -162,4 +162,12 @@ public ApplicationKeyMapping getKeyMapping(String consumerKey, String keyManager * @throws DataLoadingException */ public List loadAllTenantApiMetadata() throws DataLoadingException ; + + /** + * Internally subscribe to an API. + * @param api API to subscribe to + * @param app Application to subscribe from + * @param tenantDomain Tenant Domain + */ + void subscribeToAPIInternally(API api, Application app, String tenantDomain); } diff --git a/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/SubscriptionDataStore.java b/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/SubscriptionDataStore.java index 2418d5094329..d4de62dd155f 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/SubscriptionDataStore.java +++ b/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/SubscriptionDataStore.java @@ -48,6 +48,15 @@ public interface SubscriptionDataStore { */ Application getApplicationById(int appId); + /** + * Gets an {@link Application} by Id + * + * @param appId Id of the Application + * @param validationDisabled whether subscription validation is disabled + * @return {@link Application} with the appId + */ + Application getApplicationById(int appId, boolean validationDisabled); + /** * Gets the {@link ApplicationKeyMapping} entry by Key * @@ -57,6 +66,16 @@ public interface SubscriptionDataStore { */ ApplicationKeyMapping getKeyMappingByKeyAndKeyManager(String key, String keyManager); + /** + * Gets the {@link ApplicationKeyMapping} entry by Key + * + * @param key . + * @param keyManager Keymanager Name + * @param validationDisabled whether subscription validation is disabled + * @return {@link ApplicationKeyMapping} entry + */ + ApplicationKeyMapping getKeyMappingByKeyAndKeyManager(String key, String keyManager, boolean validationDisabled); + /** * Get API by Context and Version * @@ -92,6 +111,16 @@ public interface SubscriptionDataStore { */ Subscription getSubscriptionById(int appId, int apiId); + /** + * Gets Subscription by ID + * + * @param appId Application associated with the Subscription + * @param apiId Api associated with the Subscription + * @param validationDisabled whether subscription validation is disabled + * @return {@link Subscription} + */ + Subscription getSubscriptionById(int appId, int apiId, boolean validationDisabled); + /** * Gets API Throttling Policy by the name and Tenant Id * @@ -122,6 +151,14 @@ public interface SubscriptionDataStore { void addOrUpdateSubscription(Subscription subscription); + /** + * Internally subscribe to an API. + * @param api API to subscribe to + * @param app Application to subscribe from + * @param tenantDomain Tenant Domain + */ + void subscribeToAPIInternally(API api, Application app, String tenantDomain); + void addOrUpdateAPI(API api); void addOrUpdateAPIWithUrlTemplates(API api); diff --git a/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/entity/API.java b/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/entity/API.java index 535ed91374bb..e33443cf9684 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/entity/API.java +++ b/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/entity/API.java @@ -45,6 +45,7 @@ public class API implements CacheableEntity { private String securityScheme; private String revisionId; private List apiPolicies = new ArrayList<>(); + private boolean isSubscriptionValidationDisabled = false; private AIConfiguration aiConfiguration; public API() { @@ -209,6 +210,7 @@ public String toString() { ", apiType='" + apiType + '\'' + ", status='" + status + '\'' + ", securityScheme='" + securityScheme + '\'' + + ", isSubscriptionValidationDisabled='" + isSubscriptionValidationDisabled + '\'' + ", isDefaultVersion=" + isDefaultVersion + ", urlMappings=" + urlMappings + ", apiPolicies=" + apiPolicies + @@ -327,6 +329,14 @@ public List getApiPolicies() { return apiPolicies; } + public boolean isSubscriptionValidationDisabled() { + return isSubscriptionValidationDisabled; + } + + public void setSubscriptionValidationDisabled(boolean subscriptionValidationDisabled) { + isSubscriptionValidationDisabled = subscriptionValidationDisabled; + } + public AIConfiguration getAiConfiguration() { return aiConfiguration; } diff --git a/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/impl/SubscriptionDataLoaderImpl.java b/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/impl/SubscriptionDataLoaderImpl.java index c9d25dbca0a8..b5322cfb63da 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/impl/SubscriptionDataLoaderImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/impl/SubscriptionDataLoaderImpl.java @@ -18,12 +18,15 @@ package org.wso2.carbon.apimgt.keymgt.model.impl; import com.google.gson.Gson; +import com.google.gson.JsonObject; import org.apache.commons.codec.binary.Base64; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; import org.apache.http.util.EntityUtils; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.impl.APIConstants; @@ -450,6 +453,27 @@ public List loadAllScopes(String tenantDomain) throws DataLoadingExceptio } + @Override + public void subscribeToAPIInternally(API api, Application app, String tenantDomain) { + String path = String.format("%s?appId=%s&appUuid=%s", + APIConstants.SubscriptionValidationResources.SUBSCRIBE_INTERNAL, app.getId(), app.getUUID()); + Gson gson = new Gson(); + String apiJson = gson.toJson(api); + JsonObject apiJsonObject = gson.fromJson(apiJson, JsonObject.class); + // Remove the deployed property from the API object before sending to the internal API + // as this is not there in the internal DTO + apiJsonObject.remove("deployed"); + String modifiedApiJson = gson.toJson(apiJsonObject); + + try { + invokePostService(path, tenantDomain, modifiedApiJson); + } catch (IOException | DataLoadingException e) { + if (log.isDebugEnabled()) { + log.debug("Error while subscribing to API", e); + } + } + } + private String invokeService(String path, String tenantDomain) throws DataLoadingException, IOException { String serviceURLStr = getEventHubConfigurationDto.getServiceUrl().concat(APIConstants.INTERNAL_WEB_APP_EP); @@ -479,6 +503,36 @@ private String invokeService(String path, String tenantDomain) throws DataLoadin return responseString; } + private void invokePostService(String path, String tenantDomain, String payload) + throws IOException, DataLoadingException { + String serviceURLStr = getEventHubConfigurationDto.getServiceUrl().concat(APIConstants.INTERNAL_WEB_APP_EP); + HttpPost post = new HttpPost(serviceURLStr + path); + URL serviceURL = new URL(serviceURLStr + path); + byte[] credentials = getServiceCredentials(getEventHubConfigurationDto); + int servicePort = serviceURL.getPort(); + String serviceProtocol = serviceURL.getProtocol(); + post.setHeader(APIConstants.AUTHORIZATION_HEADER_DEFAULT, + APIConstants.AUTHORIZATION_BASIC + + new String(credentials, StandardCharsets.UTF_8)); + post.setHeader("Content-Type", "application/json"); + if (tenantDomain != null) { + post.setHeader(APIConstants.HEADER_TENANT, tenantDomain); + } + post.setEntity(new StringEntity(payload)); + + HttpClient httpClient = APIUtil.getHttpClient(servicePort, serviceProtocol); + String responseString; + try (CloseableHttpResponse httpResponse = APIUtil.executeHTTPRequest(post, httpClient)) { + responseString = EntityUtils.toString(httpResponse.getEntity(), UTF8); + } catch (APIManagementException e) { + throw new DataLoadingException("Error while invoking post service", e); + } + + if (log.isDebugEnabled()) { + log.debug("Response : " + responseString); + } + } + private byte[] getServiceCredentials(EventHubConfigurationDto eventHubConfigurationDto) { String username = eventHubConfigurationDto.getUsername(); diff --git a/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/impl/SubscriptionDataStoreImpl.java b/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/impl/SubscriptionDataStoreImpl.java index d4ebef898fa1..78056f7b2141 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/impl/SubscriptionDataStoreImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/model/impl/SubscriptionDataStoreImpl.java @@ -46,10 +46,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -75,6 +72,8 @@ public class SubscriptionDataStoreImpl implements SubscriptionDataStore { private boolean apiPoliciesInitialized; private String tenantDomain; private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(LOADING_POOL_SIZE); + private final ExecutorService subscriptionExecutorService = Executors.newFixedThreadPool(10, + new InternalSubscriptionThreadFactory()); public SubscriptionDataStoreImpl(String tenantDomain) { @@ -103,6 +102,20 @@ public void init() { initializeLoadingTasks(); } + @Override + public Application getApplicationById(int appId, boolean validationDisabled) { + Application application; + if (validationDisabled) { + try { + application = getApplicationById(appId); + } catch (Exception e) { + application = null; + } + } else { + return getApplicationById(appId); + } + return application; + } @Override public Application getApplicationById(int appId) { @@ -140,6 +153,22 @@ public Application getApplicationById(int appId) { return application; } + @Override + public ApplicationKeyMapping getKeyMappingByKeyAndKeyManager(String key, String keyManager, + boolean validationDisabled) { + ApplicationKeyMapping applicationKeyMapping; + if (validationDisabled) { + try { + applicationKeyMapping = getKeyMappingByKeyAndKeyManager(key, keyManager); + } catch (Exception e) { + applicationKeyMapping = null; + } + } else { + return getKeyMappingByKeyAndKeyManager(key, keyManager); + } + return applicationKeyMapping; + } + @Override public ApplicationKeyMapping getKeyMappingByKeyAndKeyManager(String key, String keyManager) { @@ -251,6 +280,20 @@ public ApplicationPolicy getApplicationPolicyByName(String policyName, int tenan return appPolicyMap.get(key); } + @Override + public Subscription getSubscriptionById(int appId, int apiId, boolean validationDisabled) { + Subscription subscription; + if (validationDisabled) { + try { + subscription = getSubscriptionById(appId, apiId); + } catch (Exception e) { + subscription = null; + } + } else { + return getSubscriptionById(appId, apiId); + } + return subscription; + } @Override public Subscription getSubscriptionById(int appId, int apiId) { @@ -467,6 +510,21 @@ public void addOrUpdateSubscription(Subscription subscription) { } } + @Override + public void subscribeToAPIInternally(API api, Application app, String tenantDomain) { + if (log.isDebugEnabled()) { + log.debug("Subscribing internally to API " + api.getApiName() + " with version " + api.getApiVersion() + + " from application " + app.getName()); + } + // Hand over the internal subscription to a separate thread pool to be carried out secretly + subscriptionExecutorService.submit(() -> { + if (getSubscriptionById(app.getId(), api.getApiId()) != null) { + return; + } + new SubscriptionDataLoaderImpl().subscribeToAPIInternally(api, app, tenantDomain); + }); + } + @Override public void removeSubscription(Subscription subscription) { @@ -808,4 +866,15 @@ public void run() { } } } + + /** + * Thread factory to create internal subscription threads. + */ + private static class InternalSubscriptionThreadFactory implements ThreadFactory { + private int count = 0; + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "InternalSubscriptionThread-thread-" + count++); + } + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.notification/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.notification/pom.xml index d02c53a9f3dc..ea0e184f3ede 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.notification/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.notification/pom.xml @@ -19,7 +19,7 @@ apimgt org.wso2.carbon.apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT org.wso2.carbon.apimgt.notification 4.0.0 diff --git a/components/apimgt/org.wso2.carbon.apimgt.output.adapter.http/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.output.adapter.http/pom.xml index 4c713090c859..0e91a5576613 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.output.adapter.http/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.output.adapter.http/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.persistence/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.persistence/pom.xml index adbf3467e91a..8d37e379e5e7 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.persistence/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.persistence/pom.xml @@ -3,7 +3,7 @@ apimgt org.wso2.carbon.apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml 4.0.0 diff --git a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/APIConstants.java b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/APIConstants.java index 34317eaea699..d202d5165187 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/APIConstants.java +++ b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/APIConstants.java @@ -140,6 +140,9 @@ public final class APIConstants { public static final String WSO2_ANONYMOUS_USER = "wso2.anonymous.user"; + // Subscription validation related constants + public static final String DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS = "DefaultSubscriptionless"; + /** * API categories related constants */ @@ -227,6 +230,8 @@ public static class Monetization { public static final String WSDL_FILE_EXTENSION = ".wsdl"; public static final String WSDL_PROVIDER_SEPERATOR = "--"; public static final String API_WSDL_ARCHIVE_LOCATION = "archives/"; + public static final String WSDL_XML_MEDIA_TYPE = "application/wsdl+xml"; + public static final String WSDL_FILE_MEDIA_TYPE = "application/octet-stream"; public static final String ZIP_FILE_EXTENSION = ".zip"; @@ -372,14 +377,15 @@ public enum APITransportType { public static final String USER_CTX_PROPERTY_ISADMIN = "isAdmin"; public static final String USER_CTX_PROPERTY_SKIP_ROLES = "skipRoles"; public static final String API = "API"; - + public static final String API_CUSTOM_SEQUENCE_TYPE_IN = "in"; public static final String API_CUSTOM_SEQUENCE_TYPE_OUT = "out"; public static final String API_CUSTOM_SEQUENCE_TYPE_FAULT = "fault"; - + public static final String GRAPHQL_SCHEMA_FILE_EXTENSION = ".graphql"; public static final String GRAPHQL_LOCAL_ENTRY_EXTENSION = "_graphQL"; public static final String GRAPHQL_SCHEMA_PROVIDER_SEPERATOR = "--"; + public static final String GRAPHQL_DEFINITION_MEDIA_TYPE = "text/plain; charset=ISO-8859-1"; public static final String ALLOW_MULTIPLE_STATUS = "allowMultipleStatus"; public static final String ALLOW_MULTIPLE_VERSIONS = "allowMultipleVersions"; @@ -388,6 +394,8 @@ public enum APITransportType { public static final String API_TYPE_SSE = "SSE"; public static final String API_TYPE_WEBHOOK = "WEBHOOK"; public static final String API_TYPE_WS = "WS"; + public static final String API_TYPE_GRAPHQL = "GRAPHQL"; + public static final String API_TYPE_SOAP = "SOAP"; public static final String API_ASYNC_API_DEFINITION_RESOURCE_NAME = "asyncapi.json"; diff --git a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/RegistryPersistenceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/RegistryPersistenceImpl.java index 3d49b9c429cd..dbd0900f19b6 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/RegistryPersistenceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/RegistryPersistenceImpl.java @@ -591,7 +591,42 @@ public PublisherAPI updateAPI(Organization org, PublisherAPI publisherAPI) throw RegistryPersistenceUtil.clearResourcePermissions(resourcePath, api.getId(), ((UserRegistry) registry).getTenantId()); RegistryPersistenceUtil.setResourcePermissions(api.getId().getProviderName(), api.getVisibility(), - visibleRoles, resourcePath); + visibleRoles, resourcePath, registry); + } + + // Update api def file permissions, required for API definition content search functionality + if (APIConstants.API_TYPE_GRAPHQL.equals(api.getType())) { + String resourcePath = RegistryPersistenceUtil.getOpenAPIDefinitionFilePath(api.getId().getName(), + api.getId().getVersion(), api.getId().getProviderName()); + resourcePath += api.getId().getProviderName() + APIConstants.GRAPHQL_SCHEMA_PROVIDER_SEPERATOR + + api.getId().getName() + api.getId().getVersion() + APIConstants.GRAPHQL_SCHEMA_FILE_EXTENSION; + if (registry.resourceExists(resourcePath)) { + RegistryPersistenceUtil.clearResourcePermissions(resourcePath, api.getId(), + ((UserRegistry) registry).getTenantId()); + RegistryPersistenceUtil.setResourcePermissions(api.getId().getProviderName(), api.getVisibility(), + visibleRoles, resourcePath, registry); + } + } else if (api.isAsync()) { + String resourcePath = RegistryPersistenceUtil.getOpenAPIDefinitionFilePath(api.getId().getName(), + api.getId().getVersion(), api.getId().getProviderName()); + resourcePath += APIConstants.API_ASYNC_API_DEFINITION_RESOURCE_NAME; + if (registry.resourceExists(resourcePath)) { + RegistryPersistenceUtil.clearResourcePermissions(resourcePath, api.getId(), + ((UserRegistry) registry).getTenantId()); + RegistryPersistenceUtil.setResourcePermissions(api.getId().getProviderName(), api.getVisibility(), + visibleRoles, resourcePath, registry); + } + } else if (APIConstants.API_TYPE_SOAP.equals(api.getType())) { + String resourcePath = RegistryPersistenceUtil.getOpenAPIDefinitionFilePath(api.getId().getName(), + api.getId().getVersion(), api.getId().getProviderName()); + resourcePath += api.getId().getProviderName() + APIConstants.WSDL_PROVIDER_SEPERATOR + + api.getId().getName() + api.getId().getVersion() + APIConstants.WSDL_FILE_EXTENSION; + if (registry.resourceExists(resourcePath)) { + RegistryPersistenceUtil.clearResourcePermissions(resourcePath, api.getId(), + ((UserRegistry) registry).getTenantId()); + RegistryPersistenceUtil.setResourcePermissions(api.getId().getProviderName(), api.getVisibility(), + visibleRoles, resourcePath, registry); + } } // doc visibility change @@ -1571,6 +1606,12 @@ public PublisherContentSearchResult searchContentForPublisher(Organization org, throw new GovernanceException("artifact id is null of " + apiPath); } + } else if (APIConstants.APPLICATION_JSON_MEDIA_TYPE.equals(resource.getMediaType()) || + APIConstants.GRAPHQL_DEFINITION_MEDIA_TYPE.equals(resource.getMediaType()) || + APIConstants.WSDL_XML_MEDIA_TYPE.equals(resource.getMediaType()) || + APIConstants.WSDL_FILE_MEDIA_TYPE.equals(resource.getMediaType())) { + + addAPIDefinitionSearchContent(resourcePath, registry, apiArtifactManager, contentData); } else { String apiArtifactId = resource.getUUID(); //API api; @@ -1671,7 +1712,8 @@ public DevPortalContentSearchResult searchContentForDevPortal(Organization org, .getRegistry(CarbonConstants.REGISTRY_SYSTEM_USERNAME, tenantId); ContentBasedSearchService contentBasedSearchService = new ContentBasedSearchService(); - SearchResultsBean resultsBean = contentBasedSearchService.searchByAttribute(attributes, systemUserRegistry); + SearchResultsBean resultsBean = contentBasedSearchService.searchByAttribute(attributes, + systemUserRegistry); String errorMsg = resultsBean.getErrorMessage(); if (errorMsg != null) { throw new APIPersistenceException("Error while searching " + errorMsg); @@ -1727,6 +1769,12 @@ public DevPortalContentSearchResult searchContentForDevPortal(Organization org, throw new GovernanceException("artifact id is null of " + apiPath); } + } else if (APIConstants.APPLICATION_JSON_MEDIA_TYPE.equals(resource.getMediaType()) || + APIConstants.GRAPHQL_DEFINITION_MEDIA_TYPE.equals(resource.getMediaType()) || + APIConstants.WSDL_XML_MEDIA_TYPE.equals(resource.getMediaType()) || + APIConstants.WSDL_FILE_MEDIA_TYPE.equals(resource.getMediaType())) { + + addAPIDefinitionSearchContent(resourcePath, registry, apiArtifactManager, contentData); } else { String apiArtifactId = resource.getUUID(); if (apiArtifactId != null) { @@ -1835,7 +1883,8 @@ public void saveWSDL(Organization org, String apiId, ResourceFile wsdlResourceFi if (visibleRolesList != null) { visibleRoles = visibleRolesList.split(","); } - RegistryPersistenceUtil.setResourcePermissions(apiProviderName, visibility, visibleRoles, wsdlResourcePath); + RegistryPersistenceUtil.setResourcePermissions(apiProviderName, visibility, visibleRoles, + wsdlResourcePath, registry); if (isZip) { //Delete any WSDL file if exists @@ -1986,7 +2035,8 @@ public void saveOASDefinition(Organization org, String apiId, String apiDefiniti // Need to set anonymous if the visibility is public RegistryPersistenceUtil.clearResourcePermissions(resourcePath, new APIIdentifier(apiProviderName, apiName, apiVersion), ((UserRegistry) registry).getTenantId()); - RegistryPersistenceUtil.setResourcePermissions(apiProviderName, visibility, visibleRolesArr, resourcePath); + RegistryPersistenceUtil.setResourcePermissions(apiProviderName, visibility, visibleRolesArr, + resourcePath, registry); } catch (RegistryException | APIPersistenceException | APIManagementException e) { throw new OASPersistenceException("Error while adding OSA Definition for " + apiId, e); @@ -2083,7 +2133,8 @@ public void saveAsyncDefinition(Organization org, String apiId, String apiDefini RegistryPersistenceUtil .clearResourcePermissions(resourcePath, new APIIdentifier(apiProviderName, apiName, apiVersion), ((UserRegistry) registry).getTenantId()); - RegistryPersistenceUtil.setResourcePermissions(apiProviderName, visibility, visibleRolesArr, resourcePath); + RegistryPersistenceUtil.setResourcePermissions(apiProviderName, visibility, visibleRolesArr, resourcePath + , registry); } catch (RegistryException | APIPersistenceException | APIManagementException e) { throw new AsyncSpecPersistenceException("Error while adding AsyncApi Definition for " + apiId, e); @@ -2174,7 +2225,7 @@ public void saveGraphQLSchemaDefinition(Organization org, String apiId, String s new APIIdentifier(api.apiProvider, api.apiName, api.apiVersion), ((UserRegistry) registry).getTenantId()); RegistryPersistenceUtil.setResourcePermissions(api.apiProvider, api.visibility, api.visibleRoles, - saveResourcePath); + saveResourcePath, registry); } catch (RegistryException | APIManagementException | APIPersistenceException e) { throw new GraphQLPersistenceException("Error while adding Graphql Definition for api " + apiId, e); @@ -3981,7 +4032,7 @@ public void updateSoapToRestSequences(Organization org, String apiId, List contentData) + throws APIPersistenceException, RegistryException { + APIDefSearchContent content = new APIDefSearchContent(); + int index; + + if (resourcePath.contains(APIConstants.API_ASYNC_API_DEFINITION_RESOURCE_NAME)) { + index = resourcePath.indexOf(APIConstants.API_ASYNC_API_DEFINITION_RESOURCE_NAME); + content.setApiType(APIDefSearchContent.ApiType.ASYNC); + } else if (resourcePath.contains(APIConstants.GRAPHQL_SCHEMA_FILE_EXTENSION)) { + index = resourcePath.lastIndexOf('/') + 1; + content.setApiType(APIDefSearchContent.ApiType.GRAPHQL); + } else if (resourcePath.contains(APIConstants.WSDL_FILE_EXTENSION)) { + index = resourcePath.lastIndexOf('/') + 1; + content.setApiType(APIDefSearchContent.ApiType.SOAP); + } else { + index = resourcePath.indexOf(APIConstants.API_OAS_DEFINITION_RESOURCE_NAME); + // swagger.json is included in all types of APIs, hence we need to properly set the API type + setAPITypeForSwagger(resourcePath, index, content, registry, apiArtifactManager); + } + + String apiPath = resourcePath.substring(0, index) + APIConstants.API_KEY; + Resource apiResource = registry.get(apiPath); + Resource defResource = registry.get(resourcePath); + String apiArtifactId = apiResource.getUUID(); + String defResourceId = defResource.getUUID(); + String defResourceName = defResource.getId().substring(defResource.getId().lastIndexOf('/') + 1); + DevPortalAPI devAPI; + + /* Ignore internal swagger.json content search results of non REST APIs + as most of the data is duplicated in WSDL, GraphQL, AsyncAPI def. */ + boolean ignoreDuplicateSwaggerContent = + (!APIDefSearchContent.ApiType.REST.toString().equals(content.getApiType()) + && defResourceName.contains("swagger")); + + if (apiArtifactId != null) { + if (!ignoreDuplicateSwaggerContent) { + GenericArtifact apiArtifact = apiArtifactManager.getGenericArtifact(apiArtifactId); + devAPI = RegistryPersistenceUtil.getDevPortalAPIForSearch(apiArtifact); + content.setId(defResourceId); + content.setName(defResourceName); + content.setApiUUID(devAPI.getId()); + content.setApiName(devAPI.getApiName()); + content.setApiContext(devAPI.getContext()); + content.setApiProvider(devAPI.getProviderName()); + content.setApiVersion(devAPI.getVersion()); + if (apiArtifact.getAttribute(APIConstants.API_OVERVIEW_TYPE) + .equals(APIConstants.AuditLogConstants.API_PRODUCT)) { + content.setAssociatedType(APIConstants.API_PRODUCT); + } else { + content.setAssociatedType(APIConstants.API); + } + contentData.add(content); + } + + } else { + throw new GovernanceException("artifact id is null of " + apiPath); + } + } + + /** + * This method is used to set the correct API Type for swagger.json as all API types have a swagger.json + * file in registry + * + * @param resourcePath registry resourcePath + * @param index int index + * @param content APIDefSearchContent obj. + * @param registry registry obj. + * @param artifactManager artifact manager + * @throws RegistryException on failure + */ + private void setAPITypeForSwagger(String resourcePath, int index, + APIDefSearchContent content, Registry registry, + GenericArtifactManager + artifactManager) throws RegistryException { + + String apiPath = resourcePath.substring(0, index) + APIConstants.API_KEY; + Resource apiResource = registry.get(apiPath); + String apiArtifactId = apiResource.getUUID(); + if (apiArtifactId != null) { + GenericArtifact artifact = artifactManager.getGenericArtifact(apiArtifactId); + String type = artifact.getAttribute(APIConstants.API_OVERVIEW_TYPE); + if (APIConstants.API_TYPE_SOAP.equals(type) || + APIConstants.API_TYPE_SOAPTOREST.equals(type)) { + content.setApiType(APIDefSearchContent.ApiType.SOAP); + } else if (APIConstants.API_TYPE_GRAPHQL.equals(type)) { + content.setApiType(APIDefSearchContent.ApiType.GRAPHQL); + } else if (APIConstants.API_TYPE_WS.equals(type) || + APIConstants.API_TYPE_WEBHOOK.equals(type) || + APIConstants.API_TYPE_SSE.equals(type) || + APIConstants.API_TYPE_WEBSUB.equals(type)) { + content.setApiType(APIDefSearchContent.ApiType.ASYNC); + } else { + content.setApiType(APIDefSearchContent.ApiType.REST); + } + } + } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/dto/APIDefSearchContent.java b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/dto/APIDefSearchContent.java new file mode 100644 index 000000000000..02baa8917e55 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/dto/APIDefSearchContent.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. 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.apimgt.persistence.dto; + +/** + * This hold swagger content search result content. + */ +public class APIDefSearchContent implements SearchContent { + + String id; + String type = "DEFINITION"; + String name; // Definition file name + String apiName; + String apiContext; + String apiVersion; + String apiProvider; + String apiUUID; + String apiRating; + ApiType apiType; + String associatedType = "API"; + + /** + * Holds different API Types for content search. + */ + public enum ApiType { + REST, + ASYNC, + GRAPHQL, + SOAP + } + + @Override + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getApiName() { + return apiName; + } + + public void setApiName(String apiName) { + this.apiName = apiName; + } + + public String getApiVersion() { + return apiVersion; + } + + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + + public String getApiProvider() { + return apiProvider; + } + + public void setApiProvider(String apiProvider) { + this.apiProvider = apiProvider; + } + + public String getApiUUID() { + return apiUUID; + } + + public void setApiUUID(String apiUUID) { + this.apiUUID = apiUUID; + } + + public String getAssociatedType() { + return associatedType; + } + + public void setAssociatedType(String associatedType) { + this.associatedType = associatedType; + } + + public String getApiType() { + if (apiType == null) { + return null; + } + return apiType.toString(); + } + + public void setApiType(ApiType apiType) { + this.apiType = apiType; + } + + public String getApiContext() { + return apiContext; + } + + public void setApiContext(String apiContext) { + this.apiContext = apiContext; + } + + public String getApiRating() { + return apiRating; + } + + public void setApiRating(String apiRating) { + this.apiRating = apiRating; + } +} diff --git a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/utils/RegistrySearchUtil.java b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/utils/RegistrySearchUtil.java index 7d95b95cc65d..7b8f51bb7a09 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/utils/RegistrySearchUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.persistence/src/main/java/org/wso2/carbon/apimgt/persistence/utils/RegistrySearchUtil.java @@ -39,6 +39,7 @@ import static org.wso2.carbon.apimgt.persistence.APIConstants.API_GLOBAL_VISIBILITY; import static org.wso2.carbon.apimgt.persistence.APIConstants.API_OVERVIEW_KEY_MANAGERS; import static org.wso2.carbon.apimgt.persistence.APIConstants.API_OVERVIEW_VISIBILITY; +import static org.wso2.carbon.apimgt.persistence.APIConstants.APPLICATION_JSON_MEDIA_TYPE; public class RegistrySearchUtil { @@ -53,15 +54,27 @@ public class RegistrySearchUtil { public static final String API_STATUS = "STATUS"; public static final String API_PROVIDER = "Provider"; public static final String DOCUMENT_INDEXER = "org.wso2.carbon.apimgt.impl.indexing.indexer.DocumentIndexer"; + public static final String REST_ASYNC_API_DEFINITION_INDEXER = "org.wso2.carbon.apimgt.impl.indexing.indexer" + + ".RESTAsyncAPIDefinitionIndexer"; + public static final String GRAPHQL_DEFINITION_INDEXER = "org.wso2.carbon.apimgt.impl.indexing.indexer" + + ".GraphQLAPIDefinitionIndexer"; + public static final String SOAP_DEFINITION_INDEXER = "org.wso2.carbon.apimgt.impl.indexing.indexer" + + ".SOAPAPIDefinitionIndexer"; public static final String STORE_VIEW_ROLES = "store_view_roles"; public static final String PUBLISHER_ROLES = "publisher_roles"; public static final String DOCUMENT_MEDIA_TYPE_KEY = "application/vnd.wso2-document\\+xml"; - public static final String DOCUMENT_INDEXER_INDICATOR = "document_indexed"; - public static final String DOCUMENTATION_SEARCH_MEDIA_TYPE_FIELD = "mediaType"; + public static final String API_DEF_MEDIA_TYPE_KEY = "application/json"; + public static final String GRAPHQL_DEF_MEDIA_TYPE_KEY = "text/plain(.)+charset=ISO-8859-1"; + public static final String SOAP_DEF_MEDIA_TYPE_KEY = "application/wsdl\\+xml|application/octet-stream"; + public static final String SEARCH_MEDIA_TYPE_FIELD = "mediaType"; public static final String DOCUMENTATION_INLINE_CONTENT_TYPE = "text/plain"; public static final String API_RXT_MEDIA_TYPE = "application/vnd.wso2-api+xml"; public static final String LCSTATE_SEARCH_KEY = "lcState"; public static final String DOCUMENT_RXT_MEDIA_TYPE = "application/vnd.wso2-document+xml"; + public static final String GRAPHQL_DEFINITION_MEDIA_TYPE = "text/plain; charset=ISO-8859-1"; + public static final String SOAP_DEFINITION_WSDL_XML_MEDIA_TYPE = "application/wsdl+xml"; + public static final String SOAP_DEFINITION_WSDL_FILE_MEDIA_TYPE = "application/octet-stream"; + public static final String API_OVERVIEW_STATUS = "overview_status"; public static final String API_RELATED_CUSTOM_PROPERTIES_PREFIX = "api_meta."; public static final String API_RELATED_CUSTOM_PROPERTIES_DISPLAY_DEV = "__display"; @@ -250,33 +263,61 @@ private static Map getSearchAttributes(String searchQuery) { RegistryConfigLoader registryConfig = RegistryConfigLoader.getInstance(); Map indexerMap = registryConfig.getIndexerMap(); Indexer documentIndexer = indexerMap.get(DOCUMENT_MEDIA_TYPE_KEY); - String complexAttribute; + Indexer jsonIndexer = indexerMap.get(API_DEF_MEDIA_TYPE_KEY); + Indexer graphqlIndexer = indexerMap.get(GRAPHQL_DEF_MEDIA_TYPE_KEY); + Indexer soapIndexer = indexerMap.get(SOAP_DEF_MEDIA_TYPE_KEY); + String complexAttribute = ClientUtils.escapeQueryChars(API_RXT_MEDIA_TYPE); + if (!StringUtils.isEmpty(publisherRoles)) { + complexAttribute = + "(" + ClientUtils.escapeQueryChars(API_RXT_MEDIA_TYPE) + " AND publisher_roles_ss:" + + publisherRoles + ")"; + } + if (documentIndexer != null && DOCUMENT_INDEXER.equals(documentIndexer.getClass().getName())) { - //field check on document_indexed was added to prevent unindexed(by new DocumentIndexer) from coming up as search results - //on indexed documents this property is always set to true - complexAttribute = ClientUtils.escapeQueryChars(API_RXT_MEDIA_TYPE) + " OR mediaType_s:(" + ClientUtils - .escapeQueryChars(DOCUMENT_RXT_MEDIA_TYPE) + " AND document_indexed_s:true)"; + if (!StringUtils.isEmpty(publisherRoles)) { + complexAttribute += " OR mediaType_s:(" + ClientUtils + .escapeQueryChars(DOCUMENT_RXT_MEDIA_TYPE) + " AND publisher_roles_s:" + publisherRoles + ")"; + } else { + complexAttribute += " OR mediaType_s:(" + ClientUtils + .escapeQueryChars(DOCUMENT_RXT_MEDIA_TYPE) + " AND document_indexed_s:true)"; + } + } - //construct query such that publisher roles is checked in properties for api artifacts and in fields for document artifacts - //this was designed this way so that content search can be fully functional if registry is re-indexed after engaging DocumentIndexer + if (jsonIndexer != null && REST_ASYNC_API_DEFINITION_INDEXER.equals(jsonIndexer.getClass().getName())) { if (!StringUtils.isEmpty(publisherRoles)) { - complexAttribute = - "(" + ClientUtils.escapeQueryChars(API_RXT_MEDIA_TYPE) + " AND publisher_roles_ss:" - + publisherRoles + ") OR mediaType_s:(" + ClientUtils - .escapeQueryChars(DOCUMENT_RXT_MEDIA_TYPE) + " AND publisher_roles_s:" + publisherRoles + ")"; + complexAttribute += " OR mediaType_s:(" + ClientUtils + .escapeQueryChars(APPLICATION_JSON_MEDIA_TYPE) + " AND publisher_roles_s:" + publisherRoles + ")"; + } else { + complexAttribute += " OR mediaType_s:(" + ClientUtils + .escapeQueryChars(APPLICATION_JSON_MEDIA_TYPE) + " AND document_indexed_s:true)"; } - } else { - //document indexer required for document content search is not engaged, therefore carry out the search only for api artifact contents - complexAttribute = ClientUtils.escapeQueryChars(API_RXT_MEDIA_TYPE); + } + + if (graphqlIndexer != null && GRAPHQL_DEFINITION_INDEXER.equals(graphqlIndexer.getClass().getName())) { if (!StringUtils.isEmpty(publisherRoles)) { - complexAttribute = - "(" + ClientUtils.escapeQueryChars(API_RXT_MEDIA_TYPE) + " AND publisher_roles_ss:" - + publisherRoles + ")"; + complexAttribute += " OR mediaType_s:(" + ClientUtils + .escapeQueryChars(GRAPHQL_DEFINITION_MEDIA_TYPE) + " AND publisher_roles_s:" + publisherRoles + ")"; + } else { + complexAttribute += " OR mediaType_s:(" + ClientUtils + .escapeQueryChars(GRAPHQL_DEFINITION_MEDIA_TYPE) + " AND document_indexed_s:true)"; } } + if (soapIndexer != null && SOAP_DEFINITION_INDEXER.equals(soapIndexer.getClass().getName())) { + if (!StringUtils.isEmpty(publisherRoles)) { + complexAttribute += " OR mediaType_s:((" + ClientUtils + .escapeQueryChars(SOAP_DEFINITION_WSDL_XML_MEDIA_TYPE) + + " OR " + ClientUtils.escapeQueryChars(SOAP_DEFINITION_WSDL_FILE_MEDIA_TYPE) + + " ) AND publisher_roles_s:" + publisherRoles + ")"; + } else { + complexAttribute += " OR mediaType_s:((" + ClientUtils + .escapeQueryChars(SOAP_DEFINITION_WSDL_XML_MEDIA_TYPE) + + " OR " + ClientUtils.escapeQueryChars(SOAP_DEFINITION_WSDL_FILE_MEDIA_TYPE) + + " ) AND document_indexed_s:true)"; + } + } - attributes.put(DOCUMENTATION_SEARCH_MEDIA_TYPE_FIELD, complexAttribute); + attributes.put(SEARCH_MEDIA_TYPE_FIELD, complexAttribute); attributes.put(API_OVERVIEW_STATUS, apiState); return attributes; } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/pom.xml index 7a5e12c7e6d4..b9f741d3d733 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.admin.v1/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/pom.xml index 22805d745d11..b5cedc73780f 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/pom.xml @@ -17,7 +17,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/devportal-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/devportal-api.yaml index 719eaeabc837..0bf5ad70abad 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/devportal-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.common/src/main/resources/devportal-api.yaml @@ -5342,6 +5342,7 @@ components: - DOC - API - APIProduct + - DEFINITION transportType: type: string description: Accepted values are HTTP, WS, SOAPTOREST, GRAPHQL @@ -5442,6 +5443,38 @@ components: example: admin apiUUID: type: string + APIDefinitionSearchResult: + title: API Definition Search Result + allOf: + - $ref: '#/components/schemas/SearchResult' + - properties: + apiName: + type: string + description: The name of the associated API + example: TestAPI + apiVersion: + type: string + description: The version of the associated API + example: 1.0.0 + apiContext: + type: string + description: The context of the associated API + example: /test + apiUUID: + type: string + description: The UUID of the associated API + apiProvider: + type: string + description: The provider name of the associated API + example: publisher + apiType: + type: string + description: The type of the associated API + example: REST + associatedType: + type: string + description: API or APIProduct + example: API CommenterInfo: type: object properties: 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 e55e6865f9b6..d25b133d4465 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 @@ -4014,6 +4014,12 @@ paths: schema: type: boolean default: false + - name: gatewayEnvironment + in: query + description: | + Gateway environment of the exported APIs + schema: + type: string responses: 200: description: | @@ -10370,6 +10376,7 @@ components: displayOnDevportal: type: boolean example: true + default: true deployedTime: readOnly: true type: string @@ -12599,6 +12606,7 @@ components: - DOC - API - APIProduct + - DEFINITION transportType: type: string description: Accepted values are HTTP, WS, SOAPTOREST, GRAPHQL @@ -12783,6 +12791,38 @@ components: type: string associatedType: type: string + APIDefinitionSearchResult: + title: API Definition Search Result + allOf: + - $ref: '#/components/schemas/SearchResult' + - properties: + apiName: + type: string + description: The name of the associated API + example: TestAPI + apiVersion: + type: string + description: The version of the associated API + example: 1.0.0 + apiContext: + type: string + description: The context of the associated API + example: /test + apiUUID: + type: string + description: The UUID of the associated API + apiProvider: + type: string + description: The provider name of the associated API + example: publisher + apiType: + type: string + description: The type of the associated API + example: REST + associatedType: + type: string + description: API or APIProduct + example: API MockResponsePayloadList: title: Mock Response Payload list type: object @@ -12939,6 +12979,11 @@ components: IsJWTEnabledForLoginTokens: type: boolean default: false + allowSubscriptionValidationDisabling: + type: boolean + description: | + Allow subscription validation disabling for OAuth tokens + default: true customProperties: type: array items: diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.dcr/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.dcr/pom.xml index 9762ee6d9e70..bd4a6fb0c774 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.dcr/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.dcr/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.devops/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.devops/pom.xml index 53f2c1334e33..cc1ea0119616 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.devops/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.devops/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.gateway/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.gateway/pom.xml index 2d9441c6f461..92f397112b61 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.gateway/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.gateway/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/pom.xml index 50c8363fc537..a1c3ddc461c4 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIDefinitionSearchResultAllOfDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIDefinitionSearchResultAllOfDTO.java new file mode 100644 index 000000000000..16b275098de6 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIDefinitionSearchResultAllOfDTO.java @@ -0,0 +1,208 @@ +package org.wso2.carbon.apimgt.rest.api.publisher.v1.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; + +import javax.xml.bind.annotation.*; +import org.wso2.carbon.apimgt.rest.api.common.annotations.Scope; +import com.fasterxml.jackson.annotation.JsonCreator; + +import javax.validation.Valid; + + + +public class APIDefinitionSearchResultAllOfDTO { + + private String apiName = null; + private String apiVersion = null; + private String apiContext = null; + private String apiUUID = null; + private String apiProvider = null; + private String apiType = null; + private String associatedType = null; + + /** + * The name of the associated API + **/ + public APIDefinitionSearchResultAllOfDTO apiName(String apiName) { + this.apiName = apiName; + return this; + } + + + @ApiModelProperty(example = "TestAPI", value = "The name of the associated API") + @JsonProperty("apiName") + public String getApiName() { + return apiName; + } + public void setApiName(String apiName) { + this.apiName = apiName; + } + + /** + * The version of the associated API + **/ + public APIDefinitionSearchResultAllOfDTO apiVersion(String apiVersion) { + this.apiVersion = apiVersion; + return this; + } + + + @ApiModelProperty(example = "1.0.0", value = "The version of the associated API") + @JsonProperty("apiVersion") + public String getApiVersion() { + return apiVersion; + } + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + + /** + * The context of the associated API + **/ + public APIDefinitionSearchResultAllOfDTO apiContext(String apiContext) { + this.apiContext = apiContext; + return this; + } + + + @ApiModelProperty(example = "/test", value = "The context of the associated API") + @JsonProperty("apiContext") + public String getApiContext() { + return apiContext; + } + public void setApiContext(String apiContext) { + this.apiContext = apiContext; + } + + /** + * The UUID of the associated API + **/ + public APIDefinitionSearchResultAllOfDTO apiUUID(String apiUUID) { + this.apiUUID = apiUUID; + return this; + } + + + @ApiModelProperty(value = "The UUID of the associated API") + @JsonProperty("apiUUID") + public String getApiUUID() { + return apiUUID; + } + public void setApiUUID(String apiUUID) { + this.apiUUID = apiUUID; + } + + /** + * The provider name of the associated API + **/ + public APIDefinitionSearchResultAllOfDTO apiProvider(String apiProvider) { + this.apiProvider = apiProvider; + return this; + } + + + @ApiModelProperty(example = "publisher", value = "The provider name of the associated API") + @JsonProperty("apiProvider") + public String getApiProvider() { + return apiProvider; + } + public void setApiProvider(String apiProvider) { + this.apiProvider = apiProvider; + } + + /** + * The type of the associated API + **/ + public APIDefinitionSearchResultAllOfDTO apiType(String apiType) { + this.apiType = apiType; + return this; + } + + + @ApiModelProperty(example = "REST", value = "The type of the associated API") + @JsonProperty("apiType") + public String getApiType() { + return apiType; + } + public void setApiType(String apiType) { + this.apiType = apiType; + } + + /** + * API or APIProduct + **/ + public APIDefinitionSearchResultAllOfDTO associatedType(String associatedType) { + this.associatedType = associatedType; + return this; + } + + + @ApiModelProperty(example = "API", value = "API or APIProduct") + @JsonProperty("associatedType") + public String getAssociatedType() { + return associatedType; + } + public void setAssociatedType(String associatedType) { + this.associatedType = associatedType; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + APIDefinitionSearchResultAllOfDTO apIDefinitionSearchResultAllOf = (APIDefinitionSearchResultAllOfDTO) o; + return Objects.equals(apiName, apIDefinitionSearchResultAllOf.apiName) && + Objects.equals(apiVersion, apIDefinitionSearchResultAllOf.apiVersion) && + Objects.equals(apiContext, apIDefinitionSearchResultAllOf.apiContext) && + Objects.equals(apiUUID, apIDefinitionSearchResultAllOf.apiUUID) && + Objects.equals(apiProvider, apIDefinitionSearchResultAllOf.apiProvider) && + Objects.equals(apiType, apIDefinitionSearchResultAllOf.apiType) && + Objects.equals(associatedType, apIDefinitionSearchResultAllOf.associatedType); + } + + @Override + public int hashCode() { + return Objects.hash(apiName, apiVersion, apiContext, apiUUID, apiProvider, apiType, associatedType); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class APIDefinitionSearchResultAllOfDTO {\n"); + + sb.append(" apiName: ").append(toIndentedString(apiName)).append("\n"); + sb.append(" apiVersion: ").append(toIndentedString(apiVersion)).append("\n"); + sb.append(" apiContext: ").append(toIndentedString(apiContext)).append("\n"); + sb.append(" apiUUID: ").append(toIndentedString(apiUUID)).append("\n"); + sb.append(" apiProvider: ").append(toIndentedString(apiProvider)).append("\n"); + sb.append(" apiType: ").append(toIndentedString(apiType)).append("\n"); + sb.append(" associatedType: ").append(toIndentedString(associatedType)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIDefinitionSearchResultDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIDefinitionSearchResultDTO.java new file mode 100644 index 000000000000..00bf73e57c5b --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIDefinitionSearchResultDTO.java @@ -0,0 +1,210 @@ +package org.wso2.carbon.apimgt.rest.api.publisher.v1.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.wso2.carbon.apimgt.rest.api.publisher.v1.dto.APIDefinitionSearchResultAllOfDTO; +import org.wso2.carbon.apimgt.rest.api.publisher.v1.dto.SearchResultDTO; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; + +import javax.xml.bind.annotation.*; +import org.wso2.carbon.apimgt.rest.api.common.annotations.Scope; +import com.fasterxml.jackson.annotation.JsonCreator; + +import javax.validation.Valid; + + + +public class APIDefinitionSearchResultDTO extends SearchResultDTO { + + private String apiName = null; + private String apiVersion = null; + private String apiContext = null; + private String apiUUID = null; + private String apiProvider = null; + private String apiType = null; + private String associatedType = null; + + /** + * The name of the associated API + **/ + public APIDefinitionSearchResultDTO apiName(String apiName) { + this.apiName = apiName; + return this; + } + + + @ApiModelProperty(example = "TestAPI", value = "The name of the associated API") + @JsonProperty("apiName") + public String getApiName() { + return apiName; + } + public void setApiName(String apiName) { + this.apiName = apiName; + } + + /** + * The version of the associated API + **/ + public APIDefinitionSearchResultDTO apiVersion(String apiVersion) { + this.apiVersion = apiVersion; + return this; + } + + + @ApiModelProperty(example = "1.0.0", value = "The version of the associated API") + @JsonProperty("apiVersion") + public String getApiVersion() { + return apiVersion; + } + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + + /** + * The context of the associated API + **/ + public APIDefinitionSearchResultDTO apiContext(String apiContext) { + this.apiContext = apiContext; + return this; + } + + + @ApiModelProperty(example = "/test", value = "The context of the associated API") + @JsonProperty("apiContext") + public String getApiContext() { + return apiContext; + } + public void setApiContext(String apiContext) { + this.apiContext = apiContext; + } + + /** + * The UUID of the associated API + **/ + public APIDefinitionSearchResultDTO apiUUID(String apiUUID) { + this.apiUUID = apiUUID; + return this; + } + + + @ApiModelProperty(value = "The UUID of the associated API") + @JsonProperty("apiUUID") + public String getApiUUID() { + return apiUUID; + } + public void setApiUUID(String apiUUID) { + this.apiUUID = apiUUID; + } + + /** + * The provider name of the associated API + **/ + public APIDefinitionSearchResultDTO apiProvider(String apiProvider) { + this.apiProvider = apiProvider; + return this; + } + + + @ApiModelProperty(example = "publisher", value = "The provider name of the associated API") + @JsonProperty("apiProvider") + public String getApiProvider() { + return apiProvider; + } + public void setApiProvider(String apiProvider) { + this.apiProvider = apiProvider; + } + + /** + * The type of the associated API + **/ + public APIDefinitionSearchResultDTO apiType(String apiType) { + this.apiType = apiType; + return this; + } + + + @ApiModelProperty(example = "REST", value = "The type of the associated API") + @JsonProperty("apiType") + public String getApiType() { + return apiType; + } + public void setApiType(String apiType) { + this.apiType = apiType; + } + + /** + * API or APIProduct + **/ + public APIDefinitionSearchResultDTO associatedType(String associatedType) { + this.associatedType = associatedType; + return this; + } + + + @ApiModelProperty(example = "API", value = "API or APIProduct") + @JsonProperty("associatedType") + public String getAssociatedType() { + return associatedType; + } + public void setAssociatedType(String associatedType) { + this.associatedType = associatedType; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + APIDefinitionSearchResultDTO apIDefinitionSearchResult = (APIDefinitionSearchResultDTO) o; + return Objects.equals(apiName, apIDefinitionSearchResult.apiName) && + Objects.equals(apiVersion, apIDefinitionSearchResult.apiVersion) && + Objects.equals(apiContext, apIDefinitionSearchResult.apiContext) && + Objects.equals(apiUUID, apIDefinitionSearchResult.apiUUID) && + Objects.equals(apiProvider, apIDefinitionSearchResult.apiProvider) && + Objects.equals(apiType, apIDefinitionSearchResult.apiType) && + Objects.equals(associatedType, apIDefinitionSearchResult.associatedType); + } + + @Override + public int hashCode() { + return Objects.hash(apiName, apiVersion, apiContext, apiUUID, apiProvider, apiType, associatedType); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class APIDefinitionSearchResultDTO {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append(" apiName: ").append(toIndentedString(apiName)).append("\n"); + sb.append(" apiVersion: ").append(toIndentedString(apiVersion)).append("\n"); + sb.append(" apiContext: ").append(toIndentedString(apiContext)).append("\n"); + sb.append(" apiUUID: ").append(toIndentedString(apiUUID)).append("\n"); + sb.append(" apiProvider: ").append(toIndentedString(apiProvider)).append("\n"); + sb.append(" apiType: ").append(toIndentedString(apiType)).append("\n"); + sb.append(" associatedType: ").append(toIndentedString(associatedType)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIRevisionDeploymentDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIRevisionDeploymentDTO.java index ec1698c34b9c..21c6add149c5 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIRevisionDeploymentDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/APIRevisionDeploymentDTO.java @@ -56,7 +56,7 @@ public static StatusEnum fromValue(String v) { } private StatusEnum status = StatusEnum.CREATED; private String vhost = null; - private Boolean displayOnDevportal = null; + private Boolean displayOnDevportal = true; private java.util.Date deployedTime = null; private java.util.Date successDeployedTime = null; diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/SearchResultDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/SearchResultDTO.java index 5c057ee3f5cd..595a12016561 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/SearchResultDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/SearchResultDTO.java @@ -30,7 +30,8 @@ public class SearchResultDTO { public enum TypeEnum { DOC("DOC"), API("API"), - APIPRODUCT("APIProduct"); + APIPRODUCT("APIProduct"), + DEFINITION("DEFINITION"); private String value; TypeEnum (String v) { diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/SettingsDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/SettingsDTO.java index fd6c63149aaf..f69594c374d8 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/SettingsDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1.common/src/gen/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/dto/SettingsDTO.java @@ -41,6 +41,7 @@ public class SettingsDTO { private String defaultSubscriptionPolicy = null; private String authorizationHeader = null; private Boolean isJWTEnabledForLoginTokens = false; + private Boolean allowSubscriptionValidationDisabling = true; private List customProperties = new ArrayList(); /** @@ -310,6 +311,24 @@ public void setIsJWTEnabledForLoginTokens(Boolean isJWTEnabledForLoginTokens) { this.isJWTEnabledForLoginTokens = isJWTEnabledForLoginTokens; } + /** + * Allow subscription validation disabling for OAuth tokens + **/ + public SettingsDTO allowSubscriptionValidationDisabling(Boolean allowSubscriptionValidationDisabling) { + this.allowSubscriptionValidationDisabling = allowSubscriptionValidationDisabling; + return this; + } + + + @ApiModelProperty(value = "Allow subscription validation disabling for OAuth tokens ") + @JsonProperty("allowSubscriptionValidationDisabling") + public Boolean isAllowSubscriptionValidationDisabling() { + return allowSubscriptionValidationDisabling; + } + public void setAllowSubscriptionValidationDisabling(Boolean allowSubscriptionValidationDisabling) { + this.allowSubscriptionValidationDisabling = allowSubscriptionValidationDisabling; + } + /** **/ public SettingsDTO customProperties(List customProperties) { @@ -353,12 +372,13 @@ public boolean equals(java.lang.Object o) { Objects.equals(defaultSubscriptionPolicy, settings.defaultSubscriptionPolicy) && Objects.equals(authorizationHeader, settings.authorizationHeader) && Objects.equals(isJWTEnabledForLoginTokens, settings.isJWTEnabledForLoginTokens) && + Objects.equals(allowSubscriptionValidationDisabling, settings.allowSubscriptionValidationDisabling) && Objects.equals(customProperties, settings.customProperties); } @Override public int hashCode() { - return Objects.hash(devportalUrl, environment, gatewayTypes, scopes, monetizationAttributes, subscriberContactAttributes, securityAuditProperties, externalStoresEnabled, docVisibilityEnabled, portalConfigurationOnlyModeEnabled, crossTenantSubscriptionEnabled, defaultAdvancePolicy, defaultSubscriptionPolicy, authorizationHeader, isJWTEnabledForLoginTokens, customProperties); + return Objects.hash(devportalUrl, environment, gatewayTypes, scopes, monetizationAttributes, subscriberContactAttributes, securityAuditProperties, externalStoresEnabled, docVisibilityEnabled, portalConfigurationOnlyModeEnabled, crossTenantSubscriptionEnabled, defaultAdvancePolicy, defaultSubscriptionPolicy, authorizationHeader, isJWTEnabledForLoginTokens, allowSubscriptionValidationDisabling, customProperties); } @Override @@ -381,6 +401,7 @@ public String toString() { sb.append(" defaultSubscriptionPolicy: ").append(toIndentedString(defaultSubscriptionPolicy)).append("\n"); sb.append(" authorizationHeader: ").append(toIndentedString(authorizationHeader)).append("\n"); sb.append(" isJWTEnabledForLoginTokens: ").append(toIndentedString(isJWTEnabledForLoginTokens)).append("\n"); + sb.append(" allowSubscriptionValidationDisabling: ").append(toIndentedString(allowSubscriptionValidationDisabling)).append("\n"); sb.append(" customProperties: ").append(toIndentedString(customProperties)).append("\n"); sb.append("}"); return sb.toString(); 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/ImportExportAPIServiceImpl.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/ImportExportAPIServiceImpl.java index 050efd549c32..7a19f1c7b37c 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/ImportExportAPIServiceImpl.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/ImportExportAPIServiceImpl.java @@ -203,7 +203,8 @@ public ImportedAPIDTO importAPI(InputStream fileInputStream, Boolean preservePro try { extractedFolderPath = ImportUtils.getArchivePathOfExtractedDirectory(fileInputStream); } catch (APIImportExportException e) { - throw new APIManagementException(e); + throw new APIManagementException("Error extracting and processing the directory", e, + ExceptionCodes.ERROR_PROCESSING_DIRECTORY_TO_IMPORT); } return ImportUtils.importApi(extractedFolderPath, null, preserveProvider, rotateRevision, overwrite, preservePortalConfigurations, false, tokenScopes, null, organization); @@ -220,7 +221,8 @@ public APIProduct importAPIProduct(InputStream fileInputStream, Boolean preserve try { extractedFolderPath = ImportUtils.getArchivePathOfExtractedDirectory(fileInputStream); } catch (APIImportExportException e) { - throw new APIManagementException(e); + throw new APIManagementException("Error extracting and processing the directory", e, + ExceptionCodes.ERROR_PROCESSING_DIRECTORY_TO_IMPORT); } return ImportUtils.importApiProduct(extractedFolderPath, preserveProvider, rotateRevision, overwriteAPIProduct, overwriteAPIs, importAPIs, tokenScopes, 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/ExportUtils.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/ExportUtils.java index c318151d3d2e..1c89b95b2cc1 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/ExportUtils.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/ExportUtils.java @@ -982,6 +982,11 @@ public static void addAPIMetaInformationToArchive(String archivePath, APIDTO api + apiDtoToReturn.getVersion()); } } + List tiers = apiDtoToReturn.getPolicies(); + if (tiers != null && tiers.size() == 1 + && tiers.get(0).contains(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS)) { + apiDtoToReturn.setPolicies(new ArrayList<>()); + } Gson gson = new GsonBuilder().setPrettyPrinting().create(); JsonElement apiObj = gson.toJsonTree(apiDtoToReturn); JsonObject apiJson = (JsonObject) apiObj; 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 46f9bce00d0e..71646c2243fc 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 @@ -234,6 +234,7 @@ public static ImportedAPIDTO importApi(String extractedFolderPath, APIDTO import } String apiType = importedApiDTO.getType().toString(); + boolean asyncAPI = PublisherCommonUtils.isStreamingAPI(importedApiDTO); // Validate swagger content except for streaming APIs if (!PublisherCommonUtils.isStreamingAPI(importedApiDTO) @@ -341,6 +342,21 @@ public static ImportedAPIDTO importApi(String extractedFolderPath, APIDTO import // Initialize to CREATED when import currentStatus = APIStatus.CREATED.toString(); importedApiDTO.setLifeCycleStatus(currentStatus); + if (APIStatus.PUBLISHED.toString().equalsIgnoreCase(targetStatus) + && importedApiDTO.getPolicies() != null + && importedApiDTO.getPolicies().isEmpty() + && importedApiDTO.getSecurityScheme() != null + && importedApiDTO.getSecurityScheme().contains(APIConstants.DEFAULT_API_SECURITY_OAUTH2) + && APIUtil.isSubscriptionValidationDisablingAllowed(organization) + && !PublisherCommonUtils.isThirdPartyAsyncAPI(importedApiDTO)) { + if (asyncAPI) { + importedApiDTO.setPolicies(Arrays + .asList(APIConstants.DEFAULT_SUB_POLICY_ASYNC_SUBSCRIPTIONLESS)); + } else { + importedApiDTO.setPolicies(Arrays + .asList(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS)); + } + } if (!PublisherCommonUtils.isThirdPartyAsyncAPI(importedApiDTO)) { importedApi = PublisherCommonUtils .addAPIWithGeneratedSwaggerDefinition(importedApiDTO, ImportExportConstants.OAS_VERSION_3, @@ -901,8 +917,10 @@ private static List getValidatedDeploymentsList(JsonArray } else { // set the default vhost of the given environment if (gatewayEnvironment.getVhosts().isEmpty()) { - throw new APIManagementException("No VHosts defined for the environment: " - + deploymentName); + throw new APIManagementException( + "No VHosts defined for the environment: " + deploymentName, + ExceptionCodes.from(ExceptionCodes.NO_VHOSTS_DEFINED_FOR_ENVIRONMENT, + deploymentName)); } deploymentVhost = gatewayEnvironment.getVhosts().get(0).getHost(); } @@ -1496,9 +1514,11 @@ public static APIDefinitionValidationResponse retrieveValidatedAsyncApiDefinitio APIDefinitionValidationResponse validationResponse = AsyncApiParserUtil.validateAsyncAPISpecification(asyncApiDefinition, true); if (!validationResponse.isValid()) { - throw new APIManagementException( - "Error occurred while importing the API. Invalid AsyncAPI definition found. " - + validationResponse.getErrorItems()); + String errorMessage = "Error occurred while importing the API. Invalid AsyncAPI definition found. " + + validationResponse.getErrorItems(); + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.IMPORT_ERROR_INVALID_ASYNC_API_SCHEMA, + StringUtils.join(validationResponse.getErrorItems(), ", "))); } return validationResponse; } catch (IOException e) { @@ -1543,9 +1563,11 @@ public static GraphQLValidationResponseDTO retrieveValidatedGraphqlSchemaFromArc GraphQLValidationResponseDTO graphQLValidationResponseDTO = PublisherCommonUtils .validateGraphQLSchema(file.getName(), schemaDefinition); if (!graphQLValidationResponseDTO.isIsValid()) { - throw new APIManagementException( - "Error occurred while importing the API. Invalid GraphQL schema definition found. " - + graphQLValidationResponseDTO.getErrorMessage()); + String errorMessage = "Error occurred while importing the API. Invalid GraphQL schema definition " + + "found. " + graphQLValidationResponseDTO.getErrorMessage(); + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.IMPORT_ERROR_INVALID_GRAPHQL_SCHEMA, + graphQLValidationResponseDTO.getErrorMessage())); } return graphQLValidationResponseDTO; } catch (IOException e) { @@ -2595,6 +2617,16 @@ public static APIProduct importApiProduct(String extractedFolderPath, Boolean pr log.info("Cannot find : " + importedApiProductDTO.getName() + ". Creating it."); } currentStatus = APIStatus.CREATED.toString(); + if (APIStatus.PUBLISHED.toString().equalsIgnoreCase(targetStatus) + && importedApiProductDTO.getPolicies() != null + && importedApiProductDTO.getPolicies().isEmpty() + && importedApiProductDTO.getSecurityScheme() != null + && importedApiProductDTO.getSecurityScheme().contains(APIConstants.DEFAULT_API_SECURITY_OAUTH2) + && APIUtil.isSubscriptionValidationDisablingAllowed(organization)) { + importedApiProductDTO.setPolicies(Arrays + .asList(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS)); + + } importedApiProduct = PublisherCommonUtils .addAPIProductWithGeneratedSwaggerDefinition(importedApiProductDTO, importedApiProductDTO.getProvider(), organization); @@ -2670,7 +2702,7 @@ public static APIProduct importApiProduct(String extractedFolderPath, Boolean pr importedApiProduct.getId().getVersion()); } } else { - throw new APIManagementException(e); + throw e; } } @@ -2762,8 +2794,14 @@ private static void checkAPIProductResourcesValid(String path, String currentUse // Product does not have corresponding API resources neither inside the importing directory nor // inside the APIM if (!invalidApiOperations.isEmpty()) { - throw new APIMgtResourceNotFoundException( - "Cannot find API resources for some API Product resources."); + List invalidOperationList = new ArrayList(); + for (APIOperationsDTO dto : invalidApiOperations) { + invalidOperationList.add(dto.getVerb() + ":" + dto.getTarget()); + } + String errorMessage = "Cannot find API resources for some API Product resources."; + throw new APIMgtResourceNotFoundException(errorMessage, + ExceptionCodes.from(ExceptionCodes.INVALID_API_RESOURCES_FOR_API_PRODUCT, + StringUtils.join(invalidOperationList, ", "))); } } } 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 aec3f04df15d..3afdb47196bb 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 @@ -344,16 +344,53 @@ private static API prepareForUpdateApi(API originalAPI, APIDTO apiDtoToUpdate, A List apiSecurity = apiDtoToUpdate.getSecurityScheme(); //validation for tiers List tiersFromDTO = apiDtoToUpdate.getPolicies(); + // Remove the subscriptionless tier if other tiers are available. + if (tiersFromDTO != null && tiersFromDTO.size() > 1) { + String tierToDrop = null; + for (String tier : tiersFromDTO) { + if (tier.contains(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS)) { + tierToDrop = tier; + break; + } + } + if (tierToDrop != null) { + tiersFromDTO.remove(tierToDrop); + apiDtoToUpdate.setPolicies(tiersFromDTO); + } + } String originalStatus = originalAPI.getStatus(); - if (apiSecurity != null && (apiSecurity.contains(APIConstants.DEFAULT_API_SECURITY_OAUTH2) || apiSecurity - .contains(APIConstants.API_SECURITY_API_KEY))) { - if ((tiersFromDTO == null || tiersFromDTO.isEmpty() && !(APIConstants.CREATED.equals(originalStatus) - || APIConstants.PROTOTYPED.equals(originalStatus))) - && !apiDtoToUpdate.getAdvertiseInfo().isAdvertised()) { + String tenantDomain = RestApiCommonUtil.getLoggedInUserTenantDomain(); + boolean condition = ((tiersFromDTO == null || tiersFromDTO.isEmpty() + && !(APIConstants.CREATED.equals(originalStatus) + || APIConstants.PROTOTYPED.equals(originalStatus))) + && !apiDtoToUpdate.getAdvertiseInfo().isAdvertised()); + if (!APIUtil.isSubscriptionValidationDisablingAllowed(tenantDomain)) { + if (apiSecurity != null && (apiSecurity.contains(APIConstants.DEFAULT_API_SECURITY_OAUTH2) || apiSecurity + .contains(APIConstants.API_SECURITY_API_KEY)) && condition) { throw new APIManagementException( "A tier should be defined if the API is not in CREATED or PROTOTYPED state", ExceptionCodes.TIER_CANNOT_BE_NULL); } + } else { + if (apiSecurity != null) { + if (apiSecurity.contains(APIConstants.API_SECURITY_API_KEY) && condition) { + throw new APIManagementException( + "A tier should be defined if the API is not in CREATED or PROTOTYPED state", + ExceptionCodes.TIER_CANNOT_BE_NULL); + } else if (apiSecurity.contains(APIConstants.DEFAULT_API_SECURITY_OAUTH2)) { + // Internally set the default tier when no tiers are defined in order to support + // subscription validation disabling for OAuth2 secured APIs + if (tiersFromDTO != null && tiersFromDTO.isEmpty()) { + if (isAsyncAPI) { + tiersFromDTO.add(APIConstants.DEFAULT_SUB_POLICY_ASYNC_SUBSCRIPTIONLESS); + } else { + tiersFromDTO.add(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS); + + } + apiDtoToUpdate.setPolicies(tiersFromDTO); + } + } + } } if (tiersFromDTO != null && !tiersFromDTO.isEmpty()) { @@ -954,8 +991,9 @@ public static void validateScopes(API api) throws APIManagementException { for (String aRole : scope.getRoles().split(",")) { boolean isValidRole = APIUtil.isRoleNameExist(username, aRole); if (!isValidRole) { - throw new APIManagementException("Role '" + aRole + "' does not exist.", - ExceptionCodes.ROLE_DOES_NOT_EXIST); + String errorMessage = "Role '" + aRole + "' does not exist."; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.ROLE_OF_SCOPE_DOES_NOT_EXIST, aRole)); } } } @@ -1758,7 +1796,9 @@ private static void prepareForUpdateSwagger(String apiId, APIDefinitionValidatio for (String aRole : roles.split(",")) { boolean isValidRole = APIUtil.isRoleNameExist(RestApiCommonUtil.getLoggedInUsername(), aRole); if (!isValidRole) { - throw new APIManagementException("Role '" + aRole + "' Does not exist."); + String errorMessage = "Role '" + aRole + "' Does not exist."; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.ROLE_OF_SCOPE_DOES_NOT_EXIST, aRole)); } } } @@ -2014,20 +2054,23 @@ public static Documentation addDocumentationToAPI(DocumentDTO documentDto, Strin ExceptionCodes.DOCUMENT_NAME_ILLEGAL_CHARACTERS); } if (documentDto.getType() == null) { - throw new APIManagementException("Documentation type cannot be empty", - ExceptionCodes.PARAMETER_NOT_PROVIDED); + String errorMessage = "Documentation type cannot be empty"; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.PARAMETER_NOT_PROVIDED_FOR_DOCUMENTATION, errorMessage)); } if (documentDto.getType() == DocumentDTO.TypeEnum.OTHER && StringUtils .isBlank(documentDto.getOtherTypeName())) { //check otherTypeName for not null if doc type is OTHER - throw new APIManagementException("otherTypeName cannot be empty if type is OTHER.", - ExceptionCodes.PARAMETER_NOT_PROVIDED); + String errorMessage = "otherTypeName cannot be empty if type is OTHER."; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.PARAMETER_NOT_PROVIDED_FOR_DOCUMENTATION, errorMessage)); } String sourceUrl = documentDto.getSourceUrl(); if (documentDto.getSourceType() == DocumentDTO.SourceTypeEnum.URL && ( org.apache.commons.lang3.StringUtils.isBlank(sourceUrl) || !RestApiCommonUtil.isURL(sourceUrl))) { - throw new APIManagementException("Invalid document sourceUrl Format", - ExceptionCodes.PARAMETER_NOT_PROVIDED); + String errorMessage = "Invalid document sourceUrl Format"; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.PARAMETER_NOT_PROVIDED_FOR_DOCUMENTATION, errorMessage)); } if (apiProvider.isDocumentationExist(apiId, documentName, organization)) { @@ -2125,11 +2168,34 @@ public static APIProduct updateApiProduct(APIProduct originalAPIProduct, APIProd List apiSecurity = apiProductDtoToUpdate.getSecurityScheme(); //validation for tiers List tiersFromDTO = apiProductDtoToUpdate.getPolicies(); - if (apiSecurity.contains(APIConstants.DEFAULT_API_SECURITY_OAUTH2) || apiSecurity - .contains(APIConstants.API_SECURITY_API_KEY)) { - if (tiersFromDTO == null || tiersFromDTO.isEmpty()) { - throw new APIManagementException("No tier defined for the API Product", - ExceptionCodes.TIER_CANNOT_BE_NULL); + // Remove the subscriptionless tier if other tiers are available. + if (tiersFromDTO != null && tiersFromDTO.size() > 1 + && tiersFromDTO.contains(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS)) { + tiersFromDTO.remove(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS); + apiProductDtoToUpdate.setPolicies(tiersFromDTO); + } + String tenantDomain = RestApiCommonUtil.getLoggedInUserTenantDomain(); + if (!APIUtil.isSubscriptionValidationDisablingAllowed(tenantDomain)) { + if (apiSecurity.contains(APIConstants.DEFAULT_API_SECURITY_OAUTH2) || apiSecurity + .contains(APIConstants.API_SECURITY_API_KEY)) { + if (tiersFromDTO == null || tiersFromDTO.isEmpty()) { + throw new APIManagementException("No tier defined for the API Product", + ExceptionCodes.TIER_CANNOT_BE_NULL); + } + } + } else { + if (apiSecurity.contains(APIConstants.API_SECURITY_API_KEY)) { + if (tiersFromDTO == null || tiersFromDTO.isEmpty()) { + throw new APIManagementException("No tier defined for the API Product", + ExceptionCodes.TIER_CANNOT_BE_NULL); + } + } else if (apiSecurity.contains(APIConstants.DEFAULT_API_SECURITY_OAUTH2)) { + // Internally set the default tier when no tiers are defined in order to support + // subscription validation disabling for OAuth2 secured APIs + if (tiersFromDTO != null && tiersFromDTO.isEmpty()) { + tiersFromDTO.add(APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS); + apiProductDtoToUpdate.setPolicies(tiersFromDTO); + } } } @@ -2137,17 +2203,19 @@ public static APIProduct updateApiProduct(APIProduct originalAPIProduct, APIProd Set definedTiers = apiProvider.getTiers(); List invalidTiers = PublisherCommonUtils.getInvalidTierNames(definedTiers, tiersFromDTO); if (!invalidTiers.isEmpty()) { - throw new APIManagementException( - "Specified tier(s) " + Arrays.toString(invalidTiers.toArray()) + " are invalid", - ExceptionCodes.TIER_NAME_INVALID); + String errorMessage = "Specified tier(s) " + Arrays.toString(invalidTiers.toArray()) + " are invalid"; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.TIER_NAME_INVALID_WITH_TIER_INFO, + Arrays.toString(invalidTiers.toArray()))); } if (apiProductDtoToUpdate.getAdditionalProperties() != null) { - String errorMessage = PublisherCommonUtils - .validateAdditionalProperties(apiProductDtoToUpdate.getAdditionalProperties()); + String errorMessage = PublisherCommonUtils.validateAdditionalProperties( + apiProductDtoToUpdate.getAdditionalProperties()); if (!errorMessage.isEmpty()) { - throw new APIManagementException(errorMessage, ExceptionCodes - .from(ExceptionCodes.INVALID_ADDITIONAL_PROPERTIES, originalAPIProduct.getId().getName(), - originalAPIProduct.getId().getVersion())); + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.INVALID_ADDITIONAL_PROPERTIES_WITH_ERROR, + originalAPIProduct.getId().getName(), originalAPIProduct.getId().getVersion(), + errorMessage)); } } @@ -2209,16 +2277,18 @@ public static APIProduct addAPIProductWithGeneratedSwaggerDefinition(APIProductD Set definedTiers = apiProvider.getTiers(); List invalidTiers = PublisherCommonUtils.getInvalidTierNames(definedTiers, tiersFromDTO); if (!invalidTiers.isEmpty()) { - throw new APIManagementException( - "Specified tier(s) " + Arrays.toString(invalidTiers.toArray()) + " are invalid", - ExceptionCodes.TIER_NAME_INVALID); + String errorMessage = "Specified tier(s) " + Arrays.toString(invalidTiers.toArray()) + " are invalid"; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.TIER_NAME_INVALID_WITH_TIER_INFO, + Arrays.toString(invalidTiers.toArray()))); } if (apiProductDTO.getAdditionalProperties() != null) { String errorMessage = PublisherCommonUtils .validateAdditionalProperties(apiProductDTO.getAdditionalProperties()); if (!errorMessage.isEmpty()) { throw new APIManagementException(errorMessage, - ExceptionCodes.from(ExceptionCodes.INVALID_ADDITIONAL_PROPERTIES, apiProductDTO.getName())); + ExceptionCodes.from(ExceptionCodes.INVALID_ADDITIONAL_PROPERTIES_WITH_ERROR, + apiProductDTO.getName(), apiProductDTO.getVersion(), errorMessage)); } } if (apiProductDTO.getVisibility() == null) { @@ -2438,9 +2508,10 @@ public static APIStateChangeResponse changeApiOrApiProductLifecycle(String actio String[] nextAllowedStates = (String[]) apiLCData.get(APIConstants.LC_NEXT_STATES); if (!ArrayUtils.contains(nextAllowedStates, action)) { - throw new APIManagementException("Action '" + action + "' is not allowed. Allowed actions are " - + Arrays.toString(nextAllowedStates), ExceptionCodes.from(ExceptionCodes - .UNSUPPORTED_LIFECYCLE_ACTION, action)); + String errorMessage = "Action '" + action + "' is not allowed. Allowed actions are " + + Arrays.toString(nextAllowedStates); + throw new APIManagementException(errorMessage, ExceptionCodes.from(ExceptionCodes + .UNSUPPORTED_AND_ALLOWED_LIFECYCLE_ACTIONS, action, Arrays.toString(nextAllowedStates))); } //check and set lifecycle check list items including "Deprecate Old Versions" and "Require Re-Subscription". 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/SearchResultMappingUtil.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/SearchResultMappingUtil.java index 67ef529209cf..6bddea50a028 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/SearchResultMappingUtil.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/SearchResultMappingUtil.java @@ -24,6 +24,7 @@ import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.ExceptionCodes; import org.wso2.carbon.apimgt.api.model.API; +import org.wso2.carbon.apimgt.api.model.APIDefinitionContentSearchResult; import org.wso2.carbon.apimgt.api.model.APIIdentifier; import org.wso2.carbon.apimgt.api.model.APIProduct; import org.wso2.carbon.apimgt.api.model.APIProductIdentifier; @@ -32,6 +33,7 @@ import org.wso2.carbon.apimgt.impl.utils.APIUtil; import org.wso2.carbon.apimgt.rest.api.common.RestApiCommonUtil; import org.wso2.carbon.apimgt.rest.api.common.RestApiConstants; +import org.wso2.carbon.apimgt.rest.api.publisher.v1.dto.APIDefinitionSearchResultDTO; import org.wso2.carbon.apimgt.rest.api.publisher.v1.dto.APIProductSearchResultDTO; import org.wso2.carbon.apimgt.rest.api.publisher.v1.dto.APISearchResultDTO; import org.wso2.carbon.apimgt.rest.api.publisher.v1.dto.DocumentSearchResultDTO; @@ -234,4 +236,35 @@ public static void setPaginationParams(SearchResultListDTO resultListDTO, String visibility.toString())); } } + + /** + * Get APIDefinitionSearchResultDTO representation for APi Definition Content Search Result. + * + * @param apiDefResult APIDefinitionContentSearchResult obj + * @return APIDefinitionSearchResultDTO obj + */ + + public static APIDefinitionSearchResultDTO + fromAPIDefSearchResultToAPIDefSearchResultDTO(APIDefinitionContentSearchResult apiDefResult) { + APIDefinitionSearchResultDTO apiDefSearchResultDTO = new APIDefinitionSearchResultDTO(); + apiDefSearchResultDTO.setId(apiDefResult.getId()); + apiDefSearchResultDTO.setType(SearchResultDTO.TypeEnum.DEFINITION); + apiDefSearchResultDTO.setApiUUID(apiDefResult.getApiUuid()); + apiDefSearchResultDTO.setApiName(apiDefResult.getApiName()); + apiDefSearchResultDTO.setApiContext(apiDefResult.getApiContext()); + apiDefSearchResultDTO.setApiVersion(apiDefResult.getApiVersion()); + apiDefSearchResultDTO.setApiProvider(apiDefResult.getApiProvider()); + apiDefSearchResultDTO.setApiType(apiDefResult.getApiType()); + apiDefSearchResultDTO.setAssociatedType(apiDefResult.getAssociatedType()); + if (apiDefResult.getName().contains("swagger")) { + apiDefSearchResultDTO.setName(apiDefResult.getApiName() + " REST API Definition"); + } else if (apiDefResult.getName().contains("graphql")) { + apiDefSearchResultDTO.setName(apiDefResult.getApiName() + " GraphQL Definition"); + } else if (apiDefResult.getName().contains("async")) { + apiDefSearchResultDTO.setName(apiDefResult.getApiName() + " Async Definition"); + } else if (apiDefResult.getName().contains("wsdl")) { + apiDefSearchResultDTO.setName(apiDefResult.getApiName() + " WSDL Definition"); + } + return apiDefSearchResultDTO; + } } 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/SettingsMappingUtil.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/SettingsMappingUtil.java index 87156e0d8958..f0537d89f7fa 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/SettingsMappingUtil.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/SettingsMappingUtil.java @@ -89,6 +89,8 @@ public SettingsDTO fromSettingstoDTO(Boolean isUserAvailable, String organizatio settingsDTO.setDocVisibilityEnabled(APIUtil.isDocVisibilityLevelsEnabled()); settingsDTO.setPortalConfigurationOnlyModeEnabled(APIUtil.isPortalConfigurationOnlyModeEnabled()); settingsDTO.setCrossTenantSubscriptionEnabled(APIUtil.isCrossTenantSubscriptionsEnabled()); + settingsDTO.setAllowSubscriptionValidationDisabling( + APIUtil.isSubscriptionValidationDisablingAllowed(organization)); Map gatewayEnvironments = APIUtil.getReadOnlyGatewayEnvironments(); String authorizationHeader = APIUtil.getOAuthConfiguration(loggedInUserTenantDomain, APIConstants.AUTHORIZATION_HEADER); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/pom.xml index b0bf7e3a3311..824039789596 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml 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 dbafa7734150..95ec977cfc81 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 @@ -615,8 +615,8 @@ public Response editCommentOfAPI(@ApiParam(value = "Comment Id ",required=true) @ApiResponse(code = 200, message = "OK. Export Successful. ", response = File.class), @ApiResponse(code = 404, message = "Not Found. The specified resource does not exist.", response = ErrorDTO.class), @ApiResponse(code = 500, message = "Internal Server Error.", response = ErrorDTO.class) }) - public Response exportAPI( @ApiParam(value = "UUID of the API") @QueryParam("apiId") String apiId, @ApiParam(value = "API Name ") @QueryParam("name") String name, @ApiParam(value = "Version of the API ") @QueryParam("version") String version, @ApiParam(value = "Revision number of the API artifact ") @QueryParam("revisionNumber") String revisionNumber, @ApiParam(value = "Provider name of the API ") @QueryParam("providerName") String providerName, @ApiParam(value = "Format of output documents. Can be YAML or JSON. ", allowableValues="JSON, YAML") @QueryParam("format") String format, @ApiParam(value = "Preserve API Status during export ") @QueryParam("preserveStatus") Boolean preserveStatus, @ApiParam(value = "Export the latest revision of the API ", defaultValue="false") @DefaultValue("false") @QueryParam("latestRevision") Boolean latestRevision) throws APIManagementException{ - return delegate.exportAPI(apiId, name, version, revisionNumber, providerName, format, preserveStatus, latestRevision, securityContext); + public Response exportAPI( @ApiParam(value = "UUID of the API") @QueryParam("apiId") String apiId, @ApiParam(value = "API Name ") @QueryParam("name") String name, @ApiParam(value = "Version of the API ") @QueryParam("version") String version, @ApiParam(value = "Revision number of the API artifact ") @QueryParam("revisionNumber") String revisionNumber, @ApiParam(value = "Provider name of the API ") @QueryParam("providerName") String providerName, @ApiParam(value = "Format of output documents. Can be YAML or JSON. ", allowableValues="JSON, YAML") @QueryParam("format") String format, @ApiParam(value = "Preserve API Status during export ") @QueryParam("preserveStatus") Boolean preserveStatus, @ApiParam(value = "Export the latest revision of the API ", defaultValue="false") @DefaultValue("false") @QueryParam("latestRevision") Boolean latestRevision, @ApiParam(value = "Gateway environment of the exported APIs ") @QueryParam("gatewayEnvironment") String gatewayEnvironment) throws APIManagementException{ + return delegate.exportAPI(apiId, name, version, revisionNumber, providerName, format, preserveStatus, latestRevision, gatewayEnvironment, securityContext); } @POST 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 5d47c2da35bb..e6b1fd08e701 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 @@ -90,7 +90,7 @@ public interface ApisApiService { public Response deleteComment(String commentId, String apiId, String ifMatch, MessageContext messageContext) throws APIManagementException; public Response deployAPIRevision(String apiId, String revisionId, List apIRevisionDeploymentDTO, MessageContext messageContext) throws APIManagementException; public Response editCommentOfAPI(String commentId, String apiId, PatchRequestBodyDTO patchRequestBodyDTO, MessageContext messageContext) throws APIManagementException; - public Response exportAPI(String apiId, String name, String version, String revisionNumber, String providerName, String format, Boolean preserveStatus, Boolean latestRevision, MessageContext messageContext) throws APIManagementException; + public Response exportAPI(String apiId, String name, String version, String revisionNumber, String providerName, String format, Boolean preserveStatus, Boolean latestRevision, String gatewayEnvironment, MessageContext messageContext) throws APIManagementException; public Response generateInternalAPIKey(String apiId, MessageContext messageContext) throws APIManagementException; public Response generateMockScripts(String apiId, String ifNoneMatch, MessageContext messageContext) throws APIManagementException; public Response getAPI(String apiId, String xWSO2Tenant, String ifNoneMatch, 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/ApiProductsApiServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApiProductsApiServiceImpl.java index be9bc6348bb7..62677dfa8259 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApiProductsApiServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/ApiProductsApiServiceImpl.java @@ -511,7 +511,7 @@ public Response getIsAPIProductOutdated(String apiProductId, String accept, Stri @Override public Response updateAPIProduct(String apiProductId, APIProductDTO body, String ifMatch, - MessageContext messageContext) { + MessageContext messageContext) throws APIManagementException { try { String username = RestApiCommonUtil.getLoggedInUsername(); String tenantDomain = RestApiCommonUtil.getLoggedInUserTenantDomain(); @@ -524,13 +524,15 @@ public Response updateAPIProduct(String apiProductId, APIProductDTO body, String apiProvider, username, tenantDomain); APIProductDTO updatedProductDTO = getAPIProductByID(apiProductId, apiProvider); return Response.ok().entity(updatedProductDTO).build(); - } catch (APIManagementException | FaultGatewaysException e) { + } catch (APIManagementException e) { if (isAuthorizationFailure(e)) { RestApiUtil.handleAuthorizationFailure("User is not authorized to access the API", e, log); } else { - String errorMessage = "Error while updating API Product : " + apiProductId; - RestApiUtil.handleInternalServerError(errorMessage, e, log); + throw e; } + } catch (FaultGatewaysException e) { + String errorMessage = "Error while updating API Product : " + apiProductId; + RestApiUtil.handleInternalServerError(errorMessage, e, log); } return null; } @@ -795,13 +797,15 @@ public Response getAllAPIProducts(Integer limit, Integer offset, String query, S RestApiConstants.RESOURCE_PATH_API_PRODUCTS + "/" + createdApiProductDTO.getId()); return Response.created(createdApiProductUri).entity(createdApiProductDTO).build(); - } catch (APIManagementException | FaultGatewaysException e) { + } catch (APIManagementException e) { if (e.getMessage().contains(ExceptionCodes.API_CONTEXT_MALFORMED_EXCEPTION.getErrorMessage())) { RestApiUtil.handleBadRequest("Error while adding new API Product. " + e.getMessage().replace("API", "API Product"), e, log); } - String errorMessage = "Error while adding new API Product : " + provider + "-" + body.getName() - + " - " + e.getMessage(); + throw e; + } catch (FaultGatewaysException e) { + String errorMessage = "Error while adding new API Product : " + provider + "-" + body.getName() + " - " + + e.getMessage(); RestApiUtil.handleInternalServerError(errorMessage, e, log); } catch (URISyntaxException e) { String errorMessage = "Error while retrieving API Product location : " + provider + "-" @@ -844,7 +848,11 @@ public Response createAPIProductRevision(String apiProductId, APIRevisionDTO apI return Response.created(createdApiUri).entity(createdApiRevisionDTO).build(); } catch (APIManagementException e) { String errorMessage = "Error while adding new API Revision for API Product: " + apiProductId; - RestApiUtil.handleInternalServerError(errorMessage, e, log); + if (e.getErrorHandler().getErrorCode() == ExceptionCodes.MAXIMUM_REVISIONS_REACHED.getErrorCode()) { + throw e; + } else { + RestApiUtil.handleInternalServerError(errorMessage, e, log); + } } catch (URISyntaxException e) { String errorMessage = "Error while retrieving created revision API location for API Product: " + apiProductId; @@ -877,16 +885,17 @@ public Response deployAPIProductRevision(String apiProductId, String revisionId, apiRevisionDeployment.setRevisionUUID(revisionId); String environment = apiRevisionDeploymentDTO.getName(); if (environments.get(environment) == null) { - RestApiUtil.handleBadRequest("Gateway environment not found: " + environment, log); + String errorMessage = "Gateway environment not found: " + environment; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.PROVIDED_GATEWAY_ENVIRONMENT_NOT_FOUND, environment)); } apiRevisionDeployment.setDeployment(environment); apiRevisionDeployment.setVhost(apiRevisionDeploymentDTO.getVhost()); if (StringUtils.isEmpty(apiRevisionDeploymentDTO.getVhost())) { - // vhost is only required when deploying an revision, not required when un-deploying a revision + // vhost is only required when deploying a revision, not required when un-deploying a revision // since the same scheme 'APIRevisionDeployment' is used for deploy and undeploy, handle it here. - RestApiUtil.handleBadRequest( - "Required field 'vhost' not found in deployment", log - ); + String errorMessage = "Required field 'vhost' not found in deployment"; + throw new APIManagementException(errorMessage, ExceptionCodes.GATEWAY_ENVIRONMENT_VHOST_NOT_PROVIDED); } apiRevisionDeployment.setDisplayOnDevportal(apiRevisionDeploymentDTO.isDisplayOnDevportal()); apiRevisionDeployments.add(apiRevisionDeployment); @@ -971,7 +980,9 @@ public Response undeployAPIProductRevision(String apiProductId, String revisionI if (revisionId == null && revisionNumber != null) { revisionId = apiProvider.getAPIRevisionUUID(revisionNumber, apiProductId); if (revisionId == null) { - return Response.status(Response.Status.BAD_REQUEST).entity(null).build(); + throw new APIManagementException( + "Revision " + revisionNumber + " is not found for API Product with UUID " + apiProductId, + ExceptionCodes.from(ExceptionCodes.API_REVISION_NOT_FOUND, revisionNumber)); } } String organization = RestApiUtil.getValidatedOrganization(messageContext); @@ -985,7 +996,9 @@ public Response undeployAPIProductRevision(String apiProductId, String revisionI apiRevisionDeployment.setRevisionUUID(revisionId); String environment = apiRevisionDeploymentDTO.getName(); if (environments.get(environment) == null) { - RestApiUtil.handleBadRequest("Gateway environment not found: " + environment, log); + String errorMessage = "Gateway environment not found: " + environment; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.PROVIDED_GATEWAY_ENVIRONMENT_NOT_FOUND, environment)); } apiRevisionDeployment.setDeployment(environment); apiRevisionDeployment.setVhost(apiRevisionDeploymentDTO.getVhost()); 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 353bf3859c70..90f3ca802aa2 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 @@ -31,7 +31,6 @@ import org.apache.cxf.jaxrs.ext.multipart.Attachment; import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition; import org.apache.cxf.phase.PhaseInterceptorChain; -import org.apache.http.HttpStatus; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; @@ -52,13 +51,14 @@ import org.wso2.carbon.apimgt.impl.certificatemgt.ResponseCode; import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO; import org.wso2.carbon.apimgt.impl.definitions.*; +import org.wso2.carbon.apimgt.impl.dto.RuntimeArtifactDto; import org.wso2.carbon.apimgt.impl.dto.WorkflowDTO; +import org.wso2.carbon.apimgt.impl.gatewayartifactsynchronizer.RuntimeArtifactGeneratorUtil; import org.wso2.carbon.apimgt.impl.importexport.APIImportExportException; import org.wso2.carbon.apimgt.impl.importexport.ExportFormat; import org.wso2.carbon.apimgt.impl.importexport.ImportExportAPI; import org.wso2.carbon.apimgt.impl.importexport.utils.APIImportExportUtil; import org.wso2.carbon.apimgt.impl.importexport.utils.CommonUtil; -import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder; import org.wso2.carbon.apimgt.impl.restapi.CommonUtils; import org.wso2.carbon.apimgt.impl.restapi.publisher.ApisApiServiceImplUtils; import org.wso2.carbon.apimgt.impl.restapi.publisher.OperationPoliciesApiServiceImplUtils; @@ -79,11 +79,14 @@ import org.wso2.carbon.apimgt.rest.api.util.utils.RestApiUtil; import org.wso2.carbon.core.util.CryptoException; import org.wso2.carbon.core.util.CryptoUtil; +import org.wso2.carbon.utils.multitenancy.MultitenantConstants; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; import java.io.*; import java.net.*; +import java.nio.file.Files; import java.util.*; import static org.wso2.carbon.apimgt.api.ExceptionCodes.API_VERSION_ALREADY_EXISTS; @@ -1829,7 +1832,7 @@ private LifecycleStateDTO getLifecycleState(String apiId, String organization) t } if (apiIdentifier == null) { throw new APIManagementException("Error while getting the api identifier for the API:" + - apiId, ExceptionCodes.INVALID_API_ID); + apiId, ExceptionCodes.from(ExceptionCodes.INVALID_API_ID, apiId)); } return PublisherCommonUtils.getLifecycleStateInformation(apiIdentifier, organization); } catch (APIManagementException e) { @@ -2881,7 +2884,8 @@ public Response importOpenAPIDefinition(InputStream fileInputStream, Attachment MessageContext messageContext) throws APIManagementException { // validate 'additionalProperties' json if (StringUtils.isBlank(additionalProperties)) { - RestApiUtil.handleBadRequest("'additionalProperties' is required and should not be null", log); + throw new APIManagementException("'additionalProperties' is required and should not be null", + ExceptionCodes.ADDITIONAL_PROPERTIES_CANNOT_BE_NULL); } // Convert the 'additionalProperties' json into an APIDTO object @@ -2899,7 +2903,8 @@ public Response importOpenAPIDefinition(InputStream fileInputStream, Attachment ExceptionCodes.from(ExceptionCodes.API_CONTEXT_MALFORMED_EXCEPTION, e.getMessage())); } } catch (IOException e) { - throw RestApiUtil.buildBadRequestException("Error while parsing 'additionalProperties'", e); + throw new APIManagementException("Error while parsing 'additionalProperties'", e, + ExceptionCodes.ADDITIONAL_PROPERTIES_PARSE_ERROR); } // validate sandbox and production endpoints @@ -2936,7 +2941,8 @@ public Response importOpenAPIDefinition(InputStream fileInputStream, Attachment String errorMessage = "Error while encrypting the secret key of API : " + apiDTOFromProperties.getProvider() + "-" + apiDTOFromProperties.getName() + "-" + apiDTOFromProperties.getVersion(); - throw new APIManagementException(errorMessage, e); + throw new APIManagementException(errorMessage, e, + ExceptionCodes.from(ExceptionCodes.ENDPOINT_SECURITY_CRYPTO_EXCEPTION, errorMessage)); } return null; } @@ -3366,36 +3372,71 @@ public Response createNewAPIVersion(String newVersion, String apiId, Boolean def * WSDL and sequences are exported. This service generates a zipped archive which contains all the above mentioned * resources for a given API. * - * @param apiId UUID of an API - * @param name Name of the API that needs to be exported - * @param version Version of the API that needs to be exported - * @param providerName Provider name of the API that needs to be exported - * @param format Format of output documents. Can be YAML or JSON - * @param preserveStatus Preserve API status on export + * @param apiId UUID of an API + * @param name Name of the API that needs to be exported + * @param version Version of the API that needs to be exported + * @param providerName Provider name of the API that needs to be exported + * @param format Format of output documents. Can be YAML or JSON + * @param preserveStatus Preserve API status on export + * @param gatewayEnvironment * @return */ @Override public Response exportAPI(String apiId, String name, String version, String revisionNum, String providerName, String format, Boolean preserveStatus, - Boolean exportLatestRevision, MessageContext messageContext) + Boolean exportLatestRevision, String gatewayEnvironment, + MessageContext messageContext) throws APIManagementException { - //If not specified status is preserved by default - preserveStatus = preserveStatus == null || preserveStatus; + if (StringUtils.isEmpty(gatewayEnvironment)) { + //If not specified status is preserved by default + preserveStatus = preserveStatus == null || preserveStatus; - // Default export format is YAML - ExportFormat exportFormat = StringUtils.isNotEmpty(format) ? - ExportFormat.valueOf(format.toUpperCase()) : - ExportFormat.YAML; - try { + // Default export format is YAML + ExportFormat exportFormat = StringUtils.isNotEmpty(format) ? + ExportFormat.valueOf(format.toUpperCase()) : + ExportFormat.YAML; + try { + String organization = RestApiUtil.getValidatedOrganization(messageContext); + ImportExportAPI importExportAPI = APIImportExportUtil.getImportExportAPI(); + File file = importExportAPI + .exportAPI(apiId, name, version, revisionNum, providerName, preserveStatus, exportFormat, + Boolean.TRUE, Boolean.FALSE, exportLatestRevision, StringUtils.EMPTY, organization); + return Response.ok(file).header(RestApiConstants.HEADER_CONTENT_DISPOSITION, + "attachment; filename=\"" + file.getName() + "\"").build(); + } catch (APIImportExportException e) { + throw new APIManagementException("Error while exporting " + RestApiConstants.RESOURCE_API, e); + } + } else { String organization = RestApiUtil.getValidatedOrganization(messageContext); - ImportExportAPI importExportAPI = APIImportExportUtil.getImportExportAPI(); - File file = importExportAPI - .exportAPI(apiId, name, version, revisionNum, providerName, preserveStatus, exportFormat, - Boolean.TRUE, Boolean.FALSE, exportLatestRevision, StringUtils.EMPTY, organization); - return Response.ok(file).header(RestApiConstants.HEADER_CONTENT_DISPOSITION, - "attachment; filename=\"" + file.getName() + "\"").build(); - } catch (APIImportExportException e) { - throw new APIManagementException("Error while exporting " + RestApiConstants.RESOURCE_API, e); + if (StringUtils.isEmpty(apiId) && (StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(version))) { + APIIdentifier apiIdentifier = new APIIdentifier(providerName, name, version); + apiId = APIUtil.getUUIDFromIdentifier(apiIdentifier, organization); + } + RuntimeArtifactDto runtimeArtifactDto; + if (StringUtils.isNotEmpty(organization) && MultitenantConstants.SUPER_TENANT_DOMAIN_NAME + .equalsIgnoreCase(organization)) { + runtimeArtifactDto = RuntimeArtifactGeneratorUtil.generateAllRuntimeArtifact(apiId, gatewayEnvironment, + APIConstants.API_GATEWAY_TYPE_ENVOY); + } else { + runtimeArtifactDto = RuntimeArtifactGeneratorUtil.generateRuntimeArtifact(apiId, gatewayEnvironment, + APIConstants.API_GATEWAY_TYPE_ENVOY, organization); + } + if (runtimeArtifactDto != null) { + if (runtimeArtifactDto.isFile()) { + File artifact = (File) runtimeArtifactDto.getArtifact(); + StreamingOutput streamingOutput = (outputStream) -> { + try { + Files.copy(artifact.toPath(), outputStream); + } finally { + Files.delete(artifact.toPath()); + } + }; + return Response.ok(streamingOutput).header(RestApiConstants.HEADER_CONTENT_DISPOSITION, + "attachment; filename=apis.zip").header(RestApiConstants.HEADER_CONTENT_TYPE, + APIConstants.APPLICATION_ZIP).build(); + } + } + throw new APIManagementException("No API Artifacts", ExceptionCodes.NO_API_ARTIFACT_FOUND); } } @@ -3729,7 +3770,8 @@ public Response getAPIRevisions(String apiId, String query, MessageContext messa * @return response containing newly created APIRevision object */ @Override - public Response createAPIRevision(String apiId, APIRevisionDTO apIRevisionDTO, MessageContext messageContext) { + public Response createAPIRevision(String apiId, APIRevisionDTO apIRevisionDTO, MessageContext messageContext) + throws APIManagementException { try { APIProvider apiProvider = RestApiCommonUtil.getLoggedInUserProvider(); String organization = RestApiUtil.getValidatedOrganization(messageContext); @@ -3740,8 +3782,9 @@ public Response createAPIRevision(String apiId, APIRevisionDTO apIRevisionDTO, M //validate whether the API is advertise only APIDTO apiDto = getAPIByID(apiId, apiProvider, organization); if (apiDto != null && apiDto.getAdvertiseInfo() != null && apiDto.getAdvertiseInfo().isAdvertised()) { - throw new APIManagementException("Creating API Revisions is not supported for third party APIs: " - + apiId); + throw new APIManagementException( + "Creating API Revisions is not supported for third party APIs: " + apiId, + ExceptionCodes.from(ExceptionCodes.THIRD_PARTY_API_REVISION_CREATION_UNSUPPORTED, apiId)); } //validate API update operation permitted based on the LC state @@ -3763,7 +3806,14 @@ public Response createAPIRevision(String apiId, APIRevisionDTO apIRevisionDTO, M return Response.created(createdApiUri).entity(createdApiRevisionDTO).build(); } catch (APIManagementException e) { String errorMessage = "Error while adding new API Revision for API : " + apiId; - RestApiUtil.handleInternalServerError(errorMessage, e, log); + if ((e.getErrorHandler() + .getErrorCode() == ExceptionCodes.THIRD_PARTY_API_REVISION_CREATION_UNSUPPORTED.getErrorCode()) + || (e.getErrorHandler().getErrorCode() == ExceptionCodes.MAXIMUM_REVISIONS_REACHED.getErrorCode())) + { + throw e; + } else { + RestApiUtil.handleInternalServerError(errorMessage, e, log); + } } catch (URISyntaxException e) { String errorMessage = "Error while retrieving created revision API location for API : " + apiId; @@ -3844,12 +3894,15 @@ public Response deployAPIRevision(String apiId, String revisionId, APIDTO apiDto = getAPIByID(apiId, apiProvider, organization); // Reject the request if API lifecycle is 'RETIRED'. if (apiDto.getLifeCycleStatus().equals(APIConstants.RETIRED)) { - return Response.status(Response.Status.BAD_REQUEST).entity("Deploying API Revisions is not supported for retired APIs. ApiId: " - + apiId).build(); + String errorMessage = "Deploying API Revisions is not supported for retired APIs. ApiId: " + apiId; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.RETIRED_API_REVISION_DEPLOYMENT_UNSUPPORTED, apiId)); } - if (apiDto != null && apiDto.getAdvertiseInfo() != null && Boolean.TRUE.equals(apiDto.getAdvertiseInfo().isAdvertised())) { - throw new APIManagementException("Deploying API Revisions is not supported for third party APIs: " - + apiId); + if (apiDto != null && apiDto.getAdvertiseInfo() != null && Boolean.TRUE.equals( + apiDto.getAdvertiseInfo().isAdvertised())) { + String errorMessage = "Deploying API Revisions is not supported for third party APIs: " + apiId; + throw new APIManagementException(errorMessage, + ExceptionCodes.from(ExceptionCodes.THIRD_PARTY_API_REVISION_DEPLOYMENT_UNSUPPORTED, apiId)); } Map environments = APIUtil.getEnvironments(organization); @@ -3907,7 +3960,9 @@ public Response undeployAPIRevision(String apiId, String revisionId, String revi if (revisionId == null && revisionNum != null) { revisionId = apiProvider.getAPIRevisionUUID(revisionNum, apiId); if (revisionId == null) { - return Response.status(Response.Status.BAD_REQUEST).entity(null).build(); + throw new APIManagementException( + "No revision found for revision number " + revisionNum + " of API with UUID " + apiId, + ExceptionCodes.from(ExceptionCodes.REVISION_NOT_FOUND_FOR_REVISION_NUMBER, revisionNum)); } } 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/SearchApiServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/SearchApiServiceImpl.java index 517d176d35ed..6ab36696dc85 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/SearchApiServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/publisher/v1/impl/SearchApiServiceImpl.java @@ -25,6 +25,7 @@ import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.APIProvider; import org.wso2.carbon.apimgt.api.model.API; +import org.wso2.carbon.apimgt.api.model.APIDefinitionContentSearchResult; import org.wso2.carbon.apimgt.api.model.APIProduct; import org.wso2.carbon.apimgt.api.model.Documentation; import org.wso2.carbon.apimgt.impl.APIConstants; @@ -118,6 +119,11 @@ private List getAllMatchedResults(List apis) throws API (Documentation) pair.getKey(), (APIProduct) pair.getValue()); } allMatchedResults.add(docResult); + } else if (searchResult instanceof APIDefinitionContentSearchResult) { + APIDefinitionContentSearchResult apiDefResult = (APIDefinitionContentSearchResult) searchResult; + SearchResultDTO definitionResultDTO = + SearchResultMappingUtil.fromAPIDefSearchResultToAPIDefSearchResultDTO(apiDefResult); + allMatchedResults.add(definitionResultDTO); } } return allMatchedResults; 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 e55e6865f9b6..d25b133d4465 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 @@ -4014,6 +4014,12 @@ paths: schema: type: boolean default: false + - name: gatewayEnvironment + in: query + description: | + Gateway environment of the exported APIs + schema: + type: string responses: 200: description: | @@ -10370,6 +10376,7 @@ components: displayOnDevportal: type: boolean example: true + default: true deployedTime: readOnly: true type: string @@ -12599,6 +12606,7 @@ components: - DOC - API - APIProduct + - DEFINITION transportType: type: string description: Accepted values are HTTP, WS, SOAPTOREST, GRAPHQL @@ -12783,6 +12791,38 @@ components: type: string associatedType: type: string + APIDefinitionSearchResult: + title: API Definition Search Result + allOf: + - $ref: '#/components/schemas/SearchResult' + - properties: + apiName: + type: string + description: The name of the associated API + example: TestAPI + apiVersion: + type: string + description: The version of the associated API + example: 1.0.0 + apiContext: + type: string + description: The context of the associated API + example: /test + apiUUID: + type: string + description: The UUID of the associated API + apiProvider: + type: string + description: The provider name of the associated API + example: publisher + apiType: + type: string + description: The type of the associated API + example: REST + associatedType: + type: string + description: API or APIProduct + example: API MockResponsePayloadList: title: Mock Response Payload list type: object @@ -12939,6 +12979,11 @@ components: IsJWTEnabledForLoginTokens: type: boolean default: false + allowSubscriptionValidationDisabling: + type: boolean + description: | + Allow subscription validation disabling for OAuth tokens + default: true customProperties: type: array items: diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.service.catalog/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.service.catalog/pom.xml index c8bdc0ec9398..b91d5bdf55be 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.service.catalog/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.service.catalog/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/pom.xml index 54833951bc09..98ece91ba369 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/APIDefinitionSearchResultAllOfDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/APIDefinitionSearchResultAllOfDTO.java new file mode 100644 index 000000000000..ca6b1116baf7 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/APIDefinitionSearchResultAllOfDTO.java @@ -0,0 +1,208 @@ +package org.wso2.carbon.apimgt.rest.api.store.v1.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; + +import javax.xml.bind.annotation.*; +import org.wso2.carbon.apimgt.rest.api.common.annotations.Scope; +import com.fasterxml.jackson.annotation.JsonCreator; + +import javax.validation.Valid; + + + +public class APIDefinitionSearchResultAllOfDTO { + + private String apiName = null; + private String apiVersion = null; + private String apiContext = null; + private String apiUUID = null; + private String apiProvider = null; + private String apiType = null; + private String associatedType = null; + + /** + * The name of the associated API + **/ + public APIDefinitionSearchResultAllOfDTO apiName(String apiName) { + this.apiName = apiName; + return this; + } + + + @ApiModelProperty(example = "TestAPI", value = "The name of the associated API") + @JsonProperty("apiName") + public String getApiName() { + return apiName; + } + public void setApiName(String apiName) { + this.apiName = apiName; + } + + /** + * The version of the associated API + **/ + public APIDefinitionSearchResultAllOfDTO apiVersion(String apiVersion) { + this.apiVersion = apiVersion; + return this; + } + + + @ApiModelProperty(example = "1.0.0", value = "The version of the associated API") + @JsonProperty("apiVersion") + public String getApiVersion() { + return apiVersion; + } + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + + /** + * The context of the associated API + **/ + public APIDefinitionSearchResultAllOfDTO apiContext(String apiContext) { + this.apiContext = apiContext; + return this; + } + + + @ApiModelProperty(example = "/test", value = "The context of the associated API") + @JsonProperty("apiContext") + public String getApiContext() { + return apiContext; + } + public void setApiContext(String apiContext) { + this.apiContext = apiContext; + } + + /** + * The UUID of the associated API + **/ + public APIDefinitionSearchResultAllOfDTO apiUUID(String apiUUID) { + this.apiUUID = apiUUID; + return this; + } + + + @ApiModelProperty(value = "The UUID of the associated API") + @JsonProperty("apiUUID") + public String getApiUUID() { + return apiUUID; + } + public void setApiUUID(String apiUUID) { + this.apiUUID = apiUUID; + } + + /** + * The provider name of the associated API + **/ + public APIDefinitionSearchResultAllOfDTO apiProvider(String apiProvider) { + this.apiProvider = apiProvider; + return this; + } + + + @ApiModelProperty(example = "publisher", value = "The provider name of the associated API") + @JsonProperty("apiProvider") + public String getApiProvider() { + return apiProvider; + } + public void setApiProvider(String apiProvider) { + this.apiProvider = apiProvider; + } + + /** + * The type of the associated API + **/ + public APIDefinitionSearchResultAllOfDTO apiType(String apiType) { + this.apiType = apiType; + return this; + } + + + @ApiModelProperty(example = "REST", value = "The type of the associated API") + @JsonProperty("apiType") + public String getApiType() { + return apiType; + } + public void setApiType(String apiType) { + this.apiType = apiType; + } + + /** + * API or APIProduct + **/ + public APIDefinitionSearchResultAllOfDTO associatedType(String associatedType) { + this.associatedType = associatedType; + return this; + } + + + @ApiModelProperty(example = "API", value = "API or APIProduct") + @JsonProperty("associatedType") + public String getAssociatedType() { + return associatedType; + } + public void setAssociatedType(String associatedType) { + this.associatedType = associatedType; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + APIDefinitionSearchResultAllOfDTO apIDefinitionSearchResultAllOf = (APIDefinitionSearchResultAllOfDTO) o; + return Objects.equals(apiName, apIDefinitionSearchResultAllOf.apiName) && + Objects.equals(apiVersion, apIDefinitionSearchResultAllOf.apiVersion) && + Objects.equals(apiContext, apIDefinitionSearchResultAllOf.apiContext) && + Objects.equals(apiUUID, apIDefinitionSearchResultAllOf.apiUUID) && + Objects.equals(apiProvider, apIDefinitionSearchResultAllOf.apiProvider) && + Objects.equals(apiType, apIDefinitionSearchResultAllOf.apiType) && + Objects.equals(associatedType, apIDefinitionSearchResultAllOf.associatedType); + } + + @Override + public int hashCode() { + return Objects.hash(apiName, apiVersion, apiContext, apiUUID, apiProvider, apiType, associatedType); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class APIDefinitionSearchResultAllOfDTO {\n"); + + sb.append(" apiName: ").append(toIndentedString(apiName)).append("\n"); + sb.append(" apiVersion: ").append(toIndentedString(apiVersion)).append("\n"); + sb.append(" apiContext: ").append(toIndentedString(apiContext)).append("\n"); + sb.append(" apiUUID: ").append(toIndentedString(apiUUID)).append("\n"); + sb.append(" apiProvider: ").append(toIndentedString(apiProvider)).append("\n"); + sb.append(" apiType: ").append(toIndentedString(apiType)).append("\n"); + sb.append(" associatedType: ").append(toIndentedString(associatedType)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/APIDefinitionSearchResultDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/APIDefinitionSearchResultDTO.java new file mode 100644 index 000000000000..b79b2e159f13 --- /dev/null +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/APIDefinitionSearchResultDTO.java @@ -0,0 +1,210 @@ +package org.wso2.carbon.apimgt.rest.api.store.v1.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.APIDefinitionSearchResultAllOfDTO; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.SearchResultDTO; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; + +import javax.xml.bind.annotation.*; +import org.wso2.carbon.apimgt.rest.api.common.annotations.Scope; +import com.fasterxml.jackson.annotation.JsonCreator; + +import javax.validation.Valid; + + + +public class APIDefinitionSearchResultDTO extends SearchResultDTO { + + private String apiName = null; + private String apiVersion = null; + private String apiContext = null; + private String apiUUID = null; + private String apiProvider = null; + private String apiType = null; + private String associatedType = null; + + /** + * The name of the associated API + **/ + public APIDefinitionSearchResultDTO apiName(String apiName) { + this.apiName = apiName; + return this; + } + + + @ApiModelProperty(example = "TestAPI", value = "The name of the associated API") + @JsonProperty("apiName") + public String getApiName() { + return apiName; + } + public void setApiName(String apiName) { + this.apiName = apiName; + } + + /** + * The version of the associated API + **/ + public APIDefinitionSearchResultDTO apiVersion(String apiVersion) { + this.apiVersion = apiVersion; + return this; + } + + + @ApiModelProperty(example = "1.0.0", value = "The version of the associated API") + @JsonProperty("apiVersion") + public String getApiVersion() { + return apiVersion; + } + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + + /** + * The context of the associated API + **/ + public APIDefinitionSearchResultDTO apiContext(String apiContext) { + this.apiContext = apiContext; + return this; + } + + + @ApiModelProperty(example = "/test", value = "The context of the associated API") + @JsonProperty("apiContext") + public String getApiContext() { + return apiContext; + } + public void setApiContext(String apiContext) { + this.apiContext = apiContext; + } + + /** + * The UUID of the associated API + **/ + public APIDefinitionSearchResultDTO apiUUID(String apiUUID) { + this.apiUUID = apiUUID; + return this; + } + + + @ApiModelProperty(value = "The UUID of the associated API") + @JsonProperty("apiUUID") + public String getApiUUID() { + return apiUUID; + } + public void setApiUUID(String apiUUID) { + this.apiUUID = apiUUID; + } + + /** + * The provider name of the associated API + **/ + public APIDefinitionSearchResultDTO apiProvider(String apiProvider) { + this.apiProvider = apiProvider; + return this; + } + + + @ApiModelProperty(example = "publisher", value = "The provider name of the associated API") + @JsonProperty("apiProvider") + public String getApiProvider() { + return apiProvider; + } + public void setApiProvider(String apiProvider) { + this.apiProvider = apiProvider; + } + + /** + * The type of the associated API + **/ + public APIDefinitionSearchResultDTO apiType(String apiType) { + this.apiType = apiType; + return this; + } + + + @ApiModelProperty(example = "REST", value = "The type of the associated API") + @JsonProperty("apiType") + public String getApiType() { + return apiType; + } + public void setApiType(String apiType) { + this.apiType = apiType; + } + + /** + * API or APIProduct + **/ + public APIDefinitionSearchResultDTO associatedType(String associatedType) { + this.associatedType = associatedType; + return this; + } + + + @ApiModelProperty(example = "API", value = "API or APIProduct") + @JsonProperty("associatedType") + public String getAssociatedType() { + return associatedType; + } + public void setAssociatedType(String associatedType) { + this.associatedType = associatedType; + } + + + @Override + public boolean equals(java.lang.Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + APIDefinitionSearchResultDTO apIDefinitionSearchResult = (APIDefinitionSearchResultDTO) o; + return Objects.equals(apiName, apIDefinitionSearchResult.apiName) && + Objects.equals(apiVersion, apIDefinitionSearchResult.apiVersion) && + Objects.equals(apiContext, apIDefinitionSearchResult.apiContext) && + Objects.equals(apiUUID, apIDefinitionSearchResult.apiUUID) && + Objects.equals(apiProvider, apIDefinitionSearchResult.apiProvider) && + Objects.equals(apiType, apIDefinitionSearchResult.apiType) && + Objects.equals(associatedType, apIDefinitionSearchResult.associatedType); + } + + @Override + public int hashCode() { + return Objects.hash(apiName, apiVersion, apiContext, apiUUID, apiProvider, apiType, associatedType); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class APIDefinitionSearchResultDTO {\n"); + sb.append(" ").append(toIndentedString(super.toString())).append("\n"); + sb.append(" apiName: ").append(toIndentedString(apiName)).append("\n"); + sb.append(" apiVersion: ").append(toIndentedString(apiVersion)).append("\n"); + sb.append(" apiContext: ").append(toIndentedString(apiContext)).append("\n"); + sb.append(" apiUUID: ").append(toIndentedString(apiUUID)).append("\n"); + sb.append(" apiProvider: ").append(toIndentedString(apiProvider)).append("\n"); + sb.append(" apiType: ").append(toIndentedString(apiType)).append("\n"); + sb.append(" associatedType: ").append(toIndentedString(associatedType)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } +} + diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SearchResultDTO.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SearchResultDTO.java index 5be105aa045a..729775b25c9f 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SearchResultDTO.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/gen/java/org/wso2/carbon/apimgt/rest/api/store/v1/dto/SearchResultDTO.java @@ -30,7 +30,8 @@ public class SearchResultDTO { public enum TypeEnum { DOC("DOC"), API("API"), - APIPRODUCT("APIProduct"); + APIPRODUCT("APIProduct"), + DEFINITION("DEFINITION"); private String value; TypeEnum (String v) { diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/SearchApiServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/SearchApiServiceImpl.java index 3ce86cf6cf4f..8707ee31f411 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/SearchApiServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/SearchApiServiceImpl.java @@ -24,6 +24,7 @@ import org.wso2.carbon.apimgt.api.APIConsumer; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.model.API; +import org.wso2.carbon.apimgt.api.model.APIDefinitionContentSearchResult; import org.wso2.carbon.apimgt.api.model.APIProduct; import org.wso2.carbon.apimgt.api.model.Documentation; import org.wso2.carbon.apimgt.impl.APIConstants; @@ -104,6 +105,11 @@ public Response searchGet(Integer limit, Integer offset, String xWSO2Tenant, Str APIProduct apiProduct = (APIProduct) searchResult; SearchResultDTO apiResult = SearchResultMappingUtil.fromAPIToAPIResultDTO(apiProduct); allmatchedResults.add(apiResult); + } else if (searchResult instanceof APIDefinitionContentSearchResult) { + APIDefinitionContentSearchResult apiDefResult = (APIDefinitionContentSearchResult) searchResult; + SearchResultDTO definitionResultDTO = + SearchResultMappingUtil.fromAPIDefSearchResultToAPIDefSearchResultDTO(apiDefResult); + allmatchedResults.add(definitionResultDTO); } } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/SubscriptionsApiServiceImpl.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/SubscriptionsApiServiceImpl.java index 3dcc119c6acf..2ff61d2bfc26 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/SubscriptionsApiServiceImpl.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/impl/SubscriptionsApiServiceImpl.java @@ -26,6 +26,7 @@ import org.wso2.carbon.apimgt.api.APIConsumer; import org.wso2.carbon.apimgt.api.APIManagementException; import org.wso2.carbon.apimgt.api.APIMgtAuthorizationFailedException; +import org.wso2.carbon.apimgt.api.ExceptionCodes; import org.wso2.carbon.apimgt.api.MonetizationException; import org.wso2.carbon.apimgt.api.SubscriptionAlreadyExistingException; import org.wso2.carbon.apimgt.api.SubscriptionBlockedException; @@ -215,6 +216,13 @@ public Response subscriptionsPost(SubscriptionDTO body, String xWSO2Tenant, Mess return null; } + if (APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS.equalsIgnoreCase(body.getThrottlingPolicy()) + || APIConstants.DEFAULT_SUB_POLICY_ASYNC_SUBSCRIPTIONLESS + .equalsIgnoreCase(body.getThrottlingPolicy())) { + throw new APIManagementException("Subscribing to the API with an internal business plan is not allowed", + ExceptionCodes.from(ExceptionCodes.BUSINESS_PLAN_NOT_ALLOWED, body.getThrottlingPolicy())); + } + if (!RestAPIStoreUtils.isUserAccessAllowedForApplication(application)) { //application access failure occurred RestApiUtil.handleAuthorizationFailure(RestApiConstants.RESOURCE_APPLICATION, applicationId, log); @@ -325,6 +333,13 @@ public Response subscriptionsSubscriptionIdPut(String subscriptionId, Subscripti RestApiUtil.handleAuthorizationFailure(RestApiConstants.RESOURCE_APPLICATION, applicationId, log); } + if (APIConstants.DEFAULT_SUB_POLICY_SUBSCRIPTIONLESS.equalsIgnoreCase(body.getRequestedThrottlingPolicy()) + || APIConstants.DEFAULT_SUB_POLICY_ASYNC_SUBSCRIPTIONLESS + .equalsIgnoreCase(body.getRequestedThrottlingPolicy())) { + throw new APIManagementException(ExceptionCodes.from(ExceptionCodes.BUSINESS_PLAN_NOT_ALLOWED, + body.getRequestedThrottlingPolicy())); + } + ApiTypeWrapper apiTypeWrapper = apiConsumer.getAPIorAPIProductByUUID(body.getApiId(), organization); diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/SearchResultMappingUtil.java b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/SearchResultMappingUtil.java index 31b08f6654dd..6a137f84fefb 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/SearchResultMappingUtil.java +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/java/org/wso2/carbon/apimgt/rest/api/store/v1/mappings/SearchResultMappingUtil.java @@ -19,12 +19,14 @@ package org.wso2.carbon.apimgt.rest.api.store.v1.mappings; import org.wso2.carbon.apimgt.api.model.API; +import org.wso2.carbon.apimgt.api.model.APIDefinitionContentSearchResult; import org.wso2.carbon.apimgt.api.model.APIProduct; import org.wso2.carbon.apimgt.api.model.APIIdentifier; import org.wso2.carbon.apimgt.api.model.APIProductIdentifier; import org.wso2.carbon.apimgt.api.model.Documentation; import org.wso2.carbon.apimgt.impl.utils.APIUtil; import org.wso2.carbon.apimgt.rest.api.common.RestApiCommonUtil; +import org.wso2.carbon.apimgt.rest.api.store.v1.dto.APIDefinitionSearchResultDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.DocumentSearchResultDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.PaginationDTO; import org.wso2.carbon.apimgt.rest.api.store.v1.dto.SearchResultDTO; @@ -178,4 +180,35 @@ public static void setPaginationParams(SearchResultListDTO resultListDTO, String resultListDTO.setPagination(paginationDTO); } + /** + * Get APIDefinitionSearchResultDTO representation for APi Definition Content Search Result. + * + * @param apiDefResult APIDefinitionContentSearchResult obj + * @return APIDefinitionSearchResultDTO obj + */ + + public static APIDefinitionSearchResultDTO + fromAPIDefSearchResultToAPIDefSearchResultDTO(APIDefinitionContentSearchResult apiDefResult) { + APIDefinitionSearchResultDTO apiDefSearchResultDTO = new APIDefinitionSearchResultDTO(); + apiDefSearchResultDTO.setId(apiDefResult.getId()); + apiDefSearchResultDTO.setType(SearchResultDTO.TypeEnum.DEFINITION); + apiDefSearchResultDTO.setApiUUID(apiDefResult.getApiUuid()); + apiDefSearchResultDTO.setApiName(apiDefResult.getApiName()); + apiDefSearchResultDTO.setApiContext(apiDefResult.getApiContext()); + apiDefSearchResultDTO.setApiVersion(apiDefResult.getApiVersion()); + apiDefSearchResultDTO.setApiProvider(apiDefResult.getApiProvider()); + apiDefSearchResultDTO.setApiType(apiDefResult.getApiType()); + apiDefSearchResultDTO.setAssociatedType(apiDefResult.getAssociatedType()); + if (apiDefResult.getName().contains("swagger")) { + apiDefSearchResultDTO.setName(apiDefResult.getApiName() + " REST API Definition"); + } else if (apiDefResult.getName().contains("graphql")) { + apiDefSearchResultDTO.setName(apiDefResult.getApiName() + " GraphQL Definition"); + } else if (apiDefResult.getName().contains("async")) { + apiDefSearchResultDTO.setName(apiDefResult.getApiName() + " Async Definition"); + } else if (apiDefResult.getName().contains("wsdl")) { + apiDefSearchResultDTO.setName(apiDefResult.getApiName() + " WSDL Definition"); + } + return apiDefSearchResultDTO; + } + } diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/resources/devportal-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/resources/devportal-api.yaml index 719eaeabc837..0bf5ad70abad 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/resources/devportal-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.store.v1/src/main/resources/devportal-api.yaml @@ -5342,6 +5342,7 @@ components: - DOC - API - APIProduct + - DEFINITION transportType: type: string description: Accepted values are HTTP, WS, SOAPTOREST, GRAPHQL @@ -5442,6 +5443,38 @@ components: example: admin apiUUID: type: string + APIDefinitionSearchResult: + title: API Definition Search Result + allOf: + - $ref: '#/components/schemas/SearchResult' + - properties: + apiName: + type: string + description: The name of the associated API + example: TestAPI + apiVersion: + type: string + description: The version of the associated API + example: 1.0.0 + apiContext: + type: string + description: The context of the associated API + example: /test + apiUUID: + type: string + description: The UUID of the associated API + apiProvider: + type: string + description: The provider name of the associated API + example: publisher + apiType: + type: string + description: The type of the associated API + example: REST + associatedType: + type: string + description: API or APIProduct + example: API CommenterInfo: type: object properties: diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/pom.xml index 9c814b992e1e..e7d53b39ffa8 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/pom.xml @@ -17,7 +17,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/resources/publisher-api.yaml b/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/resources/publisher-api.yaml index d4442b35e306..ec8be349b52e 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/resources/publisher-api.yaml +++ b/components/apimgt/org.wso2.carbon.apimgt.rest.api.util/src/main/resources/publisher-api.yaml @@ -3999,6 +3999,12 @@ paths: schema: type: boolean default: false + - name: gatewayEnvironment + in: query + description: | + Gateway environment of the exported APIs + schema: + type: string responses: 200: description: | @@ -11488,6 +11494,11 @@ components: type: string description: Authorization Header example: authorization + allowSubscriptionValidationDisabling: + type: boolean + description: | + Allow subscription validation disabling for OAuth tokens + default: true customProperties: type: array items: diff --git a/components/apimgt/org.wso2.carbon.apimgt.solace/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.solace/pom.xml index 83dd1aa09b0b..596d4a4d0fb4 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.solace/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.solace/pom.xml @@ -3,7 +3,7 @@ apimgt org.wso2.carbon.apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.throttle.policy.deployer/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.throttle.policy.deployer/pom.xml index 20543f53759c..3c5ceb4dda59 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.throttle.policy.deployer/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.throttle.policy.deployer/pom.xml @@ -19,7 +19,7 @@ apimgt org.wso2.carbon.apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT 4.0.0 bundle diff --git a/components/apimgt/org.wso2.carbon.apimgt.throttling.siddhi.extension/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.throttling.siddhi.extension/pom.xml index 39dd5533a8b5..48f271806900 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.throttling.siddhi.extension/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.throttling.siddhi.extension/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.tokenmgt/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.tokenmgt/pom.xml index 9d3ab0b81031..23760a3b0f21 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.tokenmgt/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.tokenmgt/pom.xml @@ -16,7 +16,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/org.wso2.carbon.apimgt.tracing/pom.xml b/components/apimgt/org.wso2.carbon.apimgt.tracing/pom.xml index b421d898dfff..c44eed4ff5d5 100644 --- a/components/apimgt/org.wso2.carbon.apimgt.tracing/pom.xml +++ b/components/apimgt/org.wso2.carbon.apimgt.tracing/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.apimgt apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/components/apimgt/pom.xml b/components/apimgt/pom.xml index f86f15cfef14..51ba6ab1c2e2 100644 --- a/components/apimgt/pom.xml +++ b/components/apimgt/pom.xml @@ -19,7 +19,7 @@ org.wso2.carbon.apimgt carbon-apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../../pom.xml diff --git a/components/apimgt/samples/org.wso2.carbon.apimgt.samples.calculator/pom.xml b/components/apimgt/samples/org.wso2.carbon.apimgt.samples.calculator/pom.xml index aada927337e1..fe8cbe752221 100644 --- a/components/apimgt/samples/org.wso2.carbon.apimgt.samples.calculator/pom.xml +++ b/components/apimgt/samples/org.wso2.carbon.apimgt.samples.calculator/pom.xml @@ -19,7 +19,7 @@ apimgt org.wso2.carbon.apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../../pom.xml diff --git a/components/apimgt/samples/org.wso2.carbon.apimgt.samples.pizzashack/pom.xml b/components/apimgt/samples/org.wso2.carbon.apimgt.samples.pizzashack/pom.xml index 6ec04e24c6fb..9fbe39f981dd 100644 --- a/components/apimgt/samples/org.wso2.carbon.apimgt.samples.pizzashack/pom.xml +++ b/components/apimgt/samples/org.wso2.carbon.apimgt.samples.pizzashack/pom.xml @@ -20,7 +20,7 @@ apimgt org.wso2.carbon.apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.cache.invalidation.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.cache.invalidation.feature/pom.xml index 152d86d9950d..35f9831d46b0 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.cache.invalidation.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.cache.invalidation.feature/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.core.feature/pom.xml index aca041fb605e..7bad5fa8dffb 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/org.wso2.carbon.apimgt.core.default.json b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/org.wso2.carbon.apimgt.core.default.json index ad67edf92bc7..1331a31019a3 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/org.wso2.carbon.apimgt.core.default.json +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/org.wso2.carbon.apimgt.core.default.json @@ -63,6 +63,7 @@ "apim.key_manager.pool.init_idle_capacity": "50", "apim.key_manager.key_validation_handler_impl": "org.wso2.carbon.apimgt.keymgt.handlers.DefaultKeyValidationHandler", "apim.key_manager.enable_provisioned_app_validation": true, + "apim.key_manager.allow_subscription_validation_disabling": true, "apim.monetization.publish_duration": "1d", "apim.monetization.granularity": "days", "apim.monetization.monetization_impl": "org.wso2.carbon.apimgt.impl.monetization.DefaultMonetizationImpl", @@ -130,6 +131,7 @@ "apim.throttling.enable_query_param_based_throttling": "false", "apim.throttling.jms.java_naming_factory_initial": "org.wso2.andes.jndi.PropertiesFileInitialContextFactory", "apim.throttling.enable_policy_deployment": true, + "apim.throttling.enable_policy_recreation_on_startup": true, "server.mode": "single", "apim.workflow.enable": "false", "apim.workflow.service_url": "https://localhost:9445/bpmn", diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/templates/repository/conf/api-manager.xml.j2 b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/templates/repository/conf/api-manager.xml.j2 index 1607b483efbc..ca8a5bf09771 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/templates/repository/conf/api-manager.xml.j2 +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/conf_templates/templates/repository/conf/api-manager.xml.j2 @@ -437,6 +437,7 @@ {% if apim.key_manager.enable_apikey_subscription_validation is defined %} {{apim.key_manager.enable_apikey_subscription_validation}} {% endif %} + {{apim.key_manager.allow_subscription_validation_disabling}} @@ -1106,6 +1107,7 @@ 2000 1000 60 + 100000 <50PerMin>50 @@ -1124,6 +1126,7 @@ {{apim.throttling.enable_query_param_based_throttling}} RequestPreProcessorExecutionPlan{% for policy in apim.throttling.skip_redeploying_policies %}{{ "," if loop.first }}{{policy}}{{ "," if not loop.last }}{% endfor %} {{apim.throttling.enable_policy_deployment}} + {{apim.throttling.enable_policy_recreation_on_startup}} diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/OGG/oracle/apimgt/tables.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/OGG/oracle/apimgt/tables.sql index 837842051ad5..16b7d7ea56b3 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/OGG/oracle/apimgt/tables.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/OGG/oracle/apimgt/tables.sql @@ -1489,6 +1489,7 @@ CREATE TABLE AM_API ( VERSION_COMPARABLE VARCHAR(15), LOG_LEVEL VARCHAR(255) DEFAULT 'OFF', REVISIONS_CREATED INTEGER DEFAULT 0, + SUB_VALIDATION VARCHAR(10) DEFAULT 'ENABLED', IS_EGRESS INTEGER DEFAULT 0, PRIMARY KEY(API_ID), UNIQUE (API_PROVIDER,API_NAME,API_VERSION,ORGANIZATION), diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/OGG/oracle/apimgt/tables_23c.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/OGG/oracle/apimgt/tables_23c.sql index ec7d98017533..25ecda61f38d 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/OGG/oracle/apimgt/tables_23c.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/OGG/oracle/apimgt/tables_23c.sql @@ -1489,6 +1489,7 @@ CREATE TABLE AM_API ( VERSION_COMPARABLE VARCHAR(15), LOG_LEVEL VARCHAR(255) DEFAULT 'OFF', REVISIONS_CREATED INTEGER DEFAULT 0, + SUB_VALIDATION VARCHAR(10) DEFAULT 'ENABLED', IS_EGRESS INTEGER DEFAULT 0, PRIMARY KEY(API_ID), UNIQUE (API_PROVIDER,API_NAME,API_VERSION,ORGANIZATION), diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/Postgresql/apimgt/tables.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/Postgresql/apimgt/tables.sql index f3d456093d50..6a9900d85673 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/Postgresql/apimgt/tables.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/Postgresql/apimgt/tables.sql @@ -1853,6 +1853,7 @@ CREATE TABLE IF NOT EXISTS AM_API ( VERSION_COMPARABLE VARCHAR(15), LOG_LEVEL VARCHAR(255) DEFAULT 'OFF', REVISIONS_CREATED INTEGER DEFAULT 0, + SUB_VALIDATION VARCHAR(10) DEFAULT 'ENABLED', IS_EGRESS INTEGER DEFAULT 0, PRIMARY KEY(API_ID), UNIQUE (API_PROVIDER,API_NAME,API_VERSION,ORGANIZATION), diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/SQLServer/mssql/apimgt/tables.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/SQLServer/mssql/apimgt/tables.sql index 2afc4367dc24..b383d7f619dc 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/SQLServer/mssql/apimgt/tables.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/multi-dc/SQLServer/mssql/apimgt/tables.sql @@ -1723,6 +1723,7 @@ CREATE TABLE AM_API ( STATUS VARCHAR(30), VERSION_COMPARABLE VARCHAR(15), LOG_LEVEL VARCHAR(255) DEFAULT 'OFF', + SUB_VALIDATION VARCHAR(10) DEFAULT 'ENABLED', PRIMARY KEY(API_ID), UNIQUE (API_PROVIDER,API_NAME,API_VERSION,ORGANIZATION), UNIQUE (API_UUID) diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/db2.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/db2.sql index 78f1932daeb2..be500f9ff8c5 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/db2.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/db2.sql @@ -2333,6 +2333,7 @@ CREATE TABLE AM_API ( STATUS VARCHAR(30), VERSION_COMPARABLE VARCHAR(15), LOG_LEVEL VARCHAR(255) DEFAULT 'OFF', + SUB_VALIDATION VARCHAR(10) DEFAULT 'ENABLED', IS_EGRESS INTEGER DEFAULT 0, UNIQUE (API_UUID), UNIQUE (API_PROVIDER,API_NAME,API_VERSION,ORGANIZATION) diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/h2.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/h2.sql index dedc65a03f51..1287eaf55ba3 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/h2.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/h2.sql @@ -1579,6 +1579,7 @@ CREATE TABLE IF NOT EXISTS AM_API ( STATUS VARCHAR(30), VERSION_COMPARABLE VARCHAR(15), LOG_LEVEL VARCHAR(255) DEFAULT 'OFF', + SUB_VALIDATION VARCHAR(10) DEFAULT 'ENABLED', IS_EGRESS INTEGER DEFAULT 0, UNIQUE (API_UUID), UNIQUE (API_PROVIDER,API_NAME,API_VERSION,ORGANIZATION) diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mssql.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mssql.sql index df031bd08186..53fdc16652f1 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mssql.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mssql.sql @@ -1733,6 +1733,7 @@ CREATE TABLE AM_API ( STATUS VARCHAR(30), VERSION_COMPARABLE VARCHAR(15), LOG_LEVEL VARCHAR(255) DEFAULT 'OFF', + SUB_VALIDATION VARCHAR(10) DEFAULT 'ENABLED', IS_EGRESS INTEGER DEFAULT 0, PRIMARY KEY(API_ID), UNIQUE (API_PROVIDER,API_NAME,API_VERSION,ORGANIZATION), diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mysql.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mysql.sql index 5204c3e8b077..8de0decd81a7 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mysql.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mysql.sql @@ -1518,6 +1518,7 @@ CREATE TABLE IF NOT EXISTS AM_API ( IS_EGRESS INTEGER DEFAULT 0, REVISIONS_CREATED INTEGER DEFAULT 0, VERSION_COMPARABLE VARCHAR(15), + SUB_VALIDATION VARCHAR(10) DEFAULT 'ENABLED', PRIMARY KEY(API_ID), UNIQUE (API_PROVIDER,API_NAME,API_VERSION,ORGANIZATION), UNIQUE (API_UUID) diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mysql_cluster.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mysql_cluster.sql index 89b9d293f709..27c5f2f78058 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mysql_cluster.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/mysql_cluster.sql @@ -1703,6 +1703,7 @@ CREATE TABLE IF NOT EXISTS AM_API ( LOG_LEVEL VARCHAR(255) DEFAULT 'OFF', IS_EGRESS INTEGER DEFAULT 0, REVISIONS_CREATED INTEGER DEFAULT 0, + SUB_VALIDATION VARCHAR(10) DEFAULT 'ENABLED', PRIMARY KEY(API_ID), UNIQUE (API_PROVIDER,API_NAME,API_VERSION,ORGANIZATION), UNIQUE (API_UUID) diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/oracle.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/oracle.sql index 2c52981b4264..6e072f6bcda1 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/oracle.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/oracle.sql @@ -2464,6 +2464,7 @@ CREATE TABLE AM_API ( LOG_LEVEL VARCHAR(255) DEFAULT 'OFF', IS_EGRESS INTEGER DEFAULT 0, REVISIONS_CREATED INTEGER DEFAULT 0, + SUB_VALIDATION VARCHAR(10) DEFAULT 'ENABLED', PRIMARY KEY(API_ID), UNIQUE (API_PROVIDER,API_NAME,API_VERSION,ORGANIZATION), UNIQUE (API_UUID) diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/oracle_23c.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/oracle_23c.sql index 191035d20dfc..9988a92fe6eb 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/oracle_23c.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/oracle_23c.sql @@ -2464,6 +2464,7 @@ CREATE TABLE AM_API ( LOG_LEVEL VARCHAR(255) DEFAULT 'OFF', IS_EGRESS INTEGER DEFAULT 0, REVISIONS_CREATED INTEGER DEFAULT 0, + SUB_VALIDATION VARCHAR(10) DEFAULT 'ENABLED', PRIMARY KEY(API_ID), UNIQUE (API_PROVIDER,API_NAME,API_VERSION,ORGANIZATION), UNIQUE (API_UUID) diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/oracle_rac.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/oracle_rac.sql index 946a660a2e96..62fcabf0ac02 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/oracle_rac.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/oracle_rac.sql @@ -2454,6 +2454,7 @@ CREATE TABLE AM_API ( LOG_LEVEL VARCHAR(255) DEFAULT 'OFF', IS_EGRESS INTEGER DEFAULT 0, REVISIONS_CREATED INTEGER DEFAULT 0, + SUB_VALIDATION VARCHAR(10) DEFAULT 'ENABLED', PRIMARY KEY(API_ID), UNIQUE (API_PROVIDER,API_NAME,API_VERSION,ORGANIZATION), UNIQUE (API_UUID) diff --git a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/postgresql.sql b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/postgresql.sql index cc82c655eed8..692bdd7f9341 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/postgresql.sql +++ b/features/apimgt/org.wso2.carbon.apimgt.core.feature/src/main/resources/sql/postgresql.sql @@ -1854,6 +1854,7 @@ CREATE TABLE IF NOT EXISTS AM_API ( LOG_LEVEL VARCHAR(255) DEFAULT 'OFF', IS_EGRESS INTEGER DEFAULT 0, REVISIONS_CREATED INTEGER DEFAULT 0, + SUB_VALIDATION VARCHAR(10) DEFAULT 'ENABLED', PRIMARY KEY(API_ID), UNIQUE (API_PROVIDER,API_NAME,API_VERSION,ORGANIZATION), UNIQUE (API_UUID) diff --git a/features/apimgt/org.wso2.carbon.apimgt.eventing.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.eventing.feature/pom.xml index 5f91a21db782..121e286923c2 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.eventing.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.eventing.feature/pom.xml @@ -20,7 +20,7 @@ apimgt-feature org.wso2.carbon.apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.eventing.hub.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.eventing.hub.feature/pom.xml index 077c1915f161..5b2abedb022c 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.eventing.hub.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.eventing.hub.feature/pom.xml @@ -20,7 +20,7 @@ apimgt-feature org.wso2.carbon.apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.feature/pom.xml index 362b228e3c21..afced47334f4 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.feature/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.gateway.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.gateway.feature/pom.xml index 16711d611287..106ac7b12771 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.gateway.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.gateway.feature/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.internal.service.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.internal.service.feature/pom.xml index 88f6a66eaa0f..e92877e2baf5 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.internal.service.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.internal.service.feature/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.jms.listener.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.jms.listener.feature/pom.xml index 9120c21814fe..76bcd33c86ea 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.jms.listener.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.jms.listener.feature/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.keymanager.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.keymanager.feature/pom.xml index 8b7956c75645..ee2db26157d3 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.keymanager.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.keymanager.feature/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.persistence.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.persistence.feature/pom.xml index ccfdff899fe0..c1c8f1c23682 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.persistence.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.persistence.feature/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.rest.api.admin.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.rest.api.admin.feature/pom.xml index 427169704ea9..d03ca0d9ec81 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.rest.api.admin.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.rest.api.admin.feature/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.rest.api.dcr.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.rest.api.dcr.feature/pom.xml index 12f64723bd17..fd40d0066ac2 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.rest.api.dcr.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.rest.api.dcr.feature/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.rest.api.devops.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.rest.api.devops.feature/pom.xml index 2bd8fff4909a..d743f1ebe17b 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.rest.api.devops.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.rest.api.devops.feature/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.rest.api.gateway.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.rest.api.gateway.feature/pom.xml index 38fd50d9bf58..d5dfac688232 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.rest.api.gateway.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.rest.api.gateway.feature/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.feature/pom.xml index 3e1dfb4ec697..84ed7f067122 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.rest.api.publisher.feature/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.rest.api.service.catalog.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.rest.api.service.catalog.feature/pom.xml index 74f3ca0a5b2a..176612eb6435 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.rest.api.service.catalog.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.rest.api.service.catalog.feature/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.rest.api.store.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.rest.api.store.feature/pom.xml index e7477a77a44c..78831be5805e 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.rest.api.store.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.rest.api.store.feature/pom.xml @@ -21,7 +21,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.scxml.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.scxml.feature/pom.xml index 92c25d77beec..8e02f41f75a8 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.scxml.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.scxml.feature/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.throttle.policy.deployer.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.throttle.policy.deployer.feature/pom.xml index be5556cfa79c..f82075a6f29a 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.throttle.policy.deployer.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.throttle.policy.deployer.feature/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.throttling.siddhi.extension.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.throttling.siddhi.extension.feature/pom.xml index a61119c6f006..509eb49d00d9 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.throttling.siddhi.extension.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.throttling.siddhi.extension.feature/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.tokenmgt.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.tokenmgt.feature/pom.xml index 2f7c8c3c7f29..905e3bbb044b 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.tokenmgt.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.tokenmgt.feature/pom.xml @@ -20,7 +20,7 @@ org.wso2.carbon.apimgt apimgt-feature - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/features/apimgt/org.wso2.carbon.apimgt.tracing.feature/pom.xml b/features/apimgt/org.wso2.carbon.apimgt.tracing.feature/pom.xml index a134a53b5f52..f0589ea7a445 100644 --- a/features/apimgt/org.wso2.carbon.apimgt.tracing.feature/pom.xml +++ b/features/apimgt/org.wso2.carbon.apimgt.tracing.feature/pom.xml @@ -21,7 +21,7 @@ apimgt-feature org.wso2.carbon.apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT 4.0.0 diff --git a/features/apimgt/pom.xml b/features/apimgt/pom.xml index e6b6e8aeb3f1..1f00cdf35a4f 100644 --- a/features/apimgt/pom.xml +++ b/features/apimgt/pom.xml @@ -19,7 +19,7 @@ org.wso2.carbon.apimgt carbon-apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../../pom.xml diff --git a/pom.xml b/pom.xml index 3f97672312ac..2b247244111d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.wso2.carbon.apimgt carbon-apimgt pom - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT WSO2 Carbon - API Management Aggregator POM https://wso2.org @@ -2012,7 +2012,7 @@ 1.3 - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT [9.0.0, 10.0.0) 5.3.13 @@ -2024,12 +2024,12 @@ 4.9.11 4.8.36 - 4.7.204 + 4.7.218 4.1.0 - 5.25.711 + 5.25.713 1.8.107 6.13.19 2.2.4 @@ -2044,7 +2044,7 @@ [19.0,20.0) 4.8.34 - 4.11.14 + 4.11.16 4.9.27 1.6.5 1.10.0 @@ -2104,7 +2104,7 @@ [1.6.0, 2.0.0) - 4.0.0-wso2v105 + 4.0.0-wso2v125 3.0.0.wso2v1 @@ -2137,7 +2137,7 @@ 1.1.1 2.15.1.wso2v1 3.1 - 2.10.1 + 2.11.0 4.5.10 1.16.0 9.37.3.wso2v1 @@ -2169,7 +2169,7 @@ 4.2.1 - 3.6.3 + 3.6.4 1.3.12 2.3.12 @@ -2186,7 +2186,7 @@ 2.12.2.wso2v1 0.9.0.wso2v2 2.3 - 2.16.1 + 2.17.2 2.0.1.Final 1 3.3.33 @@ -2260,7 +2260,7 @@ 8.34 1.4.1.wso2v1 1.4.1.Final - 1.2.18 + 1.2.19 [1.0.0,2.0.0) 2.12.1.wso2v2 ${project.parent.basedir}/../../spotbugs-exclude.xml diff --git a/service-stubs/apimgt/org.wso2.carbon.apimgt.keymgt.stub/pom.xml b/service-stubs/apimgt/org.wso2.carbon.apimgt.keymgt.stub/pom.xml index 0be0d69941a2..3534d408e2f4 100644 --- a/service-stubs/apimgt/org.wso2.carbon.apimgt.keymgt.stub/pom.xml +++ b/service-stubs/apimgt/org.wso2.carbon.apimgt.keymgt.stub/pom.xml @@ -22,7 +22,7 @@ org.wso2.carbon.apimgt apimgt-stubs - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../pom.xml diff --git a/service-stubs/apimgt/pom.xml b/service-stubs/apimgt/pom.xml index a79744aae11d..e056a602154a 100644 --- a/service-stubs/apimgt/pom.xml +++ b/service-stubs/apimgt/pom.xml @@ -19,7 +19,7 @@ org.wso2.carbon.apimgt carbon-apimgt - 9.29.200-SNAPSHOT + 9.29.205-SNAPSHOT ../../pom.xml