Skip to content

Commit

Permalink
Merge pull request #20529 from geoand/#19013
Browse files Browse the repository at this point in the history
Allow suspend functions as to be uses as custom filters
  • Loading branch information
geoand authored Oct 5, 2021
2 parents c873a41 + 5e237c2 commit cc5d211
Show file tree
Hide file tree
Showing 11 changed files with 356 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.quarkus.resteasy.reactive.common.deployment;

import static io.quarkus.resteasy.reactive.common.deployment.QuarkusResteasyReactiveDotNames.CONTINUATION;

import java.util.List;

import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.Type;

public class KotlinUtils {

private KotlinUtils() {
}

public static boolean isSuspendMethod(MethodInfo methodInfo) {
List<Type> parameters = methodInfo.parameters();
if (parameters.isEmpty()) {
return false;
}

return CONTINUATION.equals(parameters.get(parameters.size() - 1).name());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ public class QuarkusResteasyReactiveDotNames {
public static final DotName HTTP_SERVER_RESPONSE = DotName.createSimple(HttpServerResponse.class.getName());
public static final DotName JSON_IGNORE = DotName.createSimple("com.fasterxml.jackson.annotation.JsonIgnore");
public static final DotName JSONB_TRANSIENT = DotName.createSimple("javax.json.bind.annotation.JsonbTransient");

public static final DotName CONTINUATION = DotName.createSimple("kotlin.coroutines.Continuation");
public static final DotName KOTLIN_UNIT = DotName.createSimple("kotlin.Unit");

public static final IgnoreTypeForReflectionPredicate IGNORE_TYPE_FOR_REFLECTION_PREDICATE = new IgnoreTypeForReflectionPredicate();
public static final IgnoreFieldForReflectionPredicate IGNORE_FIELD_FOR_REFLECTION_PREDICATE = new IgnoreFieldForReflectionPredicate();
public static final IgnoreMethodForReflectionPredicate IGNORE_METHOD_FOR_REFLECTION_PREDICATE = new IgnoreMethodForReflectionPredicate();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.jboss.resteasy.reactive.server.runtime.kotlin

import io.smallrye.mutiny.Uni
import io.smallrye.mutiny.coroutines.asUni
import kotlinx.coroutines.async
import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext
import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveContainerRequestContext
import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveContainerRequestFilter

/**
* Base class used by Quarkus to generate an implementation at build-time that calls
* a {@code suspend} method annotated with {@code @ServerRequestFilter}
*/
@Suppress("unused")
abstract class AbstractSuspendedRequestFilter : ResteasyReactiveContainerRequestFilter {

abstract suspend fun doFilter(containerRequestContext: ResteasyReactiveContainerRequestContext): Any

abstract fun handleResult(containerRequestContext: ResteasyReactiveContainerRequestContext, uniResult: Uni<*>)


private val originalTCCL: ClassLoader = Thread.currentThread().contextClassLoader

override fun filter(containerRequestContext: ResteasyReactiveContainerRequestContext) {
val (dispatcher,coroutineScope) = prepareExecution(containerRequestContext.serverRequestContext as ResteasyReactiveRequestContext)

val uni = coroutineScope.async(context = dispatcher) {
// ensure the proper CL is not lost in dev-mode
Thread.currentThread().contextClassLoader = originalTCCL

// the implementation gets the proper values from the context and invokes the user supplied method
doFilter(containerRequestContext)
}.asUni()

// the implementation should call the appropriate FilterUtil method
handleResult(containerRequestContext, uni)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.jboss.resteasy.reactive.server.runtime.kotlin

import kotlinx.coroutines.launch
import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext
import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveContainerRequestContext
import org.jboss.resteasy.reactive.server.spi.ResteasyReactiveContainerResponseFilter
import javax.ws.rs.container.ContainerResponseContext

/**
* Base class used by Quarkus to generate an implementation at build-time that calls
* a {@code suspend} method annotated with {@code @ServerResponseFilter}
*/
@Suppress("unused")
abstract class AbstractSuspendedResponseFilter : ResteasyReactiveContainerResponseFilter {

abstract suspend fun doFilter(requestContext: ResteasyReactiveContainerRequestContext, responseContext: ContainerResponseContext): Any

private val originalTCCL: ClassLoader = Thread.currentThread().contextClassLoader

override fun filter(requestContext: ResteasyReactiveContainerRequestContext, responseContext: ContainerResponseContext) {
val (dispatcher,coroutineScope) = prepareExecution(requestContext.serverRequestContext as ResteasyReactiveRequestContext)


requestContext.suspend()
coroutineScope.launch(context = dispatcher) {
// ensure the proper CL is not lost in dev-mode
Thread.currentThread().contextClassLoader = originalTCCL
try {
doFilter(requestContext, responseContext)
} catch (t: Throwable) {
(requestContext.serverRequestContext as ResteasyReactiveRequestContext).handleException(t, true)
}
requestContext.resume()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.jboss.resteasy.reactive.server.runtime.kotlin

import io.vertx.core.Vertx
import kotlinx.coroutines.CoroutineDispatcher
import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext
import javax.enterprise.inject.spi.CDI

fun prepareExecution(requestContext: ResteasyReactiveRequestContext): Pair<CoroutineDispatcher, ApplicationCoroutineScope> {
val requestScope = requestContext.captureCDIRequestScope()
val dispatcher: CoroutineDispatcher = Vertx.currentContext()?.let {VertxDispatcher(it,requestScope)}
?: throw IllegalStateException("No Vertx context found")

val coroutineScope = CDI.current().select(ApplicationCoroutineScope::class.java)
requestContext.suspend()

return Pair(dispatcher, coroutineScope.get())
}
Loading

0 comments on commit cc5d211

Please sign in to comment.