From c0b2d65cd196428af875edd8786f16b7bb031a4f Mon Sep 17 00:00:00 2001 From: joshua bauer Date: Tue, 2 May 2017 09:43:46 -0700 Subject: [PATCH] Improved Swagger resource handling. --- pom.xml | 4 +- .../sinistral/proteus/ProteusApplication.java | 4 +- .../proteus/modules/ConfigModule.java | 5 + .../proteus/services/SwaggerService.java | 166 +++++++++++------- .../sinistral/proteus}/swagger/index.html | 4 +- .../proteus}/swagger/swagger-ui-bundle.js | 0 .../proteus}/swagger/swagger-ui-bundle.js.map | 0 .../swagger/swagger-ui-standalone-preset.js | 0 .../swagger-ui-standalone-preset.js.map | 0 .../sinistral/proteus}/swagger/swagger-ui.css | 0 .../proteus}/swagger/swagger-ui.css.map | 0 .../sinistral/proteus}/swagger/swagger-ui.js | 0 .../proteus}/swagger/swagger-ui.js.map | 0 .../swagger/themes/theme-feeling-blue.css | 0 .../proteus}/swagger/themes/theme-flattop.css | 0 .../swagger/themes/theme-material.css | 0 .../proteus}/swagger/themes/theme-monokai.css | 0 .../proteus}/swagger/themes/theme-muted.css | 0 .../swagger/themes/theme-newspaper.css | 0 .../proteus}/swagger/themes/theme-outline.css | 0 20 files changed, 116 insertions(+), 67 deletions(-) rename src/main/resources/{ => io/sinistral/proteus}/swagger/index.html (98%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/swagger-ui-bundle.js (100%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/swagger-ui-bundle.js.map (100%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/swagger-ui-standalone-preset.js (100%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/swagger-ui-standalone-preset.js.map (100%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/swagger-ui.css (100%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/swagger-ui.css.map (100%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/swagger-ui.js (100%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/swagger-ui.js.map (100%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/themes/theme-feeling-blue.css (100%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/themes/theme-flattop.css (100%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/themes/theme-material.css (100%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/themes/theme-monokai.css (100%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/themes/theme-muted.css (100%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/themes/theme-newspaper.css (100%) rename src/main/resources/{ => io/sinistral/proteus}/swagger/themes/theme-outline.css (100%) diff --git a/pom.xml b/pom.xml index f127da9..f032c21 100644 --- a/pom.xml +++ b/pom.xml @@ -3,10 +3,10 @@ 4.0.0 io.sinistral proteus-core - 0.1.0 + 0.1.0-SNAPSHOT proteus core Proteus is an extremely light, fast, and flexible Java REST API framework built atop Undertow. - http://proteus.sinistral.io + http://github.com/noboomu/proteus jar diff --git a/src/main/java/io/sinistral/proteus/ProteusApplication.java b/src/main/java/io/sinistral/proteus/ProteusApplication.java index ff4e29f..011cc05 100644 --- a/src/main/java/io/sinistral/proteus/ProteusApplication.java +++ b/src/main/java/io/sinistral/proteus/ProteusApplication.java @@ -83,7 +83,7 @@ public class ProteusApplication public ProteusApplication() { - injector = Guice.createInjector(new ConfigModule("application.conf")); + injector = Guice.createInjector(new ConfigModule()); injector.injectMembers(this); } @@ -186,7 +186,7 @@ public void shutdown() throws TimeoutException log.info("Shutting down..."); - serviceManager.stopAsync().awaitStopped(5, TimeUnit.SECONDS); + serviceManager.stopAsync().awaitStopped(8, TimeUnit.SECONDS); log.info("Shutdown complete."); } diff --git a/src/main/java/io/sinistral/proteus/modules/ConfigModule.java b/src/main/java/io/sinistral/proteus/modules/ConfigModule.java index 3975306..21eedf6 100644 --- a/src/main/java/io/sinistral/proteus/modules/ConfigModule.java +++ b/src/main/java/io/sinistral/proteus/modules/ConfigModule.java @@ -41,7 +41,12 @@ public class ConfigModule extends AbstractModule public ConfigModule() { + this.configFile = System.getenv("config.file"); + if(this.configFile == null) + { + this.configFile = "application.conf"; + } } public ConfigModule(String configFile) diff --git a/src/main/java/io/sinistral/proteus/services/SwaggerService.java b/src/main/java/io/sinistral/proteus/services/SwaggerService.java index cf1be94..c52b230 100644 --- a/src/main/java/io/sinistral/proteus/services/SwaggerService.java +++ b/src/main/java/io/sinistral/proteus/services/SwaggerService.java @@ -6,14 +6,19 @@ import java.net.URL; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Set; import java.util.function.Supplier; +import java.util.jar.JarFile; import javax.ws.rs.HttpMethod; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,13 +43,16 @@ import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; import io.undertow.server.RoutingHandler; +import io.undertow.server.handlers.ResponseCodeHandler; import io.undertow.server.handlers.resource.ClassPathResourceManager; +import io.undertow.server.handlers.resource.FileResourceManager; import io.undertow.server.handlers.resource.Resource; import io.undertow.server.handlers.resource.ResourceHandler; import io.undertow.util.CanonicalPathUtils; import io.undertow.util.Headers; import io.undertow.util.Methods; + public class SwaggerService extends BaseService implements Supplier { @@ -53,9 +61,9 @@ public class SwaggerService extends BaseService implements Supplier ze.getName().endsWith("js") || ze.getName().endsWith("css") || ze.getName().endsWith("map") || ze.getName().endsWith("html") ).forEach( ze -> { + + try + { + final InputStream entryInputStream = jarFile.getInputStream(ze); + + String filename = ze.getName().substring(swaggerResourcePrefix.length() + 1); + + Path entryFilePath = swaggerTmpDir.resolve(filename); + + java.nio.file.Files.createDirectories(entryFilePath.getParent()); + + java.nio.file.Files.copy(entryInputStream, entryFilePath,StandardCopyOption.REPLACE_EXISTING); + + } catch (Exception e) + { + log.error(e.getMessage() + " for entry " + ze.getName()); + } + }); + } + } + else + { + this.swaggerResourcePath = Paths.get(this.getClass().getClassLoader().getResource(this.swaggerResourcePrefix).toURI()); + this.serviceClassLoader = this.getClass().getClassLoader(); + } } catch (Exception e) { @@ -266,6 +324,7 @@ public RoutingHandler get() String pathTemplate = this.swaggerBasePath + ".json"; + FileResourceManager resourceManager = new FileResourceManager(this.swaggerResourcePath.toFile(),1024); router.add(HttpMethod.GET, pathTemplate, new HttpHandler(){ @@ -273,9 +332,7 @@ public RoutingHandler get() public void handleRequest(HttpServerExchange exchange) throws Exception { - exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, MimeTypes.APPLICATION_JSON_TYPE); - - + exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, MimeTypes.APPLICATION_JSON_TYPE); exchange.getResponseSender().send(swaggerSpec); } @@ -287,7 +344,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception pathTemplate = this.swaggerBasePath; - + router.add(HttpMethod.GET, pathTemplate , new HttpHandler(){ @Override @@ -304,35 +361,6 @@ public void handleRequest(HttpServerExchange exchange) throws Exception this.registeredEndpoints.add(EndpointInfo.builder().withConsumes("*/*").withProduces("text/html").withPathTemplate(pathTemplate).withControllerName("Swagger").withMethod(Methods.GET).build()); - pathTemplate = this.swaggerBasePath + "/themes/*"; - - router.add(HttpMethod.GET, pathTemplate, new HttpHandler(){ - - @Override - public void handleRequest(HttpServerExchange exchange) throws Exception - { - - String canonicalPath = CanonicalPathUtils.canonicalize((exchange.getRelativePath())); - - canonicalPath = swaggerThemesPath + canonicalPath.split(swaggerBasePath+"/themes")[1]; - - try(final InputStream resourceInputStream = serviceClassLoader.getResourceAsStream(canonicalPath)) - { - - byte[] resourceBytes = IOUtils.toByteArray(resourceInputStream); - - exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, io.sinistral.proteus.server.MediaType.TEXT_CSS_UTF8.toString()); - - exchange.getResponseSender().send(ByteBuffer.wrap(resourceBytes)); - - } - } - - }); - - - this.registeredEndpoints.add(EndpointInfo.builder().withConsumes("*/*").withProduces("text/css").withPathTemplate(pathTemplate).withControllerName("Swagger").withMethod(Methods.GET).build()); - try { @@ -340,7 +368,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception pathTemplate = this.swaggerBasePath + "/*"; - router.add(HttpMethod.GET, pathTemplate, new HttpHandler(){ + router.add(HttpMethod.GET, pathTemplate, new ResourceHandler(resourceManager){ @Override public void handleRequest(HttpServerExchange exchange) throws Exception @@ -348,19 +376,35 @@ public void handleRequest(HttpServerExchange exchange) throws Exception String canonicalPath = CanonicalPathUtils.canonicalize((exchange.getRelativePath())); - canonicalPath = swaggerResourcePath + canonicalPath.split(swaggerBasePath)[1]; - - System.out.println("canonicalPath: " + canonicalPath); + canonicalPath = canonicalPath.split(swaggerBasePath)[1]; - try(final InputStream resourceInputStream = serviceClassLoader.getResourceAsStream(canonicalPath)) - { - - byte[] resourceBytes = IOUtils.toByteArray(resourceInputStream); - - exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, io.sinistral.proteus.server.MediaType.APPLICATION_JAVASCRIPT_UTF8.toString()); - - exchange.getResponseSender().send(ByteBuffer.wrap(resourceBytes)); + exchange.setRelativePath(canonicalPath); + if(serviceClassLoader == null) + { + super.handleRequest(exchange); + } + else + { + canonicalPath = swaggerResourcePrefix + canonicalPath; + + try(final InputStream resourceInputStream = serviceClassLoader.getResourceAsStream( canonicalPath)) + { + + if(resourceInputStream == null) + { + ResponseCodeHandler.HANDLE_404.handleRequest(exchange); + return; + } + + byte[] resourceBytes = IOUtils.toByteArray(resourceInputStream); + + io.sinistral.proteus.server.MediaType mediaType = io.sinistral.proteus.server.MediaType.getByFileName(canonicalPath); + + exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, mediaType.toString()); + + exchange.getResponseSender().send(ByteBuffer.wrap(resourceBytes)); + } } } diff --git a/src/main/resources/swagger/index.html b/src/main/resources/io/sinistral/proteus/swagger/index.html similarity index 98% rename from src/main/resources/swagger/index.html rename to src/main/resources/io/sinistral/proteus/swagger/index.html index cff9601..b5c438e 100644 --- a/src/main/resources/swagger/index.html +++ b/src/main/resources/io/sinistral/proteus/swagger/index.html @@ -74,8 +74,8 @@