Skip to content

Commit

Permalink
Execute ClientResponseFilter as part of the abort chain in JAX-RS Client
Browse files Browse the repository at this point in the history
This doesn't seem to be specified by the spec or properly tested in the TCK
(I actually had to disable a single test that threw a NPE), but it does
seem to be what RESTEasy does

Relates to: quarkusio#16702
  • Loading branch information
geoand committed Apr 22, 2021
1 parent 7299fd0 commit b2ffdaf
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package io.quarkus.jaxrs.client.reactive.deployment.test;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.net.URL;

import javax.enterprise.event.Observes;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.ClientResponseContext;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;

import org.jboss.resteasy.reactive.client.spi.ResteasyReactiveClientRequestContext;
import org.jboss.resteasy.reactive.client.spi.ResteasyReactiveClientResponseFilter;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.test.QuarkusUnitTest;
import io.quarkus.test.common.http.TestHTTPResource;
import io.vertx.core.Handler;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;

public class ClientResponseFilterTestCase {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
.addClasses(Endpoint.class));

@TestHTTPResource
URL url;

private Client client;

@BeforeEach
public void before() {
client = ClientBuilder.newClient().register(TestClientResponseFilter.class);
}

@AfterEach
public void after() {
client.close();
}

@Test
public void test() {
Response response = client.target(url.toExternalForm() + "/hello").request().get();
assertEquals(200, response.getStatus());
}

public static class Endpoint {

public void setup(@Observes Router router) {
router.route("/hello").handler(new Handler<RoutingContext>() {
@Override
public void handle(RoutingContext event) {
event.response().setStatusCode(500).end();
}
});
}
}

@Provider
public static class TestClientResponseFilter implements ResteasyReactiveClientResponseFilter {

@Override
public void filter(ResteasyReactiveClientRequestContext requestContext, ClientResponseContext responseContext) {
responseContext.setStatus(200);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import javax.ws.rs.client.InvocationCallback;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.Response;
import org.jboss.resteasy.reactive.client.spi.ClientRestHandler;
import org.jboss.resteasy.reactive.common.jaxrs.ConfigurationImpl;
import org.jboss.resteasy.reactive.common.util.types.Types;
import org.jboss.resteasy.reactive.spi.ThreadSetupAction;
Expand All @@ -32,12 +31,11 @@ public class AsyncInvokerImpl implements AsyncInvoker, CompletionStageRxInvoker
final Map<String, Object> properties;
final ClientImpl restClient;
final HandlerChain handlerChain;
final ClientRestHandler[] abortHandlerChain;
final ThreadSetupAction requestContext;

public AsyncInvokerImpl(ClientImpl restClient, HttpClient httpClient, URI uri, RequestSpec requestSpec,
ConfigurationImpl configuration,
Map<String, Object> properties, HandlerChain handlerChain, ClientRestHandler[] abortHandlerChain,
Map<String, Object> properties, HandlerChain handlerChain,
ThreadSetupAction requestContext) {
this.restClient = restClient;
this.httpClient = httpClient;
Expand All @@ -46,7 +44,6 @@ public AsyncInvokerImpl(ClientImpl restClient, HttpClient httpClient, URI uri, R
this.configuration = configuration;
this.properties = new HashMap<>(properties);
this.handlerChain = handlerChain;
this.abortHandlerChain = abortHandlerChain;
this.requestContext = requestContext;
}

Expand Down Expand Up @@ -258,8 +255,8 @@ RestClientRequestContext performRequestInternal(String httpMethodName, Entity<?>
boolean registerBodyHandler) {
RestClientRequestContext restClientRequestContext = new RestClientRequestContext(restClient, httpClient, httpMethodName,
uri, requestSpec.configuration, requestSpec.headers,
entity, responseType, registerBodyHandler, properties, handlerChain.toRestHandler(configuration),
abortHandlerChain, requestContext);
entity, responseType, registerBodyHandler, properties, handlerChain.createHandlerChain(configuration),
handlerChain.createAbortHandlerChain(configuration), requestContext);
restClientRequestContext.run();
return restClientRequestContext;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Link;
import javax.ws.rs.core.UriBuilder;
import org.jboss.resteasy.reactive.client.handlers.ClientErrorHandler;
import org.jboss.resteasy.reactive.client.spi.ClientContext;
import org.jboss.resteasy.reactive.client.spi.ClientRestHandler;
import org.jboss.resteasy.reactive.common.jaxrs.ConfigurationImpl;
import org.jboss.resteasy.reactive.common.jaxrs.MultiQueryParamMode;
import org.jboss.resteasy.reactive.common.jaxrs.UriBuilderImpl;
Expand All @@ -76,7 +74,6 @@ public class ClientImpl implements Client {
final SSLContext sslContext;
private boolean isClosed;
final HandlerChain handlerChain;
final ClientRestHandler[] abortHandlerChain;
final Vertx vertx;
private final MultiQueryParamMode multiQueryParamMode;

Expand Down Expand Up @@ -117,7 +114,6 @@ public Vertx get() {
options.setMaxRedirects((Integer) maxRedirects);
}
this.httpClient = this.vertx.createHttpClient(options);
abortHandlerChain = new ClientRestHandler[] { new ClientErrorHandler() };
handlerChain = new HandlerChain(followRedirects);
}

Expand Down Expand Up @@ -162,8 +158,7 @@ public WebTarget target(UriBuilder uriBuilder) {
if (uriBuilder instanceof UriBuilderImpl && multiQueryParamMode != null) {
((UriBuilderImpl) uriBuilder).multiQueryParamMode(multiQueryParamMode);
}
return new WebTargetImpl(this, httpClient, uriBuilder, new ConfigurationImpl(configuration), handlerChain,
abortHandlerChain, null);
return new WebTargetImpl(this, httpClient, uriBuilder, new ConfigurationImpl(configuration), handlerChain, null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.List;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.client.ClientResponseFilter;
import org.jboss.resteasy.reactive.client.handlers.ClientErrorHandler;
import org.jboss.resteasy.reactive.client.handlers.ClientRequestFilterRestHandler;
import org.jboss.resteasy.reactive.client.handlers.ClientResponseCompleteRestHandler;
import org.jboss.resteasy.reactive.client.handlers.ClientResponseFilterRestHandler;
Expand All @@ -19,14 +20,16 @@ class HandlerChain {
private final ClientRestHandler clientSendHandler;
private final ClientRestHandler clientSetResponseEntityRestHandler;
private final ClientRestHandler clientResponseCompleteRestHandler;
private final ClientRestHandler clientErrorHandler;

public HandlerChain(boolean followRedirects) {
this.clientSendHandler = new ClientSendRequestHandler(followRedirects);
this.clientSetResponseEntityRestHandler = new ClientSetResponseEntityRestHandler();
this.clientResponseCompleteRestHandler = new ClientResponseCompleteRestHandler();
this.clientErrorHandler = new ClientErrorHandler();
}

ClientRestHandler[] toRestHandler(ConfigurationImpl configuration) {
ClientRestHandler[] createHandlerChain(ConfigurationImpl configuration) {
List<ClientRequestFilter> requestFilters = configuration.getRequestFilters();
List<ClientResponseFilter> responseFilters = configuration.getResponseFilters();
if (requestFilters.isEmpty() && responseFilters.isEmpty()) {
Expand All @@ -45,4 +48,17 @@ ClientRestHandler[] toRestHandler(ConfigurationImpl configuration) {
result.add(clientResponseCompleteRestHandler);
return result.toArray(EMPTY_REST_HANDLERS);
}

ClientRestHandler[] createAbortHandlerChain(ConfigurationImpl configuration) {
List<ClientResponseFilter> responseFilters = configuration.getResponseFilters();
if (responseFilters.isEmpty()) {
return new ClientRestHandler[] { clientErrorHandler };
}
List<ClientRestHandler> result = new ArrayList<>(1 + responseFilters.size());
for (int i = 0; i < responseFilters.size(); i++) {
result.add(new ClientResponseFilterRestHandler(responseFilters.get(i)));
}
result.add(clientErrorHandler);
return result.toArray(EMPTY_REST_HANDLERS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import org.jboss.resteasy.reactive.client.spi.ClientRestHandler;
import org.jboss.resteasy.reactive.common.jaxrs.ConfigurationImpl;
import org.jboss.resteasy.reactive.spi.ThreadSetupAction;

Expand All @@ -41,22 +40,19 @@ public class InvocationBuilderImpl implements Invocation.Builder {
final ConfigurationImpl configuration;
final ClientImpl restClient;
final HandlerChain handlerChain;
final ClientRestHandler[] abortHandlerChain;
final ThreadSetupAction requestContext;
final long readTimeoutMs;

public InvocationBuilderImpl(URI uri, ClientImpl restClient, HttpClient httpClient,
WebTargetImpl target,
ConfigurationImpl configuration, HandlerChain handlerChain,
ClientRestHandler[] abortHandlerChain, ThreadSetupAction requestContext) {
ConfigurationImpl configuration, HandlerChain handlerChain, ThreadSetupAction requestContext) {
this.uri = uri;
this.restClient = restClient;
this.httpClient = httpClient;
this.target = target;
this.requestSpec = new RequestSpec(configuration);
this.configuration = configuration;
this.handlerChain = handlerChain;
this.abortHandlerChain = abortHandlerChain;
this.requestContext = requestContext;
Object readTimeoutMs = configuration.getProperty(READ_TIMEOUT);
if (readTimeoutMs == null) {
Expand Down Expand Up @@ -99,7 +95,7 @@ public Invocation buildPut(Entity<?> entity) {
@Override
public AsyncInvokerImpl async() {
return new AsyncInvokerImpl(restClient, httpClient, uri, requestSpec, configuration,
properties, handlerChain, abortHandlerChain, requestContext);
properties, handlerChain, requestContext);
}

@Override
Expand Down Expand Up @@ -171,7 +167,7 @@ public Invocation.Builder property(String name, Object value) {
@Override
public CompletionStageRxInvoker rx() {
return new AsyncInvokerImpl(restClient, httpClient, uri, requestSpec, configuration,
properties, handlerChain, abortHandlerChain, requestContext);
properties, handlerChain, requestContext);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriBuilder;
import org.jboss.resteasy.reactive.client.spi.ClientRestHandler;
import org.jboss.resteasy.reactive.common.core.Serialisers;
import org.jboss.resteasy.reactive.common.jaxrs.ConfigurationImpl;
import org.jboss.resteasy.reactive.common.jaxrs.UriBuilderImpl;
Expand All @@ -24,20 +23,17 @@ public class WebTargetImpl implements WebTarget {
private boolean chunked = false;
private final ClientImpl restClient;
final HandlerChain handlerChain;
final ClientRestHandler[] abortHandlerChain;
final ThreadSetupAction requestContext;

public WebTargetImpl(ClientImpl restClient, HttpClient client, UriBuilder uriBuilder,
ConfigurationImpl configuration,
HandlerChain handlerChain,
ClientRestHandler[] abortHandlerChain,
ThreadSetupAction requestContext) {
this.restClient = restClient;
this.client = client;
this.uriBuilder = uriBuilder;
this.configuration = configuration;
this.handlerChain = handlerChain;
this.abortHandlerChain = abortHandlerChain;
this.requestContext = requestContext;
}

Expand Down Expand Up @@ -264,7 +260,7 @@ public WebTargetImpl queryParamNoTemplate(String name, Object... values) throws

protected WebTargetImpl newInstance(HttpClient client, UriBuilder uriBuilder,
ConfigurationImpl configuration) {
return new WebTargetImpl(restClient, client, uriBuilder, configuration, handlerChain, abortHandlerChain,
return new WebTargetImpl(restClient, client, uriBuilder, configuration, handlerChain,
requestContext);
}

Expand Down Expand Up @@ -300,8 +296,7 @@ private void abortIfClosed() {

protected InvocationBuilderImpl createQuarkusRestInvocationBuilder(HttpClient client, UriBuilder uri,
ConfigurationImpl configuration) {
return new InvocationBuilderImpl(uri.build(), restClient, client, this, configuration, handlerChain,
abortHandlerChain, requestContext);
return new InvocationBuilderImpl(uri.build(), restClient, client, this, configuration, handlerChain, requestContext);
}

@Override
Expand Down
2 changes: 1 addition & 1 deletion tcks/resteasy-reactive/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<properties>

<!-- to avoid sudden surprises, checkout is pinned to a specific commit -->
<resteasy-reactive-testsuite.repo.ref>531734d28f1fcb39d369c1d2fae0a0f90a4ab9dc</resteasy-reactive-testsuite.repo.ref>
<resteasy-reactive-testsuite.repo.ref>6bc5d1bacccaf45a7db968b57a262b8e84e4621b</resteasy-reactive-testsuite.repo.ref>

<exec.skip>${skipTests}</exec.skip>
<resteasy-reactive-testsuite.clone.skip>${exec.skip}</resteasy-reactive-testsuite.clone.skip>
Expand Down

0 comments on commit b2ffdaf

Please sign in to comment.