[1/2] camel git commit: CAMEL-10932 REST Swagger component

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

[1/2] camel git commit: CAMEL-10932 REST Swagger component

zregvart
Repository: camel
Updated Branches:
  refs/heads/master ae2ae6f32 -> 5b209152b


http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointTest.java
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointTest.java b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointTest.java
new file mode 100644
index 0000000..31b74ed
--- /dev/null
+++ b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointTest.java
@@ -0,0 +1,336 @@
+/**
+ * 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.rest.swagger;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collections;
+
+import io.swagger.models.Operation;
+import io.swagger.models.Scheme;
+import io.swagger.models.Swagger;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Producer;
+import org.apache.camel.impl.DefaultClassResolver;
+import org.apache.camel.spi.RestConfiguration;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class RestSwaggerEndpointTest {
+
+    URI componentJsonUri = URI.create("component.json");
+
+    URI endpointUri = URI.create("endpoint.json");
+
+    @Test(expected = IllegalArgumentException.class)
+    public void shouldComplainForUnknownOperations() throws Exception {
+        final CamelContext camelContext = mock(CamelContext.class);
+        when(camelContext.getClassResolver()).thenReturn(new DefaultClassResolver());
+
+        final RestSwaggerComponent component = new RestSwaggerComponent(camelContext);
+
+        final RestSwaggerEndpoint endpoint = new RestSwaggerEndpoint("rest-swagger:unknown", "unknown", component);
+
+        endpoint.createProducer();
+    }
+
+    @Test
+    public void shouldCreateProducers() throws Exception {
+        final CamelContext camelContext = mock(CamelContext.class);
+        when(camelContext.getClassResolver()).thenReturn(new DefaultClassResolver());
+        final Endpoint endpointDelegate = mock(Endpoint.class);
+        when(camelContext.getEndpoint("rest:GET:/v2:/pet/{petId}")).thenReturn(endpointDelegate);
+        final Producer delegateProducer = mock(Producer.class);
+        when(endpointDelegate.createProducer()).thenReturn(delegateProducer);
+
+        final RestSwaggerComponent component = new RestSwaggerComponent(camelContext);
+        component.setHost("http://petstore.swagger.io");
+
+        final RestSwaggerEndpoint endpoint = new RestSwaggerEndpoint("rest-swagger:getPetById", "getPetById",
+            component);
+
+        final Producer producer = endpoint.createProducer();
+
+        assertThat(producer).isSameAs(delegateProducer);
+    }
+
+    @Test
+    public void shouldDetermineBasePath() {
+        final RestConfiguration restConfiguration = new RestConfiguration();
+
+        final CamelContext camelContext = mock(CamelContext.class);
+        when(camelContext.getRestConfiguration("rest-swagger", true)).thenReturn(restConfiguration);
+
+        final Swagger swagger = new Swagger();
+
+        final RestSwaggerComponent component = new RestSwaggerComponent();
+        component.setCamelContext(camelContext);
+        final RestSwaggerEndpoint endpoint = new RestSwaggerEndpoint("rest-swagger:getPetById", "getPetById",
+            component);
+
+        assertThat(endpoint.determineBasePath(swagger))
+            .as("When no base path is specified on component, endpoint or rest configuration it should default to `/`")
+            .isEqualTo("/");
+
+        restConfiguration.setContextPath("/rest");
+        assertThat(endpoint.determineBasePath(swagger))
+            .as("When base path is specified in REST configuration and not specified in component the base path should be from the REST configuration")
+            .isEqualTo("/rest");
+
+        swagger.basePath("/specification");
+        assertThat(endpoint.determineBasePath(swagger))
+            .as("When base path is specified in the specification it should take precedence the one specified in the REST configuration")
+            .isEqualTo("/specification");
+
+        component.setBasePath("/component");
+        assertThat(endpoint.determineBasePath(swagger))
+            .as("When base path is specified on the component it should take precedence over Swagger specification and REST configuration")
+            .isEqualTo("/component");
+
+        endpoint.setBasePath("/endpoint");
+        assertThat(endpoint.determineBasePath(swagger))
+            .as("When base path is specified on the endpoint it should take precedence over any other")
+            .isEqualTo("/endpoint");
+    }
+
+    @Test
+    public void shouldDetermineEndpointParameters() {
+        final CamelContext camelContext = mock(CamelContext.class);
+
+        final RestSwaggerComponent component = new RestSwaggerComponent();
+        component.setCamelContext(camelContext);
+
+        final RestSwaggerEndpoint endpoint = new RestSwaggerEndpoint("uri", "remaining", component);
+        endpoint.setHost("http://petstore.swagger.io");
+
+        final Swagger swagger = new Swagger();
+        final Operation operation = new Operation();
+
+        assertThat(endpoint.determineEndpointParameters(swagger, operation))
+            .containsOnly(entry("host", "http://petstore.swagger.io"));
+
+        component.setComponentName("xyz");
+        assertThat(endpoint.determineEndpointParameters(swagger, operation))
+            .containsOnly(entry("host", "http://petstore.swagger.io"), entry("componentName", "xyz"));
+
+        swagger.consumes("application/json").produces("application/xml");
+        assertThat(endpoint.determineEndpointParameters(swagger, operation)).containsOnly(
+            entry("host", "http://petstore.swagger.io"), entry("componentName", "xyz"),
+            entry("consumes", "application/xml"), entry("produces", "application/json"));
+
+        component.setProduces("application/json");
+        component.setConsumes("application/atom+xml");
+        assertThat(endpoint.determineEndpointParameters(swagger, operation)).containsOnly(
+            entry("host", "http://petstore.swagger.io"), entry("componentName", "xyz"),
+            entry("consumes", "application/atom+xml"), entry("produces", "application/json"));
+
+        endpoint.setProduces("application/atom+xml");
+        endpoint.setConsumes("application/json");
+        assertThat(endpoint.determineEndpointParameters(swagger, operation)).containsOnly(
+            entry("host", "http://petstore.swagger.io"), entry("componentName", "xyz"),
+            entry("consumes", "application/json"), entry("produces", "application/atom+xml"));
+
+        endpoint.setComponentName("zyx");
+        assertThat(endpoint.determineEndpointParameters(swagger, operation)).containsOnly(
+            entry("host", "http://petstore.swagger.io"), entry("componentName", "zyx"),
+            entry("consumes", "application/json"), entry("produces", "application/atom+xml"));
+    }
+
+    @Test
+    public void shouldDetermineHostFromRestConfiguration() {
+        assertThat(RestSwaggerEndpoint.hostFrom(null)).isNull();
+
+        final RestConfiguration configuration = new RestConfiguration();
+        assertThat(RestSwaggerEndpoint.hostFrom(configuration)).isNull();
+
+        configuration.setScheme("ftp");
+        assertThat(RestSwaggerEndpoint.hostFrom(configuration)).isNull();
+
+        configuration.setScheme("http");
+        assertThat(RestSwaggerEndpoint.hostFrom(configuration)).isNull();
+
+        configuration.setHost("petstore.swagger.io");
+        assertThat(RestSwaggerEndpoint.hostFrom(configuration)).isEqualTo("http://petstore.swagger.io");
+
+        configuration.setPort(80);
+        assertThat(RestSwaggerEndpoint.hostFrom(configuration)).isEqualTo("http://petstore.swagger.io");
+
+        configuration.setPort(8080);
+        assertThat(RestSwaggerEndpoint.hostFrom(configuration)).isEqualTo("http://petstore.swagger.io:8080");
+
+        configuration.setScheme("https");
+        configuration.setPort(80);
+        assertThat(RestSwaggerEndpoint.hostFrom(configuration)).isEqualTo("https://petstore.swagger.io:80");
+
+        configuration.setPort(443);
+        assertThat(RestSwaggerEndpoint.hostFrom(configuration)).isEqualTo("https://petstore.swagger.io");
+    }
+
+    @Test
+    public void shouldDetermineHostFromSpecification() {
+        final RestSwaggerComponent component = new RestSwaggerComponent();
+
+        final RestSwaggerEndpoint endpoint = new RestSwaggerEndpoint("rest-swagger:http://some-uri#getPetById",
+            "http://some-uri#getPetById", component);
+
+        final Swagger swagger = new Swagger();
+        swagger.host("petstore.swagger.io");
+
+        assertThat(endpoint.determineHost(swagger)).isEqualTo("http://petstore.swagger.io");
+
+        swagger.schemes(Arrays.asList(Scheme.HTTPS));
+        assertThat(endpoint.determineHost(swagger)).isEqualTo("https://petstore.swagger.io");
+    }
+
+    @Test
+    public void shouldDetermineOptions() {
+        assertThat(RestSwaggerEndpoint.determineOption(null, null, null, null)).isNull();
+
+        assertThat(RestSwaggerEndpoint.determineOption(Collections.emptyList(), Collections.emptyList(), "", ""))
+            .isNull();
+
+        assertThat(RestSwaggerEndpoint.determineOption(Arrays.asList("specification"), null, null, null))
+            .isEqualTo("specification");
+
+        assertThat(
+            RestSwaggerEndpoint.determineOption(Arrays.asList("specification"), Arrays.asList("operation"), null, null))
+                .isEqualTo("operation");
+
+        assertThat(RestSwaggerEndpoint.determineOption(Arrays.asList("specification"), Arrays.asList("operation"),
+            "component", null)).isEqualTo("component");
+
+        assertThat(RestSwaggerEndpoint.determineOption(Arrays.asList("specification"), Arrays.asList("operation"),
+            "component", "operation")).isEqualTo("operation");
+    }
+
+    @Test
+    public void shouldHaveADefaultSpecificationPathProperty() throws Exception {
+        final RestSwaggerComponent component = new RestSwaggerComponent();
+
+        final RestSwaggerEndpoint endpoint = new RestSwaggerEndpoint("rest-swagger:getPetById", "getPetById",
+            component);
+
+        assertThat(endpoint.getSpecificationUri()).isEqualTo(RestSwaggerComponent.DEFAULT_SPECIFICATION_URI);
+    }
+
+    @Test
+    public void shouldHonourComponentSpecificationPathProperty() throws Exception {
+        final RestSwaggerComponent component = new RestSwaggerComponent();
+        component.setSpecificationUri(componentJsonUri);
+
+        final RestSwaggerEndpoint endpoint = new RestSwaggerEndpoint("rest-swagger:getPetById", "getPetById",
+            component);
+
+        assertThat(endpoint.getSpecificationUri()).isEqualTo(componentJsonUri);
+    }
+
+    @Test
+    public void shouldHonourEndpointUriPathSpecificationPathProperty() throws Exception {
+        final RestSwaggerComponent component = new RestSwaggerComponent();
+        component.setSpecificationUri(componentJsonUri);
+
+        final RestSwaggerEndpoint endpoint = new RestSwaggerEndpoint("rest-swagger:endpoint.json#getPetById",
+            "endpoint.json#getPetById", component);
+
+        assertThat(endpoint.getSpecificationUri()).isEqualTo(endpointUri);
+    }
+
+    @Test
+    public void shouldHonourHostPrecedence() {
+        final RestConfiguration globalRestConfiguration = new RestConfiguration();
+
+        final RestConfiguration componentRestConfiguration = new RestConfiguration();
+        final RestConfiguration specificRestConfiguration = new RestConfiguration();
+
+        final CamelContext camelContext = mock(CamelContext.class);
+        when(camelContext.getRestConfiguration()).thenReturn(globalRestConfiguration);
+        when(camelContext.getRestConfiguration("rest-swagger", false)).thenReturn(componentRestConfiguration);
+        when(camelContext.getRestConfiguration("petstore", false)).thenReturn(specificRestConfiguration);
+
+        final RestSwaggerComponent component = new RestSwaggerComponent();
+        component.setCamelContext(camelContext);
+
+        final RestSwaggerEndpoint endpoint = new RestSwaggerEndpoint("petstore:http://specification-uri#getPetById",
+            "http://specification-uri#getPetById", component);
+
+        final Swagger swagger = new Swagger();
+        assertThat(endpoint.determineHost(swagger)).isEqualTo("http://specification-uri");
+
+        globalRestConfiguration.setHost("global-rest");
+        globalRestConfiguration.setScheme("http");
+        assertThat(endpoint.determineHost(swagger)).isEqualTo("http://global-rest");
+
+        globalRestConfiguration.setHost("component-rest");
+        globalRestConfiguration.setScheme("http");
+        assertThat(endpoint.determineHost(swagger)).isEqualTo("http://component-rest");
+
+        specificRestConfiguration.setHost("specific-rest");
+        specificRestConfiguration.setScheme("http");
+        assertThat(endpoint.determineHost(swagger)).isEqualTo("http://specific-rest");
+
+        swagger.host("specification").scheme(Scheme.HTTP);
+        assertThat(endpoint.determineHost(swagger)).isEqualTo("http://specification");
+
+        component.setHost("http://component");
+        assertThat(endpoint.determineHost(swagger)).isEqualTo("http://component");
+
+        endpoint.setHost("http://endpoint");
+        assertThat(endpoint.determineHost(swagger)).isEqualTo("http://endpoint");
+    }
+
+    @Test
+    public void shouldLoadSwaggerSpecifications() throws IOException {
+        final CamelContext camelContext = mock(CamelContext.class);
+        when(camelContext.getClassResolver()).thenReturn(new DefaultClassResolver());
+
+        assertThat(
+            RestSwaggerEndpoint.loadSpecificationFrom(camelContext, RestSwaggerComponent.DEFAULT_SPECIFICATION_URI))
+                .isNotNull();
+    }
+
+    @Test
+    public void shouldPickBestScheme() {
+        assertThat(RestSwaggerEndpoint.pickBestScheme("http", Arrays.asList(Scheme.HTTP, Scheme.HTTPS)))
+            .isEqualTo("https");
+
+        assertThat(RestSwaggerEndpoint.pickBestScheme("https", Arrays.asList(Scheme.HTTP))).isEqualTo("http");
+
+        assertThat(RestSwaggerEndpoint.pickBestScheme("http", Collections.emptyList())).isEqualTo("http");
+
+        assertThat(RestSwaggerEndpoint.pickBestScheme("http", null)).isEqualTo("http");
+
+        assertThat(RestSwaggerEndpoint.pickBestScheme(null, Collections.emptyList())).isNull();
+
+        assertThat(RestSwaggerEndpoint.pickBestScheme(null, null)).isNull();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void shouldRaiseExceptionsForMissingSpecifications() throws IOException {
+        final CamelContext camelContext = mock(CamelContext.class);
+        when(camelContext.getClassResolver()).thenReturn(new DefaultClassResolver());
+
+        RestSwaggerEndpoint.loadSpecificationFrom(camelContext, URI.create("non-existant.json"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointUriParsingTest.java
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointUriParsingTest.java b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointUriParsingTest.java
new file mode 100644
index 0000000..ee90a36
--- /dev/null
+++ b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointUriParsingTest.java
@@ -0,0 +1,66 @@
+/**
+ * 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.rest.swagger;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(Parameterized.class)
+public class RestSwaggerEndpointUriParsingTest {
+
+    @Parameter(3)
+    public String operationId;
+
+    @Parameter(1)
+    public String remaining;
+
+    @Parameter(2)
+    public String specificationUri;
+
+    @Parameter(0)
+    public String uri;
+
+    @Test
+    public void shouldParseEndpointUri() {
+        final RestSwaggerComponent component = new RestSwaggerComponent();
+
+        final RestSwaggerEndpoint endpoint = new RestSwaggerEndpoint(specificationUri, remaining, component);
+
+        assertThat(endpoint.getSpecificationUri().toString()).isEqualTo(specificationUri);
+        assertThat(endpoint.getOperationId()).isEqualTo(operationId);
+    }
+
+    @Parameters(name = "uri={0}, remaining={1}")
+    public static Iterable<Object[]> parameters() {
+        return Arrays.asList(params("rest-swagger:operation", "operation", "swagger.json", "operation"),
+            params("rest-swagger:my-api.json#operation", "my-api.json#operation", "my-api.json", "operation"),
+            params("rest-swagger:http://api.example.com/swagger.json#operation",
+                "http://api.example.com/swagger.json#operation", "http://api.example.com/swagger.json", "operation"));
+    }
+
+    static Object[] params(final String uri, final String remaining, final String specificationUri,
+        final String operationId) {
+        return new Object[] {uri, remaining, specificationUri, operationId};
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerHelperTest.java
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerHelperTest.java b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerHelperTest.java
new file mode 100644
index 0000000..844f429
--- /dev/null
+++ b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerHelperTest.java
@@ -0,0 +1,50 @@
+/**
+ * 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.rest.swagger;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class RestSwaggerHelperTest {
+
+    @Test(expected = IllegalArgumentException.class)
+    public void emptyHostParamsAreNotAllowed() {
+        RestSwaggerHelper.isHostParam("");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void nonUriHostParametersAreNotAllowed() {
+        RestSwaggerHelper.isHostParam("carrot");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void nullHostParamsAreNotAllowed() {
+        RestSwaggerHelper.isHostParam(null);
+    }
+
+    @Test
+    public void shouldNiceify() {
+        assertThat(RestSwaggerHelper.isHostParam("http://api.example.com")).isEqualTo("http://api.example.com");
+    }
+
+    @Test
+    public void shouldReturnUriParameter() {
+        assertThat(RestSwaggerHelper.isHostParam("http://api.example.com")).isEqualTo("http://api.example.com");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/src/test/resources/log4j2.properties
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/src/test/resources/log4j2.properties b/components/camel-rest-swagger/src/test/resources/log4j2.properties
new file mode 100644
index 0000000..ddba19c
--- /dev/null
+++ b/components/camel-rest-swagger/src/test/resources/log4j2.properties
@@ -0,0 +1,24 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-rest-swagger-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d %-5p %c{1} - %m %n
+rootLogger.level = INFO
+rootLogger.appenderRef.file.ref = file

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/src/test/resources/swagger.json
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/src/test/resources/swagger.json b/components/camel-rest-swagger/src/test/resources/swagger.json
new file mode 100644
index 0000000..816847f
--- /dev/null
+++ b/components/camel-rest-swagger/src/test/resources/swagger.json
@@ -0,0 +1 @@
+{"swagger":"2.0","info":{"description":"This is a sample server Petstore server.  You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).  For this sample, you can use the api key `special-key` to test the authorization filters.","version":"1.0.0","title":"Swagger Petstore","termsOfService":"http://swagger.io/terms/","contact":{"email":"[hidden email]"},"license":{"name":"Apache 2.0","url":"http://www.apache.org/licenses/LICENSE-2.0.html"}},"host":"petstore.swagger.io","basePath":"/v2","tags":[{"name":"pet","description":"Everything about your Pets","externalDocs":{"description":"Find out more","url":"http://swagger.io"}},{"name":"store","description":"Access to Petstore orders"},{"name":"user","description":"Operations about user","externalDocs":{"description":"Find out more about our store","url":"http://swagger.io"}}],"schemes":["http"],"paths":{"/pet":{"post":{"tags":["pet"],"summary":"Add a ne
 w pet to the store","description":"","operationId":"addPet","consumes":["application/json","application/xml"],"produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Pet object that needs to be added to the store","required":true,"schema":{"$ref":"#/definitions/Pet"}}],"responses":{"405":{"description":"Invalid input"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]},"put":{"tags":["pet"],"summary":"Update an existing pet","description":"","operationId":"updatePet","consumes":["application/json","application/xml"],"produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Pet object that needs to be added to the store","required":true,"schema":{"$ref":"#/definitions/Pet"}}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"},"405":{"description":"Validation exception"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet
 /findByStatus":{"get":{"tags":["pet"],"summary":"Finds Pets by status","description":"Multiple status values can be provided with comma separated strings","operationId":"findPetsByStatus","produces":["application/xml","application/json"],"parameters":[{"name":"status","in":"query","description":"Status values that need to be considered for filter","required":true,"type":"array","items":{"type":"string","enum":["available","pending","sold"],"default":"available"},"collectionFormat":"multi"}],"responses":{"200":{"description":"successful operation","schema":{"type":"array","items":{"$ref":"#/definitions/Pet"}}},"400":{"description":"Invalid status value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/findByTags":{"get":{"tags":["pet"],"summary":"Finds Pets by tags","description":"Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.","operationId":"findPetsByTags","produces":["application/xml","application/json"],"parameters"
 :[{"name":"tags","in":"query","description":"Tags to filter by","required":true,"type":"array","items":{"type":"string"},"collectionFormat":"multi"}],"responses":{"200":{"description":"successful operation","schema":{"type":"array","items":{"$ref":"#/definitions/Pet"}}},"400":{"description":"Invalid tag value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}],"deprecated":true}},"/pet/{petId}":{"get":{"tags":["pet"],"summary":"Find pet by ID","description":"Returns a single pet","operationId":"getPetById","produces":["application/xml","application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet to return","required":true,"type":"integer","format":"int64"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Pet"}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"}},"security":[{"api_key":[]}]},"post":{"tags":["pet"],"summary":"Updates a pet in the store with form data","descriptio
 n":"","operationId":"updatePetWithForm","consumes":["application/x-www-form-urlencoded"],"produces":["application/xml","application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet that needs to be updated","required":true,"type":"integer","format":"int64"},{"name":"name","in":"formData","description":"Updated name of the pet","required":false,"type":"string"},{"name":"status","in":"formData","description":"Updated status of the pet","required":false,"type":"string"}],"responses":{"405":{"description":"Invalid input"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]},"delete":{"tags":["pet"],"summary":"Deletes a pet","description":"","operationId":"deletePet","produces":["application/xml","application/json"],"parameters":[{"name":"api_key","in":"header","required":false,"type":"string"},{"name":"petId","in":"path","description":"Pet id to delete","required":true,"type":"integer","format":"int64"}],"responses":{"400":{"description":"Invalid ID suppl
 ied"},"404":{"description":"Pet not found"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/{petId}/uploadImage":{"post":{"tags":["pet"],"summary":"uploads an image","description":"","operationId":"uploadFile","consumes":["multipart/form-data"],"produces":["application/json"],"parameters":[{"name":"petId","in":"path","description":"ID of pet to update","required":true,"type":"integer","format":"int64"},{"name":"additionalMetadata","in":"formData","description":"Additional data to pass to server","required":false,"type":"string"},{"name":"file","in":"formData","description":"file to upload","required":false,"type":"file"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/ApiResponse"}}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/store/inventory":{"get":{"tags":["store"],"summary":"Returns pet inventories by status","description":"Returns a map of status codes to quantities","operationId":"getInventory","pro
 duces":["application/json"],"parameters":[],"responses":{"200":{"description":"successful operation","schema":{"type":"object","additionalProperties":{"type":"integer","format":"int32"}}}},"security":[{"api_key":[]}]}},"/store/order":{"post":{"tags":["store"],"summary":"Place an order for a pet","description":"","operationId":"placeOrder","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"order placed for purchasing the pet","required":true,"schema":{"$ref":"#/definitions/Order"}}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Order"}},"400":{"description":"Invalid Order"}}}},"/store/order/{orderId}":{"get":{"tags":["store"],"summary":"Find purchase order by ID","description":"For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions","operationId":"getOrderById","produces":["application/xml","application/json"],"parameters":[{"name":"orderId",
 "in":"path","description":"ID of pet that needs to be fetched","required":true,"type":"integer","maximum":10.0,"minimum":1.0,"format":"int64"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/Order"}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Order not found"}}},"delete":{"tags":["store"],"summary":"Delete purchase order by ID","description":"For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors","operationId":"deleteOrder","produces":["application/xml","application/json"],"parameters":[{"name":"orderId","in":"path","description":"ID of the order that needs to be deleted","required":true,"type":"integer","minimum":1.0,"format":"int64"}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Order not found"}}}},"/user":{"post":{"tags":["user"],"summary":"Create user","description":"This can only be done by the logged in user.","op
 erationId":"createUser","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"Created user object","required":true,"schema":{"$ref":"#/definitions/User"}}],"responses":{"default":{"description":"successful operation"}}}},"/user/createWithArray":{"post":{"tags":["user"],"summary":"Creates list of users with given input array","description":"","operationId":"createUsersWithArrayInput","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"List of user object","required":true,"schema":{"type":"array","items":{"$ref":"#/definitions/User"}}}],"responses":{"default":{"description":"successful operation"}}}},"/user/createWithList":{"post":{"tags":["user"],"summary":"Creates list of users with given input array","description":"","operationId":"createUsersWithListInput","produces":["application/xml","application/json"],"parameters":[{"in":"body","name":"body","description":"List of user obj
 ect","required":true,"schema":{"type":"array","items":{"$ref":"#/definitions/User"}}}],"responses":{"default":{"description":"successful operation"}}}},"/user/login":{"get":{"tags":["user"],"summary":"Logs user into the system","description":"","operationId":"loginUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"query","description":"The user name for login","required":true,"type":"string"},{"name":"password","in":"query","description":"The password for login in clear text","required":true,"type":"string"}],"responses":{"200":{"description":"successful operation","schema":{"type":"string"},"headers":{"X-Rate-Limit":{"type":"integer","format":"int32","description":"calls per hour allowed by the user"},"X-Expires-After":{"type":"string","format":"date-time","description":"date in UTC when token expires"}}},"400":{"description":"Invalid username/password supplied"}}}},"/user/logout":{"get":{"tags":["user"],"summary":"Logs out current logged
  in user session","description":"","operationId":"logoutUser","produces":["application/xml","application/json"],"parameters":[],"responses":{"default":{"description":"successful operation"}}}},"/user/{username}":{"get":{"tags":["user"],"summary":"Get user by user name","description":"","operationId":"getUserByName","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"The name that needs to be fetched. Use user1 for testing. ","required":true,"type":"string"}],"responses":{"200":{"description":"successful operation","schema":{"$ref":"#/definitions/User"}},"400":{"description":"Invalid username supplied"},"404":{"description":"User not found"}}},"put":{"tags":["user"],"summary":"Updated user","description":"This can only be done by the logged in user.","operationId":"updateUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"name that need to be updated","required":t
 rue,"type":"string"},{"in":"body","name":"body","description":"Updated user object","required":true,"schema":{"$ref":"#/definitions/User"}}],"responses":{"400":{"description":"Invalid user supplied"},"404":{"description":"User not found"}}},"delete":{"tags":["user"],"summary":"Delete user","description":"This can only be done by the logged in user.","operationId":"deleteUser","produces":["application/xml","application/json"],"parameters":[{"name":"username","in":"path","description":"The name that needs to be deleted","required":true,"type":"string"}],"responses":{"400":{"description":"Invalid username supplied"},"404":{"description":"User not found"}}}}},"securityDefinitions":{"petstore_auth":{"type":"oauth2","authorizationUrl":"http://petstore.swagger.io/oauth/dialog","flow":"implicit","scopes":{"write:pets":"modify pets in your account","read:pets":"read your pets"}},"api_key":{"type":"apiKey","name":"api_key","in":"header"}},"definitions":{"Order":{"type":"object","properties":{
 "id":{"type":"integer","format":"int64"},"petId":{"type":"integer","format":"int64"},"quantity":{"type":"integer","format":"int32"},"shipDate":{"type":"string","format":"date-time"},"status":{"type":"string","description":"Order Status","enum":["placed","approved","delivered"]},"complete":{"type":"boolean","default":false}},"xml":{"name":"Order"}},"Category":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}},"xml":{"name":"Category"}},"User":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"username":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"},"phone":{"type":"string"},"userStatus":{"type":"integer","format":"int32","description":"User Status"}},"xml":{"name":"User"}},"Tag":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}},"xml":{"name":"Tag"}},"Pet":{"type":"object","required":["
 name","photoUrls"],"properties":{"id":{"type":"integer","format":"int64"},"category":{"$ref":"#/definitions/Category"},"name":{"type":"string","example":"doggie"},"photoUrls":{"type":"array","xml":{"name":"photoUrl","wrapped":true},"items":{"type":"string"}},"tags":{"type":"array","xml":{"name":"tag","wrapped":true},"items":{"$ref":"#/definitions/Tag"}},"status":{"type":"string","description":"pet status in the store","enum":["available","pending","sold"]}},"xml":{"name":"Pet"}},"ApiResponse":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"type":{"type":"string"},"message":{"type":"string"}}}},"externalDocs":{"description":"Find out more about Swagger","url":"http://swagger.io"}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/pom.xml
----------------------------------------------------------------------
diff --git a/components/pom.xml b/components/pom.xml
index 541a57b..be5e3af 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -221,6 +221,7 @@
     <module>camel-quickfix</module>
     <module>camel-rabbitmq</module>
     <module>camel-reactive-streams</module>
+    <module>camel-rest-swagger</module>
     <module>camel-restlet</module>
     <module>camel-rmi</module>
     <module>camel-routebox</module>

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/docs/user-manual/en/SUMMARY.md
----------------------------------------------------------------------
diff --git a/docs/user-manual/en/SUMMARY.md b/docs/user-manual/en/SUMMARY.md
index d37fbf8..327413e 100644
--- a/docs/user-manual/en/SUMMARY.md
+++ b/docs/user-manual/en/SUMMARY.md
@@ -274,6 +274,7 @@
  * [QuickFix](quickfix-component.adoc)
  * [RabbitMQ](rabbitmq-component.adoc)
  * [Reactive Streams](reactive-streams-component.adoc)
+ * [REST Swagger](rest-swagger-component.adoc)
  * [Restlet](restlet-component.adoc)
  * [RMI](rmi-component.adoc)
  * [RouteBox](routebox-component.adoc)

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/examples/camel-example-rest-swagger/README.md
----------------------------------------------------------------------
diff --git a/examples/camel-example-rest-swagger/README.md b/examples/camel-example-rest-swagger/README.md
new file mode 100644
index 0000000..d8c0bcb
--- /dev/null
+++ b/examples/camel-example-rest-swagger/README.md
@@ -0,0 +1,30 @@
+# Camel Rest Swagger example
+
+This example shows how to call a REST service defined using Swagger
+specification with the help of Camel Rest Swagger component.
+
+The example is a standalong Spring Boot application that acts as a REST
+client, you can run simply by issuing:
+
+    $ mvn spring-boot:run
+
+Or by packaging it and running it using `java` CLI:
+
+    $ mvn package
+    $ java -jar target/camel-example-rest-swagger-*.jar
+
+The example by default uses the PetStore demo hosted on swagger.io and
+invokes the `getInventory` operation. You can make it call any API
+that you have Swagger specification for and any operation with simple
+arguments, for instance this retrives a pet from the PetStore demo with
+ID `9584`:
+
+    $ java -jar target/camel-example-rest-swagger-*.jar \
+        --swagger=http://petstore.swagger.io/v2/swagger.json \
+        --operation=getPetById \
+        --petId=9584
+
+## More information
+
+You can find more information about Apache Camel at the website:
+http://camel.apache.org/

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/examples/camel-example-rest-swagger/pom.xml
----------------------------------------------------------------------
diff --git a/examples/camel-example-rest-swagger/pom.xml b/examples/camel-example-rest-swagger/pom.xml
new file mode 100644
index 0000000..fae6e83
--- /dev/null
+++ b/examples/camel-example-rest-swagger/pom.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>examples</artifactId>
+    <version>2.19.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>camel-example-rest-swagger</artifactId>
+  <name>Camel :: Example :: REST Swagger</name>
+  <version>2.19.0-SNAPSHOT</version>
+
+  <properties>
+    <category>Beginner</category>
+
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+    <spring.boot-version>${spring-boot-version}</spring.boot-version>
+  </properties>
+
+  <dependencyManagement>
+    <dependencies>
+      <!-- Spring Boot BOM -->
+      <dependency>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-dependencies</artifactId>
+        <version>${spring.boot-version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+      <!-- Camel BOM -->
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-spring-boot-dependencies</artifactId>
+        <version>${project.version}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-undertow-starter</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-rest-swagger-starter</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <version>${maven-resources-plugin-version}</version>
+        <configuration>
+          <encoding>UTF-8</encoding>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-maven-plugin</artifactId>
+        <version>${spring-boot-version}</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>repackage</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/examples/camel-example-rest-swagger/src/main/java/org/apache/camel/example/RestSwaggerApplication.java
----------------------------------------------------------------------
diff --git a/examples/camel-example-rest-swagger/src/main/java/org/apache/camel/example/RestSwaggerApplication.java b/examples/camel-example-rest-swagger/src/main/java/org/apache/camel/example/RestSwaggerApplication.java
new file mode 100644
index 0000000..a6f00dc
--- /dev/null
+++ b/examples/camel-example-rest-swagger/src/main/java/org/apache/camel/example/RestSwaggerApplication.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.example;
+
+import java.util.Map;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import static java.util.function.Function.identity;
+
+import org.apache.camel.ProducerTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.ApplicationContext;
+
+@SpringBootApplication
+public class RestSwaggerApplication implements ApplicationRunner {
+
+    @Autowired
+    ApplicationContext context;
+
+    @Value("${operation:getInventory}")
+    String operation;
+
+    @Value("${swagger:http://petstore.swagger.io/v2/swagger.json}")
+    String specificationUri;
+
+    @Autowired
+    ProducerTemplate template;
+
+    @Override
+    public void run(final ApplicationArguments args) throws Exception {
+        final Predicate<String> operations = "operation"::equals;
+
+        final Map<String, Object> headers = args.getOptionNames().stream().filter(operations.negate())
+            .collect(Collectors.toMap(identity(), arg -> args.getOptionValues(arg).get(0)));
+
+        final String body = template.requestBodyAndHeaders("rest-swagger:" + specificationUri + "#" + operation, null,
+            headers, String.class);
+
+        System.out.println(body);
+
+        SpringApplication.exit(context, () -> 0);
+    }
+
+    public static void main(final String[] args) {
+        SpringApplication.run(RestSwaggerApplication.class, args);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/parent/pom.xml
----------------------------------------------------------------------
diff --git a/parent/pom.xml b/parent/pom.xml
index fef420e..7e0dc1c 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -62,6 +62,7 @@
     <asciidoctorj-version>1.5.4.1</asciidoctorj-version>
     <asm-version>5.0.4</asm-version>
     <aspectj-version>1.8.10</aspectj-version>
+    <assertj-version>3.6.2</assertj-version>
     <asterisk-java-version>1.0.0-final</asterisk-java-version>
     <asterisk-java-bundle-version>1.0.0-final_1</asterisk-java-bundle-version>
     <atmos-client-version>2.2.2</atmos-client-version>
@@ -4057,6 +4058,11 @@
         <artifactId>httpunit</artifactId>
         <version>${httpunit-version}</version>
       </dependency>
+        <dependency>
+        <groupId>org.assertj</groupId>
+        <artifactId>assertj-core</artifactId>
+        <version>${assertj-version}</version>
+      </dependency>
 
       <!-- default JPA support -->
       <dependency>

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/platforms/spring-boot/components-starter/camel-rest-swagger-starter/pom.xml
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-rest-swagger-starter/pom.xml b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/pom.xml
new file mode 100644
index 0000000..37a7c35
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/pom.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>components-starter</artifactId>
+    <version>2.19.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>camel-rest-swagger-starter</artifactId>
+  <packaging>jar</packaging>
+  <name>Spring-Boot Starter :: Camel :: REST Swagger</name>
+  <description>Spring-Boot Starter for Camel REST support using Swagger</description>
+  <dependencies>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+      <version>${spring-boot-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-rest-swagger</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <!--START OF GENERATED CODE-->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core-starter</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-spring-boot-starter</artifactId>
+    </dependency>
+    <!--END OF GENERATED CODE-->
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/java/org/apache/camel/component/rest/swagger/springboot/RestSwaggerComponentAutoConfiguration.java
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/java/org/apache/camel/component/rest/swagger/springboot/RestSwaggerComponentAutoConfiguration.java b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/java/org/apache/camel/component/rest/swagger/springboot/RestSwaggerComponentAutoConfiguration.java
new file mode 100644
index 0000000..52f4ef1
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/java/org/apache/camel/component/rest/swagger/springboot/RestSwaggerComponentAutoConfiguration.java
@@ -0,0 +1,111 @@
+/**
+ * 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.rest.swagger.springboot;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.rest.swagger.RestSwaggerComponent;
+import org.apache.camel.util.IntrospectionSupport;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionMessage;
+import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
+import org.springframework.boot.bind.RelaxedPropertyResolver;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+/**
+ * Generated by camel-package-maven-plugin - do not edit this file!
+ */
+@Configuration
+@ConditionalOnBean(type = "org.apache.camel.spring.boot.CamelAutoConfiguration")
+@Conditional(RestSwaggerComponentAutoConfiguration.Condition.class)
+@AutoConfigureAfter(name = "org.apache.camel.spring.boot.CamelAutoConfiguration")
+@EnableConfigurationProperties(RestSwaggerComponentConfiguration.class)
+public class RestSwaggerComponentAutoConfiguration {
+
+    @Lazy
+    @Bean(name = "rest-swagger-component")
+    @ConditionalOnClass(CamelContext.class)
+    @ConditionalOnMissingBean(RestSwaggerComponent.class)
+    public RestSwaggerComponent configureRestSwaggerComponent(
+            CamelContext camelContext,
+            RestSwaggerComponentConfiguration configuration) throws Exception {
+        RestSwaggerComponent component = new RestSwaggerComponent();
+        component.setCamelContext(camelContext);
+        Map<String, Object> parameters = new HashMap<>();
+        IntrospectionSupport.getProperties(configuration, parameters, null,
+                false);
+        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
+            Object value = entry.getValue();
+            Class<?> paramClass = value.getClass();
+            if (paramClass.getName().endsWith("NestedConfiguration")) {
+                Class nestedClass = null;
+                try {
+                    nestedClass = (Class) paramClass.getDeclaredField(
+                            "CAMEL_NESTED_CLASS").get(null);
+                    HashMap<String, Object> nestedParameters = new HashMap<>();
+                    IntrospectionSupport.getProperties(value, nestedParameters,
+                            null, false);
+                    Object nestedProperty = nestedClass.newInstance();
+                    IntrospectionSupport.setProperties(camelContext,
+                            camelContext.getTypeConverter(), nestedProperty,
+                            nestedParameters);
+                    entry.setValue(nestedProperty);
+                } catch (NoSuchFieldException e) {
+                }
+            }
+        }
+        IntrospectionSupport.setProperties(camelContext,
+                camelContext.getTypeConverter(), component, parameters);
+        return component;
+    }
+
+    public static class Condition extends SpringBootCondition {
+        @Override
+        public ConditionOutcome getMatchOutcome(
+                ConditionContext conditionContext,
+                AnnotatedTypeMetadata annotatedTypeMetadata) {
+            boolean groupEnabled = isEnabled(conditionContext,
+                    "camel.component.", true);
+            ConditionMessage.Builder message = ConditionMessage
+                    .forCondition("camel.component.rest-swagger");
+            if (isEnabled(conditionContext, "camel.component.rest-swagger.",
+                    groupEnabled)) {
+                return ConditionOutcome.match(message.because("enabled"));
+            }
+            return ConditionOutcome.noMatch(message.because("not enabled"));
+        }
+
+        private boolean isEnabled(
+                org.springframework.context.annotation.ConditionContext context,
+                java.lang.String prefix, boolean defaultValue) {
+            RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
+                    context.getEnvironment(), prefix);
+            return resolver.getProperty("enabled", Boolean.class, defaultValue);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/java/org/apache/camel/component/rest/swagger/springboot/RestSwaggerComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/java/org/apache/camel/component/rest/swagger/springboot/RestSwaggerComponentConfiguration.java b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/java/org/apache/camel/component/rest/swagger/springboot/RestSwaggerComponentConfiguration.java
new file mode 100644
index 0000000..1d59966
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/java/org/apache/camel/component/rest/swagger/springboot/RestSwaggerComponentConfiguration.java
@@ -0,0 +1,142 @@
+/**
+ * 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.rest.swagger.springboot;
+
+import java.net.URI;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * An awesome REST endpoint backed by Swagger specifications.
+ *
+ * Generated by camel-package-maven-plugin - do not edit this file!
+ */
+@ConfigurationProperties(prefix = "camel.component.rest-swagger")
+public class RestSwaggerComponentConfiguration {
+
+    /**
+     * API basePath for example /v2. Default is unset if set overrides the value
+     * present in Swagger specification.
+     */
+    private String basePath;
+    /**
+     * Name of the Camel component that will perform the requests. The compnent
+     * must be present in Camel registry and it must implement
+     * RestProducerFactory service provider interface. If not set CLASSPATH is
+     * searched for single component that implements RestProducerFactory SPI.
+     * Can be overriden in endpoint configuration.
+     */
+    private String componentName;
+    /**
+     * 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
+     * Swagger specification. Can be overriden in endpoint configuration
+     */
+    private String consumes;
+    /**
+     * Scheme hostname and port to direct the HTTP requests to in the form of
+     * <a href="https://hostname:port">https://hostname:port. Can be configured at the endpoint component or in
+     * the correspoding REST configuration in the Camel Context. If you give
+     * this component a name (e.g. petstore) that REST configuration is
+     * consulted first rest-swagger next and global configuration last. If set
+     * overrides any value found in the Swagger specification RestConfiguration.
+     * Can be overriden in endpoint configuration.
+     */
+    private String host;
+    /**
+     * What payload type this component is producing. For example
+     * application/json according to the RFC7231. This equates to the value of
+     * Content-Type HTTP header. If set overrides any value present in the
+     * Swagger specification. Can be overriden in endpoint configuration.
+     */
+    private String produces;
+    /**
+     * Path to the Swagger specification file. The scheme host base path are
+     * taken from this specification but these can be overriden with properties
+     * on the component or endpoint level. If not given the component tries to
+     * load swagger.json resource. Note that the host defined on the component
+     * and endpoint of this Component should contain the scheme hostname and
+     * optionally the port in the URI syntax (i.e.
+     * https://api.example.com:8080). Can be overriden in endpoint
+     * configuration.
+     */
+    private URI specificationUri;
+    /**
+     * Whether the component should resolve property placeholders on itself when
+     * starting. Only properties which are of String type can use property
+     * placeholders.
+     */
+    private Boolean resolvePropertyPlaceholders = true;
+
+    public String getBasePath() {
+        return basePath;
+    }
+
+    public void setBasePath(String basePath) {
+        this.basePath = basePath;
+    }
+
+    public String getComponentName() {
+        return componentName;
+    }
+
+    public void setComponentName(String componentName) {
+        this.componentName = componentName;
+    }
+
+    public String getConsumes() {
+        return consumes;
+    }
+
+    public void setConsumes(String consumes) {
+        this.consumes = consumes;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public String getProduces() {
+        return produces;
+    }
+
+    public void setProduces(String produces) {
+        this.produces = produces;
+    }
+
+    public URI getSpecificationUri() {
+        return specificationUri;
+    }
+
+    public void setSpecificationUri(URI specificationUri) {
+        this.specificationUri = specificationUri;
+    }
+
+    public Boolean getResolvePropertyPlaceholders() {
+        return resolvePropertyPlaceholders;
+    }
+
+    public void setResolvePropertyPlaceholders(
+            Boolean resolvePropertyPlaceholders) {
+        this.resolvePropertyPlaceholders = resolvePropertyPlaceholders;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/LICENSE.txt
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/LICENSE.txt b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/NOTICE.txt
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/NOTICE.txt b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json
new file mode 100644
index 0000000..d3c0144
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -0,0 +1,10 @@
+{
+  "properties": [
+    {
+      "defaultValue": true,
+      "name": "camel.component.rest-swagger.enabled",
+      "description": "Enable rest-swagger component",
+      "type": "java.lang.Boolean"
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/spring.factories
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/spring.factories b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000..2bbcb95
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.apache.camel.component.rest.swagger.springboot.RestSwaggerComponentAutoConfiguration

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/spring.provides
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/spring.provides b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/spring.provides
new file mode 100644
index 0000000..9a206c6
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/resources/META-INF/spring.provides
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+provides: camel-rest-swagger
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/platforms/spring-boot/components-starter/pom.xml
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/pom.xml b/platforms/spring-boot/components-starter/pom.xml
index f8f335e..2e2be26 100644
--- a/platforms/spring-boot/components-starter/pom.xml
+++ b/platforms/spring-boot/components-starter/pom.xml
@@ -236,6 +236,7 @@
     <module>camel-quickfix-starter</module>
     <module>camel-rabbitmq-starter</module>
     <module>camel-reactive-streams-starter</module>
+    <module>camel-rest-swagger-starter</module>
     <module>camel-restlet-starter</module>
     <module>camel-ribbon-starter</module>
     <module>camel-rmi-starter</module>

Reply | Threaded
Open this post in threaded view
|

[2/2] camel git commit: CAMEL-10932 REST Swagger component

zregvart
CAMEL-10932 REST Swagger component

This includes the initial implementation of the `rest-swagger` component
that allows for a higher level abstraction over the REST API usage from
other Camel components that implement the `RestProducerFactory` SPI
combined with Swagger (Open API) specifications.

The most simple usage would be:

    to("rest-swagger:getPetById")

Which would pick up the Swagger specification from `swagger.json` and
try to find a single component that implements the `RestProducerFactory`
SPI and invoke the `getPetById` operation.

Other way of using this component could be:

    to("rest-swagger:http://petstore.swagger.io/v2/swagger.json#getPetById")

That loads the Swagger specification from the
`http://petstore.swagger.io/v2/swagger.json` URL and invokes the
`getPetById` operation.

More concise way of configuring would be to configure most properties
on the component add it to CamelContext, and use only `operationId` path
parameter when triggering the exchange:

    // add `petstore` component to the CamelContext
    RestSwaggerComponent petstore =
        new RestSwaggerComponent(camelContext);
    petstore.setSpecificationUri("http://petstore.swagger.io/v2/swagger.json");
    petstore.setComponentName("undertow");
    camelContext.addComponent("petstore", petstore);

And then use `operationId` in endpoint definition:

    ProducerTemplate template = camelContext.getProducerTemplate();
    template.requestBodyAndHeaders("petstore:getPetById", null, "petId",
        petId);


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/5b209152
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/5b209152
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/5b209152

Branch: refs/heads/master
Commit: 5b209152b2ffb1ddd507c8b265bdab50aea620ef
Parents: ae2ae6f
Author: Zoran Regvart <[hidden email]>
Authored: Thu Mar 16 12:54:47 2017 +0100
Committer: Zoran Regvart <[hidden email]>
Committed: Thu Mar 16 22:28:20 2017 +0100

----------------------------------------------------------------------
 components/camel-rest-swagger/pom.xml           | 174 +++++++
 .../src/main/docs/rest-swagger-component.adoc   | 190 +++++++
 .../rest/swagger/RestSwaggerComponent.java      | 191 ++++++++
 .../rest/swagger/RestSwaggerEndpoint.java       | 490 +++++++++++++++++++
 .../rest/swagger/RestSwaggerHelper.java         |  50 ++
 .../src/main/resources/META-INF/LICENSE.txt     | 203 ++++++++
 .../src/main/resources/META-INF/NOTICE.txt      |  11 +
 .../org/apache/camel/component/rest-swagger     |  17 +
 .../camel/component/rest/swagger/Pet.java       |  28 ++
 .../rest/swagger/RestSwaggerComponentTest.java  | 152 ++++++
 .../rest/swagger/RestSwaggerEndpointTest.java   | 336 +++++++++++++
 .../RestSwaggerEndpointUriParsingTest.java      |  66 +++
 .../rest/swagger/RestSwaggerHelperTest.java     |  50 ++
 .../src/test/resources/log4j2.properties        |  24 +
 .../src/test/resources/swagger.json             |   1 +
 components/pom.xml                              |   1 +
 docs/user-manual/en/SUMMARY.md                  |   1 +
 examples/camel-example-rest-swagger/README.md   |  30 ++
 examples/camel-example-rest-swagger/pom.xml     | 102 ++++
 .../camel/example/RestSwaggerApplication.java   |  68 +++
 parent/pom.xml                                  |   6 +
 .../camel-rest-swagger-starter/pom.xml          |  51 ++
 .../RestSwaggerComponentAutoConfiguration.java  | 111 +++++
 .../RestSwaggerComponentConfiguration.java      | 142 ++++++
 .../src/main/resources/META-INF/LICENSE.txt     | 203 ++++++++
 .../src/main/resources/META-INF/NOTICE.txt      |  11 +
 ...dditional-spring-configuration-metadata.json |  10 +
 .../main/resources/META-INF/spring.factories    |  19 +
 .../src/main/resources/META-INF/spring.provides |  18 +
 .../spring-boot/components-starter/pom.xml      |   1 +
 30 files changed, 2757 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/pom.xml b/components/camel-rest-swagger/pom.xml
new file mode 100644
index 0000000..39d6da5
--- /dev/null
+++ b/components/camel-rest-swagger/pom.xml
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>components</artifactId>
+    <version>2.19.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>camel-rest-swagger</artifactId>
+
+  <name>Camel :: REST Swagger</name>
+  <description>Camel REST support using Swagger</description>
+
+  <properties>
+    <firstVersion>2.19.0</firstVersion>
+    <label>rest,api,http</label>
+    <camel.osgi.export.pkg>org.apache.camel.component.rest.swagger.*</camel.osgi.export.pkg>
+    <camel.osgi.export.service>org.apache.camel.spi.ComponentResolver;component=rest-swagger</camel.osgi.export.service>
+  </properties>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>io.swagger</groupId>
+      <artifactId>swagger-parser</artifactId>
+      <version>${swagger-java-parser-version}</version>
+      <exclusions>
+        <!--
+        Trying to keep transitive dependencies only to required ones.
+        -->
+        <exclusion>
+          <groupId>com.google.guava</groupId>
+          <artifactId>guava</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-ext</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>io.swagger</groupId>
+          <artifactId>swagger-annotations</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>javax.validation</groupId>
+          <artifactId>validation-api</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <!-- test -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.assertj</groupId>
+      <artifactId>assertj-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>com.github.tomakehurst</groupId>
+      <artifactId>wiremock</artifactId>
+      <version>${wiremock-version}</version>
+      <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <!--
+           Adding `camel-jetty9` forces WireMock to use mixed Jetty
+           versions, here we exclude WireMocks Jetty dependencies so
+           that we only use the ones declared by the `jetty9` component
+           -->
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>*</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-jaxb</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-http</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-http4</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-netty4-http</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-restlet</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-jetty9</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-undertow</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/src/main/docs/rest-swagger-component.adoc
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/src/main/docs/rest-swagger-component.adoc b/components/camel-rest-swagger/src/main/docs/rest-swagger-component.adoc
new file mode 100644
index 0000000..acdde17
--- /dev/null
+++ b/components/camel-rest-swagger/src/main/docs/rest-swagger-component.adoc
@@ -0,0 +1,190 @@
+## REST Swagger Component
+
+*Available as of Camel version 2.19*
+
+The *rest-swagger* configures rest producers from
+http://swagger.io/[Swagger] (Open API) specification document and
+delegates to a component implementing the _RestProducerFactory_
+interface. Currently known working components are:
+
+* link:http-component.html[http]
+* link:http4-component.html[http4]
+* link:netty4-http-component.html[netty4-http]
+* link:restlet-component.html[restlet]
+* link:jetty-component.html[jetty]
+* link:undertow-component.html[undertow]
+
+Maven users will need to add the following dependency to their
+`pom.xml` for this component:
+
+[source,xml]
+------------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-rest-swagger</artifactId>
+    <version>x.x.x</version>
+    <!-- use the same version as your Camel core version -->
+</dependency>
+------------------------------------------------------------
+
+### URI format
+
+[source,java]
+-------------------------------------------------------
+rest-swagger:[specificationPath#]operationId
+-------------------------------------------------------
+
+Where `operationId` is the ID of the operation in the Swagger
+specification, and `specificationPath` is the path to the
+specification.
+If the `specificationPath` is not specified it defaults to
+`swagger.json`. The lookup mechanism uses Camels `ResourceHelper` to
+load the resource, which means that you can use CLASSPATH resources
+(`classpath:my-specification.json`), files
+(`file:/some/path.json`), the web
+(`http://api.example.com/swagger.json`) or reference a bean
+(`ref:nameOfBean`) or use a method of a bean
+(`bean:nameOfBean.methodName`) to get the specification resource,
+failing that Swagger's own resource loading support.
+
+This component does not act as a HTTP client, it delegates that to
+another component mentioned above. The lookup mechanism searches for a
+single component that implements the _RestProducerFactory_ interface and
+uses that. If the CLASSPATH contains more than one, then the property
+`componentName` should be set to indicate which component to delegate
+to.
+
+Most of the configuration is taken from the Swagger specification but
+the option exists to override those by specifying them on the component
+or on the endpoint. Typically you would just need to override the
+`host` or `basePath` if those differ from the specification.
+
+NOTE: The `host` parameter should contain the absolute URI containing
+scheme, hostname and port number, for instance:
+`https://api.example.com`
+
+With `componentName` you specify what component is used to perform the
+requests, this named component needs to be present in the Camel context
+and implement the required _RestProducerFactory_ interface -- as do the
+components listed at the top.
+
+If you do not specify the _componentName_ at either component or
+endpoint level, CLASSPATH is searched for a suitable delegate. There
+should be only one component present on the CLASSPATH that implements
+the _RestProducerFactory_ interface for this to work.
+
+### Options
+
+// component options: START
+The REST Swagger component supports 7 options which are listed below.
+
+
+
+[width="100%",cols="2,1,1m,1m,5",options="header"]
+|=======================================================================
+| Name | Group | Default | Java Type | Description
+| basePath | producer |  | String | API basePath for example /v2. Default is unset if set overrides the value present in Swagger specification.
+| componentName | producer |  | String | Name of the Camel component that will perform the requests. The compnent must be present in Camel registry and it must implement RestProducerFactory service provider interface. If not set CLASSPATH is searched for single component that implements RestProducerFactory SPI. Can be overriden in endpoint configuration.
+| consumes | producer |  | String | 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 Swagger specification. Can be overriden in endpoint configuration
+| host | producer |  | String | Scheme hostname and port to direct the HTTP requests to in the form of <a href="https://hostname:port">https://hostname:port. Can be configured at the endpoint component or in the correspoding REST configuration in the Camel Context. If you give this component a name (e.g. petstore) that REST configuration is consulted first rest-swagger next and global configuration last. If set overrides any value found in the Swagger specification RestConfiguration. Can be overriden in endpoint configuration.
+| produces | producer |  | String | What payload type this component is producing. For example application/json according to the RFC7231. This equates to the value of Content-Type HTTP header. If set overrides any value present in the Swagger specification. Can be overriden in endpoint configuration.
+| specificationUri | producer | swagger.json | URI | Path to the Swagger specification file. The scheme host base path are taken from this specification but these can be overriden with properties on the component or endpoint level. If not given the component tries to load swagger.json resource. Note that the host defined on the component and endpoint of this Component should contain the scheme hostname and optionally the port in the URI syntax (i.e. https://api.example.com:8080). Can be overriden in endpoint configuration.
+| resolvePropertyPlaceholders | advanced | true | boolean | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders.
+|=======================================================================
+// component options: END
+
+// endpoint options: START
+The REST Swagger endpoint is configured using URI syntax:
+
+    rest-swagger:specificationUri#operationId
+
+with the following path and query parameters:
+
+#### Path Parameters (2 parameters):
+
+[width="100%",cols="2,1,1m,6",options="header"]
+|=======================================================================
+| Name | Default | Java Type | Description
+| specificationUri | swagger.json | URI | Path to the Swagger specification file. The scheme host base path are taken from this specification but these can be overriden with properties on the component or endpoint level. If not given the component tries to load swagger.json resource. Note that the host defined on the component and endpoint of this Component should contain the scheme hostname and optionally the port in the URI syntax (i.e. https://api.example.com:8080). Overrides component configuration.
+| operationId |  | String | *Required* ID of the operation from the Swagger specification.
+|=======================================================================
+
+#### Query Parameters (6 parameters):
+
+[width="100%",cols="2,1,1m,1m,5",options="header"]
+|=======================================================================
+| Name | Group | Default | Java Type | Description
+| basePath | producer |  | String | API basePath for example /v2. Default is unset if set overrides the value present in Swagger specification and in the component configuration.
+| componentName | producer |  | String | Name of the Camel component that will perform the requests. The compnent must be present in Camel registry and it must implement RestProducerFactory service provider interface. If not set CLASSPATH is searched for single component that implements RestProducerFactory SPI. Overrides component configuration.
+| consumes | producer |  | String | 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 Swagger specification and. in the component configuration
+| host | producer |  | String | Scheme hostname and port to direct the HTTP requests to in the form of <a href="https://hostname:port">https://hostname:port. Can be configured at the endpoint component or in the correspoding REST configuration in the Camel Context. If you give this component a name (e.g. petstore) that REST configuration is consulted first rest-swagger next and global configuration last. If set overrides any value found in the Swagger specification RestConfiguration. Overrides all other configuration.
+| produces | producer |  | String | What payload type this component is producing. For example application/json according to the RFC7231. This equates to the value of Content-Type HTTP header. If set overrides any value present in the Swagger specification. Overrides all other configuration.
+| synchronous | advanced | false | boolean | Sets whether synchronous processing should be strictly used or Camel is allowed to use asynchronous processing (if supported).
+|=======================================================================
+// endpoint options: END
+
+### Example: PetStore
+
+Checkout the example in the `camel-example-rest-swagger` project in
+the `examples` directory.
+
+For example if you wanted to use the
+http://petstore.swagger.io/[_PetStore_] provided REST API simply
+reference the specification URI and desired operation id from the
+Swagger specification or download the specification and store it as
+`swagger.json` (in the root) of CLASSPATH that way it will be
+automaticaly used. Let's use the link:undertow-component.html[Undertow]
+component to perform all the requests and Camels excelent support for
+link:spring-boot.html[Spring Boot].
+
+Here are our dependencies defined in Maven POM file:
+
+[source,xml]
+----
+<dependency>
+  <groupId>org.apache.camel</groupId>
+  <artifactId>camel-undertow-starter</artifactId>
+</dependency>
+
+<dependency>
+  <groupId>org.apache.camel</groupId>
+  <artifactId>camel-rest-swagger-starter</artifactId>
+</dependency>
+----
+
+Start by defining the _Undertow_ component and the
+_RestSwaggerComponent_:
+
+[source,java]
+----
+@Bean
+public Component petstore(CamelContext camelContext, UndertowComponent undertow) {
+    RestSwaggerComponent petstore = new RestSwaggerComponent(camelContext);
+    petstore.setSpecificationUri("http://petstore.swagger.io/v2/swagger.json");
+    petstore.setDelegate(undertow);
+
+    return petstore;
+}
+----
+
+NOTE: Support in Camel for Spring Boot will auto create the
+`UndertowComponent` Spring bean, and you can configure it using
+`application.properties` (or `application.yml`) using prefix
+`camel.component.undertow.`. We are defining the `petstore`
+component here in order to have a named component in the Camel context
+that we can use to interact with the PetStore REST API, if this is the
+only `rest-swagger` component used we might configure it in the same
+manner (using `application.properties`).
+
+Now in our application we can simply use the `ProducerTemplate` to
+invoke PetStore REST methods:
+
+[source,java]
+----
+@Autowired
+ProducerTemplate template;
+
+String getPetJsonById(int petId) {
+    return template.requestBodyAndHeaders("petstore:getPetById", null, "petId", petId);
+}
+----

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerComponent.java b/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerComponent.java
new file mode 100644
index 0000000..943f834
--- /dev/null
+++ b/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerComponent.java
@@ -0,0 +1,191 @@
+/**
+ * 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.rest.swagger;
+
+import java.net.URI;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.impl.DefaultComponent;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.RestProducerFactory;
+
+import static org.apache.camel.component.rest.swagger.RestSwaggerHelper.isHostParam;
+import static org.apache.camel.component.rest.swagger.RestSwaggerHelper.isMediaRange;
+import static org.apache.camel.util.ObjectHelper.notNull;
+import static org.apache.camel.util.StringHelper.notEmpty;
+
+/**
+ * An awesome REST component backed by Swagger specifications. Creates endpoints
+ * that connect to REST APIs defined by Swagger specification. This component
+ * delegates to other {@link RestProducerFactory} components to act as REST
+ * clients, but it configures them from Swagger specification. Client needs to
+ * point to operation that it wants to invoke via REST, provide any additional
+ * HTTP headers as headers in the Camel message, and any payload as the body of
+ * the incoming message.
+ * <p>
+ * Example usage using Java DSL:
+ * <p>
+ *
+ * <pre>
+ * from(...).to("rest-swagger:http://petstore.swagger.io/v2/swagger.json#getPetById")
+ * </pre>
+ *
+ * This relies on only one {@link RestProducerFactory} component being available
+ * to Camel, you can use specific, for instance preconfigured component by using
+ * the {@code componentName} endpoint property. For example using Undertow
+ * component in Java DSL:
+ * <p>
+ *
+ * <pre>
+ * Component undertow = new UndertowComponent();
+ * undertow.setSslContextParameters(...);
+ * //...
+ * camelContext.addComponent("myUndertow", undertow);
+ *
+ * from(...).to("rest-swagger:http://petstore.swagger.io/v2/swagger.json#getPetById?componentName=myUndertow")
+ * </pre>
+ *
+ * The most concise way of using this component would be to define it in the
+ * Camel context under a meaningful name, for example:
+ *
+ * <pre>
+ * Component petstore = new RestSwaggerComponent();
+ * petstore.setSpecificationUri("http://petstore.swagger.io/v2/swagger.json");
+ * petstore.setComponentName("undertow");
+ * //...
+ * camelContext.addComponent("petstore", petstore);
+ *
+ * from(...).to("petstore:getPetById")
+ * </pre>
+ */
+public final class RestSwaggerComponent extends DefaultComponent {
+    public static final String DEFAULT_BASE_PATH = "/";
+
+    static final URI DEFAULT_SPECIFICATION_URI = URI.create(RestSwaggerComponent.DEFAULT_SPECIFICATION_URI_STR);
+
+    static final String DEFAULT_SPECIFICATION_URI_STR = "swagger.json";
+
+    @Metadata(
+        description = "API basePath, for example \"`/v2`\". Default is unset, if set overrides the value present in Swagger specification.",
+        defaultValue = "", label = "producer", required = "false")
+    private String basePath = "";
+
+    @Metadata(description = "Name of the Camel component that will perform the requests. The compnent must be present"
+        + " in Camel registry and it must implement RestProducerFactory service provider interface. If not set"
+        + " CLASSPATH is searched for single component that implements RestProducerFactory SPI. Can be overriden in"
+        + " endpoint configuration.", label = "producer", required = "false")
+    private String componentName;
+
+    @Metadata(
+        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 header. If set overrides any value found in the Swagger specification."
+            + " Can be overriden in endpoint configuration",
+        label = "producer", required = "false")
+    private String consumes;
+
+    @Metadata(description = "Scheme hostname and port to direct the HTTP requests to in the form of"
+        + " `http[s]://hostname[:port]`. Can be configured at the endpoint, component or in the correspoding"
+        + " REST configuration in the Camel Context. If you give this component a name (e.g. `petstore`) that"
+        + " REST configuration is consulted first, `rest-swagger` next, and global configuration last. If set"
+        + " overrides any value found in the Swagger specification, RestConfiguration. Can be overriden in endpoint"
+        + " configuration.", label = "producer", required = "false")
+    private String host;
+
+    @Metadata(
+        description = "What payload type this component is producing. For example `application/json`"
+            + " according to the RFC7231. This equates to the value of `Content-Type` HTTP header. If set overrides"
+            + " any value present in the Swagger specification. Can be overriden in endpoint configuration.",
+        label = "producer", required = "false")
+    private String produces;
+
+    @Metadata(description = "Path to the Swagger specification file. The scheme, host base path are taken from this"
+        + " specification, but these can be overriden with properties on the component or endpoint level. If not"
+        + " given the component tries to load `swagger.json` resource. Note that the `host` defined on the"
+        + " component and endpoint of this Component should contain the scheme, hostname and optionally the"
+        + " port in the URI syntax (i.e. `https://api.example.com:8080`). Can be overriden in endpoint"
+        + " configuration.", defaultValue = DEFAULT_SPECIFICATION_URI_STR, label = "producer", required = "false")
+    private URI specificationUri;
+
+    public RestSwaggerComponent() {
+    }
+
+    public RestSwaggerComponent(final CamelContext context) {
+        super(context);
+    }
+
+    public String getBasePath() {
+        return basePath;
+    }
+
+    public String getComponentName() {
+        return componentName;
+    }
+
+    public String getConsumes() {
+        return consumes;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public String getProduces() {
+        return produces;
+    }
+
+    public URI getSpecificationUri() {
+        return specificationUri;
+    }
+
+    public void setBasePath(final String basePath) {
+        this.basePath = notEmpty(basePath, "basePath");
+    }
+
+    public void setComponentName(final String componentName) {
+        this.componentName = notEmpty(componentName, "componentName");
+    }
+
+    public void setConsumes(final String consumes) {
+        this.consumes = isMediaRange(consumes, "consumes");
+    }
+
+    public void setHost(final String host) {
+        this.host = isHostParam(host);
+    }
+
+    public void setProduces(final String produces) {
+        this.produces = isMediaRange(produces, "produces");
+    }
+
+    public void setSpecificationUri(final URI specificationUri) {
+        this.specificationUri = notNull(specificationUri, "specificationUri");
+    }
+
+    @Override
+    protected Endpoint createEndpoint(final String uri, final String remaining, final Map<String, Object> parameters)
+        throws Exception {
+        final Endpoint endpoint = new RestSwaggerEndpoint(uri, remaining, this);
+
+        setProperties(endpoint, parameters);
+
+        return endpoint;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpoint.java b/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpoint.java
new file mode 100644
index 0000000..463d534
--- /dev/null
+++ b/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpoint.java
@@ -0,0 +1,490 @@
+/**
+ * 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.rest.swagger;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import static java.util.Optional.ofNullable;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.swagger.models.HttpMethod;
+import io.swagger.models.Operation;
+import io.swagger.models.Path;
+import io.swagger.models.Scheme;
+import io.swagger.models.Swagger;
+import io.swagger.parser.SwaggerParser;
+import io.swagger.util.Json;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Consumer;
+import org.apache.camel.Endpoint;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.RestConfiguration;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriPath;
+import org.apache.camel.util.ResourceHelper;
+
+import static org.apache.camel.component.rest.swagger.RestSwaggerHelper.isHostParam;
+import static org.apache.camel.component.rest.swagger.RestSwaggerHelper.isMediaRange;
+import static org.apache.camel.util.ObjectHelper.isNotEmpty;
+import static org.apache.camel.util.ObjectHelper.notNull;
+import static org.apache.camel.util.StringHelper.after;
+import static org.apache.camel.util.StringHelper.before;
+import static org.apache.camel.util.StringHelper.notEmpty;
+
+/**
+ * An awesome REST endpoint backed by Swagger specifications.
+ */
+@UriEndpoint(firstVersion = "2.19.0", scheme = "rest-swagger", title = "REST Swagger",
+    syntax = "rest-swagger:specificationUri#operationId", label = "rest,swagger,http", producerOnly = true)
+public final class RestSwaggerEndpoint extends DefaultEndpoint {
+
+    /** The name of the Camel component, be it `rest-swagger` or `petstore` */
+    private String assignedComponentName;
+
+    @UriParam(
+        description = "API basePath, for example \"`/v2`\". Default is unset, if set overrides the value present in"
+            + " Swagger specification and in the component configuration.",
+        defaultValue = "", label = "producer")
+    @Metadata(required = "false")
+    private String basePath;
+
+    @UriParam(description = "Name of the Camel component that will perform the requests. The compnent must be present"
+        + " in Camel registry and it must implement RestProducerFactory service provider interface. If not set"
+        + " CLASSPATH is searched for single component that implements RestProducerFactory SPI. Overrides"
+        + " component configuration.", label = "producer")
+    @Metadata(required = "false")
+    private String componentName;
+
+    @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"
+            + " to the value of `Accept` HTTP header. If set overrides any value found in the Swagger specification and."
+            + " in the component configuration",
+        label = "producer")
+    private String consumes;
+
+    @UriParam(description = "Scheme hostname and port to direct the HTTP requests to in the form of"
+        + " `http[s]://hostname[:port]`. Can be configured at the endpoint, component or in the correspoding"
+        + " REST configuration in the Camel Context. If you give this component a name (e.g. `petstore`) that"
+        + " REST configuration is consulted first, `rest-swagger` next, and global configuration last. If set"
+        + " overrides any value found in the Swagger specification, RestConfiguration. Overrides all other "
+        + " configuration.", label = "producer")
+    private String host;
+
+    @UriPath(description = "ID of the operation from the Swagger specification.", label = "producer")
+    @Metadata(required = "true")
+    private String operationId;
+
+    @UriParam(description = "What payload type this component is producing. For example `application/json`"
+        + " according to the RFC7231. This equates to the value of `Content-Type` HTTP header. If set overrides"
+        + " any value present in the Swagger specification. Overrides all other configuration.", label = "producer")
+    private String produces;
+
+    @UriPath(
+        description = "Path to the Swagger specification file. The scheme, host base path are taken from this"
+            + " specification, but these can be overriden with properties on the component or endpoint level. If not"
+            + " given the component tries to load `swagger.json` resource. Note that the `host` defined on the"
+            + " component and endpoint of this Component should contain the scheme, hostname and optionally the"
+            + " port in the URI syntax (i.e. `https://api.example.com:8080`). Overrides component configuration.",
+        defaultValue = RestSwaggerComponent.DEFAULT_SPECIFICATION_URI_STR,
+        defaultValueNote = "By default loads `swagger.json` file", label = "producer")
+    private URI specificationUri = RestSwaggerComponent.DEFAULT_SPECIFICATION_URI;
+
+    public RestSwaggerEndpoint() {
+        // help tooling instantiate endpoint
+    }
+
+    public RestSwaggerEndpoint(final String uri, final String remaining, final RestSwaggerComponent component) {
+        super(notEmpty(uri, "uri"), notNull(component, "component"));
+
+        assignedComponentName = before(uri, ":");
+
+        final URI componentSpecificationUri = component.getSpecificationUri();
+
+        specificationUri = ofNullable(before(remaining, "#")).map(URI::create)
+            .orElse(ofNullable(componentSpecificationUri).orElse(RestSwaggerComponent.DEFAULT_SPECIFICATION_URI));
+
+        operationId = ofNullable(after(remaining, "#")).orElse(remaining);
+
+        setExchangePattern(ExchangePattern.InOut);
+    }
+
+    @Override
+    public Consumer createConsumer(final Processor processor) throws Exception {
+        throw new UnsupportedOperationException("Consumer not supported");
+    }
+
+    @Override
+    public Producer createProducer() throws Exception {
+        final CamelContext camelContext = getCamelContext();
+        final Swagger swagger = loadSpecificationFrom(camelContext, specificationUri);
+
+        final Map<String, Path> paths = swagger.getPaths();
+
+        for (final Entry<String, Path> pathEntry : paths.entrySet()) {
+            final Path path = pathEntry.getValue();
+
+            final Optional<Entry<HttpMethod, Operation>> maybeOperationEntry = path.getOperationMap().entrySet()
+                .stream().filter(operationEntry -> operationId.equals(operationEntry.getValue().getOperationId()))
+                .findAny();
+
+            if (maybeOperationEntry.isPresent()) {
+                final Entry<HttpMethod, Operation> operationEntry = maybeOperationEntry.get();
+
+                final String uriTemplate = pathEntry.getKey();
+
+                final HttpMethod httpMethod = operationEntry.getKey();
+                final String method = httpMethod.name();
+
+                final Operation operation = operationEntry.getValue();
+
+                return createProducerFor(swagger, operation, method, uriTemplate);
+            }
+        }
+
+        final String supportedOperations = paths.values().stream().flatMap(p -> p.getOperations().stream())
+            .map(Operation::getOperationId).collect(Collectors.joining(", "));
+
+        throw new IllegalArgumentException("The specified operation with ID: `" + operationId
+            + "` cannot be found in the Swagger specification loaded from `" + specificationUri
+            + "`. Operations defined in the specification are: " + supportedOperations);
+    }
+
+    public String getBasePath() {
+        return basePath;
+    }
+
+    public String getComponentName() {
+        return componentName;
+    }
+
+    public String getConsumes() {
+        return consumes;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public String getOperationId() {
+        return operationId;
+    }
+
+    public String getProduces() {
+        return produces;
+    }
+
+    public URI getSpecificationUri() {
+        return specificationUri;
+    }
+
+    @Override
+    public boolean isSingleton() {
+        return true;
+    }
+
+    public void setBasePath(final String basePath) {
+        this.basePath = notEmpty(basePath, "basePath");
+    }
+
+    public void setComponentName(final String componentName) {
+        this.componentName = notEmpty(componentName, "componentName");
+    }
+
+    public void setConsumes(final String consumes) {
+        this.consumes = isMediaRange(consumes, "consumes");
+    }
+
+    public void setHost(final String host) {
+        this.host = isHostParam(host);
+    }
+
+    public void setOperationId(final String operationId) {
+        this.operationId = notEmpty(operationId, "operationId");
+    }
+
+    public void setProduces(final String produces) {
+        this.produces = isMediaRange(produces, "produces");
+    }
+
+    public void setSpecificationUri(final URI specificationUri) {
+        this.specificationUri = notNull(specificationUri, "specificationUri");
+    }
+
+    RestSwaggerComponent component() {
+        return (RestSwaggerComponent) getComponent();
+    }
+
+    Producer createProducerFor(final Swagger swagger, final Operation operation, final String method,
+        final String uriTemplate) throws Exception {
+        final String basePath = determineBasePath(swagger);
+
+        final StringBuilder componentEndpointUri = new StringBuilder(200).append("rest:").append(method).append(":")
+            .append(basePath).append(":").append(uriTemplate);
+
+        final CamelContext camelContext = getCamelContext();
+
+        final Endpoint endpoint = camelContext.getEndpoint(componentEndpointUri.toString());
+
+        setProperties(endpoint, determineEndpointParameters(swagger, operation));
+
+        return endpoint.createProducer();
+    }
+
+    String determineBasePath(final Swagger swagger) {
+        if (isNotEmpty(basePath)) {
+            return basePath;
+        }
+
+        final String componentBasePath = component().getBasePath();
+        if (isNotEmpty(componentBasePath)) {
+            return componentBasePath;
+        }
+
+        final String specificationBasePath = swagger.getBasePath();
+        if (isNotEmpty(specificationBasePath)) {
+            return specificationBasePath;
+        }
+
+        final CamelContext camelContext = getCamelContext();
+        final RestConfiguration specificConfiguration = camelContext.getRestConfiguration(assignedComponentName, false);
+        if (specificConfiguration != null && isNotEmpty(specificConfiguration.getContextPath())) {
+            return specificConfiguration.getContextPath();
+        }
+
+        final RestConfiguration restConfiguration = camelContext.getRestConfiguration("rest-swagger", true);
+        final String restConfigurationBasePath = restConfiguration.getContextPath();
+        if (isNotEmpty(restConfigurationBasePath)) {
+            return restConfigurationBasePath;
+        }
+
+        return RestSwaggerComponent.DEFAULT_BASE_PATH;
+    }
+
+    String determineComponentName() {
+        return Optional.ofNullable(componentName).orElse(component().getComponentName());
+    }
+
+    Map<String, Object> determineEndpointParameters(final Swagger swagger, final Operation operation) {
+        final Map<String, Object> parameters = new HashMap<>();
+
+        final String componentName = determineComponentName();
+        if (componentName != null) {
+            parameters.put("componentName", componentName);
+        }
+
+        final String host = determineHost(swagger);
+        if (host != null) {
+            parameters.put("host", host);
+        }
+
+        // what we consume is what the API defined by Swagger specification
+        // produces
+        final String determinedConsumes = determineOption(swagger.getProduces(), operation.getProduces(),
+            component().getConsumes(), consumes);
+
+        if (isNotEmpty(determinedConsumes)) {
+            parameters.put("consumes", determinedConsumes);
+        }
+
+        // what we produce is what the API defined by Swagger specification
+        // consumes
+        final String determinedProducers = determineOption(swagger.getConsumes(), operation.getConsumes(),
+            component().getProduces(), produces);
+
+        if (isNotEmpty(determinedProducers)) {
+            parameters.put("produces", determinedProducers);
+        }
+
+        return parameters;
+    }
+
+    String determineHost(final Swagger swagger) {
+        if (isNotEmpty(host)) {
+            return host;
+        }
+
+        final String componentHost = component().getHost();
+        if (isNotEmpty(componentHost)) {
+            return componentHost;
+        }
+
+        final String swaggerScheme = pickBestScheme(specificationUri.getScheme(), swagger.getSchemes());
+        final String swaggerHost = swagger.getHost();
+
+        if (isNotEmpty(swaggerScheme) && isNotEmpty(swaggerHost)) {
+            return swaggerScheme + "://" + swaggerHost;
+        }
+
+        final CamelContext camelContext = getCamelContext();
+
+        final RestConfiguration specificRestConfiguration = camelContext.getRestConfiguration(assignedComponentName,
+            false);
+        final String specificConfigurationHost = hostFrom(specificRestConfiguration);
+        if (specificConfigurationHost != null) {
+            return specificConfigurationHost;
+        }
+
+        final RestConfiguration componentRestConfiguration = camelContext.getRestConfiguration("rest-swagger", false);
+        final String componentConfigurationHost = hostFrom(componentRestConfiguration);
+        if (componentConfigurationHost != null) {
+            return componentConfigurationHost;
+        }
+
+        final RestConfiguration globalRestConfiguration = camelContext.getRestConfiguration();
+        final String globalConfigurationHost = hostFrom(globalRestConfiguration);
+        if (globalConfigurationHost != null) {
+            return globalConfigurationHost;
+        }
+
+        final String specificationScheme = specificationUri.getScheme();
+        if (specificationUri.isAbsolute() && specificationScheme.toLowerCase().startsWith("http")) {
+            try {
+                return new URI(specificationUri.getScheme(), specificationUri.getUserInfo(), specificationUri.getHost(),
+                    specificationUri.getPort(), null, null, null).toString();
+            } catch (final URISyntaxException e) {
+                throw new IllegalStateException("Unable to create a new URI from: " + specificationUri, e);
+            }
+        }
+
+        final boolean areTheSame = "rest-swagger".equals(assignedComponentName);
+
+        throw new IllegalStateException("Unable to determine destionation host for requests. The Swagger specification"
+            + " does not specify `scheme` and `host` parameters, the specification URI is not absolute with `http` or"
+            + " `https` scheme, and no RestConfigurations configured with `scheme`, `host` and `port` were found for `"
+            + (areTheSame ? "rest-swagger` component" : assignedComponentName + "` or `rest-swagger` components")
+            + " and there is no global RestConfiguration with those properties");
+    }
+
+    static String determineOption(final List<String> specificationLevel, final List<String> operationLevel,
+        final String componentLevel, final String endpointLevel) {
+        if (isNotEmpty(endpointLevel)) {
+            return endpointLevel;
+        }
+
+        if (isNotEmpty(componentLevel)) {
+            return componentLevel;
+        }
+
+        if (operationLevel != null && !operationLevel.isEmpty()) {
+            return String.join(", ", operationLevel);
+        }
+
+        if (specificationLevel != null && !specificationLevel.isEmpty()) {
+            return String.join(", ", specificationLevel);
+        }
+
+        return null;
+    }
+
+    static String hostFrom(final RestConfiguration restConfiguration) {
+        if (restConfiguration == null) {
+            return null;
+        }
+
+        final String scheme = restConfiguration.getScheme();
+        final String host = restConfiguration.getHost();
+        final int port = restConfiguration.getPort();
+
+        if (scheme == null || host == null) {
+            return null;
+        }
+
+        final StringBuilder answer = new StringBuilder(scheme).append("://").append(host);
+        if (port > 0 && !("http".equalsIgnoreCase(scheme) && port == 80)
+            && !("https".equalsIgnoreCase(scheme) && port == 443)) {
+            answer.append(':').append(port);
+        }
+
+        return answer.toString();
+    }
+
+    /**
+     * Loads the Swagger definition model from the given path. Tries to resolve
+     * the resource using Camel's resource loading support, if it fails uses
+     * Swagger's resource loading support instead.
+     *
+     * @param uri URI of the specification
+     * @param camelContext context to use
+     * @return the specification
+     * @throws IOException
+     */
+    static Swagger loadSpecificationFrom(final CamelContext camelContext, final URI uri) throws IOException {
+        final ObjectMapper mapper = Json.mapper();
+
+        final SwaggerParser swaggerParser = new SwaggerParser();
+
+        final String uriAsString = uri.toString();
+
+        try (InputStream stream = ResourceHelper.resolveMandatoryResourceAsInputStream(camelContext, uriAsString)) {
+            final JsonNode node = mapper.readTree(stream);
+
+            return swaggerParser.read(node);
+        } catch (final IOException e) {
+            // try Swaggers loader
+            final Swagger swagger = swaggerParser.read(uriAsString);
+
+            if (swagger != null) {
+                return swagger;
+            }
+
+            throw new IllegalArgumentException("The given Swagger specification could not be loaded from `" + uri
+                + "`. Tried loading using Camel's resource resolution and using Swagger's own resource resolution."
+                + " Swagger tends to swallow exceptions while parsing, try specifying Java system property `debugParser`"
+                + " (e.g. `-DdebugParser=true`), the exception that occured when loading using Camel's resource"
+                + " loader follows", e);
+        }
+    }
+
+    static String pickBestScheme(final String specificationScheme, final List<Scheme> schemes) {
+        if (schemes != null && !schemes.isEmpty()) {
+            if (schemes.contains(Scheme.HTTPS)) {
+                return "https";
+            }
+
+            if (schemes.contains(Scheme.HTTP)) {
+                return "http";
+            }
+        }
+
+        if (specificationScheme != null) {
+            return specificationScheme;
+        }
+
+        // there is no support for WebSocket (Scheme.WS, Scheme.WSS)
+
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerHelper.java
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerHelper.java b/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerHelper.java
new file mode 100644
index 0000000..ca7e972
--- /dev/null
+++ b/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerHelper.java
@@ -0,0 +1,50 @@
+/**
+ * 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.rest.swagger;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.camel.util.StringHelper;
+
+import static org.apache.camel.util.StringHelper.notEmpty;
+
+final class RestSwaggerHelper {
+
+    private static final Pattern HOST_PATTERN = Pattern.compile("https?://[^:]+(:\\d+)?", Pattern.CASE_INSENSITIVE);
+
+    private RestSwaggerHelper() {
+        // utility class
+    }
+
+    public static String isMediaRange(final String given, final String name) {
+        return notEmpty(given, name);
+    }
+
+    static String isHostParam(final String given) {
+        final String hostUri = StringHelper.notEmpty(given, "host");
+
+        final Matcher matcher = HOST_PATTERN.matcher(given);
+
+        if (!matcher.matches()) {
+            throw new IllegalArgumentException(
+                "host must be an apsolute URI (e.g. http://api.example.com), given: `" + hostUri + "`");
+        }
+
+        return hostUri;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/src/main/resources/META-INF/LICENSE.txt
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/src/main/resources/META-INF/LICENSE.txt b/components/camel-rest-swagger/src/main/resources/META-INF/LICENSE.txt
new file mode 100755
index 0000000..6b0b127
--- /dev/null
+++ b/components/camel-rest-swagger/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/src/main/resources/META-INF/NOTICE.txt
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/src/main/resources/META-INF/NOTICE.txt b/components/camel-rest-swagger/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/components/camel-rest-swagger/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/src/main/resources/META-INF/services/org/apache/camel/component/rest-swagger
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/src/main/resources/META-INF/services/org/apache/camel/component/rest-swagger b/components/camel-rest-swagger/src/main/resources/META-INF/services/org/apache/camel/component/rest-swagger
new file mode 100644
index 0000000..f4213a9
--- /dev/null
+++ b/components/camel-rest-swagger/src/main/resources/META-INF/services/org/apache/camel/component/rest-swagger
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+class=org.apache.camel.component.rest.swagger.RestSwaggerComponent

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/Pet.java
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/Pet.java b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/Pet.java
new file mode 100644
index 0000000..50308ba
--- /dev/null
+++ b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/Pet.java
@@ -0,0 +1,28 @@
+/**
+ * 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.rest.swagger;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "Pet")
+public class Pet {
+
+    public Integer id;
+
+    public String name;
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/5b209152/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerComponentTest.java
----------------------------------------------------------------------
diff --git a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerComponentTest.java b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerComponentTest.java
new file mode 100644
index 0000000..c69649c
--- /dev/null
+++ b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerComponentTest.java
@@ -0,0 +1,152 @@
+/**
+ * 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.rest.swagger;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collections;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.rest.RestEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.post;
+import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
+
+@RunWith(Parameterized.class)
+public class RestSwaggerComponentTest extends CamelTestSupport {
+
+    @ClassRule
+    public static WireMockRule petstore = new WireMockRule(wireMockConfig().dynamicPort());
+
+    static final Object NO_BODY = null;
+
+    @Parameter
+    public String componentName;
+
+    @Before
+    public void resetWireMock() {
+        petstore.resetRequests();
+    }
+
+    @Test
+    public void shouldBeAddingPets() {
+        final Pet pet = new Pet();
+        pet.name = "Jean-Luc Picard";
+
+        final Pet created = template.requestBody("direct:addPet", pet, Pet.class);
+
+        assertNotNull(created);
+
+        assertEquals(Integer.valueOf(14), created.id);
+
+        petstore.verify(
+            postRequestedFor(urlEqualTo("/v2/pet")).withHeader("Accept", equalTo("application/xml, application/json"))
+                .withHeader("Content-Type", equalTo("application/xml")));
+    }
+
+    @Test
+    public void shouldBeGettingPetsById() {
+        final Pet pet = template.requestBodyAndHeader("direct:getPetById", NO_BODY, "petId", 14, Pet.class);
+
+        assertNotNull(pet);
+
+        assertEquals(Integer.valueOf(14), pet.id);
+        assertEquals("Olafur Eliason Arnalds", pet.name);
+
+        petstore.verify(getRequestedFor(urlEqualTo("/v2/pet/14")).withHeader("Accept",
+            equalTo("application/xml, application/json")));
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        final CamelContext camelContext = super.createCamelContext();
+
+        final RestSwaggerComponent component = new RestSwaggerComponent();
+        component.setComponentName(componentName);
+        component.setHost("http://localhost:" + petstore.port());
+
+        camelContext.addComponent("petStore", component);
+
+        return camelContext;
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                final JAXBContext jaxbContext = JAXBContext.newInstance(Pet.class);
+
+                final JaxbDataFormat jaxb = new JaxbDataFormat(jaxbContext);
+                jaxb.setJaxbProviderProperties(Collections.singletonMap(Marshaller.JAXB_FORMATTED_OUTPUT, false));
+
+                from("direct:getPetById").to("petStore:getPetById").unmarshal(jaxb);
+
+                from("direct:addPet").marshal(jaxb).to("petStore:addPet").unmarshal(jaxb);
+            }
+        };
+    }
+
+    @Parameters(name = "component = {0}")
+    public static Iterable<String> knownProducers() {
+        return Arrays.asList(RestEndpoint.DEFAULT_REST_PRODUCER_COMPONENTS);
+    }
+
+    @BeforeClass
+    public static void setupStubs() throws IOException, URISyntaxException {
+        petstore.stubFor(get(urlEqualTo("/swagger.json")).willReturn(aResponse().withBody(
+            Files.readAllBytes(Paths.get(RestSwaggerComponentTest.class.getResource("/swagger.json").toURI())))));
+
+        petstore.stubFor(post(urlEqualTo("/v2/pet"))
+            .withRequestBody(equalTo(
+                "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Pet><name>Jean-Luc Picard</name></Pet>"))
+            .willReturn(aResponse().withStatus(HttpURLConnection.HTTP_CREATED)
+                .withBody("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Pet><id>14</id></Pet>")));
+
+        petstore.stubFor(
+            get(urlEqualTo("/v2/pet/14")).willReturn(aResponse().withStatus(HttpURLConnection.HTTP_OK).withBody(
+                "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Pet><id>14</id><name>Olafur Eliason Arnalds</name></Pet>")));
+    }
+
+}