Make sure the RX invoker gets ExecutorService from ExecutorServiceProvider (#4429) Signed-off-by: Jan Supol <jan.supol@oracle.com>
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/JerseyInvocation.java b/core-client/src/main/java/org/glassfish/jersey/client/JerseyInvocation.java index 248fcb9..6c2c1cb 100644 --- a/core-client/src/main/java/org/glassfish/jersey/client/JerseyInvocation.java +++ b/core-client/src/main/java/org/glassfish/jersey/client/JerseyInvocation.java
@@ -451,12 +451,19 @@ @Override public CompletionStageRxInvoker rx() { - return new JerseyCompletionStageRxInvoker(this); + return rx(JerseyCompletionStageRxInvoker.class); } @Override public <T extends RxInvoker> T rx(Class<T> clazz) { if (clazz == JerseyCompletionStageRxInvoker.class) { + final ExecutorService configured = request().getClientConfig().getExecutorService(); + if (configured == null) { + final ExecutorService provided = executorService(); + if (provided != null) { + request().getClientConfig().executorService(provided); + } + } return (T) new JerseyCompletionStageRxInvoker(this); } return createRxInvoker(clazz, executorService());
diff --git a/core-client/src/test/java/org/glassfish/jersey/client/ClientRxTest.java b/core-client/src/test/java/org/glassfish/jersey/client/ClientRxTest.java index 04191b4..c2ab1f2 100644 --- a/core-client/src/test/java/org/glassfish/jersey/client/ClientRxTest.java +++ b/core-client/src/test/java/org/glassfish/jersey/client/ClientRxTest.java
@@ -16,28 +16,35 @@ package org.glassfish.jersey.client; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.ClientRequestFilter; import jakarta.ws.rs.client.Entity; import jakarta.ws.rs.client.Invocation; import jakarta.ws.rs.client.RxInvokerProvider; import jakarta.ws.rs.client.SyncInvoker; import jakarta.ws.rs.client.WebTarget; import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.Provider; import org.glassfish.jersey.internal.guava.ThreadFactoryBuilder; +import org.glassfish.jersey.spi.ExecutorServiceProvider; import org.hamcrest.core.AllOf; import org.hamcrest.core.StringContains; import org.junit.After; -import org.junit.Ignore; +import org.junit.AfterClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; + +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** @@ -55,18 +62,21 @@ public ClientRxTest() { CLIENT = ClientBuilder.newClient(); - - // TODO JAX-RS 2.1 - // CLIENT_WITH_EXECUTOR = ClientBuilder.newBuilder().executorService(EXECUTOR_SERVICE).build(); - CLIENT_WITH_EXECUTOR = null; + CLIENT_WITH_EXECUTOR = ClientBuilder.newBuilder().executorService(EXECUTOR_SERVICE).build(); } @Rule public ExpectedException thrown = ExpectedException.none(); @After - public void afterClass() { + public void afterTest() { CLIENT.close(); + CLIENT_WITH_EXECUTOR.close(); + } + + @AfterClass + public static void afterClass() { + EXECUTOR_SERVICE.shutdownNow(); } @Test @@ -80,20 +90,58 @@ } @Test - @Ignore("TODO JAX-RS 2.1") public void testRxInvokerWithExecutor() { // implicit register (not saying that the contract is RxInvokerProvider). - CLIENT.register(TestRxInvokerProvider.class); - - ExecutorService executorService = Executors - .newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("rxTest-%d").build()); - String s = target(CLIENT_WITH_EXECUTOR).request().rx(TestRxInvoker.class).get(); + String s = target(CLIENT_WITH_EXECUTOR).register(TestRxInvokerProvider.class).request().rx(TestRxInvoker.class).get(); assertTrue("Provided RxInvoker was not used.", s.startsWith("rxTestInvoker")); assertTrue("Executor Service was not passed to RxInvoker", s.contains("rxTest-")); } @Test + public void testDefaultRxInvokerWithExecutor() throws ExecutionException, InterruptedException { + AtomicReference<String> threadName = new AtomicReference<>(); + ClientRequestFilter threadFilter = (f) -> { threadName.set(Thread.currentThread().getName()); }; + ClientRequestFilter abortFilter = (f) -> { f.abortWith(Response.ok().build()); }; + try (Response r = target(CLIENT_WITH_EXECUTOR) + .register(threadFilter, 100) + .register(abortFilter, 200) + .request().rx().get().toCompletableFuture().get()) { + + assertEquals(200, r.getStatus()); + assertTrue("Executor Service was not passed to RxInvoker", threadName.get().contains("rxTest-")); + } + } + + @Test + public void testRxInvokerWithExecutorServiceProvider() { + AtomicReference<String> threadName = new AtomicReference<>(); + String s = target(CLIENT) + .register(TestRxInvokerProvider.class, 200) + .register(TestExecutorServiceProvider.class) + .request().rx(TestRxInvoker.class).get(); + + assertTrue("Provided RxInvoker was not used.", s.startsWith("rxTestInvoker")); + assertTrue("Executor Service was not passed to RxInvoker", s.contains("rxTest-")); + } + + @Test + public void testDefaultRxInvokerWithExecutorServiceProvider() throws ExecutionException, InterruptedException { + AtomicReference<String> threadName = new AtomicReference<>(); + ClientRequestFilter threadFilter = (f) -> { threadName.set(Thread.currentThread().getName()); }; + ClientRequestFilter abortFilter = (f) -> { f.abortWith(Response.ok().build()); }; + try (Response r = target(CLIENT) + .register(threadFilter, 100) + .register(abortFilter, 200) + .register(TestExecutorServiceProvider.class) + .request().rx().get().toCompletableFuture().get()) { + + assertEquals(200, r.getStatus()); + assertTrue("Executor Service was not passed to RxInvoker", threadName.get().contains("rxTest-")); + } + } + + @Test public void testRxInvokerInvalid() { Invocation.Builder request = target(CLIENT).request(); thrown.expect(IllegalArgumentException.class); @@ -146,4 +194,17 @@ return "rxTestInvoker" + (getExecutorService() == null ? "" : " rxTest-"); } } + + private static class TestExecutorServiceProvider implements ExecutorServiceProvider { + + @Override + public ExecutorService getExecutorService() { + return EXECUTOR_SERVICE; + } + + @Override + public void dispose(ExecutorService executorService) { + //@After + } + } }