CAMEL-8545: camel-swagger-java to run outside servlet - 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/3818efe3 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/3818efe3 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/3818efe3 Branch: refs/heads/master Commit: 3818efe3ee2d1061134df37489d2f3a0dc100ea1 Parents: 8ce5a2b Author: Claus Ibsen <davscl...@apache.org> Authored: Tue Sep 22 14:07:39 2015 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Wed Sep 23 07:51:03 2015 +0200 ---------------------------------------------------------------------- .../swagger/RestSwaggerAbstractServlet.java | 241 ------------------- .../camel/swagger/RestSwaggerCorsFilter.java | 55 ----- .../camel/swagger/RestSwaggerServlet.java | 91 ------- .../camel/swagger/RestSwaggerSupport.java | 209 ++++++++++++++++ .../swagger/servlet/RestSwaggerCorsFilter.java | 55 +++++ .../swagger/servlet/RestSwaggerServlet.java | 127 ++++++++++ .../servlet/ServletSwaggerApiProvider.java | 55 +++++ .../camel/swagger/spi/SwaggerApiProvider.java | 32 +++ .../src/main/webapp/WEB-INF/web.xml | 6 +- 9 files changed, 481 insertions(+), 390 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/3818efe3/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerAbstractServlet.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerAbstractServlet.java b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerAbstractServlet.java deleted file mode 100644 index a0a1a76..0000000 --- a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerAbstractServlet.java +++ /dev/null @@ -1,241 +0,0 @@ -/** - * 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.swagger; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.List; -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import io.swagger.jaxrs.config.BeanConfig; -import io.swagger.models.Contact; -import io.swagger.models.Info; -import io.swagger.models.License; -import io.swagger.models.Swagger; -import org.apache.camel.impl.DefaultClassResolver; -import org.apache.camel.model.rest.RestDefinition; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import static org.apache.camel.swagger.SwaggerHelper.buildUrl; - -/** - * Base class for rest-dsl swagger integration to use a servlet to service the swagger api. - */ -public abstract class RestSwaggerAbstractServlet extends HttpServlet { - - private Logger LOG = LoggerFactory.getLogger(RestSwaggerAbstractServlet.class); - - private RestSwaggerReader reader = new RestSwaggerReader(); - private BeanConfig swaggerConfig = new BeanConfig(); - private boolean cors; - private volatile boolean initDone; - - @Override - public void init(ServletConfig config) throws ServletException { - super.init(config); - - // configure swagger options - String s = config.getInitParameter("swagger.version"); - if (s != null) { - swaggerConfig.setVersion(s); - } - s = config.getInitParameter("base.path"); - if (s != null) { - swaggerConfig.setBasePath(s); - } - s = config.getInitParameter("host"); - if (s != null) { - swaggerConfig.setHost(s); - } - s = config.getInitParameter("cors"); - if (s != null) { - cors = "true".equalsIgnoreCase(s); - } - s = config.getInitParameter("schemas"); - if (s != null) { - String[] schemas = s.split(","); - swaggerConfig.setSchemes(schemas); - } else { - // assume http by default - swaggerConfig.setSchemes(new String[]{"http"}); - } - - String version = config.getInitParameter("api.version"); - String title = config.getInitParameter("api.title"); - String description = config.getInitParameter("api.description"); - String termsOfService = config.getInitParameter("api.termsOfService"); - String licenseName = config.getInitParameter("api.license.name"); - String licenseUrl = config.getInitParameter("api.license.url"); - String contactName = config.getInitParameter("api.contact.name"); - String contactUrl = config.getInitParameter("api.contact.url"); - String contactEmail = config.getInitParameter("api.contact.email"); - - Info info = new Info(); - info.setVersion(version); - info.setTitle(title); - info.setDescription(description); - info.setTermsOfService(termsOfService); - - if (licenseName != null || licenseUrl != null) { - License license = new License(); - license.setName(licenseName); - license.setUrl(licenseUrl); - info.setLicense(license); - } - - if (contactName != null || contactUrl != null || contactEmail != null) { - Contact contact = new Contact(); - contact.setName(contactName); - contact.setUrl(contactUrl); - contact.setEmail(contactEmail); - info.setContact(contact); - } - - swaggerConfig.setInfo(info); - } - - public abstract List<RestDefinition> getRestDefinitions(String camelId) throws Exception; - - public abstract List<String> findCamelContexts() throws Exception; - - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - - if (!initDone) { - initBaseAndApiPaths(request); - } - - String contextId; - String route = request.getPathInfo(); - - try { - - // render list of camel contexts as root - if (route == null || route.equals("") || route.equals("/")) { - renderCamelContexts(request, response); - } else { - // first part is the camel context - if (route.startsWith("/")) { - route = route.substring(1); - } - // the remainder is the route part - contextId = route.split("/")[0]; - if (route.startsWith(contextId)) { - route = route.substring(contextId.length()); - } - - renderResourceListing(request, response, contextId, route); - } - } catch (Exception e) { - LOG.warn("Error rendering swagger due " + e.getMessage(), e); - } - } - - private void renderResourceListing(HttpServletRequest request, HttpServletResponse response, String contextId, String route) throws Exception { - LOG.trace("renderResourceListing"); - - if (cors) { - response.addHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"); - response.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH"); - response.addHeader("Access-Control-Allow-Origin", "*"); - } - - List<RestDefinition> rests = getRestDefinitions(contextId); - if (rests != null) { - // read the rest-dsl into swagger model - Swagger swagger = reader.read(rests, route, swaggerConfig, new DefaultClassResolver()); - - ObjectMapper mapper = new ObjectMapper(); - mapper.enable(SerializationFeature.INDENT_OUTPUT); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - mapper.writeValue(response.getOutputStream(), swagger); - } else { - response.setStatus(204); - } - } - - private void initBaseAndApiPaths(HttpServletRequest request) throws MalformedURLException { - String base = swaggerConfig.getBasePath(); - if (base == null || !base.startsWith("http")) { - // base path is configured using relative, so lets calculate the absolute url now we have the http request - URL url = new URL(request.getRequestURL().toString()); - if (base == null) { - base = ""; - } - String path = translateContextPath(request); - swaggerConfig.setHost(url.getHost()); - - if (url.getPort() != 80 && url.getPort() != -1) { - swaggerConfig.setHost(url.getHost() + ":" + url.getPort()); - } else { - swaggerConfig.setHost(url.getHost()); - } - swaggerConfig.setBasePath(buildUrl(path, base)); - } - initDone = true; - } - - /** - * We do only want the base context-path and not sub paths - */ - private String translateContextPath(HttpServletRequest request) { - String path = request.getContextPath(); - if (path.isEmpty() || path.equals("/")) { - return ""; - } else { - int idx = path.lastIndexOf("/"); - if (idx > 0) { - return path.substring(0, idx); - } - } - return path; - } - - /** - * Renders a list of available CamelContexts in the JVM - */ - private void renderCamelContexts(HttpServletRequest request, HttpServletResponse response) throws Exception { - LOG.trace("renderCamelContexts"); - - if (cors) { - response.addHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"); - response.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH"); - response.addHeader("Access-Control-Allow-Origin", "*"); - } - - List<String> contexts = findCamelContexts(); - response.getWriter().print("[\n"); - for (int i = 0; i < contexts.size(); i++) { - String name = contexts.get(i); - response.getWriter().print("{\"name\": \"" + name + "\"}"); - if (i < contexts.size() - 1) { - response.getWriter().print(",\n"); - } - } - response.getWriter().print("\n]"); - } - -} http://git-wip-us.apache.org/repos/asf/camel/blob/3818efe3/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerCorsFilter.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerCorsFilter.java b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerCorsFilter.java deleted file mode 100644 index 0cf7303..0000000 --- a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerCorsFilter.java +++ /dev/null @@ -1,55 +0,0 @@ -/** - * 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.swagger; - -import java.io.IOException; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; - -/** - * A simple CORS filter that can used to allow the swagger ui or other API browsers from remote origins to access the - * Rest services exposes by this Camel swagger component. - */ -public class RestSwaggerCorsFilter implements Filter { - - @Override - public void init(FilterConfig filterConfig) throws ServletException { - // noop - } - - @Override - public void destroy() { - // noop - } - - @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - HttpServletResponse res = (HttpServletResponse) response; - - res.setHeader("Access-Control-Allow-Origin", "*"); - res.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH"); - res.setHeader("Access-Control-Max-Age", "3600"); - res.setHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"); - - chain.doFilter(request, response); - } -} http://git-wip-us.apache.org/repos/asf/camel/blob/3818efe3/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerServlet.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerServlet.java b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerServlet.java deleted file mode 100644 index 7d85e76..0000000 --- a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerServlet.java +++ /dev/null @@ -1,91 +0,0 @@ -/** - * 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.swagger; - -import java.lang.management.ManagementFactory; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import javax.management.MBeanServer; -import javax.management.ObjectName; - -import org.apache.camel.model.ModelHelper; -import org.apache.camel.model.rest.RestDefinition; -import org.apache.camel.model.rest.RestsDefinition; -import org.apache.camel.util.CamelVersionHelper; - -/** - * The default Camel swagger servlet to use when exposing the APIs of the rest-dsl using swagger. - * <p/> - * This requires Camel version 2.15 or better at runtime (and JMX to be enabled). - */ -public class RestSwaggerServlet extends RestSwaggerAbstractServlet { - - @Override - public List<RestDefinition> getRestDefinitions(String camelId) throws Exception { - ObjectName found = null; - - MBeanServer server = ManagementFactory.getPlatformMBeanServer(); - Set<ObjectName> names = server.queryNames(new ObjectName("org.apache.camel:type=context,*"), null); - for (ObjectName on : names) { - String id = on.getKeyProperty("name"); - if (id.startsWith("\"") && id.endsWith("\"")) { - id = id.substring(1, id.length() - 1); - } - if (camelId == null || camelId.equals(id)) { - // filter out older Camel versions as this requires Camel 2.15 or better (rest-dsl) - String version = (String) server.getAttribute(on, "CamelVersion"); - if (CamelVersionHelper.isGE("2.15.0", version)) { - found = on; - } - } - } - - if (found != null) { - String xml = (String) server.invoke(found, "dumpRestsAsXml", null, null); - if (xml != null) { - RestsDefinition rests = ModelHelper.createModelFromXml(null, xml, RestsDefinition.class); - if (rests != null) { - return rests.getRests(); - } - } - } - - return null; - } - - @Override - public List<String> findCamelContexts() throws Exception { - List<String> answer = new ArrayList<>(); - - MBeanServer server = ManagementFactory.getPlatformMBeanServer(); - Set<ObjectName> names = server.queryNames(new ObjectName("*:type=context,*"), null); - for (ObjectName on : names) { - String id = on.getKeyProperty("name"); - if (id.startsWith("\"") && id.endsWith("\"")) { - id = id.substring(1, id.length() - 1); - } - - // filter out older Camel versions as this requires Camel 2.15 or better (rest-dsl) - String version = (String) server.getAttribute(on, "CamelVersion"); - if (CamelVersionHelper.isGE("2.15.0", version)) { - answer.add(id); - } - } - return answer; - } -} http://git-wip-us.apache.org/repos/asf/camel/blob/3818efe3/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerSupport.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerSupport.java b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerSupport.java new file mode 100644 index 0000000..6b7f56d --- /dev/null +++ b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerSupport.java @@ -0,0 +1,209 @@ +/** + * 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.swagger; + +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import io.swagger.jaxrs.config.BeanConfig; +import io.swagger.models.Contact; +import io.swagger.models.Info; +import io.swagger.models.License; +import io.swagger.models.Swagger; +import org.apache.camel.impl.DefaultClassResolver; +import org.apache.camel.model.ModelHelper; +import org.apache.camel.model.rest.RestDefinition; +import org.apache.camel.model.rest.RestsDefinition; +import org.apache.camel.swagger.spi.SwaggerApiProvider; +import org.apache.camel.util.CamelVersionHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RestSwaggerSupport { + + private static final Logger LOG = LoggerFactory.getLogger(RestSwaggerSupport.class); + private RestSwaggerReader reader = new RestSwaggerReader(); + private boolean cors; + + public void initSwagger(BeanConfig swaggerConfig, SwaggerApiProvider config) { + // configure swagger options + String s = config.getInitParameter("swagger.version"); + if (s != null) { + swaggerConfig.setVersion(s); + } + s = config.getInitParameter("base.path"); + if (s != null) { + swaggerConfig.setBasePath(s); + } + s = config.getInitParameter("host"); + if (s != null) { + swaggerConfig.setHost(s); + } + s = config.getInitParameter("cors"); + if (s != null) { + cors = "true".equalsIgnoreCase(s); + } + s = config.getInitParameter("schemas"); + if (s != null) { + String[] schemas = s.split(","); + swaggerConfig.setSchemes(schemas); + } else { + // assume http by default + swaggerConfig.setSchemes(new String[]{"http"}); + } + + String version = config.getInitParameter("api.version"); + String title = config.getInitParameter("api.title"); + String description = config.getInitParameter("api.description"); + String termsOfService = config.getInitParameter("api.termsOfService"); + String licenseName = config.getInitParameter("api.license.name"); + String licenseUrl = config.getInitParameter("api.license.url"); + String contactName = config.getInitParameter("api.contact.name"); + String contactUrl = config.getInitParameter("api.contact.url"); + String contactEmail = config.getInitParameter("api.contact.email"); + + Info info = new Info(); + info.setVersion(version); + info.setTitle(title); + info.setDescription(description); + info.setTermsOfService(termsOfService); + + if (licenseName != null || licenseUrl != null) { + License license = new License(); + license.setName(licenseName); + license.setUrl(licenseUrl); + info.setLicense(license); + } + + if (contactName != null || contactUrl != null || contactEmail != null) { + Contact contact = new Contact(); + contact.setName(contactName); + contact.setUrl(contactUrl); + contact.setEmail(contactEmail); + info.setContact(contact); + } + + swaggerConfig.setInfo(info); + } + + public List<RestDefinition> getRestDefinitions(String camelId) throws Exception { + ObjectName found = null; + + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + Set<ObjectName> names = server.queryNames(new ObjectName("org.apache.camel:type=context,*"), null); + for (ObjectName on : names) { + String id = on.getKeyProperty("name"); + if (id.startsWith("\"") && id.endsWith("\"")) { + id = id.substring(1, id.length() - 1); + } + if (camelId == null || camelId.equals(id)) { + // filter out older Camel versions as this requires Camel 2.15 or better (rest-dsl) + String version = (String) server.getAttribute(on, "CamelVersion"); + if (CamelVersionHelper.isGE("2.15.0", version)) { + found = on; + } + } + } + + if (found != null) { + String xml = (String) server.invoke(found, "dumpRestsAsXml", null, null); + if (xml != null) { + RestsDefinition rests = ModelHelper.createModelFromXml(null, xml, RestsDefinition.class); + if (rests != null) { + return rests.getRests(); + } + } + } + + return null; + } + + public List<String> findCamelContexts() throws Exception { + List<String> answer = new ArrayList<>(); + + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + Set<ObjectName> names = server.queryNames(new ObjectName("*:type=context,*"), null); + for (ObjectName on : names) { + String id = on.getKeyProperty("name"); + if (id.startsWith("\"") && id.endsWith("\"")) { + id = id.substring(1, id.length() - 1); + } + + // filter out older Camel versions as this requires Camel 2.15 or better (rest-dsl) + String version = (String) server.getAttribute(on, "CamelVersion"); + if (CamelVersionHelper.isGE("2.15.0", version)) { + answer.add(id); + } + } + return answer; + } + + public void renderResourceListing(SwaggerApiProvider provider, BeanConfig swaggerConfig, String contextId, String route) throws Exception { + LOG.trace("renderResourceListing"); + + if (cors) { + provider.addHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"); + provider.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH"); + provider.addHeader("Access-Control-Allow-Origin", "*"); + } + + List<RestDefinition> rests = getRestDefinitions(contextId); + if (rests != null) { + // read the rest-dsl into swagger model + Swagger swagger = reader.read(rests, route, swaggerConfig, new DefaultClassResolver()); + + ObjectMapper mapper = new ObjectMapper(); + mapper.enable(SerializationFeature.INDENT_OUTPUT); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.writeValue(provider.getOutputStream(), swagger); + } else { + provider.noContent(); + } + } + + /** + * Renders a list of available CamelContexts in the JVM + */ + public void renderCamelContexts(SwaggerApiProvider provider) throws Exception { + LOG.trace("renderCamelContexts"); + + if (cors) { + provider.addHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"); + provider.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH"); + provider.addHeader("Access-Control-Allow-Origin", "*"); + } + + List<String> contexts = findCamelContexts(); + provider.getOutputStream().write("[\n".getBytes()); + for (int i = 0; i < contexts.size(); i++) { + String name = contexts.get(i); + provider.getOutputStream().write(("{\"name\": \"" + name + "\"}").getBytes()); + if (i < contexts.size() - 1) { + provider.getOutputStream().write(",\n".getBytes()); + } + } + provider.getOutputStream().write("\n]".getBytes()); + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/3818efe3/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/servlet/RestSwaggerCorsFilter.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/servlet/RestSwaggerCorsFilter.java b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/servlet/RestSwaggerCorsFilter.java new file mode 100644 index 0000000..4aca487 --- /dev/null +++ b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/servlet/RestSwaggerCorsFilter.java @@ -0,0 +1,55 @@ +/** + * 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.swagger.servlet; + +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +/** + * A simple CORS filter that can used to allow the swagger ui or other API browsers from remote origins to access the + * Rest services exposes by this Camel swagger component. + */ +public class RestSwaggerCorsFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // noop + } + + @Override + public void destroy() { + // noop + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletResponse res = (HttpServletResponse) response; + + res.setHeader("Access-Control-Allow-Origin", "*"); + res.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH"); + res.setHeader("Access-Control-Max-Age", "3600"); + res.setHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"); + + chain.doFilter(request, response); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/3818efe3/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/servlet/RestSwaggerServlet.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/servlet/RestSwaggerServlet.java b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/servlet/RestSwaggerServlet.java new file mode 100644 index 0000000..75d0290 --- /dev/null +++ b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/servlet/RestSwaggerServlet.java @@ -0,0 +1,127 @@ +/** + * 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.swagger.servlet; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import io.swagger.jaxrs.config.BeanConfig; +import org.apache.camel.swagger.RestSwaggerSupport; +import org.apache.camel.swagger.spi.SwaggerApiProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.apache.camel.swagger.SwaggerHelper.buildUrl; + +/** + * The default Camel swagger servlet to use when exposing the APIs of the rest-dsl using swagger. + * <p/> + * This requires Camel version 2.15 or better at runtime (and JMX to be enabled). + */ +public class RestSwaggerServlet extends HttpServlet { + + private static final Logger LOG = LoggerFactory.getLogger(RestSwaggerServlet.class); + private BeanConfig swaggerConfig = new BeanConfig(); + private RestSwaggerSupport swagger = new RestSwaggerSupport(); + private volatile boolean initDone; + + @Override + public void init(final ServletConfig config) throws ServletException { + super.init(config); + + swagger.initSwagger(swaggerConfig, new ServletSwaggerApiProvider(config, null)); + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + if (!initDone) { + initBaseAndApiPaths(request); + } + + SwaggerApiProvider resp = new ServletSwaggerApiProvider(null, response); + + String contextId; + String route = request.getPathInfo(); + + try { + + // render list of camel contexts as root + if (route == null || route.equals("") || route.equals("/")) { + swagger.renderCamelContexts(resp); + } else { + // first part is the camel context + if (route.startsWith("/")) { + route = route.substring(1); + } + // the remainder is the route part + contextId = route.split("/")[0]; + if (route.startsWith(contextId)) { + route = route.substring(contextId.length()); + } + + swagger.renderResourceListing(resp, swaggerConfig, contextId, route); + } + } catch (Exception e) { + LOG.warn("Error rendering swagger due " + e.getMessage(), e); + } + } + + private void initBaseAndApiPaths(HttpServletRequest request) throws MalformedURLException { + String base = swaggerConfig.getBasePath(); + if (base == null || !base.startsWith("http")) { + // base path is configured using relative, so lets calculate the absolute url now we have the http request + URL url = new URL(request.getRequestURL().toString()); + if (base == null) { + base = ""; + } + String path = translateContextPath(request); + swaggerConfig.setHost(url.getHost()); + + if (url.getPort() != 80 && url.getPort() != -1) { + swaggerConfig.setHost(url.getHost() + ":" + url.getPort()); + } else { + swaggerConfig.setHost(url.getHost()); + } + swaggerConfig.setBasePath(buildUrl(path, base)); + } + initDone = true; + } + + /** + * We do only want the base context-path and not sub paths + */ + private String translateContextPath(HttpServletRequest request) { + String path = request.getContextPath(); + if (path.isEmpty() || path.equals("/")) { + return ""; + } else { + int idx = path.lastIndexOf("/"); + if (idx > 0) { + return path.substring(0, idx); + } + } + return path; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/3818efe3/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/servlet/ServletSwaggerApiProvider.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/servlet/ServletSwaggerApiProvider.java b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/servlet/ServletSwaggerApiProvider.java new file mode 100644 index 0000000..3d39825 --- /dev/null +++ b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/servlet/ServletSwaggerApiProvider.java @@ -0,0 +1,55 @@ +/** + * 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.swagger.servlet; + +import java.io.IOException; +import java.io.OutputStream; +import javax.servlet.ServletConfig; +import javax.servlet.http.HttpServletResponse; + +import org.apache.camel.swagger.spi.SwaggerApiProvider; + +public class ServletSwaggerApiProvider implements SwaggerApiProvider { + + private final ServletConfig config; + private final HttpServletResponse response; + + public ServletSwaggerApiProvider(ServletConfig config, HttpServletResponse response) { + this.config = config; + this.response = response; + } + + @Override + public String getInitParameter(String key) { + return config.getInitParameter(key); + } + + @Override + public void addHeader(String name, String value) { + response.addHeader(name, value); + } + + @Override + public OutputStream getOutputStream() throws IOException { + return response.getOutputStream(); + } + + @Override + public void noContent() { + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/3818efe3/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/spi/SwaggerApiProvider.java ---------------------------------------------------------------------- diff --git a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/spi/SwaggerApiProvider.java b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/spi/SwaggerApiProvider.java new file mode 100644 index 0000000..42e6a2d --- /dev/null +++ b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/spi/SwaggerApiProvider.java @@ -0,0 +1,32 @@ +/** + * 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.swagger.spi; + +import java.io.IOException; +import java.io.OutputStream; + +public interface SwaggerApiProvider { + + String getInitParameter(String key); + + void addHeader(String name, String value); + + OutputStream getOutputStream() throws IOException; + + void noContent(); + +} http://git-wip-us.apache.org/repos/asf/camel/blob/3818efe3/examples/camel-example-swagger-java/src/main/webapp/WEB-INF/web.xml ---------------------------------------------------------------------- diff --git a/examples/camel-example-swagger-java/src/main/webapp/WEB-INF/web.xml b/examples/camel-example-swagger-java/src/main/webapp/WEB-INF/web.xml index 35527aa..cfde29f 100755 --- a/examples/camel-example-swagger-java/src/main/webapp/WEB-INF/web.xml +++ b/examples/camel-example-swagger-java/src/main/webapp/WEB-INF/web.xml @@ -44,7 +44,7 @@ <!-- to setup Camel Swagger servlet --> <servlet> <servlet-name>ApiDeclarationServlet</servlet-name> - <servlet-class>org.apache.camel.swagger.RestSwaggerServlet</servlet-class> + <servlet-class>org.apache.camel.swagger.servlet.RestSwaggerServlet</servlet-class> <init-param> <!-- we specify the base.path using relative notation, that means the actual path will be calculated at runtime as http://server:port/contextpath/rest --> @@ -91,7 +91,7 @@ <!-- enable CORS filter so people can use swagger ui to browse and test the apis --> <filter> <filter-name>RestSwaggerCorsFilter</filter-name> - <filter-class>org.apache.camel.swagger.RestSwaggerCorsFilter</filter-class> + <filter-class>org.apache.camel.swagger.servlet.RestSwaggerCorsFilter</filter-class> </filter> <filter-mapping> @@ -101,7 +101,7 @@ </filter-mapping> <welcome-file-list> - <welcome-file>home.html</welcome-file> + <welcome-file>home.html</welcome-file> </welcome-file-list> </web-app> \ No newline at end of file