diff --git a/core/deployment/src/main/java/io/quarkus/deployment/devmode/HotReplacementContext.java b/core/deployment/src/main/java/io/quarkus/deployment/devmode/HotReplacementContext.java index 286f649d4628d..c80fcff1ca047 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/devmode/HotReplacementContext.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/devmode/HotReplacementContext.java @@ -12,5 +12,10 @@ public interface HotReplacementContext { Throwable getDeploymentProblem(); - void doScan() throws Exception; + /** + * + * @return {@code true} if a restart was performed, {@code false} otherwise + * @throws Exception + */ + boolean doScan() throws Exception; } diff --git a/core/devmode/src/main/java/io/quarkus/dev/RuntimeUpdatesProcessor.java b/core/devmode/src/main/java/io/quarkus/dev/RuntimeUpdatesProcessor.java index 16d6ede9d4ad4..7ac621e8bc9fa 100644 --- a/core/devmode/src/main/java/io/quarkus/dev/RuntimeUpdatesProcessor.java +++ b/core/devmode/src/main/java/io/quarkus/dev/RuntimeUpdatesProcessor.java @@ -78,14 +78,15 @@ public Throwable getDeploymentProblem() { return DevModeMain.deploymentProblem; } - public void doScan() throws IOException { + public boolean doScan() throws IOException { final long startNanoseconds = System.nanoTime(); final ConcurrentMap changedClasses = scanForChangedClasses(); if (changedClasses == null) - return; + return false; DevModeMain.restartApp(); log.infof("Hot replace total time: %ss ", Timing.convertToBigDecimalSeconds(System.nanoTime() - startNanoseconds)); + return true; } ConcurrentMap scanForChangedClasses() throws IOException { diff --git a/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/VertxWebProcessor.java b/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/VertxWebProcessor.java index f032fa4a436d0..1e727f58f201b 100644 --- a/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/VertxWebProcessor.java +++ b/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/VertxWebProcessor.java @@ -39,6 +39,7 @@ import io.quarkus.deployment.builditem.FeatureBuildItem; import io.quarkus.deployment.builditem.GeneratedClassBuildItem; import io.quarkus.deployment.builditem.LaunchModeBuildItem; +import io.quarkus.deployment.builditem.ShutdownContextBuildItem; import io.quarkus.deployment.builditem.substrate.ReflectiveClassBuildItem; import io.quarkus.deployment.util.HashUtil; import io.quarkus.gizmo.ClassCreator; @@ -46,9 +47,10 @@ import io.quarkus.gizmo.MethodCreator; import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.gizmo.ResultHandle; +import io.quarkus.vertx.deployment.VertxBuildItem; import io.quarkus.vertx.web.Route; import io.quarkus.vertx.web.RoutingExchange; -import io.quarkus.vertx.web.runtime.HttpServerInitializer; +import io.quarkus.vertx.web.runtime.RouterProducer; import io.quarkus.vertx.web.runtime.RoutingExchangeImpl; import io.quarkus.vertx.web.runtime.VertxHttpConfiguration; import io.quarkus.vertx.web.runtime.VertxWebTemplate; @@ -73,7 +75,7 @@ BeanDeploymentValidatorBuildItem initialize(BuildProducer feat BuildProducer routeHandlerBusinessMethods, BuildProducer unremovableBeans) { - additionalBean.produce(new AdditionalBeanBuildItem(false, HttpServerInitializer.class)); + additionalBean.produce(new AdditionalBeanBuildItem(false, RouterProducer.class)); feature.produce(new FeatureBuildItem(FeatureBuildItem.VERTX_WEB)); unremovableBeans.produce(new UnremovableBeanBuildItem(new BeanClassAnnotationExclusion(ROUTE))); unremovableBeans.produce(new UnremovableBeanBuildItem(new BeanClassAnnotationExclusion(ROUTES))); @@ -118,7 +120,9 @@ void build(VertxWebTemplate template, BeanContainerBuildItem beanContainer, List routeHandlerBusinessMethods, BuildProducer generatedClass, AnnotationProxyBuildItem annotationProxy, LaunchModeBuildItem launchMode, - BuildProducer reflectiveClasses) { + BuildProducer reflectiveClasses, + ShutdownContextBuildItem shutdown, + VertxBuildItem vertx) { ClassOutput classOutput = new ClassOutput() { @Override @@ -135,7 +139,9 @@ public void write(String name, byte[] data) { routeConfigs.put(handlerClass, routes); reflectiveClasses.produce(new ReflectiveClassBuildItem(false, false, handlerClass)); } - template.configureRouter(beanContainer.getValue(), routeConfigs, vertxHttpConfiguration, launchMode.getLaunchMode()); + template.configureRouter(vertx.getVertx(), beanContainer.getValue(), routeConfigs, vertxHttpConfiguration, + launchMode.getLaunchMode(), + shutdown); } @BuildStep diff --git a/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/devmode/VertxHotReplacementSetup.java b/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/devmode/VertxHotReplacementSetup.java index 5f0a5b2befcff..5b0aee139da9b 100644 --- a/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/devmode/VertxHotReplacementSetup.java +++ b/extensions/vertx-web/deployment/src/main/java/io/quarkus/vertx/web/deployment/devmode/VertxHotReplacementSetup.java @@ -3,7 +3,7 @@ import io.quarkus.deployment.devmode.HotReplacementContext; import io.quarkus.deployment.devmode.HotReplacementSetup; import io.quarkus.deployment.devmode.ReplacementDebugPage; -import io.quarkus.vertx.web.runtime.HttpServerInitializer; +import io.quarkus.vertx.web.runtime.VertxWebTemplate; import io.vertx.core.http.HttpServerResponse; import io.vertx.ext.web.RoutingContext; @@ -17,7 +17,7 @@ public class VertxHotReplacementSetup implements HotReplacementSetup { @Override public void setupHotDeployment(HotReplacementContext context) { this.hotReplacementContext = context; - HttpServerInitializer.setHotReplacement(this::handleHotReplacementRequest); + VertxWebTemplate.setHotReplacement(this::handleHotReplacementRequest); } void handleHotReplacementRequest(RoutingContext routingContext) { @@ -30,10 +30,11 @@ void handleHotReplacementRequest(RoutingContext routingContext) { routingContext.next(); return; } + boolean restart = false; synchronized (this) { if (nextUpdate < System.currentTimeMillis()) { try { - hotReplacementContext.doScan(); + restart = hotReplacementContext.doScan(); } catch (Exception e) { throw new IllegalStateException("Unable to perform hot replacement scanning", e); } @@ -44,7 +45,11 @@ void handleHotReplacementRequest(RoutingContext routingContext) { handleDeploymentProblem(routingContext, hotReplacementContext.getDeploymentProblem()); return; } - routingContext.next(); + if (restart) { + routingContext.reroute(routingContext.request().path()); + } else { + routingContext.next(); + } } public static void handleDeploymentProblem(RoutingContext routingContext, final Throwable exception) { diff --git a/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/runtime/HttpServerInitializer.java b/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/runtime/HttpServerInitializer.java deleted file mode 100644 index c1a27daf69f0c..0000000000000 --- a/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/runtime/HttpServerInitializer.java +++ /dev/null @@ -1,174 +0,0 @@ -package io.quarkus.vertx.web.runtime; - -import java.lang.reflect.InvocationTargetException; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.CountDownLatch; - -import javax.enterprise.context.ApplicationScoped; -import javax.enterprise.event.Event; -import javax.enterprise.inject.Produces; -import javax.inject.Inject; -import javax.inject.Singleton; - -import org.jboss.logging.Logger; - -import io.quarkus.runtime.LaunchMode; -import io.quarkus.runtime.Timing; -import io.quarkus.vertx.web.Route; -import io.vertx.core.Handler; -import io.vertx.core.Vertx; -import io.vertx.core.http.HttpMethod; -import io.vertx.core.http.HttpServerOptions; -import io.vertx.ext.web.Router; -import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.handler.BodyHandler; - -/** - * NOTE: The HTTP server instance is closed within {@link io.quarkus.vertx.runtime.VertxProducer#destroy()}. - */ -@Singleton -public class HttpServerInitializer { - - public static void setHotReplacement(Handler handler) { - hotReplacementHandler = handler; - } - - private static final Logger LOGGER = Logger.getLogger(HttpServerInitializer.class.getName()); - - private static volatile Handler hotReplacementHandler; - - private volatile Router router; - private volatile io.vertx.reactivex.ext.web.Router rxRouter; - - @Inject - Vertx vertx; - - @Inject - Event routerEvent; - - @Inject - Event serverOptionsEvent; - - void initialize(VertxHttpConfiguration vertxHttpConfiguration, Map> routeHandlers, - LaunchMode launchMode) { - Router router = Router.router(vertx); - router.route().handler(BodyHandler.create()); - if (hotReplacementHandler != null) { - router.route().blockingHandler(hotReplacementHandler); - } - for (Entry> entry : routeHandlers.entrySet()) { - Handler handler = createHandler(entry.getKey()); - for (Route route : entry.getValue()) { - addRoute(router, handler, route); - } - } - // Make it also possible to register the route handlers programatically - routerEvent.fire(router); - this.router = router; - this.rxRouter = io.vertx.reactivex.ext.web.Router.newInstance(router); - // Http server configuration - HttpServerOptions httpServerOptions = createHttpServerOptions(vertxHttpConfiguration, launchMode); - serverOptionsEvent.fire(httpServerOptions); - // Start the server - CountDownLatch latch = new CountDownLatch(1); - vertx.createHttpServer(httpServerOptions).requestHandler(router) - .listen(ar -> { - if (ar.succeeded()) { - // TODO log proper message - Timing.setHttpServer(String.format( - "Listening on: http://%s:%s", httpServerOptions.getHost(), httpServerOptions.getPort())); - latch.countDown(); - } - }); - try { - latch.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new IllegalStateException("Unable to start the HTTP server", e); - } - } - - // Note that we need a client proxy because if a bean also @Observes Router a null value would be injected - @ApplicationScoped - @Produces - Router produceRouter() { - return router; - } - - @ApplicationScoped - @Produces - io.vertx.reactivex.ext.web.Router produceRxRouter() { - return rxRouter; - } - - private HttpServerOptions createHttpServerOptions(VertxHttpConfiguration vertxHttpConfiguration, LaunchMode launchMode) { - // TODO other config properties - HttpServerOptions options = new HttpServerOptions(); - options.setHost(vertxHttpConfiguration.host); - options.setPort(vertxHttpConfiguration.determinePort(launchMode)); - return options; - } - - private void addRoute(Router router, Handler handler, Route routeAnnotation) { - io.vertx.ext.web.Route route; - if (!routeAnnotation.regex().isEmpty()) { - route = router.routeWithRegex(routeAnnotation.regex()); - } else if (!routeAnnotation.path().isEmpty()) { - route = router.route(routeAnnotation.path()); - } else { - route = router.route(); - } - if (routeAnnotation.methods().length > 0) { - for (HttpMethod method : routeAnnotation.methods()) { - route.method(method); - } - } - if (routeAnnotation.order() != Integer.MIN_VALUE) { - route.order(routeAnnotation.order()); - } - if (routeAnnotation.produces().length > 0) { - for (String produces : routeAnnotation.produces()) { - route.produces(produces); - } - } - if (routeAnnotation.consumes().length > 0) { - for (String consumes : routeAnnotation.consumes()) { - route.consumes(consumes); - } - } - switch (routeAnnotation.type()) { - case NORMAL: - route.handler(handler); - break; - case BLOCKING: - // We don't mind if blocking handlers are executed in parallel - route.blockingHandler(handler, false); - break; - case FAILURE: - route.failureHandler(handler); - break; - default: - throw new IllegalStateException("Unsupported handler type: " + routeAnnotation.type()); - } - LOGGER.debugf("Route registered for %s", routeAnnotation); - } - - @SuppressWarnings("unchecked") - private Handler createHandler(String handlerClassName) { - try { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - if (cl == null) { - cl = HttpServerInitializer.class.getClassLoader(); - } - Class> handlerClazz = (Class>) cl - .loadClass(handlerClassName); - return handlerClazz.getDeclaredConstructor().newInstance(); - } catch (InstantiationException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException - | InvocationTargetException e) { - throw new IllegalStateException("Unable to create invoker: " + handlerClassName, e); - } - } - -} diff --git a/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/runtime/RouterProducer.java b/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/runtime/RouterProducer.java new file mode 100644 index 0000000000000..671ebded49fa8 --- /dev/null +++ b/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/runtime/RouterProducer.java @@ -0,0 +1,25 @@ +package io.quarkus.vertx.web.runtime; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Produces; +import javax.inject.Singleton; + +import io.vertx.ext.web.Router; + +@Singleton +public class RouterProducer { + + private volatile Router router; + + void initialize(Router router) { + this.router = router; + } + + // Note that we need a client proxy because if a bean also @Observes Router a null value would be injected + @ApplicationScoped + @Produces + Router produceRouter() { + return router; + } + +} diff --git a/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/runtime/VertxWebTemplate.java b/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/runtime/VertxWebTemplate.java index 8e85ac307b4c5..f3aa6ac818157 100644 --- a/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/runtime/VertxWebTemplate.java +++ b/extensions/vertx-web/runtime/src/main/java/io/quarkus/vertx/web/runtime/VertxWebTemplate.java @@ -1,18 +1,179 @@ package io.quarkus.vertx.web.runtime; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.CountDownLatch; +import javax.enterprise.event.Event; + +import org.jboss.logging.Logger; + +import io.quarkus.arc.Arc; import io.quarkus.arc.runtime.BeanContainer; import io.quarkus.runtime.LaunchMode; +import io.quarkus.runtime.RuntimeValue; +import io.quarkus.runtime.ShutdownContext; +import io.quarkus.runtime.Timing; import io.quarkus.runtime.annotations.Template; import io.quarkus.vertx.web.Route; +import io.vertx.core.Handler; +import io.vertx.core.Vertx; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServer; +import io.vertx.core.http.HttpServerOptions; +import io.vertx.ext.web.Router; +import io.vertx.ext.web.RoutingContext; +import io.vertx.ext.web.handler.BodyHandler; @Template public class VertxWebTemplate { - public void configureRouter(BeanContainer container, Map> routeHandlers, - VertxHttpConfiguration vertxHttpConfiguration, LaunchMode launchMode) { - container.instance(HttpServerInitializer.class).initialize(vertxHttpConfiguration, routeHandlers, launchMode); + public static void setHotReplacement(Handler handler) { + hotReplacementHandler = handler; + } + + private static final Logger LOGGER = Logger.getLogger(VertxWebTemplate.class.getName()); + + private static volatile Handler hotReplacementHandler; + + private static volatile Router router; + private static volatile HttpServer server; + + public void configureRouter(RuntimeValue vertx, BeanContainer container, Map> routeHandlers, + VertxHttpConfiguration vertxHttpConfiguration, LaunchMode launchMode, ShutdownContext shutdown) { + + List appRoutes = initialize(vertx.getValue(), vertxHttpConfiguration, routeHandlers, + launchMode); + container.instance(RouterProducer.class).initialize(router); + + if (launchMode == LaunchMode.DEVELOPMENT) { + shutdown.addShutdownTask(new Runnable() { + @Override + public void run() { + for (io.vertx.ext.web.Route route : appRoutes) { + route.remove(); + } + } + }); + } } + + List initialize(Vertx vertx, VertxHttpConfiguration vertxHttpConfiguration, + Map> routeHandlers, + LaunchMode launchMode) { + List routes = new ArrayList<>(); + if (router == null) { + router = Router.router(vertx); + router.route().handler(BodyHandler.create()); + if (hotReplacementHandler != null) { + router.route().blockingHandler(hotReplacementHandler); + } + } + for (Entry> entry : routeHandlers.entrySet()) { + Handler handler = createHandler(entry.getKey()); + for (Route route : entry.getValue()) { + routes.add(addRoute(router, handler, route)); + } + } + // Make it also possible to register the route handlers programatically + Event event = Arc.container().beanManager().getEvent(); + event.select(Router.class).fire(router); + + // Start the server + if (server == null) { + CountDownLatch latch = new CountDownLatch(1); + // Http server configuration + HttpServerOptions httpServerOptions = createHttpServerOptions(vertxHttpConfiguration, launchMode); + event.select(HttpServerOptions.class).fire(httpServerOptions); + server = vertx.createHttpServer(httpServerOptions).requestHandler(router) + .listen(ar -> { + if (ar.succeeded()) { + // TODO log proper message + Timing.setHttpServer(String.format( + "Listening on: http://%s:%s", httpServerOptions.getHost(), httpServerOptions.getPort())); + latch.countDown(); + } + }); + try { + latch.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException("Unable to start the HTTP server", e); + } + } + return routes; + } + + private HttpServerOptions createHttpServerOptions(VertxHttpConfiguration vertxHttpConfiguration, LaunchMode launchMode) { + // TODO other config properties + HttpServerOptions options = new HttpServerOptions(); + options.setHost(vertxHttpConfiguration.host); + options.setPort(vertxHttpConfiguration.determinePort(launchMode)); + return options; + } + + private io.vertx.ext.web.Route addRoute(Router router, Handler handler, Route routeAnnotation) { + io.vertx.ext.web.Route route; + if (!routeAnnotation.regex().isEmpty()) { + route = router.routeWithRegex(routeAnnotation.regex()); + } else if (!routeAnnotation.path().isEmpty()) { + route = router.route(routeAnnotation.path()); + } else { + route = router.route(); + } + if (routeAnnotation.methods().length > 0) { + for (HttpMethod method : routeAnnotation.methods()) { + route.method(method); + } + } + if (routeAnnotation.order() != Integer.MIN_VALUE) { + route.order(routeAnnotation.order()); + } + if (routeAnnotation.produces().length > 0) { + for (String produces : routeAnnotation.produces()) { + route.produces(produces); + } + } + if (routeAnnotation.consumes().length > 0) { + for (String consumes : routeAnnotation.consumes()) { + route.consumes(consumes); + } + } + switch (routeAnnotation.type()) { + case NORMAL: + route.handler(handler); + break; + case BLOCKING: + // We don't mind if blocking handlers are executed in parallel + route.blockingHandler(handler, false); + break; + case FAILURE: + route.failureHandler(handler); + break; + default: + throw new IllegalStateException("Unsupported handler type: " + routeAnnotation.type()); + } + LOGGER.debugf("Route registered for %s", routeAnnotation); + return route; + } + + @SuppressWarnings("unchecked") + private Handler createHandler(String handlerClassName) { + try { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl == null) { + cl = RouterProducer.class.getClassLoader(); + } + Class> handlerClazz = (Class>) cl + .loadClass(handlerClassName); + return handlerClazz.getDeclaredConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException + | InvocationTargetException e) { + throw new IllegalStateException("Unable to create invoker: " + handlerClassName, e); + } + } + } diff --git a/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/VertxBuildItem.java b/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/VertxBuildItem.java new file mode 100644 index 0000000000000..78106daced2ef --- /dev/null +++ b/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/VertxBuildItem.java @@ -0,0 +1,20 @@ +package io.quarkus.vertx.deployment; + +import org.jboss.builder.item.SimpleBuildItem; + +import io.quarkus.runtime.RuntimeValue; +import io.vertx.core.Vertx; + +public final class VertxBuildItem extends SimpleBuildItem { + + private final RuntimeValue vertx; + + public VertxBuildItem(RuntimeValue vertx) { + this.vertx = vertx; + } + + public RuntimeValue getVertx() { + return vertx; + } + +} diff --git a/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/VertxProcessor.java b/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/VertxProcessor.java index 215c95c74c1bf..10a604ae5f0f8 100644 --- a/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/VertxProcessor.java +++ b/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/VertxProcessor.java @@ -54,6 +54,8 @@ import io.quarkus.deployment.builditem.AnnotationProxyBuildItem; import io.quarkus.deployment.builditem.FeatureBuildItem; import io.quarkus.deployment.builditem.GeneratedClassBuildItem; +import io.quarkus.deployment.builditem.LaunchModeBuildItem; +import io.quarkus.deployment.builditem.ShutdownContextBuildItem; import io.quarkus.deployment.builditem.substrate.ReflectiveClassBuildItem; import io.quarkus.deployment.builditem.substrate.SubstrateConfigBuildItem; import io.quarkus.deployment.util.HashUtil; @@ -64,11 +66,13 @@ import io.quarkus.gizmo.MethodCreator; import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.gizmo.ResultHandle; +import io.quarkus.runtime.RuntimeValue; import io.quarkus.vertx.ConsumeEvent; import io.quarkus.vertx.runtime.EventConsumerInvoker; import io.quarkus.vertx.runtime.VertxConfiguration; import io.quarkus.vertx.runtime.VertxProducer; import io.quarkus.vertx.runtime.VertxTemplate; +import io.vertx.core.Vertx; import io.vertx.core.eventbus.Message; class VertxProcessor { @@ -85,16 +89,9 @@ class VertxProcessor { @BuildStep SubstrateConfigBuildItem build() { - return SubstrateConfigBuildItem.builder() - .addNativeImageSystemProperty("vertx.disableDnsResolver", "true") - .build(); + return SubstrateConfigBuildItem.builder().addNativeImageSystemProperty("vertx.disableDnsResolver", "true").build(); } - /** - * The Vert.x configuration, if set. - */ - VertxConfiguration vertx; - @BuildStep AdditionalBeanBuildItem registerBean() { return new AdditionalBeanBuildItem(false, VertxProducer.class); @@ -102,10 +99,11 @@ AdditionalBeanBuildItem registerBean() { @BuildStep @Record(ExecutionTime.RUNTIME_INIT) - void build(VertxTemplate template, BeanContainerBuildItem beanContainer, BuildProducer feature, + VertxBuildItem build(VertxTemplate template, BeanContainerBuildItem beanContainer, BuildProducer feature, List messageConsumerBusinessMethods, BuildProducer generatedClass, - AnnotationProxyBuildItem annotationProxy) { + AnnotationProxyBuildItem annotationProxy, LaunchModeBuildItem launchMode, ShutdownContextBuildItem shutdown, + VertxConfiguration config) { feature.produce(new FeatureBuildItem(FeatureBuildItem.VERTX)); Map messageConsumerConfigurations = new HashMap<>(); ClassOutput classOutput = new ClassOutput() { @@ -121,7 +119,10 @@ public void write(String name, byte[] data) { .withDefaultValue("value", businessMethod.getBean().getBeanClass().toString()).build()); reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, invokerClass)); } - template.configureVertx(beanContainer.getValue(), vertx, messageConsumerConfigurations); + RuntimeValue vertx = template.configureVertx(beanContainer.getValue(), config, messageConsumerConfigurations, + launchMode.getLaunchMode(), + shutdown); + return new VertxBuildItem(vertx); } @BuildStep diff --git a/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxProducer.java b/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxProducer.java index 93db0a2978cb2..ccb40ec1b1701 100644 --- a/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxProducer.java +++ b/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxProducer.java @@ -1,32 +1,11 @@ package io.quarkus.vertx.runtime; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import javax.annotation.PreDestroy; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Produces; import javax.inject.Singleton; -import io.quarkus.vertx.ConsumeEvent; import io.vertx.core.Vertx; -import io.vertx.core.VertxOptions; import io.vertx.core.eventbus.EventBus; -import io.vertx.core.eventbus.EventBusOptions; -import io.vertx.core.eventbus.MessageConsumer; -import io.vertx.core.file.FileSystemOptions; -import io.vertx.core.http.ClientAuth; -import io.vertx.core.net.JksOptions; -import io.vertx.core.net.PemKeyCertOptions; -import io.vertx.core.net.PemTrustOptions; -import io.vertx.core.net.PfxOptions; /** * Produces a configured Vert.x instance. @@ -35,297 +14,50 @@ @ApplicationScoped public class VertxProducer { - private volatile VertxConfiguration conf; private volatile Vertx vertx; - private volatile io.vertx.axle.core.Vertx axle; - private volatile io.vertx.reactivex.core.Vertx rx; - - private void createCompanions(Vertx instance) { - this.vertx = instance == null ? Vertx.vertx() : instance; - this.axle = io.vertx.axle.core.Vertx.newInstance(this.vertx); - this.rx = io.vertx.reactivex.core.Vertx.newInstance(this.vertx); - } - - private void initialize() { - if (conf == null) { - createCompanions(null); - return; - } - - VertxOptions options = convertToVertxOptions(conf); - - if (!conf.useAsyncDNS) { - System.setProperty("vertx.disableDnsResolver", "true"); - } - - System.setProperty("vertx.cacheDirBase", System.getProperty("java.io.tmpdir")); - - if (options.isClustered()) { - AtomicReference failure = new AtomicReference<>(); - CountDownLatch latch = new CountDownLatch(1); - Vertx.clusteredVertx(options, ar -> { - if (ar.failed()) { - failure.set(ar.cause()); - } else { - createCompanions(ar.result()); - } - latch.countDown(); - }); - try { - latch.await(); - if (failure.get() != null) { - throw new IllegalStateException("Unable to initialize the Vert.x instance", failure.get()); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new IllegalStateException("Unable to initialize the Vert.x instance", e); - } - } else { - createCompanions(Vertx.vertx(options)); - } - } - - private VertxOptions convertToVertxOptions(VertxConfiguration conf) { - VertxOptions options = new VertxOptions(); - // Order matters, as the cluster options modifies the event bus options. - setEventBusOptions(options); - initializeClusterOptions(options); - - options.setFileSystemOptions(new FileSystemOptions() - .setFileCachingEnabled(conf.caching) - .setClassPathResolvingEnabled(conf.classpathResolving)); - options.setWorkerPoolSize(conf.workerPoolSize); - options.setBlockedThreadCheckInterval(conf.warningExceptionTime.toMillis()); - options.setInternalBlockingPoolSize(conf.internalBlockingPoolSize); - if (conf.eventLoopsPoolSize.isPresent()) { - options.setEventLoopPoolSize(conf.eventLoopsPoolSize.getAsInt()); - } - // TODO - Add the ability to configure these times in ns when long will be supported - // options.setMaxEventLoopExecuteTime(conf.maxEventLoopExecuteTime) - // .setMaxWorkerExecuteTime(conf.maxWorkerExecuteTime) - options.setWarningExceptionTime(conf.warningExceptionTime.toNanos()); - - return options; - } - - @PreDestroy - public void destroy() { - if (vertx != null) { - CountDownLatch latch = new CountDownLatch(1); - AtomicReference problem = new AtomicReference<>(); - vertx.close(ar -> { - if (ar.failed()) { - problem.set(ar.cause()); - } - latch.countDown(); - }); - try { - latch.await(); - if (problem.get() != null) { - throw new IllegalStateException("Error when closing Vertx instance", problem.get()); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new IllegalStateException("Interrupted when closing Vertx instance", e); - } - } - } - - private void initializeClusterOptions(VertxOptions options) { - ClusterConfiguration cluster = conf.cluster; - options.setClustered(cluster.clustered); - options.setClusterPingReplyInterval(cluster.pingReplyInterval.toMillis()); - options.setClusterPingInterval(cluster.pingInterval.toMillis()); - if (cluster.host != null) { - options.setClusterHost(cluster.host); - } - if (cluster.port.isPresent()) { - options.setClusterPort(cluster.port.getAsInt()); - } - cluster.publicHost.ifPresent(options::setClusterPublicHost); - if (cluster.publicPort.isPresent()) { - options.setClusterPort(cluster.publicPort.getAsInt()); - } - } - - private void setEventBusOptions(VertxOptions options) { - EventBusConfiguration eb = conf.eventbus; - EventBusOptions opts = new EventBusOptions(); - opts.setAcceptBacklog(eb.acceptBacklog.orElse(-1)); - opts.setClientAuth(ClientAuth.valueOf(eb.clientAuth.toUpperCase())); - opts.setConnectTimeout((int) (Math.min(Integer.MAX_VALUE, eb.connectTimeout.toMillis()))); - // todo: use timeUnit cleverly - opts.setIdleTimeout( - eb.idleTimeout.isPresent() ? (int) Math.max(1, Math.min(Integer.MAX_VALUE, eb.idleTimeout.get().getSeconds())) - : 0); - opts.setSendBufferSize(eb.sendBufferSize.orElse(-1)); - opts.setSoLinger(eb.soLinger.orElse(-1)); - opts.setSsl(eb.ssl); - opts.setReceiveBufferSize(eb.receiveBufferSize.orElse(-1)); - opts.setReconnectAttempts(eb.reconnectAttempts); - opts.setReconnectInterval(eb.reconnectInterval.toMillis()); - opts.setReuseAddress(eb.reuseAddress); - opts.setReusePort(eb.reusePort); - opts.setTrafficClass(eb.trafficClass.orElse(-1)); - opts.setTcpKeepAlive(eb.tcpKeepAlive); - opts.setTcpNoDelay(eb.tcpNoDelay); - opts.setTrustAll(eb.trustAll); - - // Certificates and trust. - if (eb.keyCertificatePem != null) { - List certs = new ArrayList<>(); - List keys = new ArrayList<>(); - eb.keyCertificatePem.certs.ifPresent( - s -> certs.addAll(Pattern.compile(",").splitAsStream(s).map(String::trim).collect(Collectors.toList()))); - eb.keyCertificatePem.keys.ifPresent( - s -> keys.addAll(Pattern.compile(",").splitAsStream(s).map(String::trim).collect(Collectors.toList()))); - PemKeyCertOptions o = new PemKeyCertOptions() - .setCertPaths(certs) - .setKeyPaths(keys); - opts.setPemKeyCertOptions(o); - } - - if (eb.keyCertificateJks != null) { - JksOptions o = new JksOptions(); - eb.keyCertificateJks.path.ifPresent(o::setPath); - eb.keyCertificateJks.password.ifPresent(o::setPassword); - opts.setKeyStoreOptions(o); - } - - if (eb.keyCertificatePfx != null) { - PfxOptions o = new PfxOptions(); - eb.keyCertificatePfx.path.ifPresent(o::setPath); - eb.keyCertificatePfx.password.ifPresent(o::setPassword); - opts.setPfxKeyCertOptions(o); - } + private volatile io.vertx.axle.core.Vertx axleVertx; + private volatile io.vertx.reactivex.core.Vertx rxVertx; - if (eb.trustCertificatePem != null) { - eb.trustCertificatePem.certs.ifPresent(s -> { - PemTrustOptions o = new PemTrustOptions(); - Pattern.compile(",").splitAsStream(s).map(String::trim).forEach(o::addCertPath); - opts.setPemTrustOptions(o); - }); - } - - if (eb.trustCertificateJks != null) { - JksOptions o = new JksOptions(); - eb.trustCertificateJks.path.ifPresent(o::setPath); - eb.trustCertificateJks.password.ifPresent(o::setPassword); - opts.setTrustStoreOptions(o); - } - - if (eb.trustCertificatePfx != null) { - PfxOptions o = new PfxOptions(); - eb.trustCertificatePfx.path.ifPresent(o::setPath); - eb.trustCertificatePfx.password.ifPresent(o::setPassword); - opts.setPfxTrustOptions(o); - } - options.setEventBusOptions(opts); + void initialize(Vertx vertx) { + this.vertx = vertx; + this.axleVertx = io.vertx.axle.core.Vertx.newInstance(vertx); + this.rxVertx = io.vertx.reactivex.core.Vertx.newInstance(vertx); } @Singleton @Produces - public synchronized Vertx vertx() { - if (vertx != null) { - return vertx; - } - initialize(); - return this.vertx; + public Vertx vertx() { + return vertx; } @Singleton @Produces - public synchronized io.vertx.axle.core.Vertx axle() { - if (this.axle != null) { - return this.axle; - } - initialize(); - return this.axle; + public io.vertx.axle.core.Vertx axle() { + return axleVertx; } @Singleton @Produces - public synchronized io.vertx.reactivex.core.Vertx rx() { - if (this.rx != null) { - return this.rx; - } - initialize(); - return this.rx; + public io.vertx.reactivex.core.Vertx rx() { + return rxVertx; } @Singleton @Produces - public synchronized EventBus eventbus() { - if (vertx == null) { - initialize(); - } - return this.vertx.eventBus(); + public EventBus eventbus() { + return vertx.eventBus(); } @Singleton @Produces - public synchronized io.vertx.axle.core.eventbus.EventBus axleEventbus() { - if (vertx == null) { - initialize(); - } - return this.axle.eventBus(); + public io.vertx.axle.core.eventbus.EventBus axleEventbus() { + return axleVertx.eventBus(); } @Singleton @Produces public synchronized io.vertx.reactivex.core.eventbus.EventBus rxRventbus() { - if (vertx == null) { - initialize(); - } - return this.rx.eventBus(); - } - - void configure(VertxConfiguration config) { - this.conf = config; + return rxVertx.eventBus(); } - void registerMessageConsumers(Map messageConsumerConfigurations) { - if (!messageConsumerConfigurations.isEmpty()) { - EventBus eventBus = eventbus(); - CountDownLatch latch = new CountDownLatch(messageConsumerConfigurations.size()); - for (Entry entry : messageConsumerConfigurations.entrySet()) { - EventConsumerInvoker invoker = createInvoker(entry.getKey()); - String address = entry.getValue().value(); - MessageConsumer consumer; - if (entry.getValue().local()) { - consumer = eventBus.localConsumer(address); - } else { - consumer = eventBus.consumer(address); - } - consumer.handler(m -> invoker.invoke(m)); - consumer.completionHandler(ar -> { - if (ar.succeeded()) { - latch.countDown(); - } - }); - } - try { - latch.await(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new IllegalStateException("Unable to register all message consumer methods", e); - } - } - } - - @SuppressWarnings("unchecked") - private EventConsumerInvoker createInvoker(String invokerClassName) { - try { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - if (cl == null) { - cl = VertxProducer.class.getClassLoader(); - } - Class invokerClazz = (Class) cl - .loadClass(invokerClassName); - return invokerClazz.getDeclaredConstructor().newInstance(); - } catch (InstantiationException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException - | InvocationTargetException e) { - throw new IllegalStateException("Unable to create invoker: " + invokerClassName, e); - } - } } diff --git a/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxTemplate.java b/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxTemplate.java index f5f5ab9e61bd8..fc9b338154f51 100644 --- a/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxTemplate.java +++ b/extensions/vertx/runtime/src/main/java/io/quarkus/vertx/runtime/VertxTemplate.java @@ -1,18 +1,311 @@ package io.quarkus.vertx.runtime; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import io.quarkus.arc.runtime.BeanContainer; +import io.quarkus.runtime.LaunchMode; +import io.quarkus.runtime.RuntimeValue; +import io.quarkus.runtime.ShutdownContext; import io.quarkus.runtime.annotations.Template; import io.quarkus.vertx.ConsumeEvent; +import io.vertx.core.Vertx; +import io.vertx.core.VertxOptions; +import io.vertx.core.eventbus.EventBus; +import io.vertx.core.eventbus.EventBusOptions; +import io.vertx.core.eventbus.MessageConsumer; +import io.vertx.core.file.FileSystemOptions; +import io.vertx.core.http.ClientAuth; +import io.vertx.core.net.JksOptions; +import io.vertx.core.net.PemKeyCertOptions; +import io.vertx.core.net.PemTrustOptions; +import io.vertx.core.net.PfxOptions; @Template public class VertxTemplate { - public void configureVertx(BeanContainer container, VertxConfiguration config, - Map messageConsumerConfigurations) { - VertxProducer instance = container.instance(VertxProducer.class); - instance.configure(config); - instance.registerMessageConsumers(messageConsumerConfigurations); + static volatile Vertx vertx; + static volatile List> messageConsumers; + + public RuntimeValue configureVertx(BeanContainer container, VertxConfiguration config, + Map messageConsumerConfigurations, + LaunchMode launchMode, ShutdownContext shutdown) { + + initialize(config); + registerMessageConsumers(messageConsumerConfigurations); + + VertxProducer producer = container.instance(VertxProducer.class); + producer.initialize(vertx); + if (launchMode == LaunchMode.DEVELOPMENT) { + shutdown.addShutdownTask(new Runnable() { + @Override + public void run() { + unregisterMessageConsumers(); + } + }); + } else { + shutdown.addShutdownTask(new Runnable() { + @Override + public void run() { + destroy(); + } + }); + } + return new RuntimeValue(vertx); } + + void initialize(VertxConfiguration conf) { + if (vertx != null) { + return; + } + if (conf == null) { + vertx = Vertx.vertx(); + return; + } + + VertxOptions options = convertToVertxOptions(conf); + + if (!conf.useAsyncDNS) { + System.setProperty("vertx.disableDnsResolver", "true"); + } + + System.setProperty("vertx.cacheDirBase", System.getProperty("java.io.tmpdir")); + + if (options.isClustered()) { + AtomicReference failure = new AtomicReference<>(); + CountDownLatch latch = new CountDownLatch(1); + Vertx.clusteredVertx(options, ar -> { + if (ar.failed()) { + failure.set(ar.cause()); + } else { + vertx = ar.result(); + } + latch.countDown(); + }); + try { + latch.await(); + if (failure.get() != null) { + throw new IllegalStateException("Unable to initialize the Vert.x instance", failure.get()); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException("Unable to initialize the Vert.x instance", e); + } + } else { + vertx = Vertx.vertx(options); + } + + messageConsumers = new ArrayList<>(); + } + + private VertxOptions convertToVertxOptions(VertxConfiguration conf) { + VertxOptions options = new VertxOptions(); + // Order matters, as the cluster options modifies the event bus options. + setEventBusOptions(conf, options); + initializeClusterOptions(conf, options); + + options.setFileSystemOptions(new FileSystemOptions() + .setFileCachingEnabled(conf.caching) + .setClassPathResolvingEnabled(conf.classpathResolving)); + options.setWorkerPoolSize(conf.workerPoolSize); + options.setBlockedThreadCheckInterval(conf.warningExceptionTime.toMillis()); + options.setInternalBlockingPoolSize(conf.internalBlockingPoolSize); + if (conf.eventLoopsPoolSize.isPresent()) { + options.setEventLoopPoolSize(conf.eventLoopsPoolSize.getAsInt()); + } + // TODO - Add the ability to configure these times in ns when long will be supported + // options.setMaxEventLoopExecuteTime(conf.maxEventLoopExecuteTime) + // .setMaxWorkerExecuteTime(conf.maxWorkerExecuteTime) + options.setWarningExceptionTime(conf.warningExceptionTime.toNanos()); + + return options; + } + + void destroy() { + if (vertx != null) { + CountDownLatch latch = new CountDownLatch(1); + AtomicReference problem = new AtomicReference<>(); + vertx.close(ar -> { + if (ar.failed()) { + problem.set(ar.cause()); + } + latch.countDown(); + }); + try { + latch.await(); + if (problem.get() != null) { + throw new IllegalStateException("Error when closing Vertx instance", problem.get()); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException("Interrupted when closing Vertx instance", e); + } + vertx = null; + messageConsumers = null; + } + } + + private void initializeClusterOptions(VertxConfiguration conf, VertxOptions options) { + ClusterConfiguration cluster = conf.cluster; + options.setClustered(cluster.clustered); + options.setClusterPingReplyInterval(cluster.pingReplyInterval.toMillis()); + options.setClusterPingInterval(cluster.pingInterval.toMillis()); + if (cluster.host != null) { + options.setClusterHost(cluster.host); + } + if (cluster.port.isPresent()) { + options.setClusterPort(cluster.port.getAsInt()); + } + cluster.publicHost.ifPresent(options::setClusterPublicHost); + if (cluster.publicPort.isPresent()) { + options.setClusterPort(cluster.publicPort.getAsInt()); + } + } + + private void setEventBusOptions(VertxConfiguration conf, VertxOptions options) { + EventBusConfiguration eb = conf.eventbus; + EventBusOptions opts = new EventBusOptions(); + opts.setAcceptBacklog(eb.acceptBacklog.orElse(-1)); + opts.setClientAuth(ClientAuth.valueOf(eb.clientAuth.toUpperCase())); + opts.setConnectTimeout((int) (Math.min(Integer.MAX_VALUE, eb.connectTimeout.toMillis()))); + // todo: use timeUnit cleverly + opts.setIdleTimeout( + eb.idleTimeout.isPresent() ? (int) Math.max(1, Math.min(Integer.MAX_VALUE, eb.idleTimeout.get().getSeconds())) + : 0); + opts.setSendBufferSize(eb.sendBufferSize.orElse(-1)); + opts.setSoLinger(eb.soLinger.orElse(-1)); + opts.setSsl(eb.ssl); + opts.setReceiveBufferSize(eb.receiveBufferSize.orElse(-1)); + opts.setReconnectAttempts(eb.reconnectAttempts); + opts.setReconnectInterval(eb.reconnectInterval.toMillis()); + opts.setReuseAddress(eb.reuseAddress); + opts.setReusePort(eb.reusePort); + opts.setTrafficClass(eb.trafficClass.orElse(-1)); + opts.setTcpKeepAlive(eb.tcpKeepAlive); + opts.setTcpNoDelay(eb.tcpNoDelay); + opts.setTrustAll(eb.trustAll); + + // Certificates and trust. + if (eb.keyCertificatePem != null) { + List certs = new ArrayList<>(); + List keys = new ArrayList<>(); + eb.keyCertificatePem.certs.ifPresent( + s -> certs.addAll(Pattern.compile(",").splitAsStream(s).map(String::trim).collect(Collectors.toList()))); + eb.keyCertificatePem.keys.ifPresent( + s -> keys.addAll(Pattern.compile(",").splitAsStream(s).map(String::trim).collect(Collectors.toList()))); + PemKeyCertOptions o = new PemKeyCertOptions() + .setCertPaths(certs) + .setKeyPaths(keys); + opts.setPemKeyCertOptions(o); + } + + if (eb.keyCertificateJks != null) { + JksOptions o = new JksOptions(); + eb.keyCertificateJks.path.ifPresent(o::setPath); + eb.keyCertificateJks.password.ifPresent(o::setPassword); + opts.setKeyStoreOptions(o); + } + + if (eb.keyCertificatePfx != null) { + PfxOptions o = new PfxOptions(); + eb.keyCertificatePfx.path.ifPresent(o::setPath); + eb.keyCertificatePfx.password.ifPresent(o::setPassword); + opts.setPfxKeyCertOptions(o); + } + + if (eb.trustCertificatePem != null) { + eb.trustCertificatePem.certs.ifPresent(s -> { + PemTrustOptions o = new PemTrustOptions(); + Pattern.compile(",").splitAsStream(s).map(String::trim).forEach(o::addCertPath); + opts.setPemTrustOptions(o); + }); + } + + if (eb.trustCertificateJks != null) { + JksOptions o = new JksOptions(); + eb.trustCertificateJks.path.ifPresent(o::setPath); + eb.trustCertificateJks.password.ifPresent(o::setPassword); + opts.setTrustStoreOptions(o); + } + + if (eb.trustCertificatePfx != null) { + PfxOptions o = new PfxOptions(); + eb.trustCertificatePfx.path.ifPresent(o::setPath); + eb.trustCertificatePfx.password.ifPresent(o::setPassword); + opts.setPfxTrustOptions(o); + } + options.setEventBusOptions(opts); + } + + void registerMessageConsumers(Map messageConsumerConfigurations) { + if (!messageConsumerConfigurations.isEmpty()) { + EventBus eventBus = vertx.eventBus(); + CountDownLatch latch = new CountDownLatch(messageConsumerConfigurations.size()); + for (Entry entry : messageConsumerConfigurations.entrySet()) { + EventConsumerInvoker invoker = createInvoker(entry.getKey()); + String address = entry.getValue().value(); + MessageConsumer consumer; + if (entry.getValue().local()) { + consumer = eventBus.localConsumer(address); + } else { + consumer = eventBus.consumer(address); + } + consumer.handler(m -> invoker.invoke(m)); + consumer.completionHandler(ar -> { + if (ar.succeeded()) { + latch.countDown(); + } + }); + messageConsumers.add(consumer); + } + try { + latch.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException("Unable to register all message consumer methods", e); + } + } + } + + void unregisterMessageConsumers() { + CountDownLatch latch = new CountDownLatch(messageConsumers.size()); + for (MessageConsumer messageConsumer : messageConsumers) { + messageConsumer.unregister(ar -> { + if (ar.succeeded()) { + latch.countDown(); + } + }); + } + try { + latch.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException("Unable to unregister all message consumer methods", e); + } + messageConsumers.clear(); + } + + @SuppressWarnings("unchecked") + private EventConsumerInvoker createInvoker(String invokerClassName) { + try { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl == null) { + cl = VertxProducer.class.getClassLoader(); + } + Class invokerClazz = (Class) cl + .loadClass(invokerClassName); + return invokerClazz.getDeclaredConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException + | InvocationTargetException e) { + throw new IllegalStateException("Unable to create invoker: " + invokerClassName, e); + } + } + } diff --git a/extensions/vertx/runtime/src/test/java/io/quarkus/vertx/runtime/VertxProducerTest.java b/extensions/vertx/runtime/src/test/java/io/quarkus/vertx/runtime/VertxProducerTest.java index d73bbba0ae372..b6d9eb198865d 100644 --- a/extensions/vertx/runtime/src/test/java/io/quarkus/vertx/runtime/VertxProducerTest.java +++ b/extensions/vertx/runtime/src/test/java/io/quarkus/vertx/runtime/VertxProducerTest.java @@ -14,21 +14,24 @@ public class VertxProducerTest { + private VertxTemplate template; private VertxProducer producer; @Before public void setUp() throws Exception { producer = new VertxProducer(); + template = new VertxTemplate(); } @After public void tearDown() throws Exception { - producer.destroy(); + template.destroy(); } @Test public void shouldNotFailWithoutConfig() { - producer.configure(null); + template.initialize(null); + producer.initialize(VertxTemplate.vertx); verifyProducer(); } @@ -52,7 +55,8 @@ public void shouldNotFailWithDefaultConfig() { configuration.workerPoolSize = 10; configuration.warningExceptionTime = Duration.ofSeconds(1); configuration.internalBlockingPoolSize = 5; - producer.configure(configuration); + template.initialize(configuration); + producer.initialize(VertxTemplate.vertx); verifyProducer(); } @@ -71,9 +75,8 @@ public void shouldEnableClustering() { configuration.eventbus.acceptBacklog = OptionalInt.empty(); configuration.cluster = cc; - producer.configure(configuration); try { - producer.vertx(); + template.initialize(configuration); fail("It should not have a cluster manager on the classpath, and so fail the creation"); } catch (IllegalStateException e) { assertTrue(e.getMessage().contains("No ClusterManagerFactory"));