You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by am...@apache.org on 2019/01/17 00:00:41 UTC
[cxf] branch master updated: [CXF-7926] Initial MP Rest Client 1.2
impl - part 2
This is an automated email from the ASF dual-hosted git repository.
amccright pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/master by this push:
new f29e60b [CXF-7926] Initial MP Rest Client 1.2 impl - part 2
new 0669933 Merge pull request #499 from andymc12/mpRest12initial-part2
f29e60b is described below
commit f29e60b167440662b1406693cda4c44c06df78e7
Author: Andy McCright <j....@gmail.com>
AuthorDate: Tue Dec 11 22:16:03 2018 -0600
[CXF-7926] Initial MP Rest Client 1.2 impl - part 2
* This includes generation and propagation of HTTPHeaders via
@ClientHeaderParam annotations and ClientHeadersFactory.
* Ensuring that timeout props only have effect when using CDI.
* Related unit and system tests.
---
rt/rs/microprofile-client/pom.xml | 2 +-
.../client/CxfTypeSafeClientBuilder.java | 25 ---
.../cxf/microprofile/client/Messages.properties | 9 +-
.../client/MicroProfileClientFactoryBean.java | 4 +-
.../apache/cxf/microprofile/client/Validator.java | 92 ++++++++++
.../microprofile/client/cdi/RestClientBean.java | 24 +++
.../client/proxy/MicroProfileClientProxyImpl.java | 198 ++++++++++++++++++++-
.../cxf/microprofile/client/ClientHeadersTest.java | 92 ++++++++++
.../cxf/microprofile/client/ValidatorTest.java | 90 ++++++++++
.../mock/HeaderCaptureClientRequestFilter.java | 46 +++++
.../microprofile/client/mock/HeaderGenerator.java | 33 ++++
.../client/mock/HeadersFactoryClient.java | 40 +++++
.../client/mock/HeadersOnInterfaceClient.java | 40 +++++
.../client/mock/HeadersOnMethodClient.java | 41 +++++
.../client/mock/MockConfigProviderResolver.java | 1 -
.../client/mock/MyClientHeadersFactory.java | 61 +++++++
systests/microprofile/client/async/pom.xml | 4 +-
systests/microprofile/client/jaxrs/pom.xml | 190 ++++++++++++++++++++
.../rest/client/JaxrsHeaderPropagationTest.java | 118 ++++++++++++
.../microprofile/rest/client/JaxrsResource.java | 49 +++++
.../rest/client}/MockConfigProviderResolver.java | 3 +-
.../microprofile/rest/client/RestClient.java | 32 ++++
.../client/ReturnAllOutboundHeadersFilter.java | 40 +++++
systests/microprofile/client/weld/testng.xml | 1 +
systests/microprofile/pom.xml | 3 +-
25 files changed, 1199 insertions(+), 39 deletions(-)
diff --git a/rt/rs/microprofile-client/pom.xml b/rt/rs/microprofile-client/pom.xml
index b122d56..8235b21 100644
--- a/rt/rs/microprofile-client/pom.xml
+++ b/rt/rs/microprofile-client/pom.xml
@@ -42,7 +42,7 @@
org.apache.aries.blueprint.NamespaceHandler;osgi.service.blueprint.namespace="http://cxf.apache.org/blueprint/jaxrs-client"
</cxf.export.service>
<cxf.bundle.activator>org.apache.cxf.jaxrs.client.blueprint.Activator</cxf.bundle.activator>
- <mp.rest.client.version>1.2-m2</mp.rest.client.version>
+ <mp.rest.client.version>1.2-RC1</mp.rest.client.version>
</properties>
<dependencies>
<dependency>
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilder.java b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilder.java
index 5b1ff3d..d1177af 100644
--- a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilder.java
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilder.java
@@ -29,16 +29,12 @@ import java.util.ServiceLoader;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
-import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import javax.ws.rs.core.Configurable;
import javax.ws.rs.core.Configuration;
-import org.apache.cxf.common.logging.LogUtils;
-import org.apache.cxf.microprofile.client.config.ConfigFacade;
import org.eclipse.microprofile.rest.client.RestClientBuilder;
import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.eclipse.microprofile.rest.client.spi.RestClientListener;
@@ -47,9 +43,6 @@ import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_CONNECTION_TIMEO
import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_RECEIVE_TIMEOUT_PROP;
public class CxfTypeSafeClientBuilder implements RestClientBuilder, Configurable<RestClientBuilder> {
- private static final Logger LOG = LogUtils.getL7dLogger(CxfTypeSafeClientBuilder.class);
- private static final String REST_CONN_TIMEOUT_FORMAT = "%s/mp-rest/connectTimeout";
- private static final String REST_READ_TIMEOUT_FORMAT = "%s/mp-rest/readTimeout";
private static final Map<ClassLoader, Collection<RestClientListener>> REST_CLIENT_LISTENERS =
new WeakHashMap<>();
@@ -136,24 +129,6 @@ public class CxfTypeSafeClientBuilder implements RestClientBuilder, Configurable
}
}
- final String interfaceName = aClass.getName();
-
- ConfigFacade.getOptionalLong(String.format(REST_CONN_TIMEOUT_FORMAT, interfaceName)).ifPresent(
- timeoutValue -> {
- connectTimeout(timeoutValue, TimeUnit.MILLISECONDS);
- if (LOG.isLoggable(Level.FINEST)) {
- LOG.finest("readTimeout set by MP Config: " + timeoutValue);
- }
- });
-
- ConfigFacade.getOptionalLong(String.format(REST_READ_TIMEOUT_FORMAT, interfaceName)).ifPresent(
- timeoutValue -> {
- readTimeout(timeoutValue, TimeUnit.MILLISECONDS);
- if (LOG.isLoggable(Level.FINEST)) {
- LOG.finest("readTimeout set by MP Config: " + timeoutValue);
- }
- });
-
listeners().forEach(l -> l.onNewClient(aClass, this));
MicroProfileClientFactoryBean bean = new MicroProfileClientFactoryBean(configImpl,
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/Messages.properties b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/Messages.properties
index 1af5bb6..dfe9ac0 100644
--- a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/Messages.properties
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/Messages.properties
@@ -29,4 +29,11 @@ ASYNC_INTERCEPTOR_EXCEPTION_PREPARE_CONTEXT=The AsyncInvocationInterceptor, {0}
ASYNC_INTERCEPTOR_EXCEPTION_APPLY_CONTEXT=The AsyncInvocationInterceptor, {0} has thrown an exception during the invocation of the applyContext method.
ASYNC_INTERCEPTOR_EXCEPTION_REMOVE_CONTEXT=The AsyncInvocationInterceptor, {0} has thrown an exception during the invocation of the removeContext method.
-INVALID_TIMEOUT_PROPERTY=The timeout property, {0} is specified as {1}, and is invalid. It must be a non-negative integer.
\ No newline at end of file
+INVALID_TIMEOUT_PROPERTY=The timeout property, {0} is specified as {1}, and is invalid. It must be a non-negative integer.
+
+CLIENT_HEADER_NO_NAME=A @ClientHeaderParam annotation specified in the {0} interface is invalid because it has a null or empty name.
+CLIENT_HEADER_NO_VALUE=A @ClientHeaderParam annotation specified in the {0} interface is invalid because it does not define a valid value attribute.
+CLIENT_HEADER_INVALID_COMPUTE_METHOD=A @ClientHeaderParam annotation specified in the {0} interface is invalid because it's value attribute specifies a method, {1}, that does not exist, is not accessible, or contains an incorrect signature. The signature must return a String or String[] and must contain either no arguments or contain exactly one String argument.
+CLIENT_HEADER_MULTI_METHOD=A @ClientHeaderParam annotation specified in the {0} interface is invalid because it's value attribute specifies multiple values and at least one of those values is a compute method. If the value attribute specifies a compute method, that must be the only value.
+CLIENT_HEADER_COMPUTE_CLASS_NOT_FOUND=A @ClientHeaderParam annotation specified in the {0} interface is invalid because it specifies a compute method on a class that cannot be found.
+CLIENT_HEADER_MULTIPLE_SAME_HEADER_NAMES=A @ClientHeaderParam annotation specified in the {0} interface is invalid because it specifies a header name that is already specified on the same target. A header name may only be specified in one @ClientHeaderParam per target.
\ No newline at end of file
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientFactoryBean.java b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientFactoryBean.java
index 6d59031..6007e3b 100644
--- a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientFactoryBean.java
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientFactoryBean.java
@@ -115,10 +115,10 @@ public class MicroProfileClientFactoryBean extends JAXRSClientFactoryBean {
private Set<Object> processProviders() {
Set<Object> providers = new LinkedHashSet<>();
for (Object provider : configuration.getInstances()) {
- Class<?> providerCls = ClassHelper.getRealClass(bus, provider);
+ Class<?> providerCls = ClassHelper.getRealClass(getBus(), provider);
if (provider instanceof ClientRequestFilter || provider instanceof ClientResponseFilter) {
FilterProviderInfo<Object> filter = new FilterProviderInfo<>(providerCls, providerCls,
- provider, bus, configuration.getContracts(providerCls));
+ provider, getBus(), configuration.getContracts(providerCls));
providers.add(filter);
} else {
providers.add(provider);
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/Validator.java b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/Validator.java
index 3155164..1ae4807 100644
--- a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/Validator.java
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/Validator.java
@@ -20,8 +20,10 @@ package org.apache.cxf.microprofile.client;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -29,17 +31,24 @@ import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
+import org.apache.cxf.common.classloader.ClassLoaderUtils;
import org.apache.cxf.common.i18n.BundleUtils;
import org.apache.cxf.common.i18n.Message;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.jaxrs.model.URITemplate;
import org.eclipse.microprofile.rest.client.RestClientDefinitionException;
+import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam;
final class Validator {
+ private static final Logger LOG = LogUtils.getL7dLogger(Validator.class);
private static final ResourceBundle BUNDLE = BundleUtils.getBundle(Validator.class);
private Validator() {
@@ -53,6 +62,7 @@ final class Validator {
Method[] methods = userType.getMethods();
checkMethodsForMultipleHTTPMethodAnnotations(methods);
checkMethodsForInvalidURITemplates(userType, methods);
+ checkForInvalidClientHeaderParams(userType, methods);
}
private static void checkMethodsForMultipleHTTPMethodAnnotations(Method[] clientMethods)
@@ -129,6 +139,88 @@ final class Validator {
}
}
+ private static void checkForInvalidClientHeaderParams(Class<?> userType, Method[] methods) {
+ ClientHeaderParam[] interfaceAnnotations = userType.getAnnotationsByType(ClientHeaderParam.class);
+ checkClientHeaderParamAnnotation(interfaceAnnotations, userType, methods);
+ for (Method method : methods) {
+ ClientHeaderParam[] methodAnnotations = method.getAnnotationsByType(ClientHeaderParam.class);
+ checkClientHeaderParamAnnotation(methodAnnotations, userType, methods);
+ }
+ }
+
+ private static void checkClientHeaderParamAnnotation(ClientHeaderParam[] annos, Class<?> userType,
+ Method[] methods) {
+ Set<String> headerNames = new HashSet<>();
+ for (ClientHeaderParam anno : annos) {
+ String name = anno.name();
+ if (headerNames.contains(name)) {
+ throwException("CLIENT_HEADER_MULTIPLE_SAME_HEADER_NAMES", userType.getName());
+ }
+ headerNames.add(name);
+
+ if (name == null || "".equals(name)) {
+ throwException("CLIENT_HEADER_NO_NAME", userType.getName());
+ }
+
+ String[] values = anno.value();
+
+ for (String value : values) {
+ if (StringUtils.isEmpty(value)) {
+ throwException("CLIENT_HEADER_NO_VALUE", userType.getName());
+ }
+
+ if (value.startsWith("{") && value.endsWith("}")) {
+ if (values.length > 1) {
+ throwException("CLIENT_HEADER_MULTI_METHOD", userType.getName());
+ }
+ String computeValue = value.substring(1, value.length() - 1);
+ boolean usingOtherClass = false;
+ if (computeValue.contains(".")) {
+ usingOtherClass = true;
+ String className = computeValue.substring(0, computeValue.lastIndexOf('.'));
+ computeValue = computeValue.substring(computeValue.lastIndexOf('.') + 1);
+ try {
+ Class<?> computeClass = ClassLoaderUtils.loadClass(className, userType);
+ methods = Arrays.stream(computeClass.getDeclaredMethods())
+ .filter(m -> {
+ int i = m.getModifiers();
+ return Modifier.isPublic(i)
+ && Modifier.isStatic(i);
+ })
+ .toArray(Method[]::new);
+ } catch (ClassNotFoundException ex) {
+ if (LOG.isLoggable(Level.FINEST)) {
+ LOG.log(Level.FINEST, "Unable to load specified compute method class", ex);
+ }
+ throwException("CLIENT_HEADER_COMPUTE_CLASS_NOT_FOUND", userType.getName(), ex);
+ }
+
+ }
+ boolean foundMatchingMethod = false;
+ for (Method method : methods) {
+ Class<?> returnType = method.getReturnType();
+ if ((usingOtherClass || method.isDefault())
+ && (String.class.equals(returnType) || String[].class.equals(returnType))
+ && computeValue.equals(method.getName())) {
+
+ Class<?>[] args = method.getParameterTypes();
+ if (args.length == 0 || (args.length == 1 && String.class.equals(args[0]))) {
+ foundMatchingMethod = true;
+ break;
+ }
+
+ }
+ }
+ if (!foundMatchingMethod) {
+ throwException("CLIENT_HEADER_INVALID_COMPUTE_METHOD",
+ userType.getName(),
+ computeValue);
+ }
+ }
+ }
+ }
+ }
+
private static void throwException(String msgKey, Object...msgParams) throws RestClientDefinitionException {
Message msg = new Message(msgKey, BUNDLE, msgParams);
throw new RestClientDefinitionException(msg.toString());
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/RestClientBean.java b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/RestClientBean.java
index 89d2b7d..fa6a84a 100644
--- a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/RestClientBean.java
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/RestClientBean.java
@@ -29,6 +29,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -55,6 +56,8 @@ public class RestClientBean implements Bean<Object>, PassivationCapable {
public static final String REST_URI_FORMAT = "%s/mp-rest/uri";
public static final String REST_SCOPE_FORMAT = "%s/mp-rest/scope";
public static final String REST_PROVIDERS_FORMAT = "%s/mp-rest/providers";
+ public static final String REST_CONN_TIMEOUT_FORMAT = "%s/mp-rest/connectTimeout";
+ public static final String REST_READ_TIMEOUT_FORMAT = "%s/mp-rest/readTimeout";
public static final String REST_PROVIDERS_PRIORITY_FORMAT = "%s/mp-rest/providers/%s/priority";
private static final Logger LOG = LogUtils.getL7dLogger(RestClientBean.class);
private static final Default DEFAULT_LITERAL = new DefaultLiteral();
@@ -98,6 +101,7 @@ public class RestClientBean implements Bean<Object>, PassivationCapable {
builder = (CxfTypeSafeClientBuilder) builder.register(providerClass,
providerPriorities.getOrDefault(providerClass, Priorities.USER));
}
+ setTimeouts(builder);
return builder.build(clientInterface);
}
@@ -229,4 +233,24 @@ public class RestClientBean implements Bean<Object>, PassivationCapable {
private static final long serialVersionUID = 1L;
}
+
+ private void setTimeouts(CxfTypeSafeClientBuilder builder) {
+ final String interfaceName = clientInterface.getName();
+
+ ConfigFacade.getOptionalLong(String.format(REST_CONN_TIMEOUT_FORMAT, interfaceName)).ifPresent(
+ timeoutValue -> {
+ builder.connectTimeout(timeoutValue, TimeUnit.MILLISECONDS);
+ if (LOG.isLoggable(Level.FINEST)) {
+ LOG.finest("readTimeout set by MP Config: " + timeoutValue);
+ }
+ });
+
+ ConfigFacade.getOptionalLong(String.format(REST_READ_TIMEOUT_FORMAT, interfaceName)).ifPresent(
+ timeoutValue -> {
+ builder.readTimeout(timeoutValue, TimeUnit.MILLISECONDS);
+ if (LOG.isLoggable(Level.FINEST)) {
+ LOG.finest("readTimeout set by MP Config: " + timeoutValue);
+ }
+ });
+ }
}
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/proxy/MicroProfileClientProxyImpl.java b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/proxy/MicroProfileClientProxyImpl.java
index ea7db94..14ab55a 100644
--- a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/proxy/MicroProfileClientProxyImpl.java
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/proxy/MicroProfileClientProxyImpl.java
@@ -18,9 +18,11 @@
*/
package org.apache.cxf.microprofile.client.proxy;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.net.URI;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -32,10 +34,13 @@ import java.util.logging.Logger;
import javax.ws.rs.client.InvocationCallback;
import javax.ws.rs.core.Configuration;
+import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
+import org.apache.cxf.common.classloader.ClassLoaderUtils;
import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.helpers.CastUtils;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.jaxrs.client.ClientProxyImpl;
import org.apache.cxf.jaxrs.client.ClientState;
@@ -43,12 +48,18 @@ import org.apache.cxf.jaxrs.client.JaxrsClientCallback;
import org.apache.cxf.jaxrs.client.LocalClientState;
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.jaxrs.model.OperationResourceInfo;
+import org.apache.cxf.jaxrs.model.Parameter;
+import org.apache.cxf.jaxrs.model.ParameterType;
+import org.apache.cxf.jaxrs.utils.HttpUtils;
import org.apache.cxf.jaxrs.utils.InjectionUtils;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.Message;
import org.apache.cxf.microprofile.client.MPRestClientCallback;
import org.apache.cxf.microprofile.client.MicroProfileClientProviderFactory;
import org.apache.cxf.microprofile.client.cdi.CDIInterceptorWrapper;
+import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam;
+import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
+import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;
import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper;
import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_CONNECTION_TIMEOUT_PROP;
@@ -65,8 +76,25 @@ public class MicroProfileClientProxyImpl extends ClientProxyImpl {
public void completed(Object o) { }
};
- private final CDIInterceptorWrapper interceptorWrapper;
+ private static final Method JAXRS_UTILS_GET_CURRENT_MESSAGE_METHOD;
+ static {
+ Method m;
+ try {
+ Class<?> jaxrsUtilsClass = Class.forName("org.apache.cxf.jaxrs.utils.JAXRSUtils");
+ m = jaxrsUtilsClass.getDeclaredMethod("getCurrentMessage");
+ } catch (Throwable t) {
+ // expected in non-JAX-RS server environments
+ if (LOG.isLoggable(Level.FINEST)) {
+ LOG.log(Level.FINEST, "Caught exception getting JAXRUtils class", t);
+ }
+ m = null;
+ }
+ JAXRS_UTILS_GET_CURRENT_MESSAGE_METHOD = m;
+ }
+ private final CDIInterceptorWrapper interceptorWrapper;
+ private Object objectInstance;
+
//CHECKSTYLE:OFF
public MicroProfileClientProxyImpl(URI baseURI, ClassLoader loader, ClassResourceInfo cri,
boolean isRoot, boolean inheritHeaders, ExecutorService executorService,
@@ -89,8 +117,6 @@ public class MicroProfileClientProxyImpl extends ClientProxyImpl {
}
//CHECKSTYLE:ON
-
-
@SuppressWarnings("unchecked")
@Override
protected InvocationCallback<Object> checkAsyncCallback(OperationResourceInfo ori,
@@ -207,7 +233,9 @@ public class MicroProfileClientProxyImpl extends ClientProxyImpl {
cfg.getHttpConduit().getClient().setReceiveTimeout(readTimeout);
}
} catch (Exception ex) {
- ex.printStackTrace();
+ if (LOG.isLoggable(Level.FINEST)) {
+ LOG.log(Level.FINEST, "Caught exception setting timeouts", ex);
+ }
}
}
@@ -237,8 +265,144 @@ public class MicroProfileClientProxyImpl extends ClientProxyImpl {
return l;
}
+ private String invokeBestFitComputeMethod(Class<?> clientIntf, ClientHeaderParam anno) throws Throwable {
+ String methodName = anno.value()[0];
+ methodName = methodName.substring(1, methodName.length() - 1);
+ Class<?> computeClass = clientIntf;
+ if (methodName.contains(".")) {
+ String className = methodName.substring(0, methodName.lastIndexOf('.'));
+ methodName = methodName.substring(methodName.lastIndexOf('.') + 1);
+ try {
+ computeClass = ClassLoaderUtils.loadClass(className, clientIntf);
+ } catch (ClassNotFoundException ex) {
+ LOG.warning("Cannot find specified computeValue class, " + className);
+ return null;
+ }
+ }
+ Method m = null;
+ boolean includeHeaderName = false;
+ try {
+ m = computeClass.getMethod(methodName, String.class);
+ includeHeaderName = true;
+ } catch (NoSuchMethodException expected) {
+ try {
+ m = computeClass.getMethod(methodName);
+ } catch (NoSuchMethodException expected2) { }
+ }
+
+ String value;
+ if (m == null) {
+ value = null;
+ LOG.warning("Cannot find specified computeValue method, "
+ + methodName + ", on client interface, " + clientIntf.getName());
+ } else {
+ try {
+ Object valueFromComputeMethod;
+ if (includeHeaderName) {
+ valueFromComputeMethod = m.invoke(computeClass == clientIntf ? objectInstance : null,
+ anno.name());
+ } else {
+ valueFromComputeMethod = m.invoke(computeClass == clientIntf ? objectInstance : null);
+ }
+ if (valueFromComputeMethod instanceof String[]) {
+ value = HttpUtils.getHeaderString(Arrays.asList((String[]) valueFromComputeMethod));
+ } else {
+ value = (String) valueFromComputeMethod;
+ }
+ } catch (Throwable t) {
+ if (LOG.isLoggable(Level.FINEST)) {
+ LOG.log(Level.FINEST, "Caught exception invoking compute method", t);
+ }
+ if (t instanceof InvocationTargetException) {
+ t = t.getCause();
+ }
+ throw t;
+ }
+ }
+ return value;
+ }
+
+ private Parameter createClientHeaderParameter(ClientHeaderParam anno, Class<?> clientIntf) {
+ Parameter p = new Parameter(ParameterType.HEADER, anno.name());
+ String[] values = anno.value();
+ String headerValue;
+ if (values[0] != null && values[0].length() > 2 && values[0].startsWith("{") && values[0].endsWith("}")) {
+ try {
+ headerValue = invokeBestFitComputeMethod(clientIntf, anno);
+ } catch (Throwable t) {
+ if (anno.required()) {
+ throwException(t);
+ }
+ return null;
+ }
+ } else {
+ headerValue = HttpUtils.getHeaderString(Arrays.asList(values));
+ }
+
+ p.setDefaultValue(headerValue);
+ return p;
+ }
+
+ @Override
+ protected void handleHeaders(Method m,
+ Object[] params,
+ MultivaluedMap<String, String> headers,
+ List<Parameter> beanParams,
+ MultivaluedMap<ParameterType, Parameter> map) {
+ super.handleHeaders(m, params, headers, beanParams, map);
+
+ try {
+ Class<?> declaringClass = m.getDeclaringClass();
+ ClientHeaderParam[] clientHeaderAnnosOnInterface = declaringClass
+ .getAnnotationsByType(ClientHeaderParam.class);
+ ClientHeaderParam[] clientHeaderAnnosOnMethod = m.getAnnotationsByType(ClientHeaderParam.class);
+ RegisterClientHeaders headersFactoryAnno = declaringClass.getAnnotation(RegisterClientHeaders.class);
+ if (clientHeaderAnnosOnInterface.length < 1 && clientHeaderAnnosOnMethod.length < 1
+ && headersFactoryAnno == null) {
+ return;
+ }
+
+ for (ClientHeaderParam methodAnno : clientHeaderAnnosOnMethod) {
+ String headerName = methodAnno.name();
+ if (!headers.containsKey(headerName)) {
+ Parameter p = createClientHeaderParameter(methodAnno, declaringClass);
+ if (p != null) {
+ headers.putSingle(p.getName(), p.getDefaultValue());
+ }
+ }
+ }
+ for (ClientHeaderParam intfAnno : clientHeaderAnnosOnInterface) {
+ String headerName = intfAnno.name();
+ if (!headers.containsKey(headerName)) {
+ Parameter p = createClientHeaderParameter(intfAnno, declaringClass);
+ if (p != null) {
+ headers.putSingle(p.getName(), p.getDefaultValue());
+ }
+ }
+ }
+
+ ClientHeadersFactory headersFactory = null;
+
+ if (headersFactoryAnno != null) {
+ Class<?> headersFactoryClass = headersFactoryAnno.value();
+ headersFactory = (ClientHeadersFactory) headersFactoryClass.newInstance();
+ mergeHeaders(headersFactory, headers);
+ }
+ } catch (Throwable t) {
+ throwException(t);
+ }
+ }
+
+ private void mergeHeaders(ClientHeadersFactory factory,
+ MultivaluedMap<String, String> existingHeaders) {
+
+ MultivaluedMap<String, String> jaxrsHeaders = getJaxrsHeaders();
+ MultivaluedMap<String, String> updatedHeaders = factory.update(jaxrsHeaders, existingHeaders);
+ existingHeaders.putAll(updatedHeaders);
+ }
@Override
public Object invoke(Object o, Method m, Object[] params) throws Throwable {
+ objectInstance = o;
return interceptorWrapper.invoke(o, m, params, new Invoker(o, m, params, this));
}
@@ -271,4 +435,30 @@ public class MicroProfileClientProxyImpl extends ClientProxyImpl {
}
}
}
+
+ private void throwException(Throwable t) {
+ if (t instanceof Error) {
+ throw (Error) t;
+ }
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ }
+ throw new RuntimeException(t);
+ }
+
+ private static MultivaluedMap<String, String> getJaxrsHeaders() {
+ MultivaluedMap<String, String> headers = new MultivaluedHashMap<>();
+ try {
+ if (JAXRS_UTILS_GET_CURRENT_MESSAGE_METHOD != null) {
+ Message m = (Message) JAXRS_UTILS_GET_CURRENT_MESSAGE_METHOD.invoke(null);
+ headers.putAll(CastUtils.cast((Map<?, ?>)m.get(Message.PROTOCOL_HEADERS)));
+ }
+ } catch (Throwable t) {
+ // expected if not running in a JAX-RS server environment.
+ if (LOG.isLoggable(Level.FINEST)) {
+ LOG.log(Level.FINEST, "Caught exception getting JAX-RS incoming headers", t);
+ }
+ }
+ return headers;
+ }
}
diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/ClientHeadersTest.java b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/ClientHeadersTest.java
new file mode 100644
index 0000000..3a3f3f2
--- /dev/null
+++ b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/ClientHeadersTest.java
@@ -0,0 +1,92 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.microprofile.client;
+
+import java.net.URI;
+
+import org.apache.cxf.microprofile.client.mock.HeaderCaptureClientRequestFilter;
+import org.apache.cxf.microprofile.client.mock.HeadersFactoryClient;
+import org.apache.cxf.microprofile.client.mock.HeadersOnInterfaceClient;
+import org.apache.cxf.microprofile.client.mock.HeadersOnMethodClient;
+import org.apache.cxf.microprofile.client.mock.MyClientHeadersFactory;
+import org.eclipse.microprofile.rest.client.RestClientBuilder;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.apache.cxf.microprofile.client.mock.HeaderCaptureClientRequestFilter.getOutboundHeaders;
+import static org.apache.cxf.microprofile.client.mock.MyClientHeadersFactory.getInitialHeaders;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class ClientHeadersTest {
+
+ @Before
+ public void clearHeaders() {
+ HeaderCaptureClientRequestFilter.setOutboundHeaders(null);
+ MyClientHeadersFactory.setInitialHeaders(null);
+ }
+
+ @Test
+ public void testClientHeaderParamsOnInterface() {
+ HeadersOnInterfaceClient client = RestClientBuilder.newBuilder()
+ .baseUri(URI.create("http://localhost/notUsed"))
+ .register(HeaderCaptureClientRequestFilter.class)
+ .build(HeadersOnInterfaceClient.class);
+ assertEquals("SUCCESS", client.put("ignored"));
+ assertNotNull(getOutboundHeaders());
+ assertEquals("value1", getOutboundHeaders().getFirst("IntfHeader1"));
+ assertEquals("value2,value3", getOutboundHeaders().getFirst("IntfHeader2"));
+ assertEquals("HeadersOnInterfaceClientValueForIntfHeader3", getOutboundHeaders().getFirst("IntfHeader3"));
+ assertEquals("valueForIntfHeader4", getOutboundHeaders().getFirst("IntfHeader4"));
+ }
+
+ @Test
+ public void testClientHeaderParamsOnMethod() {
+ HeadersOnMethodClient client = RestClientBuilder.newBuilder()
+ .baseUri(URI.create("http://localhost/notUsed"))
+ .register(HeaderCaptureClientRequestFilter.class)
+ .build(HeadersOnMethodClient.class);
+ assertEquals("SUCCESS", client.delete("ignored"));
+ assertNotNull(getOutboundHeaders());
+ assertEquals("valueA", getOutboundHeaders().getFirst("MethodHeader1"));
+ assertEquals("valueB,valueC", getOutboundHeaders().getFirst("MethodHeader2"));
+ assertEquals("HeadersOnMethodClientValueForMethodHeader3", getOutboundHeaders().getFirst("MethodHeader3"));
+ assertEquals("valueForMethodHeader4", getOutboundHeaders().getFirst("MethodHeader4"));
+ }
+
+ @Test
+ public void testClientHeadersFactory() {
+ HeadersFactoryClient client = RestClientBuilder.newBuilder()
+ .baseUri(URI.create("http://localhost/notUsed"))
+ .register(HeaderCaptureClientRequestFilter.class)
+ .build(HeadersFactoryClient.class);
+ assertEquals("SUCCESS", client.get("headerParamValue1"));
+ assertNotNull(getInitialHeaders());
+ assertEquals("headerParamValue1", getInitialHeaders().getFirst("HeaderParam1"));
+ assertEquals("abc", getInitialHeaders().getFirst("IntfHeader1"));
+ assertEquals("def", getInitialHeaders().getFirst("MethodHeader1"));
+
+ assertNotNull(getOutboundHeaders());
+ assertEquals("1eulaVmaraPredaeh", getOutboundHeaders().getFirst("HeaderParam1"));
+ assertEquals("cba", getOutboundHeaders().getFirst("IntfHeader1"));
+ assertEquals("fed", getOutboundHeaders().getFirst("MethodHeader1"));
+
+ }
+}
diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/ValidatorTest.java b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/ValidatorTest.java
index 9432399..f79437e 100644
--- a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/ValidatorTest.java
+++ b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/ValidatorTest.java
@@ -27,10 +27,12 @@ import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
+import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.core.Response;
import org.eclipse.microprofile.rest.client.RestClientBuilder;
import org.eclipse.microprofile.rest.client.RestClientDefinitionException;
+import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam;
import org.junit.Test;
@@ -94,6 +96,62 @@ public class ValidatorTest {
Response get(@PathParam("any") String any);
}
+ public interface ClientHeaderParamNoName {
+ @ClientHeaderParam(name = "", value = "something")
+ @GET
+ Response get();
+ }
+
+ public interface ClientHeaderParamNoComputeMethod {
+ @ClientHeaderParam(name = "SomeHeader", value = "{missingComputeMethod}")
+ @GET
+ Response get();
+ }
+
+ public interface ClientHeaderParamNonDefaultComputeMethod {
+ @ClientHeaderParam(name = "SomeHeader", value = "{nonDefaultComputeMethod}")
+ @GET
+ Response get();
+
+ String nonDefaultComputeMethod();
+ }
+
+ public interface ClientHeaderParamComputeMethodDoesNotExist {
+ @ClientHeaderParam(name = "SomeHeader", value = "{nonExistentComputeMethod}")
+ @GET
+ Response get();
+ }
+
+ public interface ClientHeaderParamInaccessibleComputeMethod {
+ @ClientHeaderParam(name = "SomeHeader",
+ value = "{org.apache.cxf.microprofile.client.mock.HeaderGenerator.generateHeaderPrivate}")
+ @GET
+ Response get();
+ }
+
+ public interface ClientHeaderParamNoValidComputeMethodSignatures {
+ @ClientHeaderParam(name = "SomeHeader", value = "{computeMethod}")
+ @GET
+ Response get();
+
+ default String computeMethod(String x, String y) {
+ return "must only contain one String argument";
+ }
+ default String computeMethod(ClientRequestContext x, ClientRequestContext y) {
+ return "must only contain one ClientRequestContext argument";
+ }
+ default Integer computeMethod() {
+ return 5; // must return a String
+ }
+ default void computeMethod(String headerName) { } // must return a String
+ default String computeMethod(java.util.Date date) {
+ return "unexpected argument";
+ }
+ default String computeMethod(String headerName, ClientRequestContext context, int extra) {
+ return "too many arguments";
+ }
+ }
+
private static RestClientBuilder newBuilder() {
RestClientBuilder builder = RestClientBuilder.newBuilder();
try {
@@ -132,6 +190,38 @@ public class ValidatorTest {
test(ExtraParamTemplate.class, "extra path segments", "ExtraParamTemplate");
}
+ @Test
+ public void testClientHeaderParamNoName() {
+ test(ClientHeaderParamNoName.class, ClientHeaderParamNoName.class.getName(), "null or empty name");
+ }
+
+ @Test
+ public void testClientHeaderParamNoComputeMethod() {
+ test(ClientHeaderParamNoComputeMethod.class, ClientHeaderParamNoComputeMethod.class.getName(),
+ "value attribute specifies a method", "that does not exist");
+ }
+
+ @Test
+ public void testClientHeaderParamNonDefaultComputeMethod() {
+ test(ClientHeaderParamNonDefaultComputeMethod.class,
+ ClientHeaderParamNonDefaultComputeMethod.class.getName(),
+ " is not accessible");
+ }
+
+ @Test
+ public void testClientHeaderParamComputeMethodDoesNotExist() {
+ test(ClientHeaderParamNonDefaultComputeMethod.class,
+ ClientHeaderParamNonDefaultComputeMethod.class.getName(),
+ " does not exist");
+ }
+
+ @Test
+ public void testClientHeaderParamNoValidComputeMethodSignatures() {
+ test(ClientHeaderParamNoValidComputeMethodSignatures.class,
+ ClientHeaderParamNoValidComputeMethodSignatures.class.getName(),
+ " contains an incorrect signature");
+ }
+
private void test(Class<?> clientInterface, String...expectedMessageTexts) {
try {
newBuilder().build(clientInterface);
diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeaderCaptureClientRequestFilter.java b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeaderCaptureClientRequestFilter.java
new file mode 100644
index 0000000..57c6fc5
--- /dev/null
+++ b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeaderCaptureClientRequestFilter.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.microprofile.client.mock;
+
+import java.io.IOException;
+
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+
+public class HeaderCaptureClientRequestFilter implements ClientRequestFilter {
+
+ private static MultivaluedMap<String, String> outboundHeaders;
+
+ public static MultivaluedMap<String, String> getOutboundHeaders() {
+ return outboundHeaders;
+ }
+
+ public static void setOutboundHeaders(MultivaluedMap<String, String> newHeaders) {
+ outboundHeaders = newHeaders;
+ }
+
+ @Override
+ public void filter(ClientRequestContext ctx) throws IOException {
+ setOutboundHeaders(ctx.getStringHeaders());
+ ctx.abortWith(Response.ok("SUCCESS").build());
+ }
+
+}
diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeaderGenerator.java b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeaderGenerator.java
new file mode 100644
index 0000000..d710994
--- /dev/null
+++ b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeaderGenerator.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.microprofile.client.mock;
+
+public final class HeaderGenerator {
+
+ private HeaderGenerator() {
+ }
+
+ public static String generateHeader(String headerName) {
+ return generateHeaderPrivate(headerName);
+ }
+
+ private static String generateHeaderPrivate(String headerName) {
+ return "valueFor" + headerName;
+ }
+}
diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeadersFactoryClient.java b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeadersFactoryClient.java
new file mode 100644
index 0000000..dc6d125
--- /dev/null
+++ b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeadersFactoryClient.java
@@ -0,0 +1,40 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.microprofile.client.mock;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.Path;
+
+import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam;
+import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
+
+@RegisterClientHeaders(MyClientHeadersFactory.class)
+@ClientHeaderParam(name = "IntfHeader1", value = "abc")
+public interface HeadersFactoryClient {
+
+ default String computeHeader(String headerName) {
+ return "HeadersOnMethodClientValueFor" + headerName;
+ }
+
+ @ClientHeaderParam(name = "MethodHeader1", value = "def")
+ @GET
+ @Path("/")
+ String get(@HeaderParam("HeaderParam1") String someValue);
+}
diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeadersOnInterfaceClient.java b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeadersOnInterfaceClient.java
new file mode 100644
index 0000000..dd9d5a6
--- /dev/null
+++ b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeadersOnInterfaceClient.java
@@ -0,0 +1,40 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.microprofile.client.mock;
+
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+
+import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam;
+
+@ClientHeaderParam(name = "IntfHeader1", value = "value1")
+@ClientHeaderParam(name = "IntfHeader2", value = {"value2", "value3"})
+@ClientHeaderParam(name = "IntfHeader3", value = "{computeHeader}")
+@ClientHeaderParam(name = "IntfHeader4",
+ value = "{org.apache.cxf.microprofile.client.mock.HeaderGenerator.generateHeader}")
+public interface HeadersOnInterfaceClient {
+
+ default String computeHeader(String headerName) {
+ return "HeadersOnInterfaceClientValueFor" + headerName;
+ }
+
+ @PUT
+ @Path("/")
+ String put(String someValue);
+}
diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeadersOnMethodClient.java b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeadersOnMethodClient.java
new file mode 100644
index 0000000..799620b
--- /dev/null
+++ b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/HeadersOnMethodClient.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.microprofile.client.mock;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.Path;
+
+import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam;
+
+
+public interface HeadersOnMethodClient {
+
+ default String computeHeader(String headerName) {
+ return "HeadersOnMethodClientValueFor" + headerName;
+ }
+
+ @ClientHeaderParam(name = "MethodHeader1", value = "valueA")
+ @ClientHeaderParam(name = "MethodHeader2", value = {"valueB", "valueC"})
+ @ClientHeaderParam(name = "MethodHeader3", value = "{computeHeader}")
+ @ClientHeaderParam(name = "MethodHeader4",
+ value = "{org.apache.cxf.microprofile.client.mock.HeaderGenerator.generateHeader}")
+ @DELETE
+ @Path("/")
+ String delete(String someValue);
+}
diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/MockConfigProviderResolver.java b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/MockConfigProviderResolver.java
index 05267a1..962d969 100644
--- a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/MockConfigProviderResolver.java
+++ b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/MockConfigProviderResolver.java
@@ -77,7 +77,6 @@ public class MockConfigProviderResolver extends ConfigProviderResolver {
}
public MockConfigProviderResolver(Map<String, String> configValues) {
- System.out.println("MockConfigProviderResolver ctor " + configValues);
this.configValues = configValues;
}
diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/MyClientHeadersFactory.java b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/MyClientHeadersFactory.java
new file mode 100644
index 0000000..bc039bc
--- /dev/null
+++ b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/MyClientHeadersFactory.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.microprofile.client.mock;
+
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;
+
+public class MyClientHeadersFactory implements ClientHeadersFactory {
+
+ private static MultivaluedMap<String, String> initialHeaders;
+
+ public static MultivaluedMap<String, String> getInitialHeaders() {
+ return initialHeaders;
+ }
+
+ public static void setInitialHeaders(MultivaluedMap<String, String> newHeaders) {
+ initialHeaders = newHeaders;
+ }
+
+ private static String reverse(String s) {
+ StringBuilder sb = new StringBuilder();
+ char[] ch = s.toCharArray();
+ //CHECKSTYLE:OFF
+ for (int i = ch.length-1; i >= 0; i--) {
+ sb.append(ch[i]);
+ }
+ //CHECKSTYLE:ON
+ return sb.toString();
+ }
+
+ @Override
+ public MultivaluedMap<String, String> update(MultivaluedMap<String, String> incomingHeaders,
+ MultivaluedMap<String, String> clientOutgoingHeaders) {
+
+ initialHeaders = new MultivaluedHashMap<>();
+ initialHeaders.putAll(clientOutgoingHeaders);
+ MultivaluedMap<String, String> updatedMap = new MultivaluedHashMap<>();
+ clientOutgoingHeaders.forEach((k, v) -> {
+ updatedMap.putSingle(k, reverse(v.get(0))); });
+ return updatedMap;
+ }
+}
diff --git a/systests/microprofile/client/async/pom.xml b/systests/microprofile/client/async/pom.xml
index 043b095..a85ad88 100644
--- a/systests/microprofile/client/async/pom.xml
+++ b/systests/microprofile/client/async/pom.xml
@@ -26,14 +26,14 @@
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.cxf.systests</groupId>
- <artifactId>cxf-microprofile-async</artifactId>
+ <artifactId>cxf-systests-microprofile-async</artifactId>
<name>Apache CXF MicroProfile Async Sys Tests</name>
<description>Apache CXF System Tests - MicroProfile Rest Client Async Tests</description>
<url>http://cxf.apache.org</url>
<properties>
<cxf.module.name>org.apache.cxf.systests.microprofile.async</cxf.module.name>
<cxf.geronimo.config.version>1.0</cxf.geronimo.config.version>
- <cxf.microprofile.rest.client.version>1.2-m2</cxf.microprofile.rest.client.version>
+ <cxf.microprofile.rest.client.version>1.2-RC1</cxf.microprofile.rest.client.version>
<cxf.wiremock.params>--port=8765</cxf.wiremock.params>
<cxf.weld.se.version>2.4.5.Final</cxf.weld.se.version>
<cxf.arquillian.weld.container.version>2.0.0.Final</cxf.arquillian.weld.container.version>
diff --git a/systests/microprofile/client/jaxrs/pom.xml b/systests/microprofile/client/jaxrs/pom.xml
new file mode 100644
index 0000000..c53a686
--- /dev/null
+++ b/systests/microprofile/client/jaxrs/pom.xml
@@ -0,0 +1,190 @@
+<?xml version="1.0"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>cxf-microprofile-tck</artifactId>
+ <groupId>org.apache.cxf.systests</groupId>
+ <version>3.3.0-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.apache.cxf.systests</groupId>
+ <artifactId>cxf-systests-microprofile-jaxrs</artifactId>
+ <name>Apache CXF MicroProfile JAX-RS integration Sys Tests</name>
+ <description>Apache CXF System Tests - verifying MicroProfile Rest Client integration with JAX-RS</description>
+ <url>http://cxf.apache.org</url>
+ <properties>
+ <cxf.module.name>org.apache.cxf.systests.microprofile.jaxrs</cxf.module.name>
+ <cxf.geronimo.config.version>1.0</cxf.geronimo.config.version>
+ <cxf.microprofile.rest.client.version>1.2-RC1</cxf.microprofile.rest.client.version>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.microprofile.rest.client</groupId>
+ <artifactId>microprofile-rest-client-api</artifactId>
+ <version>${cxf.microprofile.rest.client.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.config</groupId>
+ <artifactId>geronimo-config-impl</artifactId>
+ <version>${cxf.geronimo.config.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-mp-client</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-service-description-swagger</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-service-description-openapi-v3</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.webjars</groupId>
+ <artifactId>swagger-ui</artifactId>
+ <version>${cxf.swagger.ui.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ant</groupId>
+ <artifactId>ant</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-server</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-io</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-security</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-plus</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-webapp</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>apache-jsp</artifactId>
+ <version>${cxf.jetty.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.glassfish</groupId>
+ <artifactId>javax.el</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-commons</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-util</artifactId>
+ <version>${cxf.jetty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-transports-http</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-transports-http-jetty</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-features-logging</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-jdk14</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-transports-local</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-client</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-testutils</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-testutils</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ <classifier>keys</classifier>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-transports-http-hc</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.annotation</groupId>
+ <artifactId>jsr250-api</artifactId>
+ <version>1.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/JaxrsHeaderPropagationTest.java b/systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/JaxrsHeaderPropagationTest.java
new file mode 100644
index 0000000..943fa80
--- /dev/null
+++ b/systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/JaxrsHeaderPropagationTest.java
@@ -0,0 +1,118 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systest.microprofile.rest.client;
+
+import java.util.Collections;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
+import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class JaxrsHeaderPropagationTest extends AbstractBusClientServerTestBase {
+ public static final String PORT = allocatePort(JaxrsHeaderPropagationTest.class);
+
+ WebClient client;
+ @Ignore
+ public static class Server extends AbstractBusTestServerBase {
+ protected void run() {
+ final JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+ sf.setResourceClasses(JaxrsResource.class);
+ sf.setResourceProvider(JaxrsResource.class,
+ new SingletonResourceProvider(new JaxrsResource()));
+ sf.setAddress("http://localhost:" + PORT + "/");
+ sf.setPublishedEndpointUrl("/");
+ sf.create();
+ }
+
+ public static void main(String[] args) {
+ try {
+ Server s = new Server();
+ s.start();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ System.exit(-1);
+ } finally {
+ System.out.println("done!");
+ }
+ }
+ }
+
+ @BeforeClass
+ public static void startServers() throws Exception {
+
+ AbstractResourceInfo.clearAllMaps();
+ //keep out of process due to stack traces testing failures
+ assertTrue("server did not launch correctly", launchServer(Server.class, true));
+ createStaticBus();
+ System.out.println("Listening on port " + PORT);
+ }
+
+ @Before
+ public void setUp() {
+ final Response r = createWebClient("/jaxrs/check").get();
+ assertEquals(Status.OK.getStatusCode(), r.getStatus());
+ }
+
+ @Test
+ public void testHeadersArePropagated() throws Exception {
+ ConfigProviderResolver.setInstance(
+ new MockConfigProviderResolver(Collections.singletonMap(
+ "org.eclipse.microprofile.rest.client.propagateHeaders", "Header1,MultiHeader")));
+ Logger logger =
+ Logger.getLogger("org.eclipse.microprofile.rest.client.ext.DefaultClientHeadersFactoryImpl"); //NOPMD
+ logger.setLevel(Level.ALL);
+ ConsoleHandler h = new ConsoleHandler();
+ h.setLevel(Level.ALL);
+ logger.addHandler(new ConsoleHandler());
+ final Response r = createWebClient("/jaxrs/propagate")
+ .header("Header1", "Single")
+ .header("MultiHeader", "value1", "value2", "value3")
+ .get();
+ assertEquals(Status.OK.getStatusCode(), r.getStatus());
+ String propagatedHeaderContent = r.readEntity(String.class);
+ System.out.println("propagatedHeaderContent: " + propagatedHeaderContent);
+ assertTrue(propagatedHeaderContent.contains("Header1=Single"));
+ assertTrue(propagatedHeaderContent.contains("MultiHeader=value1,value2,value3"));
+ }
+
+ private static WebClient createWebClient(final String url) {
+ return WebClient
+ .create("http://localhost:" + PORT + url)
+ .accept(MediaType.TEXT_PLAIN);
+ }
+}
diff --git a/systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/JaxrsResource.java b/systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/JaxrsResource.java
new file mode 100644
index 0000000..455ef80
--- /dev/null
+++ b/systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/JaxrsResource.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systest.microprofile.rest.client;
+
+import java.net.URI;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+
+import org.eclipse.microprofile.rest.client.RestClientBuilder;
+
+@Path("/jaxrs")
+@Produces("text/plain")
+public class JaxrsResource {
+
+ @Path("/check")
+ @GET
+ public Response statusCheck() {
+ return Response.ok("up").build();
+ }
+
+ @Path("/propagate")
+ @GET
+ public String propagateHeadersToRestClient() {
+ RestClient client = RestClientBuilder.newBuilder()
+ .baseUri(URI.create("http://localhost:8080/ignored"))
+ .register(ReturnAllOutboundHeadersFilter.class)
+ .build(RestClient.class);
+ return client.getAllHeadersToBeSent();
+ }
+}
diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/MockConfigProviderResolver.java b/systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/MockConfigProviderResolver.java
similarity index 96%
copy from rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/MockConfigProviderResolver.java
copy to systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/MockConfigProviderResolver.java
index 05267a1..6a11f26 100644
--- a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/mock/MockConfigProviderResolver.java
+++ b/systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/MockConfigProviderResolver.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.cxf.microprofile.client.mock;
+package org.apache.cxf.systest.microprofile.rest.client;
import java.util.Arrays;
import java.util.HashMap;
@@ -77,7 +77,6 @@ public class MockConfigProviderResolver extends ConfigProviderResolver {
}
public MockConfigProviderResolver(Map<String, String> configValues) {
- System.out.println("MockConfigProviderResolver ctor " + configValues);
this.configValues = configValues;
}
diff --git a/systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/RestClient.java b/systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/RestClient.java
new file mode 100644
index 0000000..648aa66
--- /dev/null
+++ b/systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/RestClient.java
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systest.microprofile.rest.client;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+
+import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
+
+@Path("/remote")
+@RegisterClientHeaders
+public interface RestClient {
+
+ @GET
+ String getAllHeadersToBeSent();
+}
diff --git a/systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/ReturnAllOutboundHeadersFilter.java b/systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/ReturnAllOutboundHeadersFilter.java
new file mode 100644
index 0000000..2d034e2
--- /dev/null
+++ b/systests/microprofile/client/jaxrs/src/test/java/org/apache/cxf/systest/microprofile/rest/client/ReturnAllOutboundHeadersFilter.java
@@ -0,0 +1,40 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systest.microprofile.rest.client;
+
+import java.io.IOException;
+import java.util.stream.Collectors;
+
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.core.Response;
+
+public class ReturnAllOutboundHeadersFilter implements ClientRequestFilter {
+
+ @Override
+ public void filter(ClientRequestContext requestContext) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ requestContext.getStringHeaders().forEach((k, v) -> {
+ sb.append(k).append("=").append(v.stream().collect(Collectors.joining(",")))
+ .append(System.lineSeparator());
+ });
+ requestContext.abortWith(Response.ok(sb.toString()).build());
+ }
+
+}
diff --git a/systests/microprofile/client/weld/testng.xml b/systests/microprofile/client/weld/testng.xml
index f2cea4b..70f37b9 100644
--- a/systests/microprofile/client/weld/testng.xml
+++ b/systests/microprofile/client/weld/testng.xml
@@ -6,6 +6,7 @@
<package name="org.eclipse.microprofile.rest.client.tck" />
<package name="org.eclipse.microprofile.rest.client.tck.asynctests" />
<package name="org.eclipse.microprofile.rest.client.tck.cditests" />
+ <package name="org.eclipse.microprofile.rest.client.tck.timeout" />
</packages>
</test>
</suite>
diff --git a/systests/microprofile/pom.xml b/systests/microprofile/pom.xml
index f92b748..8889de5 100644
--- a/systests/microprofile/pom.xml
+++ b/systests/microprofile/pom.xml
@@ -33,7 +33,7 @@
<url>http://cxf.apache.org</url>
<properties>
<cxf.geronimo.config.version>1.0</cxf.geronimo.config.version>
- <cxf.microprofile.rest.client.version>1.2-m2</cxf.microprofile.rest.client.version>
+ <cxf.microprofile.rest.client.version>1.2-RC1</cxf.microprofile.rest.client.version>
<cxf.wiremock.params>--port=8765</cxf.wiremock.params>
<cxf.weld.se.version>2.4.5.Final</cxf.weld.se.version>
<cxf.arquillian.weld.container.version>2.0.0.Final</cxf.arquillian.weld.container.version>
@@ -133,6 +133,7 @@
</dependencyManagement>
<modules>
<module>client/async</module>
+ <module>client/jaxrs</module>
<module>client/weld</module>
</modules>
</project>