This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch vc4
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 14f1b58af44e8a97fea86aa668129eed8ee143b5
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Thu Jun 6 07:06:09 2024 +0200

    CAMEL-20832: camel-openapi-validator to use Atlassian openapi validator for 
rest-dsl
---
 .../camel/catalog/components/rest-openapi.json     |  2 +-
 .../client/OpenApiRestClientRequestValidator.java  | 41 +++++++++++++++++++++-
 .../camel/component/rest/openapi/rest-openapi.json |  2 +-
 .../DefaultRestOpenapiProcessorStrategy.java       |  3 +-
 .../rest/openapi/RestOpenApiEndpoint.java          |  1 +
 .../rest/openapi/RestOpenApiProcessor.java         |  2 +-
 .../rest/openapi/RestOpenapiProcessorStrategy.java |  3 +-
 .../org/apache/camel/ExchangeConstantProvider.java |  3 +-
 .../src/main/java/org/apache/camel/Exchange.java   |  1 +
 .../camel/support/processor/RestBindingAdvice.java |  2 ++
 .../dsl/RestOpenApiEndpointBuilderFactory.java     |  8 +++--
 .../camel/kotlin/components/RestOpenapiUriDsl.kt   |  3 +-
 12 files changed, 60 insertions(+), 11 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-openapi.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-openapi.json
index 32f5b67f650..f978b2d54e9 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-openapi.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-openapi.json
@@ -48,7 +48,7 @@
     "operationId": { "index": 1, "kind": "path", "displayName": "Operation 
Id", "group": "producer", "label": "producer", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "description": "ID of the operation from the OpenApi 
specification. This is required when using producer" },
     "apiContextPath": { "index": 2, "kind": "parameter", "displayName": "Api 
Context Path", "group": "consumer", "label": "consumer", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "description": "Sets the context-path to 
use for servicing the OpenAPI specification" },
     "clientRequestValidation": { "index": 3, "kind": "parameter", 
"displayName": "Client Request Validation", "group": "consumer", "label": 
"consumer", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 
false, "description": "Whether to enable validation of the client request to 
check if the incoming request is valid according to the OpenAPI specification" 
},
-    "consumes": { "index": 4, "kind": "parameter", "displayName": "Consumes", 
"group": "consumer", "label": "consumer", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "description": "What payload type this component capable of 
consuming. Could be one type, like application\/json or multiple types as 
application\/json, application\/xml; q=0.5 according to the RFC7231. This 
equates to the value of Accept HTTP h [...]
+    "consumes": { "index": 4, "kind": "parameter", "displayName": "Consumes", 
"group": "consumer", "label": "consumer", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "description": "What payload type this component capable of 
consuming. Could be one type, like application\/json or multiple types as 
application\/json, application\/xml; q=0.5 according to the RFC7231. This 
equates or multiple types as applicat [...]
     "missingOperation": { "index": 5, "kind": "parameter", "displayName": 
"Missing Operation", "group": "consumer", "label": "consumer", "required": 
false, "type": "string", "javaType": "java.lang.String", "enum": [ "fail", 
"ignore", "mock" ], "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": "fail", "description": "Whether the consumer should fail,ignore 
or return a mock response for OpenAPI operations that are not mapped to a 
corresponding route." },
     "bridgeErrorHandler": { "index": 6, "kind": "parameter", "displayName": 
"Bridge Error Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Allows for bridging the consumer to the 
Camel routing Error Handler, which mean any exceptions (if possible) occurred 
while the Camel consumer is trying to pickup incoming  [...]
     "consumerComponentName": { "index": 7, "kind": "parameter", "displayName": 
"Consumer Component Name", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "Name of the Camel component that will service the requests. The 
component must be present in Camel registry and it must implement 
RestOpenApiConsumerFactory service provider interfa [...]
diff --git 
a/components/camel-openapi-validator/src/main/java/org/apache/camel/component/rest/openapi/validator/client/OpenApiRestClientRequestValidator.java
 
b/components/camel-openapi-validator/src/main/java/org/apache/camel/component/rest/openapi/validator/client/OpenApiRestClientRequestValidator.java
index 7c8c37fff76..989478c01e0 100644
--- 
a/components/camel-openapi-validator/src/main/java/org/apache/camel/component/rest/openapi/validator/client/OpenApiRestClientRequestValidator.java
+++ 
b/components/camel-openapi-validator/src/main/java/org/apache/camel/component/rest/openapi/validator/client/OpenApiRestClientRequestValidator.java
@@ -16,15 +16,54 @@
  */
 package org.apache.camel.component.rest.openapi.validator.client;
 
+import com.atlassian.oai.validator.OpenApiInteractionValidator;
+import com.atlassian.oai.validator.model.SimpleRequest;
+import com.atlassian.oai.validator.report.ValidationReport;
+import io.swagger.v3.oas.models.OpenAPI;
 import org.apache.camel.Exchange;
 import org.apache.camel.spi.RestClientRequestValidator;
 import org.apache.camel.spi.annotations.JdkService;
+import org.apache.camel.support.ExchangeHelper;
+import org.apache.camel.support.MessageHelper;
 
 @JdkService(RestClientRequestValidator.FACTORY)
-public class OpenApiRestClientRequestValidator implements 
RestClientRequestValidator{
+public class OpenApiRestClientRequestValidator implements 
RestClientRequestValidator {
+
+    // TODO: use default validator if no OpenAPI
 
     @Override
     public ValidationError validate(Exchange exchange, ValidationContext 
validationContent) {
+        OpenAPI openAPI = exchange.getProperty(Exchange.REST_OPENAPI, 
OpenAPI.class);
+        if (openAPI == null) {
+            return null;
+        }
+
+        String method = exchange.getMessage().getHeader(Exchange.HTTP_METHOD, 
String.class);
+        String path = exchange.getMessage().getHeader(Exchange.HTTP_PATH, 
String.class);
+        String accept = exchange.getMessage().getHeader("Accept", 
String.class);
+        String contentType = ExchangeHelper.getContentType(exchange);
+        String body = MessageHelper.extractBodyAsString(exchange.getIn());
+
+        SimpleRequest.Builder builder = new SimpleRequest.Builder(method, 
path, false);
+        if (contentType != null) {
+            builder.withContentType(contentType);
+        }
+        if (accept != null) {
+            builder.withAccept(accept);
+        }
+        if (body != null) {
+            builder.withBody(body);
+        }
+
+        
Thread.currentThread().setContextClassLoader(exchange.getContext().getApplicationContextClassLoader());
+        OpenApiInteractionValidator validator = 
OpenApiInteractionValidator.createFor(openAPI).build();
+        ValidationReport report = validator.validateRequest(builder.build());
+        if (report.hasErrors()) {
+            for (var m : report.getMessages()) {
+                System.out.println(m);
+            }
+        }
         return null;
     }
+
 }
diff --git 
a/components/camel-rest-openapi/src/generated/resources/META-INF/org/apache/camel/component/rest/openapi/rest-openapi.json
 
b/components/camel-rest-openapi/src/generated/resources/META-INF/org/apache/camel/component/rest/openapi/rest-openapi.json
index 32f5b67f650..f978b2d54e9 100644
--- 
a/components/camel-rest-openapi/src/generated/resources/META-INF/org/apache/camel/component/rest/openapi/rest-openapi.json
+++ 
b/components/camel-rest-openapi/src/generated/resources/META-INF/org/apache/camel/component/rest/openapi/rest-openapi.json
@@ -48,7 +48,7 @@
     "operationId": { "index": 1, "kind": "path", "displayName": "Operation 
Id", "group": "producer", "label": "producer", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "description": "ID of the operation from the OpenApi 
specification. This is required when using producer" },
     "apiContextPath": { "index": 2, "kind": "parameter", "displayName": "Api 
Context Path", "group": "consumer", "label": "consumer", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "description": "Sets the context-path to 
use for servicing the OpenAPI specification" },
     "clientRequestValidation": { "index": 3, "kind": "parameter", 
"displayName": "Client Request Validation", "group": "consumer", "label": 
"consumer", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 
false, "description": "Whether to enable validation of the client request to 
check if the incoming request is valid according to the OpenAPI specification" 
},
-    "consumes": { "index": 4, "kind": "parameter", "displayName": "Consumes", 
"group": "consumer", "label": "consumer", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "description": "What payload type this component capable of 
consuming. Could be one type, like application\/json or multiple types as 
application\/json, application\/xml; q=0.5 according to the RFC7231. This 
equates to the value of Accept HTTP h [...]
+    "consumes": { "index": 4, "kind": "parameter", "displayName": "Consumes", 
"group": "consumer", "label": "consumer", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "description": "What payload type this component capable of 
consuming. Could be one type, like application\/json or multiple types as 
application\/json, application\/xml; q=0.5 according to the RFC7231. This 
equates or multiple types as applicat [...]
     "missingOperation": { "index": 5, "kind": "parameter", "displayName": 
"Missing Operation", "group": "consumer", "label": "consumer", "required": 
false, "type": "string", "javaType": "java.lang.String", "enum": [ "fail", 
"ignore", "mock" ], "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": "fail", "description": "Whether the consumer should fail,ignore 
or return a mock response for OpenAPI operations that are not mapped to a 
corresponding route." },
     "bridgeErrorHandler": { "index": 6, "kind": "parameter", "displayName": 
"Bridge Error Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Allows for bridging the consumer to the 
Camel routing Error Handler, which mean any exceptions (if possible) occurred 
while the Camel consumer is trying to pickup incoming  [...]
     "consumerComponentName": { "index": 7, "kind": "parameter", "displayName": 
"Consumer Component Name", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "Name of the Camel component that will service the requests. The 
component must be present in Camel registry and it must implement 
RestOpenApiConsumerFactory service provider interfa [...]
diff --git 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java
 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java
index e0bff0f9672..d023b7b43b8 100644
--- 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java
+++ 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/DefaultRestOpenapiProcessorStrategy.java
@@ -169,7 +169,7 @@ public class DefaultRestOpenapiProcessorStrategy extends 
ServiceSupport
     }
 
     @Override
-    public boolean process(
+    public boolean process(OpenAPI openAPI,
             Operation operation, String verb, String path,
             RestBindingAdvice binding,
             Exchange exchange, AsyncCallback callback) {
@@ -190,6 +190,7 @@ public class DefaultRestOpenapiProcessorStrategy extends 
ServiceSupport
         // there is a route so process
         Map<String, Object> state;
         try {
+            exchange.setProperty(Exchange.REST_OPENAPI, openAPI);
             state = binding.before(exchange);
         } catch (Exception e) {
             exchange.setException(e);
diff --git 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
index dee36ced6a1..f7780434237 100644
--- 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
+++ 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
@@ -128,6 +128,7 @@ public final class RestOpenApiEndpoint extends 
DefaultEndpoint {
              label = "producer")
     private String operationId;
     @UriParam(description = "What payload type this component capable of 
consuming. Could be one type, like `application/json`"
+                            + " or multiple types as `application/json, 
application/xml; q=0.5` according to the RFC7231. This equates"
                             + " or multiple types as `application/json, 
application/xml; q=0.5` according to the RFC7231. This equates"
                             + " to the value of `Accept` HTTP header. If set 
overrides any value found in the OpenApi specification and."
                             + " in the component configuration",
diff --git 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java
 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java
index 8304028d1eb..d9873587b2f 100644
--- 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java
+++ 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiProcessor.java
@@ -123,7 +123,7 @@ public class RestOpenApiProcessor extends 
DelegateAsyncProcessor implements Came
             HttpHelper.evalPlaceholders(exchange.getMessage().getHeaders(), 
uri, rcp.getConsumerPath());
 
             // process the incoming request
-            return restOpenapiProcessorStrategy.process(o, verb, uri, 
rcp.getBinding(), exchange, callback);
+            return restOpenapiProcessorStrategy.process(openAPI, o, verb, uri, 
rcp.getBinding(), exchange, callback);
         }
 
         // is it the api-context path
diff --git 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategy.java
 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategy.java
index 52c71a7c671..d93d0a79557 100644
--- 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategy.java
+++ 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenapiProcessorStrategy.java
@@ -66,6 +66,7 @@ public interface RestOpenapiProcessorStrategy {
     /**
      * Strategy for processing the Rest DSL operation
      *
+     * @param  openAPI   the openapi specification
      * @param  operation the rest operation
      * @param  verb      the HTTP verb (GET, POST etc.)
      * @param  path      the context-path
@@ -77,7 +78,7 @@ public interface RestOpenapiProcessorStrategy {
      * @return           (doneSync) true to continue execute synchronously, 
false to continue being executed
      *                   asynchronously
      */
-    boolean process(
+    boolean process(OpenAPI openAPI,
             Operation operation, String verb, String path,
             RestBindingAdvice binding,
             Exchange exchange, AsyncCallback callback);
diff --git 
a/core/camel-api/src/generated/java/org/apache/camel/ExchangeConstantProvider.java
 
b/core/camel-api/src/generated/java/org/apache/camel/ExchangeConstantProvider.java
index a97e9e8fc89..1887de93403 100644
--- 
a/core/camel-api/src/generated/java/org/apache/camel/ExchangeConstantProvider.java
+++ 
b/core/camel-api/src/generated/java/org/apache/camel/ExchangeConstantProvider.java
@@ -13,7 +13,7 @@ public class ExchangeConstantProvider {
 
     private static final Map<String, String> MAP;
     static {
-        Map<String, String> map = new HashMap<>(155);
+        Map<String, String> map = new HashMap<>(156);
         map.put("ACCEPT_CONTENT_TYPE", "CamelAcceptContentType");
         map.put("AGGREGATED_COLLECTION_GUARD", 
"CamelAggregatedCollectionGuard");
         map.put("AGGREGATED_COMPLETED_BY", "CamelAggregatedCompletedBy");
@@ -132,6 +132,7 @@ public class ExchangeConstantProvider {
         map.put("REDELIVERY_MAX_COUNTER", "CamelRedeliveryMaxCounter");
         map.put("REST_HTTP_QUERY", "CamelRestHttpQuery");
         map.put("REST_HTTP_URI", "CamelRestHttpUri");
+        map.put("REST_OPENAPI", "CamelRestOpenAPI");
         map.put("REUSE_SCRIPT_ENGINE", "CamelReuseScripteEngine");
         map.put("ROLLBACK_ONLY", "CamelRollbackOnly");
         map.put("ROLLBACK_ONLY_LAST", "CamelRollbackOnlyLast");
diff --git a/core/camel-api/src/main/java/org/apache/camel/Exchange.java 
b/core/camel-api/src/main/java/org/apache/camel/Exchange.java
index 13cda74cb76..82d256b5f2d 100644
--- a/core/camel-api/src/main/java/org/apache/camel/Exchange.java
+++ b/core/camel-api/src/main/java/org/apache/camel/Exchange.java
@@ -260,6 +260,7 @@ public interface Exchange extends VariableAware {
     String REDELIVERY_DELAY = "CamelRedeliveryDelay";
     String REST_HTTP_URI = "CamelRestHttpUri";
     String REST_HTTP_QUERY = "CamelRestHttpQuery";
+    String REST_OPENAPI = "CamelRestOpenAPI";
     @Deprecated(since = "3.1.0")
     String ROLLBACK_ONLY = "CamelRollbackOnly";
     @Deprecated(since = "3.1.0")
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdvice.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdvice.java
index 32b5bc27775..93e76403335 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdvice.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdvice.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.support.processor;
 
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RestOpenApiEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RestOpenApiEndpointBuilderFactory.java
index 44adbafbbed..70173163f09 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RestOpenApiEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RestOpenApiEndpointBuilderFactory.java
@@ -92,9 +92,11 @@ public interface RestOpenApiEndpointBuilderFactory {
         /**
          * What payload type this component capable of consuming. Could be one
          * type, like application/json or multiple types as application/json,
-         * application/xml; q=0.5 according to the RFC7231. This equates to the
-         * value of Accept HTTP header. If set overrides any value found in the
-         * OpenApi specification and. in the component configuration.
+         * application/xml; q=0.5 according to the RFC7231. This equates or
+         * multiple types as application/json, application/xml; q=0.5 according
+         * to the RFC7231. This equates to the value of Accept HTTP header. If
+         * set overrides any value found in the OpenApi specification and. in
+         * the component configuration.
          * 
          * The option is a: <code>java.lang.String</code> type.
          * 
diff --git 
a/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/RestOpenapiUriDsl.kt
 
b/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/RestOpenapiUriDsl.kt
index 8aa50678a4a..6d209ef1058 100644
--- 
a/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/RestOpenapiUriDsl.kt
+++ 
b/dsl/camel-kotlin-api/src/generated/kotlin/org/apache/camel/kotlin/components/RestOpenapiUriDsl.kt
@@ -95,7 +95,8 @@ public class RestOpenapiUriDsl(
   /**
    * What payload type this component capable of consuming. Could be one type, 
like application/json
    * or multiple types as application/json, application/xml; q=0.5 according 
to the RFC7231. This
-   * equates to the value of Accept HTTP header. If set overrides any value 
found in the OpenApi
+   * equates or multiple types as application/json, application/xml; q=0.5 
according to the RFC7231.
+   * This equates to the value of Accept HTTP header. If set overrides any 
value found in the OpenApi
    * specification and. in the component configuration
    */
   public fun consumes(consumes: String) {

Reply via email to