[GitHub] andymc12 closed pull request #379: [CXF-7638] Only register provider if it implements specified contracts

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[GitHub] andymc12 closed pull request #379: [CXF-7638] Only register provider if it implements specified contracts

GitBox
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:
[hidden email]


With regards,
Apache Git Services