You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2016/02/27 16:25:22 UTC

[4/4] camel git commit: CAMEL-9652: camel-spark-rest - Add support for hosting swagger api

CAMEL-9652: camel-spark-rest - Add support for hosting swagger api


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

Branch: refs/heads/master
Commit: f22d4848573e40f4847b89b38a89efaa15a2eaab
Parents: 558747b
Author: Claus Ibsen <da...@apache.org>
Authored: Sat Feb 27 14:09:15 2016 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Sat Feb 27 16:25:10 2016 +0100

----------------------------------------------------------------------
 components/camel-spark-rest/pom.xml             |  5 ++
 .../camel/component/sparkrest/CamelSpark.java   |  1 +
 .../sparkrest/DefaultSparkBinding.java          | 23 +++++-
 .../component/sparkrest/SparkComponent.java     | 26 +++++--
 .../component/sparkrest/SparkConsumer.java      |  5 ++
 .../component/sparkrest/SparkEndpoint.java      | 18 ++++-
 .../component/sparkrest/RestApiSparkTest.java   | 73 ++++++++++++++++++++
 7 files changed, 144 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/f22d4848/components/camel-spark-rest/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-spark-rest/pom.xml b/components/camel-spark-rest/pom.xml
index 29ee6e7..a57caf3 100644
--- a/components/camel-spark-rest/pom.xml
+++ b/components/camel-spark-rest/pom.xml
@@ -89,6 +89,11 @@
       <artifactId>camel-http</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-swagger-java</artifactId>
+      <scope>test</scope>
+    </dependency>
 
     <!-- for testing rest-dsl -->
     <dependency>

http://git-wip-us.apache.org/repos/asf/camel/blob/f22d4848/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/CamelSpark.java
----------------------------------------------------------------------
diff --git a/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/CamelSpark.java b/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/CamelSpark.java
index c5e317d..df631df 100644
--- a/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/CamelSpark.java
+++ b/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/CamelSpark.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.sparkrest;
 
+import spark.Filter;
 import spark.Route;
 import spark.Spark;
 

http://git-wip-us.apache.org/repos/asf/camel/blob/f22d4848/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/DefaultSparkBinding.java
----------------------------------------------------------------------
diff --git a/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/DefaultSparkBinding.java b/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/DefaultSparkBinding.java
index 3efa003..e721baa 100644
--- a/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/DefaultSparkBinding.java
+++ b/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/DefaultSparkBinding.java
@@ -23,6 +23,7 @@ import java.io.StringWriter;
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.util.Iterator;
+import java.util.Locale;
 import java.util.Map;
 
 import org.apache.camel.Exchange;
@@ -33,6 +34,7 @@ import org.apache.camel.util.ExchangeHelper;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.MessageHelper;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.URISupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import spark.Request;
@@ -69,9 +71,28 @@ public class DefaultSparkBinding implements SparkBinding {
         headers.put(Exchange.HTTP_QUERY, request.raw().getQueryString());
         headers.put(Exchange.HTTP_URL, request.raw().getRequestURL().toString());
         headers.put(Exchange.HTTP_URI, request.raw().getRequestURI());
-        headers.put(Exchange.HTTP_PATH, request.raw().getPathInfo());
         headers.put(Exchange.CONTENT_TYPE, request.raw().getContentType());
 
+        String path = request.raw().getPathInfo();
+        SparkEndpoint endpoint = (SparkEndpoint) exchange.getFromEndpoint();
+        if (endpoint.getPath() != null) {
+            // need to match by lower case as we want to ignore case on context-path
+            String endpointPath = endpoint.getPath();
+            String matchPath = path.toLowerCase(Locale.US);
+            String match = endpointPath.toLowerCase(Locale.US);
+
+            if (match.endsWith("/*")) {
+                match = match.substring(0, match.length() - 2);
+            }
+            if (!match.startsWith("/")) {
+                match = "/" + match;
+            }
+            if (matchPath.startsWith(match)) {
+                path = path.substring(match.length());
+            }
+        }
+        headers.put(Exchange.HTTP_PATH, path);
+
         for (String key : request.attributes()) {
             Object value = request.attribute(key);
             Object decoded = shouldUrlDecodeHeader(configuration, key, value, "UTF-8");

http://git-wip-us.apache.org/repos/asf/camel/blob/f22d4848/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkComponent.java b/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkComponent.java
index 51c553f..5484fd7 100644
--- a/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkComponent.java
+++ b/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkComponent.java
@@ -26,13 +26,14 @@ import org.apache.camel.Consumer;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Processor;
 import org.apache.camel.impl.UriEndpointComponent;
+import org.apache.camel.spi.RestApiConsumerFactory;
 import org.apache.camel.spi.RestConfiguration;
 import org.apache.camel.spi.RestConsumerFactory;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.URISupport;
 
-public class SparkComponent extends UriEndpointComponent implements RestConsumerFactory {
+public class SparkComponent extends UriEndpointComponent implements RestConsumerFactory, RestApiConsumerFactory {
 
     private final Pattern pattern = Pattern.compile("\\{(.*?)\\}");
 
@@ -237,6 +238,18 @@ public class SparkComponent extends UriEndpointComponent implements RestConsumer
     @Override
     public Consumer createConsumer(CamelContext camelContext, Processor processor, String verb, String basePath, String uriTemplate,
                                    String consumes, String produces, RestConfiguration configuration, Map<String, Object> parameters) throws Exception {
+        return doCreateConsumer(camelContext, processor, verb, basePath, uriTemplate, consumes, produces, configuration, parameters, false);
+    }
+
+    @Override
+    public Consumer createApiConsumer(CamelContext camelContext, Processor processor, String contextPath,
+                                      RestConfiguration configuration, Map<String, Object> parameters) throws Exception {
+        // reuse the createConsumer method we already have. The api need to use GET and match on uri prefix
+        return doCreateConsumer(camelContext, processor, "get", contextPath, null, null, null, configuration, parameters, true);
+    }
+
+    Consumer doCreateConsumer(CamelContext camelContext, Processor processor, String verb, String basePath, String uriTemplate,
+                              String consumes, String produces, RestConfiguration configuration, Map<String, Object> parameters, boolean api) throws Exception {
 
         String path = basePath;
         if (uriTemplate != null) {
@@ -280,11 +293,16 @@ public class SparkComponent extends UriEndpointComponent implements RestConsumer
             }
         }
 
-        String uri = String.format("spark-rest:%s:%s", verb, path);
+        String url;
+        if (api) {
+            url = "spark-rest:%s:%s?matchOnUriPrefix=true";
+        } else {
+            url = "spark-rest:%s:%s";
+        }
 
-        String query = URISupport.createQueryString(map);
+        url = String.format(url, verb, path);
 
-        String url = uri;
+        String query = URISupport.createQueryString(map);
         if (!query.isEmpty()) {
             url = url + "?" + query;
         }

http://git-wip-us.apache.org/repos/asf/camel/blob/f22d4848/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkConsumer.java
----------------------------------------------------------------------
diff --git a/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkConsumer.java b/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkConsumer.java
index 1786700..d3191f2 100644
--- a/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkConsumer.java
+++ b/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkConsumer.java
@@ -41,6 +41,7 @@ public class SparkConsumer extends DefaultConsumer {
         String verb = getEndpoint().getVerb();
         String path = getEndpoint().getPath();
         String accept = getEndpoint().getAccept();
+        boolean matchOnUriPrefix = getEndpoint().isMatchOnUriPrefix();
 
         if (accept != null) {
             log.debug("Spark-rest: {}({}) accepting: {}", new Object[]{verb, path, accept});
@@ -48,6 +49,10 @@ public class SparkConsumer extends DefaultConsumer {
             log.debug("Spark-rest: {}({})", verb, path);
         }
         CamelSpark.spark(verb, path, accept, route);
+
+        if (matchOnUriPrefix) {
+            CamelSpark.spark(verb, path + "/*", accept, route);
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/f22d4848/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkEndpoint.java b/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkEndpoint.java
index af5c9b2..3e8df90 100644
--- a/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkEndpoint.java
+++ b/components/camel-spark-rest/src/main/java/org/apache/camel/component/sparkrest/SparkEndpoint.java
@@ -43,6 +43,8 @@ public class SparkEndpoint extends DefaultEndpoint {
     private SparkConfiguration sparkConfiguration;
     @UriParam
     private SparkBinding sparkBinding;
+    @UriParam
+    private boolean matchOnUriPrefix;
 
     public SparkEndpoint(String endpointUri, Component component) {
         super(endpointUri, component);
@@ -103,6 +105,17 @@ public class SparkEndpoint extends DefaultEndpoint {
         this.accept = accept;
     }
 
+    public boolean isMatchOnUriPrefix() {
+        return matchOnUriPrefix;
+    }
+
+    /**
+     * Whether or not the consumer should try to find a target consumer by matching the URI prefix if no exact match is found.
+     */
+    public void setMatchOnUriPrefix(boolean matchOnUriPrefix) {
+        this.matchOnUriPrefix = matchOnUriPrefix;
+    }
+
     @Override
     public Producer createProducer() throws Exception {
         throw new UnsupportedOperationException("Producer not supported");
@@ -128,7 +141,8 @@ public class SparkEndpoint extends DefaultEndpoint {
         ObjectHelper.notEmpty(verb, "verb", this);
         ObjectHelper.notEmpty(path, "path", this);
 
-        // verb must be supported by Spark
-        HttpMethod.valueOf(verb);
+        // verb must be supported by Spark and lets convert to the actual name
+        HttpMethod method = getCamelContext().getTypeConverter().mandatoryConvertTo(HttpMethod.class, verb);
+        verb = method.name();
     }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/f22d4848/components/camel-spark-rest/src/test/java/org/apache/camel/component/sparkrest/RestApiSparkTest.java
----------------------------------------------------------------------
diff --git a/components/camel-spark-rest/src/test/java/org/apache/camel/component/sparkrest/RestApiSparkTest.java b/components/camel-spark-rest/src/test/java/org/apache/camel/component/sparkrest/RestApiSparkTest.java
new file mode 100644
index 0000000..8295939
--- /dev/null
+++ b/components/camel-spark-rest/src/test/java/org/apache/camel/component/sparkrest/RestApiSparkTest.java
@@ -0,0 +1,73 @@
+/**
+ * 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.sparkrest;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.model.rest.RestParamType;
+import org.junit.Test;
+
+public class RestApiSparkTest extends BaseSparkTest {
+
+    @Override
+    protected boolean useJmx() {
+        return true;
+    }
+
+    @Test
+    public void testApi() throws Exception {
+        String out = template.requestBody("http://localhost:" + getPort() + "/api-doc", null, String.class);
+        assertNotNull(out);
+        assertTrue(out.contains("\"version\" : \"1.2.3\""));
+        assertTrue(out.contains("\"title\" : \"The hello rest thing\""));
+        assertTrue(out.contains("\"/hello/bye/{name}\""));
+        assertTrue(out.contains("\"/hello/hi/{name}\""));
+        assertTrue(out.contains("\"summary\" : \"To update the greeting message\""));
+
+        // regular REST service should still work
+        out = template.requestBody("http://localhost:" + getPort() + "/hello/hi/world", null, String.class);
+        assertEquals("Hello World", out);
+
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                restConfiguration().component("spark-rest").host("localhost").port(getPort()).apiContextPath("/api-doc")
+                        .apiProperty("cors", "true").apiProperty("api.title", "The hello rest thing").apiProperty("api.version", "1.2.3");
+
+                rest("/hello").consumes("application/json").produces("application/json")
+                    .get("/hi/{name}").description("Saying hi")
+                        .param().name("name").type(RestParamType.path).dataType("string").description("Who is it").endParam()
+                        .to("direct:hello")
+                    .get("/bye/{name}").description("Saying bye")
+                        .param().name("name").type(RestParamType.path).dataType("string").description("Who is it").endParam()
+                        .responseMessage().code(200).message("A reply message").endResponseMessage()
+                        .to("log:bye")
+                    .post("/bye").description("To update the greeting message").consumes("application/xml").produces("application/xml")
+                        .param().name("greeting").type(RestParamType.body).dataType("string").description("Message to use as greeting").endParam()
+                        .to("log:bye");
+
+                from("direct:hello")
+                        .transform().constant("Hello World");
+
+            }
+        };
+    }
+
+}