You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cxf.apache.org by GitBox <gi...@apache.org> on 2019/01/04 20:38:26 UTC

[GitHub] andymc12 closed pull request #482: [CXF-7926] Initial MP Rest Client 1.2 impl

andymc12 closed pull request #482: [CXF-7926] Initial MP Rest Client 1.2 impl
URL: https://github.com/apache/cxf/pull/482
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProperties.java b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProperties.java
new file mode 100644
index 00000000000..1c6d13be9d1
--- /dev/null
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProperties.java
@@ -0,0 +1,42 @@
+/**
+ * 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.jaxrs.client;
+
+import org.apache.cxf.common.util.SystemPropertyAction;
+
+public interface ClientProperties {
+    String HTTP_CONNECTION_TIMEOUT_PROP = "http.connection.timeout";
+    String HTTP_RECEIVE_TIMEOUT_PROP = "http.receive.timeout";
+    String HTTP_PROXY_SERVER_PROP = "http.proxy.server.uri";
+    String HTTP_PROXY_SERVER_PORT_PROP = "http.proxy.server.port";
+    String HTTP_AUTOREDIRECT_PROP = "http.autoredirect";
+    String HTTP_MAINTAIN_SESSION_PROP = "http.maintain.session";
+    String HTTP_RESPONSE_AUTOCLOSE_PROP = "http.response.stream.auto.close";
+    String THREAD_SAFE_CLIENT_PROP = "thread.safe.client";
+    String THREAD_SAFE_CLIENT_STATE_CLEANUP_PROP = "thread.safe.client.state.cleanup.period";
+    Boolean DEFAULT_THREAD_SAFETY_CLIENT_STATUS = 
+        Boolean.parseBoolean(SystemPropertyAction.getPropertyOrNull(THREAD_SAFE_CLIENT_PROP));;
+    Integer THREAD_SAFE_CLIENT_STATE_CLEANUP_PERIOD = 
+        getIntValue(SystemPropertyAction.getPropertyOrNull(THREAD_SAFE_CLIENT_STATE_CLEANUP_PROP));
+
+    static Integer getIntValue(Object o) {
+        return o instanceof Integer ? (Integer)o : o instanceof String ? Integer.valueOf(o.toString()) : null;
+    }
+}
diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientBuilderImpl.java b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientBuilderImpl.java
index f82e26a7705..0e989a037f3 100644
--- a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientBuilderImpl.java
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientBuilderImpl.java
@@ -36,6 +36,9 @@
 
 import org.apache.cxf.jaxrs.client.AbstractClient;
 
+import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_CONNECTION_TIMEOUT_PROP;
+import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_RECEIVE_TIMEOUT_PROP;
+
 public class ClientBuilderImpl extends ClientBuilder {
 
     private ClientConfigurableImpl<ClientBuilder> configImpl;
@@ -171,13 +174,13 @@ public ClientBuilder scheduledExecutorService(ScheduledExecutorService scheduled
     @Override
     public ClientBuilder connectTimeout(long timeout, TimeUnit timeUnit) {
         validateTimeout(timeout);
-        return property(ClientImpl.HTTP_CONNECTION_TIMEOUT_PROP, timeUnit.toMillis(timeout));
+        return property(HTTP_CONNECTION_TIMEOUT_PROP, timeUnit.toMillis(timeout));
     }
 
     @Override
     public ClientBuilder readTimeout(long timeout, TimeUnit timeUnit) {
         validateTimeout(timeout);
-        return property(ClientImpl.HTTP_RECEIVE_TIMEOUT_PROP, timeUnit.toMillis(timeout));
+        return property(HTTP_RECEIVE_TIMEOUT_PROP, timeUnit.toMillis(timeout));
     }
 
     private void validateTimeout(long timeout) {
diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientImpl.java b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientImpl.java
index 410b8c77e55..de4d2ca4a4f 100644
--- a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientImpl.java
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientImpl.java
@@ -40,7 +40,6 @@
 import javax.ws.rs.core.UriBuilder;
 
 import org.apache.cxf.common.util.ClassHelper;
-import org.apache.cxf.common.util.SystemPropertyAction;
 import org.apache.cxf.configuration.jsse.TLSClientParameters;
 import org.apache.cxf.jaxrs.client.AbstractClient;
 import org.apache.cxf.jaxrs.client.ClientConfiguration;
@@ -51,24 +50,19 @@
 import org.apache.cxf.message.Message;
 import org.apache.cxf.transport.https.SSLUtils;
 
+import static org.apache.cxf.jaxrs.client.ClientProperties.DEFAULT_THREAD_SAFETY_CLIENT_STATUS;
+import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_AUTOREDIRECT_PROP;
+import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_CONNECTION_TIMEOUT_PROP;
+import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_MAINTAIN_SESSION_PROP;
+import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_PROXY_SERVER_PORT_PROP;
+import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_PROXY_SERVER_PROP;
+import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_RECEIVE_TIMEOUT_PROP;
+import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_RESPONSE_AUTOCLOSE_PROP;
+import static org.apache.cxf.jaxrs.client.ClientProperties.THREAD_SAFE_CLIENT_PROP;
+import static org.apache.cxf.jaxrs.client.ClientProperties.THREAD_SAFE_CLIENT_STATE_CLEANUP_PERIOD;
+import static org.apache.cxf.jaxrs.client.ClientProperties.THREAD_SAFE_CLIENT_STATE_CLEANUP_PROP;
+
 public class ClientImpl implements Client {
-    static final String HTTP_CONNECTION_TIMEOUT_PROP = "http.connection.timeout";
-    static final String HTTP_RECEIVE_TIMEOUT_PROP = "http.receive.timeout";
-    private static final String HTTP_PROXY_SERVER_PROP = "http.proxy.server.uri";
-    private static final String HTTP_PROXY_SERVER_PORT_PROP = "http.proxy.server.port";
-    private static final String HTTP_AUTOREDIRECT_PROP = "http.autoredirect";
-    private static final String HTTP_MAINTAIN_SESSION_PROP = "http.maintain.session";
-    private static final String HTTP_RESPONSE_AUTOCLOSE_PROP = "http.response.stream.auto.close";
-    private static final String THREAD_SAFE_CLIENT_PROP = "thread.safe.client";
-    private static final String THREAD_SAFE_CLIENT_STATE_CLEANUP_PROP = "thread.safe.client.state.cleanup.period";
-    private static final Boolean DEFAULT_THREAD_SAFETY_CLIENT_STATUS;
-    private static final Integer THREAD_SAFE_CLIENT_STATE_CLEANUP_PERIOD;
-    static  {
-        DEFAULT_THREAD_SAFETY_CLIENT_STATUS =
-            Boolean.parseBoolean(SystemPropertyAction.getPropertyOrNull(THREAD_SAFE_CLIENT_PROP));
-        THREAD_SAFE_CLIENT_STATE_CLEANUP_PERIOD =
-            getIntValue(SystemPropertyAction.getPropertyOrNull(THREAD_SAFE_CLIENT_STATE_CLEANUP_PROP));
-    }
 
     private Configurable<Client> configImpl;
     private TLSConfiguration secConfig;
diff --git a/rt/rs/microprofile-client/pom.xml b/rt/rs/microprofile-client/pom.xml
index c072b6f9477..b122d56b5d6 100644
--- a/rt/rs/microprofile-client/pom.xml
+++ b/rt/rs/microprofile-client/pom.xml
@@ -42,6 +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>
     </properties>
     <dependencies>
         <dependency>
@@ -104,7 +105,7 @@
         <dependency>
             <groupId>org.eclipse.microprofile.rest.client</groupId>
             <artifactId>microprofile-rest-client-api</artifactId>
-            <version>1.1</version>
+            <version>${mp.rest.client.version}</version>
         </dependency>
         <dependency>
             <groupId>org.apache.cxf</groupId>
@@ -114,12 +115,12 @@
         <dependency>
             <groupId>javax.json</groupId>
             <artifactId>javax.json-api</artifactId>
-            <version>1.0</version>
+            <version>1.1</version>
         </dependency>
         <dependency>
             <groupId>org.eclipse.microprofile.rest.client</groupId>
             <artifactId>microprofile-rest-client-tck</artifactId>
-            <version>1.1</version>
+            <version>${mp.rest.client.version}</version>
             <exclusions>
                 <exclusion>
                     <groupId>org.testng</groupId>
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 ed7715233b4..5b1ff3d4fab 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
@@ -20,22 +20,59 @@
 
 import java.net.URI;
 import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collection;
 import java.util.Map;
 import java.util.Objects;
+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;
+
+import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_CONNECTION_TIMEOUT_PROP;
+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<>();
+
     private String baseUri;
     private ExecutorService executorService;
     private final MicroProfileClientConfigurableImpl<RestClientBuilder> configImpl =
             new MicroProfileClientConfigurableImpl<>(this);
 
+    private static Collection<RestClientListener> listeners() {
+        ClassLoader threadContextClassLoader;
+        if (System.getSecurityManager() == null) {
+            threadContextClassLoader = Thread.currentThread().getContextClassLoader();
+        } else {
+            threadContextClassLoader = AccessController.doPrivileged(
+                (PrivilegedAction<ClassLoader>)() -> Thread.currentThread().getContextClassLoader());
+        }
+        synchronized (REST_CLIENT_LISTENERS) {
+            return REST_CLIENT_LISTENERS.computeIfAbsent(threadContextClassLoader, key -> 
+                StreamSupport.stream(ServiceLoader.load(RestClientListener.class).spliterator(), false)
+                             .collect(Collectors.toList()));
+        }
+    }
+
     @Override
     public RestClientBuilder baseUrl(URL url) {
         this.baseUri = Objects.requireNonNull(url).toExternalForm();
@@ -57,6 +94,28 @@ public RestClientBuilder executorService(ExecutorService executor) {
         return this;
     }
 
+    @Override
+    public RestClientBuilder connectTimeout(long timeout, TimeUnit unit) {
+        if (null == unit) {
+            throw new IllegalArgumentException("time unit must not be null");
+        }
+        if (timeout < 0) {
+            throw new IllegalArgumentException("timeout must be non-negative");
+        }
+        return property(HTTP_CONNECTION_TIMEOUT_PROP, unit.toMillis(timeout));
+    }
+
+    @Override
+    public RestClientBuilder readTimeout(long timeout, TimeUnit unit) {
+        if (null == unit) {
+            throw new IllegalArgumentException("time unit must not be null");
+        }
+        if (timeout < 0) {
+            throw new IllegalArgumentException("timeout must be non-negative");
+        }
+        return property(HTTP_RECEIVE_TIMEOUT_PROP, unit.toMillis(timeout));
+    }
+
     @Override
     public <T> T build(Class<T> aClass) {
         if (baseUri == null) {
@@ -76,8 +135,29 @@ public RestClientBuilder executorService(ExecutorService executor) {
                 }
             }
         }
+
+        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,
-                baseUri, aClass, executorService);
+                                                                               baseUri, aClass, executorService);
         return bean.create(aClass);
     }
 
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 f4c7633d409..1af5bb65caa 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
@@ -26,4 +26,7 @@ VALIDATION_EXTRA_PATH_PARAMS=The client interface, {0} has one or more extra pat
 VALIDATION_ASYNC_METHOD_RETURNS_UNEXPECTED_TYPE=The client interface, {0} has an asynchronous method, {1} that returns an unexpected type, {2}. If the method has an InvocationCallback parameter, then it must be return void.
 
 ASYNC_INTERCEPTOR_EXCEPTION_PREPARE_CONTEXT=The AsyncInvocationInterceptor, {0} has thrown an exception during the invocation of the prepareContext method. This interceptor's applyContext method will not be invoked.
-ASYNC_INTERCEPTOR_EXCEPTION_APPLY_CONTEXT=The AsyncInvocationInterceptor, {0} has thrown an exception during the invocation of the applyContext method.
\ No newline at end of file
+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
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientConfigurableImpl.java b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientConfigurableImpl.java
index 4cf27631d0e..1a64e3b8378 100644
--- a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientConfigurableImpl.java
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientConfigurableImpl.java
@@ -28,6 +28,7 @@
 import javax.ws.rs.ext.ReaderInterceptor;
 import javax.ws.rs.ext.WriterInterceptor;
 
+import org.apache.cxf.common.util.PropertyUtils;
 import org.apache.cxf.jaxrs.impl.ConfigurableImpl;
 import org.apache.cxf.jaxrs.impl.ConfigurationImpl;
 import org.apache.cxf.microprofile.client.config.ConfigFacade;
@@ -52,8 +53,8 @@ public MicroProfileClientConfigurableImpl(C configurable, Configuration config)
 
     boolean isDefaultExceptionMapperDisabled() {
         Object prop = getConfiguration().getProperty(CONFIG_KEY_DISABLE_MAPPER);
-        if (prop instanceof Boolean) {
-            return (Boolean)prop;
+        if (prop != null) {
+            return PropertyUtils.isTrue(prop);
         }
         return ConfigFacade.getOptionalValue(CONFIG_KEY_DISABLE_MAPPER,
                                              Boolean.class).orElse(false);
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 479cabb8a19..6d59031adc9 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
@@ -40,6 +40,7 @@
 import org.apache.cxf.jaxrs.model.FilterProviderInfo;
 import org.apache.cxf.jaxrs.model.ProviderInfo;
 import org.apache.cxf.jaxrs.provider.jsrjsonp.JsrJsonpProvider;
+import org.apache.cxf.microprofile.client.cdi.CDIInterceptorWrapper;
 import org.apache.cxf.microprofile.client.proxy.MicroProfileClientProxyImpl;
 import org.eclipse.microprofile.rest.client.RestClientBuilder;
 
@@ -97,12 +98,13 @@ protected void initClient(AbstractClient client, Endpoint ep, boolean addHeaders
     @Override
     protected ClientProxyImpl createClientProxy(ClassResourceInfo cri, boolean isRoot,
                                                 ClientState actualState, Object[] varValues) {
+        CDIInterceptorWrapper interceptorWrapper = CDIInterceptorWrapper.createWrapper(getServiceClass());
         if (actualState == null) {
             return new MicroProfileClientProxyImpl(URI.create(getAddress()), proxyLoader, cri, isRoot,
-                    inheritHeaders, executorService, configuration, varValues);
+                    inheritHeaders, executorService, configuration, interceptorWrapper, varValues);
         } else {
             return new MicroProfileClientProxyImpl(actualState, proxyLoader, cri, isRoot,
-                    inheritHeaders, executorService, configuration, varValues);
+                    inheritHeaders, executorService, configuration, interceptorWrapper, varValues);
         }
     }
 
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/CDIInterceptorWrapper.java b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/CDIInterceptorWrapper.java
new file mode 100644
index 00000000000..298317b5dd2
--- /dev/null
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/CDIInterceptorWrapper.java
@@ -0,0 +1,69 @@
+/**
+ * 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.cdi;
+
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.concurrent.Callable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.cxf.common.logging.LogUtils;
+
+
+public interface CDIInterceptorWrapper {
+    Logger LOG = LogUtils.getL7dLogger(CDIInterceptorWrapper.class);
+
+    class BasicCDIInterceptorWrapper implements CDIInterceptorWrapper {
+        BasicCDIInterceptorWrapper() {
+        }
+
+        @Override
+        public Object invoke(Object restClient, Method m, Object[] params, Callable callable)  throws Exception {
+            return callable.call();
+        }
+    }
+
+    static CDIInterceptorWrapper createWrapper(Class<?> restClient) {
+        try {
+            return AccessController.doPrivileged((PrivilegedExceptionAction<CDIInterceptorWrapper>) () -> {
+                Class<?> cdiClass = Class.forName("javax.enterprise.inject.spi.CDI", false,
+                                                  restClient.getClassLoader());
+                Method currentMethod = cdiClass.getMethod("current");
+                Object cdiCurrent = currentMethod.invoke(null);
+
+                Method getBeanMgrMethod = cdiClass.getMethod("getBeanManager");
+
+                return new CDIInterceptorWrapperImpl(restClient, getBeanMgrMethod.invoke(cdiCurrent));
+            });
+        } catch (PrivilegedActionException pae) {
+            // expected for environments where CDI is not supported
+            if (LOG.isLoggable(Level.FINEST)) {
+                LOG.log(Level.FINEST, "Unable to load CDI SPI classes, assuming no CDI is available", pae);
+            }
+            return new BasicCDIInterceptorWrapper(); 
+        }
+
+    }
+
+    Object invoke(Object restClient, Method m, Object[] params, Callable<Object> callable) throws Exception;
+}
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/CDIInterceptorWrapperImpl.java b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/CDIInterceptorWrapperImpl.java
new file mode 100644
index 00000000000..3e68de4029a
--- /dev/null
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/CDIInterceptorWrapperImpl.java
@@ -0,0 +1,138 @@
+/**
+ * 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.cdi;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.AnnotatedMethod;
+import javax.enterprise.inject.spi.AnnotatedType;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.InterceptionType;
+import javax.enterprise.inject.spi.Interceptor;
+
+import org.apache.cxf.common.logging.LogUtils;
+
+
+class CDIInterceptorWrapperImpl implements CDIInterceptorWrapper {
+    private static final Logger LOG = LogUtils.getL7dLogger(CDIInterceptorWrapperImpl.class);
+
+    private final CreationalContext<?> creationalContext;
+    private final Map<Method, List<InterceptorInvoker>> interceptorInvokers;
+
+    CDIInterceptorWrapperImpl(Class<?> restClient, Object beanManagerObject) {
+        BeanManager beanManager = (BeanManager) beanManagerObject;
+        creationalContext = beanManager != null ? beanManager.createCreationalContext(null) : null;
+        interceptorInvokers = initInterceptorInvokers(beanManager, creationalContext, restClient);
+    }
+
+    private static Map<Method, List<InterceptorInvoker>> initInterceptorInvokers(BeanManager beanManager,
+                                                                                 CreationalContext<?> creationalContext,
+                                                                                 Class<?> restClient) {
+        Map<Method, List<InterceptorInvoker>> invokers = new HashMap<>();
+        // Interceptor as a key in a map is not entirely correct (custom interceptors) but should work in most cases
+        Map<Interceptor<?>, Object> interceptorInstances = new HashMap<>();
+        
+        AnnotatedType<?> restClientType = beanManager.createAnnotatedType(restClient);
+
+        List<Annotation> classBindings = getBindings(restClientType.getAnnotations(), beanManager);
+
+        for (AnnotatedMethod<?> method : restClientType.getMethods()) {
+            Method javaMethod = method.getJavaMember();
+            if (javaMethod.isDefault() || method.isStatic()) {
+                continue;
+            }
+            List<Annotation> methodBindings = getBindings(method.getAnnotations(), beanManager);
+
+            if (!classBindings.isEmpty() || !methodBindings.isEmpty()) {
+                Annotation[] interceptorBindings = merge(methodBindings, classBindings);
+
+                List<Interceptor<?>> interceptors =
+                    new ArrayList<>(beanManager.resolveInterceptors(InterceptionType.AROUND_INVOKE, 
+                                                                    interceptorBindings));
+                if (LOG.isLoggable(Level.FINEST)) {
+                    LOG.finest("Resolved interceptors from beanManager, " + beanManager + ":" + interceptors);
+                }
+
+                if (!interceptors.isEmpty()) {
+                    List<InterceptorInvoker> chain = new ArrayList<>();
+                    for (Interceptor<?> interceptor : interceptors) {
+                        chain.add(
+                            new InterceptorInvoker(interceptor, 
+                                                   interceptorInstances.computeIfAbsent(interceptor, 
+                                                       i -> beanManager.getReference(i, 
+                                                                                     i.getBeanClass(), 
+                                                                                     creationalContext))));
+                    }
+                    invokers.put(javaMethod, chain);
+                }
+            }
+        }
+        return invokers.isEmpty() ? Collections.emptyMap() : invokers;
+    }
+
+    private static Annotation[] merge(List<Annotation> methodBindings, List<Annotation> classBindings) {
+        Set<Class<? extends Annotation>> types = methodBindings.stream()
+                                                               .map(a -> a.annotationType())
+                                                               .collect(Collectors.toSet());
+        List<Annotation> merged = new ArrayList<>(methodBindings);
+        for (Annotation annotation : classBindings) {
+            if (!types.contains(annotation.annotationType())) {
+                merged.add(annotation);
+            }
+        }
+        return merged.toArray(new Annotation[] {});
+    }
+
+    private static List<Annotation> getBindings(Set<Annotation> annotations, BeanManager beanManager) {
+        if (annotations == null || annotations.size() == 0) {
+            return Collections.emptyList();
+        }
+        List<Annotation> bindings = new ArrayList<>();
+        for (Annotation annotation : annotations) {
+            if (beanManager.isInterceptorBinding(annotation.annotationType())) {
+                bindings.add(annotation);
+            }
+        }
+        return bindings;
+    }
+
+    @Override
+    public Object invoke(Object restClient, Method method, Object[] params, Callable<Object> callable) 
+        throws Exception {
+
+        List<InterceptorInvoker> invokers = interceptorInvokers.get(method);
+        if (invokers == null || invokers.isEmpty()) {
+            return callable.call();
+        }
+        return new MPRestClientInvocationContextImpl(restClient, method, params, invokers, callable).proceed();
+    }
+}
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/InterceptorInvoker.java b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/InterceptorInvoker.java
new file mode 100644
index 00000000000..6ef755c23c2
--- /dev/null
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/InterceptorInvoker.java
@@ -0,0 +1,43 @@
+/**
+ * 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.cdi;
+
+import javax.enterprise.inject.spi.InterceptionType;
+import javax.enterprise.inject.spi.Interceptor;
+import javax.interceptor.InvocationContext;
+
+public class InterceptorInvoker {
+
+    @SuppressWarnings("rawtypes")
+    private final Interceptor interceptor;
+
+    private final Object interceptorInstance;
+
+    public InterceptorInvoker(Interceptor<?> interceptor, Object interceptorInstance) {
+        this.interceptor = interceptor;
+        this.interceptorInstance = interceptorInstance;
+    }
+
+    @SuppressWarnings("unchecked")
+    Object invoke(InvocationContext ctx) throws Exception {
+        return interceptor.intercept(InterceptionType.AROUND_INVOKE, interceptorInstance, ctx);
+    }
+
+}
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/MPRestClientInvocationContextImpl.java b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/MPRestClientInvocationContextImpl.java
new file mode 100644
index 00000000000..1c3a67244a1
--- /dev/null
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/cdi/MPRestClientInvocationContextImpl.java
@@ -0,0 +1,129 @@
+/**
+ * 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.cdi;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import javax.interceptor.InvocationContext;
+
+
+class MPRestClientInvocationContextImpl implements InvocationContext {
+
+    private final Object target;
+
+    private final Method method;
+
+    private Object[] args;
+
+    private int index;
+
+    private final List<InterceptorInvoker> interceptorInvokers;
+
+    private final Map<String, Object> contextData = new HashMap<>();
+
+    private final Callable<Object> callable;
+    /**
+     * @param target
+     * @param method
+     * @param args
+     * @param interceptorInvokers
+     */
+    MPRestClientInvocationContextImpl(Object target, Method method, Object[] args, 
+                                      List<InterceptorInvoker> interceptorInvokers, 
+                                      Callable<Object> callable) {
+        this.target = target;
+        this.method = method;
+        this.args = args == null ? new Object[] {} : args;
+        this.interceptorInvokers = interceptorInvokers;
+        this.callable = callable;
+    }
+
+    boolean hasNextInterceptor() {
+        return index < interceptorInvokers.size();
+    }
+
+    protected Object invokeNextInterceptor() throws Exception {
+        int oldIndex = index;
+        try {
+            // Note that some FaultTolerance interceptors can cause
+            // some interesting behaviors if they are invoked before
+            // other interceptors. The CDIInterceptorWrapperImpl
+            // intentionally orders the FT interceptor last to
+            // avoid these side effects.
+            return interceptorInvokers.get(index++).invoke(this);
+        } finally {
+            index = oldIndex;
+        }
+    }
+
+    protected Object interceptorChainCompleted() throws Exception {
+        return callable.call();
+    }
+
+    @Override
+    public Object proceed() throws Exception {
+        if (hasNextInterceptor()) {
+            return invokeNextInterceptor();
+        } else {
+            return interceptorChainCompleted();
+        }
+    }
+
+    @Override
+    public Object getTarget() {
+        return target;
+    }
+
+    @Override
+    public Method getMethod() {
+        return method;
+    }
+
+    @Override
+    public Constructor<?> getConstructor() {
+        return null;
+    }
+
+    @Override
+    public Object[] getParameters() throws IllegalStateException {
+        return args;
+    }
+
+    @Override
+    public void setParameters(Object[] params) throws IllegalStateException, IllegalArgumentException {
+        this.args = params;
+    }
+
+    @Override
+    public Map<String, Object> getContextData() {
+        return contextData;
+    }
+
+    @Override
+    public Object getTimer() {
+        return null;
+    }
+
+}
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 04a8e70cbd0..89d2b7ddc9a 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
@@ -28,7 +28,6 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -48,6 +47,7 @@
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.microprofile.client.CxfTypeSafeClientBuilder;
 import org.apache.cxf.microprofile.client.config.ConfigFacade;
+import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
 import org.eclipse.microprofile.rest.client.inject.RestClient;
 
 public class RestClientBean implements Bean<Object>, PassivationCapable {
@@ -138,21 +138,26 @@ public boolean isAlternative() {
 
     private String getBaseUri() {
         String interfaceName = clientInterface.getName();
-        String property = String.format(REST_URI_FORMAT, interfaceName);
-        String baseURI = null;
-        try {
-            baseURI = ConfigFacade.getValue(property, String.class);
-        } catch (NoSuchElementException ex) {
-            // no-op - will revert to baseURL config value (as opposed to baseURI)
-        }
+        String baseURI = ConfigFacade
+            .getOptionalValue(String.format(REST_URI_FORMAT, interfaceName), String.class)
+            .orElseGet(() -> ConfigFacade.getOptionalValue(String.format(REST_URL_FORMAT, interfaceName),
+                                                           String.class).orElse(null));
+
         if (baseURI == null) {
-            // revert to baseUrl
-            property = String.format(REST_URL_FORMAT, interfaceName);
-            baseURI = ConfigFacade.getValue(property, String.class);
-            if (baseURI == null) {
-                throw new IllegalStateException("Unable to determine base URI from configuration");
+            // last, if baseUrl/Uri is not specified via MP Config, check the @RegisterRestClient annotation
+            RegisterRestClient anno = clientInterface.getAnnotation(RegisterRestClient.class);
+            if (anno != null) {
+                String annoUri = anno.baseUri();
+                if (annoUri != null && !"".equals(anno.baseUri())) {
+                    baseURI = annoUri;
+                }
             }
         }
+
+        if (baseURI == null) {
+            throw new IllegalStateException("Unable to determine base URI from configuration for "
+                                            + interfaceName);
+        }
         return baseURI;
     }
 
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/config/ConfigFacade.java b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/config/ConfigFacade.java
index e543d7c0cfb..9bb688e6ce1 100644
--- a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/config/ConfigFacade.java
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/config/ConfigFacade.java
@@ -20,6 +20,7 @@
 package org.apache.cxf.microprofile.client.config;
 
 import java.util.Optional;
+import java.util.OptionalLong;
 
 import org.eclipse.microprofile.config.Config;
 import org.eclipse.microprofile.config.ConfigProvider;
@@ -28,7 +29,7 @@
 
     private ConfigFacade() {
     }
-    
+
     private static Optional<Config> config() {
         Config c;
         try {
@@ -39,15 +40,22 @@ private ConfigFacade() {
         }
         return Optional.ofNullable(c);
     }
-    
+
     public static <T> Optional<T> getOptionalValue(String propertyName, Class<T> clazz) {
         Optional<Config> c = config();
         return c.isPresent() ? c.get().getOptionalValue(propertyName, clazz) : Optional.empty();
     }
-    
+
     public static <T> T getValue(String propertyName, Class<T> clazz) {
         Optional<Config> c = config();
         return c.isPresent() ? c.get().getValue(propertyName, clazz) : null;
     }
-    
+
+    public static OptionalLong getOptionalLong(String propName) {
+        Optional<Config> c = config();
+        Optional<Long> opt =
+            c.isPresent() ? c.get().getOptionalValue(propName, Long.class) : Optional.empty();
+        return opt.isPresent() ? OptionalLong.of(opt.get()) : OptionalLong.empty();
+
+    }
 }
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/proxy/MPAsyncInvocationInterceptorImpl.java b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/proxy/MPAsyncInvocationInterceptorImpl.java
index 13ecf18b346..5871c8a6fb4 100644
--- a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/proxy/MPAsyncInvocationInterceptorImpl.java
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/proxy/MPAsyncInvocationInterceptorImpl.java
@@ -41,8 +41,18 @@
     private final List<AsyncInvocationInterceptor> interceptors = new ArrayList<>();
 
     
-    MPAsyncInvocationInterceptorImpl() {
+    MPAsyncInvocationInterceptorImpl(Message message) {
         super(Phase.POST_MARSHAL);
+
+        MicroProfileClientProviderFactory factory = MicroProfileClientProviderFactory.getInstance(message);
+        List<ProviderInfo<Object>> aiiProviderList = 
+            factory.getAsyncInvocationInterceptorFactories();
+
+        for (ProviderInfo<Object> providerInfo: aiiProviderList) {
+            AsyncInvocationInterceptor aiInterceptor = 
+                ((AsyncInvocationInterceptorFactory) providerInfo.getProvider()).newInterceptor();
+            interceptors.add(0, aiInterceptor); // sort in reverse order
+        }
     }
 
     List<AsyncInvocationInterceptor> getInterceptors() {
@@ -52,23 +62,14 @@
     /** {@inheritDoc}*/
     @Override
     public void handleMessage(Message message) throws Fault {
-        MicroProfileClientProviderFactory factory = MicroProfileClientProviderFactory.getInstance(message);
-        List<ProviderInfo<Object>> aiiProviderList = 
-            factory.getAsyncInvocationInterceptorFactories();
-
-        for (ProviderInfo<Object> providerInfo: aiiProviderList) {
-            AsyncInvocationInterceptor aiInterceptor = 
-                ((AsyncInvocationInterceptorFactory) providerInfo.getProvider()).newInterceptor();
+        for (int i = interceptors.size() - 1; i >= 0; i--) {
             try {
-                aiInterceptor.prepareContext();
-                interceptors.add(0, aiInterceptor); // sort in reverse order
+                interceptors.get(i).prepareContext();
             } catch (Throwable t) {
                 LOG.log(Level.WARNING, "ASYNC_INTERCEPTOR_EXCEPTION_PREPARE_CONTEXT", 
-                        new Object[]{aiInterceptor.getClass().getName(), t});
+                        new Object[]{interceptors.get(i).getClass().getName(), t});
             }
         }
-        
-        //message.getInterceptorChain().add(new MPAsyncInvocationInterceptorPostAsyncImpl(interceptors));
     }
 
 }
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/proxy/MPAsyncInvocationInterceptorRemoveContextImpl.java b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/proxy/MPAsyncInvocationInterceptorRemoveContextImpl.java
new file mode 100644
index 00000000000..8813ee4e74f
--- /dev/null
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/proxy/MPAsyncInvocationInterceptorRemoveContextImpl.java
@@ -0,0 +1,58 @@
+/**
+ * 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.proxy;
+
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.AbstractPhaseInterceptor;
+import org.apache.cxf.phase.Phase;
+import org.eclipse.microprofile.rest.client.ext.AsyncInvocationInterceptor;
+
+/**
+ * 
+ */
+public class MPAsyncInvocationInterceptorRemoveContextImpl extends AbstractPhaseInterceptor<Message> {
+    private static final Logger LOG = LogUtils.getL7dLogger(MPAsyncInvocationInterceptorRemoveContextImpl.class);
+
+    private List<AsyncInvocationInterceptor> interceptors;
+
+    public MPAsyncInvocationInterceptorRemoveContextImpl(List<AsyncInvocationInterceptor> interceptors) {
+        super(Phase.POST_INVOKE);
+        this.interceptors = interceptors;
+    }
+
+    /** {@inheritDoc}*/
+    @Override
+    public void handleMessage(Message message) throws Fault {
+        for (AsyncInvocationInterceptor interceptor : interceptors) {
+            try {
+                interceptor.removeContext();
+            } catch (Throwable t) {
+                LOG.log(Level.WARNING, "ASYNC_INTERCEPTOR_EXCEPTION_REMOVE_CONTEXT", 
+                        new Object[]{interceptor.getClass().getName(), t});
+            }
+        }
+    }
+}
\ No newline at end of file
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 1296cdc69af..ea7db941bda 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
@@ -24,14 +24,19 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Callable;
 import java.util.concurrent.CompletionStage;
 import java.util.concurrent.ExecutorService;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 import javax.ws.rs.client.InvocationCallback;
 import javax.ws.rs.core.Configuration;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.interceptor.Interceptor;
 import org.apache.cxf.jaxrs.client.ClientProxyImpl;
 import org.apache.cxf.jaxrs.client.ClientState;
 import org.apache.cxf.jaxrs.client.JaxrsClientCallback;
@@ -43,9 +48,14 @@
 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.ext.ResponseExceptionMapper;
 
+import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_CONNECTION_TIMEOUT_PROP;
+import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_RECEIVE_TIMEOUT_PROP;
+
 public class MicroProfileClientProxyImpl extends ClientProxyImpl {
+    private static final Logger LOG = LogUtils.getL7dLogger(MicroProfileClientProxyImpl.class);
 
     private static final InvocationCallback<Object> NO_OP_CALLBACK = new InvocationCallback<Object>() {
         @Override
@@ -55,23 +65,27 @@ public void failed(Throwable t) { }
         public void completed(Object o) { }
     };
 
-    private final MPAsyncInvocationInterceptorImpl aiiImpl = new MPAsyncInvocationInterceptorImpl();
-
+    private final CDIInterceptorWrapper interceptorWrapper;
+    
     //CHECKSTYLE:OFF
     public MicroProfileClientProxyImpl(URI baseURI, ClassLoader loader, ClassResourceInfo cri,
                                        boolean isRoot, boolean inheritHeaders, ExecutorService executorService,
-                                       Configuration configuration, Object... varValues) {
+                                       Configuration configuration, CDIInterceptorWrapper interceptorWrapper, 
+                                       Object... varValues) {
         super(new LocalClientState(baseURI), loader, cri, isRoot, inheritHeaders, varValues);
         cfg.getRequestContext().put(EXECUTOR_SERVICE_PROPERTY, executorService);
         cfg.getRequestContext().putAll(configuration.getProperties());
+        this.interceptorWrapper = interceptorWrapper;
     }
 
     public MicroProfileClientProxyImpl(ClientState initialState, ClassLoader loader, ClassResourceInfo cri,
                                        boolean isRoot, boolean inheritHeaders, ExecutorService executorService,
-                                       Configuration configuration, Object... varValues) {
+                                       Configuration configuration, CDIInterceptorWrapper interceptorWrapper,
+                                       Object... varValues) {
         super(initialState, loader, cri, isRoot, inheritHeaders, varValues);
         cfg.getRequestContext().put(EXECUTOR_SERVICE_PROPERTY, executorService);
         cfg.getRequestContext().putAll(configuration.getProperties());
+        this.interceptorWrapper = interceptorWrapper;
     }
     //CHECKSTYLE:ON
 
@@ -99,15 +113,25 @@ protected boolean checkAsyncReturnType(OperationResourceInfo ori,
     @Override
     protected Object doInvokeAsync(OperationResourceInfo ori, Message outMessage,
                                    InvocationCallback<Object> asyncCallback) {
+        MPAsyncInvocationInterceptorImpl aiiImpl = new MPAsyncInvocationInterceptorImpl(outMessage);
         outMessage.getInterceptorChain().add(aiiImpl);
-        cfg.getInInterceptors().add(new MPAsyncInvocationInterceptorPostAsyncImpl(aiiImpl.getInterceptors()));
+        List<Interceptor<? extends Message>>inboundChain = cfg.getInInterceptors();
+        inboundChain.add(new MPAsyncInvocationInterceptorPostAsyncImpl(aiiImpl.getInterceptors()));
+        inboundChain.add(new MPAsyncInvocationInterceptorRemoveContextImpl(aiiImpl.getInterceptors()));
 
+        setTimeouts(cfg.getRequestContext());
         super.doInvokeAsync(ori, outMessage, asyncCallback);
 
         JaxrsClientCallback<?> cb = outMessage.getExchange().get(JaxrsClientCallback.class);
         return cb.createFuture();
     }
 
+    @Override
+    protected void doRunInterceptorChain(Message message) {
+        setTimeouts(cfg.getRequestContext());
+        super.doRunInterceptorChain(message);
+    }
+
     @Override
     protected JaxrsClientCallback<?> newJaxrsClientCallback(InvocationCallback<Object> asyncCallback,
                                                             Class<?> responseClass,
@@ -171,4 +195,80 @@ protected Message createMessage(Object body,
         filterProps.put("org.eclipse.microprofile.rest.client.invokedMethod", m);
         return msg;
     }
+
+    protected void setTimeouts(Map<String, Object> props) {
+        try {
+            Long connectTimeout = getIntFromProps(props, HTTP_CONNECTION_TIMEOUT_PROP);
+            Long readTimeout = getIntFromProps(props, HTTP_RECEIVE_TIMEOUT_PROP);
+            if (connectTimeout > -1) {
+                cfg.getHttpConduit().getClient().setConnectionTimeout(connectTimeout);
+            }
+            if (readTimeout > -1) {
+                cfg.getHttpConduit().getClient().setReceiveTimeout(readTimeout);
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    private Long getIntFromProps(Map<String, Object> props, String key) {
+        Object o = props.get(key);
+        if (o == null) {
+            return -1L; // not declared
+        }
+        Long l;
+        if (o instanceof Long) {
+            l = (Long) o;
+        } else if (o instanceof String) {
+            try {
+                l = Long.parseLong((String)o);
+            } catch (NumberFormatException ex) {
+                LOG.log(Level.WARNING, "INVALID_TIMEOUT_PROPERTY", new Object[]{key, o});
+                return -1L; // 
+            }
+        } else {
+            LOG.log(Level.WARNING, "INVALID_TIMEOUT_PROPERTY", new Object[]{key, o});
+            return -1L;
+        }
+        if (l < 0) {
+            LOG.log(Level.WARNING, "INVALID_TIMEOUT_PROPERTY", new Object[]{key, o});
+            return -1L;
+        }
+        return l;
+    }
+
+    @Override
+    public Object invoke(Object o, Method m, Object[] params) throws Throwable {
+        return interceptorWrapper.invoke(o, m, params, new Invoker(o, m, params, this));
+    }
+
+    private Object invokeActual(Object o, Method m, Object[] params) throws Throwable {
+        return super.invoke(o, m, params);
+    }
+
+    private static class Invoker implements Callable<Object> {
+        private final Object targetObject;
+        private final Method method;
+        private final Object[] params;
+        private final MicroProfileClientProxyImpl proxy;
+
+        Invoker(Object o, Method m, Object[] params, MicroProfileClientProxyImpl proxy) {
+            this.targetObject = o;
+            this.method = m;
+            this.params = params;
+            this.proxy = proxy;
+        }
+
+        @Override
+        public Object call() throws Exception {
+            try {
+                return proxy.invokeActual(targetObject, method, params);
+            } catch (Throwable t) {
+                if (t instanceof Exception) {
+                    throw (Exception) t;
+                }
+                throw new RuntimeException(t);
+            }
+        }
+    }
 }
diff --git a/systests/microprofile/client/async/pom.xml b/systests/microprofile/client/async/pom.xml
index 80db328436c..043b095a7aa 100644
--- a/systests/microprofile/client/async/pom.xml
+++ b/systests/microprofile/client/async/pom.xml
@@ -33,7 +33,7 @@
     <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.1</cxf.microprofile.rest.client.version>
+        <cxf.microprofile.rest.client.version>1.2-m2</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/async/src/test/java/org/apache/cxf/systest/microprofile/rest/client/mock/AsyncInvocationInterceptorFactoryTestImpl.java b/systests/microprofile/client/async/src/test/java/org/apache/cxf/systest/microprofile/rest/client/mock/AsyncInvocationInterceptorFactoryTestImpl.java
index 242b161972c..75b863498c4 100644
--- a/systests/microprofile/client/async/src/test/java/org/apache/cxf/systest/microprofile/rest/client/mock/AsyncInvocationInterceptorFactoryTestImpl.java
+++ b/systests/microprofile/client/async/src/test/java/org/apache/cxf/systest/microprofile/rest/client/mock/AsyncInvocationInterceptorFactoryTestImpl.java
@@ -51,6 +51,14 @@ public void applyContext() {
             list.add(Thread.currentThread().getName());
             list.add(AsyncInvocationInterceptorFactoryTestImpl.class.getSimpleName());
         }
+
+        /** {@inheritDoc}*/
+        @Override
+        public void removeContext() {
+            List<String> list = INBOUND.get();
+            list.add("REMOVE-" + Thread.currentThread().getName());
+            list.add("REMOVE-" + AsyncInvocationInterceptorFactoryTestImpl.class.getSimpleName());
+        }
     }
 
     /** {@inheritDoc}*/
diff --git a/systests/microprofile/client/async/src/test/java/org/apache/cxf/systest/microprofile/rest/client/mock/AsyncInvocationInterceptorFactoryTestImpl2.java b/systests/microprofile/client/async/src/test/java/org/apache/cxf/systest/microprofile/rest/client/mock/AsyncInvocationInterceptorFactoryTestImpl2.java
index e4ceb6e6704..2576cb4c6b0 100644
--- a/systests/microprofile/client/async/src/test/java/org/apache/cxf/systest/microprofile/rest/client/mock/AsyncInvocationInterceptorFactoryTestImpl2.java
+++ b/systests/microprofile/client/async/src/test/java/org/apache/cxf/systest/microprofile/rest/client/mock/AsyncInvocationInterceptorFactoryTestImpl2.java
@@ -46,6 +46,14 @@ public void applyContext() {
             list.add(Thread.currentThread().getName());
             list.add(AsyncInvocationInterceptorFactoryTestImpl2.class.getSimpleName());
         }
+
+        /** {@inheritDoc}*/
+        @Override
+        public void removeContext() {
+            List<String> list = AsyncInvocationInterceptorFactoryTestImpl.INBOUND.get();
+            list.add("REMOVE-" + Thread.currentThread().getName());
+            list.add("REMOVE-" + AsyncInvocationInterceptorFactoryTestImpl.class.getSimpleName());
+        }
     }
 
     /** {@inheritDoc}*/
diff --git a/systests/microprofile/client/weld/testng.xml b/systests/microprofile/client/weld/testng.xml
index cae845056c4..f2cea4b5514 100644
--- a/systests/microprofile/client/weld/testng.xml
+++ b/systests/microprofile/client/weld/testng.xml
@@ -1,27 +1,11 @@
 <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
  
-<suite name="MPRestClientTCK1.1">
-    <test name="All tests except Executor Service Test">
+<suite name="MPRestClientTCK1.2">
+    <test name="All TCK Tests">
         <packages>
             <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" />
         </packages>
-        <classes>
-            <class name="org.eclipse.microprofile.rest.client.tck.asynctests.CDIInvokeSimpleGetOperationTest" />
-            <class name="org.eclipse.microprofile.rest.client.tck.asynctests.AsyncMethodTest">
-                <methods>
-                    <exclude name="testExecutorService" />
-                </methods>
-            </class>
-        </classes>
-    </test>
-    <test name="Solo Executor Service Test">
-        <classes>
-            <class name="org.eclipse.microprofile.rest.client.tck.asynctests.AsyncMethodTest">
-                <methods>
-                    <include name="testExecutorService" />
-                </methods>
-            </class>
-        </classes>
     </test>
 </suite>
diff --git a/systests/microprofile/pom.xml b/systests/microprofile/pom.xml
index 18100adc643..f92b748ed9b 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.1</cxf.microprofile.rest.client.version>
+        <cxf.microprofile.rest.client.version>1.2-m2</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>


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services