Rest DSL. camel-swagger work in progress.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/a578af93 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/a578af93 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/a578af93 Branch: refs/heads/master Commit: a578af9375b7ab86737505858801cc79362f5560 Parents: 7aa0b4a Author: Claus Ibsen <davscl...@apache.org> Authored: Sat Aug 9 10:35:20 2014 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Sat Aug 9 11:06:32 2014 +0200 ---------------------------------------------------------------------- .../component/swagger/RestSwaggerReader.scala | 194 +++++++++++-------- .../swagger/DummyRestConsumerFactory.java | 48 +++++ .../swagger/RestSwaggerReaderTest.java | 38 ++-- 3 files changed, 182 insertions(+), 98 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/a578af93/components/camel-swagger/src/main/scala/org/apache/camel/component/swagger/RestSwaggerReader.scala ---------------------------------------------------------------------- diff --git a/components/camel-swagger/src/main/scala/org/apache/camel/component/swagger/RestSwaggerReader.scala b/components/camel-swagger/src/main/scala/org/apache/camel/component/swagger/RestSwaggerReader.scala index c8e84a7..2b57013 100644 --- a/components/camel-swagger/src/main/scala/org/apache/camel/component/swagger/RestSwaggerReader.scala +++ b/components/camel-swagger/src/main/scala/org/apache/camel/component/swagger/RestSwaggerReader.scala @@ -6,7 +6,7 @@ * (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 + * 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, @@ -16,109 +16,137 @@ */ package org.apache.camel.component.swagger -import org.apache.camel.model.rest.{VerbDefinition, RestDefinition} +import java.util.Locale + import com.wordnik.swagger.config.SwaggerConfig import com.wordnik.swagger.model.{ApiDescription, Operation, ApiListing} -import org.slf4j.LoggerFactory import com.wordnik.swagger.core.util.ModelUtil import com.wordnik.swagger.core.SwaggerSpec + +import org.apache.camel.model.rest.{VerbDefinition, RestDefinition} +import org.apache.camel.util.FileUtil + import org.slf4j.LoggerFactory + import scala.collection.mutable.ListBuffer -import java.util.Locale -// to iterate using for loop +// to iterate Java list using for loop import scala.collection.JavaConverters._ class RestSwaggerReader { private val LOG = LoggerFactory.getLogger(classOf[RestSwaggerReader]) + def buildUrl(path1: String, path2: String): String = { + val s1 = FileUtil.stripTrailingSeparator(path1) + val s2 = FileUtil.stripLeadingSeparator(path2) + if (s1 != null && s2 != null) { + s1 + "/" + s2 + } else if (path1 != null) { + path1 + } else { + path2 + } + } + def read(rest: RestDefinition, config: SwaggerConfig): Option[ApiListing] = { - val api = rest.getPath - if (api != null) { - val fullPath = { - if (api.startsWith("/")) api.substring(1) - else api + val resourcePath = rest.getPath + + // create a list of apis + val apis = new ListBuffer[ApiDescription] + + // used during gathering of apis + val operations = new ListBuffer[Operation] + var path: String = null + + // must sort the verbs by uri so we group them together when an uri has multiple operations + // TODO: we want to sort /{xx} first, so we may need some regexp matching to trigger sorting them before non {} + // TODO: and then 2nd sort by http method + var list = rest.getVerbs.asScala + list = list.sortBy(v => v.getUri match { + case v: Any => v + case _ => "" + }) + + for (verb: VerbDefinition <- list) { + + if (verb.getUri != path && operations.size > 0) { + // restart + apis += ApiDescription( + buildUrl(resourcePath, path), + Some(""), + operations.toList) + operations.clear() } - val (resourcePath, subpath) = { - if (fullPath.indexOf("/") > 0) { - val pos = fullPath.indexOf("/") - ("/" + fullPath.substring(0, pos), fullPath.substring(pos)) - } - else ("/", fullPath) + + path = verb.getUri + var method = verb.asVerb().toUpperCase(Locale.US) + + var responseType = verb.getOutType match { + case e: String => e + case _ => "java.lang.Void" } - LOG.debug("read routes from classes: %s, %s".format(resourcePath, subpath)) - - val operations = new ListBuffer[Operation] - - val list = rest.getVerbs.asScala - for (verb: VerbDefinition <- list) { - - var method = verb.asVerb().toUpperCase(Locale.US) - - var responseType = verb.getOutType match { - case e: String => e - case _ => "java.lang.Void" - } - - var p = verb.getProduces - if (p == null) { - p = rest.getProduces - } - val produces = p match { - case e: String if e != "" => e.split(",").map(_.trim).toList - case _ => List() - } - - var c = verb.getConsumes - if (c == null) { - c = rest.getConsumes - } - val consumes = c match { - case e: String if e != "" => e.split(",").map(_.trim).toList - case _ => List() - } - - operations += Operation( - method, - "", - "", - responseType, - "", - 0, - produces, - consumes, - List(), - List(), - List(), - List(), - None) + var p = verb.getProduces + if (p == null) { + p = rest.getProduces + } + val produces = p match { + case e: String if e != "" => e.split(",").map(_.trim).toList + case _ => List() } - if (operations.size > 0) { - val apis = List( - ApiDescription( - "/" + fullPath, - Some(""), - operations.toList)) - val models = ModelUtil.modelsFromApis(apis) - Some( - ApiListing( - config.apiVersion, - SwaggerSpec.version, - config.basePath, - resourcePath, - List(), // produces - List(), // consumes - List(), // protocols - List(), // authorizations - ModelUtil.stripPackages(apis), - models) - ) + var c = verb.getConsumes + if (c == null) { + c = rest.getConsumes } - else None + val consumes = c match { + case e: String if e != "" => e.split(",").map(_.trim).toList + case _ => List() + } + + operations += Operation( + method, + "", + "", + responseType, + "", + 0, + produces, + consumes, + List(), + List(), + List(), + List(), + None) } + + // add remainder + if (operations.size > 0) { + apis += ApiDescription( + buildUrl(resourcePath, path), + Some(""), + operations.toList) + } + + if (apis.size > 0) { + + val models = ModelUtil.modelsFromApis(apis.toList) + Some( + ApiListing( + config.apiVersion, + SwaggerSpec.version, + config.basePath, + resourcePath, + List(), // produces + List(), // consumes + List(), // protocols + List(), // authorizations + ModelUtil.stripPackages(apis.toList), + models) + ) + } + else None } http://git-wip-us.apache.org/repos/asf/camel/blob/a578af93/components/camel-swagger/src/test/java/org/apache/camel/component/swagger/DummyRestConsumerFactory.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger/src/test/java/org/apache/camel/component/swagger/DummyRestConsumerFactory.java b/components/camel-swagger/src/test/java/org/apache/camel/component/swagger/DummyRestConsumerFactory.java new file mode 100644 index 0000000..eed969e --- /dev/null +++ b/components/camel-swagger/src/test/java/org/apache/camel/component/swagger/DummyRestConsumerFactory.java @@ -0,0 +1,48 @@ +/** + * 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.swagger; + +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.component.seda.SedaEndpoint; +import org.apache.camel.impl.ActiveMQUuidGenerator; +import org.apache.camel.spi.RestConsumerFactory; + +public class DummyRestConsumerFactory implements RestConsumerFactory { + + @Override + public Consumer createConsumer(CamelContext camelContext, Processor processor, String verb, String basePath, String uriTemplate, + String consumes, String produces, Map<String, Object> parameters) throws Exception { + // just use a seda endpoint for testing purpose + String id; + if (uriTemplate != null) { + id = ActiveMQUuidGenerator.generateSanitizedId(basePath + uriTemplate); + } else { + id = ActiveMQUuidGenerator.generateSanitizedId(basePath); + } + // remove leading dash as we add that ourselves + if (id.startsWith("-")) { + id = id.substring(1); + } + SedaEndpoint seda = camelContext.getEndpoint("seda:" + verb + "-" + id, SedaEndpoint.class); + return seda.createConsumer(processor); + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/a578af93/components/camel-swagger/src/test/java/org/apache/camel/component/swagger/RestSwaggerReaderTest.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger/src/test/java/org/apache/camel/component/swagger/RestSwaggerReaderTest.java b/components/camel-swagger/src/test/java/org/apache/camel/component/swagger/RestSwaggerReaderTest.java index 041e421..d1be9c9 100644 --- a/components/camel-swagger/src/test/java/org/apache/camel/component/swagger/RestSwaggerReaderTest.java +++ b/components/camel-swagger/src/test/java/org/apache/camel/component/swagger/RestSwaggerReaderTest.java @@ -17,38 +17,44 @@ package org.apache.camel.component.swagger; import com.wordnik.swagger.config.SwaggerConfig; +import com.wordnik.swagger.core.util.JsonSerializer; import com.wordnik.swagger.model.ApiListing; -import org.apache.camel.CamelContext; import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.impl.JndiRegistry; import org.apache.camel.model.rest.RestDefinition; -import org.junit.Ignore; +import org.apache.camel.test.junit4.CamelTestSupport; import org.junit.Test; import scala.Option; -import static org.junit.Assert.assertNotNull; +public class RestSwaggerReaderTest extends CamelTestSupport { -public class RestSwaggerReaderTest { + @Override + protected JndiRegistry createRegistry() throws Exception { + JndiRegistry jndi = super.createRegistry(); + jndi.bind("dummy-rest", new DummyRestConsumerFactory()); + return jndi; + } - @Test - @Ignore - public void testReaderRead() throws Exception { - CamelContext context = new DefaultCamelContext(); - context.addRoutes(new RouteBuilder() { + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { @Override public void configure() throws Exception { - restConfiguration().component("jetty").host("localhost").port(9090); - rest("/hello") - .get("/hi").to("log:hi"); + .get("/hi").to("log:hi") + .get("/bye").to("log:bye") + .post("/bye").to("log:bye"); } - }); - context.start(); + }; + } + @Test + public void testReaderRead() throws Exception { RestDefinition rest = context.getRestDefinitions().get(0); assertNotNull(rest); SwaggerConfig config = new SwaggerConfig(); + config.setBasePath("http://localhost:8080/api"); RestSwaggerReader reader = new RestSwaggerReader(); Option<ApiListing> option = reader.read(rest, config); assertNotNull(option); @@ -56,6 +62,8 @@ public class RestSwaggerReaderTest { assertNotNull(listing); System.out.println(listing); + String json = JsonSerializer.asJson(listing); + System.out.println(json); context.stop(); }