andymc12 closed pull request #379: [CXF-7638] Only register provider if it 
implements specified contracts
URL: https://github.com/apache/cxf/pull/379
 
 
   

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/integration/cdi/src/main/java/org/apache/cxf/cdi/CdiServerConfigurableFactory.java
 
b/integration/cdi/src/main/java/org/apache/cxf/cdi/CdiServerConfigurableFactory.java
index 9090bbfa664..96977d2c298 100644
--- 
a/integration/cdi/src/main/java/org/apache/cxf/cdi/CdiServerConfigurableFactory.java
+++ 
b/integration/cdi/src/main/java/org/apache/cxf/cdi/CdiServerConfigurableFactory.java
@@ -83,7 +83,7 @@
         private final Instantiator instantiator;
         
         CdiServerFeatureContextConfigurable(FeatureContext mc, BeanManager 
beanManager) {
-            super(mc, RuntimeType.SERVER, SERVER_FILTER_INTERCEPTOR_CLASSES);
+            super(mc, RuntimeType.SERVER);
             this.instantiator = new CdiInstantiator(beanManager);
         }
         
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 3685a874cb6..4abfed58246 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,11 +19,20 @@
 
 package org.apache.cxf.jaxrs.impl;
 
+import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.logging.Logger;
+import java.util.stream.Collectors;
 
+import javax.ws.rs.ConstrainedTo;
 import javax.ws.rs.Priorities;
 import javax.ws.rs.RuntimeType;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.client.ClientResponseFilter;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.container.ContainerResponseFilter;
 import javax.ws.rs.core.Configurable;
 import javax.ws.rs.core.Configuration;
 import javax.ws.rs.core.Feature;
@@ -33,29 +42,46 @@
 
 public class ConfigurableImpl<C extends Configurable<C>> implements 
Configurable<C> {
     private static final Logger LOG = 
LogUtils.getL7dLogger(ConfigurableImpl.class);
+    
+    private static final Class<?>[] RESTRICTED_CLASSES_IN_SERVER = 
{ClientRequestFilter.class, 
+                                                                    
ClientResponseFilter.class};
+    private static final Class<?>[] RESTRICTED_CLASSES_IN_CLIENT = 
{ContainerRequestFilter.class, 
+                                                                    
ContainerResponseFilter.class};
+    
     private ConfigurationImpl config;
     private final C configurable;
-    private final Class<?>[] supportedProviderClasses;
     
+    private final Class<?>[] restrictedContractTypes;
+
     public interface Instantiator {
         <T> Object create(Class<T> cls);
     }
     
-    public ConfigurableImpl(C configurable, RuntimeType rt, Class<?>[] 
supportedProviderClasses) {
-        this(configurable, supportedProviderClasses, new 
ConfigurationImpl(rt));
+    public ConfigurableImpl(C configurable, RuntimeType rt) {
+        this(configurable, new ConfigurationImpl(rt));
     }
     
-    public ConfigurableImpl(C configurable, Class<?>[] 
supportedProviderClasses, Configuration config) {
-        this(configurable, supportedProviderClasses);
+    public ConfigurableImpl(C configurable, Configuration config) {
+        this.configurable = configurable;
         this.config = config instanceof ConfigurationImpl
-            ? (ConfigurationImpl)config : new ConfigurationImpl(config, 
supportedProviderClasses);
+            ? (ConfigurationImpl)config : new ConfigurationImpl(config);
+        restrictedContractTypes = 
RuntimeType.CLIENT.equals(config.getRuntimeType()) ? 
RESTRICTED_CLASSES_IN_CLIENT 
+            : RESTRICTED_CLASSES_IN_SERVER;
     }
 
-    private ConfigurableImpl(C configurable, Class<?>[] 
supportedProviderClasses) {
-        this.configurable = configurable;
-        this.supportedProviderClasses = supportedProviderClasses;
+    static Class<?>[] getImplementedContracts(Object provider, Class<?>[] 
restrictedClasses) {
+        Class<?> providerClass = provider instanceof Class<?> ? 
((Class<?>)provider) : provider.getClass();
+        Set<Class<?>> interfaces = 
Arrays.stream(providerClass.getInterfaces()).collect(Collectors.toSet());
+        providerClass = providerClass.getSuperclass();
+        for (; providerClass != null && providerClass != Object.class; 
providerClass = providerClass.getSuperclass()) {
+            
interfaces.addAll(Arrays.stream(providerClass.getInterfaces()).collect(Collectors.toSet()));
+        }
+        List<Class<?>> implementedContracts = interfaces.stream()
+            .filter(el -> 
Arrays.stream(restrictedClasses).noneMatch(el::equals))
+            .collect(Collectors.toList());
+        return implementedContracts.toArray(new Class<?>[]{});
     }
-
+    
     protected C getConfigurable() {
         return configurable;
     }
@@ -78,7 +104,7 @@ public C register(Object provider) {
 
     @Override
     public C register(Object provider, int bindingPriority) {
-        return doRegister(provider, bindingPriority, supportedProviderClasses);
+        return doRegister(provider, bindingPriority, 
getImplementedContracts(provider, restrictedContractTypes));
     }
 
     @Override
@@ -98,7 +124,8 @@ public C register(Class<?> providerClass) {
 
     @Override
     public C register(Class<?> providerClass, int bindingPriority) {
-        return doRegister(getInstantiator().create(providerClass), 
bindingPriority, supportedProviderClasses);
+        return doRegister(getInstantiator().create(providerClass), 
bindingPriority, 
+                          getImplementedContracts(providerClass, 
restrictedContractTypes));
     }
 
     @Override
@@ -110,20 +137,23 @@ public C register(Class<?> providerClass, Class<?>... 
contracts) {
     public C register(Class<?> providerClass, Map<Class<?>, Integer> 
contracts) {
         return register(getInstantiator().create(providerClass), contracts);
     }
-    
+
     protected Instantiator getInstantiator() {
         return ConfigurationImpl::createProvider;
     }
 
     private C doRegister(Object provider, int bindingPriority, Class<?>... 
contracts) {
         if (contracts == null || contracts.length == 0) {
-            LOG.warning("Null or empty contracts specified for " + provider + 
"; ignoring.");
+            LOG.warning("Null, empty or invalid contracts specified for " + 
provider + "; ignoring.");
             return configurable;
         }
         return doRegister(provider, 
ConfigurationImpl.initContractsMap(bindingPriority, contracts));
     }
-    
+
     private C doRegister(Object provider, Map<Class<?>, Integer> contracts) {
+        if (!checkConstraints(provider)) {
+            return configurable;
+        }
         if (provider instanceof Feature) {
             Feature feature = (Feature)provider;
             boolean enabled = feature.configure(new FeatureContextImpl(this));
@@ -134,4 +164,33 @@ private C doRegister(Object provider, Map<Class<?>, 
Integer> contracts) {
         config.register(provider, contracts);
         return configurable;
     }
+
+    private boolean checkConstraints(Object provider) {
+        Class<?> providerClass = provider.getClass();
+        ConstrainedTo providerConstraint = 
providerClass.getAnnotation(ConstrainedTo.class);
+        if (providerConstraint != null) {
+            RuntimeType currentRuntime = config.getRuntimeType();
+            RuntimeType providerRuntime = providerConstraint.value();
+            // need to check (1) whether the registration is occurring in the 
specified runtime type
+            // and (2) does the provider implement an invalid interface based 
on the constrained runtime type
+            if (!providerRuntime.equals(currentRuntime)) {
+                LOG.warning("Provider " + provider + " cannot be registered in 
this " + currentRuntime
+                            + " runtime because it is constrained to " + 
providerRuntime + " runtimes.");
+                return false;
+            }
+            
+            Class<?>[] restrictedInterfaces = 
RuntimeType.CLIENT.equals(providerRuntime) ? RESTRICTED_CLASSES_IN_CLIENT
+                                                                               
          : RESTRICTED_CLASSES_IN_SERVER;
+            for (Class<?> restrictedContract : restrictedInterfaces) {
+                if (restrictedContract.isAssignableFrom(providerClass)) {
+                    RuntimeType opposite = 
RuntimeType.CLIENT.equals(providerRuntime) ? RuntimeType.SERVER
+                                                                               
       : RuntimeType.CLIENT;
+                    LOG.warning("Provider " + providerClass.getName() + " is 
invalid - it is constrained to "
+                        + providerRuntime + " runtimes but implements a " + 
opposite + " interface ");
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
 }
diff --git 
a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ConfigurationImpl.java
 
b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ConfigurationImpl.java
index 271fdec3c78..f68faf8e828 100644
--- 
a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ConfigurationImpl.java
+++ 
b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ConfigurationImpl.java
@@ -47,7 +47,7 @@ public ConfigurationImpl(RuntimeType rt) {
         this.runtimeType = rt;
     }
 
-    public ConfigurationImpl(Configuration parent, Class<?>[] 
defaultContracts) {
+    public ConfigurationImpl(Configuration parent) {
         if (parent != null) {
             this.props.putAll(parent.getProperties());
             this.runtimeType = parent.getRuntimeType();
@@ -55,7 +55,7 @@ public ConfigurationImpl(Configuration parent, Class<?>[] 
defaultContracts) {
             Set<Class<?>> providerClasses = new 
HashSet<Class<?>>(parent.getClasses());
             for (Object o : parent.getInstances()) {
                 if (!(o instanceof Feature)) {
-                    registerParentProvider(o, parent, defaultContracts);
+                    registerParentProvider(o, parent);
                 } else {
                     Feature f = (Feature)o;
                     features.put(f, parent.isEnabled(f));
@@ -63,18 +63,19 @@ public ConfigurationImpl(Configuration parent, Class<?>[] 
defaultContracts) {
                 providerClasses.remove(o.getClass());
             }
             for (Class<?> cls : providerClasses) {
-                registerParentProvider(createProvider(cls), parent, 
defaultContracts);
+                registerParentProvider(createProvider(cls), parent);
             }
 
         }
     }
 
-    private void registerParentProvider(Object o, Configuration parent, 
Class<?>[] defaultContracts) {
+    private void registerParentProvider(Object o, Configuration parent) {
         Map<Class<?>, Integer> contracts = parent.getContracts(o.getClass());
         if (contracts != null) {
             providers.put(o, contracts);
         } else {
-            register(o, AnnotationUtils.getBindingPriority(o.getClass()), 
defaultContracts);
+            register(o, AnnotationUtils.getBindingPriority(o.getClass()), 
+                        ConfigurableImpl.getImplementedContracts(o, new 
Class<?>[]{}));
         }
     }
 
@@ -131,13 +132,15 @@ public RuntimeType getRuntimeType() {
 
     @Override
     public boolean isEnabled(Feature f) {
-        return features.containsKey(f);
+        return features.containsKey(f) && features.get(f);
     }
 
     @Override
     public boolean isEnabled(Class<? extends Feature> f) {
-        for (Feature feature : features.keySet()) {
-            if (feature.getClass().isAssignableFrom(f)) {
+        for (Entry<Feature, Boolean> entry : features.entrySet()) {
+            Feature feature = entry.getKey();
+            Boolean enabled = entry.getValue();
+            if (f.isAssignableFrom(feature.getClass()) && 
enabled.booleanValue()) {
                 return true;
             }
         }
@@ -194,6 +197,10 @@ public boolean register(Object provider, Map<Class<?>, 
Integer> contracts) {
             return false;
         }
 
+        if (!contractsValid(provider, contracts)) {
+            return false;
+        }
+
         Map<Class<?>, Integer> metadata = providers.get(provider);
         if (metadata == null) {
             metadata = new HashMap<>();
@@ -207,6 +214,17 @@ public boolean register(Object provider, Map<Class<?>, 
Integer> contracts) {
         return true;
     }
 
+    private boolean contractsValid(Object provider, Map<Class<?>, Integer> 
contracts) {
+        final Class<?> providerClass = provider.getClass();
+        for (Class<?> contractInterface : contracts.keySet()) {
+            if (!contractInterface.isAssignableFrom(providerClass)) {
+                LOG.warning("Provider " + providerClass.getName() + " does not 
implement specified contract: "
+                    + contractInterface.getName());
+                return false;
+            }
+        }
+        return true;
+    }
     public static Map<Class<?>, Integer> initContractsMap(int bindingPriority, 
Class<?>... contracts) {
         Map<Class<?>, Integer> metadata = new HashMap<>();
         for (Class<?> contract : contracts) {
diff --git 
a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerConfigurableFactory.java
 
b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerConfigurableFactory.java
index 0e9473f40f7..bd907d89424 100644
--- 
a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerConfigurableFactory.java
+++ 
b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerConfigurableFactory.java
@@ -19,12 +19,8 @@
 
 package org.apache.cxf.jaxrs.provider;
 
-import javax.ws.rs.container.ContainerRequestFilter;
-import javax.ws.rs.container.ContainerResponseFilter;
 import javax.ws.rs.core.Configurable;
 import javax.ws.rs.core.FeatureContext;
-import javax.ws.rs.ext.ReaderInterceptor;
-import javax.ws.rs.ext.WriterInterceptor;
 
 /**
  * Manages the creation of server-side {@code Configurable<FeatureContext>} 
depending on 
@@ -34,12 +30,6 @@
  * notice, please be aware of that. 
  */
 public interface ServerConfigurableFactory {
-    Class<?>[] SERVER_FILTER_INTERCEPTOR_CLASSES = new Class<?>[] {
-        ContainerRequestFilter.class,
-        ContainerResponseFilter.class,
-        ReaderInterceptor.class,
-        WriterInterceptor.class 
-    };
-    
+
     Configurable<FeatureContext> create(FeatureContext context);
 }
diff --git 
a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerProviderFactory.java
 
b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerProviderFactory.java
index bfdd8cc59d2..f0a411aeff6 100644
--- 
a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerProviderFactory.java
+++ 
b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerProviderFactory.java
@@ -453,7 +453,7 @@ protected static boolean isPrematching(Class<?> filterCls) {
 
     private static class ServerFeatureContextConfigurable extends 
ConfigurableImpl<FeatureContext> {
         protected ServerFeatureContextConfigurable(FeatureContext mc) {
-            super(mc, RuntimeType.SERVER, 
ServerConfigurableFactory.SERVER_FILTER_INTERCEPTOR_CLASSES);
+            super(mc, RuntimeType.SERVER);
         }
     }
 
diff --git 
a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/ConfigurationImplTest.java
 
b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/ConfigurationImplTest.java
index c50bb428a20..0e43f05e3d9 100644
--- 
a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/ConfigurationImplTest.java
+++ 
b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/ConfigurationImplTest.java
@@ -20,12 +20,34 @@
 package org.apache.cxf.jaxrs.impl;
 
 import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
 
+import javax.ws.rs.ConstrainedTo;
 import javax.ws.rs.RuntimeType;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.client.ClientResponseContext;
+import javax.ws.rs.client.ClientResponseFilter;
 import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
 import javax.ws.rs.container.ContainerResponseContext;
 import javax.ws.rs.container.ContainerResponseFilter;
+import javax.ws.rs.core.Configurable;
+import javax.ws.rs.core.Configuration;
+import javax.ws.rs.core.Feature;
+import javax.ws.rs.core.FeatureContext;
+import javax.ws.rs.ext.MessageBodyReader;
+
+import org.apache.cxf.common.logging.LogUtils;
 
 import org.junit.Assert;
 import org.junit.Test;
@@ -33,28 +55,290 @@
 public class ConfigurationImplTest extends Assert {
 
     @Test
-    public void testIsRegistered() {
+    public void testIsRegistered() throws Exception {
+//        ConfigurationImpl c = new ConfigurationImpl(RuntimeType.SERVER);
+//        ContainerResponseFilter filter = new ContainerResponseFilterImpl();
+//        assertTrue(c.register(filter,
+//                              Collections.<Class<?>, 
Integer>singletonMap(ContainerResponseFilter.class, 1000)));
+//        assertTrue(c.isRegistered(filter));
+//        assertFalse(c.isRegistered(new ContainerResponseFilterImpl()));
+//        assertTrue(c.isRegistered(ContainerResponseFilterImpl.class));
+//        assertFalse(c.isRegistered(ContainerResponseFilter.class));
+//        assertFalse(c.register(filter,
+//                               Collections.<Class<?>, 
Integer>singletonMap(ContainerResponseFilter.class, 1000)));
+//        assertFalse(c.register(ContainerResponseFilterImpl.class,
+//                               Collections.<Class<?>, 
Integer>singletonMap(ContainerResponseFilter.class, 1000)));
+        doTestIsFilterRegistered(new ContainerResponseFilterImpl(), 
ContainerResponseFilterImpl.class);
+    }
+    
+    @Test
+    public void testIsRegisteredSubClass() throws Exception {
+        doTestIsFilterRegistered(new ContainerResponseFilterSubClassImpl(), 
ContainerResponseFilterSubClassImpl.class);
+    }
+
+    private void doTestIsFilterRegistered(Object provider, Class<?> 
providerClass) throws Exception {
         ConfigurationImpl c = new ConfigurationImpl(RuntimeType.SERVER);
-        ContainerResponseFilter filter = new ContainerResponseFilterImpl();
-        assertTrue(c.register(filter,
-                   Collections.<Class<?>, 
Integer>singletonMap(ContainerResponseFilter.class, 1000)));
-        assertTrue(c.isRegistered(filter));
-        assertFalse(c.isRegistered(new ContainerResponseFilterImpl()));
-        assertTrue(c.isRegistered(ContainerResponseFilterImpl.class));
-        assertFalse(c.isRegistered(ContainerResponseFilter.class));
-        assertFalse(c.register(filter,
+        assertTrue(c.register(provider,
                               Collections.<Class<?>, 
Integer>singletonMap(ContainerResponseFilter.class, 1000)));
-        assertFalse(c.register(ContainerResponseFilterImpl.class,
+        assertTrue(c.isRegistered(provider));
+        assertFalse(c.isRegistered(providerClass.newInstance()));
+        assertTrue(c.isRegistered(providerClass));
+        assertFalse(c.isRegistered(ContainerResponseFilter.class));
+        assertFalse(c.register(provider,
+                               Collections.<Class<?>, 
Integer>singletonMap(ContainerResponseFilter.class, 1000)));
+        assertFalse(c.register(providerClass,
                                Collections.<Class<?>, 
Integer>singletonMap(ContainerResponseFilter.class, 1000)));
     }
+
+    @ConstrainedTo(RuntimeType.SERVER)
     public static class ContainerResponseFilterImpl implements 
ContainerResponseFilter {
 
         @Override
         public void filter(ContainerRequestContext requestContext, 
ContainerResponseContext responseContext)
             throws IOException {
+        }
+
+    }
 
+    public static class ContainerResponseFilterSubClassImpl extends 
ContainerResponseFilterImpl { }
+
+    @ConstrainedTo(RuntimeType.CLIENT)
+    public static class ClientResponseFilterImpl implements 
ClientResponseFilter {
+
+        @Override
+        public void filter(ClientRequestContext requestContext, 
ClientResponseContext responseContext)
+            throws IOException {
         }
 
     }
+    static class TestHandler extends Handler {
+
+        List<String> messages = new ArrayList<>();
+
+        /** {@inheritDoc}*/
+        @Override
+        public void publish(LogRecord record) {
+            messages.add(record.getLevel().toString() + ": " + 
record.getMessage());
+        }
+
+        /** {@inheritDoc}*/
+        @Override
+        public void flush() {
+            // no-op
+        }
+
+        /** {@inheritDoc}*/
+        @Override
+        public void close() throws SecurityException {
+            // no-op
+        }
+    }
+
+    @Test
+    public void testInvalidContract() {
+        TestHandler handler = new TestHandler();
+        LogUtils.getL7dLogger(ConfigurationImpl.class).addHandler(handler);
+
+        ConfigurationImpl c = new ConfigurationImpl(RuntimeType.SERVER);
+        ContainerResponseFilter filter = new ContainerResponseFilterImpl();
+        assertFalse(c.register(filter,
+                               Collections.<Class<?>, 
Integer>singletonMap(MessageBodyReader.class, 1000)));
+
+        for (String message : handler.messages) {
+            if (message.startsWith("WARN") && message.contains("does not 
implement specified contract")) {
+                return; // success
+            }
+        }
+        fail("did not log expected message");
+    }
+
+    public static class TestFilter implements ContainerRequestFilter, 
ContainerResponseFilter, 
+    ClientRequestFilter, ClientResponseFilter {
+
+        @Override
+        public void filter(ClientRequestContext paramClientRequestContext,
+                           ClientResponseContext paramClientResponseContext)
+                               throws IOException {
+            // no-op
+        }
+
+        @Override
+        public void filter(ClientRequestContext paramClientRequestContext) 
throws IOException {
+            // no-op
+        }
+
+        @Override
+        public void filter(ContainerRequestContext 
paramContainerRequestContext,
+                           ContainerResponseContext 
paramContainerResponseContext)
+                               throws IOException {
+            // no-op
+        }
+
+        @Override
+        public void filter(ContainerRequestContext 
paramContainerRequestContext) throws IOException {
+            // no-op
+        }
+    }
+
+    private Client createClientProxy() {
+        return (Client) 
Proxy.newProxyInstance(this.getClass().getClassLoader(), 
+            new Class<?>[]{Client.class},
+            new InvocationHandler() {
 
+                @Override
+                public Object invoke(Object proxy, Method method, Object[] 
args) throws Throwable {
+                    return null; //no-op
+                } });
+    }
+
+    @Test
+    public void testSubClassIsRegisteredOnConfigurable() {
+        FeatureContextImpl featureContext = new FeatureContextImpl();
+        Configurable<FeatureContext> configurable = new 
ConfigurableImpl<>(featureContext, RuntimeType.SERVER);
+        featureContext.setConfigurable(configurable);
+        featureContext.register(ContainerResponseFilterSubClassImpl.class);
+        Configuration config = configurable.getConfiguration();
+        Map<Class<?>, Integer> contracts = 
config.getContracts(ContainerResponseFilter.class);
+        assertEquals(1, contracts.size());
+        assertTrue(contracts.containsKey(ContainerResponseFilter.class));
+    }
+    
+    @Test
+    public void testServerFilterContractsOnClientIsRejected() {
+        Configurable<Client> configurable = new 
ConfigurableImpl<Client>(createClientProxy(), RuntimeType.CLIENT);
+        Configuration config = configurable.getConfiguration();
+        configurable.register(TestFilter.class);
+        Map<Class<?>, Integer> contracts = 
config.getContracts(TestFilter.class);
+        assertTrue(contracts.containsKey(ClientRequestFilter.class));
+        assertTrue(contracts.containsKey(ClientResponseFilter.class));
+        assertFalse(contracts.containsKey(ContainerRequestFilter.class));
+        assertFalse(contracts.containsKey(ContainerResponseFilter.class));
+    }
+
+    @Test
+    public void testClientFilterContractsOnServerFeatureIsRejected() {
+        FeatureContextImpl featureContext = new FeatureContextImpl();
+        Configurable<FeatureContext> configurable = new 
ConfigurableImpl<>(featureContext, RuntimeType.SERVER);
+        featureContext.setConfigurable(configurable);
+        featureContext.register(TestFilter.class);
+        Configuration config = configurable.getConfiguration();
+        Map<Class<?>, Integer> contracts = 
config.getContracts(TestFilter.class);
+        assertFalse(contracts.containsKey(ClientRequestFilter.class));
+        assertFalse(contracts.containsKey(ClientResponseFilter.class));
+        assertTrue(contracts.containsKey(ContainerRequestFilter.class));
+        assertTrue(contracts.containsKey(ContainerResponseFilter.class));
+    }
+
+    public static class DisablableFeature implements Feature {
+
+        boolean enabled;
+
+        /** {@inheritDoc}*/
+        @Override
+        public boolean configure(FeatureContext context) {
+            return enabled;
+        }
+
+    }
+
+    @Test
+    public void testFeatureDisabledClass() {
+        FeatureContextImpl featureContext = new FeatureContextImpl();
+        Configurable<FeatureContext> configurable = new 
ConfigurableImpl<>(featureContext, RuntimeType.SERVER);
+        featureContext.setConfigurable(configurable);
+        featureContext.register(DisablableFeature.class);
+
+        Configuration config = configurable.getConfiguration();
+        assertFalse(config.isEnabled(DisablableFeature.class));
+    }
+
+    @Test
+    public void testFeatureDisabledInstance() {
+        FeatureContextImpl featureContext = new FeatureContextImpl();
+        Configurable<FeatureContext> configurable = new 
ConfigurableImpl<>(featureContext, RuntimeType.SERVER);
+        featureContext.setConfigurable(configurable);
+        Feature feature = new DisablableFeature();
+        featureContext.register(feature);
+
+        Configuration config = configurable.getConfiguration();
+        assertFalse(config.isEnabled(feature));
+    }
+
+    @Test 
+    public void testIsEnabledWithMultipleFeaturesOfSameType() {
+        FeatureContextImpl featureContext = new FeatureContextImpl();
+        Configurable<FeatureContext> configurable = new 
ConfigurableImpl<>(featureContext, RuntimeType.SERVER);
+        featureContext.setConfigurable(configurable);
+
+        featureContext.register(new DisablableFeature());
+        featureContext.register(new DisablableFeature());
+        featureContext.register(new DisablableFeature());
+
+        Configuration config = configurable.getConfiguration();
+        assertEquals(3, config.getInstances().size());
+        assertFalse(config.isEnabled(DisablableFeature.class));
+
+        DisablableFeature enabledFeature = new DisablableFeature();
+        enabledFeature.enabled = true;
+
+        featureContext.register(enabledFeature);
+        assertEquals(4, config.getInstances().size());
+        assertTrue(config.isEnabled(DisablableFeature.class));
+
+        featureContext.register(new DisablableFeature());
+        assertEquals(5, config.getInstances().size());
+        assertTrue(config.isEnabled(DisablableFeature.class));
+    }
+
+    @ConstrainedTo(RuntimeType.SERVER)
+    public static class ClientFilterConstrainedToServer implements 
ClientRequestFilter {
+
+        /** {@inheritDoc}*/
+        @Override
+        public void filter(ClientRequestContext paramClientRequestContext) 
throws IOException {
+            // no-op
+        }
+        
+    }
+
+    @Test
+    public void testInvalidConstraintOnProvider() {
+        TestHandler handler = new TestHandler();
+        LogUtils.getL7dLogger(ConfigurableImpl.class).addHandler(handler);
+
+        Configurable<Client> configurable = new 
ConfigurableImpl<Client>(createClientProxy(), RuntimeType.CLIENT);
+        Configuration config = configurable.getConfiguration();
+
+        configurable.register(ClientFilterConstrainedToServer.class);
+
+        assertEquals(0, config.getInstances().size());
+
+        for (String message : handler.messages) {
+            if (message.startsWith("WARN") && message.contains("cannot be 
registered in ")) {
+                return; // success
+            }
+        }
+        fail("did not log expected message");
+    }
+
+    
+    @Test
+    public void testChecksConstrainedToAnnotationDuringRegistration() {
+        TestHandler handler = new TestHandler();
+        LogUtils.getL7dLogger(ConfigurableImpl.class).addHandler(handler);
+
+        Configurable<Client> configurable = new 
ConfigurableImpl<Client>(createClientProxy(), RuntimeType.CLIENT);
+        Configuration config = configurable.getConfiguration();
+
+        configurable.register(ContainerResponseFilterImpl.class);
+
+        assertEquals(0, config.getInstances().size());
+
+        for (String message : handler.messages) {
+            if (message.startsWith("WARN") && message.contains("Null, empty or 
invalid contracts specified")) {
+                return; // success
+            }
+        }
+        fail("did not log expected message");
+    }
 }
diff --git 
a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientConfigurableImpl.java
 
b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientConfigurableImpl.java
index 12cd2a6e5e1..5ed6439803e 100644
--- 
a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientConfigurableImpl.java
+++ 
b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spec/ClientConfigurableImpl.java
@@ -20,22 +20,13 @@
 package org.apache.cxf.jaxrs.client.spec;
 
 import javax.ws.rs.RuntimeType;
-import javax.ws.rs.client.ClientRequestFilter;
-import javax.ws.rs.client.ClientResponseFilter;
 import javax.ws.rs.core.Configurable;
 import javax.ws.rs.core.Configuration;
-import javax.ws.rs.ext.ReaderInterceptor;
-import javax.ws.rs.ext.WriterInterceptor;
 
 import org.apache.cxf.jaxrs.impl.ConfigurableImpl;
 import org.apache.cxf.jaxrs.impl.ConfigurationImpl;
 
 public class ClientConfigurableImpl<C extends Configurable<C>> extends 
ConfigurableImpl<C> {
-    private static final Class<?>[] CLIENT_FILTER_INTERCEPTOR_CLASSES =
-        new Class<?>[] {ClientRequestFilter.class,
-                        ClientResponseFilter.class,
-                        ReaderInterceptor.class,
-                        WriterInterceptor.class};
 
 
     public ClientConfigurableImpl(C configurable) {
@@ -44,8 +35,7 @@ public ClientConfigurableImpl(C configurable) {
 
     public ClientConfigurableImpl(C configurable, Configuration config) {
         super(configurable,
-              CLIENT_FILTER_INTERCEPTOR_CLASSES,
               config == null ? new ConfigurationImpl(RuntimeType.CLIENT)
-                  : new ConfigurationImpl(config, 
CLIENT_FILTER_INTERCEPTOR_CLASSES));
+                  : new ConfigurationImpl(config));
     }
 }
diff --git 
a/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spec/ClientImplTest.java
 
b/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spec/ClientImplTest.java
index f45c2ea9e3c..88cf9da8f5f 100644
--- 
a/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spec/ClientImplTest.java
+++ 
b/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spec/ClientImplTest.java
@@ -164,7 +164,7 @@ public void testRegisterNullComponentClass() {
         ClientBuilder.newClient().register(MyInterceptor.class, (Class<?>[]) 
null);
 
         for (String message : handler.messages) {
-            if (message.startsWith("WARN") && message.contains("Null or empty 
contracts")) {
+            if (message.startsWith("WARN") && message.contains("Null, empty or 
invalid contracts specified")) {
                 return; // success
             }
         }
@@ -181,7 +181,7 @@ public void testRegisterNullComponentObject() {
         ClientBuilder.newClient().register(new MyInterceptor(), (Class<?>[]) 
null);
 
         for (String message : handler.messages) {
-            if (message.startsWith("WARN") && message.contains("Null or empty 
contracts")) {
+            if (message.startsWith("WARN") && message.contains("Null, empty or 
invalid contracts specified")) {
                 return; // success
             }
         }
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 97e8c7d81b3..4cf27631d0e 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
@@ -46,9 +46,8 @@ public MicroProfileClientConfigurableImpl(C configurable) {
     }
 
     public MicroProfileClientConfigurableImpl(C configurable, Configuration 
config) {
-        super(configurable,
-                CONTRACTS, config == null ? new 
ConfigurationImpl(RuntimeType.CLIENT)
-                        : new ConfigurationImpl(config, CONTRACTS));
+        super(configurable, config == null ? new 
ConfigurationImpl(RuntimeType.CLIENT)
+                        : new ConfigurationImpl(config));
     }
 
     boolean isDefaultExceptionMapperDisabled() {


 

----------------------------------------------------------------
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:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to