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