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 2018/09/23 14:56:20 UTC

[GitHub] rmannibucau closed pull request #448: [CXF-7846] jaxrs client instantiator lifecycle and pluggability

rmannibucau closed pull request #448: [CXF-7846] jaxrs client instantiator lifecycle and pluggability
URL: https://github.com/apache/cxf/pull/448
 
 
   

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/distribution/src/main/release/samples/pom.xml b/distribution/src/main/release/samples/pom.xml
index d27ed63a9f4..8f3d3520478 100644
--- a/distribution/src/main/release/samples/pom.xml
+++ b/distribution/src/main/release/samples/pom.xml
@@ -31,7 +31,7 @@
         <maven.deploy.skip>true</maven.deploy.skip>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <spring.boot.version>2.0.5.RELEASE</spring.boot.version>
-        <spring.cloud.eureka.version>2.0.0.RELEASE</spring.cloud.eureka.version>
+        <spring.cloud.eureka.version>2.0.1.RELEASE</spring.cloud.eureka.version>
     </properties>
     <dependencies>
         <dependency>
diff --git a/parent/pom.xml b/parent/pom.xml
index ede0ab1d2fd..fd6e3990504 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -158,7 +158,7 @@
         <cxf.servlet-api-2.5.version>1.2</cxf.servlet-api-2.5.version>
         <cxf.slf4j.version>1.7.25</cxf.slf4j.version>
         <cxf.specs.jaxws.api.version>1.2</cxf.specs.jaxws.api.version>
-        <cxf.spring.version>5.0.8.RELEASE</cxf.spring.version>
+        <cxf.spring.version>5.0.9.RELEASE</cxf.spring.version>
         <cxf.spring.boot.version>2.0.5.RELEASE</cxf.spring.boot.version>
         <cxf.spring.security.version>5.0.8.RELEASE</cxf.spring.security.version>
         <cxf.spring.osgi.version>1.2.1</cxf.spring.osgi.version>
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ConfigurableImpl.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ConfigurableImpl.java
index fe2427a7b7f..436f8245d21 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ConfigurableImpl.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ConfigurableImpl.java
@@ -19,10 +19,14 @@
 
 package org.apache.cxf.jaxrs.impl;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.ServiceLoader;
 import java.util.Set;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
@@ -41,7 +45,7 @@
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.jaxrs.utils.AnnotationUtils;
 
-public class ConfigurableImpl<C extends Configurable<C>> implements Configurable<C> {
+public class ConfigurableImpl<C extends Configurable<C>> implements Configurable<C>, AutoCloseable {
     private static final Logger LOG = LogUtils.getL7dLogger(ConfigurableImpl.class);
     
     private static final Class<?>[] RESTRICTED_CLASSES_IN_SERVER = {ClientRequestFilter.class, 
@@ -51,11 +55,19 @@
     
     private ConfigurationImpl config;
     private final C configurable;
-    
+    private final ClassLoader classLoader;
+
     private final Class<?>[] restrictedContractTypes;
 
+    private final Collection<Object> instantiatorInstances = new ArrayList<>();
+    private volatile Instantiator instantiator;
+
     public interface Instantiator {
         <T> Object create(Class<T> cls);
+
+        default void release(Object instance) {
+            // no-op
+        }
     }
     
     public ConfigurableImpl(C configurable, RuntimeType rt) {
@@ -66,7 +78,8 @@ public ConfigurableImpl(C configurable, Configuration config) {
         this.configurable = configurable;
         this.config = config instanceof ConfigurationImpl
             ? (ConfigurationImpl)config : new ConfigurationImpl(config);
-        restrictedContractTypes = RuntimeType.CLIENT.equals(config.getRuntimeType()) ? RESTRICTED_CLASSES_IN_CLIENT 
+        this.classLoader = Thread.currentThread().getContextClassLoader();
+        restrictedContractTypes = RuntimeType.CLIENT.equals(config.getRuntimeType()) ? RESTRICTED_CLASSES_IN_CLIENT
             : RESTRICTED_CLASSES_IN_SERVER;
     }
 
@@ -110,6 +123,17 @@ protected C getConfigurable() {
         return configurable;
     }
 
+    @Override
+    public void close() {
+        synchronized (instantiatorInstances) {
+            if (instantiatorInstances.isEmpty()) {
+                return;
+            }
+            instantiatorInstances.forEach(instantiator::release);
+            instantiatorInstances.clear();
+        }
+    }
+
     @Override
     public Configuration getConfiguration() {
         return config;
@@ -128,6 +152,12 @@ public C register(Object provider) {
 
     @Override
     public C register(Object provider, int bindingPriority) {
+        if (Instantiator.class.isInstance(provider)) {
+            synchronized (this) {
+                instantiator = Instantiator.class.cast(provider);
+            }
+            return configurable;
+        }
         return doRegister(provider, bindingPriority, getImplementedContracts(provider, restrictedContractTypes));
     }
 
@@ -148,7 +178,7 @@ public C register(Class<?> providerClass) {
 
     @Override
     public C register(Class<?> providerClass, int bindingPriority) {
-        return doRegister(getInstantiator().create(providerClass), bindingPriority, 
+        return doRegister(createProvider(providerClass), bindingPriority,
                           getImplementedContracts(providerClass, restrictedContractTypes));
     }
 
@@ -159,11 +189,25 @@ public C register(Class<?> providerClass, Class<?>... contracts) {
 
     @Override
     public C register(Class<?> providerClass, Map<Class<?>, Integer> contracts) {
-        return register(getInstantiator().create(providerClass), contracts);
+        return register(createProvider(providerClass), contracts);
     }
 
     protected Instantiator getInstantiator() {
-        return ConfigurationImpl::createProvider;
+        if (instantiator != null) {
+            return instantiator;
+        }
+        synchronized (this) {
+            if (instantiator != null) {
+                return instantiator;
+            }
+            final Iterator<Instantiator> instantiators = ServiceLoader.load(Instantiator.class, classLoader).iterator();
+            if (instantiators.hasNext()) {
+                instantiator = instantiators.next();
+            } else {
+                instantiator = ConfigurationImpl::createProvider;
+            }
+        }
+        return instantiator;
     }
 
     private C doRegister(Object provider, int bindingPriority, Class<?>... contracts) {
@@ -217,4 +261,12 @@ private boolean checkConstraints(Object provider) {
         }
         return true;
     }
+
+    private Object createProvider(final Class<?> providerClass) {
+        final Object instance = getInstantiator().create(providerClass);
+        synchronized (instantiatorInstances) {
+            instantiatorInstances.add(instance);
+        }
+        return instance;
+    }
 }
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 93f8034c2ec..0bc9710e214 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
@@ -32,14 +32,13 @@
 import javax.ws.rs.RuntimeType;
 import javax.ws.rs.client.Client;
 import javax.ws.rs.client.ClientBuilder;
-import javax.ws.rs.core.Configurable;
 import javax.ws.rs.core.Configuration;
 
 import org.apache.cxf.jaxrs.client.AbstractClient;
 
 public class ClientBuilderImpl extends ClientBuilder {
 
-    private Configurable<ClientBuilder> configImpl;
+    private ClientConfigurableImpl<ClientBuilder> configImpl;
     private TLSConfiguration secConfig = new TLSConfiguration();
 
     public ClientBuilderImpl() {
@@ -98,7 +97,13 @@ public ClientBuilder register(Object object, Map<Class<?>, Integer> map) {
 
     @Override
     public Client build() {
-        return new ClientImpl(configImpl.getConfiguration(), secConfig);
+        return new ClientImpl(configImpl.getConfiguration(), secConfig) {
+            @Override
+            public void close() {
+                super.close();
+                configImpl.close();
+            }
+        };
     }
 
     @Override
diff --git a/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spec/ClientBuilderImplTest.java b/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spec/ClientBuilderImplTest.java
new file mode 100644
index 00000000000..69cd9f6ef79
--- /dev/null
+++ b/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spec/ClientBuilderImplTest.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.jaxrs.client.spec;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.ws.rs.client.Client;
+
+import org.apache.cxf.jaxrs.impl.ConfigurableImpl;
+import org.apache.cxf.jaxrs.provider.PrimitiveTextProvider;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+public class ClientBuilderImplTest {
+    @Test
+    public void withCustomInstantiator() {
+        final AtomicInteger create = new AtomicInteger();
+        final AtomicInteger close = new AtomicInteger();
+        final Client build = new ClientBuilderImpl().register(new ConfigurableImpl.Instantiator() {
+            @Override
+            public <T> Object create(final Class<T> cls) {
+                try {
+                    create.incrementAndGet();
+                    return cls.newInstance();
+                } catch (final InstantiationException | IllegalAccessException e) {
+                    fail(e.getMessage());
+                }
+                return null;
+            }
+
+            @Override
+            public void release(final Object instance) {
+                close.incrementAndGet();
+            }
+        }).register(PrimitiveTextProvider.class).build();
+        assertEquals(1, create.get());
+        assertEquals(0, close.get());
+        build.close();
+        assertEquals(1, create.get());
+        assertEquals(1, close.get());
+    }
+}


 

----------------------------------------------------------------
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