From 0c5dae902a0add088ce30587c4302dd699dc9170 Mon Sep 17 00:00:00 2001 From: Claus Ibsen Date: Wed, 3 Apr 2024 14:17:21 +0200 Subject: [PATCH] rest-dsl binding part 1 (#13688) CAMEL-20557: Rest DSL to use openapi spec directly --- ...RestOpenApiConsumerRestDslBindingTest.java | 68 ++++++ ...ormHttpRestOpenApiConsumerRestDslTest.java | 4 + .../platform/http/vertx/model/Category.java} | 47 ++-- .../platform/http/vertx/model/Pet.java | 99 ++++++++ .../platform/http/vertx/model/Tag.java | 47 ++++ .../DefaultRestOpenapiProcessorStrategy.java | 25 +- .../rest/openapi/RestOpenApiConsumerPath.java | 10 +- .../rest/openapi/RestOpenApiProcessor.java | 115 ++++++++- .../openapi/RestOpenapiProcessorStrategy.java | 7 +- .../validator/DefaultRequestValidator.java | 19 -- .../reifier/rest/RestBindingReifier.java | 196 ++------------- .../support}/processor/RestBindingAdvice.java | 25 +- .../processor/RestBindingAdviceFactory.java | 223 ++++++++++++++++++ .../processor/RestBindingConfiguration.java | 171 ++++++++++++++ 14 files changed, 821 insertions(+), 235 deletions(-) create mode 100644 components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslBindingTest.java rename components/{camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/validator/RestOpenApiPath.java => camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/model/Category.java} (50%) create mode 100644 components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/model/Pet.java create mode 100644 components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/model/Tag.java rename core/{camel-core-processor/src/main/java/org/apache/camel => camel-support/src/main/java/org/apache/camel/support}/processor/RestBindingAdvice.java (97%) create mode 100644 core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdviceFactory.java create mode 100644 core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingConfiguration.java diff --git a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslBindingTest.java b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslBindingTest.java new file mode 100644 index 0000000000000..ab62516d8c6fb --- /dev/null +++ b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslBindingTest.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.platform.http.vertx; + +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.platform.http.vertx.model.Pet; +import org.apache.camel.model.rest.RestBindingMode; +import org.junit.jupiter.api.Test; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.equalTo; + +public class PlatformHttpRestOpenApiConsumerRestDslBindingTest { + + @Test + public void testRestOpenApi() throws Exception { + final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext(); + + try { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() { + restConfiguration().bindingMode(RestBindingMode.json); + + rest().openApi().specification("openapi-v3.json").missingOperation("ignore"); + + from("direct:getPetById") + .process(e -> { + // build response body as POJO + Pet pet = new Pet(); + pet.setId(e.getMessage().getHeader("petId", long.class)); + pet.setName("tony the tiger"); + pet.setStatus(Pet.Status.AVAILABLE); + e.getMessage().setBody(pet); + }); + } + }); + + context.start(); + + given() + .when() + .get("/api/v3/pet/123") + .then() + .statusCode(200) + .body(equalTo("{\"id\":123,\"name\":\"tony the tiger\",\"status\":\"AVAILABLE\"}")); + + } finally { + context.stop(); + } + } + +} diff --git a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslTest.java b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslTest.java index 0a64d1edb0c69..b81eaff10d43a 100644 --- a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslTest.java +++ b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/PlatformHttpRestOpenApiConsumerRestDslTest.java @@ -27,6 +27,7 @@ import static io.restassured.RestAssured.given; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalToCompressingWhiteSpace; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; public class PlatformHttpRestOpenApiConsumerRestDslTest { @@ -42,6 +43,9 @@ public void configure() { rest().openApi().specification("openapi-v3.json").missingOperation("ignore"); from("direct:getPetById") + .process(e -> { + assertEquals("123", e.getMessage().getHeader("petId")); + }) .setBody().constant("{\"pet\": \"tony the tiger\"}"); } }); diff --git a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/validator/RestOpenApiPath.java b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/model/Category.java similarity index 50% rename from components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/validator/RestOpenApiPath.java rename to components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/model/Category.java index 14efcf67d8d62..7fe7055c73410 100644 --- a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/validator/RestOpenApiPath.java +++ b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/model/Category.java @@ -14,41 +14,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.component.rest.openapi.validator; +package org.apache.camel.component.platform.http.vertx.model; -import io.swagger.v3.oas.models.Operation; -import org.apache.camel.support.RestConsumerContextPathMatcher; +import jakarta.xml.bind.annotation.XmlRootElement; -class RestOpenApiPath implements RestConsumerContextPathMatcher.ConsumerPath { +import com.fasterxml.jackson.annotation.JsonInclude; - private final String verb; - private final String path; - private final Operation consumer; - - public RestOpenApiPath(String verb, String path, Operation consumer) { - this.verb = verb; - this.path = path; - this.consumer = consumer; - } - - @Override - public String getRestrictMethod() { - return verb; +/** + * The structure of this class must adhere to the schema defined in the Pet Store OpenAPI specification JSON / YAML. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@XmlRootElement(name = "Category") +public class Category { + private Long id; + private String name; + + public Long getId() { + return id; } - @Override - public String getConsumerPath() { - return path; + public void setId(Long id) { + this.id = id; } - @Override - public Operation getConsumer() { - return consumer; + public String getName() { + return name; } - @Override - public boolean isMatchOnUriPrefix() { - return false; + public void setName(String name) { + this.name = name; } - } diff --git a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/model/Pet.java b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/model/Pet.java new file mode 100644 index 0000000000000..7a1e27d887a95 --- /dev/null +++ b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/model/Pet.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.platform.http.vertx.model; + +import java.util.List; + +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonInclude; + +/** + * The structure of this class must adhere to the schema defined in the Pet Store OpenAPI specification JSON / YAML. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@XmlRootElement(name = "Pet") +public class Pet { + @XmlElement + private Long id; + private String name; + private Category category; + private List photoUrls; + private List tags; + private Status status; + + public Long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Category getCategory() { + return category; + } + + public void setCategory(Category category) { + this.category = category; + } + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } + + public List getPhotoUrls() { + return photoUrls; + } + + public void setPhotoUrls(List photoUrls) { + this.photoUrls = photoUrls; + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public enum Status { + AVAILABLE, + PENDING, + SOLD; + + @JsonCreator + public static Status fromString(String status) { + return Status.valueOf(status.toUpperCase()); + } + } +} diff --git a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/model/Tag.java b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/model/Tag.java new file mode 100644 index 0000000000000..9571ab8e3c668 --- /dev/null +++ b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/model/Tag.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.platform.http.vertx.model; + +import jakarta.xml.bind.annotation.XmlRootElement; + +import com.fasterxml.jackson.annotation.JsonInclude; + +/** + * The structure of this class must adhere to the schema defined in the Pet Store OpenAPI specification JSON / YAML. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +@XmlRootElement(name = "Tag") +public class Tag { + private Long id; + private String name; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} 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 db3c0eff79275..414a5efb1e375 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 @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import io.swagger.v3.oas.models.OpenAPI; @@ -41,6 +42,7 @@ import org.apache.camel.support.ExchangeHelper; import org.apache.camel.support.PluginHelper; import org.apache.camel.support.cache.DefaultProducerCache; +import org.apache.camel.support.processor.RestBindingAdvice; import org.apache.camel.support.service.ServiceHelper; import org.apache.camel.support.service.ServiceSupport; import org.apache.camel.util.FileUtil; @@ -161,22 +163,39 @@ public boolean processApiSpecification(String specificationUri, Exchange exchang } @Override - public boolean process(Operation operation, String path, Exchange exchange, AsyncCallback callback) { + public boolean process( + Operation operation, String path, + RestBindingAdvice binding, + Exchange exchange, AsyncCallback callback) { + if ("mock".equalsIgnoreCase(missingOperation)) { // check if there is a route Endpoint e = camelContext.hasEndpoint(component + ":" + operation.getOperationId()); if (e == null) { + // no route then try to load mock data as the answer loadMockData(operation, path, exchange); callback.done(true); return true; } } - Endpoint e = camelContext.getEndpoint(component + ":" + operation.getOperationId()); - AsyncProducer p = producerCache.acquireProducer(e); + Map state; + try { + state = binding.before(exchange); + } catch (Exception e) { + exchange.setException(e); + callback.done(true); + return true; + } + + final Endpoint e = camelContext.getEndpoint(component + ":" + operation.getOperationId()); + final AsyncProducer p = producerCache.acquireProducer(e); return p.process(exchange, doneSync -> { try { producerCache.releaseProducer(e, p); + binding.after(exchange, state); + } catch (Exception ex) { + exchange.setException(ex); } finally { callback.done(doneSync); } diff --git a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiConsumerPath.java b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiConsumerPath.java index d94684eb9b2fd..fffa8e508a8b7 100644 --- a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiConsumerPath.java +++ b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiConsumerPath.java @@ -18,17 +18,21 @@ import io.swagger.v3.oas.models.Operation; import org.apache.camel.support.RestConsumerContextPathMatcher; +import org.apache.camel.support.processor.RestBindingAdvice; class RestOpenApiConsumerPath implements RestConsumerContextPathMatcher.ConsumerPath { private final String verb; private final String path; private final Operation consumer; + private final RestBindingAdvice binding; - public RestOpenApiConsumerPath(String verb, String path, Operation consumer) { + public RestOpenApiConsumerPath(String verb, String path, Operation consumer, + RestBindingAdvice binding) { this.verb = verb; this.path = path; this.consumer = consumer; + this.binding = binding; } @Override @@ -50,4 +54,8 @@ public Operation getConsumer() { public boolean isMatchOnUriPrefix() { return false; } + + public RestBindingAdvice getBinding() { + return binding; + } } 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 4e379e3a29269..c3e46f12ce4ea 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 @@ -21,6 +21,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; @@ -33,6 +34,7 @@ import org.apache.camel.CamelContextAware; import org.apache.camel.Exchange; import org.apache.camel.Processor; +import org.apache.camel.http.base.HttpHelper; import org.apache.camel.spi.DataType; import org.apache.camel.spi.DataTypeAware; import org.apache.camel.spi.RestConfiguration; @@ -40,6 +42,9 @@ import org.apache.camel.support.MessageHelper; import org.apache.camel.support.RestConsumerContextPathMatcher; import org.apache.camel.support.processor.DelegateAsyncProcessor; +import org.apache.camel.support.processor.RestBindingAdvice; +import org.apache.camel.support.processor.RestBindingAdviceFactory; +import org.apache.camel.support.processor.RestBindingConfiguration; import org.apache.camel.support.service.ServiceHelper; import org.apache.camel.util.ObjectHelper; import org.slf4j.Logger; @@ -93,19 +98,25 @@ public boolean process(Exchange exchange, AsyncCallback callback) { RestConsumerContextPathMatcher.ConsumerPath m = RestConsumerContextPathMatcher.matchBestPath(verb, path, paths); - if (m != null) { - Operation o = m.getConsumer(); + if (m instanceof RestOpenApiConsumerPath rcp) { + Operation o = rcp.getConsumer(); + // binding mode RestConfiguration config = camelContext.getRestConfiguration(); RestConfiguration.RestBindingMode bindingMode = config.getBindingMode(); + + // map path-parameters from operation to camel headers + HttpHelper.evalPlaceholders(exchange.getMessage().getHeaders(), path, rcp.getConsumerPath()); + // we have found the op to call, but if validation is enabled then we need // to validate the incoming request first if (endpoint.isClientRequestValidation() && isInvalidClientRequest(exchange, callback, o, bindingMode)) { // okay some validation error so return true return true; } + // process the incoming request - return restOpenapiProcessorStrategy.process(o, path, exchange, callback); + return restOpenapiProcessorStrategy.process(o, path, rcp.getBinding(), exchange, callback); } // is it the api-context path @@ -310,17 +321,101 @@ protected void doBuild() throws Exception { super.doBuild(); CamelContextAware.trySetCamelContext(restOpenapiProcessorStrategy, getCamelContext()); + // register all openapi paths for (var e : openAPI.getPaths().entrySet()) { String path = e.getKey(); // path for (var o : e.getValue().readOperationsMap().entrySet()) { String v = o.getKey().name(); // verb - paths.add(new RestOpenApiConsumerPath(v, path, o.getValue())); + // create per operation binding + RestBindingAdvice binding = createRestBinding(o.getValue()); + ServiceHelper.buildService(binding); + paths.add(new RestOpenApiConsumerPath(v, path, o.getValue(), binding)); } } ServiceHelper.buildService(restOpenapiProcessorStrategy); } + private RestBindingAdvice createRestBinding(Operation o) throws Exception { + RestConfiguration config = camelContext.getRestConfiguration(); + RestConfiguration.RestBindingMode mode = config.getBindingMode(); + + RestBindingConfiguration bc = new RestBindingConfiguration(); + bc.setBindingMode(mode.name()); + bc.setEnableCORS(config.isEnableCORS()); + bc.setCorsHeaders(config.getCorsHeaders()); + bc.setClientRequestValidation(config.isClientRequestValidation()); + bc.setEnableNoContentResponse(config.isEnableNoContentResponse()); + bc.setSkipBindingOnErrorCode(config.isSkipBindingOnErrorCode()); + + String consumes = endpoint.getConsumes(); + String produces = endpoint.getProduces(); + // the operation may have specific information what it can consume + if (o.getRequestBody() != null) { + Content c = o.getRequestBody().getContent(); + if (c != null) { + consumes = c.keySet().stream().sorted().collect(Collectors.joining(",")); + } + } + // the operation may have specific information what it can produce + if (o.getResponses() != null) { + for (var a : o.getResponses().values()) { + Content c = a.getContent(); + if (c != null) { + produces = c.keySet().stream().sorted().collect(Collectors.joining(",")); + } + } + } + bc.setConsumes(consumes); + bc.setProduces(produces); + + boolean requiredBody = false; + if (o.getRequestBody() != null) { + requiredBody = Boolean.TRUE == o.getRequestBody().getRequired(); + } + bc.setRequiredBody(requiredBody); + + Set requiredQueryParameters = null; + if (o.getParameters() != null) { + requiredQueryParameters = o.getParameters().stream() + .filter(p -> "query".equals(p.getIn())) + .filter(p -> Boolean.TRUE == p.getRequired()) + .map(Parameter::getName) + .collect(Collectors.toSet()); + } + if (requiredQueryParameters != null) { + bc.setRequiredQueryParameters(requiredQueryParameters); + } + + Set requiredHeaders = null; + if (o.getParameters() != null) { + requiredHeaders = o.getParameters().stream() + .filter(p -> "header".equals(p.getIn())) + .filter(p -> Boolean.TRUE == p.getRequired()) + .map(Parameter::getName) + .collect(Collectors.toSet()); + } + if (requiredHeaders != null) { + bc.setRequiredHeaders(requiredHeaders); + } + // TODO: should type be string/int/long for basic types? + Map defaultQueryValues = null; + if (o.getParameters() != null) { + defaultQueryValues = o.getParameters().stream() + .filter(p -> "query".equals(p.getIn())) + .filter(p -> p.getSchema() != null) + .filter(p -> p.getSchema().getDefault() != null) + .collect(Collectors.toMap(Parameter::getName, p -> p.getSchema().getDefault().toString())); + } + if (defaultQueryValues != null) { + bc.setQueryDefaultValues(defaultQueryValues); + } + + // TODO: type/outType + + return RestBindingAdviceFactory.build(camelContext, bc); + } + @Override protected void doInit() throws Exception { super.doInit(); @@ -337,12 +432,22 @@ protected void doInit() throws Exception { protected void doStart() throws Exception { super.doStart(); ServiceHelper.startService(restOpenapiProcessorStrategy); + for (var p : paths) { + if (p instanceof RestOpenApiConsumerPath rcp) { + ServiceHelper.startService(rcp.getBinding()); + } + } } @Override protected void doStop() throws Exception { super.doStop(); - paths.clear(); ServiceHelper.stopService(restOpenapiProcessorStrategy); + for (var p : paths) { + if (p instanceof RestOpenApiConsumerPath rcp) { + ServiceHelper.stopService(rcp.getBinding()); + } + } + paths.clear(); } } 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 5dab95b0a6f9f..90455836228d8 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 @@ -20,6 +20,7 @@ import io.swagger.v3.oas.models.Operation; import org.apache.camel.AsyncCallback; import org.apache.camel.Exchange; +import org.apache.camel.support.processor.RestBindingAdvice; /** * Strategy for processing the Rest DSL that services an OpenAPI spec. @@ -65,6 +66,7 @@ default void validateOpenApi(OpenAPI openAPI) throws Exception { * * @param operation the rest operation * @param path the context-path + * @param binding binding advice * @param exchange the exchange * @param callback the AsyncCallback will be invoked when the processing of the exchange is completed. If the * exchange is completed synchronously, then the callback is also invoked synchronously. The @@ -72,7 +74,10 @@ default void validateOpenApi(OpenAPI openAPI) throws Exception { * @return (doneSync) true to continue execute synchronously, false to continue being executed * asynchronously */ - boolean process(Operation operation, String path, Exchange exchange, AsyncCallback callback); + boolean process( + Operation operation, String path, + RestBindingAdvice binding, + Exchange exchange, AsyncCallback callback); /** * Strategy for processing the OpenAPI specification (to return the contract) diff --git a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/validator/DefaultRequestValidator.java b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/validator/DefaultRequestValidator.java index 32ac3f42d73ff..7a3474db65553 100644 --- a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/validator/DefaultRequestValidator.java +++ b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/validator/DefaultRequestValidator.java @@ -20,8 +20,6 @@ import java.util.LinkedHashSet; import java.util.Objects; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Collectors; import com.fasterxml.jackson.databind.json.JsonMapper; @@ -30,14 +28,11 @@ import org.apache.camel.Message; import org.apache.camel.support.MessageHelper; import org.apache.camel.util.ObjectHelper; -import org.apache.camel.util.UnsafeUriCharactersEncoder; import static org.apache.camel.support.http.RestUtil.isValidOrAcceptedContentType; public class DefaultRequestValidator implements RequestValidator { - private static final Pattern REST_PATH_PARAM_PATTERN = Pattern.compile("\\{([^}]+)}"); - private RestOpenApiOperation operation; @Override @@ -126,18 +121,4 @@ public Set validate(Exchange exchange, RestOpenApiOperation o) { return Collections.unmodifiableSet(validationErrors); } - protected String resolvePathParams(Exchange exchange, RestOpenApiOperation o) { - String path = o.getUriTemplate(); - Matcher matcher = REST_PATH_PARAM_PATTERN.matcher(path); - String pathToProcess = path; - while (matcher.find()) { - String paramName = matcher.group(1); - String paramValue = exchange.getMessage().getHeader(paramName, String.class); - if (ObjectHelper.isNotEmpty(paramValue)) { - pathToProcess = pathToProcess.replace("{" + paramName + "}", UnsafeUriCharactersEncoder.encode(paramValue)); - } - } - return pathToProcess; - } - } diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/rest/RestBindingReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/rest/RestBindingReifier.java index ccc54d212545b..67f872abec848 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/rest/RestBindingReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/rest/RestBindingReifier.java @@ -16,20 +16,15 @@ */ package org.apache.camel.reifier.rest; -import java.util.HashMap; -import java.util.Map; - import org.apache.camel.Route; import org.apache.camel.model.rest.RestBindingDefinition; import org.apache.camel.model.rest.RestBindingMode; -import org.apache.camel.processor.RestBindingAdvice; import org.apache.camel.reifier.AbstractReifier; -import org.apache.camel.spi.BeanIntrospection; -import org.apache.camel.spi.DataFormat; import org.apache.camel.spi.RestConfiguration; import org.apache.camel.support.CamelContextHelper; -import org.apache.camel.support.PluginHelper; -import org.apache.camel.support.PropertyBindingSupport; +import org.apache.camel.support.processor.RestBindingAdvice; +import org.apache.camel.support.processor.RestBindingAdviceFactory; +import org.apache.camel.support.processor.RestBindingConfiguration; public class RestBindingReifier extends AbstractReifier { @@ -42,193 +37,48 @@ public RestBindingReifier(Route route, RestBindingDefinition definition) { public RestBindingAdvice createRestBindingAdvice() throws Exception { RestConfiguration config = CamelContextHelper.getRestConfiguration(camelContext, definition.getComponent()); + RestBindingConfiguration rbc = new RestBindingConfiguration(); // these options can be overridden per rest verb String mode = config.getBindingMode().name(); if (definition.getBindingMode() != null) { mode = parse(RestBindingMode.class, definition.getBindingMode()).name(); } + rbc.setBindingMode(mode); boolean cors = config.isEnableCORS(); if (definition.getEnableCORS() != null) { cors = parseBoolean(definition.getEnableCORS(), false); } + rbc.setEnableCORS(cors); boolean noContentResponse = config.isEnableNoContentResponse(); if (definition.getEnableNoContentResponse() != null) { noContentResponse = parseBoolean(definition.getEnableNoContentResponse(), false); } + rbc.setEnableNoContentResponse(noContentResponse); boolean skip = config.isSkipBindingOnErrorCode(); if (definition.getSkipBindingOnErrorCode() != null) { skip = parseBoolean(definition.getSkipBindingOnErrorCode(), false); } + rbc.setSkipBindingOnErrorCode(skip); boolean validation = config.isClientRequestValidation(); if (definition.getClientRequestValidation() != null) { validation = parseBoolean(definition.getClientRequestValidation(), false); } - - // cors headers - Map corsHeaders = config.getCorsHeaders(); - - if ("off".equals(mode)) { - // binding mode is off, so create off mode binding processor - return new RestBindingAdvice( - camelContext, null, null, null, null, - parseString(definition.getConsumes()), parseString(definition.getProduces()), mode, skip, validation, cors, - noContentResponse, corsHeaders, - definition.getDefaultValues(), definition.getRequiredBody() != null ? definition.getRequiredBody() : false, - definition.getRequiredQueryParameters(), definition.getRequiredHeaders()); - } - - // setup json data format - DataFormat json = null; - DataFormat outJson = null; - if (mode.contains("json") || "auto".equals(mode)) { - String name = config.getJsonDataFormat(); - if (name != null) { - // must only be a name, not refer to an existing instance - Object instance = lookupByName(name); - if (instance != null) { - throw new IllegalArgumentException( - "JsonDataFormat name: " + name + " must not be an existing bean instance from the registry"); - } - } else { - name = "jackson"; - } - // this will create a new instance as the name was not already - // pre-created - json = camelContext.createDataFormat(name); - outJson = camelContext.createDataFormat(name); - - if (json != null) { - setupJson( - config, - parseString(definition.getType()), definition.getTypeClass(), - parseString(definition.getOutType()), definition.getOutTypeClass(), - json, outJson); - } - } - - // setup xml data format - DataFormat jaxb = null; - DataFormat outJaxb = null; - if (mode.contains("xml") || "auto".equals(mode)) { - String name = config.getXmlDataFormat(); - if (name != null) { - // must only be a name, not refer to an existing instance - Object instance = lookupByName(name); - if (instance != null) { - throw new IllegalArgumentException( - "XmlDataFormat name: " + name + " must not be an existing bean instance from the registry"); - } - } else { - name = "jaxb"; - } - // this will create a new instance as the name was not already - // pre-created - jaxb = camelContext.createDataFormat(name); - outJaxb = camelContext.createDataFormat(name); - - // is xml binding required? - if (mode.contains("xml") && jaxb == null) { - throw new IllegalArgumentException("XML DataFormat " + name + " not found."); - } - - if (jaxb != null) { - // to setup JAXB we need to use camel-jaxb - PluginHelper.getRestBindingJaxbDataFormatFactory(camelContext).setupJaxb( - camelContext, config, - parseString(definition.getType()), definition.getTypeClass(), - parseString(definition.getOutType()), definition.getOutTypeClass(), - jaxb, outJaxb); - } - } - - return new RestBindingAdvice( - camelContext, json, jaxb, outJson, outJaxb, - parseString(definition.getConsumes()), parseString(definition.getProduces()), - mode, skip, validation, cors, noContentResponse, corsHeaders, - definition.getDefaultValues(), definition.getRequiredBody() != null ? definition.getRequiredBody() : false, - definition.getRequiredQueryParameters(), definition.getRequiredHeaders()); - } - - protected void setupJson( - RestConfiguration config, String type, Class typeClass, String outType, Class outTypeClass, DataFormat json, - DataFormat outJson) - throws Exception { - Class clazz = null; - boolean useList = false; - - if (typeClass != null) { - useList = typeClass.isArray(); - clazz = useList ? typeClass.getComponentType() : typeClass; - } else if (type != null) { - useList = type.endsWith("[]"); - String typeName = useList ? type.substring(0, type.length() - 2) : type; - clazz = camelContext.getClassResolver().resolveMandatoryClass(typeName); - } - final BeanIntrospection beanIntrospection = PluginHelper.getBeanIntrospection(camelContext); - if (clazz != null) { - beanIntrospection.setProperty(camelContext, json, - "unmarshalType", clazz); - beanIntrospection.setProperty(camelContext, json, "useList", - useList); - } - - setAdditionalConfiguration(config, json, "json.in."); - - Class outClazz = null; - boolean outUseList = false; - - if (outTypeClass != null) { - outUseList = outTypeClass.isArray(); - outClazz = outUseList ? outTypeClass.getComponentType() : outTypeClass; - } else if (outType != null) { - outUseList = outType.endsWith("[]"); - String typeName = outUseList ? outType.substring(0, outType.length() - 2) : outType; - outClazz = camelContext.getClassResolver().resolveMandatoryClass(typeName); - } - - if (outClazz != null) { - beanIntrospection.setProperty(camelContext, outJson, - "unmarshalType", outClazz); - beanIntrospection.setProperty(camelContext, outJson, "useList", - outUseList); - } - - setAdditionalConfiguration(config, outJson, "json.out."); - } - - private void setAdditionalConfiguration(RestConfiguration config, DataFormat dataFormat, String prefix) { - if (config.getDataFormatProperties() != null && !config.getDataFormatProperties().isEmpty()) { - // must use a copy as otherwise the options gets removed during - // introspection setProperties - Map copy = new HashMap<>(); - - // filter keys on prefix - // - either its a known prefix and must match the prefix parameter - // - or its a common configuration that we should always use - for (Map.Entry entry : config.getDataFormatProperties().entrySet()) { - String key = entry.getKey(); - String copyKey; - boolean known = isKeyKnownPrefix(key); - if (known) { - // remove the prefix from the key to use - copyKey = key.substring(prefix.length()); - } else { - // use the key as is - copyKey = key; - } - if (!known || key.startsWith(prefix)) { - copy.put(copyKey, entry.getValue()); - } - } - - PropertyBindingSupport.build().bind(camelContext, dataFormat, copy); - } - } - - private boolean isKeyKnownPrefix(String key) { - return key.startsWith("json.in.") || key.startsWith("json.out.") || key.startsWith("xml.in.") - || key.startsWith("xml.out."); + rbc.setClientRequestValidation(validation); + rbc.setConsumes(parseString(definition.getConsumes())); + rbc.setProduces(parseString(definition.getProduces())); + rbc.setCorsHeaders(config.getCorsHeaders()); + rbc.setQueryDefaultValues(definition.getDefaultValues()); + rbc.setRequiredBody(definition.getRequiredBody() != null && definition.getRequiredBody()); + rbc.setRequiredQueryParameters(definition.getRequiredQueryParameters()); + rbc.setRequiredHeaders(definition.getRequiredHeaders()); + rbc.setType(parseString(definition.getType())); + rbc.setTypeClass(definition.getTypeClass()); + rbc.setOutType(parseString(definition.getOutType())); + rbc.setOutTypeClass(definition.getOutTypeClass()); + + // use factory to create advice + return RestBindingAdviceFactory.build(camelContext, rbc); } } diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/RestBindingAdvice.java b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdvice.java similarity index 97% rename from core/camel-core-processor/src/main/java/org/apache/camel/processor/RestBindingAdvice.java rename to core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdvice.java index 0efcf7c0dae85..a548f486525a0 100644 --- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/RestBindingAdvice.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdvice.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.processor; +package org.apache.camel.support.processor; import java.util.HashMap; import java.util.Locale; @@ -33,8 +33,8 @@ import org.apache.camel.spi.RestConfiguration; import org.apache.camel.support.ExchangeHelper; import org.apache.camel.support.MessageHelper; -import org.apache.camel.support.processor.MarshalProcessor; -import org.apache.camel.support.processor.UnmarshalProcessor; +import org.apache.camel.support.service.ServiceHelper; +import org.apache.camel.support.service.ServiceSupport; import org.apache.camel.util.ObjectHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,15 +42,16 @@ import static org.apache.camel.support.http.RestUtil.isValidOrAcceptedContentType; /** - * A {@link CamelInternalProcessorAdvice} that binds the REST DSL incoming and outgoing messages from sources of json or - * xml to Java Objects. + * Used for Rest DSL with binding to json/xml for incoming requests and outgoing responses. *

* The binding uses {@link org.apache.camel.spi.DataFormat} for the actual work to transform from xml/json to Java * Objects and reverse again. *

* The rest producer side is implemented in {@link org.apache.camel.component.rest.RestProducerBindingProcessor} + * + * @see RestBindingAdviceFactory */ -public class RestBindingAdvice implements CamelInternalProcessorAdvice> { +public class RestBindingAdvice extends ServiceSupport implements CamelInternalProcessorAdvice> { private static final Logger LOG = LoggerFactory.getLogger(RestBindingAdvice.class); private static final String STATE_KEY_DO_MARSHAL = "doMarshal"; @@ -75,6 +76,9 @@ public class RestBindingAdvice implements CamelInternalProcessorAdvice requiredQueryParameters; private final Set requiredHeaders; + /** + * Use {@link RestBindingAdviceFactory} to create. + */ public RestBindingAdvice(CamelContext camelContext, DataFormat jsonDataFormat, DataFormat xmlDataFormat, DataFormat outJsonDataFormat, DataFormat outXmlDataFormat, String consumes, String produces, String bindingMode, @@ -585,4 +589,13 @@ private void setCORSHeaders(Exchange exchange) { } } + @Override + protected void doStart() throws Exception { + ServiceHelper.startService(jsonUnmarshal, xmlUnmarshal, jsonMarshal, xmlMarshal); + } + + @Override + protected void doStop() throws Exception { + ServiceHelper.stopService(jsonUnmarshal, xmlUnmarshal, jsonMarshal, xmlMarshal); + } } diff --git a/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdviceFactory.java b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdviceFactory.java new file mode 100644 index 0000000000000..173d0722c63c0 --- /dev/null +++ b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingAdviceFactory.java @@ -0,0 +1,223 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.support.processor; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.BeanIntrospection; +import org.apache.camel.spi.DataFormat; +import org.apache.camel.spi.RestConfiguration; +import org.apache.camel.support.EndpointHelper; +import org.apache.camel.support.PluginHelper; +import org.apache.camel.support.PropertyBindingSupport; + +/** + * Factory to create {@link RestBindingAdvice} from the given configuration. + */ +public class RestBindingAdviceFactory { + + /** + * Builds the {@link RestBindingAdvice} from the given configuration + * + * @param camelContext the camel context + * @param bc the binding configuration + * @return the created binding advice + */ + public static RestBindingAdvice build(CamelContext camelContext, RestBindingConfiguration bc) throws Exception { + String mode = bc.getBindingMode(); + + if ("off".equals(mode)) { + // binding mode is off, so create off mode binding processor + return new RestBindingAdvice( + camelContext, null, null, null, null, + bc.getConsumes(), bc.getProduces(), mode, bc.isSkipBindingOnErrorCode(), bc.isClientRequestValidation(), + bc.isEnableCORS(), + bc.isEnableNoContentResponse(), bc.getCorsHeaders(), + bc.getQueryDefaultValues(), bc.isRequiredBody(), bc.getRequiredQueryParameters(), + bc.getRequiredHeaders()); + } + + // setup json data format + RestConfiguration config = camelContext.getRestConfiguration(); + DataFormat json = null; + DataFormat outJson = null; + if (mode.contains("json") || "auto".equals(mode)) { + String name = config.getJsonDataFormat(); + if (name != null) { + // must only be a name, not refer to an existing instance + Object instance = lookupByName(camelContext, name); + if (instance != null) { + throw new IllegalArgumentException( + "JsonDataFormat name: " + name + " must not be an existing bean instance from the registry"); + } + } else { + name = "jackson"; + } + // this will create a new instance as the name was not already + // pre-created + json = camelContext.createDataFormat(name); + outJson = camelContext.createDataFormat(name); + + if (json != null) { + setupJson(camelContext, config, + bc.getType(), bc.getTypeClass(), + bc.getOutType(), bc.getOutTypeClass(), + json, outJson); + } + } + + // setup xml data format + DataFormat jaxb = null; + DataFormat outJaxb = null; + if (mode.contains("xml") || "auto".equals(mode)) { + String name = config.getXmlDataFormat(); + if (name != null) { + // must only be a name, not refer to an existing instance + Object instance = lookupByName(camelContext, name); + if (instance != null) { + throw new IllegalArgumentException( + "XmlDataFormat name: " + name + " must not be an existing bean instance from the registry"); + } + } else { + name = "jaxb"; + } + // this will create a new instance as the name was not already + // pre-created + jaxb = camelContext.createDataFormat(name); + outJaxb = camelContext.createDataFormat(name); + + // is xml binding required? + if (mode.contains("xml") && jaxb == null) { + throw new IllegalArgumentException("XML DataFormat " + name + " not found."); + } + + if (jaxb != null) { + // to setup JAXB we need to use camel-jaxb + PluginHelper.getRestBindingJaxbDataFormatFactory(camelContext).setupJaxb(camelContext, config, + bc.getType(), bc.getTypeClass(), + bc.getOutType(), bc.getOutTypeClass(), + jaxb, outJaxb); + } + } + + return new RestBindingAdvice( + camelContext, json, jaxb, outJson, outJaxb, + bc.getConsumes(), bc.getProduces(), mode, bc.isSkipBindingOnErrorCode(), bc.isClientRequestValidation(), + bc.isEnableCORS(), + bc.isEnableNoContentResponse(), bc.getCorsHeaders(), + bc.getQueryDefaultValues(), bc.isRequiredBody(), bc.getRequiredQueryParameters(), + bc.getRequiredHeaders()); + } + + protected static void setupJson( + CamelContext camelContext, + RestConfiguration config, String type, Class typeClass, String outType, Class outTypeClass, DataFormat json, + DataFormat outJson) + throws Exception { + Class clazz = null; + boolean useList = false; + + if (typeClass != null) { + useList = typeClass.isArray(); + clazz = useList ? typeClass.getComponentType() : typeClass; + } else if (type != null) { + useList = type.endsWith("[]"); + String typeName = useList ? type.substring(0, type.length() - 2) : type; + clazz = camelContext.getClassResolver().resolveMandatoryClass(typeName); + } + final BeanIntrospection beanIntrospection = PluginHelper.getBeanIntrospection(camelContext); + if (clazz != null) { + beanIntrospection.setProperty(camelContext, json, + "unmarshalType", clazz); + beanIntrospection.setProperty(camelContext, json, "useList", + useList); + } + + setAdditionalConfiguration(camelContext, config, json, "json.in."); + + Class outClazz = null; + boolean outUseList = false; + + if (outTypeClass != null) { + outUseList = outTypeClass.isArray(); + outClazz = outUseList ? outTypeClass.getComponentType() : outTypeClass; + } else if (outType != null) { + outUseList = outType.endsWith("[]"); + String typeName = outUseList ? outType.substring(0, outType.length() - 2) : outType; + outClazz = camelContext.getClassResolver().resolveMandatoryClass(typeName); + } + + if (outClazz != null) { + beanIntrospection.setProperty(camelContext, outJson, + "unmarshalType", outClazz); + beanIntrospection.setProperty(camelContext, outJson, "useList", + outUseList); + } + + setAdditionalConfiguration(camelContext, config, outJson, "json.out."); + } + + private static void setAdditionalConfiguration( + CamelContext camelContext, RestConfiguration config, DataFormat dataFormat, String prefix) { + if (config.getDataFormatProperties() != null && !config.getDataFormatProperties().isEmpty()) { + // must use a copy as otherwise the options gets removed during + // introspection setProperties + Map copy = new HashMap<>(); + + // filter keys on prefix + // - either its a known prefix and must match the prefix parameter + // - or its a common configuration that we should always use + for (Map.Entry entry : config.getDataFormatProperties().entrySet()) { + String key = entry.getKey(); + String copyKey; + boolean known = isKeyKnownPrefix(key); + if (known) { + // remove the prefix from the key to use + copyKey = key.substring(prefix.length()); + } else { + // use the key as is + copyKey = key; + } + if (!known || key.startsWith(prefix)) { + copy.put(copyKey, entry.getValue()); + } + } + + PropertyBindingSupport.build().bind(camelContext, dataFormat, copy); + } + } + + private static boolean isKeyKnownPrefix(String key) { + return key.startsWith("json.in.") || key.startsWith("json.out.") || key.startsWith("xml.in.") + || key.startsWith("xml.out."); + } + + private static Object lookupByName(CamelContext camelContext, String name) { + if (name == null) { + return null; + } + + if (EndpointHelper.isReferenceParameter(name)) { + return EndpointHelper.resolveReferenceParameter(camelContext, name, Object.class, false); + } else { + return camelContext.getRegistry().lookupByName(name); + } + } + +} diff --git a/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingConfiguration.java b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingConfiguration.java new file mode 100644 index 0000000000000..383d33a3a04cd --- /dev/null +++ b/core/camel-support/src/main/java/org/apache/camel/support/processor/RestBindingConfiguration.java @@ -0,0 +1,171 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.support.processor; + +import java.util.Map; +import java.util.Set; + +/** + * Configuration for {@link RestBindingAdvice}. + */ +public class RestBindingConfiguration { + + private String consumes; + private String produces; + private String bindingMode; + private boolean skipBindingOnErrorCode; + private boolean clientRequestValidation; + private boolean enableCORS; + private boolean enableNoContentResponse; + private Map corsHeaders; + private Map queryDefaultValues; + private boolean requiredBody; + private Set requiredQueryParameters; + private Set requiredHeaders; + private String type; + private Class typeClass; + private String outType; + private Class outTypeClass; + + public String getConsumes() { + return consumes; + } + + public void setConsumes(String consumes) { + this.consumes = consumes; + } + + public String getProduces() { + return produces; + } + + public void setProduces(String produces) { + this.produces = produces; + } + + public String getBindingMode() { + return bindingMode; + } + + public void setBindingMode(String bindingMode) { + this.bindingMode = bindingMode; + } + + public boolean isSkipBindingOnErrorCode() { + return skipBindingOnErrorCode; + } + + public void setSkipBindingOnErrorCode(boolean skipBindingOnErrorCode) { + this.skipBindingOnErrorCode = skipBindingOnErrorCode; + } + + public boolean isClientRequestValidation() { + return clientRequestValidation; + } + + public void setClientRequestValidation(boolean clientRequestValidation) { + this.clientRequestValidation = clientRequestValidation; + } + + public boolean isEnableCORS() { + return enableCORS; + } + + public void setEnableCORS(boolean enableCORS) { + this.enableCORS = enableCORS; + } + + public boolean isEnableNoContentResponse() { + return enableNoContentResponse; + } + + public void setEnableNoContentResponse(boolean enableNoContentResponse) { + this.enableNoContentResponse = enableNoContentResponse; + } + + public Map getCorsHeaders() { + return corsHeaders; + } + + public void setCorsHeaders(Map corsHeaders) { + this.corsHeaders = corsHeaders; + } + + public Map getQueryDefaultValues() { + return queryDefaultValues; + } + + public void setQueryDefaultValues(Map queryDefaultValues) { + this.queryDefaultValues = queryDefaultValues; + } + + public boolean isRequiredBody() { + return requiredBody; + } + + public void setRequiredBody(boolean requiredBody) { + this.requiredBody = requiredBody; + } + + public Set getRequiredQueryParameters() { + return requiredQueryParameters; + } + + public void setRequiredQueryParameters(Set requiredQueryParameters) { + this.requiredQueryParameters = requiredQueryParameters; + } + + public Set getRequiredHeaders() { + return requiredHeaders; + } + + public void setRequiredHeaders(Set requiredHeaders) { + this.requiredHeaders = requiredHeaders; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Class getTypeClass() { + return typeClass; + } + + public void setTypeClass(Class typeClass) { + this.typeClass = typeClass; + } + + public String getOutType() { + return outType; + } + + public void setOutType(String outType) { + this.outType = outType; + } + + public Class getOutTypeClass() { + return outTypeClass; + } + + public void setOutTypeClass(Class outTypeClass) { + this.outTypeClass = outTypeClass; + } +}