From d9bf9470b3aaf8e70734b5a59c204b1e223321f1 Mon Sep 17 00:00:00 2001 From: joshua bauer Date: Thu, 20 Dec 2018 13:51:28 -0800 Subject: [PATCH] Improved documentation and cleaned up service code. --- .../sinistral/proteus/ProteusApplication.java | 309 +++++++++--------- .../proteus/services/AssetsService.java | 6 +- .../proteus/services/BaseService.java | 9 - .../proteus/services/OpenAPIService.java | 6 +- .../proteus/services/SwaggerService.java | 18 +- 5 files changed, 173 insertions(+), 175 deletions(-) diff --git a/src/main/java/io/sinistral/proteus/ProteusApplication.java b/src/main/java/io/sinistral/proteus/ProteusApplication.java index ef82725..335533c 100644 --- a/src/main/java/io/sinistral/proteus/ProteusApplication.java +++ b/src/main/java/io/sinistral/proteus/ProteusApplication.java @@ -1,6 +1,3 @@ -/** - * - */ package io.sinistral.proteus; import java.io.ByteArrayOutputStream; @@ -63,6 +60,7 @@ import io.undertow.util.Methods; /** + * The base class for proteus applications. * @author jbauer */ public class ProteusApplication @@ -91,13 +89,20 @@ public class ProteusApplication public List> registeredModules = new ArrayList<>(); - public Injector injector = null; + public Injector injector; + public ServiceManager serviceManager = null; + public Undertow undertow = null; + public Class rootHandlerClass; + public HttpHandler rootHandler; + public AtomicBoolean running = new AtomicBoolean(false); + public List ports = new ArrayList<>(); + public Function serverConfigurationFunction = null; public Duration startupDuration; @@ -192,30 +197,21 @@ public void failure(Service service) }, MoreExecutors.directExecutor()); - Runtime.getRuntime().addShutdownHook(new Thread() - { - @Override - public void run() + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { - try - { - shutdown(); - } catch (TimeoutException timeout) - { - log.error(timeout.getMessage(),timeout); - } + shutdown(); + } catch (TimeoutException timeout) + { + log.error(timeout.getMessage(),timeout); } - }); + })); buildServer(); undertow.start(); serviceManager.startAsync(); - - - - } public void shutdown() throws TimeoutException @@ -228,12 +224,7 @@ public void shutdown() throws TimeoutException log.info("Shutting down..."); - try { - serviceManager.stopAsync().awaitStopped(1, TimeUnit.SECONDS); - - } catch (TimeoutException timeout) { - log.warn("Failed to shutdown within specified timeout."); - } + serviceManager.stopAsync().awaitStopped(1, TimeUnit.SECONDS); log.info("Shutdown complete."); } @@ -351,131 +342,46 @@ public void buildServer() } + /** + * Add a service class to the application + * @param serviceClass + * @return the application + */ public ProteusApplication addService(Class serviceClass) { registeredServices.add(serviceClass); return this; } + /** + * Add a controller class to the application + * @param controllerClass + * @return the application + */ public ProteusApplication addController(Class controllerClass) { registeredControllers.add(controllerClass); return this; } - public ProteusApplication addModule(Class module) - { - registeredModules.add(module); - return this; - } - - public void setRootHandlerClass(Class rootHandlerClass) - { - this.rootHandlerClass = rootHandlerClass; - } - - public void setRootHandler(HttpHandler rootHandler) - { - this.rootHandler = rootHandler; - } - - public Undertow getUndertow() - { - return undertow; - } /** - * Allows direct access to the Undertow.Builder for custom configuration - * - * @param serverConfigurationFunction - * the serverConfigurationFunction + * Add a module class to the application + * @param moduleClass + * @return the application */ - public void setServerConfigurationFunction(Function serverConfigurationFunction) + public ProteusApplication addModule(Class moduleClass) { - this.serverConfigurationFunction = serverConfigurationFunction; + registeredModules.add(moduleClass); + return this; } - /** - * @return the serviceManager - */ - public ServiceManager getServiceManager() - { - return serviceManager; - } /** - * @return the config + * Add utility routes the router + * @param router */ - public Config getConfig() - { - return config; - } - - public void printStatus() - { - Config globalHeaders = config.getConfig("globalHeaders"); - - Map globalHeadersParameters = globalHeaders.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().render())); - - StringBuilder sb = new StringBuilder(); - - sb.append("\nUsing global headers: \n"); - - List tableHeaders = Arrays.asList("Header","Value"); - - List> tableRows = globalHeadersParameters.entrySet().stream().map( e -> { - - return Arrays.asList( e.getKey(), e.getValue() ); - - }).collect(Collectors.toList()); - - TablePrinter printer = new TablePrinter(tableHeaders, tableRows); - - sb.append(printer.toString()); - - sb.append("\nRegistered endpoints: \n"); - - tableHeaders = Arrays.asList("Method","Path","Consumes","Produces","Controller"); - - tableRows = this.registeredEndpoints.stream().sorted().map( e -> { - - return Arrays.asList( e.getMethod().toString(), e.getPathTemplate(), String.format("[%s]", e.getConsumes()), String.format("[%s]", e.getProduces()), String.format("(%s.%s)", e.getControllerName() , e.getControllerMethod() ) ); - - }).collect(Collectors.toList()); - - printer = new TablePrinter(tableHeaders, tableRows); - - sb.append(printer.toString()); - - sb.append("\nRegistered services: \n"); - - ImmutableMultimap serviceStateMap = this.serviceManager.servicesByState(); - - ImmutableMap serviceStartupTimeMap = this.serviceManager.startupTimes(); - - tableHeaders = Arrays.asList("Service","State","Startup Time"); - - tableRows = serviceStateMap.asMap().entrySet().stream().flatMap(e -> { - - return e.getValue().stream().map(s -> { - - return Arrays.asList(s.getClass().getSimpleName() , e.getKey().toString(), DurationFormatUtils.formatDurationHMS(serviceStartupTimeMap.get(s)) ); - }); - - }).collect(Collectors.toList()); - - printer = new TablePrinter(tableHeaders, tableRows); - - sb.append(printer.toString()); - - sb.append("\nListening On: " + this.ports ); - - sb.append("\nApplication Startup Time: " + DurationFormatUtils.formatDurationHMS(this.startupDuration.toMillis()) + "\n"); - - log.info(sb.toString()); - } - - public void addDefaultRoutes(RoutingHandler router) + public ProteusApplication addDefaultRoutes(RoutingHandler router) { if (config.hasPath("health.statusPath")) @@ -484,16 +390,10 @@ public void addDefaultRoutes(RoutingHandler router) { final String statusPath = config.getString("health.statusPath"); - router.add(Methods.GET, statusPath, new HttpHandler() + router.add(Methods.GET, statusPath, (final HttpServerExchange exchange) -> { - - @Override - public void handleRequest(HttpServerExchange exchange) throws Exception - { exchange.getResponseHeaders().add(Headers.CONTENT_TYPE, MediaType.TEXT_PLAIN); exchange.getResponseSender().send("OK"); - } - }); this.registeredEndpoints.add(EndpointInfo.builder().withConsumes("*/*").withProduces("text/plain").withPathTemplate(statusPath).withControllerName("Internal").withMethod(Methods.GET).build()); @@ -510,7 +410,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { final ByteBuffer faviconImageBuffer; - + final File faviconFile = new File(config.getString("application.favicon")); if (!faviconFile.exists()) @@ -555,27 +455,69 @@ public void handleRequest(HttpServerExchange exchange) throws Exception } } - if (faviconImageBuffer != null) + router.add(Methods.GET, "favicon.ico", (final HttpServerExchange exchange) -> { - - router.add(Methods.GET, "favicon.ico", new HttpHandler() - { - @Override - public void handleRequest(HttpServerExchange exchange) throws Exception - { - exchange.getResponseHeaders().add(Headers.CONTENT_TYPE, io.sinistral.proteus.server.MediaType.IMAGE_X_ICON.toString()); - exchange.getResponseSender().send(faviconImageBuffer); - } - - }); - - } + exchange.getResponseHeaders().add(Headers.CONTENT_TYPE, io.sinistral.proteus.server.MediaType.IMAGE_X_ICON.toString()); + exchange.getResponseSender().send(faviconImageBuffer); + }); } catch (Exception e) { log.error("Error adding favicon route.", e.getMessage()); } } + + return this; + } + + /** + * Set the root HttpHandler class + * @param rootHandlerClass + * @return the application + */ + public ProteusApplication setRootHandlerClass(Class rootHandlerClass) + { + this.rootHandlerClass = rootHandlerClass; + return this; + } + + /** + * Set the root HttpHandler + * @param rootHandler + * @return the application + */ + public ProteusApplication setRootHandler(HttpHandler rootHandler) + { + this.rootHandler = rootHandler; + return this; + } + + /** + * Allows direct access to the Undertow.Builder for custom configuration + * + * @param serverConfigurationFunction + * the serverConfigurationFunction + */ + public ProteusApplication setServerConfigurationFunction(Function serverConfigurationFunction) + { + this.serverConfigurationFunction = serverConfigurationFunction; + return this; + } + + /** + * @return the serviceManager + */ + public ServiceManager getServiceManager() + { + return serviceManager; + } + + /** + * @return the config + */ + public Config getConfig() + { + return config; } /** @@ -585,10 +527,10 @@ public RoutingHandler getRouter() { return router; } - + /** - * @return the ports + * @return a list of used ports */ public List getPorts() { @@ -596,5 +538,64 @@ public List getPorts() } + /** + * @return The Undertow server + */ + public Undertow getUndertow() + { + return undertow; + } + + + public void printStatus() + { + Config globalHeaders = config.getConfig("globalHeaders"); + + Map globalHeadersParameters = globalHeaders.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().render())); + + StringBuilder sb = new StringBuilder(); + + sb.append("\nUsing global headers: \n"); + + List tableHeaders = Arrays.asList("Header","Value"); + + List> tableRows = globalHeadersParameters.entrySet().stream().map( e -> Arrays.asList( e.getKey(), e.getValue() )) + .collect(Collectors.toList()); + + TablePrinter printer = new TablePrinter(tableHeaders, tableRows); + + sb.append(printer.toString()); + + sb.append("\nRegistered endpoints: \n"); + + tableHeaders = Arrays.asList("Method","Path","Consumes","Produces","Controller"); + + tableRows = this.registeredEndpoints.stream().sorted().map( e -> + Arrays.asList( e.getMethod().toString(), e.getPathTemplate(), String.format("[%s]", e.getConsumes()), String.format("[%s]", e.getProduces()), String.format("(%s.%s)", e.getControllerName() , e.getControllerMethod() ) )) + .collect(Collectors.toList()); + + printer = new TablePrinter(tableHeaders, tableRows); + + sb.append(printer.toString()).append("\nRegistered services: \n"); + + ImmutableMultimap serviceStateMap = this.serviceManager.servicesByState(); + + ImmutableMap serviceStartupTimeMap = this.serviceManager.startupTimes(); + + tableHeaders = Arrays.asList("Service","State","Startup Time"); + + tableRows = serviceStateMap.asMap().entrySet().stream().flatMap(e -> + e.getValue().stream().map(s -> + Arrays.asList(s.getClass().getSimpleName() , e.getKey().toString(), DurationFormatUtils.formatDurationHMS(serviceStartupTimeMap.get(s)) ))) + .collect(Collectors.toList()); + + printer = new TablePrinter(tableHeaders, tableRows); + + sb.append(printer.toString()).append("\nListening On: " + this.ports ).append("\nApplication Startup Time: " + DurationFormatUtils.formatDurationHMS(this.startupDuration.toMillis()) + "\n"); + + log.info(sb.toString()); + } + + } diff --git a/src/main/java/io/sinistral/proteus/services/AssetsService.java b/src/main/java/io/sinistral/proteus/services/AssetsService.java index f5641da..3dbdcbb 100644 --- a/src/main/java/io/sinistral/proteus/services/AssetsService.java +++ b/src/main/java/io/sinistral/proteus/services/AssetsService.java @@ -1,7 +1,3 @@ - -/** - * - */ package io.sinistral.proteus.services; import java.nio.file.Paths; @@ -23,8 +19,8 @@ import io.undertow.util.Methods; /** + * A service for serving static assets from a directory. * @author jbauer - * */ public class AssetsService extends BaseService implements Supplier { diff --git a/src/main/java/io/sinistral/proteus/services/BaseService.java b/src/main/java/io/sinistral/proteus/services/BaseService.java index bedf807..6fbd4de 100644 --- a/src/main/java/io/sinistral/proteus/services/BaseService.java +++ b/src/main/java/io/sinistral/proteus/services/BaseService.java @@ -1,7 +1,4 @@ -/** - * - */ package io.sinistral.proteus.services; import org.slf4j.Logger; @@ -17,9 +14,7 @@ /** * An abstract base class for a Proteus service. - * * @author jbauer - * */ @Singleton public abstract class BaseService extends AbstractIdleService implements Module @@ -27,7 +22,6 @@ public abstract class BaseService extends AbstractIdleService implements Module private static Logger log = LoggerFactory.getLogger(BaseService.class.getCanonicalName()); /* - * (non-Javadoc) * @see com.google.inject.AbstractModule#configure() */ @Inject @@ -38,7 +32,6 @@ public BaseService() } /* - * (non-Javadoc) * @see com.google.inject.Module#configure(com.google.inject.Binder) */ public void configure(Binder binder) @@ -46,7 +39,6 @@ public void configure(Binder binder) } /* - * (non-Javadoc) * @see com.google.common.util.concurrent.AbstractIdleService#shutDown() */ @Override @@ -56,7 +48,6 @@ protected void shutDown() throws Exception } /* - * (non-Javadoc) * @see com.google.common.util.concurrent.AbstractIdleService#startUp() */ @Override diff --git a/src/main/java/io/sinistral/proteus/services/OpenAPIService.java b/src/main/java/io/sinistral/proteus/services/OpenAPIService.java index 8becd34..967e075 100644 --- a/src/main/java/io/sinistral/proteus/services/OpenAPIService.java +++ b/src/main/java/io/sinistral/proteus/services/OpenAPIService.java @@ -60,7 +60,6 @@ import io.swagger.v3.oas.models.servers.Server; import io.undertow.server.HandlerWrapper; -import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; import io.undertow.server.RoutingHandler; import io.undertow.server.handlers.ResponseCodeHandler; @@ -70,6 +69,11 @@ import io.undertow.util.Headers; import io.undertow.util.Methods; +/** + * A service for generating and serving an OpenAPI v3 spec and ui. + * @author jbauer + */ + @Singleton public class OpenAPIService extends BaseService implements Supplier { diff --git a/src/main/java/io/sinistral/proteus/services/SwaggerService.java b/src/main/java/io/sinistral/proteus/services/SwaggerService.java index d27032e..3d9b16a 100644 --- a/src/main/java/io/sinistral/proteus/services/SwaggerService.java +++ b/src/main/java/io/sinistral/proteus/services/SwaggerService.java @@ -78,6 +78,11 @@ import io.undertow.util.HttpString; import io.undertow.util.Methods; +/** + * A service for generating and serving an Swagger 2.0 spec and ui. + * @author jbauer + */ + @Singleton public class SwaggerService extends BaseService implements Supplier { @@ -342,10 +347,10 @@ protected void generateSwaggerHTML() themePath = "themes/theme-" + theme + ".css"; } - templateString = templateString.replaceAll("\\{\\{ themePath \\}\\}", themePath); - templateString = templateString.replaceAll("\\{\\{ swaggerBasePath \\}\\}", basePath); - templateString = templateString.replaceAll("\\{\\{ title \\}\\}", applicationName + " Swagger UI"); - templateString = templateString.replaceAll("\\{\\{ swaggerFilePath \\}\\}", basePath + ".json"); + templateString = templateString.replaceAll("\\{\\{ themePath }}", themePath); + templateString = templateString.replaceAll("\\{\\{ swaggerBasePath }}", basePath); + templateString = templateString.replaceAll("\\{\\{ title }}", applicationName + " Swagger UI"); + templateString = templateString.replaceAll("\\{\\{ swaggerFilePath }}", basePath + ".json"); this.swaggerIndexHTML = templateString; } @@ -356,8 +361,8 @@ protected void generateSwaggerHTML() String templateString = new String(templateBytes, Charset.defaultCharset()); - templateString = templateString.replaceAll("\\{\\{ specPath \\}\\}", this.basePath + ".json"); - templateString = templateString.replaceAll("\\{\\{ applicationName \\}\\}", applicationName); + templateString = templateString.replaceAll("\\{\\{ specPath }}", this.basePath + ".json"); + templateString = templateString.replaceAll("\\{\\{ applicationName }}", applicationName); this.redocHTML = templateString; } @@ -392,6 +397,7 @@ protected void generateSwaggerHTML() } catch (java.lang.IllegalArgumentException e) { log.debug("Swagger tmp directory is not a directory..."); + swaggerTmpDir.toFile().delete(); } }