Skip to content

Commit

Permalink
Add UrlTemplatePath handling for Reactive REST Client
Browse files Browse the repository at this point in the history
  • Loading branch information
geoand authored and ebullient committed Jun 14, 2021
1 parent 08f8a90 commit 61268cf
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@
import org.jboss.jandex.PrimitiveType;
import org.jboss.jandex.Type;
import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.client.handlers.ClientObservabilityHandler;
import org.jboss.resteasy.reactive.client.impl.AsyncInvokerImpl;
import org.jboss.resteasy.reactive.client.impl.ClientImpl;
import org.jboss.resteasy.reactive.client.impl.UniInvoker;
import org.jboss.resteasy.reactive.client.impl.WebTargetImpl;
import org.jboss.resteasy.reactive.client.spi.ClientRestHandler;
import org.jboss.resteasy.reactive.common.core.GenericTypeMapping;
import org.jboss.resteasy.reactive.common.core.ResponseBuilderFactory;
import org.jboss.resteasy.reactive.common.core.Serialisers;
Expand All @@ -78,6 +80,8 @@
import io.quarkus.arc.processor.DotNames;
import io.quarkus.arc.processor.MethodDescriptors;
import io.quarkus.arc.processor.Types;
import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.Capability;
import io.quarkus.deployment.GeneratedClassGizmoAdaptor;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
Expand All @@ -90,6 +94,7 @@
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
import io.quarkus.deployment.metrics.MetricsCapabilityBuildItem;
import io.quarkus.deployment.recording.RecorderContext;
import io.quarkus.deployment.util.JandexUtil;
import io.quarkus.gizmo.AssignableResultHandle;
Expand Down Expand Up @@ -121,6 +126,7 @@
import io.quarkus.resteasy.reactive.spi.MessageBodyWriterBuildItem;
import io.quarkus.resteasy.reactive.spi.MessageBodyWriterOverrideBuildItem;
import io.quarkus.runtime.RuntimeValue;
import io.quarkus.runtime.metrics.MetricsFactory;
import io.smallrye.mutiny.Uni;
import io.vertx.core.buffer.Buffer;
import io.vertx.ext.web.multipart.MultipartForm;
Expand Down Expand Up @@ -171,6 +177,7 @@ void setupClientProxies(JaxrsClientReactiveRecorder recorder,
List<JaxrsClientReactiveEnricherBuildItem> enricherBuildItems,
BeanArchiveIndexBuildItem beanArchiveIndexBuildItem,
Optional<ResourceScanningResultBuildItem> resourceScanningResultBuildItem,
Capabilities capabilities, Optional<MetricsCapabilityBuildItem> metricsCapability,
ResteasyReactiveConfig config,
RecorderContext recorderContext,
BuildProducer<GeneratedClassBuildItem> generatedClassBuildItemBuildProducer,
Expand Down Expand Up @@ -215,6 +222,10 @@ void setupClientProxies(JaxrsClientReactiveRecorder recorder,
.setSmartDefaultProduces(disableSmartDefaultProduces.isEmpty())
.build();

boolean observabilityIntegrationNeeded = (capabilities.isPresent(Capability.OPENTELEMETRY_TRACER) ||
(metricsCapability.isPresent()
&& metricsCapability.get().metricsSupported(MetricsFactory.MICROMETER)));

Map<String, RuntimeValue<Function<WebTarget, ?>>> clientImplementations = new HashMap<>();
Map<String, String> failures = new HashMap<>();
for (Map.Entry<DotName, String> i : result.getClientInterfaces().entrySet()) {
Expand All @@ -228,7 +239,7 @@ void setupClientProxies(JaxrsClientReactiveRecorder recorder,
try {
RuntimeValue<Function<WebTarget, ?>> proxyProvider = generateClientInvoker(recorderContext, clientProxy,
enricherBuildItems, generatedClassBuildItemBuildProducer, clazz, index, defaultConsumesType,
result.getHttpAnnotationToMethod());
result.getHttpAnnotationToMethod(), observabilityIntegrationNeeded);
if (proxyProvider != null) {
clientImplementations.put(clientProxy.getClassName(), proxyProvider);
}
Expand Down Expand Up @@ -419,7 +430,8 @@ A more full example of generated client (with sub-resource) can is at the bottom
private RuntimeValue<Function<WebTarget, ?>> generateClientInvoker(RecorderContext recorderContext,
RestClientInterface restClientInterface, List<JaxrsClientReactiveEnricherBuildItem> enrichers,
BuildProducer<GeneratedClassBuildItem> generatedClasses, ClassInfo interfaceClass,
IndexView index, String defaultMediaType, Map<DotName, String> httpAnnotationToMethod) {
IndexView index, String defaultMediaType, Map<DotName, String> httpAnnotationToMethod,
boolean observabilityIntegrationNeeded) {

String name = restClientInterface.getClassName() + "$$QuarkusRestClientInterface";
MethodDescriptor ctorDesc = MethodDescriptor.ofConstructor(name, WebTarget.class.getName());
Expand Down Expand Up @@ -763,12 +775,22 @@ A more full example of generated client (with sub-resource) can is at the bottom
} else {

// constructor: initializing the immutable part of the method-specific web target
FieldDescriptor webTargetForMethod = FieldDescriptor.of(name, "target" + methodIndex, WebTarget.class);
FieldDescriptor webTargetForMethod = FieldDescriptor.of(name, "target" + methodIndex, WebTargetImpl.class);
c.getFieldCreator(webTargetForMethod).setModifiers(Modifier.FINAL);
webTargets.add(webTargetForMethod);

AssignableResultHandle constructorTarget = createWebTargetForMethod(constructor, baseTarget, method);
constructor.writeInstanceField(webTargetForMethod, constructor.getThis(), constructorTarget);
if (observabilityIntegrationNeeded) {
String templatePath = restClientInterface.getPath() + method.getPath();
constructor.invokeVirtualMethod(
MethodDescriptor.ofMethod(WebTargetImpl.class, "setPreClientSendHandler", void.class,
ClientRestHandler.class),
constructor.readInstanceField(webTargetForMethod, constructor.getThis()),
constructor.newInstance(
MethodDescriptor.ofConstructor(ClientObservabilityHandler.class, String.class),
constructor.load(templatePath)));
}

// generate implementation for a method from jaxrs interface:
MethodCreator methodCreator = c.getMethodCreator(method.getName(), method.getSimpleReturnType(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.jboss.resteasy.reactive.client.handlers;

import org.jboss.resteasy.reactive.client.impl.RestClientRequestContext;
import org.jboss.resteasy.reactive.client.spi.ClientRestHandler;

/**
* This is added by the Reactive Rest Client if observability features are enabled
*/
@SuppressWarnings("unused")
public class ClientObservabilityHandler implements ClientRestHandler {

private final String templatePath;

public ClientObservabilityHandler(String templatePath) {
this.templatePath = templatePath;
}

@Override
public void handle(RestClientRequestContext requestContext) throws Exception {
requestContext.getClientFilterProperties().put("UrlPathTemplate", templatePath);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,35 @@ class HandlerChain {
private final ClientRestHandler clientResponseCompleteRestHandler;
private final ClientRestHandler clientErrorHandler;

private ClientRestHandler preClientSendHandler = null;

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

HandlerChain setPreClientSendHandler(ClientRestHandler preClientSendHandler) {
this.preClientSendHandler = preClientSendHandler;
return this;
}

ClientRestHandler[] createHandlerChain(ConfigurationImpl configuration) {
List<ClientRequestFilter> requestFilters = configuration.getRequestFilters();
List<ClientResponseFilter> responseFilters = configuration.getResponseFilters();
if (requestFilters.isEmpty() && responseFilters.isEmpty()) {
return new ClientRestHandler[] { clientSendHandler, clientSetResponseEntityRestHandler,
clientResponseCompleteRestHandler };
}
List<ClientRestHandler> result = new ArrayList<>(3 + requestFilters.size() + responseFilters.size());
List<ClientRestHandler> result = new ArrayList<>(
(preClientSendHandler != null ? 4 : 3) + requestFilters.size() + responseFilters.size());
for (int i = 0; i < requestFilters.size(); i++) {
result.add(new ClientRequestFilterRestHandler(requestFilters.get(i)));
}
if (preClientSendHandler != null) {
result.add(preClientSendHandler);
}
result.add(clientSendHandler);
result.add(clientSetResponseEntityRestHandler);
for (int i = 0; i < responseFilters.size(); i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,4 +361,8 @@ public RestClientRequestContext setAbortedWith(Response abortedWith) {
public boolean isMultipart() {
return entity != null && entity.getEntity() instanceof MultipartForm;
}

public Map<String, Object> getClientFilterProperties() {
return properties;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
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 @@ -25,6 +26,10 @@ public class WebTargetImpl implements WebTarget {
final HandlerChain handlerChain;
final ThreadSetupAction requestContext;

// an additional handler that is passed to the handlerChain
// used to support observability features
private ClientRestHandler preClientSendHandler = null;

public WebTargetImpl(ClientImpl restClient, HttpClient client, UriBuilder uriBuilder,
ConfigurationImpl configuration,
HandlerChain handlerChain,
Expand Down Expand Up @@ -260,8 +265,11 @@ 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,
WebTargetImpl result = new WebTargetImpl(restClient, client, uriBuilder, configuration,
handlerChain.setPreClientSendHandler(preClientSendHandler),
requestContext);
result.setPreClientSendHandler(preClientSendHandler);
return result;
}

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

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

@Override
Expand Down Expand Up @@ -377,6 +386,11 @@ public ClientImpl getRestClient() {
return restClient;
}

@SuppressWarnings("unused")
public void setPreClientSendHandler(ClientRestHandler preClientSendHandler) {
this.preClientSendHandler = preClientSendHandler;
}

Serialisers getSerialisers() {
return restClient.getClientContext().getSerialisers();
}
Expand Down

0 comments on commit 61268cf

Please sign in to comment.