CAMEL-10164: swagger component for making rest calls with swagger schema validation and facade to actual HTTP client in use
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/b2508f19 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/b2508f19 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/b2508f19 Branch: refs/heads/master Commit: b2508f1961d900558eb22387ec28f4c35c510e0b Parents: adde56a Author: Claus Ibsen <[email protected]> Authored: Wed Aug 24 14:15:53 2016 +0200 Committer: Claus Ibsen <[email protected]> Committed: Fri Aug 26 16:53:31 2016 +0200 ---------------------------------------------------------------------- .../component/jetty/JettyHttpComponent.java | 40 +++++++++++++- .../rest/producer/JettyRestProducerGetTest.java | 57 ++++++++++++++++++++ .../src/test/resources/hello-api.json | 26 +++++++++ .../src/test/resources/log4j2.properties | 1 + .../swagger/component/SwaggerProducer.java | 2 + .../swagger/RestSwaggerReaderApiDocsTest.java | 1 - .../component/DummyRestProducerFactory.java | 6 ++- 7 files changed, 129 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/b2508f19/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java ---------------------------------------------------------------------- diff --git a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java index 8e06626..b1972fc 100644 --- a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java +++ b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java @@ -38,7 +38,9 @@ import javax.servlet.http.HttpServletResponse; import org.apache.camel.CamelContext; import org.apache.camel.Consumer; import org.apache.camel.Endpoint; +import org.apache.camel.Exchange; import org.apache.camel.Processor; +import org.apache.camel.Producer; import org.apache.camel.RuntimeCamelException; import org.apache.camel.http.common.CamelServlet; import org.apache.camel.http.common.HttpBinding; @@ -55,11 +57,12 @@ import org.apache.camel.spi.Metadata; import org.apache.camel.spi.RestApiConsumerFactory; import org.apache.camel.spi.RestConfiguration; import org.apache.camel.spi.RestConsumerFactory; -import org.apache.camel.spi.UriParam; +import org.apache.camel.spi.RestProducerFactory; import org.apache.camel.util.FileUtil; import org.apache.camel.util.HostUtils; import org.apache.camel.util.IntrospectionSupport; import org.apache.camel.util.ObjectHelper; +import org.apache.camel.util.StringHelper; import org.apache.camel.util.URISupport; import org.apache.camel.util.UnsafeUriCharactersEncoder; import org.apache.camel.util.jsse.SSLContextParameters; @@ -95,7 +98,7 @@ import org.slf4j.LoggerFactory; * * @version */ -public abstract class JettyHttpComponent extends HttpCommonComponent implements RestConsumerFactory, RestApiConsumerFactory { +public abstract class JettyHttpComponent extends HttpCommonComponent implements RestConsumerFactory, RestApiConsumerFactory, RestProducerFactory { public static final String TMP_DIR = "CamelJettyTempDir"; protected static final HashMap<String, ConnectorRef> CONNECTORS = new HashMap<String, ConnectorRef>(); @@ -1147,6 +1150,39 @@ public abstract class JettyHttpComponent extends HttpCommonComponent implements return consumer; } + @Override + public Producer createProducer(CamelContext camelContext, Exchange exchange, String scheme, String host, + String verb, String basePath, String uriTemplate, String queryParameters, + String consumes, String produces, Map<String, Object> parameters) throws Exception { + + // avoid leading slash + basePath = FileUtil.stripLeadingSeparator(basePath); + uriTemplate = FileUtil.stripLeadingSeparator(uriTemplate); + + // does the uri template use placeholders? + if (uriTemplate.contains("{")) { + // us a header for the dynamic uri template so we reuse same endpoint + // TODO: fix me later + String path = StringHelper.replaceAll(uriTemplate, "{name}", "Donald Duck"); + String overrideUri = String.format("%s://%s/%s/%s", scheme, host, basePath, path); + exchange.getIn().setHeader(Exchange.HTTP_URI, overrideUri); + } + + // get the endpoint + String url = "jetty:%s://%s/%s/%s"; + url = String.format(url, scheme, host, basePath, uriTemplate); + if (queryParameters != null) { + url = url + "&" + queryParameters; + } + + JettyHttpEndpoint endpoint = camelContext.getEndpoint(url, JettyHttpEndpoint.class); + if (parameters != null && !parameters.isEmpty()) { + setProperties(camelContext, endpoint, parameters); + } + + return endpoint.createProducer(); + } + protected CamelServlet createServletForConnector(Server server, Connector connector, List<Handler> handlers, JettyHttpEndpoint endpoint) throws Exception { ServletContextHandler context = new ServletContextHandler(server, "/", ServletContextHandler.NO_SECURITY | ServletContextHandler.NO_SESSIONS); http://git-wip-us.apache.org/repos/asf/camel/blob/b2508f19/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/producer/JettyRestProducerGetTest.java ---------------------------------------------------------------------- diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/producer/JettyRestProducerGetTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/producer/JettyRestProducerGetTest.java new file mode 100644 index 0000000..69422d1 --- /dev/null +++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/producer/JettyRestProducerGetTest.java @@ -0,0 +1,57 @@ +/** + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.jetty.rest.producer; + +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.jetty.BaseJettyTest; +import org.apache.camel.swagger.component.SwaggerComponent; +import org.junit.Test; + +public class JettyRestProducerGetTest extends BaseJettyTest { + + @Test + public void testSwaggerGet() throws Exception { + getMockEndpoint("mock:result").expectedBodiesReceived("Hello Donald Duck"); + + template.sendBodyAndHeader("direct:start", null, "name", "Donald Duck"); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + SwaggerComponent sc = new SwaggerComponent(); + sc.setComponentName("jetty"); + context.addComponent("swagger", sc); + + String host = "localhost:" + getPort(); + + from("direct:start") + .to("swagger:hello-api.json:get:hello/hi/{name}?host=" + host) + .to("mock:result"); + + from("jetty:http://localhost:{{port}}/api/hello/hi/?matchOnUriPrefix=true") + .transform().constant("Hello Donald Duck"); + } + }; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/b2508f19/components/camel-jetty9/src/test/resources/hello-api.json ---------------------------------------------------------------------- diff --git a/components/camel-jetty9/src/test/resources/hello-api.json b/components/camel-jetty9/src/test/resources/hello-api.json new file mode 100644 index 0000000..82d61f8 --- /dev/null +++ b/components/camel-jetty9/src/test/resources/hello-api.json @@ -0,0 +1,26 @@ +{ + "swagger" : "2.0", + "host" : "localhost:8080", + "basePath" : "/api", + "tags" : [ { + "name" : "hello" + } ], + "schemes" : [ "http" ], + "paths" : { + "/hello/hi/{name}" : { + "get" : { + "tags" : [ "hello" ], + "summary" : "Saying hi", + "consumes" : [ "application/json" ], + "produces" : [ "application/json" ], + "parameters" : [ { + "name" : "name", + "in" : "path", + "description" : "Who is it", + "required" : true, + "type" : "string" + } ] + } + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/b2508f19/components/camel-jetty9/src/test/resources/log4j2.properties ---------------------------------------------------------------------- diff --git a/components/camel-jetty9/src/test/resources/log4j2.properties b/components/camel-jetty9/src/test/resources/log4j2.properties index c863dc3..b91c7b3 100644 --- a/components/camel-jetty9/src/test/resources/log4j2.properties +++ b/components/camel-jetty9/src/test/resources/log4j2.properties @@ -25,4 +25,5 @@ appender.out.name = out appender.out.layout.type = PatternLayout appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n rootLogger.level = INFO +rootLogger.appenderRef.out.ref = out rootLogger.appenderRef.file.ref = file http://git-wip-us.apache.org/repos/asf/camel/blob/b2508f19/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/component/SwaggerProducer.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/component/SwaggerProducer.java b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/component/SwaggerProducer.java index 019bdd3..1456dc5 100644 --- a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/component/SwaggerProducer.java +++ b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/component/SwaggerProducer.java @@ -37,6 +37,7 @@ import org.apache.camel.impl.DefaultAsyncProducer; import org.apache.camel.spi.RestProducerFactory; import org.apache.camel.util.AsyncProcessorConverterHelper; import org.apache.camel.util.CollectionStringBuffer; +import org.apache.camel.util.ServiceHelper; import org.apache.camel.util.URISupport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -100,6 +101,7 @@ public class SwaggerProducer extends DefaultAsyncProducer { // TODO: create the producer once and reuse (create HTTP_XXX headers for dynamic values) Producer producer = createHttpProducer(exchange, operation, verb, path, options); if (producer != null) { + ServiceHelper.startService(producer); AsyncProcessor async = AsyncProcessorConverterHelper.convert(producer); return async.process(exchange, callback); } http://git-wip-us.apache.org/repos/asf/camel/blob/b2508f19/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerReaderApiDocsTest.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerReaderApiDocsTest.java b/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerReaderApiDocsTest.java index e1a31ed..14a7bf2 100644 --- a/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerReaderApiDocsTest.java +++ b/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerReaderApiDocsTest.java @@ -74,7 +74,6 @@ public class RestSwaggerReaderApiDocsTest extends CamelTestSupport { String json = mapper.writeValueAsString(swagger); log.info(json); - System.out.println(json); assertTrue(json.contains("\"host\" : \"localhost:8080\"")); assertTrue(json.contains("\"basePath\" : \"/api\"")); http://git-wip-us.apache.org/repos/asf/camel/blob/b2508f19/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/component/DummyRestProducerFactory.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/component/DummyRestProducerFactory.java b/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/component/DummyRestProducerFactory.java index d960dbe..d092f16 100644 --- a/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/component/DummyRestProducerFactory.java +++ b/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/component/DummyRestProducerFactory.java @@ -19,6 +19,7 @@ package org.apache.camel.swagger.component; import java.util.Map; import org.apache.camel.CamelContext; +import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Producer; import org.apache.camel.impl.DefaultProducer; @@ -31,7 +32,10 @@ public class DummyRestProducerFactory implements RestProducerFactory { String verb, String basePath, final String uriTemplate, final String queryParameters, String consumes, String produces, Map<String, Object> parameters) throws Exception { - return new DefaultProducer(null) { + // use a dummy endpoint + Endpoint endpoint = camelContext.getEndpoint("stub:dummy"); + + return new DefaultProducer(endpoint) { @Override public void process(Exchange exchange) throws Exception { // for testing purpose, check if we have {name} in template
