From 4dccd035613a7f62098ba73ff058a76b8c06f8a8 Mon Sep 17 00:00:00 2001 From: sgayangi Date: Fri, 23 Aug 2024 15:26:37 +0530 Subject: [PATCH] Add config deployer changes for gRPC APIs --- .../ballerina/APIClient.bal | 168 +- .../ballerina/Ballerina.toml | 10 + .../ballerina/Ballerina.toml.template | 6 + .../ballerina/ConfigGenreatorClient.bal | 20 +- .../ballerina/Dependencies.toml | 13 +- .../ballerina/DeployerClient.bal | 94 +- .../ballerina/K8sClient.bal | 44 +- .../ballerina/constants.bal | 4 +- .../ballerina/modules/model/API.bal | 4 +- .../ballerina/modules/model/APIArtifact.bal | 2 + .../ballerina/modules/model/GRPCRoute.bal | 70 + .../RuntimeAPICommonUtil.bal | 7 +- .../config-deployer-service/java/build.gradle | 1 + .../org/wso2/apk/config/APIConstants.java | 5 +- .../apk/config/DefinitionParserFactory.java | 6 + .../wso2/apk/config/RuntimeAPICommonUtil.java | 57 +- .../wso2/apk/config/api/ExceptionCodes.java | 1769 +++++++++-------- .../apk/config/definitions/OASParserUtil.java | 118 +- .../apk/config/definitions/ProtoParser.java | 336 ++++ .../config/definitions/ProtoParserUtil.java | 70 + .../java/org/wso2/apk/config/model/API.java | 9 + 21 files changed, 1912 insertions(+), 901 deletions(-) create mode 100644 runtime/config-deployer-service/ballerina/modules/model/GRPCRoute.bal create mode 100644 runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/ProtoParser.java create mode 100644 runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/ProtoParserUtil.java diff --git a/runtime/config-deployer-service/ballerina/APIClient.bal b/runtime/config-deployer-service/ballerina/APIClient.bal index 4331101e8..d4acec057 100644 --- a/runtime/config-deployer-service/ballerina/APIClient.bal +++ b/runtime/config-deployer-service/ballerina/APIClient.bal @@ -46,7 +46,7 @@ public class APIClient { encodedString = encodedString.substring(0, encodedString.length() - 1); } APKConf apkConf = { - name: api.getName(), + name: self.getAPIName(api.getName(), api.getType()), basePath: api.getBasePath().length() > 0 ? api.getBasePath() : encodedString, version: api.getVersion(), 'type: api.getType() == "" ? API_TYPE_REST : api.getType().toUpperAscii() @@ -138,6 +138,11 @@ public class APIClient { _ = check self.setRoute(apiArtifact, apkConf, createdEndpoints.hasKey(PRODUCTION_TYPE) ? createdEndpoints.get(PRODUCTION_TYPE) : (), uniqueId, PRODUCTION_TYPE, organization); _ = check self.setRoute(apiArtifact, apkConf, createdEndpoints.hasKey(SANDBOX_TYPE) ? createdEndpoints.get(SANDBOX_TYPE) : (), uniqueId, SANDBOX_TYPE, organization); string|json generatedSwagger = check self.retrieveGeneratedSwaggerDefinition(apkConf, definition); + if generatedSwagger is string { + log:printInfo(generatedSwagger); + } else { + log:printInfo(generatedSwagger.toJsonString()); + } check self.retrieveGeneratedConfigmapForDefinition(apiArtifact, apkConf, generatedSwagger, uniqueId, organization); self.generateAndSetAPICRArtifact(apiArtifact, apkConf, organization); _ = check self.generateAndSetPolicyCRArtifact(apiArtifact, apkConf, organization); @@ -288,6 +293,14 @@ public class APIClient { return backendSpec.protocol + "://" + backendSpec.services[0].host + backendSpec.services[0].port.toString(); } + isolated function returnFullGRPCBasePath(string basePath, string 'version) returns string { + string fullBasePath = basePath; + if (!string:endsWith(basePath, 'version)) { + fullBasePath = string:'join(".", basePath, 'version); + } + return fullBasePath; + } + private isolated function retrieveGeneratedConfigmapForDefinition(model:APIArtifact apiArtifact, APKConf apkConf, string|json generatedSwaggerDefinition, string uniqueId, commons:Organization organization) returns error? { byte[]|javaio:IOException compressedContent = []; if apkConf.'type == API_TYPE_REST { @@ -421,7 +434,7 @@ public class APIClient { }, spec: { apiName: apkConf.name, - apiType: apkConf.'type == "GRAPHQL" ? "GraphQL" : apkConf.'type, + apiType: self.getAPIType(apkConf.'type), apiVersion: apkConf.'version, basePath: self.returnFullBasePath(apkConf.basePath, apkConf.'version), isDefaultVersion: apkConf.defaultVersion, @@ -459,6 +472,18 @@ public class APIClient { sandboxRoutes.push(httpRoute.metadata.name); } } + } else if apkConf.'type == API_TYPE_GRPC { + k8sAPI.spec.basePath = self.returnFullGRPCBasePath(apkConf.basePath, apkConf.'version); + foreach model:GRPCRoute grpcRoute in apiArtifact.productionGrpcRoutes { + if grpcRoute.spec.rules.length() > 0 { + productionRoutes.push(grpcRoute.metadata.name); + } + } + foreach model:GRPCRoute grpcRoute in apiArtifact.sandboxGrpcRoutes { + if grpcRoute.spec.rules.length() > 0 { + sandboxRoutes.push(grpcRoute.metadata.name); + } + } } if productionRoutes.length() > 0 { @@ -484,6 +509,15 @@ public class APIClient { return uniqueId + "-definition"; } + private isolated function getAPIType(string apiType) returns string { + if apiType.toUpperAscii() == "GRAPHQL" { + return "GraphQL"; + } else if apiType.toUpperAscii() == "GRPC" { + return "gRPC"; + } + return apiType; + } + private isolated function retrieveDisableAuthenticationRefName(APKConf apkConf, string 'type, commons:Organization organization) returns string { return self.getUniqueIdForAPI(apkConf.name, apkConf.'version, organization) + "-" + 'type + "-no-authentication"; } @@ -558,6 +592,26 @@ public class APIClient { apiArtifact.sandboxHttpRoutes.push(httpRoute); } } + } else if apkConf.'type == API_TYPE_GRPC { + model:GRPCRoute grpcRoute = { + metadata: + { + name: uniqueId + "-" + endpointType + "-grpcroute-" + count.toString(), + labels: self.getLabels(apkConf, organization) + }, + spec: { + parentRefs: self.generateAndRetrieveParentRefs(apkConf, uniqueId), + rules: check self.generateGRPCRouteRules(apiArtifact, apkConf, endpoint, endpointType, organization), + hostnames: self.getHostNames(apkConf, uniqueId, endpointType, organization) + } + }; + if grpcRoute.spec.rules.length() > 0 { + if endpointType == PRODUCTION_TYPE { + apiArtifact.productionGrpcRoutes.push(grpcRoute); + } else { + apiArtifact.sandboxGrpcRoutes.push(grpcRoute); + } + } } else { return e909018("Invalid API Type specified"); } @@ -579,7 +633,7 @@ public class APIClient { APKOperations[]? operations = apkConf.operations; if operations is APKOperations[] { foreach APKOperations operation in operations { - model:HTTPRouteRule|model:GQLRouteRule|() routeRule = check self.generateRouteRule(apiArtifact, apkConf, endpoint, operation, endpointType, organization); + model:HTTPRouteRule|model:GQLRouteRule|model:GRPCRouteRule|() routeRule = check self.generateRouteRule(apiArtifact, apkConf, endpoint, operation, endpointType, organization); if routeRule is model:HTTPRouteRule { model:HTTPRouteFilter[]? filters = routeRule.filters; if filters is () { @@ -638,7 +692,7 @@ public class APIClient { APKOperations[]? operations = apkConf.operations; if operations is APKOperations[] { foreach APKOperations operation in operations { - model:HTTPRouteRule|model:GQLRouteRule|() routeRule = check self.generateRouteRule(apiArtifact, apkConf, endpoint, operation, endpointType, organization); + model:HTTPRouteRule|model:GQLRouteRule|model:GRPCRouteRule|() routeRule = check self.generateRouteRule(apiArtifact, apkConf, endpoint, operation, endpointType, organization); if routeRule is model:GQLRouteRule { model:GQLRouteFilter[]? filters = routeRule.filters; if filters is () { @@ -692,6 +746,66 @@ public class APIClient { return gqlRouteRules; } + private isolated function generateGRPCRouteRules(model:APIArtifact apiArtifact, APKConf apkConf, model:Endpoint? endpoint, string endpointType, commons:Organization organization) returns model:GRPCRouteRule[]|commons:APKError|error { + model:GRPCRouteRule[] grpcRouteRules = []; + APKOperations[]? operations = apkConf.operations; + if operations is APKOperations[] { + foreach APKOperations operation in operations { + model:HTTPRouteRule|model:GQLRouteRule|model:GRPCRouteRule|() routeRule = check self.generateRouteRule(apiArtifact, apkConf, endpoint, operation, endpointType, organization); + if routeRule is model:GRPCRouteRule { + model:GRPCRouteFilter[]? filters = routeRule.filters; + if filters is () { + filters = []; + routeRule.filters = filters; + } + string disableAuthenticationRefName = self.retrieveDisableAuthenticationRefName(apkConf, endpointType, organization); + if !(operation.secured ?: true) { + if !apiArtifact.authenticationMap.hasKey(disableAuthenticationRefName) { + model:Authentication generateDisableAuthenticationCR = self.generateDisableAuthenticationCR(apiArtifact, apkConf, endpointType, organization); + apiArtifact.authenticationMap[disableAuthenticationRefName] = generateDisableAuthenticationCR; + } + model:GRPCRouteFilter disableAuthenticationFilter = {'type: "ExtensionRef", extensionRef: {group: "dp.wso2.com", kind: "Authentication", name: disableAuthenticationRefName}}; + (filters).push(disableAuthenticationFilter); + } + string[]? scopes = operation.scopes; + if scopes is string[] { + int count = 1; + foreach string scope in scopes { + model:Scope scopeCr; + if apiArtifact.scopes.hasKey(scope) { + scopeCr = apiArtifact.scopes.get(scope); + } else { + scopeCr = self.generateScopeCR(operation, apiArtifact, apkConf, organization, scope, count); + count = count + 1; + } + model:GRPCRouteFilter scopeFilter = {'type: "ExtensionRef", extensionRef: {group: "dp.wso2.com", kind: scopeCr.kind, name: scopeCr.metadata.name}}; + (filters).push(scopeFilter); + } + } + if operation.rateLimit != () { + model:RateLimitPolicy? rateLimitPolicyCR = self.generateRateLimitPolicyCR(apkConf, operation.rateLimit, apiArtifact.uniqueId, operation, organization); + if rateLimitPolicyCR != () { + apiArtifact.rateLimitPolicies[rateLimitPolicyCR.metadata.name] = rateLimitPolicyCR; + model:GRPCRouteFilter rateLimitPolicyFilter = {'type: "ExtensionRef", extensionRef: {group: "dp.wso2.com", kind: "RateLimitPolicy", name: rateLimitPolicyCR.metadata.name}}; + (filters).push(rateLimitPolicyFilter); + } + } + if operation.operationPolicies != () { + model:APIPolicy? apiPolicyCR = check self.generateAPIPolicyAndBackendCR(apiArtifact, apkConf, operation, operation.operationPolicies, organization, apiArtifact.uniqueId); + + if apiPolicyCR != () { + apiArtifact.apiPolicies[apiPolicyCR.metadata.name] = apiPolicyCR; + model:GRPCRouteFilter apiPolicyFilter = {'type: "ExtensionRef", extensionRef: {group: "dp.wso2.com", kind: "APIPolicy", name: apiPolicyCR.metadata.name}}; + (filters).push(apiPolicyFilter); + } + } + grpcRouteRules.push(routeRule); + } + } + } + return grpcRouteRules; + } + private isolated function generateAPIPolicyAndBackendCR(model:APIArtifact apiArtifact, APKConf apkConf, APKOperations? operations, APIOperationPolicies? policies, commons:Organization organization, string targetRefName) returns model:APIPolicy?|error { model:APIPolicyData defaultSpecData = {}; APKRequestOperationPolicy[]? request = policies?.request; @@ -762,13 +876,16 @@ public class APIClient { return authentication; } - private isolated function generateRouteRule(model:APIArtifact apiArtifact, APKConf apkConf, model:Endpoint? endpoint, APKOperations operation, string endpointType, commons:Organization organization) returns model:HTTPRouteRule|model:GQLRouteRule|()|commons:APKError { + private isolated function generateRouteRule(model:APIArtifact apiArtifact, APKConf apkConf, model:Endpoint? endpoint, APKOperations operation, string endpointType, commons:Organization organization) + returns model:HTTPRouteRule|model:GQLRouteRule|model:GRPCRouteRule|()|commons:APKError { + do { EndpointConfigurations? endpointConfig = operation.endpointConfigurations; model:Endpoint? endpointToUse = (); if endpointConfig is EndpointConfigurations { // endpointConfig presence at Operation Level. - map operationalLevelBackend = check self.createAndAddBackendServices(apiArtifact, apkConf, endpointConfig, operation, endpointType, organization); + map operationalLevelBackend = check self.createAndAddBackendServices(apiArtifact, apkConf, + endpointConfig, operation, endpointType, organization); if operationalLevelBackend.hasKey(endpointType) { endpointToUse = operationalLevelBackend.get(endpointType); } @@ -798,6 +915,14 @@ public class APIClient { httpRouteRule.backendRefs = self.retrieveGeneratedBackend(apkConf, endpointToUse, endpointType); } return httpRouteRule; + } else if apkConf.'type == API_TYPE_GRPC { + model:GRPCRouteMatch[]|error routeMatches = self.retrieveGRPCMatches(apkConf, operation, organization); + if routeMatches is model:GRPCRouteMatch[] && routeMatches.length() > 0 { + model:GRPCRouteRule grpcRouteRule = {matches: routeMatches, backendRefs: self.retrieveGeneratedBackend(apkConf, endpointToUse, endpointType)}; + return grpcRouteRule; + } else { + return e909022("Provided Type currently not supported for GRPC APIs.", error("Provided Type currently not supported for GRPC APIs.")); + } } else { return e909018("Invalid API Type specified"); } @@ -1097,7 +1222,13 @@ public class APIClient { gqlRouteMatch.push(gqlRoute); } return gqlRouteMatch; + } + private isolated function retrieveGRPCMatches(APKConf apkConf, APKOperations apiOperation, commons:Organization organization) returns model:GRPCRouteMatch[] { + model:GRPCRouteMatch[] grpcRouteMatch = []; + model:GRPCRouteMatch grpcRoute = self.retrieveGRPCRouteMatch(apiOperation); + grpcRouteMatch.push(grpcRoute); + return grpcRouteMatch; } private isolated function retrieveHttpRouteMatch(APKConf apkConf, APKOperations apiOperation, commons:Organization organization) returns model:HTTPRouteMatch { @@ -1114,6 +1245,17 @@ public class APIClient { } } + private isolated function retrieveGRPCRouteMatch(APKOperations apiOperation) returns model:GRPCRouteMatch { + model:GRPCRouteMatch grpcRouteMatch = { + method: { + 'type: "Exact", + 'service: apiOperation.target, + method: apiOperation.verb + } + }; + return grpcRouteMatch; + } + isolated function retrieveGeneratedSwaggerDefinition(APKConf apkConf, string? definition) returns string|json|commons:APKError|error { runtimeModels:API api1 = runtimeModels:newAPI1(); api1.setName(apkConf.name); @@ -1831,7 +1973,7 @@ public class APIClient { } else if definitionFile.fileName.endsWith(".json") { apiDefinition = definitionFileContent; } - } else if apiType == API_TYPE_GRAPHQL { + } else if apiType == API_TYPE_GRAPHQL || apiType == API_TYPE_GRPC { apiDefinition = definitionFileContent; } if apkConf is () { @@ -1848,4 +1990,16 @@ public class APIClient { } } + + private isolated function getAPIName(string apiName, string apiType) returns string { + if apiType.toUpperAscii() == API_TYPE_GRPC { + return self.getUniqueNameForGrpcApi(apiName); + } + return apiName; + } + + public isolated function getUniqueNameForGrpcApi(string concatanatedServices) returns string { + byte[] hashedValue = crypto:hashSha1(concatanatedServices.toBytes()); + return hashedValue.toBase16(); + } } diff --git a/runtime/config-deployer-service/ballerina/Ballerina.toml b/runtime/config-deployer-service/ballerina/Ballerina.toml index 7546eb4cf..1f90067f0 100644 --- a/runtime/config-deployer-service/ballerina/Ballerina.toml +++ b/runtime/config-deployer-service/ballerina/Ballerina.toml @@ -373,6 +373,11 @@ groupId = "joda-time" artifactId = "joda-time" version = "2.10.2" +# transitive dependency of com.google.protobuf:protobuf-java:3.21.7 +[[platform.java11.dependency]] +groupId = "com.google.protobuf" +artifactId = "protobuf-java" +version = "3.21.7" # transitive dependency of org.wso2.apk:org.wso2.apk.config:1.1.0-SNAPSHOT [[platform.java11.dependency]] @@ -385,3 +390,8 @@ version = "20231013" groupId = "commons-lang" artifactId = "commons-lang" version = "2.4" + +[[platform.java11.dependency]] +groupId = "org.wso2.apk" +artifactId = "org.wso2.apk.config" +version = "1.1.0-SNAPSHOT" diff --git a/runtime/config-deployer-service/ballerina/Ballerina.toml.template b/runtime/config-deployer-service/ballerina/Ballerina.toml.template index 9fba67b1b..9edcdc00c 100644 --- a/runtime/config-deployer-service/ballerina/Ballerina.toml.template +++ b/runtime/config-deployer-service/ballerina/Ballerina.toml.template @@ -319,6 +319,12 @@ groupId = "org.reactivestreams" artifactId = "reactive-streams" version = "1.0.3" +# transitive dependency of com.google.protobuf:protobuf-java:3.21.7 +[[platform.java11.dependency]] +groupId = "com.google.protobuf" +artifactId = "protobuf-java" +version = "3.21.7" + # transitive dependency of org.wso2.apk:org.wso2.apk.config:1.0.0-SNAPSHOT [[platform.java11.dependency]] groupId = "com.fasterxml.jackson.core" diff --git a/runtime/config-deployer-service/ballerina/ConfigGenreatorClient.bal b/runtime/config-deployer-service/ballerina/ConfigGenreatorClient.bal index e410cdb51..07f4f649b 100644 --- a/runtime/config-deployer-service/ballerina/ConfigGenreatorClient.bal +++ b/runtime/config-deployer-service/ballerina/ConfigGenreatorClient.bal @@ -1,17 +1,19 @@ -import wso2/apk_common_lib as commons; -import ballerina/http; -import config_deployer_service.org.wso2.apk.config.api as runtimeapi; -import config_deployer_service.org.wso2.apk.config.model as runtimeModels; import config_deployer_service.java.util as utilapis; -import config_deployer_service.org.wso2.apk.config as runtimeUtil; -import ballerina/mime; -import ballerina/jballerina.java; import config_deployer_service.model; -import ballerina/io; +import config_deployer_service.org.wso2.apk.config as runtimeUtil; +import config_deployer_service.org.wso2.apk.config.api as runtimeapi; +import config_deployer_service.org.wso2.apk.config.model as runtimeModels; + import ballerina/file; +import ballerina/http; +import ballerina/io; +import ballerina/jballerina.java; import ballerina/log; +import ballerina/mime; import ballerina/uuid; +import wso2/apk_common_lib as commons; + public class ConfigGeneratorClient { public isolated function getGeneratedAPKConf(http:Request request) returns OkAnydata|commons:APKError|BadRequestError { @@ -93,7 +95,7 @@ public class ConfigGeneratorClient { private isolated function validateAndRetrieveDefinition(string 'type, string? url, byte[]? content, string? fileName) returns runtimeapi:APIDefinitionValidationResponse|runtimeapi:APIManagementException|error|commons:APKError { runtimeapi:APIDefinitionValidationResponse|runtimeapi:APIManagementException|error validationResponse; boolean typeAvailable = 'type.length() > 0; - string[] ALLOWED_API_DEFINITION_TYPES = [API_TYPE_REST, API_TYPE_GRAPHQL, "ASYNC"]; + string[] ALLOWED_API_DEFINITION_TYPES = [API_TYPE_REST, API_TYPE_GRAPHQL, API_TYPE_GRPC, API_TYPE_ASYNC]; if !typeAvailable { return e909005("type"); } diff --git a/runtime/config-deployer-service/ballerina/Dependencies.toml b/runtime/config-deployer-service/ballerina/Dependencies.toml index cb855bd71..6992cd148 100644 --- a/runtime/config-deployer-service/ballerina/Dependencies.toml +++ b/runtime/config-deployer-service/ballerina/Dependencies.toml @@ -44,7 +44,7 @@ modules = [ [[package]] org = "ballerina" name = "crypto" -version = "2.6.2" +version = "2.6.3" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "time"} @@ -70,7 +70,7 @@ modules = [ [[package]] org = "ballerina" name = "http" -version = "2.10.12" +version = "2.10.15" dependencies = [ {org = "ballerina", name = "auth"}, {org = "ballerina", name = "cache"}, @@ -102,7 +102,7 @@ modules = [ [[package]] org = "ballerina" name = "io" -version = "1.6.0" +version = "1.6.1" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.value"} @@ -273,7 +273,7 @@ dependencies = [ [[package]] org = "ballerina" name = "observe" -version = "1.2.2" +version = "1.2.3" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -302,7 +302,7 @@ modules = [ [[package]] org = "ballerina" name = "sql" -version = "1.11.1" +version = "1.11.2" dependencies = [ {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, @@ -424,8 +424,7 @@ dependencies = [ modules = [ {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib"}, {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.io"}, - {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.lang"}, - {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.org.wso2.apk.common"} + {org = "wso2", packageName = "apk_common_lib", moduleName = "apk_common_lib.java.lang"} ] [[package]] diff --git a/runtime/config-deployer-service/ballerina/DeployerClient.bal b/runtime/config-deployer-service/ballerina/DeployerClient.bal index e5beb5d2d..943a525b4 100644 --- a/runtime/config-deployer-service/ballerina/DeployerClient.bal +++ b/runtime/config-deployer-service/ballerina/DeployerClient.bal @@ -1,9 +1,11 @@ -import ballerina/mime; import config_deployer_service.model; + import ballerina/http; -import wso2/apk_common_lib as commons; -import ballerina/log; import ballerina/lang.value; +import ballerina/log; +import ballerina/mime; + +import wso2/apk_common_lib as commons; public class DeployerClient { public isolated function handleAPIDeployment(http:Request request, commons:Organization organization) returns commons:APKError|http:Response { @@ -82,6 +84,7 @@ public class DeployerClient { private isolated function deployAPIToK8s(model:APIArtifact apiArtifact) returns commons:APKError|model:API { do { + log:printInfo("DEPLOYING API TO K8s"); model:Partition apiPartition; model:API? existingAPI; model:Partition|() availablePartitionForAPI = check partitionResolver.getAvailablePartitionForAPI(apiArtifact.uniqueId, apiArtifact.organization); @@ -95,6 +98,7 @@ public class DeployerClient { apiArtifact.namespace = apiPartition.namespace; if existingAPI is model:API { check self.deleteHttpRoutes(existingAPI, apiArtifact?.organization); + check self.deleteGrpcRoutes(existingAPI, apiArtifact?.organization); check self.deleteAuthenticationCRs(existingAPI, apiArtifact?.organization); _ = check self.deleteScopeCrsForAPI(existingAPI, apiArtifact?.organization); check self.deleteBackends(existingAPI, apiArtifact?.organization); @@ -121,9 +125,9 @@ public class DeployerClient { check self.deployInterceptorServiceCRs(apiArtifact, ownerReference); check self.deployBackendJWTConfigs(apiArtifact, ownerReference); check self.deployAPIPolicyCRs(apiArtifact, ownerReference); - - check self.deployRoutes(apiArtifact.productionHttpRoutes, apiArtifact.productionGqlRoutes, apiArtifact?.namespace, ownerReference); - check self.deployRoutes(apiArtifact.sandboxHttpRoutes, apiArtifact.sandboxGqlRoutes, apiArtifact?.namespace, ownerReference); + log:printInfo("REACHED THE POINT OF DEPLOYING ROUTES"); + check self.deployRoutes(apiArtifact.productionHttpRoutes, apiArtifact.productionGqlRoutes, apiArtifact.productionGrpcRoutes, apiArtifact?.namespace, ownerReference); + check self.deployRoutes(apiArtifact.sandboxHttpRoutes, apiArtifact.sandboxGqlRoutes, apiArtifact.sandboxGrpcRoutes, apiArtifact?.namespace, ownerReference); return deployK8sAPICrResult; } on fail var e { @@ -138,12 +142,15 @@ public class DeployerClient { return e909028(); } } else { + log:printInfo("NOT AN API??"); return e909028(); } } on fail var e { if e is commons:APKError { return e; } + log:printInfo("DEPLOYMENT FAAAAILED"); + log:printError("Internal Error occured while deploying API", e); return e909028(); } @@ -197,6 +204,30 @@ public class DeployerClient { } } + private isolated function deleteGrpcRoutes(model:API api, string organization) returns commons:APKError? { + do { + model:GRPCRouteList|http:ClientError grpcRouteListResponse = check getGrpcRoutesForAPIs(api.spec.apiName, api.spec.apiVersion, api.metadata?.namespace, organization); + if grpcRouteListResponse is model:GRPCRouteList { + foreach model:GRPCRoute item in grpcRouteListResponse.items { + http:Response|http:ClientError grpcRouteDeletionResponse = deleteGrpcRoute(item.metadata.name, api.metadata?.namespace); + if grpcRouteDeletionResponse is http:Response { + if grpcRouteDeletionResponse.statusCode != http:STATUS_OK { + json responsePayLoad = check grpcRouteDeletionResponse.getJsonPayload(); + model:Status statusResponse = check responsePayLoad.cloneWithType(model:Status); + check self.handleK8sTimeout(statusResponse); + } + } else { + log:printError("Error occured while deleting GrpcRoute", grpcRouteDeletionResponse); + } + } + return; + } + } on fail var e { + log:printError("Error occured deleting grpcRoutes", e); + return e909022("Error occured deleting grpcRoutes", e); + } + } + private isolated function deleteBackends(model:API api, string organization) returns commons:APKError? { do { model:BackendList|http:ClientError backendPolicyListResponse = check getBackendPolicyCRsForAPI(api.spec.apiName, api.spec.apiVersion, api.metadata?.namespace, organization); @@ -300,6 +331,7 @@ public class DeployerClient { if k8sAPIByNameAndNamespace is model:API { k8sAPI.metadata.resourceVersion = k8sAPIByNameAndNamespace.metadata.resourceVersion; http:Response deployAPICRResult = check updateAPICR(k8sAPI, apiArtifact?.namespace); + log:printInfo(deployAPICRResult.statusCode.toString()); if deployAPICRResult.statusCode == http:STATUS_OK { json responsePayLoad = check deployAPICRResult.getJsonPayload(); log:printDebug("Updated K8sAPI Successfully" + responsePayLoad.toJsonString()); @@ -312,8 +344,10 @@ public class DeployerClient { model:StatusCause[] 'causes = details.'causes; foreach model:StatusCause 'cause in 'causes { if 'cause.'field == "spec.basePath" { + log:printError("Error occured while updating K8sAPI due to base path ", e909015(k8sAPI.spec.basePath)); return e909015(k8sAPI.spec.basePath); } else if 'cause.'field == "spec.apiName" { + log:printError("Error occured while updating K8sAPI due to base path ", e909015(k8sAPI.spec.basePath)); return e909016(k8sAPI.spec.apiName); } } @@ -349,7 +383,8 @@ public class DeployerClient { return e909022("Internal error occured", e = error("Internal error occured")); } } - private isolated function deployRoutes(model:HTTPRoute[]? httproutes, model:GQLRoute[]? gqlroutes, string namespace, model:OwnerReference ownerReference) returns error? { + private isolated function deployRoutes(model:HTTPRoute[]? httproutes, model:GQLRoute[]? gqlroutes, model:GRPCRoute[]? grpcroutes, + string namespace, model:OwnerReference ownerReference) returns error? { if httproutes is model:HTTPRoute[] && httproutes.length() > 0 { model:HTTPRoute[] deployReadyHttproutes = httproutes; model:HTTPRoute[]|commons:APKError orderedHttproutes = self.createHttpRoutesOrder(httproutes); @@ -408,6 +443,51 @@ public class DeployerClient { } } } + } else if grpcroutes is model:GRPCRoute[] && grpcroutes.length() > 0 { + model:GRPCRoute[] deployReadyGrpcRoutes = grpcroutes; + model:GRPCRoute[]|commons:APKError orderedGrpcRoutes = self.createGrpcRoutesOrder(grpcroutes); + if orderedGrpcRoutes is model:GRPCRoute[] { + deployReadyGrpcRoutes = orderedGrpcRoutes; + } + foreach model:GRPCRoute grpcRoute in deployReadyGrpcRoutes { + grpcRoute.metadata.ownerReferences = [ownerReference]; + if grpcRoute.spec.rules.length() > 0 { + http:Response deployGrpcRouteResult = check deployGrpcRoute(grpcRoute, namespace); + if deployGrpcRouteResult.statusCode == http:STATUS_CREATED { + log:printDebug("Deployed GrpcRoute Successfully" + grpcRoute.toString()); + } else if deployGrpcRouteResult.statusCode == http:STATUS_CONFLICT { + log:printDebug("GrpcRoute already exists" + grpcRoute.toString()); + model:GRPCRoute grpcRouteFromK8s = check getGrpcRoute(grpcRoute.metadata.name, namespace); + grpcRoute.metadata.resourceVersion = grpcRouteFromK8s.metadata.resourceVersion; + http:Response grpcRouteCR = check updateGrpcRoute(grpcRoute, namespace); + if grpcRouteCR.statusCode != http:STATUS_OK { + json responsePayLoad = check grpcRouteCR.getJsonPayload(); + model:Status statusResponse = check responsePayLoad.cloneWithType(model:Status); + check self.handleK8sTimeout(statusResponse); + } + } else { + json responsePayLoad = check deployGrpcRouteResult.getJsonPayload(); + model:Status statusResponse = check responsePayLoad.cloneWithType(model:Status); + check self.handleK8sTimeout(statusResponse); + } + } + } + } + } + + public isolated function createGrpcRoutesOrder(model:GRPCRoute[] grpcRoutes) returns model:GRPCRoute[]|commons:APKError { + do { + foreach model:GRPCRoute route in grpcRoutes { + model:GRPCRouteRule[] routeRules = route.spec.rules; + model:GRPCRouteRule[] sortedRouteRules = from var routeRule in routeRules + order by (routeRule.matches[0].method.'service) descending + select routeRule; + route.spec.rules = sortedRouteRules; + } + return grpcRoutes; + } on fail var e { + log:printError("Error occured while sorting grpcRoutes", e); + return e909022("Error occured while sorting grpcRoutes", e); } } diff --git a/runtime/config-deployer-service/ballerina/K8sClient.bal b/runtime/config-deployer-service/ballerina/K8sClient.bal index 5e7757206..a68a13846 100644 --- a/runtime/config-deployer-service/ballerina/K8sClient.bal +++ b/runtime/config-deployer-service/ballerina/K8sClient.bal @@ -1,3 +1,7 @@ +import config_deployer_service.model as model; + +import ballerina/crypto; +import ballerina/http; // // Copyright (c) 2022, WSO2 LLC. (http://www.wso2.com). // @@ -15,13 +19,11 @@ // specific language governing permissions and limitations // under the License. // - import ballerina/io; +import ballerina/log; import ballerina/url; -import ballerina/http; + import wso2/apk_common_lib as commons; -import ballerina/crypto; -import config_deployer_service.model as model; const string K8S_API_ENDPOINT = "/api/v1"; final string token = check io:fileReadString(k8sConfiguration.serviceAccountPath + "/token"); @@ -56,7 +58,7 @@ isolated function getConfigMapValueFromNameAndNamespace(string name, string name } isolated function deleteAPICR(string name, string namespace) returns http:Response|http:ClientError { - string endpoint = "/apis/dp.wso2.com/v1alpha2/namespaces/" + namespace + "/apis/" + name; + string endpoint = "/apis/dp.wso2.com/v1beta1/namespaces/" + namespace + "/apis/" + name; return k8sApiServerEp->delete(endpoint, targetType = http:Response); } @@ -111,12 +113,13 @@ isolated function deleteConfigMap(string name, string namespace) returns http:Re } isolated function deployAPICR(model:API api, string namespace) returns http:Response|http:ClientError { - string endpoint = "/apis/dp.wso2.com/v1alpha2/namespaces/" + namespace + "/apis"; + string endpoint = "/apis/dp.wso2.com/v1beta1/namespaces/" + namespace + "/apis"; return k8sApiServerEp->post(endpoint, api, targetType = http:Response); } isolated function updateAPICR(model:API api, string namespace) returns http:Response|http:ClientError { - string endpoint = "/apis/dp.wso2.com/v1alpha2/namespaces/" + namespace + "/apis/" + api.metadata.name; + string endpoint = "/apis/dp.wso2.com/v1beta1/namespaces/" + namespace + "/apis/" + api.metadata.name; + log:printInfo("UPDATING API CR"); return k8sApiServerEp->put(endpoint, api, targetType = http:Response); } @@ -151,7 +154,7 @@ isolated function updateGqlRoute(model:GQLRoute gqlroute, string namespace) retu } public isolated function getK8sAPIByNameAndNamespace(string name, string namespace) returns model:API?|commons:APKError { - string endpoint = "/apis/dp.wso2.com/v1alpha2/namespaces/" + namespace + "/apis/" + name; + string endpoint = "/apis/dp.wso2.com/v1beta1/namespaces/" + namespace + "/apis/" + name; do { http:Response response = check k8sApiServerEp->get(endpoint); if response.statusCode == 200 { @@ -344,3 +347,28 @@ isolated function getBackendJWTCrsForAPI(string apiName, string apiVersion, stri string endpoint = "/apis/dp.wso2.com/v1alpha1/namespaces/" + namespace + "/backendjwts?labelSelector=" + check generateUrlEncodedLabelSelector(apiName, apiVersion, organization); return k8sApiServerEp->get(endpoint, targetType = model:BackendJWTList); } + +isolated function getGrpcRoute(string name, string namespace) returns model:GRPCRoute|http:ClientError { + string endpoint = "/apis/gateway.networking.k8s.io/v1alpha2/namespaces/" + namespace + "/grpcroutes/" + name; + return k8sApiServerEp->get(endpoint, targetType = model:GRPCRoute); +} + +isolated function deleteGrpcRoute(string name, string namespace) returns http:Response|http:ClientError { + string endpoint = "/apis/gateway.networking.k8s.io/v1alpha2/namespaces/" + namespace + "/grpcroutes/" + name; + return k8sApiServerEp->delete(endpoint, targetType = http:Response); +} + +isolated function deployGrpcRoute(model:GRPCRoute grpcRoute, string namespace) returns http:Response|http:ClientError { + string endpoint = "/apis/gateway.networking.k8s.io/v1alpha2/namespaces/" + namespace + "/grpcroutes"; + return k8sApiServerEp->post(endpoint, grpcRoute, targetType = http:Response); +} + +isolated function updateGrpcRoute(model:GRPCRoute grpcRoute, string namespace) returns http:Response|http:ClientError { + string endpoint = "/apis/gateway.networking.k8s.io/v1alpha2/namespaces/" + namespace + "/grpcroutes/" + grpcRoute.metadata.name; + return k8sApiServerEp->put(endpoint, grpcRoute, targetType = http:Response); +} + +public isolated function getGrpcRoutesForAPIs(string apiName, string apiVersion, string namespace, string organization) returns model:GRPCRouteList|http:ClientError|error { + string endpoint = "/apis/gateway.networking.k8s.io/v1alpha2/namespaces/" + namespace + "/grpcroutes/?labelSelector=" + check generateUrlEncodedLabelSelector(apiName, apiVersion, organization); + return k8sApiServerEp->get(endpoint, targetType = model:GRPCRouteList); +} diff --git a/runtime/config-deployer-service/ballerina/constants.bal b/runtime/config-deployer-service/ballerina/constants.bal index 66f523456..85246b3a1 100644 --- a/runtime/config-deployer-service/ballerina/constants.bal +++ b/runtime/config-deployer-service/ballerina/constants.bal @@ -11,6 +11,8 @@ public final string[] WS_SUPPORTED_METHODS = ["subscribe", "publish"]; const string API_TYPE_REST = "REST"; const string API_TYPE_GRAPHQL = "GRAPHQL"; +const string API_TYPE_GRPC = "GRPC"; +const string API_TYPE_ASYNC = "ASYNC"; const string API_TYPE_SOAP = "SOAP"; const string API_TYPE_SSE = "SSE"; const string API_TYPE_WS = "WS"; @@ -52,7 +54,7 @@ const string ENDPOINT_SECURITY_PASSWORD = "password"; const string ZIP_FILE_EXTENSTION = ".zip"; const string PROTOCOL_HTTP = "http"; const string PROTOCOL_HTTPS = "https"; -final string[] & readonly ALLOWED_API_TYPES = [API_TYPE_REST, API_TYPE_GRAPHQL]; +final string[] & readonly ALLOWED_API_TYPES = [API_TYPE_REST, API_TYPE_GRAPHQL, API_TYPE_GRPC]; const string MEDIATION_POLICY_TYPE_REQUEST_HEADER_MODIFIER = "RequestHeaderModifier"; const string MEDIATION_POLICY_TYPE_RESPONSE_HEADER_MODIFIER = "ResponseHeaderModifier"; diff --git a/runtime/config-deployer-service/ballerina/modules/model/API.bal b/runtime/config-deployer-service/ballerina/modules/model/API.bal index 25d7bd40c..d7f6008b8 100644 --- a/runtime/config-deployer-service/ballerina/modules/model/API.bal +++ b/runtime/config-deployer-service/ballerina/modules/model/API.bal @@ -18,7 +18,7 @@ public type API record { string kind = "API"; - string apiVersion = "dp.wso2.com/v1alpha2"; + string apiVersion = "dp.wso2.com/v1beta1"; Metadata metadata; APISpec spec; APIStatus? status = (); @@ -62,7 +62,7 @@ public type EnvConfig record { }; public type APIList record { - string apiVersion = "dp.wso2.com/v1alpha2"; + string apiVersion = "dp.wso2.com/v1beta1"; string kind = "APIList"; API[] items; ListMeta metadata; diff --git a/runtime/config-deployer-service/ballerina/modules/model/APIArtifact.bal b/runtime/config-deployer-service/ballerina/modules/model/APIArtifact.bal index 7f272176a..b40f95448 100644 --- a/runtime/config-deployer-service/ballerina/modules/model/APIArtifact.bal +++ b/runtime/config-deployer-service/ballerina/modules/model/APIArtifact.bal @@ -6,6 +6,8 @@ public type APIArtifact record {| HTTPRoute[] sandboxHttpRoutes = []; GQLRoute[] productionGqlRoutes = []; GQLRoute[] sandboxGqlRoutes = []; + GRPCRoute[] productionGrpcRoutes = []; + GRPCRoute[] sandboxGrpcRoutes = []; ConfigMap definition?; map endpointCertificates = {}; map certificateMap = {}; diff --git a/runtime/config-deployer-service/ballerina/modules/model/GRPCRoute.bal b/runtime/config-deployer-service/ballerina/modules/model/GRPCRoute.bal new file mode 100644 index 000000000..3c28ef72b --- /dev/null +++ b/runtime/config-deployer-service/ballerina/modules/model/GRPCRoute.bal @@ -0,0 +1,70 @@ +// +// 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. +// + +public type GRPCRouteSpec record { + *CommonRouteSpec; + string[] hostnames?; + GRPCRouteRule[] rules = []; +}; + +public type GRPCRouteRule record { + GRPCRouteMatch[] matches; + GRPCRouteFilter[] filters?; + GRPCBackendRef[] backendRefs?; +}; + +public type GRPCRouteMatch record { + GRPCMethodMatch method; + GRPCHeaderMatch[] headers?; +}; + +public type GRPCHeaderMatch record { + string 'type; + string name; + string value; +}; + +public type GRPCMethodMatch record { + string 'type; + string 'service; + string method; +}; + +public type GRPCRouteFilter record { + string 'type; + LocalObjectReference extensionRef?; +}; + +public type GRPCBackendRef record { + *BackendRef; + GRPCRouteFilter[] filters?; +}; + +public type GRPCRoute record {| + string apiVersion = "gateway.networking.k8s.io/v1alpha2"; + string kind = "GRPCRoute"; + Metadata metadata; + GRPCRouteSpec spec; +|}; + +public type GRPCRouteList record {| + string apiVersion = "gateway.networking.k8s.io/v1alpha2"; + string kind = "GRPCRouteList"; + ListMeta metadata; + GRPCRoute[] items; +|}; diff --git a/runtime/config-deployer-service/ballerina/modules/org.wso2.apk.config/RuntimeAPICommonUtil.bal b/runtime/config-deployer-service/ballerina/modules/org.wso2.apk.config/RuntimeAPICommonUtil.bal index 6bf917f90..1e5011dc5 100644 --- a/runtime/config-deployer-service/ballerina/modules/org.wso2.apk.config/RuntimeAPICommonUtil.bal +++ b/runtime/config-deployer-service/ballerina/modules/org.wso2.apk.config/RuntimeAPICommonUtil.bal @@ -1,9 +1,10 @@ -import ballerina/jballerina.java; -import ballerina/jballerina.java.arrays as jarrays; import config_deployer_service.java.lang as javalang; import config_deployer_service.java.util as javautil; -import config_deployer_service.org.wso2.apk.config.model as orgwso2apkconfigmodel; import config_deployer_service.org.wso2.apk.config.api as orgwso2apkconfigapi; +import config_deployer_service.org.wso2.apk.config.model as orgwso2apkconfigmodel; + +import ballerina/jballerina.java; +import ballerina/jballerina.java.arrays as jarrays; # Ballerina class mapping for the Java `org.wso2.apk.config.RuntimeAPICommonUtil` class. @java:Binding {'class: "org.wso2.apk.config.RuntimeAPICommonUtil"} diff --git a/runtime/config-deployer-service/java/build.gradle b/runtime/config-deployer-service/java/build.gradle index a7f868785..c5d212cd9 100644 --- a/runtime/config-deployer-service/java/build.gradle +++ b/runtime/config-deployer-service/java/build.gradle @@ -33,6 +33,7 @@ dependencies { implementation libs.json implementation libs.commons.lang implementation libs.prometheus + implementation libs.protobuf.java } tasks.register('copy_dependencies', Copy) { diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/APIConstants.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/APIConstants.java index ed4a91e2a..dac89a008 100644 --- a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/APIConstants.java +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/APIConstants.java @@ -81,16 +81,17 @@ public final class APIConstants { public static final String SQS_TRANSPORT_PROTOCOL_NAME = "sqs"; public static final String STOMP_TRANSPORT_PROTOCOL_NAME = "stomp"; public static final String REDIS_TRANSPORT_PROTOCOL_NAME = "redis"; - + // GraphQL related constants public static final Set GRAPHQL_SUPPORTED_METHOD_LIST = Collections.unmodifiableSet(new HashSet( Arrays.asList(new String[] { "QUERY", "MUTATION", "SUBSCRIPTION", "head", "options" }))); public static final String GRAPHQL_MUTATION = "MUTATION"; public static final String GRAPHQL_SUBSCRIPTION = "SUBSCRIPTION"; public static final String GRAPHQL_QUERY = "QUERY"; + public static final String GRPC_API = "GRPC"; public enum ParserType { - REST, ASYNC, GRAPHQL + REST, ASYNC, GRAPHQL, GRPC } public static class OperationParameter { diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/DefinitionParserFactory.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/DefinitionParserFactory.java index 8cfb71084..3041eaa22 100644 --- a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/DefinitionParserFactory.java +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/DefinitionParserFactory.java @@ -3,6 +3,7 @@ import org.wso2.apk.config.api.APIDefinition; import org.wso2.apk.config.definitions.AsyncApiParser; import org.wso2.apk.config.definitions.OAS3Parser; +import org.wso2.apk.config.definitions.ProtoParser; import org.wso2.apk.config.model.API; import java.util.ArrayList; @@ -17,12 +18,15 @@ private DefinitionParserFactory() { static { parsers.add(new AsyncApiParser()); parsers.add(new OAS3Parser()); + parsers.add(new ProtoParser()); } public static APIDefinition getParser(API api) { if (APIConstants.ParserType.REST.name().equals(api.getType()) || APIConstants.ParserType.GRAPHQL.name().equals(api.getType())) { return new OAS3Parser(); + } else if (APIConstants.ParserType.GRPC.name().equals(api.getType())) { + return new ProtoParser(); } else if (APIConstants.ParserType.ASYNC.name().equals(api.getType())) { return new AsyncApiParser(); } @@ -33,6 +37,8 @@ public static APIDefinition getParser(String apiType) { if (APIConstants.ParserType.REST.name().equals(apiType) || APIConstants.ParserType.GRAPHQL.name().equals(apiType)) { return new OAS3Parser(); + } else if (APIConstants.ParserType.GRPC.name().equals(apiType)) { + return new ProtoParser(); } else if ("ASYNC".equals(apiType)) { return new AsyncApiParser(); } diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/RuntimeAPICommonUtil.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/RuntimeAPICommonUtil.java index 03f043359..68c8b2014 100644 --- a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/RuntimeAPICommonUtil.java +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/RuntimeAPICommonUtil.java @@ -6,6 +6,8 @@ import org.wso2.apk.config.api.ExceptionCodes; import org.wso2.apk.config.definitions.GraphQLSchemaDefinition; import org.wso2.apk.config.definitions.OASParserUtil; +import org.wso2.apk.config.definitions.ProtoParser; +import org.wso2.apk.config.definitions.ProtoParserUtil; import org.wso2.apk.config.model.API; import org.wso2.apk.config.model.URITemplate; @@ -20,31 +22,28 @@ public class RuntimeAPICommonUtil { public static String generateDefinition(API api) throws APIManagementException { - APIDefinition parser = DefinitionParserFactory.getParser(api); return parser.generateAPIDefinition(api); } /** - * @param inputByteArray OpenAPI definition file - * @param apiDefinition OpenAPI definition + * @param inputByteArray API definition file + * @param apiDefinition API definition * @param fileName Filename of the definition file * @param returnContent Whether to return json or not * @return APIDefinitionValidationResponse * @throws APIManagementException when file parsing fails */ public static APIDefinitionValidationResponse validateOpenAPIDefinition(String type, byte[] inputByteArray, - String apiDefinition, String fileName, - boolean returnContent) - throws APIManagementException { + String apiDefinition, String fileName, boolean returnContent) throws APIManagementException { APIDefinitionValidationResponse validationResponse = new APIDefinitionValidationResponse(); if (APIConstants.ParserType.REST.name().equals(type)) { if (inputByteArray != null && inputByteArray.length > 0) { if (fileName != null) { if (fileName.endsWith(".zip")) { - validationResponse = - OASParserUtil.extractAndValidateOpenAPIArchive(inputByteArray, returnContent); + validationResponse = OASParserUtil.extractAndValidateOpenAPIArchive(inputByteArray, + returnContent); } else { String openAPIContent = new String(inputByteArray, StandardCharsets.UTF_8); validationResponse = OASParserUtil.validateAPIDefinition(openAPIContent, returnContent); @@ -66,10 +65,50 @@ public static APIDefinitionValidationResponse validateOpenAPIDefinition(String t OASParserUtil.addErrorToValidationResponse(validationResponse, "Invalid definition file type provided."); } + } else if (APIConstants.ParserType.GRPC.name().equals(type.toUpperCase())) { + if (fileName.endsWith(".proto")) { + validationResponse = ProtoParserUtil.validateGRPCAPIDefinition( + new String(inputByteArray, StandardCharsets.UTF_8), + returnContent); + } else { + ProtoParserUtil.addErrorToValidationResponse(validationResponse, + "Invalid definition file type provided."); + } } return validationResponse; } + public static API getGRPCAPIFromProtoDefinition(String definition) { + System.out.println("GETTING API FROM PROTO"); + ProtoParser protoParser = new ProtoParser(); + protoParser.setContent(definition); + List uriTemplates = new ArrayList<>(); + API api = new API(); + api.setBasePath("/" + protoParser.protoFile.basePath); + api.setVersion(protoParser.protoFile.version); + StringBuilder apiName = new StringBuilder(); + List sortedServices = new ArrayList<>(); + + for (ProtoParser.Service service : protoParser.getServices()) { + sortedServices.add(service.name); + for (String method : service.methods) { + URITemplate uriTemplate = new URITemplate(); + uriTemplate.setUriTemplate(protoParser.protoFile.packageName + "." + service.name); + uriTemplate.setVerb(method); + uriTemplates.add(uriTemplate); + } + } + sortedServices.sort(String::compareTo); + for (String service : sortedServices) { + apiName.append(service).append("-"); + } + apiName.deleteCharAt(apiName.length() - 1); + api.setName(apiName.toString()); + api.setUriTemplates(uriTemplates.toArray(new URITemplate[uriTemplates.size()])); + + return api; + } + public static Set generateUriTemplatesFromAPIDefinition(String apiType, String content) throws APIManagementException { @@ -99,6 +138,8 @@ public static API getAPIFromDefinition(String definition, String apiType) throws if (apiType.toUpperCase().equals(APIConstants.GRAPHQL_API)) { return getGQLAPIFromDefinition(definition); + } else if (apiType.toUpperCase().equals(APIConstants.GRPC_API)) { + return getGRPCAPIFromProtoDefinition(definition); } else { APIDefinition parser = DefinitionParserFactory.getParser(apiType); if (parser != null) { diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/api/ExceptionCodes.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/api/ExceptionCodes.java index f24a3a2fe..f097316cd 100644 --- a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/api/ExceptionCodes.java +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/api/ExceptionCodes.java @@ -21,820 +21,967 @@ import java.util.Arrays; /** - * This enum class holds error codes that we need to pass to upper level. For example, to the UI. + * This enum class holds error codes that we need to pass to upper level. For + * example, to the UI. * You have to define your custom error codes here. */ public enum ExceptionCodes implements ErrorHandler { - // API, Application related codes - API_NAME_ALREADY_EXISTS(900250, "The API name already exists.", 409, "An API with name '%s' already exists"), - API_CONTEXT_ALREADY_EXISTS(900251, "The API context already exists.", 409, "An API with context '%s' already exists"), - API_VERSION_ALREADY_EXISTS(900252, "The API version already exists.", 409, "An API with version '%s' already exists for API '%s'"), - API_EMPTY_PASSWORD_FOR_SECURED_ENDPOINT(900253, "Empty password is given for endpointSecurity when creating API: %s", - 400, "An empty password is given for endpointSecurity when creating API: %s"), - - API_PRODUCT_CONTEXT_ALREADY_EXISTS(900275, "The API Product context already exists.", 409, "An API Product with context '%s' already exists"), - - API_ALREADY_EXISTS(900300, "The API already exists.", 409, "The API already exists"), - APPLICATION_ALREADY_EXISTS(900301, "The application already exists.", 409, "The application already exists"), - APIMGT_DAO_EXCEPTION(900302, "Internal server error.", 500, "Error occurred while persisting/retrieving data"), - APIMGT_LIFECYCLE_EXCEPTION(900303, "Lifecycle exception occurred", 500, "Error occurred while changing " + - "lifecycle state"), - TIER_CANNOT_BE_NULL(900304, "The tier cannot be null.", 400, "The tier cannot be null"), - TIER_NAME_INVALID(900305, "The tier name is invalid.", 400, "The tier name is invalid"), - SEARCH_API_EXCEPTION(900306, "Internal server error.", 500, "Error occurred while searching APIs"), - APPLICATION_NOT_FOUND(900307, "Application not found", 404, "Application not found"), - API_NOT_FOUND(900308, "API Not Found", 404, "Requested API with id '%s' not found"), - APPLICATION_DELETE_FAILED(900309, "Error has occurred. Could not delete the application", 500, "Error has occurred. Could not delete the application '%s'"), - SUBSCRIPTION_NOT_FOUND(900310, "Subscription not found", 404, "Couldn't retrieve Subscriptions for API"), - UPDATE_STATE_CHANGE(900311, "API fields have state changes", 400, "Couldn't Update as API have changes can't be done"), - DOCUMENT_ALREADY_EXISTS(900312, "Document already exists", 409, "Document already exists"), - COULD_NOT_UPDATE_API(900313, "Error has occurred. Could not update the API", 500, "Error has occurred. Could not " - + "update the API"), - DOCUMENT_CONTENT_NOT_FOUND(900314, "Document content not found", 404, "Document content not found"), - DOCUMENT_NOT_FOUND(900315, "Document not found", 404, "Document not found"), - DOCUMENT_INVALID_SOURCE_TYPE(900319, "Invalid document source type", 500, "Source type of the document '%s' is invalid"), - UNSUPPORTED_DOC_EXTENSION(900367, "Document file type not supported", 400, "Unsupported extension type of document file"), - - API_EXPORT_ERROR(900316, "API export Error", 500, "Error while exporting the given APIs"), - API_IMPORT_ERROR(900317, "API import Error", 500, "Error while importing the given APIs"), - API_PRODUCT_IMPORT_ERROR(900318, "API product import Error", 500, - "Error while importing the given API Products"), - SUBSCRIPTION_STATE_INVALID(900320, "Invalid state change for subscription", 400, "Invalid state change for " + - "subscription"), - API_RETRIEVE_EXCEPTION(900319, "Internal server error.", 500, "Error occurred while retrieving %s"), - APPLICATION_RETRIEVE_EXCEPTION(900320, "Internal server error.", 500, "Error occurred while retrieving %s"), - SUBSCRIPTION_RETRIEVE_EXCEPTION(900321, "Internal server error.", 500, "Error occurred while retrieving %s"), - - GATEWAY_LABELS_CANNOT_BE_NULL(900322, "Gateway labels cannot be null.", 400, "Gateway labels cannot be null"), - ERROR_RETRIEVING_RATING(900323, "Cannot retrieve rating", 500, "Error while retrieving ratings for API '%s'"), - RATING_NOT_FOUND(900324, "Rating not found", 404, "Couldn't retrieve rating for API '%s'"), - RATING_VALUE_INVALID(900325, "Rating value invalid", 400, "Provided rating value does not fall in between min max " - + "values"), - DOCUMENT_INVALID_VISIBILITY(900326, "Invalid document visibility type", 500, "Visibility type of the document '%s' is invalid"), - API_TYPE_INVALID(900327, "API Type specified is invalid.", 400, "API Type specified is invalid"), - COMPOSITE_API_ALREADY_EXISTS(900328, "A Composite API already exists.", 409, - "A Composite API already exists for this application"), - API_DEFINITION_NOT_FOUND(900330, "API definition not found", 404, "API definition not found"), - APPLICATION_KEY_MAPPING_NOT_FOUND(900331, "Application Key mapping not found", 404, "Application Key mapping not " + - "found"), - NO_UPDATE_PERMISSIONS(900332, "No permissions to update API.", 403, "No permissions to update API."), - NO_DELETE_PERMISSIONS(900333, "No permissions to delete API.", 403, "No permissions to delete API."), - API_ATTRIBUTE_NOT_FOUND(900335, "API attribute not found", 404, "API attribute not found"), - SUBSCRIPTION_ALREADY_EXISTS(900336, "Subscription already exists", 409, "Subscription already exists"), - SDK_NOT_GENERATED(900337, "Error while generating SDK", 500, "Error while generating SDK"), - APPLICATION_EXPORT_ERROR(900338, "Application Export Error", 500, "Error while exporting the given Application"), - APPLICATION_IMPORT_ERROR(900339, "Application Import Error", 500, "Error while importing the given Application"), - NO_READ_PERMISSIONS(900340, "No permissions to read API.", 403, "No permissions to read API."), - API_PRODUCT_DUPLICATE_RESOURCE(900341, "Cannot create API Product with duplicate resource", - 400, "Cannot create API Product with duplicate resource: %s , verb: %s combination"), - API_PRODUCT_RESOURCE_ENDPOINT_UNDEFINED(900342, - "Cannot create API Product, due to resources with undefined endpoints in their parent APIs", - 409, "Cannot create API Product %s, due to resources with undefined endpoints in their parent APIs %s"), - API_PRODUCT_WITH_UNSUPPORTED_LIFECYCLE_API(900343, - "Cannot create API Product, due to resources parent API being in an unsupported Life Cycle state", - 409, "Cannot create API Product, due to resources parent API being in an unsupported Life Cycle state: %s"), - API_PRODUCT_USED_RESOURCES(900344, - "Cannot remove the resource paths because they are used by one or more API Products", - 409, "Cannot update API: %s:%s, due to the resources to remove are used by one or more API Products"), - API_DELETE_API_PRODUCT_USED_RESOURCES(900344, API_PRODUCT_USED_RESOURCES.getErrorMessage(), 409, - "Cannot delete API since the resources to remove are used by one or more API Products"), - API_CATEGORY_INVALID( - 900345, "The API category is invalid.", 400, " The API category is invalid for API: %s:%s"), - INVALID_ADDITIONAL_PROPERTIES(900346, "Invalid additional properties", 400, - "Invalid additional properties for API: %s:%s"), - INVALID_CONTEXT(900346, "Invalid context provided", 400, "Invalid context provided for API: %s:%s"), - INVALID_ENDPOINT_URL(900346, "Endpoint URL(s) is(are) not valid", 400, "Endpoint URL(s) is(are) not valid"), - USER_ROLES_CANNOT_BE_NULL(900610, "User roles cannot be found", 400, "User roles cannot be found"), - - ERROR_RETRIEVING_REVISION_FOR_UUID(900410, "Failed to get revision details for revision UUID: %s", - 500, "Failed to get revision details"), - - ERROR_RETRIEVING_REVISION_DEPLOYMENT_MAPPING(900411, - "Failed to get API Revision deployment mapping details for %s: %s", 500, - "Failed to get API Revision deployment mapping details"), - - ERROR_UPDATING_REVISION_DEPLOYMENT_MAPPING(900412, - "Failed to update Deployment Mapping entry for API UUID: ", 500, - "Failed to update Deployment Mapping entry"), - - METHOD_NOT_ALLOWED(900420, "Not allowed", 405, "Method not allowed"), - API_REVISION_NOT_FOUND(900347, "API Revision Not Found", 404, "Requested API Revision with id %s not found"), - EXISTING_API_REVISION_DEPLOYMENT_FOUND(900348, "Can not delete API Revision ", 400, "Couldn't delete API revision since API revision is currently deployed to a gateway. " + - "You need to undeploy the API Revision from the gateway before attempting deleting API Revision: %s "), - EXISTING_API_REVISION_FOUND(900349, "Can not create API Revision ", 400, "API revision already exists with id: %s "), - API_REVISION_UUID_NOT_FOUND(900350, "Can not create API Revision ", 400, "Failed to retrieve revision uuid from revision registry artifact"), - MAXIMUM_REVISIONS_REACHED(900351, "Can not create API Revision ", 400, "Maximum number of revisions per API has reached." + - "Need to remove any revision to create a new Revision for API with API UUID: %s"), - ERROR_CREATING_API_REVISION(900352, "Can not create API Revision ", 400, "Failed to create API revision registry artifacts: %s "), - ERROR_DELETING_API_REVISION(900353, "Can not delete API Revision ", 400, "Failed to delete API revision registry artifacts: %s "), - ERROR_RESTORING_API_REVISION(900354, "Can not restore API Revision ", 400, "Failed to restore API revision registry artifacts: %s "), - DEPLOYMENT_ID_NOT_FOUND(900355, "Deployment Id Not Found", 400, "Deployment Id Not Found"), - EXISTING_DEPLOYMENT_NOT_FOUND(900356, "Existing Deployment Not Found", 404, "Deployment with %s not found"), - ORGANIZATION_NOT_FOUND(900357, "Organization Not Found", 400, "Organization is not found in the request"), - INVALID_ENV_API_PROP_CONFIG(900358, "Invalid environment specific api property config", 400, - "Environment specific api property config is not valid. %s", false), - API_OR_API_PRODUCT_NOT_FOUND(900359, "API or API Product Not Found", 404, "Requested API or API Product with id '%s' not found"), - API_PRODUCT_NOT_FOUND(900360, "API Product Not Found", 404, "Requested API Product with id '%s' not found"), - SUB_ORGANIZATION_NOT_IDENTIFIED(900361, "User's Organization Not Identified", 403, "User's Organization is not identified"), - ERROR_RETRIEVING_CATEGORY(900362, "Cannot retrieve categories", 500, "Error while retrieving categories for organization '%s'"), - PERSISTENCE_ERROR(900363, "Error occurred in registry transaction", 500, "'%s'"), - NO_VIEW_UPDATE_PERMISSIONS(900365, "Insufficient permission to view or update the API", 403, "Insufficient permission to view or update the API"), - API_DELETE_FAILED_SUBSCRIPTIONS(900366, "Failed to delete the API", 409, "Cannot remove the API as active subscriptions exist"), - CATEGORY_NAME_CONTAINS_SPECIAL_CHARS(900368, "Name field contains special characters", 400, "API Category name contains special characters"), - CATEGORY_NAME_TOO_LONG(900369, "API Category name is too long", 400, "API Category name exceeds 255 characters"), - CATEGORY_ALREADY_EXISTS(900370, "API Category name already exists", 409, "Category with name '%s' already exists"), - CATEGORY_NOT_FOUND(900371, "Category not found", 404, "No API Category with the given category ID '%s' exists"), - CATEGORY_USED(900372, "Category has usages", 409, "Category is attached to one or more APIs"), - ERROR_CHANGING_APP_OWNER(900373, "Failed to change the application owner", 500, "Error while changing the application owner"), - - USER_SUBSCRIPTION_EXISTS_CHECK_FAILED(900374, "Failed to check if user subscribed to API", 500, "Failed to check if user '%s' with an application '%s' is subscribed to API %s"), - - USER_ACCESSIBLE_APPLICATION_CHECK_FAILED(900375, "Failed to check if user subscribed to API", 500, "Error occurred while checking whether the application '%s' is accessible to user '%s'" ), - API_TAGS_NOT_FOUND(900376, "API Tags Not Found", 404, "API Tags not found for organization '%s'"), - - //Lifecycle related codes - API_UPDATE_FORBIDDEN_PER_LC(900380, "Insufficient permission to update the API", 403, - "Updating the API is restricted as as it is %s."), - UNSUPPORTED_LIFECYCLE_ACTION(900381, "Unsupported state change action", 400, "Lifecycle state change action %s is not allowed"), - LIFECYCLE_STATE_INFORMATION_NOT_FOUND(900382, "Lifecycle state information not found", 500,"Lifecycle state change information for %s with %s cannot be found"), - - // Generic codes - JSON_PARSE_ERROR(900400, "Json parse error", 500, "JSON parse error"), - RESOURCE_NOT_FOUND(900401, "Resource not found", 404, "Requested resource not found"), - RESOURCE_RETRIEVAL_FAILED(900402, "Resource retrieval failed", 400, "Resource retrieval failed"), - USER_MAPPING_RETRIEVAL_FAILED(900404, "User mapping retrieval failed", 404, "User mapping retrieval failed"), - MALFORMED_URL(900403, "Malformed URL", 400, "Invalid or Malformed URL"), - URI_PARSE_ERROR(900405, "Error constructing the URI", 500, "'%s'"), - INVALID_OPERATION_TYPE(900406, "Unsupported '%s' operation", 400, "The '%s' operation type '%s' is invalid"), - VERB_NOT_FOUND(900407, "Missing '%s' type", 400, "Missing '%s type in URI templates"), - YAML_PARSE_ERROR(900408, "Yaml parse error", 500, "Yaml parse error"), - RESOURCE_NOT_FOUND_WITH_TYPE_AND_ID(900409, "Requested %s with Id %s not found", 404, - "Requested %s with Id %s not found"), - AUTHORIZATION_ERROR(900409, "Forbidden", 403, "You don't have permission to access the '%s' with Id '%s'"), - FORBIDDEN_ERROR(900409, "Forbidden", 403, "You don't have permission to access this resource"), - RESOURCE_NOT_FOUND_WITH_DESC(900401, "Resource not found", 404, "Requested '%s' with Id '%s' not found"), - UNAUTHORIZED(900410, "Unauthorized", 401, "User is unauthorized"), - - // Endpoint related codes - ENDPOINT_NOT_FOUND(900450, "Endpoint Not Found", 404, "Endpoint Not Found"), - ENDPOINT_ALREADY_EXISTS(900451, "Endpoint already exists", 409, "Endpoint already exists"), - ENDPOINT_ADD_FAILED(900452, "Endpoint adding failed", 400, "Endpoint adding failed"), - ENDPOINT_DELETE_FAILED(900453, "Endpoint Delete Failed", 400, "Endpoint Delete Failed"), - ENDPOINT_CRYPTO_ERROR(900454, "Error while encrypting/decrypting endpoint secrets", 500, "'%s'"), - ENDPOINT_CONFIG_PARSE_FAILED(900455, "Endpoint config parsing failed", 500, "Error occurred while parsing endpoint config json"), - - - // Service Endpoint Discovery related codes - ERROR_LOADING_SERVICE_DISCOVERY_IMPL_CLASS(900460, "Error loading service discovery impl class", 500, - "Error while trying to load a service discovery impl class"), - ERROR_INITIALIZING_SERVICE_DISCOVERY(900461, "Error initializing service discovery", 500, - "Error while connecting to the system with services"), - ERROR_WHILE_TRYING_TO_DISCOVER_SERVICES(900462, "Error while discovering services", 500, - "Error while trying to discover service endpoints"), - - // Gateway related codes - API_DEFINITION_MALFORMED(900500, "ApiDefinition not found", 400, "Failed to retrieve API Definition"), - TEMPLATE_EXCEPTION(900501, "Service configuration Error", 500, "Error generate service config"), - GATEWAY_EXCEPTION(900502, "Gateway publishing Error", 500, "Error occurred while publishing to Gateway"), - BROKER_EXCEPTION(900503, "Broker Connection Error", 500, "Error occurred while obtaining broker connection"), - INVALID_GATEWAY_ENVIRONMENT(900504, "Invalid Gateway Environment", 400, "Gateway Environment with name '%s' not found"), - NO_GATEWAY_ENVIRONMENTS_ADDED(900505, "No Gateway Environments Available", 400, "No gateway environments " + - "available for the API : %s."), - GATEWAY_ENVIRONMENT_NOT_FOUND(900506, "Gateway Environment not found", 404, - "Gateway Environment with %s not found"), - EXISTING_GATEWAY_ENVIRONMENT_FOUND(900507, "Gateway Environment already exists", 400, - "A Gateway Environment with %s already exists"), - READONLY_GATEWAY_ENVIRONMENT(900508, "Gateway Environment is read only", 400, - "A Gateway Environment with %s is read only"), - GATEWAY_ENVIRONMENT_DUPLICATE_VHOST_FOUND(900509, "Gateway Environment with duplicate virtual hosts", - 400, "A Gateway Environment cannot exists with duplicate virtual hosts"), - READONLY_GATEWAY_ENVIRONMENT_NAME(900510, "Names of Gateway Environment cannot be changed", - 400, "Name of the gateway is read only"), - GATEWAY_ENVIRONMENT_VHOST_NOT_PROVIDED(900511, "Gateway Environment virtual hosts name not provided", - 400, "Gateway Environment VHOST name not provided"), - - FAILED_GET_ENVIRONMENT_LIST_OF_VHOST(900512, "Failed to get gateway environments list of VHost", - 500, "Failed to get gateway environments list of VHost"), - FAILED_GET_ENVIRONMENT_LIST_OF_TENANT_DOMAIN(900513, "Failed to get Environments in tenant domain", - 500, "Failed to get Environments in tenant domain: %s"), - FAILED_GET_ENVIRONMENT_FOR_TENANT_DOMAIN(900514, "Failed to get Environment in tenant domain: %s", - 500, "Failed to get Environment in tenant domain: %s"), - TENANT_NOT_FOUND(900515, "Tenant does not exist", 404, - "Tenant does not exist"), - INVALID_TENANT_STATE(900516, "Invalid tenant state", 400, - "Invalid tenant state provided"), - FAILED_GET_ENVIRONMENT_SPECIFIC_PROPERTIES(900517, - "Error occurred when getting environment specific api properties", 500, - "Error occurred when getting environment specific api properties"), - VHOST_FOR_ENVIRONMENT_NOT_FOUND(900518, "VHosts not found for the environment: %s", 404, - "VHosts not found for the environment: %s"), - - // Workflow related codes - WORKFLOW_EXCEPTION(900550, "Workflow error", 500, - "Error occurred while executing workflow task"), - WORKFLOW_NOT_FOUND(900551, "Workflow error", 404, - "Workflow entry cannot be found for the given reference id"), - WORKFLOW_ALREADY_COMPLETED(900552, "Workflow error", 400, - "Workflow is already completed"), - WORKFLOW_PENDING(900553, "Workflow exception", 409, - "Pending workflow task exists for the seleted API"), - WORKFLOW_INVALID_WFTYPE(900554, "Workflow error", 500, "Invalid workflow type specified"), - WORKFLOW_INV_STORE_WFTYPE(900555, "Workflow error", 500, "Invalid workflow type for store workflows"), - WORKFLOW_STATE_MISSING(900556, "Workflow error", 400, "Workflow status is not defined"), - WORKFLOW_NO_PENDING_TASK(900557, "Workflow error", 412, - "Requested resource does not have a pending workflow task"), - WORKFLOW_REJCECTED(900558, "Workflow error", 403, "Requested action is rejected"), - INCOMPATIBLE_WORKFLOW_REQUEST_FOR_PUBLISHER(900559, "Incompatible workflow request", 400, "Incompatible workflow " + - "request received by publisher"), - INCOMPATIBLE_WORKFLOW_REQUEST_FOR_STORE(900560, "Incompatible workflow request", 400, "Incompatible workflow " + - "request received by store"), - WORKFLOW_RETRIEVE_EXCEPTION(900561, "Workflow retrieval error", 400, "Provided parameter is not valid"), - - // Auth related codes - ROLES_CANNOT_BE_EMPTY(900600, "Role list cannot be empty", 400, "Role list cannot be empty"), - ROLES_CANNOT_BE_NULL(900601, "Role list cannot be null", 400, "Role list cannot be null"), - UNSUPPORTED_ROLE(900602, "Non existing roles cannot be added to an API", 400, - "Non existing roles cannot be added to an API"), - USER_DOES_NOT_EXIST(900603, "User does not exist in the system", 404, "User does not exist in the system"), - USER_CREATION_FAILED(900604, "User creation failed", 500, "User creation failed"), - IDP_INITIALIZATION_FAILED(900605, "Identity Provider initialization failed", 500, - "Identity provider initialization failed"), - KEY_MANAGER_INITIALIZATION_FAILED(900606, "Key Manager initialization failed", 500, - "Key Manager initialization failed",true), - ROLE_DOES_NOT_EXIST(900607, "Role does not exist in the system", 404, "Role does not exist in the system"), - MULTIPLE_ROLES_EXIST(900608, "Multiple roles with the same display name exist in the system", 500, "Multiple " + - "roles with the same display name exist in the system"), - MULTIPLE_USERS_EXIST(900609, "Multiple users with the same username exist in the system", 500, "Multiple " + - "users with the same username exist in the system"), - INVALID_USER_ROLES(900610, "Invalid user roles found", 400, "Invalid user roles found"), - IDP_ADDING_FAILED(900611, "Unable to add the identity provider", 400, "Error while adding the identity provider"), - IDP_RETRIEVAL_FAILED(900612, "Unable to retrieve the identity provider", 400, "Error while retrieving the " - + "identity provider details"), - IDP_DELETION_FAILED(900613, "Unable to delete the identity provider", 400, "Error while deleting the " - + "identity provider"), - INVALID_IDP_TYPE(900614, "Unsupported identity provider type", 400, "Invalid identity provider type. %s"), - USERSTORE_INITIALIZATION_FAILED(900615, "Unable to get the user store manager", 500, - "Error while getting the user store manager from the realm"), - ANON_USER_ACTION(900616, "Operation not permitted", 401, "Attempt to execute privileged operation as the anonymous user"), - ROLE_ID_EMPTY(900617, "Role Id cannot be empty", 400, - "Role Id cannot be empty"), - - // Labels related codes - LABEL_INFORMATION_CANNOT_BE_NULL(900650, "Label information cannot be null", 400, "Label information cannot be " + - "null"), - LABEL_EXCEPTION(900651, "Label Error", 500, "Error occurred while retrieving label information"), - LABEL_NOT_FOUND(900652, "Label Not Found", 404, "Label with specified name cannot be found."), - LABEL_NOT_FOUND_IN_API(900653, "Label Not Found In API", 404, "Label with specified name" - + " cannot be found in the API."), - LABEL_ADDING_FAILED(900654, "Label Error", 500, "Error occurred while trying to add label"), - LABEL_UPDATE_FAILED(900655, "Label Error", 500, "Error occurred while trying to update label"), - LABEL_DELETION_FAILED(900656, "Label Error", 500, "Error occurred while trying to delete label"), - - - //WSDL related codes - INVALID_WSDL_URL_EXCEPTION(900675, "Invalid WSDL", 400, "Invalid WSDL URL"), - CANNOT_PROCESS_WSDL_CONTENT(900676, "Invalid WSDL", 400, "Provided WSDL content cannot be processed"), - INTERNAL_WSDL_EXCEPTION(900677, "Internal WSDL error", 500, "Internal error while processing WSDL"), - UNSUPPORTED_WSDL_EXTENSIBILITY_ELEMENT(900678, "Invalid WSDL", 400, "WSDL extensibility element not supported"), - ERROR_WHILE_INITIALIZING_WSDL_FACTORY(900679, "Internal WSDL error", 500, "Error while initializing WSDL factory"), - ERROR_WHILE_CREATING_WSDL_ARCHIVE(900680, "Internal WSDL error", 500, "Error while creating WSDL archive"), - NO_WSDL_FOUND_IN_WSDL_ARCHIVE(900681, "Invalid WSDL Archive", 400, "No valid WSDLs found in the provided WSDL archive"), - CONTENT_NOT_RECOGNIZED_AS_WSDL(900682, "Invalid WSDL Content", 400, "Provided content is not recognized as a WSDL"), - URL_NOT_RECOGNIZED_AS_WSDL(900683, "Invalid WSDL URL", 400, "Provided URL is not recognized as a WSDL"), - NO_WSDL_AVAILABLE_FOR_API(900684, "WSDL Not Found", 404, "No WSDL Available for the API %s:%s"), - CORRUPTED_STORED_WSDL(900685, "Corrupted Stored WSDL", 500, "The WSDL of the API %s is corrupted."), - UNSUPPORTED_WSDL_FILE_EXTENSION(900686, "Unsupported WSDL File Extension", 400, "Unsupported extension. Only supported extensions are .wsdl and .zip"), - API_NOT_SOAPTOREST(900687, "Provided API is not a SOAP to REST converted API", 400, "Provided API is not a SOAP to REST converted API"), - ERROR_ADDING_WSDL_TO_API(900687, "Error while adding WSDL to API: %s", 500, - "Error while saving WSDL"), - - - //OpenAPI/Swagger related codes [900750 900???) - MALFORMED_OPENAPI_DEFINITON(900758, "Malformed OpenAPI Definition", 400, "The provided OpenAPI definition is not parsable as a valid JSON or YAML."), - UNRECOGNIZED_OPENAPI_DEFINITON(900759, "Unrecognized OpenAPI Definition", 400, "The definition is parsable but cannot be identified as an OpenAPI definition."), - INVALID_SWAGGER_VERSION(900760, "Invalid Swagger Definition", 400, "Unsupported swagger version provided. Please add with swagger version 2.0."), - INVALID_SWAGGER_PARAMS(900751, "Invalid Swagger Definition", 400, "Swagger contains invalid parameters. Please add valid swagger definition."), - INVALID_OPENAPI_VERSION(900752, "Invalid OpenAPI Definition", 400, "Unsupported OpenAPI version provided. Please add with OpenAPI version 3.0.0."), - INVALID_OPENAPI_NO_INFO_PATH(900753, "Invalid OpenAPI Definition", 400, "Required property 'info' or 'paths' are not provided."), - OPENAPI_PARSE_EXCEPTION(900754, "Error while parsing OpenAPI definition", 400, "Error while parsing OpenAPI definition"), - OPENAPI_PARSE_EXCEPTION_WITH_CUSTOM_MESSAGE(OPENAPI_PARSE_EXCEPTION.getErrorCode(), OPENAPI_PARSE_EXCEPTION.getErrorMessage(), OPENAPI_PARSE_EXCEPTION.getHttpStatusCode(), "'%s'"), - OPENAPI_NOT_FOUND(900755, "OpenAPI definition not found", 404, "OpenAPI definition not found"), - OPENAPI_URL_MALFORMED(900756, "OpenAPI definition retrieval from URL failed", 400, "Exception occurred while retrieving the OpenAPI definition from URL"), - OPENAPI_URL_NO_200(900757, "OpenAPI definition retrieval from URL failed", 400, "Response didn't return a 200 OK status"), - INVALID_OAS2_FOUND(900761, "Invalid OpenAPI V2 definition found", 400, "Invalid OpenAPI V2 definition found"), - INVALID_OAS3_FOUND(900762, "Invalid OpenAPI V3 definition found", 400, "Invalid OpenAPI V3 definition found"), - NO_RESOURCES_FOUND(900763, "No resources found", 404, "API must have at least one resource defined"), - ERROR_REMOVING_EXAMPLES(900764, "Internal Error While Processing Swagger Definition", 500, "Couldn't remove one or more examples from the swagger definition"), - MOCK_HTTP_METHOD_MISSING(900765, "Could not find HTTP methods", 400, "Cannot find the HTTP method for the API Resource Mediation Policy"), - SWAGGER_ARCHIVE_MISSING(900766, "Could not find an archive in the given ZIP file", 500, "Could not find an archive in the given ZIP file"), - - //AsyncApi related error codes - ASYNCAPI_URL_MALFORMED(900756, "AsyncAPI specification retrieval from URL failed", 400, "Exception occurred while retrieving the AsyncAPI Specification from URL"), - ASYNCAPI_URL_NO_200(900757, "AsyncAPI specification retrieval from URL failed", 400, "Response didn't return a 200 OK status"), - - ERROR_READING_ASYNCAPI_SPECIFICATION(900765, "AsyncAPI specification read error", 500, "Exception occurred while reading the AsyncAPI Specification file"), - - // REST API related codes - PARAMETER_NOT_PROVIDED(900700, "Parameter value missing", 400, - "Some of the mandatory parameter values were missing"), - LOCATION_HEADER_INCORRECT(900701, "Error while obtaining URI for Location header", 500, - "Error occurred while obtaining URI for Location header"), - LAST_UPDATED_TIME_RETRIEVAL_ERROR(900702, "Error while retrieving last access time for the resource", 500, - "Error while retrieving last access time for the resource"), - INVALID_DATE_TIME_STAMP(900703, "Invalid timestamp value", 400, "Timestamp should be in ISO8601 format"), - LENGTH_EXCEEDS(900704, "Character length exceeds the allowable limit", 400, - "One of the provided input character length exceeds the allowable limit."), - BLANK_PROPERTY_VALUE(900705, "Blank value for required property", 400, - "%s property value of payload cannot be blank"), - CONTAIN_SPECIAL_CHARACTERS(900706, "contain invalid characters", 400, - "%s property value of payload cannot contain invalid characters"), - INVALID_SORT_CRITERIA(900707, "Invalid sort criteria", 400, "Sort criteria contain a non-allowable value"), - INVALID_PARAMETERS_PROVIDED(900708, "Invalid parameter(s) provided", 400, "Bad Request. Mandatory parameters are invalid/missing"), - - INVALID_PARAMETERS_PROVIDED_WITH_MESSAGE(900708, "'%s'", 400, "Bad Request. Parameters are invalid/missing"), - - //GraphQL API related codes - API_NOT_GRAPHQL(900800, "This API is not a GraphQL API", 400, "This API is not a GraphQL API"), - GRAPHQL_SCHEMA_CANNOT_BE_NULL(900801, "GraphQL Schema cannot be empty or nul", 400, - "GraphQL Schema cannot be empty or null"), - UNSUPPORTED_GRAPHQL_FILE_EXTENSION(900802, "Unsupported GraphQL Schema File Extension", 400, - "Unsupported extension. Only supported extensions are .graphql, .txt and .sdl"), - - // Oauth related codes - AUTH_GENERAL_ERROR(900900, "Authorization Error", 403, " Error in authorization"), - INVALID_CREDENTIALS(900901, "Invalid Credentials", 401, " Invalid username or password"), - MISSING_CREDENTIALS(900902, "Missing Credentials", 401, " Please provide an active access token to proceed"), - ACCESS_TOKEN_EXPIRED(900903, "Invalid Credentials", 401, " Access token is expired."), - ACCESS_TOKEN_INACTIVE(900904, "Access Token Error", 401, " Access token is inactive."), - USER_NOT_AUTHENTICATED(900905, "User is not Authenticated", 401, " User is not authenticated."), - ACCESS_TOKEN_INVALID(900906, "Invalid Credentials", 401, " Access token is invalid."), - - INVALID_SCOPE(900910, "Invalid Scope", 403, " You are not authorized to access the resource."), - INVALID_AUTHORIZATION_HEADER(900911, "Invalid Authorization header", 401, - " Please provide the Authorization : Bearer <> token to proceed."), - MALFORMED_AUTHORIZATION_HEADER_OAUTH(900912, "Malformed Authorization Header", 400, - "Please provide the Authorization : Bearer <> token to proceed."), - MALFORMED_AUTHORIZATION_HEADER_BASIC(900913, "Malformed Authorization Header", 400, - "Please provide the Authorization : Basic <> token to proceed."), - INVALID_PERMISSION(900915, "Invalid Permission", 403, " You are not authorized to access the '%s'."), - OPENID_CONFIG(900916, "Missing OpenID configurations", 500, "Error in fetching Open ID configuration"), - OAUTH2_APP_CREATION_FAILED(900950, "Key Management Error", 500, "Error while creating the consumer application."), - OAUTH2_APP_ALREADY_EXISTS(900951, "Key Management Error", 409, "OAuth2 application already created."), - OAUTH2_APP_DELETION_FAILED(900952, "Key Management Error", 500, "Error while deleting the consumer application."), - OAUTH2_APP_UPDATE_FAILED(900953, "Key Management Error", 500, "Error while updating the consumer application."), - OAUTH2_APP_RETRIEVAL_FAILED(900954, "Key Management Error", 500, "Error while retrieving the consumer application." - ), - APPLICATION_TOKEN_GENERATION_FAILED(900957, "Keymanagement Error", 500, " Error while generating the application" + - "access token."), - APPLICATION_CONSUMER_KEY_NOT_FOUND(900958, "Keymanagement Error", 403, "Requested consumer key with application '%s' not found"), - UNSUPPORTED_THROTTLE_LIMIT_TYPE(900960, "Throttle Policy Error", 400, "Throttle Limit type is not supported"), - POLICY_NOT_FOUND(900961, "Policy Not found", 404, "Failed to retrieve Policy Definition"), - OAUTH2_APP_MAP_FAILED(900962, "Key Management Error", 500, "Error while mapping an existing consumer application."), - TOKEN_INTROSPECTION_FAILED(900963, "Key Management Error", 500, "Error while introspecting the access token."), - ACCESS_TOKEN_GENERATION_FAILED(900964, "Key Management Error", 500, "Error while generating a new access token."), - INVALID_TOKEN_REQUEST(900965, "Key Management Error", 400, "Invalid access token request."), - ACCESS_TOKEN_REVOKE_FAILED(900966, "Key Management Error", 500, "Error while revoking the '%s'."), - - INTERNAL_ERROR(900967, "General Error", 500, "Server Error Occurred"), - INTERNAL_ERROR_WITH_SPECIFIC_MESSAGE(903006, "%s", 500, "Server Error Occurred"), - INTERNAL_ERROR_WITH_SPECIFIC_DESC(903007, "Internal Server Error", 500, "'%s'"), - - POLICY_LEVEL_NOT_SUPPORTED(900968, "Throttle Policy level invalid", 400, "Specified Throttle policy level is not " - + "valid"), - POLICY_LEVEL_EMPTY(900973, "Policy Level can not be empty", 400, - "Throttle policy level can not be empty"), - POLICY_LEVEL_NOT_FOUND(900974, "Policy Level %s not found", 404, - "Throttle policy level %s not found"), - UNSUPPORTED_POLICY_TYPE(901001, "Policy type error", 400, "Unsupported policy type"), - UNSUPPORTED_TIER_TYPE(901002, "Policy tier error", 400, "Unsupported policy tier"), - INVALID_THROTTLE_TIER(901003, "Invalid throttle tier", 400, "Invalid x-throttling tier"), - - THROTTLE_TIER_NOT_FOUND(901004, "Throttle tier", 400, "throttling tier cannot be found"), - - THROTTLING_POLICY_NOT_FOUND(903005, "Throttling Policy Not Found", 404, - "Requested throttling policy with name '%s' and type '%s' not found"), - INVALID_APPLICATION_ADDITIONAL_PROPERTIES(900970, "Invalid application additional properties", 400, - "Invalid additional properties. %s"), - ERROR_RETRIEVE_APPLICATION_DETAILS(900972, "Error while obtaining details of the Application : %s", - 500, "Error while obtaining details of the Application : %s"), - JWT_PARSING_FAILED(900986, "Key Management Error", 500, "Error while parsing JWT. Invalid Jwt."), - TOKEN_SCOPES_NOT_SET( - 900987, "The token information has not been correctly set internally", 400, - "The token information has not been correctly set internally"), - MUTUAL_SSL_NOT_SUPPORTED( - 900988, "Mutual SSL based authentication is not supported in this server", 400, - "Cannot add client certificates to this server"), - THROTTLING_POLICY_CANNOT_BE_NULL(900989, - "Throttling Policy cannot be empty or null", 400, "Throttling Policy cannot be empty or null"), - ALREADY_ASSIGNED_ADVANCED_POLICY_DELETE_ERROR(900971, "Cannot delete the advanced throttling policy", 403, - "Cannot delete the advanced policy with the name %s because it is already assigned to an API/Resource"), - - //Throttle related codes - ADVANCED_POLICY_EXISTS(902900, "Advanced policy already exists", 409, "Advanced Policy with name '%s' already exists"), - APPLICATION_POLICY_EXISTS(902901, "Application policy already exists", 409, "Application Policy with name '%s' already exists"), - SUBSCRIPTION_POLICY_EXISTS(902902, "Subscription policy already exists", 409, "Subscription Policy with name '%s' already exists"), - GLOBAL_POLICY_EXISTS(902903, "Policy already exists", 409, "Policy already exists"), - ADVANCED_POLICY_ADD_FAILED(902904, "Error while adding an Advanced level policy: '%s'", 500, "'%s'"), - ADVANCED_POLICY_GET_FAILED(902905, "Error while retrieving Advanced level policy : '%s'", 500, "'%s'"), - ADVANCED_POLICY_UPDATE_FAILED(902906, "Error while updating Advanced level policy : '%s'", 500, "'%s'"), - SUBSCRIPTION_POLICY_GET_ALL_FAILED(902907, "Error while retrieving Subscription level policies", 500, "Server Error Occurred"), - SUBSCRIPTION_POLICY_ADD_FAILED(902908, "Error while adding Subscription level policies", 500, "Server Error Occurred"), - SUBSCRIPTION_POLICY_GET_FAILED(902909, "Error while retrieving Subscription level policy : '%s'", 500, "Server Error Occurred"), - BAD_POLICY_OBJECT(902010, "Policy object doesn't contain mandatory parameters", 500, "Policy object doesn't contain mandatory parameters."), - SUBSCRIPTION_POLICY_UPDATE_FAILED(902911, "Error while updating Subscription level policy : '%s'", 500, "Server Error Occurred"), - CUSTOM_RULE_EXISTS(902914, "Custom rule already exists", 409, "Custom rule with name %s already exists"), - INVALID_IP_ADDRESS_FORMAT(902915, "Invalid IP address format", 400, "Invalid IP address format"), - BLOCK_CONDITION_ALREADY_EXISTS(902916, "Block condition already exists", 409, "A block condition with type: %s, value: %s already exists"), - ALREADY_ASSIGNED_APP_POLICY_DELETE_ERROR(902912, "Cannot delete the application throttling policy", 409, "Policy %s is already attached to an Application"), - ALREADY_ASSIGNED_SUB_POLICY_DELETE_ERROR(902913, "Cannot delete the subscription throttling policy", 409, "Policy %s already has subscriptions"), - - THROTTLE_TEMPLATE_EXCEPTION(900969, "Policy Generating Error", 500, " Error while generate policy configuration"), - ENDPOINT_CONFIG_NOT_FOUND(90070, "Endpoint Config Not found", 404, "Error while retrieving Endpoint " + - "Configuration"), - UNSUPPORTED_THROTTLE_CONDITION_TYPE(900975, "Throttle Condition Error", 400, "Throttle Condition type is not " - + "supported"), - INVALID_DOCUMENT_CONTENT_DATA(900976, "Invalid document content data provided", 400, "Mismatch between provided " + - "document content data and Document Source Type given"), - BLOCK_CONDITION_UNSUPPORTED_API_CONTEXT(900977, "Block Condition Error", 400, "API Context does not exist"), - BLOCK_CONDITION_UNSUPPORTED_APP_ID_NAME(900978, "Block Condition Error", 400, "Application ID or Name does not " + - "exist"), - SYSTEM_APP_NOT_FOUND(900980, "System Application not found", 409, "System Application not found"), - - SHARED_SCOPE_NOT_FOUND(900981, "Shared Scope not found", 404, - "Requested Shared Scope ID %s could not be found"), - SHARED_SCOPE_ID_NOT_SPECIFIED(900982, "Shared Scope ID not specified", 400, - "Shared Scope ID not specified"), - SHARED_SCOPE_NAME_NOT_SPECIFIED(900983, "Shared Scope name not specified", 400, - "Shared Scope name not specified"), - SCOPE_ALREADY_REGISTERED(900984, "Scope already exists", 409, "Scope %s already exists"), - SHARED_SCOPE_ALREADY_ATTACHED(900985, "Shared Scope already attached", 409, - "Shared Scope %s is already used by one or more APIs"), - SCOPE_VALIDATION_FAILED(900986, "Scope validation failed", 412, "Scope validation failed"), - SHARED_SCOPE_DISPLAY_NAME_NOT_SPECIFIED(900987, "Shared Scope display name not specified", 400, - "Shared Scope display name not specified"), - SCOPE_ALREADY_ASSIGNED(900988, "Scope already assigned locally by another API", 400, - "Scope already assigned locally by another API"), - TOKEN_VALIDATION_FAILED(900989, "Validation failed for the given token", 500, "Validation failed for the given token"), - ERROR_CHECKING_SCOPE_NAME(901000, "Error while checking scope name", 500, - "Error occurred while checking scope name %s"), - ERROR_CREATING_URI_FOR_SHARED_SCOPE(901004, "Error while creating shared scope URI", 500, - "Error while creating URI for shared scope: %s"), - FAILED_RETRIEVE_SHARED_SCOPE(901005, "Error while retrieving shared scope", 500, - "Error while retrieving shared scope"), - FAILED_CHECKING_SCOPE_KEY_AVAILABILITY(901006, "Failed to check scope key availability for: %s" , - 500, "Error while checking scope key availability"), - - //Dedicated container based gateway related Codes - NO_RESOURCE_LOADED_FROM_DEFINITION(900990, "Container based resource Not Found", 404, "No resource loaded from " + - "definition provided"), - LOADED_RESOURCE_DEFINITION_IS_NOT_VALID(900991, "Loaded resource is not valid", 400, "The loaded resource " + - "definition is not a valid"), - TEMPLATE_LOAD_EXCEPTION(900992, "Error in loading the template file by client as an InputStream", 500, " Error " + - "in loading the FileInputStream by client"), - CONTAINER_GATEWAY_REMOVAL_FAILED(900993, "Cannot complete removing dedicated container based Gateway", 404, - "Error in deleting the dedicated container based Gateway"), - ERROR_INITIALIZING_DEDICATED_CONTAINER_BASED_GATEWAY(900994, "Error initializing dedicated container based" + - " gateway", 500, "Error initializing dedicated container based gateway"), - DEDICATED_CONTAINER_GATEWAY_CREATION_FAILED(900995, "Error while creating dedicated container based gateway", 500, - "Error while creating dedicated container based gateway"), - ERROR_WHILE_UPDATING_DEDICATED_CONTAINER_BASED_GATEWAY(900996, "Error while updating dedicated container based" + - " gateway", 500, "Error while updating dedicated container based gateway"), - ERROR_WHILE_RETRIEVING_DEDICATED_CONTAINER_BASED_GATEWAY(900997, "Error while retrieving dedicated container " + - "based gateway", 500, "Error while retrieving dedicated container based gateway"), - INVALID_DEDICATED_CONTAINER_BASED_GATEWAY_LABEL(900998, "Invalid gateway label is provided", 400, - "Invalid gateway label is provided"), - DEDICATED_GATEWAY_DETAILS_NOT_FOUND(900999, "Dedicated gateway details not found for the API", 404, "Dedicated " + - "gateway details not found for the API"), - - //Comments related Codes - NEED_COMMENT_MODERATOR_PERMISSION(901100, "Comment moderator permission needed", 403, - "This user is not a comment moderator"), - COULD_NOT_UPDATE_COMMENT(901101, "Error has occurred. Could not update the Comment", 500, - "Error has occurred. Could not update the Comment"), - COMMENT_NOT_FOUND(901102, "Comment not found", 404, "Failed to retrieve comment"), - COMMENT_LENGTH_EXCEEDED(901103, "Comment length exceeds max limit", 400, "Comment length exceeds allowed maximum " - + "number of characters"), - COMMENT_NO_PERMISSION(901104, "Insufficient permission", 403, "User '%s' doesn't have permission to access the comment with id '%s'"), - COMMENT_CANNOT_RETRIEVE(901105, "Failed to get '%s'", 500, "Failed to get '%s"), - - COMMENT_CANNOT_DELETE(901106, "Failed to delete the Comment", 500, "Failed to delete the Comment of '%s'"), - - NEED_ADMIN_PERMISSION(901100, "Admin permission needed", 403, - "This user is not an admin"), - - //External Stores related codes - EXTERNAL_STORE_ID_NOT_FOUND(901200,"External Store Not Found", 404, "Error while publishing to external stores. " + - "External Store Not Found"), - EXTERNAL_STORE_CLASS_NOT_FOUND(901201, - ExceptionConstants.EXTERNAL_STORE_ERROR_MSG, 404, - "One or more classes defined in APIConstants.EXTERNAL_API_STORE_CLASS_NAME cannot be found"), - EXTERNAL_STORE_CLASS_NOT_LOADED(901202, - ExceptionConstants.EXTERNAL_STORE_ERROR_MSG, 500, - "One or more classes defined in APIConstants.EXTERNAL_API_STORE_CLASS_NAME cannot be loaded"), - EXTERNAL_STORE_CLASS_NOT_ACCESSIBLE(901203, - ExceptionConstants.EXTERNAL_STORE_ERROR_MSG, 500, - "One or more classes defined in APIConstants.EXTERNAL_API_STORE_CLASS_NAME cannot be accessed"), - ERROR_RETRIEVE_EXTERNAL_STORE_CONFIG(901204, "External Store Config Retrieve Error", 500, - "Error while retrieving External Stores Configuration from registry"), - MALFORMED_XML_IN_EXTERNAL_STORE_CONFIG(901205, "Malformed XML in External Stores Configuration", - 500, "Malformed XML found in the External Stores Configuration resource"), - - // Tenant related - INVALID_TENANT(901300,"Tenant Not Found", 404, "Tenant Not Found"), - CONFIG_NOT_FOUND(901301, "Config not found", 404, "Config not found in tenant-config"), - ERROR_GETTING_CUSTOM_URLS(901302, "Failed to get custom url info", 500, "Error while retrieving custom url info for tenant : '%s'"), - // Key Manager Related - INVALID_KEY_MANAGERS_VALUE(901350, "Key Managers value need to be an array", 400, - "Invalid Key Managers value"), - INVALID_KEY_MANAGER_TYPE(901400, "Key Manager Type not configured", 400, "Key Manager Type not configured"), - REQUIRED_KEY_MANAGER_CONFIGURATION_MISSING(901401,"Required Key Manager configuration missing",400,"Missing " + - "required configuration"), - KEY_MANAGER_ALREADY_EXIST(901402, "Key Manager Already Exists", 409, "Key Manager Already Exists"), - KEY_MANAGER_NOT_REGISTERED(901403, "Key Manager not Registered", 400, "Key Manager not Registered"), - KEY_MANAGER_NOT_FOUND(901411, "Key Manager not Found", 404, "Key Manager not found"), - KEY_MANAGER_NAME_EMPTY(901404, - "Key Manager name cannot be empty", 400,"Key Manager name cannot be empty"), - KEY_MANAGER_NOT_SUPPORT_OAUTH_APP_CREATION(901405, "Key Manager doesn't support generating OAuth applications", 400, - "Key Manager doesn't support generating OAuth applications"), - KEY_MANAGER_NOT_SUPPORTED_TOKEN_GENERATION(901405, "Key Manager doesn't support token generation", 400, - "Key Manager doesn't support token generation"), - KEY_MANAGER_NOT_ENABLED(901406, "Key Manager is not enabled in the system", 400, - "Key Manager is not enabled in the system"), - KEY_MANAGER_MISSING_REQUIRED_PROPERTIES_IN_APPLICATION(901407, "Required application properties are missing", 400, - "Required application properties are missing"), - APPLICATION_ALREADY_REGISTERED(901408, "Application already Registered", 409, "Application already Registered"), - KEY_MAPPING_ALREADY_EXIST(901409, "Key Mappings already exists", 409, "Key Mappings already exists"), - TENANT_MISMATCH(901410,"Tenant mismatch", 400, "Tenant mismatch"), - INVALID_APPLICATION_PROPERTIES(901411, "Invalid additional properties", 400, - "Invalid additional properties given for application"), - DECRYPT_CONFIG_ERROR(901412, "Error while decrypting key manager configuration", 500, "Unable to decrypt the value"), - - //Scope related - SCOPE_NOT_FOUND_FOR_USER(901500, "Scope does not belong to this user", 404, "Scope not found"), - SCOPE_NOT_FOUND(901501, "Scope Not Found", 404, "Scope does not exist"), - USER_NOT_FOUND(901502, "User Not Found", 404, "User does not exist"), - DEFINITION_EXCEPTION(901503, "Internal server error.", 500, " Error occurred while retrieving swagger definition"), - - //Analytics related codes - ANALYTICS_NOT_ENABLED(901600, "%s not accessible", 404, - "Analytics should be enabled to access %s"), - UNSUPPORTED_ALERT_TYPE(901601, "Unsupported alert type", 400, "Unsupported alert type: '%s' is provided"), - MALFORMED_SP_URL(901602, "Malformed URL", 500, "Error while parsing the stream processor url"), - ERROR_INVOKING_SP_REST_API(901603, "Error while invoking steam processor REST API", 500, "'%s'"), - ALREADY_SUBSCRIBED_FOR_BOT_ALERTS(901604, "Subscription already exists", 409, "Email: '%s' has already been subscribed for bot detection alerts"), - BOT_DETECTION_SUBSCRIPTION_NOT_FOUND(901605, "Subscription does not exist", 404, "Bot detection alert subscription with uuid: '%s' uuid does not exist"), - - // Password change related - PASSWORD_CHANGE_DISABLED(901450, "Password change disabled", 400, "Password change operation is disabled in the system"), - - CURRENT_PASSWORD_INCORRECT(901451, "Current password incorrect", 400, "The current password entered is incorrect"), - - PASSWORD_PATTERN_INVALID(901452, "Password pattern invalid", 400, "Password entered is invalid since it doesn't comply with the pattern/policy configured"), - - //Tenant theme related codes - TENANT_THEME_IMPORT_FAILED(901700, "Failed to import tenant theme of tenant %s", 500, - "%s"), - TENANT_THEME_EXPORT_FAILED(901701, "Failed to export tenant theme of tenant %s", 500, - "%s"), - TENANT_THEME_IMPORT_NOT_ALLOWED(901702, "Super Tenant not allowed to import tenant theme", 400, - "Super Tenant %s is not allowed to import a tenant theme"), - TENANT_THEME_NOT_FOUND(901703, "Tenant theme does not exist", 404, "Tenant theme for tenant: '%s' does not exist"), - - INVALID_API_IDENTIFIER(900851, "Provided API identifier (%s) is invalid", 400, - "Provided API identifier (%s) is invalid"), - API_NAME_OR_VERSION_NOT_NULL(900852, "name or version couldn't be null", 400, "name or version couldn't be null"), - INVALID_CONFIGURATION_ID(900853,"The configuration id validation failed. Should be " + - "{apiName}#{apiVersion}#{tenantDomain}",400,"The configuration id validation failed. Should be " + - "{apiName}#{apiVersion}#{tenantDomain}"), - INVALID_API_NAME(900854, "Invalid API Name",400 ,"Invalid API Name"), - ALIAS_CANNOT_BE_EMPTY(900855, "The alias cannot be empty", 400, "The alias cannot be empty"), - - // API import/export related codes - ERROR_READING_META_DATA(900907, "Error while reading meta information from the definition", 400, - "Error while reading meta information from the definition"), - ERROR_READING_PARAMS_FILE(900908, "Error while reading meta information from the params file", 400, - "%s"), - ERROR_FETCHING_DEFINITION_FILE(900909, "Cannot find the definition file of the project", 400, - "Cannot find the yaml/json file with the project definition."), - NO_API_ARTIFACT_FOUND(900910, "No Api artifacts found for given criteria", 404, - "No Api artifacts found for given criteria"), - ERROR_UPLOADING_THUMBNAIL(900914, - "Error while updating thumbnail of API/API Product", 500, - "Error while updating thumbnail of API/API Product: %s-%s"), - APICTL_OPENAPI_PARSE_EXCEPTION( - OPENAPI_PARSE_EXCEPTION.getErrorCode(), OPENAPI_PARSE_EXCEPTION.getErrorMessage(), - OPENAPI_PARSE_EXCEPTION.getHttpStatusCode(), "%s"), - GATEWAY_TYPE_NOT_FOUND(900903, "Gateway type not found", 404, - "Gateway type not found available Gateway types : " + "%s"), - - SERVICE_IMPORT_FAILED_WITHOUT_OVERWRITE(900910, "Service import is failed" , 412, "Cannot update existing services " + - "when overwrite is false"), - MISSING_PROTOCOL_IN_ASYNC_API_DEFINITION(900911, "Missing protocol in Async API Definition", 400, - "Missing protocol in Async API Definition"), - UNSUPPORTED_PROTOCOL_SPECIFIED_IN_ASYNC_API_DEFINITION(900912, "Unsupported protocol specified in Async API " + - "Definition", 400, "Unsupported protocol specified in Async API Definition"), - API_CREATION_NOT_SUPPORTED_FOR_ASYNC_TYPE_APIS(900915, "API Creation is supported only for WebSocket, WebSub and SSE APIs", 400, - "API Creation is supported only for WebSocket, WebSub and SSE APIs"), - LOGGING_API_NOT_FOUND(901400, "Requested Resource Not Found", 404, "Request API Not Found for context: %s"), - LOGGING_API_INCORRECT_LOG_LEVEL(901401, "Bad Request", 400, "Log level should be either OFF, BASIC, STANDARD or FULL"), - LOGGING_API_MISSING_DATA(901402, "Missing data", 400, "API context or log level is missing"), - - //Service Catalog related error codes - SERVICE_VERSION_NOT_FOUND(901900, "Cannot find the service version", 404, "Cannot find a service that matches the given version"), - ERROR_RETRIEVE_SERVICE_INFORMATION(901901, "Error while getting service information", - 500, "Error while executing SQL for getting service information"), - - INVALID_ENDPOINT_CREDENTIALS(902000, "Invalid Endpoint Security credentials", 400, - "Invalid Endpoint Security credentials. %s", false), - INVALID_TENANT_CONFIG(902001, "Invalid tenant-config found", 400, "Invalid tenant-config found with error %s", false), - - //Operation Policies related error codes - INVALID_OPERATION_POLICY(902005, "%s. Cannot find the selected operation policy", 400, - "Selected operation policy is not found"), - INVALID_OPERATION_POLICY_SPECIFICATION(902006, "Invalid operation policy specification found", 400, - "Invalid operation policy specification. %s", false), - - INVALID_OPERATION_POLICY_PARAMETERS(902007, "Missing required parameters for operation policy specification", 400, - "Required parameter(s) %s for operation policy specification %s are either missing or empty"), - OPERATION_POLICY_NOT_ALLOWED_IN_THE_APPLIED_FLOW(902008, "Operation policy is not allowed in the applied flow", 400, - "%s policy is not allowed in response flow"), - MISSING_MANDATORY_POLICY_ATTRIBUTES(902009, "Missing mandatory operation policy attribute", 400, - "Required attributes(s) %s for operation policy specification %s are either missing or empty"), - OPERATION_POLICY_NOT_FOUND(902010, "Operation Policy Not Found", 404, - "Requested operation policy with id '%s' not found"), - OPERATION_POLICY_SPEC_MISMATCH(902011, "Applied policy does not match specification", 400, "Applied policy for URI template does not match specification"), - - OPERATION_POLICY_ALREADY_EXISTS(903001, "The Operation Policy already exists.", 409, "An Operation Policy with name '%s' and version '%s' already exists"), - - OPERATION_POLICY_NOT_FOUND_WITH_NAME_AND_VERSION(903004, "Operation Policy Not Found with given name and version", 404, - "Requested operation policy with name '%s' and version '%s' not found"), - - OPERATION_POLICY_GATEWAY_ERROR(903008, - "Either Synapse or Choreo Gateway Definition files or both should be present", 400, - "Operation Policy cannot be imported due to the missing Gateway files."), - OPERATION_POLICY_USAGE_EXISTS(903009, "Operation policy usages exist", 500, "Policy usages exist for policy ID '%s'"), - - SUBSCRIPTION_TIER_NOT_ALLOWED(902002, "Subscription Tier is not allowed for user", 403, "Subscription Tier %s is" + - " not allowed for user %s ", false), - INVALID_KEY_MANAGER_REQUEST(902003, "Invalid Request sent to Key Manager.", 400, "Invalid Request sent to Key Manager.Error from Backend : %s", false), - INTERNAL_SERVER_ERROR_FROM_KEY_MANAGER(902004, "Internal Server Error from Key Manager", 500, "Internal Server Error from Key Manager.Error from Backend : %s", true), - REVISION_ALREADY_DEPLOYED(902005, "Revision deployment state conflicted", 409, - "Revision deployment request conflicted with the current deployment state of the revision %s. Please try again later", false), - INVALID_API_ID(902006, "Invalid API ID", 404, - "The provided API ID is not found %s", false), - GATEWAY_DOMAIN_MAPPING_RETRIEVE_ERROR(902100, "Error retrieving gateway domain mappings from registry", - 500, "Error while retrieving gateway domain mappings from registry"), - INVALID_GATEWAY_DOMAIN_MAPPING_JSON(902101, "Invalid JSON in gateway tenant domain mappings", - 500, "Invalid JSON found in the gateway tenant domain mappings"), - MALFORMED_GATEWAY_DOMAIN_MAPPING_JSON(902102, "Malformed JSON in gateway tenant domain mappings", - 500, "Malformed JSON found in the gateway tenant domain mappings"), - ERROR_PARSING_TENANT_CONFIG_JSON(902103, "Error occurred while converting to json", - 500, "Error occurred while converting tenantConfig to json"), - FAILED_RETRIEVE_CONFIGURATION_FOR_ORGANIZATION(902150, "Failed to retrieve configuration", - 500, "Failed to retrieve %s Configuration for org: %s"), - INVALID_QUERY(902200, "Failed to retrieve configuration", - 500, "Failed to retrieve %s Configuration for org: %s"), - ERROR_RETRIEVING_CLAIM_VALUES(902300, "Error while retrieving claim values from user store", - 500, "Error while retrieving claim values from user store"), - FAILED_FIND_API_USAGE(902350, "Failed to find API Usage for : %s", 500, - "Failed to find API Usage for : %s"), - BAD_REQUEST_SUBSCRIPTION_ID(902351, "Invalid Subscription ID", 400, - "Invalid Subscription ID"), - FAILED_GET_SUBSCRIPTION_POLICY(902352, "Failed to get subscription policy: %s", 500, - "Failed to retrieve subscription policy: %s data"), - FAILED_GET_API_POLICY(902353, "Failed to get API policy: %s", 500, - "Failed to retrieve API policy: %s data"), - FAILED_GET_APPLICATION_POLICY(902354, "Failed to get application policy: %s", 500, - "Failed to retrieve application policy: %s data"), - - READ_ONLY_ENVIRONMENT_NOT_FOUND(902400, "Configured read only environment not found: %s", - 404, "Configured read only environment not found: %s"), - - // monetization related codes - - INVALID_API_STATE_MONETIZATION(904300, "Invalid API state", 400, "Invalid API state to configure monetization"), - MONETIZATION_STATE_CHANGE_FAILED(904301, "Could not change the monetization state", 500, "Monetization state change to '%s' failed"), - - MONETIZATION_IMPLEMENTATION_LOADING_FAILED(904302, "Could not load the monetization implementation", 500, "Failed to load the monetization implementation"), - - // audit related codes - - AUDIT_SEND_FAILED(904200, "Error sending audit data", 500, "Sending audit data failed. Response code: '%s'"), - AUDIT_RETRIEVE_FAILED(904201, "Error retrieving audit data", 500, "Error retrieving audit data"), - - // transport related codes - UNSUPPORTED_TRANSPORT_TYPE(904100, "Unsupported transport type", 400, "Transport type '%s' is not supported"), - - // certificate related error codes - - CERT_NOT_FOUND(904001, "Could not find the certificate", 404, "'Cannot find the certificate with alias '%s' in the truststore'"), - CERT_BAD_REQUEST(904002, "Bad Request", 400, "'%s"), - GET_CERT_CONTENT(904003, "Error getting the certificate content", 500, "'%s'"), - RETRIEVE_CERT(904004, "Could not retrieve the certificate", 500, "'%s"), - DELETE_CERT(904005, "Could not delete the certificate", 500, "Error while deleting the certificate for alias '%s'"), - GET_CERT_INFO(904006, "Could not get the certificate information", 500, "'%s"), - UPDATE_CERT(904007, "Could not update the certificate", 500, "'%s'"), - ENCODE_CERT(904008, "Error occurred while encoding the certificate", 500, "'%s"), - INTERNAL_SERVER_CERT(904009, "Internal server error", 500, "'%s'"), - EXPIRED_CERT(904010, "Certificate expired", 400, "'%s'"), - CERT_ALREADY_EXIST(904011, "Certificate alias already exists", 409, "The alias '%s' already exists in the truststore"), - DECODE_CERT(904012, "Error occurred while decoding the certificate", 500, "'%s'"), - - INVALID_KEY_TYPE(904013, "Bad Request", 400, "Invalid keyType. KeyType should be either PRODUCTION or SANDBOX"), - - ERROR_DELETING_APPLICATION_REGISTRATION(904014, "Can not delete application registration", 400, "Failed to delete Application registration of : '%s'"), - - ERROR_DELETING_APPLICATION_KEY_MAPPING(904015, "Can not delete application key mapping", 500, "Failed to delete Application key mapping of : '%s'"), - - ERROR_RETRIEVE_APPLICATION_KEYS(904016, "Failed to retrieve application keys", 500, "Failed to retrieve application keys for '%s' "); - - private final long errorCode; - private final String errorMessage; - private final int httpStatusCode; - private final String errorDescription; - private boolean stackTrace = false; - - /** - * @param errorCode This is unique error code that pass to upper level. - * @param msg The error message that you need to pass along with the error code. - * @param httpErrorCode This HTTP status code which should return from REST API layer. If you don't want to pass - * a http status code keep it blank. - * @param errorDescription The error description. - */ - ExceptionCodes(long errorCode, String msg, int httpErrorCode, String errorDescription, boolean stackTrace) { - this.errorCode = errorCode; - this.errorMessage = msg; - this.httpStatusCode = httpErrorCode; - this.errorDescription = errorDescription; - this.stackTrace = stackTrace; - } - - /** - * @param errorCode This is unique error code that pass to upper level. - * @param msg The error message that you need to pass along with the error code. - * @param httpErrorCode This HTTP status code which should return from REST API layer. If you don't want to pass - * a http status code keep it blank. - * @param errorDescription The error description. - */ - ExceptionCodes(long errorCode, String msg, int httpErrorCode, String errorDescription) { - this.errorCode = errorCode; - this.errorMessage = msg; - this.httpStatusCode = httpErrorCode; - this.errorDescription = errorDescription; - } - @Override - public long getErrorCode() { - return this.errorCode; - } - - @Override - public String getErrorMessage() { - return this.errorMessage; - } - - @Override - public int getHttpStatusCode() { - return this.httpStatusCode; - } - - @Override - public String getErrorDescription() { - return this.errorDescription; - } - - public boolean printStackTrace() { - - return stackTrace; - } - - /** - * Create an ErrorHandler instance with the provided ExceptionCode filled with some dynamic input values - * - * @param errorHandler ErrorHandler or ExceptionCode object - * @param params dynamic values to be filled - * @return ErrorHandler instance with the provided ExceptionCode filled with some dynamic input values - */ - public static ErrorHandler from(ErrorHandler errorHandler, String... params) { - String message = errorHandler.getErrorMessage(); - String description = errorHandler.getErrorDescription(); - - if (params != null && params.length > 0) { - int placesToFormatInMessage = message.length() - message.replace("%", "").length(); - int placesToFormatInDescription = description.length() - description.replace("%", "").length(); - - String[] part1 = Arrays.copyOfRange(params, 0, placesToFormatInMessage); - String[] part2 = Arrays.copyOfRange(params, placesToFormatInMessage, - placesToFormatInMessage + placesToFormatInDescription); - - if (placesToFormatInMessage > 0) { - message = String.format(message, part1); - } - if (placesToFormatInDescription > 0) { - description = String.format(description, part2); - } + // API, Application related codes + API_NAME_ALREADY_EXISTS(900250, "The API name already exists.", 409, "An API with name '%s' already exists"), + API_CONTEXT_ALREADY_EXISTS(900251, "The API context already exists.", 409, + "An API with context '%s' already exists"), + API_VERSION_ALREADY_EXISTS(900252, "The API version already exists.", 409, + "An API with version '%s' already exists for API '%s'"), + API_EMPTY_PASSWORD_FOR_SECURED_ENDPOINT(900253, + "Empty password is given for endpointSecurity when creating API: %s", + 400, "An empty password is given for endpointSecurity when creating API: %s"), + + API_PRODUCT_CONTEXT_ALREADY_EXISTS(900275, "The API Product context already exists.", 409, + "An API Product with context '%s' already exists"), + + API_ALREADY_EXISTS(900300, "The API already exists.", 409, "The API already exists"), + APPLICATION_ALREADY_EXISTS(900301, "The application already exists.", 409, "The application already exists"), + APIMGT_DAO_EXCEPTION(900302, "Internal server error.", 500, "Error occurred while persisting/retrieving data"), + APIMGT_LIFECYCLE_EXCEPTION(900303, "Lifecycle exception occurred", 500, "Error occurred while changing " + + "lifecycle state"), + TIER_CANNOT_BE_NULL(900304, "The tier cannot be null.", 400, "The tier cannot be null"), + TIER_NAME_INVALID(900305, "The tier name is invalid.", 400, "The tier name is invalid"), + SEARCH_API_EXCEPTION(900306, "Internal server error.", 500, "Error occurred while searching APIs"), + APPLICATION_NOT_FOUND(900307, "Application not found", 404, "Application not found"), + API_NOT_FOUND(900308, "API Not Found", 404, "Requested API with id '%s' not found"), + APPLICATION_DELETE_FAILED(900309, "Error has occurred. Could not delete the application", 500, + "Error has occurred. Could not delete the application '%s'"), + SUBSCRIPTION_NOT_FOUND(900310, "Subscription not found", 404, "Couldn't retrieve Subscriptions for API"), + UPDATE_STATE_CHANGE(900311, "API fields have state changes", 400, + "Couldn't Update as API have changes can't be done"), + DOCUMENT_ALREADY_EXISTS(900312, "Document already exists", 409, "Document already exists"), + COULD_NOT_UPDATE_API(900313, "Error has occurred. Could not update the API", 500, + "Error has occurred. Could not " + + "update the API"), + DOCUMENT_CONTENT_NOT_FOUND(900314, "Document content not found", 404, "Document content not found"), + DOCUMENT_NOT_FOUND(900315, "Document not found", 404, "Document not found"), + DOCUMENT_INVALID_SOURCE_TYPE(900319, "Invalid document source type", 500, + "Source type of the document '%s' is invalid"), + UNSUPPORTED_DOC_EXTENSION(900367, "Document file type not supported", 400, + "Unsupported extension type of document file"), + + API_EXPORT_ERROR(900316, "API export Error", 500, "Error while exporting the given APIs"), + API_IMPORT_ERROR(900317, "API import Error", 500, "Error while importing the given APIs"), + API_PRODUCT_IMPORT_ERROR(900318, "API product import Error", 500, + "Error while importing the given API Products"), + SUBSCRIPTION_STATE_INVALID(900320, "Invalid state change for subscription", 400, "Invalid state change for " + + "subscription"), + API_RETRIEVE_EXCEPTION(900319, "Internal server error.", 500, "Error occurred while retrieving %s"), + APPLICATION_RETRIEVE_EXCEPTION(900320, "Internal server error.", 500, "Error occurred while retrieving %s"), + SUBSCRIPTION_RETRIEVE_EXCEPTION(900321, "Internal server error.", 500, "Error occurred while retrieving %s"), + + GATEWAY_LABELS_CANNOT_BE_NULL(900322, "Gateway labels cannot be null.", 400, "Gateway labels cannot be null"), + ERROR_RETRIEVING_RATING(900323, "Cannot retrieve rating", 500, "Error while retrieving ratings for API '%s'"), + RATING_NOT_FOUND(900324, "Rating not found", 404, "Couldn't retrieve rating for API '%s'"), + RATING_VALUE_INVALID(900325, "Rating value invalid", 400, + "Provided rating value does not fall in between min max " + + "values"), + DOCUMENT_INVALID_VISIBILITY(900326, "Invalid document visibility type", 500, + "Visibility type of the document '%s' is invalid"), + API_TYPE_INVALID(900327, "API Type specified is invalid.", 400, "API Type specified is invalid"), + COMPOSITE_API_ALREADY_EXISTS(900328, "A Composite API already exists.", 409, + "A Composite API already exists for this application"), + API_DEFINITION_NOT_FOUND(900330, "API definition not found", 404, "API definition not found"), + APPLICATION_KEY_MAPPING_NOT_FOUND(900331, "Application Key mapping not found", 404, + "Application Key mapping not " + + "found"), + NO_UPDATE_PERMISSIONS(900332, "No permissions to update API.", 403, "No permissions to update API."), + NO_DELETE_PERMISSIONS(900333, "No permissions to delete API.", 403, "No permissions to delete API."), + API_ATTRIBUTE_NOT_FOUND(900335, "API attribute not found", 404, "API attribute not found"), + SUBSCRIPTION_ALREADY_EXISTS(900336, "Subscription already exists", 409, "Subscription already exists"), + SDK_NOT_GENERATED(900337, "Error while generating SDK", 500, "Error while generating SDK"), + APPLICATION_EXPORT_ERROR(900338, "Application Export Error", 500, + "Error while exporting the given Application"), + APPLICATION_IMPORT_ERROR(900339, "Application Import Error", 500, + "Error while importing the given Application"), + NO_READ_PERMISSIONS(900340, "No permissions to read API.", 403, "No permissions to read API."), + API_PRODUCT_DUPLICATE_RESOURCE(900341, "Cannot create API Product with duplicate resource", + 400, "Cannot create API Product with duplicate resource: %s , verb: %s combination"), + API_PRODUCT_RESOURCE_ENDPOINT_UNDEFINED(900342, + "Cannot create API Product, due to resources with undefined endpoints in their parent APIs", + 409, + "Cannot create API Product %s, due to resources with undefined endpoints in their parent APIs %s"), + API_PRODUCT_WITH_UNSUPPORTED_LIFECYCLE_API(900343, + "Cannot create API Product, due to resources parent API being in an unsupported Life Cycle state", + 409, + "Cannot create API Product, due to resources parent API being in an unsupported Life Cycle state: %s"), + API_PRODUCT_USED_RESOURCES(900344, + "Cannot remove the resource paths because they are used by one or more API Products", + 409, + "Cannot update API: %s:%s, due to the resources to remove are used by one or more API Products"), + API_DELETE_API_PRODUCT_USED_RESOURCES(900344, API_PRODUCT_USED_RESOURCES.getErrorMessage(), 409, + "Cannot delete API since the resources to remove are used by one or more API Products"), + API_CATEGORY_INVALID( + 900345, "The API category is invalid.", 400, " The API category is invalid for API: %s:%s"), + INVALID_ADDITIONAL_PROPERTIES(900346, "Invalid additional properties", 400, + "Invalid additional properties for API: %s:%s"), + INVALID_CONTEXT(900346, "Invalid context provided", 400, "Invalid context provided for API: %s:%s"), + INVALID_ENDPOINT_URL(900346, "Endpoint URL(s) is(are) not valid", 400, "Endpoint URL(s) is(are) not valid"), + USER_ROLES_CANNOT_BE_NULL(900610, "User roles cannot be found", 400, "User roles cannot be found"), + + ERROR_RETRIEVING_REVISION_FOR_UUID(900410, "Failed to get revision details for revision UUID: %s", + 500, "Failed to get revision details"), + + ERROR_RETRIEVING_REVISION_DEPLOYMENT_MAPPING(900411, + "Failed to get API Revision deployment mapping details for %s: %s", 500, + "Failed to get API Revision deployment mapping details"), + + ERROR_UPDATING_REVISION_DEPLOYMENT_MAPPING(900412, + "Failed to update Deployment Mapping entry for API UUID: ", 500, + "Failed to update Deployment Mapping entry"), + + METHOD_NOT_ALLOWED(900420, "Not allowed", 405, "Method not allowed"), + API_REVISION_NOT_FOUND(900347, "API Revision Not Found", 404, "Requested API Revision with id %s not found"), + EXISTING_API_REVISION_DEPLOYMENT_FOUND(900348, "Can not delete API Revision ", 400, + "Couldn't delete API revision since API revision is currently deployed to a gateway. " + + "You need to undeploy the API Revision from the gateway before attempting deleting API Revision: %s "), + EXISTING_API_REVISION_FOUND(900349, "Can not create API Revision ", 400, + "API revision already exists with id: %s "), + API_REVISION_UUID_NOT_FOUND(900350, "Can not create API Revision ", 400, + "Failed to retrieve revision uuid from revision registry artifact"), + MAXIMUM_REVISIONS_REACHED(900351, "Can not create API Revision ", 400, + "Maximum number of revisions per API has reached." + + "Need to remove any revision to create a new Revision for API with API UUID: %s"), + ERROR_CREATING_API_REVISION(900352, "Can not create API Revision ", 400, + "Failed to create API revision registry artifacts: %s "), + ERROR_DELETING_API_REVISION(900353, "Can not delete API Revision ", 400, + "Failed to delete API revision registry artifacts: %s "), + ERROR_RESTORING_API_REVISION(900354, "Can not restore API Revision ", 400, + "Failed to restore API revision registry artifacts: %s "), + DEPLOYMENT_ID_NOT_FOUND(900355, "Deployment Id Not Found", 400, "Deployment Id Not Found"), + EXISTING_DEPLOYMENT_NOT_FOUND(900356, "Existing Deployment Not Found", 404, "Deployment with %s not found"), + ORGANIZATION_NOT_FOUND(900357, "Organization Not Found", 400, "Organization is not found in the request"), + INVALID_ENV_API_PROP_CONFIG(900358, "Invalid environment specific api property config", 400, + "Environment specific api property config is not valid. %s", false), + API_OR_API_PRODUCT_NOT_FOUND(900359, "API or API Product Not Found", 404, + "Requested API or API Product with id '%s' not found"), + API_PRODUCT_NOT_FOUND(900360, "API Product Not Found", 404, "Requested API Product with id '%s' not found"), + SUB_ORGANIZATION_NOT_IDENTIFIED(900361, "User's Organization Not Identified", 403, + "User's Organization is not identified"), + ERROR_RETRIEVING_CATEGORY(900362, "Cannot retrieve categories", 500, + "Error while retrieving categories for organization '%s'"), + PERSISTENCE_ERROR(900363, "Error occurred in registry transaction", 500, "'%s'"), + NO_VIEW_UPDATE_PERMISSIONS(900365, "Insufficient permission to view or update the API", 403, + "Insufficient permission to view or update the API"), + API_DELETE_FAILED_SUBSCRIPTIONS(900366, "Failed to delete the API", 409, + "Cannot remove the API as active subscriptions exist"), + CATEGORY_NAME_CONTAINS_SPECIAL_CHARS(900368, "Name field contains special characters", 400, + "API Category name contains special characters"), + CATEGORY_NAME_TOO_LONG(900369, "API Category name is too long", 400, + "API Category name exceeds 255 characters"), + CATEGORY_ALREADY_EXISTS(900370, "API Category name already exists", 409, + "Category with name '%s' already exists"), + CATEGORY_NOT_FOUND(900371, "Category not found", 404, "No API Category with the given category ID '%s' exists"), + CATEGORY_USED(900372, "Category has usages", 409, "Category is attached to one or more APIs"), + ERROR_CHANGING_APP_OWNER(900373, "Failed to change the application owner", 500, + "Error while changing the application owner"), + + USER_SUBSCRIPTION_EXISTS_CHECK_FAILED(900374, "Failed to check if user subscribed to API", 500, + "Failed to check if user '%s' with an application '%s' is subscribed to API %s"), + + USER_ACCESSIBLE_APPLICATION_CHECK_FAILED(900375, "Failed to check if user subscribed to API", 500, + "Error occurred while checking whether the application '%s' is accessible to user '%s'"), + API_TAGS_NOT_FOUND(900376, "API Tags Not Found", 404, "API Tags not found for organization '%s'"), + + // Lifecycle related codes + API_UPDATE_FORBIDDEN_PER_LC(900380, "Insufficient permission to update the API", 403, + "Updating the API is restricted as as it is %s."), + UNSUPPORTED_LIFECYCLE_ACTION(900381, "Unsupported state change action", 400, + "Lifecycle state change action %s is not allowed"), + LIFECYCLE_STATE_INFORMATION_NOT_FOUND(900382, "Lifecycle state information not found", 500, + "Lifecycle state change information for %s with %s cannot be found"), + + // Generic codes + JSON_PARSE_ERROR(900400, "Json parse error", 500, "JSON parse error"), + RESOURCE_NOT_FOUND(900401, "Resource not found", 404, "Requested resource not found"), + RESOURCE_RETRIEVAL_FAILED(900402, "Resource retrieval failed", 400, "Resource retrieval failed"), + USER_MAPPING_RETRIEVAL_FAILED(900404, "User mapping retrieval failed", 404, "User mapping retrieval failed"), + MALFORMED_URL(900403, "Malformed URL", 400, "Invalid or Malformed URL"), + URI_PARSE_ERROR(900405, "Error constructing the URI", 500, "'%s'"), + INVALID_OPERATION_TYPE(900406, "Unsupported '%s' operation", 400, "The '%s' operation type '%s' is invalid"), + VERB_NOT_FOUND(900407, "Missing '%s' type", 400, "Missing '%s type in URI templates"), + YAML_PARSE_ERROR(900408, "Yaml parse error", 500, "Yaml parse error"), + RESOURCE_NOT_FOUND_WITH_TYPE_AND_ID(900409, "Requested %s with Id %s not found", 404, + "Requested %s with Id %s not found"), + AUTHORIZATION_ERROR(900409, "Forbidden", 403, "You don't have permission to access the '%s' with Id '%s'"), + FORBIDDEN_ERROR(900409, "Forbidden", 403, "You don't have permission to access this resource"), + RESOURCE_NOT_FOUND_WITH_DESC(900401, "Resource not found", 404, "Requested '%s' with Id '%s' not found"), + UNAUTHORIZED(900410, "Unauthorized", 401, "User is unauthorized"), + + // Endpoint related codes + ENDPOINT_NOT_FOUND(900450, "Endpoint Not Found", 404, "Endpoint Not Found"), + ENDPOINT_ALREADY_EXISTS(900451, "Endpoint already exists", 409, "Endpoint already exists"), + ENDPOINT_ADD_FAILED(900452, "Endpoint adding failed", 400, "Endpoint adding failed"), + ENDPOINT_DELETE_FAILED(900453, "Endpoint Delete Failed", 400, "Endpoint Delete Failed"), + ENDPOINT_CRYPTO_ERROR(900454, "Error while encrypting/decrypting endpoint secrets", 500, "'%s'"), + ENDPOINT_CONFIG_PARSE_FAILED(900455, "Endpoint config parsing failed", 500, + "Error occurred while parsing endpoint config json"), + + // Service Endpoint Discovery related codes + ERROR_LOADING_SERVICE_DISCOVERY_IMPL_CLASS(900460, "Error loading service discovery impl class", 500, + "Error while trying to load a service discovery impl class"), + ERROR_INITIALIZING_SERVICE_DISCOVERY(900461, "Error initializing service discovery", 500, + "Error while connecting to the system with services"), + ERROR_WHILE_TRYING_TO_DISCOVER_SERVICES(900462, "Error while discovering services", 500, + "Error while trying to discover service endpoints"), + + // Gateway related codes + API_DEFINITION_MALFORMED(900500, "ApiDefinition not found", 400, "Failed to retrieve API Definition"), + TEMPLATE_EXCEPTION(900501, "Service configuration Error", 500, "Error generate service config"), + GATEWAY_EXCEPTION(900502, "Gateway publishing Error", 500, "Error occurred while publishing to Gateway"), + BROKER_EXCEPTION(900503, "Broker Connection Error", 500, "Error occurred while obtaining broker connection"), + INVALID_GATEWAY_ENVIRONMENT(900504, "Invalid Gateway Environment", 400, + "Gateway Environment with name '%s' not found"), + NO_GATEWAY_ENVIRONMENTS_ADDED(900505, "No Gateway Environments Available", 400, "No gateway environments " + + "available for the API : %s."), + GATEWAY_ENVIRONMENT_NOT_FOUND(900506, "Gateway Environment not found", 404, + "Gateway Environment with %s not found"), + EXISTING_GATEWAY_ENVIRONMENT_FOUND(900507, "Gateway Environment already exists", 400, + "A Gateway Environment with %s already exists"), + READONLY_GATEWAY_ENVIRONMENT(900508, "Gateway Environment is read only", 400, + "A Gateway Environment with %s is read only"), + GATEWAY_ENVIRONMENT_DUPLICATE_VHOST_FOUND(900509, "Gateway Environment with duplicate virtual hosts", + 400, "A Gateway Environment cannot exists with duplicate virtual hosts"), + READONLY_GATEWAY_ENVIRONMENT_NAME(900510, "Names of Gateway Environment cannot be changed", + 400, "Name of the gateway is read only"), + GATEWAY_ENVIRONMENT_VHOST_NOT_PROVIDED(900511, "Gateway Environment virtual hosts name not provided", + 400, "Gateway Environment VHOST name not provided"), + + FAILED_GET_ENVIRONMENT_LIST_OF_VHOST(900512, "Failed to get gateway environments list of VHost", + 500, "Failed to get gateway environments list of VHost"), + FAILED_GET_ENVIRONMENT_LIST_OF_TENANT_DOMAIN(900513, "Failed to get Environments in tenant domain", + 500, "Failed to get Environments in tenant domain: %s"), + FAILED_GET_ENVIRONMENT_FOR_TENANT_DOMAIN(900514, "Failed to get Environment in tenant domain: %s", + 500, "Failed to get Environment in tenant domain: %s"), + TENANT_NOT_FOUND(900515, "Tenant does not exist", 404, + "Tenant does not exist"), + INVALID_TENANT_STATE(900516, "Invalid tenant state", 400, + "Invalid tenant state provided"), + FAILED_GET_ENVIRONMENT_SPECIFIC_PROPERTIES(900517, + "Error occurred when getting environment specific api properties", 500, + "Error occurred when getting environment specific api properties"), + VHOST_FOR_ENVIRONMENT_NOT_FOUND(900518, "VHosts not found for the environment: %s", 404, + "VHosts not found for the environment: %s"), + + // Workflow related codes + WORKFLOW_EXCEPTION(900550, "Workflow error", 500, + "Error occurred while executing workflow task"), + WORKFLOW_NOT_FOUND(900551, "Workflow error", 404, + "Workflow entry cannot be found for the given reference id"), + WORKFLOW_ALREADY_COMPLETED(900552, "Workflow error", 400, + "Workflow is already completed"), + WORKFLOW_PENDING(900553, "Workflow exception", 409, + "Pending workflow task exists for the seleted API"), + WORKFLOW_INVALID_WFTYPE(900554, "Workflow error", 500, "Invalid workflow type specified"), + WORKFLOW_INV_STORE_WFTYPE(900555, "Workflow error", 500, "Invalid workflow type for store workflows"), + WORKFLOW_STATE_MISSING(900556, "Workflow error", 400, "Workflow status is not defined"), + WORKFLOW_NO_PENDING_TASK(900557, "Workflow error", 412, + "Requested resource does not have a pending workflow task"), + WORKFLOW_REJCECTED(900558, "Workflow error", 403, "Requested action is rejected"), + INCOMPATIBLE_WORKFLOW_REQUEST_FOR_PUBLISHER(900559, "Incompatible workflow request", 400, + "Incompatible workflow " + + "request received by publisher"), + INCOMPATIBLE_WORKFLOW_REQUEST_FOR_STORE(900560, "Incompatible workflow request", 400, "Incompatible workflow " + + "request received by store"), + WORKFLOW_RETRIEVE_EXCEPTION(900561, "Workflow retrieval error", 400, "Provided parameter is not valid"), + + // Auth related codes + ROLES_CANNOT_BE_EMPTY(900600, "Role list cannot be empty", 400, "Role list cannot be empty"), + ROLES_CANNOT_BE_NULL(900601, "Role list cannot be null", 400, "Role list cannot be null"), + UNSUPPORTED_ROLE(900602, "Non existing roles cannot be added to an API", 400, + "Non existing roles cannot be added to an API"), + USER_DOES_NOT_EXIST(900603, "User does not exist in the system", 404, "User does not exist in the system"), + USER_CREATION_FAILED(900604, "User creation failed", 500, "User creation failed"), + IDP_INITIALIZATION_FAILED(900605, "Identity Provider initialization failed", 500, + "Identity provider initialization failed"), + KEY_MANAGER_INITIALIZATION_FAILED(900606, "Key Manager initialization failed", 500, + "Key Manager initialization failed", true), + ROLE_DOES_NOT_EXIST(900607, "Role does not exist in the system", 404, "Role does not exist in the system"), + MULTIPLE_ROLES_EXIST(900608, "Multiple roles with the same display name exist in the system", 500, "Multiple " + + "roles with the same display name exist in the system"), + MULTIPLE_USERS_EXIST(900609, "Multiple users with the same username exist in the system", 500, "Multiple " + + "users with the same username exist in the system"), + INVALID_USER_ROLES(900610, "Invalid user roles found", 400, "Invalid user roles found"), + IDP_ADDING_FAILED(900611, "Unable to add the identity provider", 400, + "Error while adding the identity provider"), + IDP_RETRIEVAL_FAILED(900612, "Unable to retrieve the identity provider", 400, "Error while retrieving the " + + "identity provider details"), + IDP_DELETION_FAILED(900613, "Unable to delete the identity provider", 400, "Error while deleting the " + + "identity provider"), + INVALID_IDP_TYPE(900614, "Unsupported identity provider type", 400, "Invalid identity provider type. %s"), + USERSTORE_INITIALIZATION_FAILED(900615, "Unable to get the user store manager", 500, + "Error while getting the user store manager from the realm"), + ANON_USER_ACTION(900616, "Operation not permitted", 401, + "Attempt to execute privileged operation as the anonymous user"), + ROLE_ID_EMPTY(900617, "Role Id cannot be empty", 400, + "Role Id cannot be empty"), + + // Labels related codes + LABEL_INFORMATION_CANNOT_BE_NULL(900650, "Label information cannot be null", 400, + "Label information cannot be " + + "null"), + LABEL_EXCEPTION(900651, "Label Error", 500, "Error occurred while retrieving label information"), + LABEL_NOT_FOUND(900652, "Label Not Found", 404, "Label with specified name cannot be found."), + LABEL_NOT_FOUND_IN_API(900653, "Label Not Found In API", 404, "Label with specified name" + + " cannot be found in the API."), + LABEL_ADDING_FAILED(900654, "Label Error", 500, "Error occurred while trying to add label"), + LABEL_UPDATE_FAILED(900655, "Label Error", 500, "Error occurred while trying to update label"), + LABEL_DELETION_FAILED(900656, "Label Error", 500, "Error occurred while trying to delete label"), + + // WSDL related codes + INVALID_WSDL_URL_EXCEPTION(900675, "Invalid WSDL", 400, "Invalid WSDL URL"), + CANNOT_PROCESS_WSDL_CONTENT(900676, "Invalid WSDL", 400, "Provided WSDL content cannot be processed"), + INTERNAL_WSDL_EXCEPTION(900677, "Internal WSDL error", 500, "Internal error while processing WSDL"), + UNSUPPORTED_WSDL_EXTENSIBILITY_ELEMENT(900678, "Invalid WSDL", 400, "WSDL extensibility element not supported"), + ERROR_WHILE_INITIALIZING_WSDL_FACTORY(900679, "Internal WSDL error", 500, + "Error while initializing WSDL factory"), + ERROR_WHILE_CREATING_WSDL_ARCHIVE(900680, "Internal WSDL error", 500, "Error while creating WSDL archive"), + NO_WSDL_FOUND_IN_WSDL_ARCHIVE(900681, "Invalid WSDL Archive", 400, + "No valid WSDLs found in the provided WSDL archive"), + CONTENT_NOT_RECOGNIZED_AS_WSDL(900682, "Invalid WSDL Content", 400, + "Provided content is not recognized as a WSDL"), + URL_NOT_RECOGNIZED_AS_WSDL(900683, "Invalid WSDL URL", 400, "Provided URL is not recognized as a WSDL"), + NO_WSDL_AVAILABLE_FOR_API(900684, "WSDL Not Found", 404, "No WSDL Available for the API %s:%s"), + CORRUPTED_STORED_WSDL(900685, "Corrupted Stored WSDL", 500, "The WSDL of the API %s is corrupted."), + UNSUPPORTED_WSDL_FILE_EXTENSION(900686, "Unsupported WSDL File Extension", 400, + "Unsupported extension. Only supported extensions are .wsdl and .zip"), + API_NOT_SOAPTOREST(900687, "Provided API is not a SOAP to REST converted API", 400, + "Provided API is not a SOAP to REST converted API"), + ERROR_ADDING_WSDL_TO_API(900687, "Error while adding WSDL to API: %s", 500, + "Error while saving WSDL"), + + // OpenAPI/Swagger related codes [900750 900???) + MALFORMED_OPENAPI_DEFINITON(900758, "Malformed OpenAPI Definition", 400, + "The provided OpenAPI definition is not parsable as a valid JSON or YAML."), + UNRECOGNIZED_OPENAPI_DEFINITON(900759, "Unrecognized OpenAPI Definition", 400, + "The definition is parsable but cannot be identified as an OpenAPI definition."), + INVALID_SWAGGER_VERSION(900760, "Invalid Swagger Definition", 400, + "Unsupported swagger version provided. Please add with swagger version 2.0."), + INVALID_SWAGGER_PARAMS(900751, "Invalid Swagger Definition", 400, + "Swagger contains invalid parameters. Please add valid swagger definition."), + INVALID_OPENAPI_VERSION(900752, "Invalid OpenAPI Definition", 400, + "Unsupported OpenAPI version provided. Please add with OpenAPI version 3.0.0."), + INVALID_OPENAPI_NO_INFO_PATH(900753, "Invalid OpenAPI Definition", 400, + "Required property 'info' or 'paths' are not provided."), + OPENAPI_PARSE_EXCEPTION(900754, "Error while parsing OpenAPI definition", 400, + "Error while parsing OpenAPI definition"), + OPENAPI_PARSE_EXCEPTION_WITH_CUSTOM_MESSAGE(OPENAPI_PARSE_EXCEPTION.getErrorCode(), + OPENAPI_PARSE_EXCEPTION.getErrorMessage(), OPENAPI_PARSE_EXCEPTION.getHttpStatusCode(), "'%s'"), + OPENAPI_NOT_FOUND(900755, "OpenAPI definition not found", 404, "OpenAPI definition not found"), + OPENAPI_URL_MALFORMED(900756, "OpenAPI definition retrieval from URL failed", 400, + "Exception occurred while retrieving the OpenAPI definition from URL"), + OPENAPI_URL_NO_200(900757, "OpenAPI definition retrieval from URL failed", 400, + "Response didn't return a 200 OK status"), + INVALID_OAS2_FOUND(900761, "Invalid OpenAPI V2 definition found", 400, "Invalid OpenAPI V2 definition found"), + INVALID_OAS3_FOUND(900762, "Invalid OpenAPI V3 definition found", 400, "Invalid OpenAPI V3 definition found"), + NO_RESOURCES_FOUND(900763, "No resources found", 404, "API must have at least one resource defined"), + ERROR_REMOVING_EXAMPLES(900764, "Internal Error While Processing Swagger Definition", 500, + "Couldn't remove one or more examples from the swagger definition"), + MOCK_HTTP_METHOD_MISSING(900765, "Could not find HTTP methods", 400, + "Cannot find the HTTP method for the API Resource Mediation Policy"), + SWAGGER_ARCHIVE_MISSING(900766, "Could not find an archive in the given ZIP file", 500, + "Could not find an archive in the given ZIP file"), + + // AsyncApi related error codes + ASYNCAPI_URL_MALFORMED(900756, "AsyncAPI specification retrieval from URL failed", 400, + "Exception occurred while retrieving the AsyncAPI Specification from URL"), + ASYNCAPI_URL_NO_200(900757, "AsyncAPI specification retrieval from URL failed", 400, + "Response didn't return a 200 OK status"), + + ERROR_READING_ASYNCAPI_SPECIFICATION(900765, "AsyncAPI specification read error", 500, + "Exception occurred while reading the AsyncAPI Specification file"), + + // REST API related codes + PARAMETER_NOT_PROVIDED(900700, "Parameter value missing", 400, + "Some of the mandatory parameter values were missing"), + LOCATION_HEADER_INCORRECT(900701, "Error while obtaining URI for Location header", 500, + "Error occurred while obtaining URI for Location header"), + LAST_UPDATED_TIME_RETRIEVAL_ERROR(900702, "Error while retrieving last access time for the resource", 500, + "Error while retrieving last access time for the resource"), + INVALID_DATE_TIME_STAMP(900703, "Invalid timestamp value", 400, "Timestamp should be in ISO8601 format"), + LENGTH_EXCEEDS(900704, "Character length exceeds the allowable limit", 400, + "One of the provided input character length exceeds the allowable limit."), + BLANK_PROPERTY_VALUE(900705, "Blank value for required property", 400, + "%s property value of payload cannot be blank"), + CONTAIN_SPECIAL_CHARACTERS(900706, "contain invalid characters", 400, + "%s property value of payload cannot contain invalid characters"), + INVALID_SORT_CRITERIA(900707, "Invalid sort criteria", 400, "Sort criteria contain a non-allowable value"), + INVALID_PARAMETERS_PROVIDED(900708, "Invalid parameter(s) provided", 400, + "Bad Request. Mandatory parameters are invalid/missing"), + + INVALID_PARAMETERS_PROVIDED_WITH_MESSAGE(900708, "'%s'", 400, "Bad Request. Parameters are invalid/missing"), + + // GraphQL API related codes + API_NOT_GRAPHQL(900800, "This API is not a GraphQL API", 400, "This API is not a GraphQL API"), + GRAPHQL_SCHEMA_CANNOT_BE_NULL(900801, "GraphQL Schema cannot be empty or nul", 400, + "GraphQL Schema cannot be empty or null"), + UNSUPPORTED_GRAPHQL_FILE_EXTENSION(900802, "Unsupported GraphQL Schema File Extension", 400, + "Unsupported extension. Only supported extensions are .graphql, .txt and .sdl"), + + // GRPC API related codes + GRPC_PROTO_DEFINTION_CANNOT_BE_NULL(900803, "gRPC Proto Definition cannot be empty or null", 400, + "gRPC Proto Definition cannot be empty or null"), + API_NOT_GRPC(900800, "This API is not a GRPC API", 400, "This API is not a GRPC API"), + PROTO_DEFINITION_PARSE_EXCEPTION(900754, "Error while parsing the proto definition", 400, + "Error while parsing the proto definition"), + + // Oauth related codes + AUTH_GENERAL_ERROR(900900, "Authorization Error", 403, " Error in authorization"), + INVALID_CREDENTIALS(900901, "Invalid Credentials", 401, " Invalid username or password"), + MISSING_CREDENTIALS(900902, "Missing Credentials", 401, " Please provide an active access token to proceed"), + ACCESS_TOKEN_EXPIRED(900903, "Invalid Credentials", 401, " Access token is expired."), + ACCESS_TOKEN_INACTIVE(900904, "Access Token Error", 401, " Access token is inactive."), + USER_NOT_AUTHENTICATED(900905, "User is not Authenticated", 401, " User is not authenticated."), + ACCESS_TOKEN_INVALID(900906, "Invalid Credentials", 401, " Access token is invalid."), + + INVALID_SCOPE(900910, "Invalid Scope", 403, " You are not authorized to access the resource."), + INVALID_AUTHORIZATION_HEADER(900911, "Invalid Authorization header", 401, + " Please provide the Authorization : Bearer <> token to proceed."), + MALFORMED_AUTHORIZATION_HEADER_OAUTH(900912, "Malformed Authorization Header", 400, + "Please provide the Authorization : Bearer <> token to proceed."), + MALFORMED_AUTHORIZATION_HEADER_BASIC(900913, "Malformed Authorization Header", 400, + "Please provide the Authorization : Basic <> token to proceed."), + INVALID_PERMISSION(900915, "Invalid Permission", 403, " You are not authorized to access the '%s'."), + OPENID_CONFIG(900916, "Missing OpenID configurations", 500, "Error in fetching Open ID configuration"), + OAUTH2_APP_CREATION_FAILED(900950, "Key Management Error", 500, + "Error while creating the consumer application."), + OAUTH2_APP_ALREADY_EXISTS(900951, "Key Management Error", 409, "OAuth2 application already created."), + OAUTH2_APP_DELETION_FAILED(900952, "Key Management Error", 500, + "Error while deleting the consumer application."), + OAUTH2_APP_UPDATE_FAILED(900953, "Key Management Error", 500, "Error while updating the consumer application."), + OAUTH2_APP_RETRIEVAL_FAILED(900954, "Key Management Error", 500, + "Error while retrieving the consumer application."), + APPLICATION_TOKEN_GENERATION_FAILED(900957, "Keymanagement Error", 500, + " Error while generating the application" + + "access token."), + APPLICATION_CONSUMER_KEY_NOT_FOUND(900958, "Keymanagement Error", 403, + "Requested consumer key with application '%s' not found"), + UNSUPPORTED_THROTTLE_LIMIT_TYPE(900960, "Throttle Policy Error", 400, "Throttle Limit type is not supported"), + POLICY_NOT_FOUND(900961, "Policy Not found", 404, "Failed to retrieve Policy Definition"), + OAUTH2_APP_MAP_FAILED(900962, "Key Management Error", 500, + "Error while mapping an existing consumer application."), + TOKEN_INTROSPECTION_FAILED(900963, "Key Management Error", 500, "Error while introspecting the access token."), + ACCESS_TOKEN_GENERATION_FAILED(900964, "Key Management Error", 500, + "Error while generating a new access token."), + INVALID_TOKEN_REQUEST(900965, "Key Management Error", 400, "Invalid access token request."), + ACCESS_TOKEN_REVOKE_FAILED(900966, "Key Management Error", 500, "Error while revoking the '%s'."), + + INTERNAL_ERROR(900967, "General Error", 500, "Server Error Occurred"), + INTERNAL_ERROR_WITH_SPECIFIC_MESSAGE(903006, "%s", 500, "Server Error Occurred"), + INTERNAL_ERROR_WITH_SPECIFIC_DESC(903007, "Internal Server Error", 500, "'%s'"), + + POLICY_LEVEL_NOT_SUPPORTED(900968, "Throttle Policy level invalid", 400, + "Specified Throttle policy level is not " + + "valid"), + POLICY_LEVEL_EMPTY(900973, "Policy Level can not be empty", 400, + "Throttle policy level can not be empty"), + POLICY_LEVEL_NOT_FOUND(900974, "Policy Level %s not found", 404, + "Throttle policy level %s not found"), + UNSUPPORTED_POLICY_TYPE(901001, "Policy type error", 400, "Unsupported policy type"), + UNSUPPORTED_TIER_TYPE(901002, "Policy tier error", 400, "Unsupported policy tier"), + INVALID_THROTTLE_TIER(901003, "Invalid throttle tier", 400, "Invalid x-throttling tier"), + + THROTTLE_TIER_NOT_FOUND(901004, "Throttle tier", 400, "throttling tier cannot be found"), + + THROTTLING_POLICY_NOT_FOUND(903005, "Throttling Policy Not Found", 404, + "Requested throttling policy with name '%s' and type '%s' not found"), + INVALID_APPLICATION_ADDITIONAL_PROPERTIES(900970, "Invalid application additional properties", 400, + "Invalid additional properties. %s"), + ERROR_RETRIEVE_APPLICATION_DETAILS(900972, "Error while obtaining details of the Application : %s", + 500, "Error while obtaining details of the Application : %s"), + JWT_PARSING_FAILED(900986, "Key Management Error", 500, "Error while parsing JWT. Invalid Jwt."), + TOKEN_SCOPES_NOT_SET( + 900987, "The token information has not been correctly set internally", 400, + "The token information has not been correctly set internally"), + MUTUAL_SSL_NOT_SUPPORTED( + 900988, "Mutual SSL based authentication is not supported in this server", 400, + "Cannot add client certificates to this server"), + THROTTLING_POLICY_CANNOT_BE_NULL(900989, + "Throttling Policy cannot be empty or null", 400, "Throttling Policy cannot be empty or null"), + ALREADY_ASSIGNED_ADVANCED_POLICY_DELETE_ERROR(900971, "Cannot delete the advanced throttling policy", 403, + "Cannot delete the advanced policy with the name %s because it is already assigned to an API/Resource"), + + // Throttle related codes + ADVANCED_POLICY_EXISTS(902900, "Advanced policy already exists", 409, + "Advanced Policy with name '%s' already exists"), + APPLICATION_POLICY_EXISTS(902901, "Application policy already exists", 409, + "Application Policy with name '%s' already exists"), + SUBSCRIPTION_POLICY_EXISTS(902902, "Subscription policy already exists", 409, + "Subscription Policy with name '%s' already exists"), + GLOBAL_POLICY_EXISTS(902903, "Policy already exists", 409, "Policy already exists"), + ADVANCED_POLICY_ADD_FAILED(902904, "Error while adding an Advanced level policy: '%s'", 500, "'%s'"), + ADVANCED_POLICY_GET_FAILED(902905, "Error while retrieving Advanced level policy : '%s'", 500, "'%s'"), + ADVANCED_POLICY_UPDATE_FAILED(902906, "Error while updating Advanced level policy : '%s'", 500, "'%s'"), + SUBSCRIPTION_POLICY_GET_ALL_FAILED(902907, "Error while retrieving Subscription level policies", 500, + "Server Error Occurred"), + SUBSCRIPTION_POLICY_ADD_FAILED(902908, "Error while adding Subscription level policies", 500, + "Server Error Occurred"), + SUBSCRIPTION_POLICY_GET_FAILED(902909, "Error while retrieving Subscription level policy : '%s'", 500, + "Server Error Occurred"), + BAD_POLICY_OBJECT(902010, "Policy object doesn't contain mandatory parameters", 500, + "Policy object doesn't contain mandatory parameters."), + SUBSCRIPTION_POLICY_UPDATE_FAILED(902911, "Error while updating Subscription level policy : '%s'", 500, + "Server Error Occurred"), + CUSTOM_RULE_EXISTS(902914, "Custom rule already exists", 409, "Custom rule with name %s already exists"), + INVALID_IP_ADDRESS_FORMAT(902915, "Invalid IP address format", 400, "Invalid IP address format"), + BLOCK_CONDITION_ALREADY_EXISTS(902916, "Block condition already exists", 409, + "A block condition with type: %s, value: %s already exists"), + ALREADY_ASSIGNED_APP_POLICY_DELETE_ERROR(902912, "Cannot delete the application throttling policy", 409, + "Policy %s is already attached to an Application"), + ALREADY_ASSIGNED_SUB_POLICY_DELETE_ERROR(902913, "Cannot delete the subscription throttling policy", 409, + "Policy %s already has subscriptions"), + + THROTTLE_TEMPLATE_EXCEPTION(900969, "Policy Generating Error", 500, + " Error while generate policy configuration"), + ENDPOINT_CONFIG_NOT_FOUND(90070, "Endpoint Config Not found", 404, "Error while retrieving Endpoint " + + "Configuration"), + UNSUPPORTED_THROTTLE_CONDITION_TYPE(900975, "Throttle Condition Error", 400, "Throttle Condition type is not " + + "supported"), + INVALID_DOCUMENT_CONTENT_DATA(900976, "Invalid document content data provided", 400, + "Mismatch between provided " + + "document content data and Document Source Type given"), + BLOCK_CONDITION_UNSUPPORTED_API_CONTEXT(900977, "Block Condition Error", 400, "API Context does not exist"), + BLOCK_CONDITION_UNSUPPORTED_APP_ID_NAME(900978, "Block Condition Error", 400, + "Application ID or Name does not " + + "exist"), + SYSTEM_APP_NOT_FOUND(900980, "System Application not found", 409, "System Application not found"), + + SHARED_SCOPE_NOT_FOUND(900981, "Shared Scope not found", 404, + "Requested Shared Scope ID %s could not be found"), + SHARED_SCOPE_ID_NOT_SPECIFIED(900982, "Shared Scope ID not specified", 400, + "Shared Scope ID not specified"), + SHARED_SCOPE_NAME_NOT_SPECIFIED(900983, "Shared Scope name not specified", 400, + "Shared Scope name not specified"), + SCOPE_ALREADY_REGISTERED(900984, "Scope already exists", 409, "Scope %s already exists"), + SHARED_SCOPE_ALREADY_ATTACHED(900985, "Shared Scope already attached", 409, + "Shared Scope %s is already used by one or more APIs"), + SCOPE_VALIDATION_FAILED(900986, "Scope validation failed", 412, "Scope validation failed"), + SHARED_SCOPE_DISPLAY_NAME_NOT_SPECIFIED(900987, "Shared Scope display name not specified", 400, + "Shared Scope display name not specified"), + SCOPE_ALREADY_ASSIGNED(900988, "Scope already assigned locally by another API", 400, + "Scope already assigned locally by another API"), + TOKEN_VALIDATION_FAILED(900989, "Validation failed for the given token", 500, + "Validation failed for the given token"), + ERROR_CHECKING_SCOPE_NAME(901000, "Error while checking scope name", 500, + "Error occurred while checking scope name %s"), + ERROR_CREATING_URI_FOR_SHARED_SCOPE(901004, "Error while creating shared scope URI", 500, + "Error while creating URI for shared scope: %s"), + FAILED_RETRIEVE_SHARED_SCOPE(901005, "Error while retrieving shared scope", 500, + "Error while retrieving shared scope"), + FAILED_CHECKING_SCOPE_KEY_AVAILABILITY(901006, "Failed to check scope key availability for: %s", + 500, "Error while checking scope key availability"), + + // Dedicated container based gateway related Codes + NO_RESOURCE_LOADED_FROM_DEFINITION(900990, "Container based resource Not Found", 404, + "No resource loaded from " + + "definition provided"), + LOADED_RESOURCE_DEFINITION_IS_NOT_VALID(900991, "Loaded resource is not valid", 400, "The loaded resource " + + "definition is not a valid"), + TEMPLATE_LOAD_EXCEPTION(900992, "Error in loading the template file by client as an InputStream", 500, + " Error " + + "in loading the FileInputStream by client"), + CONTAINER_GATEWAY_REMOVAL_FAILED(900993, "Cannot complete removing dedicated container based Gateway", 404, + "Error in deleting the dedicated container based Gateway"), + ERROR_INITIALIZING_DEDICATED_CONTAINER_BASED_GATEWAY(900994, "Error initializing dedicated container based" + + " gateway", 500, "Error initializing dedicated container based gateway"), + DEDICATED_CONTAINER_GATEWAY_CREATION_FAILED(900995, "Error while creating dedicated container based gateway", + 500, + "Error while creating dedicated container based gateway"), + ERROR_WHILE_UPDATING_DEDICATED_CONTAINER_BASED_GATEWAY(900996, + "Error while updating dedicated container based" + + " gateway", + 500, "Error while updating dedicated container based gateway"), + ERROR_WHILE_RETRIEVING_DEDICATED_CONTAINER_BASED_GATEWAY(900997, "Error while retrieving dedicated container " + + "based gateway", 500, "Error while retrieving dedicated container based gateway"), + INVALID_DEDICATED_CONTAINER_BASED_GATEWAY_LABEL(900998, "Invalid gateway label is provided", 400, + "Invalid gateway label is provided"), + DEDICATED_GATEWAY_DETAILS_NOT_FOUND(900999, "Dedicated gateway details not found for the API", 404, + "Dedicated " + + "gateway details not found for the API"), + + // Comments related Codes + NEED_COMMENT_MODERATOR_PERMISSION(901100, "Comment moderator permission needed", 403, + "This user is not a comment moderator"), + COULD_NOT_UPDATE_COMMENT(901101, "Error has occurred. Could not update the Comment", 500, + "Error has occurred. Could not update the Comment"), + COMMENT_NOT_FOUND(901102, "Comment not found", 404, "Failed to retrieve comment"), + COMMENT_LENGTH_EXCEEDED(901103, "Comment length exceeds max limit", 400, + "Comment length exceeds allowed maximum " + + "number of characters"), + COMMENT_NO_PERMISSION(901104, "Insufficient permission", 403, + "User '%s' doesn't have permission to access the comment with id '%s'"), + COMMENT_CANNOT_RETRIEVE(901105, "Failed to get '%s'", 500, "Failed to get '%s"), + + COMMENT_CANNOT_DELETE(901106, "Failed to delete the Comment", 500, "Failed to delete the Comment of '%s'"), + + NEED_ADMIN_PERMISSION(901100, "Admin permission needed", 403, + "This user is not an admin"), + + // External Stores related codes + EXTERNAL_STORE_ID_NOT_FOUND(901200, "External Store Not Found", 404, + "Error while publishing to external stores. " + + "External Store Not Found"), + EXTERNAL_STORE_CLASS_NOT_FOUND(901201, + ExceptionConstants.EXTERNAL_STORE_ERROR_MSG, 404, + "One or more classes defined in APIConstants.EXTERNAL_API_STORE_CLASS_NAME cannot be found"), + EXTERNAL_STORE_CLASS_NOT_LOADED(901202, + ExceptionConstants.EXTERNAL_STORE_ERROR_MSG, 500, + "One or more classes defined in APIConstants.EXTERNAL_API_STORE_CLASS_NAME cannot be loaded"), + EXTERNAL_STORE_CLASS_NOT_ACCESSIBLE(901203, + ExceptionConstants.EXTERNAL_STORE_ERROR_MSG, 500, + "One or more classes defined in APIConstants.EXTERNAL_API_STORE_CLASS_NAME cannot be accessed"), + ERROR_RETRIEVE_EXTERNAL_STORE_CONFIG(901204, "External Store Config Retrieve Error", 500, + "Error while retrieving External Stores Configuration from registry"), + MALFORMED_XML_IN_EXTERNAL_STORE_CONFIG(901205, "Malformed XML in External Stores Configuration", + 500, "Malformed XML found in the External Stores Configuration resource"), + + // Tenant related + INVALID_TENANT(901300, "Tenant Not Found", 404, "Tenant Not Found"), + CONFIG_NOT_FOUND(901301, "Config not found", 404, "Config not found in tenant-config"), + ERROR_GETTING_CUSTOM_URLS(901302, "Failed to get custom url info", 500, + "Error while retrieving custom url info for tenant : '%s'"), + // Key Manager Related + INVALID_KEY_MANAGERS_VALUE(901350, "Key Managers value need to be an array", 400, + "Invalid Key Managers value"), + INVALID_KEY_MANAGER_TYPE(901400, "Key Manager Type not configured", 400, "Key Manager Type not configured"), + REQUIRED_KEY_MANAGER_CONFIGURATION_MISSING(901401, "Required Key Manager configuration missing", 400, + "Missing " + + "required configuration"), + KEY_MANAGER_ALREADY_EXIST(901402, "Key Manager Already Exists", 409, "Key Manager Already Exists"), + KEY_MANAGER_NOT_REGISTERED(901403, "Key Manager not Registered", 400, "Key Manager not Registered"), + KEY_MANAGER_NOT_FOUND(901411, "Key Manager not Found", 404, "Key Manager not found"), + KEY_MANAGER_NAME_EMPTY(901404, + "Key Manager name cannot be empty", 400, "Key Manager name cannot be empty"), + KEY_MANAGER_NOT_SUPPORT_OAUTH_APP_CREATION(901405, "Key Manager doesn't support generating OAuth applications", + 400, + "Key Manager doesn't support generating OAuth applications"), + KEY_MANAGER_NOT_SUPPORTED_TOKEN_GENERATION(901405, "Key Manager doesn't support token generation", 400, + "Key Manager doesn't support token generation"), + KEY_MANAGER_NOT_ENABLED(901406, "Key Manager is not enabled in the system", 400, + "Key Manager is not enabled in the system"), + KEY_MANAGER_MISSING_REQUIRED_PROPERTIES_IN_APPLICATION(901407, "Required application properties are missing", + 400, + "Required application properties are missing"), + APPLICATION_ALREADY_REGISTERED(901408, "Application already Registered", 409, "Application already Registered"), + KEY_MAPPING_ALREADY_EXIST(901409, "Key Mappings already exists", 409, "Key Mappings already exists"), + TENANT_MISMATCH(901410, "Tenant mismatch", 400, "Tenant mismatch"), + INVALID_APPLICATION_PROPERTIES(901411, "Invalid additional properties", 400, + "Invalid additional properties given for application"), + DECRYPT_CONFIG_ERROR(901412, "Error while decrypting key manager configuration", 500, + "Unable to decrypt the value"), + + // Scope related + SCOPE_NOT_FOUND_FOR_USER(901500, "Scope does not belong to this user", 404, "Scope not found"), + SCOPE_NOT_FOUND(901501, "Scope Not Found", 404, "Scope does not exist"), + USER_NOT_FOUND(901502, "User Not Found", 404, "User does not exist"), + DEFINITION_EXCEPTION(901503, "Internal server error.", 500, + " Error occurred while retrieving swagger definition"), + + // Analytics related codes + ANALYTICS_NOT_ENABLED(901600, "%s not accessible", 404, + "Analytics should be enabled to access %s"), + UNSUPPORTED_ALERT_TYPE(901601, "Unsupported alert type", 400, "Unsupported alert type: '%s' is provided"), + MALFORMED_SP_URL(901602, "Malformed URL", 500, "Error while parsing the stream processor url"), + ERROR_INVOKING_SP_REST_API(901603, "Error while invoking steam processor REST API", 500, "'%s'"), + ALREADY_SUBSCRIBED_FOR_BOT_ALERTS(901604, "Subscription already exists", 409, + "Email: '%s' has already been subscribed for bot detection alerts"), + BOT_DETECTION_SUBSCRIPTION_NOT_FOUND(901605, "Subscription does not exist", 404, + "Bot detection alert subscription with uuid: '%s' uuid does not exist"), + + // Password change related + PASSWORD_CHANGE_DISABLED(901450, "Password change disabled", 400, + "Password change operation is disabled in the system"), + + CURRENT_PASSWORD_INCORRECT(901451, "Current password incorrect", 400, + "The current password entered is incorrect"), + + PASSWORD_PATTERN_INVALID(901452, "Password pattern invalid", 400, + "Password entered is invalid since it doesn't comply with the pattern/policy configured"), + + // Tenant theme related codes + TENANT_THEME_IMPORT_FAILED(901700, "Failed to import tenant theme of tenant %s", 500, + "%s"), + TENANT_THEME_EXPORT_FAILED(901701, "Failed to export tenant theme of tenant %s", 500, + "%s"), + TENANT_THEME_IMPORT_NOT_ALLOWED(901702, "Super Tenant not allowed to import tenant theme", 400, + "Super Tenant %s is not allowed to import a tenant theme"), + TENANT_THEME_NOT_FOUND(901703, "Tenant theme does not exist", 404, + "Tenant theme for tenant: '%s' does not exist"), + + INVALID_API_IDENTIFIER(900851, "Provided API identifier (%s) is invalid", 400, + "Provided API identifier (%s) is invalid"), + API_NAME_OR_VERSION_NOT_NULL(900852, "name or version couldn't be null", 400, + "name or version couldn't be null"), + INVALID_CONFIGURATION_ID(900853, "The configuration id validation failed. Should be " + + "{apiName}#{apiVersion}#{tenantDomain}", 400, + "The configuration id validation failed. Should be " + + "{apiName}#{apiVersion}#{tenantDomain}"), + INVALID_API_NAME(900854, "Invalid API Name", 400, "Invalid API Name"), + ALIAS_CANNOT_BE_EMPTY(900855, "The alias cannot be empty", 400, "The alias cannot be empty"), + + // API import/export related codes + ERROR_READING_META_DATA(900907, "Error while reading meta information from the definition", 400, + "Error while reading meta information from the definition"), + ERROR_READING_PARAMS_FILE(900908, "Error while reading meta information from the params file", 400, + "%s"), + ERROR_FETCHING_DEFINITION_FILE(900909, "Cannot find the definition file of the project", 400, + "Cannot find the yaml/json file with the project definition."), + NO_API_ARTIFACT_FOUND(900910, "No Api artifacts found for given criteria", 404, + "No Api artifacts found for given criteria"), + ERROR_UPLOADING_THUMBNAIL(900914, + "Error while updating thumbnail of API/API Product", 500, + "Error while updating thumbnail of API/API Product: %s-%s"), + APICTL_OPENAPI_PARSE_EXCEPTION( + OPENAPI_PARSE_EXCEPTION.getErrorCode(), OPENAPI_PARSE_EXCEPTION.getErrorMessage(), + OPENAPI_PARSE_EXCEPTION.getHttpStatusCode(), "%s"), + GATEWAY_TYPE_NOT_FOUND(900903, "Gateway type not found", 404, + "Gateway type not found available Gateway types : " + "%s"), + + SERVICE_IMPORT_FAILED_WITHOUT_OVERWRITE(900910, "Service import is failed", 412, + "Cannot update existing services " + + "when overwrite is false"), + MISSING_PROTOCOL_IN_ASYNC_API_DEFINITION(900911, "Missing protocol in Async API Definition", 400, + "Missing protocol in Async API Definition"), + UNSUPPORTED_PROTOCOL_SPECIFIED_IN_ASYNC_API_DEFINITION(900912, "Unsupported protocol specified in Async API " + + "Definition", 400, "Unsupported protocol specified in Async API Definition"), + API_CREATION_NOT_SUPPORTED_FOR_ASYNC_TYPE_APIS(900915, + "API Creation is supported only for WebSocket, WebSub and SSE APIs", 400, + "API Creation is supported only for WebSocket, WebSub and SSE APIs"), + LOGGING_API_NOT_FOUND(901400, "Requested Resource Not Found", 404, "Request API Not Found for context: %s"), + LOGGING_API_INCORRECT_LOG_LEVEL(901401, "Bad Request", 400, + "Log level should be either OFF, BASIC, STANDARD or FULL"), + LOGGING_API_MISSING_DATA(901402, "Missing data", 400, "API context or log level is missing"), + + // Service Catalog related error codes + SERVICE_VERSION_NOT_FOUND(901900, "Cannot find the service version", 404, + "Cannot find a service that matches the given version"), + ERROR_RETRIEVE_SERVICE_INFORMATION(901901, "Error while getting service information", + 500, "Error while executing SQL for getting service information"), + + INVALID_ENDPOINT_CREDENTIALS(902000, "Invalid Endpoint Security credentials", 400, + "Invalid Endpoint Security credentials. %s", false), + INVALID_TENANT_CONFIG(902001, "Invalid tenant-config found", 400, "Invalid tenant-config found with error %s", + false), + + // Operation Policies related error codes + INVALID_OPERATION_POLICY(902005, "%s. Cannot find the selected operation policy", 400, + "Selected operation policy is not found"), + INVALID_OPERATION_POLICY_SPECIFICATION(902006, "Invalid operation policy specification found", 400, + "Invalid operation policy specification. %s", false), + + INVALID_OPERATION_POLICY_PARAMETERS(902007, "Missing required parameters for operation policy specification", + 400, + "Required parameter(s) %s for operation policy specification %s are either missing or empty"), + OPERATION_POLICY_NOT_ALLOWED_IN_THE_APPLIED_FLOW(902008, "Operation policy is not allowed in the applied flow", + 400, + "%s policy is not allowed in response flow"), + MISSING_MANDATORY_POLICY_ATTRIBUTES(902009, "Missing mandatory operation policy attribute", 400, + "Required attributes(s) %s for operation policy specification %s are either missing or empty"), + OPERATION_POLICY_NOT_FOUND(902010, "Operation Policy Not Found", 404, + "Requested operation policy with id '%s' not found"), + OPERATION_POLICY_SPEC_MISMATCH(902011, "Applied policy does not match specification", 400, + "Applied policy for URI template does not match specification"), + + OPERATION_POLICY_ALREADY_EXISTS(903001, "The Operation Policy already exists.", 409, + "An Operation Policy with name '%s' and version '%s' already exists"), + + OPERATION_POLICY_NOT_FOUND_WITH_NAME_AND_VERSION(903004, + "Operation Policy Not Found with given name and version", 404, + "Requested operation policy with name '%s' and version '%s' not found"), + + OPERATION_POLICY_GATEWAY_ERROR(903008, + "Either Synapse or Choreo Gateway Definition files or both should be present", 400, + "Operation Policy cannot be imported due to the missing Gateway files."), + OPERATION_POLICY_USAGE_EXISTS(903009, "Operation policy usages exist", 500, + "Policy usages exist for policy ID '%s'"), + + SUBSCRIPTION_TIER_NOT_ALLOWED(902002, "Subscription Tier is not allowed for user", 403, + "Subscription Tier %s is" + + " not allowed for user %s ", + false), + INVALID_KEY_MANAGER_REQUEST(902003, "Invalid Request sent to Key Manager.", 400, + "Invalid Request sent to Key Manager.Error from Backend : %s", false), + INTERNAL_SERVER_ERROR_FROM_KEY_MANAGER(902004, "Internal Server Error from Key Manager", 500, + "Internal Server Error from Key Manager.Error from Backend : %s", true), + REVISION_ALREADY_DEPLOYED(902005, "Revision deployment state conflicted", 409, + "Revision deployment request conflicted with the current deployment state of the revision %s. Please try again later", + false), + INVALID_API_ID(902006, "Invalid API ID", 404, + "The provided API ID is not found %s", false), + GATEWAY_DOMAIN_MAPPING_RETRIEVE_ERROR(902100, "Error retrieving gateway domain mappings from registry", + 500, "Error while retrieving gateway domain mappings from registry"), + INVALID_GATEWAY_DOMAIN_MAPPING_JSON(902101, "Invalid JSON in gateway tenant domain mappings", + 500, "Invalid JSON found in the gateway tenant domain mappings"), + MALFORMED_GATEWAY_DOMAIN_MAPPING_JSON(902102, "Malformed JSON in gateway tenant domain mappings", + 500, "Malformed JSON found in the gateway tenant domain mappings"), + ERROR_PARSING_TENANT_CONFIG_JSON(902103, "Error occurred while converting to json", + 500, "Error occurred while converting tenantConfig to json"), + FAILED_RETRIEVE_CONFIGURATION_FOR_ORGANIZATION(902150, "Failed to retrieve configuration", + 500, "Failed to retrieve %s Configuration for org: %s"), + INVALID_QUERY(902200, "Failed to retrieve configuration", + 500, "Failed to retrieve %s Configuration for org: %s"), + ERROR_RETRIEVING_CLAIM_VALUES(902300, "Error while retrieving claim values from user store", + 500, "Error while retrieving claim values from user store"), + FAILED_FIND_API_USAGE(902350, "Failed to find API Usage for : %s", 500, + "Failed to find API Usage for : %s"), + BAD_REQUEST_SUBSCRIPTION_ID(902351, "Invalid Subscription ID", 400, + "Invalid Subscription ID"), + FAILED_GET_SUBSCRIPTION_POLICY(902352, "Failed to get subscription policy: %s", 500, + "Failed to retrieve subscription policy: %s data"), + FAILED_GET_API_POLICY(902353, "Failed to get API policy: %s", 500, + "Failed to retrieve API policy: %s data"), + FAILED_GET_APPLICATION_POLICY(902354, "Failed to get application policy: %s", 500, + "Failed to retrieve application policy: %s data"), + + READ_ONLY_ENVIRONMENT_NOT_FOUND(902400, "Configured read only environment not found: %s", + 404, "Configured read only environment not found: %s"), + + // monetization related codes + + INVALID_API_STATE_MONETIZATION(904300, "Invalid API state", 400, "Invalid API state to configure monetization"), + MONETIZATION_STATE_CHANGE_FAILED(904301, "Could not change the monetization state", 500, + "Monetization state change to '%s' failed"), + + MONETIZATION_IMPLEMENTATION_LOADING_FAILED(904302, "Could not load the monetization implementation", 500, + "Failed to load the monetization implementation"), + + // audit related codes + + AUDIT_SEND_FAILED(904200, "Error sending audit data", 500, "Sending audit data failed. Response code: '%s'"), + AUDIT_RETRIEVE_FAILED(904201, "Error retrieving audit data", 500, "Error retrieving audit data"), + + // transport related codes + UNSUPPORTED_TRANSPORT_TYPE(904100, "Unsupported transport type", 400, "Transport type '%s' is not supported"), + + // certificate related error codes + + CERT_NOT_FOUND(904001, "Could not find the certificate", 404, + "'Cannot find the certificate with alias '%s' in the truststore'"), + CERT_BAD_REQUEST(904002, "Bad Request", 400, "'%s"), + GET_CERT_CONTENT(904003, "Error getting the certificate content", 500, "'%s'"), + RETRIEVE_CERT(904004, "Could not retrieve the certificate", 500, "'%s"), + DELETE_CERT(904005, "Could not delete the certificate", 500, + "Error while deleting the certificate for alias '%s'"), + GET_CERT_INFO(904006, "Could not get the certificate information", 500, "'%s"), + UPDATE_CERT(904007, "Could not update the certificate", 500, "'%s'"), + ENCODE_CERT(904008, "Error occurred while encoding the certificate", 500, "'%s"), + INTERNAL_SERVER_CERT(904009, "Internal server error", 500, "'%s'"), + EXPIRED_CERT(904010, "Certificate expired", 400, "'%s'"), + CERT_ALREADY_EXIST(904011, "Certificate alias already exists", 409, + "The alias '%s' already exists in the truststore"), + DECODE_CERT(904012, "Error occurred while decoding the certificate", 500, "'%s'"), + + INVALID_KEY_TYPE(904013, "Bad Request", 400, "Invalid keyType. KeyType should be either PRODUCTION or SANDBOX"), + + ERROR_DELETING_APPLICATION_REGISTRATION(904014, "Can not delete application registration", 400, + "Failed to delete Application registration of : '%s'"), + + ERROR_DELETING_APPLICATION_KEY_MAPPING(904015, "Can not delete application key mapping", 500, + "Failed to delete Application key mapping of : '%s'"), + + ERROR_RETRIEVE_APPLICATION_KEYS(904016, "Failed to retrieve application keys", 500, + "Failed to retrieve application keys for '%s' "); + + private final long errorCode; + private final String errorMessage; + private final int httpStatusCode; + private final String errorDescription; + private boolean stackTrace = false; + + /** + * @param errorCode This is unique error code that pass to upper level. + * @param msg The error message that you need to pass along with + * the error code. + * @param httpErrorCode This HTTP status code which should return from REST + * API layer. If you don't want to pass + * a http status code keep it blank. + * @param errorDescription The error description. + */ + ExceptionCodes(long errorCode, String msg, int httpErrorCode, String errorDescription, boolean stackTrace) { + this.errorCode = errorCode; + this.errorMessage = msg; + this.httpStatusCode = httpErrorCode; + this.errorDescription = errorDescription; + this.stackTrace = stackTrace; + } + + /** + * @param errorCode This is unique error code that pass to upper level. + * @param msg The error message that you need to pass along with + * the error code. + * @param httpErrorCode This HTTP status code which should return from REST + * API layer. If you don't want to pass + * a http status code keep it blank. + * @param errorDescription The error description. + */ + ExceptionCodes(long errorCode, String msg, int httpErrorCode, String errorDescription) { + this.errorCode = errorCode; + this.errorMessage = msg; + this.httpStatusCode = httpErrorCode; + this.errorDescription = errorDescription; + } + + @Override + public long getErrorCode() { + return this.errorCode; + } + + @Override + public String getErrorMessage() { + return this.errorMessage; + } + + @Override + public int getHttpStatusCode() { + return this.httpStatusCode; + } + + @Override + public String getErrorDescription() { + return this.errorDescription; + } + + public boolean printStackTrace() { + + return stackTrace; + } + + /** + * Create an ErrorHandler instance with the provided ExceptionCode filled with + * some dynamic input values + * + * @param errorHandler ErrorHandler or ExceptionCode object + * @param params dynamic values to be filled + * @return ErrorHandler instance with the provided ExceptionCode filled with + * some dynamic input values + */ + public static ErrorHandler from(ErrorHandler errorHandler, String... params) { + String message = errorHandler.getErrorMessage(); + String description = errorHandler.getErrorDescription(); + + if (params != null && params.length > 0) { + int placesToFormatInMessage = message.length() - message.replace("%", "").length(); + int placesToFormatInDescription = description.length() - description.replace("%", "").length(); + + String[] part1 = Arrays.copyOfRange(params, 0, placesToFormatInMessage); + String[] part2 = Arrays.copyOfRange(params, placesToFormatInMessage, + placesToFormatInMessage + placesToFormatInDescription); + + if (placesToFormatInMessage > 0) { + message = String.format(message, part1); + } + if (placesToFormatInDescription > 0) { + description = String.format(description, part2); + } + } + return new ErrorItem(message, description, errorHandler.getErrorCode(), + errorHandler.getHttpStatusCode(), + errorHandler.printStackTrace()); } - return new ErrorItem(message, description, errorHandler.getErrorCode(), errorHandler.getHttpStatusCode(), - errorHandler.printStackTrace()); - } } diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/OASParserUtil.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/OASParserUtil.java index 66eae511c..77e38e5c3 100644 --- a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/OASParserUtil.java +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/OASParserUtil.java @@ -94,7 +94,7 @@ public class OASParserUtil { private static final Log log = LogFactory.getLog(OASParserUtil.class); private static final String OPENAPI_RESOURCE_KEY = "paths"; - private static final String[] UNSUPPORTED_RESOURCE_BLOCKS = new String[]{"servers"}; + private static final String[] UNSUPPORTED_RESOURCE_BLOCKS = new String[] { "servers" }; private static final APIDefinition oas3Parser = new OAS3Parser(); public enum SwaggerVersion { @@ -123,7 +123,6 @@ static class SwaggerUpdateContext { referenceObjectMap.put(HEADERS, new HashSet<>()); } - Paths getPaths() { return paths; } @@ -236,9 +235,11 @@ public static File checkMasterSwagger(File archiveDirectory) throws APIManagemen } /** - * Update the APIDefinitionValidationResponse object with success state using the values given + * Update the APIDefinitionValidationResponse object with success state using + * the values given * - * @param validationResponse APIDefinitionValidationResponse object to be updated + * @param validationResponse APIDefinitionValidationResponse object to be + * updated * @param originalAPIDefinition original API Definition * @param openAPIVersion version of OpenAPI Spec (2.0 or 3.0.0) * @param title title of the OpenAPI Definition @@ -262,7 +263,8 @@ public static void updateValidationResponseAsSuccess(APIDefinitionValidationResp } /** - * Add error item with the provided message to the provided validation response object + * Add error item with the provided message to the provided validation response + * object * * @param validationResponse APIDefinitionValidationResponse object * @param errMessage error message @@ -290,14 +292,14 @@ public static String getSwaggerJsonString(Swagger swaggerObj) throws APIManageme mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); mapper.enable(SerializationFeature.INDENT_OUTPUT); - //this is to ignore "originalRef" in schema objects + // this is to ignore "originalRef" in schema objects mapper.addMixIn(RefModel.class, IgnoreOriginalRefMixin.class); mapper.addMixIn(RefProperty.class, IgnoreOriginalRefMixin.class); mapper.addMixIn(RefPath.class, IgnoreOriginalRefMixin.class); mapper.addMixIn(RefParameter.class, IgnoreOriginalRefMixin.class); mapper.addMixIn(RefResponse.class, IgnoreOriginalRefMixin.class); - //this is to ignore "responseSchema" in response schema objects + // this is to ignore "responseSchema" in response schema objects mapper.addMixIn(Response.class, ResponseSchemaMixin.class); try { return new String(mapper.writeValueAsBytes(swaggerObj)); @@ -309,9 +311,9 @@ public static String getSwaggerJsonString(Swagger swaggerObj) throws APIManageme /** * Sets the scopes to the URL template object using the given list of scopes * - * @param template URL template - * @param resourceScopes list of scopes of the resource - * @param apiScopes set of scopes defined for the API + * @param template URL template + * @param resourceScopes list of scopes of the resource + * @param apiScopes set of scopes defined for the API * @return URL template after setting the scopes */ public static URITemplate setScopesToTemplate(URITemplate template, List resourceScopes, @@ -379,35 +381,39 @@ public static void copyOperationVendorExtensions(Map existingExt .get(APIConstants.SWAGGER_X_AMZN_RESOURCE_TIMEOUT)); } } + /** * Extract the archive file and validates the openAPI definition * - * @param inputByteArray file as input stream - * @param returnContent whether to return the content of the definition in the response DTO + * @param inputByteArray file as input stream + * @param returnContent whether to return the content of the definition in the + * response DTO * @return APIDefinitionValidationResponse * @throws APIManagementException if error occurred while parsing definition */ public static APIDefinitionValidationResponse extractAndValidateOpenAPIArchive(byte[] inputByteArray, - boolean returnContent) throws APIManagementException { + boolean returnContent) throws APIManagementException { String path = System.getProperty(APIConstants.JAVA_IO_TMPDIR) + File.separator + APIConstants.OPENAPI_ARCHIVES_TEMP_FOLDER + File.separator + UUID.randomUUID(); String archivePath = path + File.separator + APIConstants.OPENAPI_ARCHIVE_ZIP_FILE; - String extractedLocation = OASParserUtil.extractUploadedArchive(inputByteArray, APIConstants.OPENAPI_EXTRACTED_DIRECTORY, archivePath, path); + String extractedLocation = OASParserUtil.extractUploadedArchive(inputByteArray, + APIConstants.OPENAPI_EXTRACTED_DIRECTORY, archivePath, path); File[] listOfFiles = new File(extractedLocation).listFiles(); File archiveDirectory = null; if (listOfFiles != null) { if (listOfFiles.length > 1) { throw new APIManagementException("Swagger Definitions should be placed under one root folder."); } - for (File file: listOfFiles) { + for (File file : listOfFiles) { if (file.isDirectory()) { archiveDirectory = file.getAbsoluteFile(); break; } } } - //Verify whether the zipped input is archive or file. - //If it is a single swagger file without remote references it can be imported directly, without zipping. + // Verify whether the zipped input is archive or file. + // If it is a single swagger file without remote references it can be imported + // directly, without zipping. if (archiveDirectory == null) { throw new APIManagementException("Could not find an archive in the given ZIP file."); } @@ -442,8 +448,9 @@ public static APIDefinitionValidationResponse extractAndValidateOpenAPIArchive(b apiDefinitionValidationResponse = OASParserUtil.validateAPIDefinition(openAPIContent, returnContent); return apiDefinitionValidationResponse; } + public static String extractUploadedArchive(byte[] byteArray, String importedDirectoryName, - String apiArchiveLocation, String extractLocation) throws APIManagementException { + String apiArchiveLocation, String extractLocation) throws APIManagementException { String archiveExtractLocation; try (ByteArrayInputStream uploadedApiArchiveInputStream = new ByteArrayInputStream(byteArray)) { @@ -463,6 +470,7 @@ public static String extractUploadedArchive(byte[] byteArray, String importedDir } return archiveExtractLocation; } + /** * Delete a given directory * @@ -485,7 +493,8 @@ public static void deleteDirectory(String path) throws APIManagementException { * @param archiveFilePath path of the zip archive * @param destination extract location * @return name of the extracted zip archive - * @throws APIManagementException if an error occurs while extracting the archive + * @throws APIManagementException if an error occurs while extracting the + * archive */ public static String extractArchive(String archiveFilePath, String destination) throws APIManagementException { @@ -505,7 +514,8 @@ public static String extractArchive(String archiveFilePath, String destination) while ((entry = zis.getNextEntry()) != null) { String currentEntry = entry.getName(); int index = 0; - //This index variable is used to get the extracted folder name; that is root directory + // This index variable is used to get the extracted folder name; that is root + // directory if (index == 0 && currentEntry.indexOf('/') != -1) { archiveName = currentEntry.substring(0, currentEntry.indexOf('/')); --index; @@ -558,6 +568,7 @@ public static String extractArchive(String archiveFilePath, String destination) throw new APIManagementException(errorMsg, e); } } + /** * Creates a zip archive from the given {@link InputStream} inputStream * @@ -575,11 +586,13 @@ public static void createArchiveFromInputStream(InputStream inputStream, String throw new APIManagementException(errorMsg, e); } } + /** * Creates a directory * * @param path path of the directory to create - * @throws APIManagementException if an error occurs while creating the directory + * @throws APIManagementException if an error occurs while creating the + * directory */ public static void createDirectory(String path) throws APIManagementException { try { @@ -591,7 +604,6 @@ public static void createDirectory(String path) throws APIManagementException { } } - /** * Try to validate a give openAPI definition using OpenAPI 3 parser * @@ -605,7 +617,8 @@ public static APIDefinitionValidationResponse validateAPIDefinition(String apiDe String apiDefinitionProcessed = apiDefinition; if (!apiDefinition.trim().startsWith("{")) { try { - JsonNode jsonNode = DeserializationUtils.readYamlTree(apiDefinition, new SwaggerDeserializationResult()); + JsonNode jsonNode = DeserializationUtils.readYamlTree(apiDefinition, + new SwaggerDeserializationResult()); apiDefinitionProcessed = jsonNode.toString(); } catch (IOException e) { throw new APIManagementException("Error while reading API definition yaml", e); @@ -615,14 +628,15 @@ public static APIDefinitionValidationResponse validateAPIDefinition(String apiDe if (apiDefinitionProcessed != null) { apiDefinition = apiDefinitionProcessed; } - APIDefinitionValidationResponse validationResponse = - oas3Parser.validateAPIDefinition(apiDefinition, returnJsonContent); + APIDefinitionValidationResponse validationResponse = oas3Parser.validateAPIDefinition(apiDefinition, + returnJsonContent); if (!validationResponse.isValid()) { -// for (ErrorHandler handler : validationResponse.getErrorItems()) { -// if (ExceptionCodes.INVALID_OAS3_FOUND.getErrorCode() == handler.getErrorCode()) { -// return tryOAS2Validation(apiDefinition, returnJsonContent); -// } -// } + // for (ErrorHandler handler : validationResponse.getErrorItems()) { + // if (ExceptionCodes.INVALID_OAS3_FOUND.getErrorCode() == + // handler.getErrorCode()) { + // return tryOAS2Validation(apiDefinition, returnJsonContent); + // } + // } } return validationResponse; } @@ -671,18 +685,20 @@ public static APIDefinitionValidationResponse validateGraphQLSchema(String apiDe /** * This method removes the unsupported json blocks from the given json string. * - * @param jsonString Open api specification from which unsupported blocks must be removed. - * @return String open api specification without unsupported blocks. Null value if there is no unsupported blocks. + * @param jsonString Open api specification from which unsupported blocks must + * be removed. + * @return String open api specification without unsupported blocks. Null value + * if there is no unsupported blocks. */ public static String removeUnsupportedBlocksFromResources(String jsonString) { JSONObject jsonObject = new JSONObject(jsonString); boolean definitionUpdated = false; if (jsonObject.has(OPENAPI_RESOURCE_KEY)) { JSONObject paths = jsonObject.optJSONObject(OPENAPI_RESOURCE_KEY); - if (paths != null ) { + if (paths != null) { for (String unsupportedBlockKey : UNSUPPORTED_RESOURCE_BLOCKS) { boolean result = removeBlocksRecursivelyFromJsonObject(unsupportedBlockKey, paths, false); - definitionUpdated = definitionUpdated || result; + definitionUpdated = definitionUpdated || result; } } } @@ -700,13 +716,15 @@ public static String removeUnsupportedBlocksFromResources(String jsonString) { return null; } } + /** * This method removes provided key from the json object recursively. * * @param keyToBeRemoved, Key to remove from open api spec. - * @param jsonObject, Open api spec as json object. + * @param jsonObject, Open api spec as json object. */ - private static boolean removeBlocksRecursivelyFromJsonObject(String keyToBeRemoved, JSONObject jsonObject, boolean definitionUpdated) { + private static boolean removeBlocksRecursivelyFromJsonObject(String keyToBeRemoved, JSONObject jsonObject, + boolean definitionUpdated) { if (jsonObject == null) { return definitionUpdated; } @@ -723,4 +741,32 @@ private static boolean removeBlocksRecursivelyFromJsonObject(String keyToBeRemov } return definitionUpdated; } + + /** + * Validate gRPC proto definition + * + * @return Validation response + */ + public static APIDefinitionValidationResponse validateProtoDefinition(String apiDefinition, + boolean returnContent) { + APIDefinitionValidationResponse validationResponse = new APIDefinitionValidationResponse(); + ArrayList errors = new ArrayList<>(); + try { + if (apiDefinition.isBlank()) { + validationResponse.setValid(false); + errors.add(ExceptionCodes.GRPC_PROTO_DEFINTION_CANNOT_BE_NULL); + validationResponse.setErrorItems(errors); + } else { + validationResponse.setValid(true); + validationResponse.setContent(apiDefinition); + } + } catch (Exception e) { + OASParserUtil.addErrorToValidationResponse(validationResponse, e.getMessage()); + validationResponse.setValid(false); + errors.add(new ErrorItem("API Definition Validation Error", "API Definition is invalid", 400, 400)); + validationResponse.setErrorItems(errors); + } + return validationResponse; + + } } diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/ProtoParser.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/ProtoParser.java new file mode 100644 index 000000000..3010905c2 --- /dev/null +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/ProtoParser.java @@ -0,0 +1,336 @@ +package org.wso2.apk.config.definitions; + +import java.io.*; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.wso2.apk.config.api.APIDefinition; +import org.wso2.apk.config.api.APIDefinitionValidationResponse; +import org.wso2.apk.config.api.APIManagementException; +import org.wso2.apk.config.api.ErrorHandler; +import org.wso2.apk.config.api.ErrorItem; +import org.wso2.apk.config.api.ExceptionCodes; +import org.wso2.apk.config.model.API; +import org.wso2.apk.config.model.SwaggerData; +import org.wso2.apk.config.model.URITemplate; + +import io.swagger.v3.core.util.Json; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.parser.OpenAPIV3Parser; +import io.swagger.v3.parser.core.models.SwaggerParseResult; + +import com.google.protobuf.DescriptorProtos; +import com.google.protobuf.TextFormat; +import com.google.protobuf.InvalidProtocolBufferException; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; + +public class ProtoParser extends APIDefinition { + + public ProtoFile protoFile; + + public ProtoParser() { + } + + public void setContent(String content) { + protoFile = parseProtoContent(content); + } + + public String getPackageString(String content) { + Pattern packagePattern = Pattern.compile("package\\s+([\\w\\.]+);"); + Matcher packageMatcher = packagePattern.matcher(content); + if (packageMatcher.find()) { + return packageMatcher.group(1); + } + return null; + } + + public String getVersion(String packageString) { + Pattern versionPattern = Pattern.compile("v\\d+(\\.\\d+)*"); + Matcher versionMatcher = versionPattern.matcher(packageString); + if (versionMatcher.find()) { + return versionMatcher.group(0); + } + System.out.println("No version found"); + return null; + } + + public String getPackageName(String packageString) { + Pattern namePattern = Pattern.compile("v\\d+(\\.\\d+)*\\.(\\w+)"); + Matcher nameMatcher = namePattern.matcher(packageString); + if (nameMatcher.find()) { + return nameMatcher.group(2); + } + System.out.println("No name found"); + return null; + } + + public String getBasePath(String packageString) { + Pattern basePathPattern = Pattern.compile("^(.*?)v\\d"); + + Matcher basePathMatcher = basePathPattern.matcher(packageString); + if (basePathMatcher.find()) { + String basePath = basePathMatcher.group(1); + if (basePath.charAt(basePath.length() - 1) == '.') { + basePath = basePath.substring(0, basePath.length() - 1); + } + return basePath; + } + System.out.println("No base path found"); + return null; + } + + // Method to extract service blocks from a given text + public List extractServiceBlocks(String text) { + // Regular expression pattern to match the service blocks + String patternString = "service\\s+\\w+\\s*\\{[^{}]*(?:\\{[^{}]*\\}[^{}]*)*\\}"; + + // Compile the regular expression + Pattern pattern = Pattern.compile(patternString, Pattern.DOTALL); + Matcher matcher = pattern.matcher(text); + + // Find all matches and append them to the result + List result = new ArrayList<>(); + while (matcher.find()) { + result.add(matcher.group()); + } + return result; + } + + public List extractMethodNames(String serviceBlock) { + // Regular expression pattern to match the method names + String patternString = "(?<=rpc\\s)\\w+"; + + // Compile the regular expression + Pattern pattern = Pattern.compile(patternString); + Matcher matcher = pattern.matcher(serviceBlock); + + // Find all matches and append them to the result + List result = new ArrayList<>(); + while (matcher.find()) { + result.add(matcher.group()); + } + return result; + } + + public String getServiceName(String serviceBlock) { + // Regular expression pattern to match the service name + String patternString = "(?<=service\\s)\\w+"; + + // Compile the regular expression + Pattern pattern = Pattern.compile(patternString); + Matcher matcher = pattern.matcher(serviceBlock); + + // Find the first match and return it + if (matcher.find()) { + return matcher.group(); + } + return null; + } + + public ProtoFile parseProtoContent(String content) { + ProtoFile protoFile = new ProtoFile(); + protoFile.services = new ArrayList<>(); + + List serviceBlocks = extractServiceBlocks(content); + for (String serviceBlock : serviceBlocks) { + Service service = new Service(); + service.name = getServiceName(serviceBlock); + service.methods = new ArrayList<>(); + service.methods.addAll(extractMethodNames(serviceBlock)); + protoFile.services.add(service); + } + + // Extract package name + String packageName = getPackageString(content); + protoFile.packageName = getPackageName(packageName); + protoFile.version = getVersion(packageName); + protoFile.basePath = getBasePath(packageName); + + // System.out.println(protoFile); + + return protoFile; + } + + public List getMethods(Service Service) { + return Service.methods; + } + + public List getServices() { + return this.protoFile.services; + } + + public class ProtoFile { + public String packageName; + public String basePath; + public String version; + public List services; + + @Override + public String toString() { + return "ProtoFile{" + + "packageName='" + packageName + '\'' + + ", basePath='" + basePath + '\'' + + ", version='" + version + '\'' + + ", services=" + services + + '}'; + } + + } + + public class Service { + public String name; + public List methods; + + @Override + public String toString() { + return " Service{" + + "name='" + name + '\'' + + ", methods=" + methods + + '}'; + } + } + + @Override + public Set getURITemplates(String resourceConfigsJSON) throws APIManagementException { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getURITemplates'"); + } + + @Override + public String[] getScopes(String resourceConfigsJSON) throws APIManagementException { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getScopes'"); + } + + @Override + public String generateAPIDefinition(API api) throws APIManagementException { + + SwaggerData swaggerData = new SwaggerData(api); + return generateAPIDefinition(swaggerData); + } + + /** + * This method generates API definition to the given api + * + * @param swaggerData api + * @return API definition in string format + * @throws APIManagementException + */ + private String generateAPIDefinition(SwaggerData swaggerData) { + + OpenAPI openAPI = new OpenAPI(); + + // create path if null + if (openAPI.getPaths() == null) { + openAPI.setPaths(new Paths()); + } + + // Create info object + Info info = new Info(); + info.setTitle(swaggerData.getTitle()); + if (swaggerData.getDescription() != null) { + info.setDescription(swaggerData.getDescription()); + } + + Contact contact = new Contact(); + // Create contact object and map business owner info + if (swaggerData.getContactName() != null) { + contact.setName(swaggerData.getContactName()); + } + if (swaggerData.getContactEmail() != null) { + contact.setEmail(swaggerData.getContactEmail()); + } + if (swaggerData.getContactName() != null || swaggerData.getContactEmail() != null) { + // put contact object to info object + info.setContact(contact); + } + + info.setVersion(swaggerData.getVersion()); + openAPI.setInfo(info); + return Json.pretty(openAPI); + } + + /** + * Validate gRPC proto definition + * + * @return Validation response + */ + public APIDefinitionValidationResponse validateAPIDefinition(String apiDefinition, + boolean returnContent) { + APIDefinitionValidationResponse validationResponse = new APIDefinitionValidationResponse(); + ArrayList errors = new ArrayList<>(); + try { + if (apiDefinition.isBlank()) { + validationResponse.setValid(false); + errors.add(ExceptionCodes.GRPC_PROTO_DEFINTION_CANNOT_BE_NULL); + validationResponse.setErrorItems(errors); + } else { + validationResponse.setValid(true); + validationResponse.setContent(apiDefinition); + } + } catch (Exception e) { + OASParserUtil.addErrorToValidationResponse(validationResponse, e.getMessage()); + validationResponse.setValid(false); + errors.add(new ErrorItem("API Definition Validation Error", "API Definition is invalid", 400, 400)); + validationResponse.setErrorItems(errors); + } + return validationResponse; + + } + + @Override + public API getAPIFromDefinition(String content) throws APIManagementException { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getAPIFromDefinition'"); + } + + @Override + public String processOtherSchemeScopes(String resourceConfigsJSON) throws APIManagementException { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'processOtherSchemeScopes'"); + } + + @Override + public String getType() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getType'"); + } + + @Override + public boolean canHandleDefinition(String definition) { + return true; + } + + @Override + public String generateAPIDefinition(API api, String swagger) throws APIManagementException { + return null; + } + + public boolean validateProtoFile(String protoContent) { + try { + DescriptorProtos.FileDescriptorProto.Builder builder = DescriptorProtos.FileDescriptorProto.newBuilder(); + TextFormat.getParser().merge(protoContent, builder); + // If parsing succeeds, return true + return true; + } catch (IOException e) { + // If an exception occurs, the proto file is invalid + System.err.println("Validation failed: " + e.getMessage()); + return false; + } + } + +} \ No newline at end of file diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/ProtoParserUtil.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/ProtoParserUtil.java new file mode 100644 index 000000000..6c65adc04 --- /dev/null +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/definitions/ProtoParserUtil.java @@ -0,0 +1,70 @@ +package org.wso2.apk.config.definitions; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.apk.config.api.APIDefinition; +import org.wso2.apk.config.api.APIDefinitionValidationResponse; +import org.wso2.apk.config.api.ErrorHandler; +import org.wso2.apk.config.api.ErrorItem; +import org.wso2.apk.config.api.ExceptionCodes; + +public class ProtoParserUtil { + /** + * Provide common functions related to OAS + */ + private static final Log log = LogFactory.getLog(ProtoParserUtil.class); + private static final ProtoParser protoParser = new ProtoParser(); + + /** + * Validate graphQL Schema + * + * @return Validation response + */ + public static APIDefinitionValidationResponse validateGRPCAPIDefinition(String apiDefinition, + boolean returnGRPCContent) { + APIDefinitionValidationResponse validationResponse = new APIDefinitionValidationResponse(); + ArrayList errors = new ArrayList<>(); + + if (apiDefinition.isBlank()) { + validationResponse.setValid(false); + errors.add(ExceptionCodes.GRPC_PROTO_DEFINTION_CANNOT_BE_NULL); + validationResponse.setErrorItems(errors); + } + + try { + boolean validated = protoParser.validateProtoFile(apiDefinition); + validationResponse.setValid(validated); + validationResponse.setContent(apiDefinition); + } catch (Exception e) { + ProtoParserUtil.addErrorToValidationResponse(validationResponse, e.getMessage()); + validationResponse.setValid(false); + errors.add(new ErrorItem("API Definition Validation Error", "API Definition is invalid", 400, 400)); + validationResponse.setErrorItems(errors); + } + + return validationResponse; + } + + /** + * Add error item with the provided message to the provided validation response + * object + * + * @param validationResponse APIDefinitionValidationResponse object + * @param errMessage error message + * @return added ErrorItem object + */ + public static ErrorItem addErrorToValidationResponse(APIDefinitionValidationResponse validationResponse, + String errMessage) { + ErrorItem errorItem = new ErrorItem(); + errorItem.setErrorCode(ExceptionCodes.PROTO_DEFINITION_PARSE_EXCEPTION.getErrorCode()); + errorItem.setMessage(ExceptionCodes.PROTO_DEFINITION_PARSE_EXCEPTION.getErrorMessage()); + errorItem.setDescription(errMessage); + validationResponse.getErrorItems().add(errorItem); + return errorItem; + } + +} diff --git a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/model/API.java b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/model/API.java index d2715d77b..98c810eaa 100644 --- a/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/model/API.java +++ b/runtime/config-deployer-service/java/src/main/java/org/wso2/apk/config/model/API.java @@ -11,6 +11,7 @@ public class API { private String apiSecurity; private String[] scopes; private String graphQLSchema; + private String protoDefinition; private String swaggerDefinition; private String environment; @@ -87,6 +88,14 @@ public void setSwaggerDefinition(String swaggerDefinition) { this.swaggerDefinition = swaggerDefinition; } + public void setProtoDefinition(String protoDefinition) { + this.protoDefinition = protoDefinition; + } + + public String getProtoDefinition() { + return protoDefinition; + } + public String getBasePath() { return basePath;