Skip to content

Commit

Permalink
REST client: allow subtyping the ClientInvocation RESTEASY-2443
Browse files Browse the repository at this point in the history
Use this to capture container headers and restore them in a request context property
  • Loading branch information
FroMage authored and asoldano committed Dec 3, 2019
1 parent 89f73bf commit 8c0e65b
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 99 deletions.
Expand Up @@ -26,10 +26,11 @@
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.engines.URLConnectionClientEngineBuilder;
import org.jboss.resteasy.client.jaxrs.internal.LocalResteasyProviderFactory;
import org.jboss.resteasy.microprofile.client.async.AsyncInvocationInterceptorHandler;
import org.jboss.resteasy.microprofile.client.async.AsyncInterceptorRxInvokerProvider;
import org.jboss.resteasy.microprofile.client.async.AsyncInvocationInterceptorHandler;
import org.jboss.resteasy.microprofile.client.header.ClientHeaderProviders;
import org.jboss.resteasy.microprofile.client.header.ClientHeadersRequestFilter;
import org.jboss.resteasy.microprofile.client.impl.MpClientBuilderImpl;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.ResteasyUriBuilder;

Expand All @@ -40,11 +41,11 @@
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Priorities;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.ext.ParamConverterProvider;

import java.io.Closeable;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
Expand Down Expand Up @@ -91,29 +92,23 @@ public static void setProviderFactory(ResteasyProviderFactory providerFactory) {
}

public RestClientBuilderImpl() {
ClientBuilder availableBuilder = ClientBuilder.newBuilder();
builderDelegate = new MpClientBuilderImpl();

if (availableBuilder instanceof ResteasyClientBuilder) {
builderDelegate = (ResteasyClientBuilder) availableBuilder;

if (PROVIDER_FACTORY != null) {
ResteasyProviderFactory localProviderFactory = new LocalResteasyProviderFactory(PROVIDER_FACTORY);
if (ResteasyProviderFactory.peekInstance() != null) {
localProviderFactory.initializeClientProviders(ResteasyProviderFactory.getInstance());
}
builderDelegate.providerFactory(localProviderFactory);
if (PROVIDER_FACTORY != null) {
ResteasyProviderFactory localProviderFactory = new LocalResteasyProviderFactory(PROVIDER_FACTORY);
if (ResteasyProviderFactory.peekInstance() != null) {
localProviderFactory.initializeClientProviders(ResteasyProviderFactory.getInstance());
}
builderDelegate.providerFactory(localProviderFactory);
}

configurationWrapper = new ConfigurationWrapper(builderDelegate.getConfiguration());
configurationWrapper = new ConfigurationWrapper(builderDelegate.getConfiguration());

try {
// configuration MP may not be available.
config = ConfigProvider.getConfig();
} catch (Throwable e) {
try {
// configuration MP may not be available.
config = ConfigProvider.getConfig();
} catch (Throwable e) {

}
} else {
throw new IllegalStateException("Incompatible client builder found " + availableBuilder.getClass());
}
}

Expand Down
Expand Up @@ -15,60 +15,35 @@
*/
package org.jboss.resteasy.microprofile.client.header;

import static org.jboss.resteasy.microprofile.client.utils.ListCastUtils.castToListOfStrings;

import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;
import org.jboss.resteasy.microprofile.client.impl.MpClientInvocation;
import org.jboss.resteasy.microprofile.client.utils.ClientRequestContextUtils;

import javax.annotation.Priority;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.ServiceLoader;

import static org.jboss.resteasy.microprofile.client.utils.ListCastUtils.castToListOfStrings;


/**
* First the headers from `@ClientHeaderParam` annotations are applied,
* they can be overwritten by JAX-RS `@HeaderParam` (coming in the `requestContext`)
*
* Then, if a `ClientHeadersFactory` is defined, all the headers, together with headers from `IncomingHeadersProvider`,
* Then, if a `ClientHeadersFactory` is defined, all the headers, together with incoming container headers,
* are passed to it and it can overwrite them.
*/
@Priority(Integer.MIN_VALUE)
public class ClientHeadersRequestFilter implements ClientRequestFilter {

private static final IncomingHeadersProvider noIncomingHeadersProvider = MultivaluedHashMap::new;

private static final IncomingHeadersProvider incomingHeadersProvider;

static {
incomingHeadersProvider = initializeProvider();
}

private static IncomingHeadersProvider initializeProvider() {
ServiceLoader<IncomingHeadersProvider> providerLoader =
ServiceLoader.load(IncomingHeadersProvider.class);

Iterator<IncomingHeadersProvider> providers = providerLoader.iterator();

if (!providers.hasNext()) {
return noIncomingHeadersProvider;
}

IncomingHeadersProvider result = providers.next();
if (providers.hasNext()) {
throw new RuntimeException("Multiple " + IncomingHeadersProvider.class.getCanonicalName() + "'s " +
"registered, expecting at most one.");
}

return result;
}
private static final MultivaluedMap<String, String> EMPTY_MAP = new MultivaluedHashMap<>();

@Override
public void filter(ClientRequestContext requestContext) {
Expand All @@ -85,17 +60,19 @@ public void filter(ClientRequestContext requestContext) {
(key, values) -> headers.put(key, castToListOfStrings(values))
);

factory.map(f -> updateHeaders(headers, f))
MultivaluedMap<String,String> containerHeaders = (MultivaluedMap<String, String>) requestContext.getProperty(MpClientInvocation.CONTAINER_HEADERS);
if(containerHeaders == null)
containerHeaders = EMPTY_MAP;
// stupid final rules
MultivaluedMap<String,String> incomingHeaders = containerHeaders;

factory.map(f -> f.update(incomingHeaders, headers))
.orElse(headers)
.forEach(
(key, values) -> requestContext.getHeaders().put(key, castToListOfObjects(values))
);
}

private MultivaluedMap<String, String> updateHeaders(MultivaluedMap<String, String> headers, ClientHeadersFactory factory) {
return factory.update(incomingHeadersProvider.getIncomingHeaders(), headers);
}

private static List<Object> castToListOfObjects(List<String> values) {
return new ArrayList<>(values);
}
Expand Down

This file was deleted.

@@ -0,0 +1,34 @@
package org.jboss.resteasy.microprofile.client.impl;

import java.net.URI;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;

import javax.ws.rs.core.UriBuilder;

import org.jboss.resteasy.client.jaxrs.ClientHttpEngine;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
import org.jboss.resteasy.client.jaxrs.internal.ClientConfiguration;
import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientImpl;


public class MpClient extends ResteasyClientImpl {

public MpClient(final ClientHttpEngine engine, final ExecutorService executor, final boolean cleanupExecutor,
final ScheduledExecutorService scheduledExecutorService, final ClientConfiguration config) {
super(engine, executor, cleanupExecutor, scheduledExecutorService, config);
}

protected ResteasyWebTarget createClientWebTarget(ResteasyClientImpl client, String uri, ClientConfiguration configuration) {
return new MpClientWebTarget(client, uri, configuration);
}

protected ResteasyWebTarget createClientWebTarget(ResteasyClientImpl client, URI uri, ClientConfiguration configuration) {
return new MpClientWebTarget(client, uri, configuration);
}

protected ResteasyWebTarget createClientWebTarget(ResteasyClientImpl client, UriBuilder uriBuilder, ClientConfiguration configuration) {
return new MpClientWebTarget(client, uriBuilder, configuration);
}

}
@@ -0,0 +1,19 @@
package org.jboss.resteasy.microprofile.client.impl;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;

import org.jboss.resteasy.client.jaxrs.ClientHttpEngine;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.internal.ClientConfiguration;
import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl;


public class MpClientBuilderImpl extends ResteasyClientBuilderImpl {

@Override
protected ResteasyClient createResteasyClient(ClientHttpEngine engine, ExecutorService executor, boolean cleanupExecutor,
ScheduledExecutorService scheduledExecutorService, ClientConfiguration config) {
return new MpClient(engine, executor, cleanupExecutor, scheduledExecutorService, config);
}
}
@@ -0,0 +1,47 @@
package org.jboss.resteasy.microprofile.client.impl;

import java.net.URI;

import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap;

import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.internal.ClientConfiguration;
import org.jboss.resteasy.client.jaxrs.internal.ClientInvocation;
import org.jboss.resteasy.client.jaxrs.internal.ClientRequestContextImpl;
import org.jboss.resteasy.client.jaxrs.internal.ClientRequestHeaders;
import org.jboss.resteasy.client.jaxrs.internal.ClientResponse;
import org.jboss.resteasy.core.ResteasyContext;


public class MpClientInvocation extends ClientInvocation {

public static final String CONTAINER_HEADERS = "MP_CLIENT_CONTAINER_HEADERS";

private MultivaluedMap<String, String> containerHeaders;

protected MpClientInvocation(final ClientInvocation clientInvocation) {
super(clientInvocation);
captureContainerHeaders();
}

protected MpClientInvocation(final ResteasyClient client, final URI uri, final ClientRequestHeaders headers, final ClientConfiguration parent) {
super(client, uri, headers, parent);
captureContainerHeaders();
}

private void captureContainerHeaders() {
HttpHeaders containerHeaders = ResteasyContext.getContextData(HttpHeaders.class);
if(containerHeaders != null) {
this.containerHeaders = containerHeaders.getRequestHeaders();
}
}

@Override
protected ClientResponse filterRequest(ClientRequestContextImpl requestContext) {
if(containerHeaders != null) {
requestContext.setProperty(CONTAINER_HEADERS, containerHeaders);
}
return super.filterRequest(requestContext);
}
}
@@ -0,0 +1,28 @@
package org.jboss.resteasy.microprofile.client.impl;

import java.net.URI;

import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.internal.ClientConfiguration;
import org.jboss.resteasy.client.jaxrs.internal.ClientInvocation;
import org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder;
import org.jboss.resteasy.client.jaxrs.internal.ClientRequestHeaders;


public class MpClientInvocationBuilder extends ClientInvocationBuilder {

public MpClientInvocationBuilder(final ResteasyClient client, final URI uri, final ClientConfiguration configuration) {
super(client, uri, configuration);
}

@Override
protected ClientInvocation createClientInvocation(ClientInvocation invocation) {
return new MpClientInvocation(invocation);
}

@Override
protected ClientInvocation createClientInvocation(ResteasyClient client, URI uri, ClientRequestHeaders headers,
ClientConfiguration parent) {
return new MpClientInvocation(client, uri, headers, parent);
}
}
@@ -0,0 +1,43 @@
package org.jboss.resteasy.microprofile.client.impl;

import java.net.URI;

import javax.ws.rs.core.UriBuilder;

import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.internal.ClientConfiguration;
import org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder;
import org.jboss.resteasy.client.jaxrs.internal.ClientWebTarget;

public class MpClientWebTarget extends ClientWebTarget {

protected MpClientWebTarget(final ResteasyClient client, final ClientConfiguration configuration)
{
super(client, configuration);
}

public MpClientWebTarget(final ResteasyClient client, final String uri, final ClientConfiguration configuration) throws IllegalArgumentException, NullPointerException
{
super(client, uri, configuration);
}

public MpClientWebTarget(final ResteasyClient client, final URI uri, final ClientConfiguration configuration) throws NullPointerException
{
super(client, uri, configuration);
}

public MpClientWebTarget(final ResteasyClient client, final UriBuilder uriBuilder, final ClientConfiguration configuration) throws NullPointerException
{
super(client, uriBuilder, configuration);
}

@Override
protected ClientWebTarget newInstance(ResteasyClient client, UriBuilder uriBuilder, ClientConfiguration configuration) {
return new MpClientWebTarget(client, uriBuilder, configuration);
}

@Override
protected ClientInvocationBuilder createClientInvocationBuilder(ResteasyClient client, URI uri, ClientConfiguration configuration) {
return new MpClientInvocationBuilder(client, uri, configuration);
}
}

0 comments on commit 8c0e65b

Please sign in to comment.