Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose Mutiny variant of the Router #20192

Merged
merged 2 commits into from
Sep 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/src/main/asciidoc/reactive-routes.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,15 @@ Check the https://vertx.io/docs/vertx-web/java/#_basic_vert_x_web_concepts[Vert.
If you use `quarkus-resteasy` or `quarkus-reactive-routes`, the extension will be added automatically.
====

You can also receive the Mutiny variant of the Router (`io.vertx.mutiny.ext.web.Router`):

[source,java]
----
public void init(@Observes io.vertx.mutiny.ext.web.Router router) {
router.get("/my-route").handler(rc -> rc.response().endAndForget("Hello from my route"));
}
----

== Intercepting HTTP requests

You can also register filters that would intercept incoming HTTP requests.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import java.util.function.Function;

import io.quarkus.runtime.annotations.Recorder;
import io.quarkus.vertx.http.runtime.RouterProducer;
import io.vertx.core.Handler;
import io.vertx.core.http.HttpMethod;
import io.vertx.ext.web.Router;
Expand All @@ -18,7 +17,7 @@ public Handler<RoutingContext> createHandler(String handlerClassName) {
try {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
if (cl == null) {
cl = RouterProducer.class.getClassLoader();
cl = VertxWebRecorder.class.getClassLoader();
}
Class<? extends Handler<RoutingContext>> handlerClazz = (Class<? extends Handler<RoutingContext>>) cl
.loadClass(handlerClassName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import java.util.Optional;

import io.quarkus.arc.deployment.BeanContainerBuildItem;
import io.quarkus.builder.item.SimpleBuildItem;
import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.Capability;
Expand Down Expand Up @@ -72,7 +71,6 @@ public void boot(ShutdownContextBuildItem shutdown,
BuildProducer<DefaultRouteBuildItem> defaultRoutes,
BuildProducer<RouteBuildItem> routes,
CoreVertxBuildItem vertx,
BeanContainerBuildItem beanContainer,
ResteasyStandaloneBuildItem standalone,
Optional<RequireVirtualHttpBuildItem> requireVirtual,
ExecutorBuildItem executorBuildItem,
Expand All @@ -86,7 +84,7 @@ public void boot(ShutdownContextBuildItem shutdown,

// Handler used for both the default and non-default deployment path (specified as application path or resteasyConfig.path)
// Routes use the order VertxHttpRecorder.DEFAULT_ROUTE_ORDER + 1 to ensure the default route is called before the resteasy one
Handler<RoutingContext> handler = recorder.vertxRequestHandler(vertx.getVertx(), beanContainer.getValue(),
Handler<RoutingContext> handler = recorder.vertxRequestHandler(vertx.getVertx(),
executorBuildItem.getExecutorProxy(), httpConfiguration, resteasyVertxConfig);
// Exact match for resources matched to the root path
routes.produce(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.quarkus.arc.runtime.BeanContainer;
import io.quarkus.resteasy.runtime.ResteasyVertxConfig;
import io.quarkus.runtime.ShutdownContext;
import io.quarkus.runtime.annotations.Recorder;
Expand Down Expand Up @@ -52,10 +51,10 @@ public void run() {
useDirect = !isVirtual;
}

public Handler<RoutingContext> vertxRequestHandler(Supplier<Vertx> vertx,
BeanContainer beanContainer, Executor executor, HttpConfiguration readTimeout, ResteasyVertxConfig config) {
public Handler<RoutingContext> vertxRequestHandler(Supplier<Vertx> vertx, Executor executor, HttpConfiguration readTimeout,
ResteasyVertxConfig config) {
if (deployment != null) {
return new VertxRequestHandler(vertx.get(), beanContainer, deployment, contextPath,
return new VertxRequestHandler(vertx.get(), deployment, contextPath,
new ResteasyVertxAllocator(config.responseBufferSize), executor,
readTimeout.readTimeout.toMillis());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
import org.jboss.resteasy.spi.Failure;
import org.jboss.resteasy.spi.ResteasyDeployment;

import io.quarkus.arc.Arc;
import io.quarkus.arc.ManagedContext;
import io.quarkus.arc.runtime.BeanContainer;
import io.quarkus.resteasy.runtime.ContextUtil;
import io.quarkus.runtime.BlockingOperationControl;
import io.quarkus.security.identity.CurrentIdentityAssociation;
Expand All @@ -45,19 +45,16 @@ public class VertxRequestHandler implements Handler<RoutingContext> {
protected final RequestDispatcher dispatcher;
protected final String rootPath;
protected final BufferAllocator allocator;
protected final BeanContainer beanContainer;
protected final CurrentIdentityAssociation association;
protected final CurrentVertxRequest currentVertxRequest;
protected final Executor executor;
protected final long readTimeout;

public VertxRequestHandler(Vertx vertx,
BeanContainer beanContainer,
ResteasyDeployment deployment,
String rootPath,
BufferAllocator allocator, Executor executor, long readTimeout) {
this.vertx = vertx;
this.beanContainer = beanContainer;
this.dispatcher = new RequestDispatcher((SynchronousDispatcher) deployment.getDispatcher(),
deployment.getProviderFactory(), null, Thread.currentThread().getContextClassLoader());
this.rootPath = rootPath;
Expand Down Expand Up @@ -101,7 +98,7 @@ public void run() {
}

private void dispatch(RoutingContext routingContext, InputStream is, VertxOutput output) {
ManagedContext requestContext = beanContainer.requestContext();
ManagedContext requestContext = Arc.container().requestContext();
requestContext.activate();
routingContext.remove(QuarkusHttpUser.AUTH_FAILURE_HANDLER);
if (association != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.quarkus.vertx.http.deployment;

import io.quarkus.builder.item.SimpleBuildItem;
import io.quarkus.runtime.RuntimeValue;
import io.vertx.ext.web.Router;

final class InitialRouterBuildItem extends SimpleBuildItem {

private final RuntimeValue<Router> httpRouter;
private final RuntimeValue<io.vertx.mutiny.ext.web.Router> mutinyRouter;

public InitialRouterBuildItem(RuntimeValue<Router> httpRouter, RuntimeValue<io.vertx.mutiny.ext.web.Router> mutinyRouter) {
this.httpRouter = httpRouter;
this.mutinyRouter = mutinyRouter;
}

public RuntimeValue<Router> getHttpRouter() {
return httpRouter;
}

public RuntimeValue<io.vertx.mutiny.ext.web.Router> getMutinyRouter() {
return mutinyRouter;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.BeanContainerBuildItem;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.arc.processor.BuiltinScope;
import io.quarkus.bootstrap.util.ZipUtils;
import io.quarkus.builder.BuildException;
import io.quarkus.deployment.annotations.BuildProducer;
Expand Down Expand Up @@ -53,7 +55,6 @@
import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig;
import io.quarkus.vertx.http.runtime.HttpConfiguration;
import io.quarkus.vertx.http.runtime.HttpHostConfigSource;
import io.quarkus.vertx.http.runtime.RouterProducer;
import io.quarkus.vertx.http.runtime.VertxHttpRecorder;
import io.quarkus.vertx.http.runtime.attribute.ExchangeAttributeBuilder;
import io.quarkus.vertx.http.runtime.cors.CORSRecorder;
Expand Down Expand Up @@ -96,7 +97,6 @@ FilterBuildItem cors(CORSRecorder recorder, HttpConfiguration configuration) {
AdditionalBeanBuildItem additionalBeans() {
return AdditionalBeanBuildItem.builder()
.setUnremovable()
.addBeanClass(RouterProducer.class)
.addBeanClass(CurrentVertxRequest.class)
.addBeanClass(CurrentRequestProducer.class)
.build();
Expand Down Expand Up @@ -132,16 +132,38 @@ void notFoundRoutes(
}
}

@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void preinitializeRouter(CoreVertxBuildItem vertx, VertxHttpRecorder recorder,
BuildProducer<InitialRouterBuildItem> initialRouter, BuildProducer<SyntheticBeanBuildItem> syntheticBeans) {
// We need to initialize the routers that are exposed as synthetic beans in a separate build step to avoid cycles in the build chain
RuntimeValue<Router> httpRouteRouter = recorder.initializeRouter(vertx.getVertx());
RuntimeValue<io.vertx.mutiny.ext.web.Router> mutinyRouter = recorder.createMutinyRouter(httpRouteRouter);
initialRouter.produce(new InitialRouterBuildItem(httpRouteRouter, mutinyRouter));

// Also note that we need a client proxy to handle the use case where a bean also @Observes Router
syntheticBeans.produce(SyntheticBeanBuildItem.configure(Router.class)
.scope(BuiltinScope.APPLICATION.getInfo())
.setRuntimeInit()
.runtimeValue(httpRouteRouter).done());
syntheticBeans.produce(SyntheticBeanBuildItem.configure(io.vertx.mutiny.ext.web.Router.class)
.scope(BuiltinScope.APPLICATION.getInfo())
.setRuntimeInit()
.runtimeValue(mutinyRouter).done());
}

@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
VertxWebRouterBuildItem initializeRouter(VertxHttpRecorder recorder,
InitialRouterBuildItem initialRouter,
CoreVertxBuildItem vertx,
List<RouteBuildItem> routes,
HttpBuildTimeConfig httpBuildTimeConfig,
NonApplicationRootPathBuildItem nonApplicationRootPath,
ShutdownContextBuildItem shutdown) {

RuntimeValue<Router> httpRouteRouter = recorder.initializeRouter(vertx.getVertx());
RuntimeValue<Router> httpRouteRouter = initialRouter.getHttpRouter();
RuntimeValue<io.vertx.mutiny.ext.web.Router> mutinyRouter = initialRouter.getMutinyRouter();
RuntimeValue<Router> frameworkRouter = null;
RuntimeValue<Router> mainRouter = null;

Expand Down Expand Up @@ -182,7 +204,7 @@ VertxWebRouterBuildItem initializeRouter(VertxHttpRecorder recorder,
}
}

return new VertxWebRouterBuildItem(httpRouteRouter, mainRouter, frameworkRouter);
return new VertxWebRouterBuildItem(httpRouteRouter, mainRouter, frameworkRouter, mutinyRouter);
}

@BuildStep
Expand Down Expand Up @@ -258,6 +280,7 @@ ServiceStartBuildItem finalizeRouter(
recorder.finalizeRouter(beanContainer.getValue(),
defaultRoute.map(DefaultRouteBuildItem::getRoute).orElse(null),
listOfFilters, vertx.getVertx(), lrc, mainRouter, httpRouteRouter.getHttpRouter(),
httpRouteRouter.getMutinyRouter(),
httpRootPathBuildItem.getRootPath(),
launchMode.getLaunchMode(),
!requireBodyHandlerBuildItems.isEmpty(), bodyHandler, httpConfiguration, gracefulShutdownFilter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,27 @@

public final class VertxWebRouterBuildItem extends SimpleBuildItem {

private RuntimeValue<Router> httpRouter;
private RuntimeValue<Router> mainRouter;
private RuntimeValue<Router> frameworkRouter;
private final RuntimeValue<Router> httpRouter;
private final RuntimeValue<Router> mainRouter;
private final RuntimeValue<Router> frameworkRouter;
private final RuntimeValue<io.vertx.mutiny.ext.web.Router> mutinyRouter;

VertxWebRouterBuildItem(RuntimeValue<Router> httpRouter, RuntimeValue<Router> mainRouter,
RuntimeValue<Router> frameworkRouter) {
RuntimeValue<Router> frameworkRouter, RuntimeValue<io.vertx.mutiny.ext.web.Router> mutinyRouter) {
this.httpRouter = httpRouter;
this.mainRouter = mainRouter;
this.frameworkRouter = frameworkRouter;
this.mutinyRouter = mutinyRouter;
}

public RuntimeValue<Router> getHttpRouter() {
return httpRouter;
}

public RuntimeValue<io.vertx.mutiny.ext.web.Router> getMutinyRouter() {
return mutinyRouter;
}

/**
* Will be {@code null} if `${quarkus.http.root-path}` is {@literal /}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,21 @@ public class UserRouteRegistrationTest {
@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClasses(BeanRegisteringRouteUsingObserves.class, BeanRegisteringRouteUsingInject.class));
.addClasses(BeanRegisteringRouteUsingObserves.class,
BeanRegisteringRouteUsingObservesWithMutinyRouter.class,
BeanRegisteringRouteUsingInject.class,
BeanRegisteringRouteUsingInjectWithMutinyRouter.class));

@Test
public void test() {
assertThat(RestAssured.get("/observes").asString()).isEqualTo("observers - ok");
assertThat(RestAssured.get("/observes-mutiny").asString()).isEqualTo("observers mutiny - ok");
assertThat(RestAssured.get("/inject").asString()).isEqualTo("inject - ok");
assertThat(RestAssured.get("/inject-mutiny").asString()).isEqualTo("inject mutiny - ok");
assertThat(given().body("test").contentType("text/plain").post("/body").asString()).isEqualTo("test");
assertThat(given().body("test mutiny").contentType("text/plain").post("/body-mutiny").asString())
.isEqualTo("test mutiny");

}

@ApplicationScoped
Expand All @@ -41,6 +49,15 @@ public void register(@Observes Router router) {

}

@ApplicationScoped
static class BeanRegisteringRouteUsingObservesWithMutinyRouter {

public void register(@Observes io.vertx.mutiny.ext.web.Router router) {
router.route("/observes-mutiny").handler(rc -> rc.response().endAndForget("observers mutiny - ok"));
}

}

@ApplicationScoped
static class BeanRegisteringRouteUsingInject {

Expand All @@ -55,4 +72,18 @@ public void register(@Observes StartupEvent ignored) {
}

}

@ApplicationScoped
static class BeanRegisteringRouteUsingInjectWithMutinyRouter {

@Inject
io.vertx.mutiny.ext.web.Router router;

public void register(@Observes StartupEvent ignored) {
router.route("/inject-mutiny").handler(rc -> rc.response().endAndForget("inject mutiny - ok"));
router.route("/body-mutiny").consumes("text/plain").handler(io.vertx.mutiny.ext.web.handler.BodyHandler.create())
.handler(rc -> rc.response().endAndForget(rc.getBodyAsString()));
}

}
}
4 changes: 4 additions & 0 deletions extensions/vertx-http/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-vertx</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>smallrye-mutiny-vertx-web</artifactId>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,10 @@ public RuntimeValue<Router> initializeRouter(final Supplier<Vertx> vertxRuntimeV
return new RuntimeValue<>(router);
}

public RuntimeValue<io.vertx.mutiny.ext.web.Router> createMutinyRouter(final RuntimeValue<Router> router) {
return new RuntimeValue<>(new io.vertx.mutiny.ext.web.Router(router.getValue()));
}

public void startServer(Supplier<Vertx> vertx, ShutdownContext shutdown,
HttpBuildTimeConfig httpBuildTimeConfig, HttpConfiguration httpConfiguration,
LaunchMode launchMode,
Expand Down Expand Up @@ -271,7 +275,8 @@ public void mountFrameworkRouter(RuntimeValue<Router> mainRouter, RuntimeValue<R
public void finalizeRouter(BeanContainer container, Consumer<Route> defaultRouteHandler,
List<Filter> filterList, Supplier<Vertx> vertx,
LiveReloadConfig liveReloadConfig, Optional<RuntimeValue<Router>> mainRouterRuntimeValue,
RuntimeValue<Router> httpRouterRuntimeValue, String rootPath, LaunchMode launchMode, boolean requireBodyHandler,
RuntimeValue<Router> httpRouterRuntimeValue, RuntimeValue<io.vertx.mutiny.ext.web.Router> mutinyRouter,
String rootPath, LaunchMode launchMode, boolean requireBodyHandler,
Handler<RoutingContext> bodyHandler, HttpConfiguration httpConfiguration,
GracefulShutdownFilter gracefulShutdownFilter, ShutdownConfig shutdownConfig,
Executor executor) {
Expand All @@ -289,6 +294,8 @@ public void finalizeRouter(BeanContainer container, Consumer<Route> defaultRoute

// Then, fire the resuming router
event.select(Router.class).fire(httpRouteRouter);
// Also fires the Mutiny one
event.select(io.vertx.mutiny.ext.web.Router.class).fire(mutinyRouter.getValue());

for (Filter filter : filterList) {
if (filter.getHandler() != null) {
Expand All @@ -301,7 +308,6 @@ public void finalizeRouter(BeanContainer container, Consumer<Route> defaultRoute
defaultRouteHandler.accept(httpRouteRouter.route().order(DEFAULT_ROUTE_ORDER));
}

container.instance(RouterProducer.class).initialize(httpRouteRouter);
httpRouteRouter.route().last().failureHandler(new QuarkusErrorHandler(launchMode.isDevOrTest()));

if (requireBodyHandler) {
Expand Down