diff --git a/CHANGELOG.md b/CHANGELOG.md index 2781a64..3f432ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ Proteus Changelog. ## Unreleased ### No issue +**Reduce logging.** + + +[f6a8f1986b6d0da](https://github.com/noboomu/proteus/commit/f6a8f1986b6d0da) Joshua Bauer *2022-07-19 20:15:26* + **Tweak parameters.** diff --git a/pom.xml b/pom.xml index 008d2f9..02f80bc 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,7 @@ 3.0.0-M4 1.6.8 2.2.1 - 2.21ea82 + 2.23ea0 UTF-8 ${project.version} 0.10.2 diff --git a/proteus-core/conf/logback-test.xml b/proteus-core/conf/logback-test.xml index 2fb2167..f934c40 100644 --- a/proteus-core/conf/logback-test.xml +++ b/proteus-core/conf/logback-test.xml @@ -19,6 +19,8 @@ + + diff --git a/proteus-core/conf/logback.xml b/proteus-core/conf/logback.xml index dd8243f..b9f5278 100644 --- a/proteus-core/conf/logback.xml +++ b/proteus-core/conf/logback.xml @@ -27,6 +27,7 @@ + diff --git a/proteus-core/src/main/java/io/sinistral/proteus/ProteusApplication.java b/proteus-core/src/main/java/io/sinistral/proteus/ProteusApplication.java index 354097c..9319f69 100644 --- a/proteus-core/src/main/java/io/sinistral/proteus/ProteusApplication.java +++ b/proteus-core/src/main/java/io/sinistral/proteus/ProteusApplication.java @@ -30,10 +30,10 @@ import io.undertow.server.session.SessionAttachmentHandler; import io.undertow.util.Headers; import io.undertow.util.Methods; +import net.openhft.compiler.CachedCompiler; import org.apache.commons.lang3.time.DurationFormatUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.xnio.Options; import org.xnio.Xnio; import org.xnio.XnioWorker; @@ -61,6 +61,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -71,11 +72,13 @@ * @author jbauer */ -@SuppressWarnings("UnusedReturnValue") +@SuppressWarnings({"UnusedReturnValue", "unchecked"}) public class ProteusApplication { private static Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ProteusApplication.class.getCanonicalName()); + private static final String TMP_DIRECTORY_NAME = "proteus_generated_classes"; + @Inject @Named("registeredControllers") public Set> registeredControllers; @@ -118,6 +121,7 @@ public class ProteusApplication { public ProteusApplication() { + injector = Guice.createInjector(new ConfigModule()); injector.injectMembers(this); } @@ -138,7 +142,7 @@ public ProteusApplication(URL configURL) } - public ProteusApplication(Module ... modules) + public ProteusApplication(Module... modules) { injector = Guice.createInjector(modules); @@ -146,7 +150,6 @@ public ProteusApplication(Module ... modules) } - public void start() { @@ -158,7 +161,6 @@ public void start() final Thread mainThread = Thread.currentThread(); - log.info("Installing modules: {}", registeredModules.stream().map(Class::getSimpleName).collect(Collectors.joining(","))); Set modules = registeredModules.stream().map(mc -> injector.getInstance(mc)).collect(Collectors.toSet()); @@ -182,6 +184,7 @@ public void start() serviceManager.addListener(new Listener() { public void stopped() { + log.info("Services are stopped"); } @@ -191,7 +194,7 @@ public void healthy() log.info("Services are healthy"); - startupDuration = Duration.between(startTime,Instant.now()); + startupDuration = Duration.between(startTime, Instant.now()); for (ListenerInfo info : undertow.getListenerInfo()) { @@ -213,7 +216,7 @@ public void failure(Service service) log.error("Service failure: " + service); - startupDuration = Duration.between(startTime,Instant.now()); + startupDuration = Duration.between(startTime, Instant.now()); for (ListenerInfo info : undertow.getListenerInfo()) { @@ -256,7 +259,6 @@ public void failure(Service service) buildServer(); - undertow.start(); Duration timeout = config.getDuration("application.services.timeout"); @@ -264,16 +266,14 @@ public void failure(Service service) try { serviceManager.startAsync().awaitHealthy(timeout); - } catch( TimeoutException e ) + } catch (TimeoutException e) { - log.error("Failed start to services within {} minutes",timeout,e); + log.error("Failed start to services within {} minutes", timeout, e); } catch (Exception e) { - log.error("Failed to start services",e); + log.error("Failed to start services", e); } - - this.running.set(true); // serviceManager.startAsync(); @@ -317,6 +317,8 @@ public void buildServer() CopyOnWriteArrayList>> routerClasses = new CopyOnWriteArrayList<>(); + ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + log.info("Compiling route handlers..."); for (Class controllerClass : registeredControllers) @@ -327,19 +329,27 @@ public void buildServer() try { - // log.debug("Generating {}...", controllerClass); + // log.debug("Generating {}...", controllerClass); HandlerGenerator generator = new HandlerGenerator("io.sinistral.proteus.controllers.handlers", controllerClass); injector.injectMembers(generator); - // log.debug("Compiling {}...", controllerClass); + // log.debug("Compiling {}...", controllerClass); + + try (CachedCompiler cachedCompiler = new CachedCompiler(null, getTemporaryDirectoryPath().toFile())) + { + final String source = generator.generateClassSource(); + var routerClass = cachedCompiler.loadFromJava(generator.getCanonicalName(), source); - Class> routerClass = generator.compileClass(); + lock.writeLock().lock(); + + routerClasses.add(routerClass); + + lock.writeLock().unlock(); + } - routerClasses.add(routerClass); - // log.debug("Compiled {}", controllerClass); } catch (Exception e) { @@ -359,7 +369,7 @@ public void buildServer() log.error("Failed waiting for handlers to generate", e); } - log.debug("Compilation completed in {}", DurationFormatUtils.formatDurationHMS(Duration.between(compilationStartTime,Instant.now()).toMillis())); + log.debug("Compilation completed in {}", DurationFormatUtils.formatDurationHMS(Duration.between(compilationStartTime, Instant.now()).toMillis())); for (Class> clazz : routerClasses) { @@ -400,8 +410,7 @@ public void buildServer() handler = sessionAttachmentHandler; } - - if(config.hasPath("undertow.gracefulShutdown") && config.getBoolean("undertow.gracefulShutdown")) + if (config.hasPath("undertow.gracefulShutdown") && config.getBoolean("undertow.gracefulShutdown")) { handler = new GracefulShutdownHandler(handler); } @@ -433,7 +442,6 @@ public void buildServer() .setServerOption(UndertowOptions.MAX_BUFFERED_REQUEST_SIZE, config.getInt("undertow.server.maxBufferedRequestSize")) .setHandler(handler); - if (config.getBoolean("undertow.ssl.enabled")) { try @@ -522,7 +530,7 @@ public ProteusApplication addDefaultRoutes(RoutingHandler router) { exchange.getResponseHeaders().add(Headers.CONTENT_TYPE, MediaType.TEXT_PLAIN); - if(this.serviceManager.servicesByState().values().stream().allMatch(Service::isRunning)) + if (this.serviceManager.servicesByState().values().stream().allMatch(Service::isRunning)) { exchange.setStatusCode(200).getResponseSender().send("OK"); } @@ -734,7 +742,7 @@ public void printStatus() 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()))) + 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); @@ -748,17 +756,33 @@ public void printStatus() 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))))) + 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: ").append(DurationFormatUtils.formatDurationHMS(this.startupDuration.toMillis())).append( "\n"); + sb.append(printer.toString()).append("\nListening On: " + this.ports).append("\nApplication Startup Time: ").append(DurationFormatUtils.formatDurationHMS(this.startupDuration.toMillis())).append("\n"); log.info(sb.toString()); } + protected java.nio.file.Path getTemporaryDirectoryPath() throws Exception + { + + String tmpDirLocation = System.getProperty("java.io.tmpdir"); + java.nio.file.Path tmpPath = Paths.get(tmpDirLocation); + + try + { + return Files.createDirectory(tmpPath.resolve(TMP_DIRECTORY_NAME)); + + } catch (Exception e) + { + return tmpPath; + } + + } } diff --git a/proteus-core/src/main/java/io/sinistral/proteus/modules/JacksonModule.java b/proteus-core/src/main/java/io/sinistral/proteus/modules/JacksonModule.java index 10e59ef..d4f3ac7 100644 --- a/proteus-core/src/main/java/io/sinistral/proteus/modules/JacksonModule.java +++ b/proteus-core/src/main/java/io/sinistral/proteus/modules/JacksonModule.java @@ -7,7 +7,9 @@ import com.fasterxml.jackson.module.afterburner.AfterburnerModule; import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; import com.google.inject.AbstractModule; +import com.google.inject.Singleton; +@Singleton public class JacksonModule extends AbstractModule { @Override diff --git a/proteus-core/src/main/java/io/sinistral/proteus/modules/XmlModule.java b/proteus-core/src/main/java/io/sinistral/proteus/modules/XmlModule.java index 8381607..65df682 100644 --- a/proteus-core/src/main/java/io/sinistral/proteus/modules/XmlModule.java +++ b/proteus-core/src/main/java/io/sinistral/proteus/modules/XmlModule.java @@ -12,10 +12,12 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; import com.google.inject.AbstractModule; +import com.google.inject.Singleton; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLOutputFactory; +@Singleton public class XmlModule extends AbstractModule { @Override diff --git a/proteus-core/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java b/proteus-core/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java index 9ab0fa6..a899784 100644 --- a/proteus-core/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java +++ b/proteus-core/src/main/java/io/sinistral/proteus/server/handlers/HandlerGenerator.java @@ -92,7 +92,6 @@ public class HandlerGenerator { private static final Pattern CONCURRENT_TYPE_NAME_PATTERN = Pattern.compile("(java\\.util\\.concurrent\\.[A-Za-z]+)<([^>]+)", Pattern.DOTALL | Pattern.UNIX_LINES); - private static final String TMP_DIRECTORY_NAME = "proteus_generated_classes"; private static java.nio.file.Path TMP_DIRECTORY = null; @@ -109,6 +108,8 @@ public enum StatementParameterType { protected String packageName; + protected String canonicalName; + protected String className; protected String sourceString; @@ -129,7 +130,7 @@ public enum StatementParameterType { protected Map, String> typeLevelHandlerWrapperMap = new LinkedHashMap<>(); - final Map> typeTokenMap = new ConcurrentHashMap<>(); + final Map> typeTokenMap = new ConcurrentHashMap<>(); /** * Create a new {@code HandlerGenerator} instance used to generate a @@ -144,48 +145,20 @@ public HandlerGenerator(String packageName, Class controllerClass) this.packageName = packageName; this.controllerClass = controllerClass; this.className = controllerClass.getSimpleName() + "RouteSupplier"; + this.canonicalName = String.format("%s.%s", this.packageName, this.className); } - /** - * Compiles the generated source into a new {@link Class} - * - * @return a new {@code Supplier} class - */ - public Class compileClass() throws Exception - { - - String source = null; - - try - { - - if (TMP_DIRECTORY == null) - { - TMP_DIRECTORY = getTemporaryDirectoryPath(); - } - - source = this.generateClassSource(); - - // log.debug("\n\nGenerated Class Source:\n\n{}", source); - - try (CachedCompiler cachedCompiler = new CachedCompiler(null, null)) - { - return cachedCompiler.loadFromJava(packageName + "." + className, source); - } + public String getCanonicalName() { - } catch (Exception e) - { - log.error("Failed to compile {}\nSource:\n{}", packageName + "." + className, source, e); - throw e; - } + return canonicalName; } /** * Generates the routing Java source code */ - protected String generateClassSource() throws Exception + public String generateClassSource() throws Exception { TypeSpec.Builder typeBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC) @@ -239,27 +212,11 @@ protected String generateClassSource() throws Exception javaFile.writeTo(sb); - javaFile.writeToPath(TMP_DIRECTORY); + // javaFile.writeToPath(TMP_DIRECTORY); - return sb.toString(); - - } - - protected java.nio.file.Path getTemporaryDirectoryPath() throws Exception - { + this.sourceString = sb.toString(); - String tmpDirLocation = System.getProperty("java.io.tmpdir"); - - java.nio.file.Path tmpPath = Paths.get(tmpDirLocation); - - try - { - return Files.createDirectory(tmpPath.resolve(TMP_DIRECTORY_NAME)); - - } catch (Exception e) - { - return tmpPath; - } + return this.sourceString; } @@ -285,44 +242,40 @@ protected void addClassMethodHandlers(TypeSpec.Builder typeBuilder, Class cla .distinct().filter(t -> { - TypeHandler handler = TypeHandler.forType(t); return (handler.equals(TypeHandler.ModelType) || handler.equals(TypeHandler.OptionalModelType) || handler.equals(TypeHandler.NamedModelType) || handler.equals(TypeHandler.OptionalNamedModelType)); }).collect(Collectors.toMap(java.util.function.Function.identity(), ClassUtilities::typeReferenceNameForParameterizedType)); - java.util.regex.Pattern internalTypesPattern = java.util.regex.Pattern.compile("concurrent|<"); - final Map> googleParameterTypeTokens = Arrays.stream(clazz.getDeclaredMethods()) - .filter(m -> m.getAnnotation(Path.class) != null) - .flatMap( - m -> Invokable.from(m).getParameters().stream()) - .filter(p -> internalTypesPattern.matcher(p.getType().getType().getTypeName()).find() ) - .distinct().collect(Collectors.toMap(p -> p.getType().toString(), com.google.common.reflect.Parameter::getType, (p1, p2) -> p1 )); - - + final Map> googleParameterTypeTokens = Arrays.stream(clazz.getDeclaredMethods()) + .filter(m -> m.getAnnotation(Path.class) != null) + .flatMap( + m -> Invokable.from(m).getParameters().stream()) + .filter(p -> internalTypesPattern.matcher(p.getType().getType().getTypeName()).find()) + .distinct().collect(Collectors.toMap(p -> p.getType().toString(), com.google.common.reflect.Parameter::getType, (p1, p2) -> p1)); //log.info("googleParameterTypeTokens: {}",googleParameterTypeTokens); - Arrays.stream(clazz.getDeclaredMethods()) + Arrays.stream(clazz.getDeclaredMethods()) .filter(m -> m.getAnnotation(Path.class) != null) .forEach(m -> { - Invokable invokable = Invokable.from(m); + Invokable invokable = Invokable.from(m); List> parameterTokens = invokable.getParameters().stream().filter(p -> Objects.isNull(p.getAnnotation(BeanParam.class))).map(com.google.common.reflect.Parameter::getType).collect(Collectors.toList()); - // log.info("parameterTokens: {}",parameterTokens); + // log.info("parameterTokens: {}",parameterTokens); parameterTokens.forEach(rt -> { - // log.info("t:\n|{}|\n|{}|\n|{}|\ncached:\n|{}|",rt.getType(), rt.getRawType(), rt, typeTokenMap.get(rt.getType())); - typeTokenMap.put(rt.getType(),rt); + // log.info("t:\n|{}|\n|{}|\n|{}|\ncached:\n|{}|",rt.getType(), rt.getRawType(), rt, typeTokenMap.get(rt.getType())); + typeTokenMap.put(rt.getType(), rt); }); - // log.info("invokable: \ntype {}\n rawt {}\n hc {}\n params{}\n return type{}\n generic string {}\nog return type: {}",returnType.getType(),returnType.getRawType(),returnType.hashCode(), + // log.info("invokable: \ntype {}\n rawt {}\n hc {}\n params{}\n return type{}\n generic string {}\nog return type: {}",returnType.getType(),returnType.getRawType(),returnType.hashCode(), // m.getParameters(),m.getReturnType(),m.getReturnType().toGenericString(), // m.getReturnType()); - // typeTokenMap.put(m.getReturnType().getTypeName(),invokable.getReturnType()); + // typeTokenMap.put(m.getReturnType().getTypeName(),invokable.getReturnType()); }); Arrays.stream(clazz.getDeclaredMethods()) @@ -483,7 +436,7 @@ else if (t.equals(HttpServerExchange.class) || t.equals(ServerRequest.class)) continue; } - // log.debug("\n\nScanning method: {}\n", m.getName()); + // log.debug("\n\nScanning method: {}\n", m.getName()); EndpointInfo endpointInfo = new EndpointInfo(); @@ -631,9 +584,8 @@ else if (t.equals(HttpServerExchange.class) || t.equals(ServerRequest.class)) // // TypeToken token = invokable.getReturnType(); - // Object obj - MutableTypeToInstanceMap - // log.error("parameterized: {} \ntoken: {}\ntoken type: {}", p.getParameterizedType(), token, token.getType()); - + // Object obj - MutableTypeToInstanceMap + // log.error("parameterized: {} \ntoken: {}\ntoken type: {}", p.getParameterizedType(), token, token.getType()); TypeHandler t = TypeHandler.forType(p.getParameterizedType(), isBeanParameter); @@ -665,7 +617,7 @@ else if (t.equals(HttpServerExchange.class) || t.equals(ServerRequest.class)) List parameters = Arrays.stream(m.getParameters()).collect(Collectors.toList()); - // log.debug("parameterizedLiteralsNameMap: " + parameterizedLiteralsNameMap); + // log.debug("parameterizedLiteralsNameMap: " + parameterizedLiteralsNameMap); for (Parameter p : parameters) { diff --git a/proteus-openapi/src/main/java/io/sinistral/proteus/openapi/services/OpenAPIService.java b/proteus-openapi/src/main/java/io/sinistral/proteus/openapi/services/OpenAPIService.java index dedec6c..c00a2a5 100644 --- a/proteus-openapi/src/main/java/io/sinistral/proteus/openapi/services/OpenAPIService.java +++ b/proteus-openapi/src/main/java/io/sinistral/proteus/openapi/services/OpenAPIService.java @@ -58,6 +58,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ForkJoinPool; import java.util.function.Supplier; import java.util.jar.JarFile; import java.util.stream.Collectors; @@ -313,6 +314,21 @@ protected void generateSpec() throws Exception } + public OpenAPI getOpenApi() { + + return openApi; + } + + public String getYamlSpec() { + + return yamlSpec; + } + + public String getJsonSpec() { + + return jsonSpec; + } + @Override protected void startUp() throws Exception { @@ -321,7 +337,7 @@ protected void startUp() throws Exception generateHTML(); - CompletableFuture.runAsync(() -> + ForkJoinPool.commonPool().execute(() -> { try { @@ -360,9 +376,18 @@ public RoutingHandler get() router.add(HttpMethod.GET, yamlTemplatePath, (HttpServerExchange exchange) -> { + + String spec = getYamlSpec(); + + if(spec == null) + { + exchange.setStatusCode(404).setReasonPhrase("Spec has not yet been generated").endExchange(); + return; + } + exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, io.sinistral.proteus.protocol.MediaType.TEXT_YAML.contentType()); - exchange.getResponseSender().send(yamlSpec); + exchange.getResponseSender().send(spec); }); this.registeredEndpoints.add(EndpointInfo.builder() @@ -385,9 +410,17 @@ public RoutingHandler get() router.add(HttpMethod.GET, jsonTemplatePath, (HttpServerExchange exchange) -> { + final String spec = this.getJsonSpec(); + + if(spec == null) + { + exchange.setStatusCode(404).setReasonPhrase("Spec has not yet been generated").endExchange(); + return; + } + exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, io.sinistral.proteus.protocol.MediaType.JSON.contentType()); - exchange.getResponseSender().send(jsonSpec); + exchange.getResponseSender().send(spec); }); this.registeredEndpoints.add(EndpointInfo.builder()