Skip to content

Commit

Permalink
Merge pull request #20886 from stuartwdouglas/ut-rr-fix
Browse files Browse the repository at this point in the history
Allow Undertow to work with RESTEasy Reactive
  • Loading branch information
geoand authored Oct 21, 2021
2 parents af8b95d + b9b6ab8 commit 292d92b
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ public void run() {
};
}

@Override
public boolean resumeExternalProcessing() {
return false;
}

@Override
public String getRequestHeader(CharSequence name) {
return request.getHeader(name.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,7 @@ public void serverSerializers(ResteasyReactiveRecorder recorder,
@Record(value = ExecutionTime.STATIC_INIT, useIdentityComparisonForParameters = false)
public void setupDeployment(BeanArchiveIndexBuildItem beanArchiveIndexBuildItem,
BeanContainerBuildItem beanContainerBuildItem,
Capabilities capabilities,
ResteasyReactiveConfig config,
Optional<ResourceScanningResultBuildItem> resourceScanningResultBuildItem,
ResteasyReactiveRecorder recorder,
Expand Down Expand Up @@ -742,10 +743,18 @@ public void setupDeployment(BeanArchiveIndexBuildItem beanArchiveIndexBuildItem,
quarkusRestDeploymentInfoBuildItemBuildProducer
.produce(new ResteasyReactiveDeploymentInfoBuildItem(deploymentInfo));

boolean servletPresent = false;
int orderAdd = 1;
if (capabilities.isPresent("io.quarkus.servlet")) {
//if servlet is present we run RR before the default route
//otherwise we run after it
orderAdd = -1;
servletPresent = true;
}
RuntimeValue<Deployment> deployment = recorder.createDeployment(deploymentInfo,
beanContainerBuildItem.getValue(), shutdownContext, vertxConfig,
requestContextFactoryBuildItem.map(RequestContextFactoryBuildItem::getFactory).orElse(null),
initClassFactory, launchModeBuildItem.getLaunchMode());
initClassFactory, launchModeBuildItem.getLaunchMode(), servletPresent);

quarkusRestDeploymentBuildItemBuildProducer
.produce(new ResteasyReactiveDeploymentBuildItem(deployment, deploymentPath));
Expand All @@ -755,7 +764,7 @@ public void setupDeployment(BeanArchiveIndexBuildItem beanArchiveIndexBuildItem,

// Exact match for resources matched to the root path
routes.produce(RouteBuildItem.builder()
.orderedRoute(deploymentPath, VertxHttpRecorder.DEFAULT_ROUTE_ORDER + 1).handler(handler).build());
.orderedRoute(deploymentPath, VertxHttpRecorder.DEFAULT_ROUTE_ORDER + orderAdd).handler(handler).build());
String matchPath = deploymentPath;
if (matchPath.endsWith("/")) {
matchPath += "*";
Expand All @@ -764,7 +773,7 @@ public void setupDeployment(BeanArchiveIndexBuildItem beanArchiveIndexBuildItem,
}
// Match paths that begin with the deployment path
routes.produce(
RouteBuildItem.builder().orderedRoute(matchPath, VertxHttpRecorder.DEFAULT_ROUTE_ORDER + 1)
RouteBuildItem.builder().orderedRoute(matchPath, VertxHttpRecorder.DEFAULT_ROUTE_ORDER + orderAdd)
.handler(handler).build());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ public RuntimeValue<Deployment> createDeployment(DeploymentInfo info,
ShutdownContext shutdownContext, HttpBuildTimeConfig vertxConfig,
RequestContextFactory contextFactory,
BeanFactory<ResteasyReactiveInitialiser> initClassFactory,
LaunchMode launchMode) {
LaunchMode launchMode, boolean servletPresent) {

if (servletPresent) {
info.setResumeOn404(true);
}

CurrentRequestManager
.setCurrentRequestInstance(new QuarkusCurrentRequest(beanContainer.instance(CurrentVertxRequest.class)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class Deployment {
private final List<ServerRestHandler> preMatchHandlers;
private final List<RequestMapper.RequestPath<RestInitialHandler.InitialMatch>> classMappers;
private final List<RuntimeConfigurableServerRestHandler> runtimeConfigurableServerRestHandlers;
private final boolean resumeOn404;

public Deployment(ExceptionMapping exceptionMapping, ContextResolvers contextResolvers,
ServerSerialisers serialisers,
Expand All @@ -49,7 +50,7 @@ public Deployment(ExceptionMapping exceptionMapping, ContextResolvers contextRes
ThreadSetupAction threadSetupAction, RequestContextFactory requestContextFactory,
List<ServerRestHandler> preMatchHandlers,
List<RequestMapper.RequestPath<RestInitialHandler.InitialMatch>> classMappers,
List<RuntimeConfigurableServerRestHandler> runtimeConfigurableServerRestHandlers) {
List<RuntimeConfigurableServerRestHandler> runtimeConfigurableServerRestHandlers, boolean resumeOn404) {
this.exceptionMapping = exceptionMapping;
this.contextResolvers = contextResolvers;
this.serialisers = serialisers;
Expand All @@ -64,6 +65,7 @@ public Deployment(ExceptionMapping exceptionMapping, ContextResolvers contextRes
this.preMatchHandlers = preMatchHandlers;
this.classMappers = classMappers;
this.runtimeConfigurableServerRestHandlers = runtimeConfigurableServerRestHandlers;
this.resumeOn404 = resumeOn404;
}

public Supplier<Application> getApplicationSupplier() {
Expand Down Expand Up @@ -94,6 +96,10 @@ public EntityWriter getDynamicEntityWriter() {
return dynamicEntityWriter;
}

public boolean isResumeOn404() {
return resumeOn404;
}

/**
* Application path prefix. Must start with "/" and not end with a "/". Cannot be null.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class DeploymentInfo {
private String applicationPath;
private List<HandlerChainCustomizer> globalHandlerCustomers = new ArrayList<>();
private boolean developmentMode;
private boolean resumeOn404;

public ResourceInterceptors getInterceptors() {
return interceptors;
Expand Down Expand Up @@ -177,4 +178,13 @@ public DeploymentInfo setDevelopmentMode(boolean developmentMode) {
this.developmentMode = developmentMode;
return this;
}

public boolean isResumeOn404() {
return resumeOn404;
}

public DeploymentInfo setResumeOn404(boolean resumeOn404) {
this.resumeOn404 = resumeOn404;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,8 @@ private String getResourceLocatorPathParam(String name, PreviousResource previou
return getResourceLocatorPathParam(name, previousResource.prev);
}

public abstract boolean resumeExternalProcessing();

static class PreviousResource {

public PreviousResource(RuntimeResource locatorTarget, Object locatorPathParamValues, PreviousResource prev) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ public BeanFactory.BeanInstance<?> apply(Class<?> aClass) {
.getValue();
Map<String, RequestMapper<RuntimeResource>> mappersByMethod = RuntimeMappingDeployment
.buildClassMapper(perClassMappers);
ClassRoutingHandler classRoutingHandler = new ClassRoutingHandler(mappersByMethod, classTemplateNameCount);
ClassRoutingHandler classRoutingHandler = new ClassRoutingHandler(mappersByMethod, classTemplateNameCount,
info.isResumeOn404());

int maxMethodTemplateNameCount = 0;
for (TreeMap<URITemplate, List<RequestMapper.RequestPath<RuntimeResource>>> i : perClassMappers.values()) {
Expand Down Expand Up @@ -206,7 +207,7 @@ public BeanFactory.BeanInstance<?> apply(Class<?> aClass) {
abortHandlingChain.toArray(EMPTY_REST_HANDLER_ARRAY), dynamicEntityWriter,
prefix, paramConverterProviders, configurationImpl, applicationSupplier,
threadSetupAction, requestContextFactory, preMatchHandlers, classMappers,
runtimeConfigurableServerRestHandlers);
runtimeConfigurableServerRestHandlers, info.isResumeOn404());
}

private void addRuntimeConfigurableHandlers(RuntimeResource runtimeResource,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ public class ClassRoutingHandler implements ServerRestHandler {

private final Map<String, RequestMapper<RuntimeResource>> mappers;
private final int parameterOffset;
final boolean resumeOn404;

public ClassRoutingHandler(Map<String, RequestMapper<RuntimeResource>> mappers, int parameterOffset) {
public ClassRoutingHandler(Map<String, RequestMapper<RuntimeResource>> mappers, int parameterOffset, boolean resumeOn404) {
this.mappers = mappers;
this.parameterOffset = parameterOffset;
this.resumeOn404 = resumeOn404;
}

@Override
Expand Down Expand Up @@ -201,9 +203,15 @@ private MediaType toMediaType(String mediaTypeStr) {
}

private void throwNotFound(ResteasyReactiveRequestContext requestContext) {
if (resumeOn404) {
if (requestContext.resumeExternalProcessing()) {
return;
}
}
// the exception mapper needs access to request scoped beans, so make sure we have the context
requestContext.requireCDIRequestScope();
throw new NotFoundException("Unable to find matching target resource method");

}

private String getRemaining(ResteasyReactiveRequestContext requestContext) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ public class RestInitialHandler implements ServerRestHandler {

final ThreadSetupAction requestContext;
final RequestContextFactory requestContextFactory;
final boolean resumeOn404;

public RestInitialHandler(Deployment deployment) {
this.mappers = new RequestMapper<>(deployment.getClassMappers());
this.deployment = deployment;
this.providers = new ProvidersImpl(deployment);
this.preMappingHandlers = deployment.getPreMatchHandlers();
this.resumeOn404 = deployment.isResumeOn404();
if (preMappingHandlers.isEmpty()) {
initialChain = new ServerRestHandler[] { new MatrixParamHandler(), this };
} else {
Expand All @@ -51,10 +53,16 @@ public void beginProcessing(Object extenalHttpContext) {
public void handle(ResteasyReactiveRequestContext requestContext) throws Exception {
RequestMapper.RequestMatch<InitialMatch> target = mappers.map(requestContext.getPathWithoutPrefix());
if (target == null) {
if (resumeOn404) {
if (requestContext.resumeExternalProcessing()) {
return;
}
}
// the NotFoundExceptionMapper needs access to the headers so we need to activate the scope
requestContext.requireCDIRequestScope();
// we want to engage the NotFoundExceptionMapper when nothing is found
requestContext.handleException(new NotFoundException());

return;
}
requestContext.restart(target.value.handlers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ public void run() {
};
}

@Override
public boolean resumeExternalProcessing() {
context.next();
return true;
}

@Override
public String getRequestHeader(CharSequence name) {
return request.headers().get(name);
Expand Down
23 changes: 22 additions & 1 deletion integration-tests/hibernate-reactive-panache/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jsonb</artifactId>
</dependency>
<!--
Makes sure that undertow does not interfere with RESTEasy Reactive
Undertow is blocking so if it interfered it would break everything
but the RR endpoints should run first
-->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-undertow</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core</artifactId>
Expand Down Expand Up @@ -144,7 +153,19 @@
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-undertow-deployment</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<build>
Expand Down

0 comments on commit 292d92b

Please sign in to comment.