Skip to content

Commit 021b979

Browse files
authored
Updated CommandInterceptor with special code to handle async calls coming from the RestClient implementation in Jersey due to an issue with the default invocation context in Weld. See issue 6580. New integration test that is currently disabled until the next integration with Jersey. (helidon-io#6665)
1 parent 872890d commit 021b979

5 files changed

Lines changed: 78 additions & 14 deletions

File tree

microprofile/fault-tolerance/src/main/java/io/helidon/microprofile/faulttolerance/CommandInterceptor.java

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2020 Oracle and/or its affiliates.
2+
* Copyright (c) 2018, 2023 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,14 +24,20 @@
2424
import jakarta.interceptor.InvocationContext;
2525

2626
/**
27-
* Intercepts calls to FT methods and implements annotation semantics.
27+
* <p>Intercepts calls to FT methods and implements annotation semantics.</p>
28+
*
29+
* <p>There is special code to handle async calls coming from the RestClient
30+
* implementation in Jersey due to an issue with the default invocation context
31+
* in Weld. See issue https://github.com/helidon-io/helidon/issues/6580.</p>
2832
*/
2933
@Interceptor
3034
@CommandBinding
3135
@Priority(Interceptor.Priority.PLATFORM_AFTER + 10)
3236
class CommandInterceptor {
3337

3438
private static final Logger LOGGER = Logger.getLogger(CommandInterceptor.class.getName());
39+
private static final String INVOCATION_CONTEXT_KEY =
40+
"org.glassfish.jersey.microprofile.restclient.InterceptorInvocationContext";
3541

3642
/**
3743
* Intercepts a call to bean method annotated by any of the fault tolerance
@@ -44,16 +50,25 @@ class CommandInterceptor {
4450
@AroundInvoke
4551
public Object interceptCommand(InvocationContext context) throws Throwable {
4652
try {
47-
LOGGER.fine("Interceptor called for '" + context.getTarget().getClass()
53+
LOGGER.fine(() -> "Interceptor called for '" + context.getTarget().getClass()
4854
+ "::" + context.getMethod().getName() + "'");
4955

5056
// Create method introspector and executer retrier
5157
MethodIntrospector introspector = new MethodIntrospector(context.getTarget().getClass(),
5258
context.getMethod());
53-
MethodInvoker runner = new MethodInvoker(context, introspector);
54-
return runner.get();
59+
60+
// If async call triggered by RestClient, use its invocation context instead
61+
if (introspector.isAsynchronous() && context.getContextData().containsKey(INVOCATION_CONTEXT_KEY)) {
62+
InvocationContext override = (InvocationContext) context.getContextData().get(INVOCATION_CONTEXT_KEY);
63+
LOGGER.fine(() -> "Overriding invocation context from map " + override);
64+
MethodInvoker runner = new MethodInvoker(override, introspector);
65+
return runner.get();
66+
} else {
67+
MethodInvoker runner = new MethodInvoker(context, introspector);
68+
return runner.get();
69+
}
5570
} catch (Throwable t) {
56-
LOGGER.fine("Throwable caught by interceptor '" + t.getMessage() + "'");
71+
LOGGER.fine(() -> "Throwable caught by interceptor '" + t.getMessage() + "'");
5772
throw t;
5873
}
5974
}

tests/integration/restclient/src/main/java/io/helidon/tests/integration/restclient/GreetResource.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 Oracle and/or its affiliates.
2+
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,14 +16,15 @@
1616

1717
package io.helidon.tests.integration.restclient;
1818

19+
import java.util.Collections;
20+
1921
import jakarta.json.Json;
2022
import jakarta.json.JsonBuilderFactory;
2123
import jakarta.json.JsonObject;
2224
import jakarta.ws.rs.GET;
2325
import jakarta.ws.rs.Path;
2426
import jakarta.ws.rs.Produces;
2527
import jakarta.ws.rs.core.MediaType;
26-
import java.util.Collections;
2728

2829
/**
2930
* A typical greet resource that only handles a single GET for a default message.
@@ -39,6 +40,13 @@ public JsonObject getDefaultMessage() {
3940
return createResponse("World");
4041
}
4142

43+
@GET
44+
@Path("async")
45+
@Produces(MediaType.APPLICATION_JSON)
46+
public JsonObject getDefaultMessageAsync() {
47+
return createResponse("World");
48+
}
49+
4250
private JsonObject createResponse(String who) {
4351
String msg = String.format("%s %s!", "Hello", who);
4452

tests/integration/restclient/src/main/java/io/helidon/tests/integration/restclient/GreetResourceClient.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 Oracle and/or its affiliates.
2+
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,12 +16,14 @@
1616

1717
package io.helidon.tests.integration.restclient;
1818

19+
import java.util.concurrent.CompletionStage;
20+
1921
import jakarta.json.JsonObject;
2022
import jakarta.ws.rs.GET;
2123
import jakarta.ws.rs.Path;
2224
import jakarta.ws.rs.Produces;
2325
import jakarta.ws.rs.core.MediaType;
24-
26+
import org.eclipse.microprofile.faulttolerance.Asynchronous;
2527
import org.eclipse.microprofile.faulttolerance.Retry;
2628
import org.eclipse.microprofile.faulttolerance.Timeout;
2729
import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
@@ -40,4 +42,10 @@ public interface GreetResourceClient {
4042
@Timeout(value = 3000)
4143
@Produces(MediaType.APPLICATION_JSON)
4244
JsonObject getDefaultMessage();
45+
46+
@GET
47+
@Path("async")
48+
@Asynchronous
49+
@Produces(MediaType.APPLICATION_JSON)
50+
CompletionStage<JsonObject> getDefaultMessageAsync();
4351
}

tests/integration/restclient/src/main/java/io/helidon/tests/integration/restclient/GreetResourceProxy.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 Oracle and/or its affiliates.
2+
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,10 @@
1616

1717
package io.helidon.tests.integration.restclient;
1818

19+
import java.util.concurrent.ExecutionException;
20+
import java.util.concurrent.TimeUnit;
21+
import java.util.concurrent.TimeoutException;
22+
1923
import jakarta.annotation.PostConstruct;
2024
import jakarta.inject.Inject;
2125
import jakarta.json.JsonObject;
@@ -25,7 +29,6 @@
2529
import jakarta.ws.rs.core.Context;
2630
import jakarta.ws.rs.core.MediaType;
2731
import jakarta.ws.rs.core.UriInfo;
28-
2932
import org.eclipse.microprofile.rest.client.RestClientBuilder;
3033
import org.eclipse.microprofile.rest.client.inject.RestClient;
3134

@@ -75,4 +78,23 @@ public JsonObject getDefaultMessage() {
7578
}
7679
return msg1;
7780
}
81+
82+
/**
83+
* Test both clients and compares responses before returning one. Async version.
84+
*
85+
* @return JSON response.
86+
*/
87+
@GET
88+
@Path("async")
89+
@Produces(MediaType.APPLICATION_JSON)
90+
public JsonObject getDefaultMessageAsync() throws ExecutionException, InterruptedException, TimeoutException {
91+
JsonObject msg1 = injectedClient.getDefaultMessageAsync()
92+
.toCompletableFuture().get(5, TimeUnit.SECONDS);
93+
JsonObject msg2 = builderClient.getDefaultMessageAsync()
94+
.toCompletableFuture().get(5, TimeUnit.SECONDS);
95+
if (!msg1.getString("message").equals(msg2.getString("message"))) {
96+
throw new IllegalStateException("Oops");
97+
}
98+
return msg1;
99+
}
78100
}

tests/integration/restclient/src/test/java/io/helidon/tests/integration/restclient/MainTest.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@
1616

1717
package io.helidon.tests.integration.restclient;
1818

19+
import io.helidon.microprofile.tests.junit5.HelidonTest;
1920
import jakarta.inject.Inject;
2021
import jakarta.json.JsonObject;
2122
import jakarta.ws.rs.client.WebTarget;
22-
23-
import io.helidon.microprofile.tests.junit5.HelidonTest;
2423
import org.eclipse.microprofile.metrics.Counter;
2524
import org.eclipse.microprofile.metrics.MetricID;
2625
import org.eclipse.microprofile.metrics.MetricRegistry;
2726
import org.eclipse.microprofile.metrics.Tag;
2827
import org.eclipse.microprofile.metrics.annotation.RegistryType;
28+
import org.junit.jupiter.api.Disabled;
2929
import org.junit.jupiter.api.Test;
3030

3131
import static org.hamcrest.CoreMatchers.is;
@@ -67,4 +67,15 @@ void testHelloWorld() {
6767
counter = registry.getCounters().get(metricID);
6868
assertThat(counter.getCount(), is(2L));
6969
}
70+
71+
@Test
72+
@Disabled
73+
void testHelloWorldAsync() {
74+
JsonObject jsonObject = target
75+
.path("proxy")
76+
.path("async")
77+
.request()
78+
.get(JsonObject.class);
79+
assertThat(jsonObject.getString("message"), is("Hello World!"));
80+
}
7081
}

0 commit comments

Comments
 (0)