mirror of https://github.com/apache/kafka.git
				
				
				
			KAFKA-14654: Connector classes should statically initialize with plugin classloader (#13165)
Reviewers: Chaitanya Mukka <chaitanya.mvs2007@gmail.com>, Chris Egerton <chrise@aiven.io>
This commit is contained in:
		
							parent
							
								
									fe303b9c3e
								
							
						
					
					
						commit
						dc00832b96
					
				|  | @ -400,7 +400,7 @@ public class DelegatingClassLoader extends URLClassLoader { | ||||||
|         Collection<PluginDesc<T>> result = new ArrayList<>(); |         Collection<PluginDesc<T>> result = new ArrayList<>(); | ||||||
|         for (Class<? extends T> plugin : plugins) { |         for (Class<? extends T> plugin : plugins) { | ||||||
|             if (PluginUtils.isConcrete(plugin)) { |             if (PluginUtils.isConcrete(plugin)) { | ||||||
|                 try { |                 try (LoaderSwap loaderSwap = withClassLoader(loader)) { | ||||||
|                     result.add(pluginDesc(plugin, versionFor(plugin), loader)); |                     result.add(pluginDesc(plugin, versionFor(plugin), loader)); | ||||||
|                 } catch (ReflectiveOperationException | LinkageError e) { |                 } catch (ReflectiveOperationException | LinkageError e) { | ||||||
|                     log.error("Failed to discover {}: Unable to instantiate {}{}", klass.getSimpleName(), plugin.getSimpleName(), reflectiveErrorDescription(e), e); |                     log.error("Failed to discover {}: Unable to instantiate {}{}", klass.getSimpleName(), plugin.getSimpleName(), reflectiveErrorDescription(e), e); | ||||||
|  | @ -419,11 +419,10 @@ public class DelegatingClassLoader extends URLClassLoader { | ||||||
| 
 | 
 | ||||||
|     @SuppressWarnings("unchecked") |     @SuppressWarnings("unchecked") | ||||||
|     private <T> Collection<PluginDesc<T>> getServiceLoaderPluginDesc(Class<T> klass, ClassLoader loader) { |     private <T> Collection<PluginDesc<T>> getServiceLoaderPluginDesc(Class<T> klass, ClassLoader loader) { | ||||||
|         ClassLoader savedLoader = Plugins.compareAndSwapLoaders(loader); |  | ||||||
|         Collection<PluginDesc<T>> result = new ArrayList<>(); |         Collection<PluginDesc<T>> result = new ArrayList<>(); | ||||||
|         try { |         ServiceLoader<T> serviceLoader = ServiceLoader.load(klass, loader); | ||||||
|             ServiceLoader<T> serviceLoader = ServiceLoader.load(klass, loader); |         for (Iterator<T> iterator = serviceLoader.iterator(); iterator.hasNext(); ) { | ||||||
|             for (Iterator<T> iterator = serviceLoader.iterator(); iterator.hasNext(); ) { |             try (LoaderSwap loaderSwap = withClassLoader(loader)) { | ||||||
|                 T pluginImpl; |                 T pluginImpl; | ||||||
|                 try { |                 try { | ||||||
|                     pluginImpl = iterator.next(); |                     pluginImpl = iterator.next(); | ||||||
|  | @ -434,8 +433,6 @@ public class DelegatingClassLoader extends URLClassLoader { | ||||||
|                 result.add(pluginDesc((Class<? extends T>) pluginImpl.getClass(), |                 result.add(pluginDesc((Class<? extends T>) pluginImpl.getClass(), | ||||||
|                     versionFor(pluginImpl), loader)); |                     versionFor(pluginImpl), loader)); | ||||||
|             } |             } | ||||||
|         } finally { |  | ||||||
|             Plugins.compareAndSwapLoaders(savedLoader); |  | ||||||
|         } |         } | ||||||
|         return result; |         return result; | ||||||
|     } |     } | ||||||
|  | @ -473,6 +470,16 @@ public class DelegatingClassLoader extends URLClassLoader { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public LoaderSwap withClassLoader(ClassLoader loader) { | ||||||
|  |         ClassLoader savedLoader = Plugins.compareAndSwapLoaders(loader); | ||||||
|  |         try { | ||||||
|  |             return new LoaderSwap(savedLoader); | ||||||
|  |         } catch (Throwable t) { | ||||||
|  |             Plugins.compareAndSwapLoaders(savedLoader); | ||||||
|  |             throw t; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { |     protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { | ||||||
|         String fullName = aliases.getOrDefault(name, name); |         String fullName = aliases.getOrDefault(name, name); | ||||||
|  |  | ||||||
|  | @ -30,6 +30,7 @@ import org.apache.kafka.common.config.AbstractConfig; | ||||||
| import org.apache.kafka.common.config.ConfigDef; | import org.apache.kafka.common.config.ConfigDef; | ||||||
| import org.apache.kafka.common.config.ConfigException; | import org.apache.kafka.common.config.ConfigException; | ||||||
| import org.apache.kafka.common.config.provider.ConfigProvider; | import org.apache.kafka.common.config.provider.ConfigProvider; | ||||||
|  | import org.apache.kafka.connect.connector.Connector; | ||||||
| import org.apache.kafka.connect.data.Schema; | import org.apache.kafka.connect.data.Schema; | ||||||
| import org.apache.kafka.connect.data.SchemaAndValue; | import org.apache.kafka.connect.data.SchemaAndValue; | ||||||
| import org.apache.kafka.connect.errors.ConnectException; | import org.apache.kafka.connect.errors.ConnectException; | ||||||
|  | @ -295,7 +296,7 @@ public class PluginsTest { | ||||||
|         // Assert that the service loaded subclass is found in both environments |         // Assert that the service loaded subclass is found in both environments | ||||||
|         assertTrue(samples.containsKey("ServiceLoadedSubclass.static")); |         assertTrue(samples.containsKey("ServiceLoadedSubclass.static")); | ||||||
|         assertTrue(samples.containsKey("ServiceLoadedSubclass.dynamic")); |         assertTrue(samples.containsKey("ServiceLoadedSubclass.dynamic")); | ||||||
|         assertPluginClassLoaderAlwaysActive(samples); |         assertPluginClassLoaderAlwaysActive(plugin); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|  | @ -306,9 +307,7 @@ public class PluginsTest { | ||||||
|             Converter.class |             Converter.class | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|         assertInstanceOf(SamplingTestPlugin.class, plugin, "Cannot collect samples"); |         assertPluginClassLoaderAlwaysActive(plugin); | ||||||
|         Map<String, SamplingTestPlugin> samples = ((SamplingTestPlugin) plugin).flatten(); |  | ||||||
|         assertPluginClassLoaderAlwaysActive(samples); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|  | @ -334,7 +333,7 @@ public class PluginsTest { | ||||||
|         assertInstanceOf(SamplingTestPlugin.class, plugin, "Cannot collect samples"); |         assertInstanceOf(SamplingTestPlugin.class, plugin, "Cannot collect samples"); | ||||||
|         Map<String, SamplingTestPlugin> samples = ((SamplingTestPlugin) plugin).flatten(); |         Map<String, SamplingTestPlugin> samples = ((SamplingTestPlugin) plugin).flatten(); | ||||||
|         assertTrue(samples.containsKey("configure")); |         assertTrue(samples.containsKey("configure")); | ||||||
|         assertPluginClassLoaderAlwaysActive(samples); |         assertPluginClassLoaderAlwaysActive(plugin); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|  | @ -357,7 +356,7 @@ public class PluginsTest { | ||||||
|         assertInstanceOf(SamplingTestPlugin.class, plugin, "Cannot collect samples"); |         assertInstanceOf(SamplingTestPlugin.class, plugin, "Cannot collect samples"); | ||||||
|         Map<String, SamplingTestPlugin> samples = ((SamplingTestPlugin) plugin).flatten(); |         Map<String, SamplingTestPlugin> samples = ((SamplingTestPlugin) plugin).flatten(); | ||||||
|         assertTrue(samples.containsKey("configure")); |         assertTrue(samples.containsKey("configure")); | ||||||
|         assertPluginClassLoaderAlwaysActive(samples); |         assertPluginClassLoaderAlwaysActive(plugin); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|  | @ -377,7 +376,17 @@ public class PluginsTest { | ||||||
|         assertInstanceOf(SamplingTestPlugin.class, plugin, "Cannot collect samples"); |         assertInstanceOf(SamplingTestPlugin.class, plugin, "Cannot collect samples"); | ||||||
|         Map<String, SamplingTestPlugin> samples = ((SamplingTestPlugin) plugin).flatten(); |         Map<String, SamplingTestPlugin> samples = ((SamplingTestPlugin) plugin).flatten(); | ||||||
|         assertTrue(samples.containsKey("configure")); // HeaderConverter::configure was called |         assertTrue(samples.containsKey("configure")); // HeaderConverter::configure was called | ||||||
|         assertPluginClassLoaderAlwaysActive(samples); |         assertPluginClassLoaderAlwaysActive(plugin); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void newConnectorShouldInstantiateWithPluginClassLoader() { | ||||||
|  |         Connector plugin = plugins.newConnector(TestPlugin.SAMPLING_CONNECTOR.className()); | ||||||
|  | 
 | ||||||
|  |         assertInstanceOf(SamplingTestPlugin.class, plugin, "Cannot collect samples"); | ||||||
|  |         Map<String, SamplingTestPlugin> samples = ((SamplingTestPlugin) plugin).flatten(); | ||||||
|  |         assertTrue(samples.containsKey("<init>")); // constructor was called | ||||||
|  |         assertPluginClassLoaderAlwaysActive(plugin); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|  | @ -393,7 +402,7 @@ public class PluginsTest { | ||||||
|         assertInstanceOf(SamplingTestPlugin.class, plugin, "Cannot collect samples"); |         assertInstanceOf(SamplingTestPlugin.class, plugin, "Cannot collect samples"); | ||||||
|         Map<String, SamplingTestPlugin> samples = ((SamplingTestPlugin) plugin).flatten(); |         Map<String, SamplingTestPlugin> samples = ((SamplingTestPlugin) plugin).flatten(); | ||||||
|         assertTrue(samples.containsKey("configure")); // Configurable::configure was called |         assertTrue(samples.containsKey("configure")); // Configurable::configure was called | ||||||
|         assertPluginClassLoaderAlwaysActive(samples); |         assertPluginClassLoaderAlwaysActive(plugin); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|  | @ -460,19 +469,23 @@ public class PluginsTest { | ||||||
|                 converter.toConnectData(null, null).value()); |                 converter.toConnectData(null, null).value()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static void assertPluginClassLoaderAlwaysActive(Map<String, SamplingTestPlugin> samples) { |     public static void assertPluginClassLoaderAlwaysActive(Object plugin) { | ||||||
|         for (Entry<String, SamplingTestPlugin> e : samples.entrySet()) { |         assertInstanceOf(SamplingTestPlugin.class, plugin, "Cannot collect samples"); | ||||||
|             String sampleName = "\"" + e.getKey() + "\" (" + e.getValue() + ")"; |         for (SamplingTestPlugin instance : ((SamplingTestPlugin) plugin).allInstances()) { | ||||||
|             assertInstanceOf( |             Map<String, SamplingTestPlugin> samples = instance.flatten(); | ||||||
|                 PluginClassLoader.class, |             for (Entry<String, SamplingTestPlugin> e : samples.entrySet()) { | ||||||
|                 e.getValue().staticClassloader(), |                 String sampleName = "\"" + e.getKey() + "\" (" + e.getValue() + ")"; | ||||||
|                 sampleName + " has incorrect static classloader" |                 assertInstanceOf( | ||||||
|             ); |                         PluginClassLoader.class, | ||||||
|             assertInstanceOf( |                         e.getValue().staticClassloader(), | ||||||
|                 PluginClassLoader.class, |                         sampleName + " has incorrect static classloader" | ||||||
|                 e.getValue().classloader(), |                 ); | ||||||
|                 sampleName + " has incorrect dynamic classloader" |                 assertInstanceOf( | ||||||
|             ); |                         PluginClassLoader.class, | ||||||
|  |                         e.getValue().classloader(), | ||||||
|  |                         sampleName + " has incorrect dynamic classloader" | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -19,36 +19,44 @@ package org.apache.kafka.connect.runtime.isolation; | ||||||
| 
 | 
 | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
|  | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.Map.Entry; | import java.util.Map.Entry; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Base class for plugins so we can sample information about their initialization |  * Base class for plugins so we can sample information about their initialization | ||||||
|  */ |  */ | ||||||
| public abstract class SamplingTestPlugin { | public interface SamplingTestPlugin { | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * @return the ClassLoader used to statically initialize this plugin class |      * @return the ClassLoader used to statically initialize this plugin class | ||||||
|      */ |      */ | ||||||
|     public abstract ClassLoader staticClassloader(); |     ClassLoader staticClassloader(); | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * @return the ClassLoader used to initialize this plugin instance |      * @return the ClassLoader used to initialize this plugin instance | ||||||
|      */ |      */ | ||||||
|     public abstract ClassLoader classloader(); |     ClassLoader classloader(); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * @return All known instances of this class, including this instance. | ||||||
|  |      */ | ||||||
|  |     default List<SamplingTestPlugin> allInstances() { | ||||||
|  |         return Collections.singletonList(this); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * @return a group of other SamplingTestPlugin instances known by this plugin |      * @return a group of other SamplingTestPlugin instances known by this plugin | ||||||
|      * This should only return direct children, and not reference this instance directly |      * This should only return direct children, and not reference this instance directly | ||||||
|      */ |      */ | ||||||
|     public Map<String, SamplingTestPlugin> otherSamples() { |     default Map<String, SamplingTestPlugin> otherSamples() { | ||||||
|         return Collections.emptyMap(); |         return Collections.emptyMap(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * @return a flattened list of child samples including this entry keyed as "this" |      * @return a flattened list of child samples including this entry keyed as "this" | ||||||
|      */ |      */ | ||||||
|     public Map<String, SamplingTestPlugin> flatten() { |     default Map<String, SamplingTestPlugin> flatten() { | ||||||
|         Map<String, SamplingTestPlugin> out = new HashMap<>(); |         Map<String, SamplingTestPlugin> out = new HashMap<>(); | ||||||
|         Map<String, SamplingTestPlugin> otherSamples = otherSamples(); |         Map<String, SamplingTestPlugin> otherSamples = otherSamples(); | ||||||
|         if (otherSamples != null) { |         if (otherSamples != null) { | ||||||
|  | @ -71,7 +79,7 @@ public abstract class SamplingTestPlugin { | ||||||
|      * Stores only the last invocation of each method if there are multiple invocations. |      * Stores only the last invocation of each method if there are multiple invocations. | ||||||
|      * @param samples The collection of samples to which this method call should be added |      * @param samples The collection of samples to which this method call should be added | ||||||
|      */ |      */ | ||||||
|     public void logMethodCall(Map<String, SamplingTestPlugin> samples) { |     default void logMethodCall(Map<String, SamplingTestPlugin> samples) { | ||||||
|         StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace(); |         StackTraceElement[] stackTraces = Thread.currentThread().getStackTrace(); | ||||||
|         if (stackTraces.length < 2) { |         if (stackTraces.length < 2) { | ||||||
|             return; |             return; | ||||||
|  | @ -88,7 +96,7 @@ public abstract class SamplingTestPlugin { | ||||||
|         )); |         )); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static class MethodCallSample extends SamplingTestPlugin { |     class MethodCallSample implements SamplingTestPlugin { | ||||||
| 
 | 
 | ||||||
|         private final StackTraceElement caller; |         private final StackTraceElement caller; | ||||||
|         private final ClassLoader staticClassLoader; |         private final ClassLoader staticClassLoader; | ||||||
|  |  | ||||||
|  | @ -94,6 +94,11 @@ public class TestPlugins { | ||||||
|          * which samples information about its method calls. |          * which samples information about its method calls. | ||||||
|          */ |          */ | ||||||
|         SAMPLING_CONFIG_PROVIDER("sampling-config-provider", "test.plugins.SamplingConfigProvider"), |         SAMPLING_CONFIG_PROVIDER("sampling-config-provider", "test.plugins.SamplingConfigProvider"), | ||||||
|  |         /** | ||||||
|  |          * A {@link org.apache.kafka.connect.sink.SinkConnector} | ||||||
|  |          * which samples information about its method calls. | ||||||
|  |          */ | ||||||
|  |         SAMPLING_CONNECTOR("sampling-connector", "test.plugins.SamplingConnector"), | ||||||
|         /** |         /** | ||||||
|          * A plugin which uses a {@link java.util.ServiceLoader} |          * A plugin which uses a {@link java.util.ServiceLoader} | ||||||
|          * to load internal classes, and samples information about their initialization. |          * to load internal classes, and samples information about their initialization. | ||||||
|  |  | ||||||
|  | @ -30,7 +30,7 @@ import org.apache.kafka.connect.runtime.isolation.SamplingTestPlugin; | ||||||
|  * <p>Samples data about its initialization environment for later analysis. |  * <p>Samples data about its initialization environment for later analysis. | ||||||
|  * Samples are shared between instances of the same class in a static variable. |  * Samples are shared between instances of the same class in a static variable. | ||||||
|  */ |  */ | ||||||
| public class AliasedStaticField extends SamplingTestPlugin implements Converter { | public class AliasedStaticField implements SamplingTestPlugin, Converter { | ||||||
| 
 | 
 | ||||||
|   private static final Map<String, SamplingTestPlugin> SAMPLES; |   private static final Map<String, SamplingTestPlugin> SAMPLES; | ||||||
|   private static final ClassLoader STATIC_CLASS_LOADER; |   private static final ClassLoader STATIC_CLASS_LOADER; | ||||||
|  |  | ||||||
|  | @ -20,7 +20,6 @@ package test.plugins; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import org.apache.kafka.connect.data.Schema; | import org.apache.kafka.connect.data.Schema; | ||||||
| import org.apache.kafka.connect.data.SchemaAndValue; | import org.apache.kafka.connect.data.SchemaAndValue; | ||||||
| import org.apache.kafka.connect.runtime.isolation.SamplingTestPlugin; |  | ||||||
| import org.apache.kafka.connect.storage.Converter; | import org.apache.kafka.connect.storage.Converter; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  |  | ||||||
|  | @ -21,7 +21,6 @@ import java.nio.charset.StandardCharsets; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import org.apache.kafka.connect.data.Schema; | import org.apache.kafka.connect.data.Schema; | ||||||
| import org.apache.kafka.connect.data.SchemaAndValue; | import org.apache.kafka.connect.data.SchemaAndValue; | ||||||
| import org.apache.kafka.connect.runtime.isolation.SamplingTestPlugin; |  | ||||||
| import org.apache.kafka.connect.storage.Converter; | import org.apache.kafka.connect.storage.Converter; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  |  | ||||||
|  | @ -21,7 +21,6 @@ import java.nio.charset.StandardCharsets; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import org.apache.kafka.connect.data.Schema; | import org.apache.kafka.connect.data.Schema; | ||||||
| import org.apache.kafka.connect.data.SchemaAndValue; | import org.apache.kafka.connect.data.SchemaAndValue; | ||||||
| import org.apache.kafka.connect.runtime.isolation.SamplingTestPlugin; |  | ||||||
| import org.apache.kafka.connect.runtime.isolation.TestPlugins; | import org.apache.kafka.connect.runtime.isolation.TestPlugins; | ||||||
| import org.apache.kafka.connect.storage.Converter; | import org.apache.kafka.connect.storage.Converter; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -17,9 +17,13 @@ | ||||||
| 
 | 
 | ||||||
| package test.plugins; | package test.plugins; | ||||||
| 
 | 
 | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
| import java.util.Set; | import java.util.Set; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
|  | 
 | ||||||
| import org.apache.kafka.common.config.provider.ConfigProvider; | import org.apache.kafka.common.config.provider.ConfigProvider; | ||||||
| import org.apache.kafka.common.config.ConfigData; | import org.apache.kafka.common.config.ConfigData; | ||||||
| import org.apache.kafka.common.config.ConfigChangeCallback; | import org.apache.kafka.common.config.ConfigChangeCallback; | ||||||
|  | @ -34,14 +38,16 @@ import org.apache.kafka.connect.storage.HeaderConverter; | ||||||
|  * See {@link org.apache.kafka.connect.runtime.isolation.TestPlugins}. |  * See {@link org.apache.kafka.connect.runtime.isolation.TestPlugins}. | ||||||
|  * <p>Samples data about its initialization environment for later analysis. |  * <p>Samples data about its initialization environment for later analysis. | ||||||
|  */ |  */ | ||||||
| public class SamplingConfigProvider extends SamplingTestPlugin implements ConfigProvider { | public final class SamplingConfigProvider implements SamplingTestPlugin, ConfigProvider { | ||||||
| 
 | 
 | ||||||
|   private static final ClassLoader STATIC_CLASS_LOADER; |   private static final ClassLoader STATIC_CLASS_LOADER; | ||||||
|  |   private static List<SamplingTestPlugin> instances; | ||||||
|   private final ClassLoader classloader; |   private final ClassLoader classloader; | ||||||
|   private Map<String, SamplingTestPlugin> samples; |   private Map<String, SamplingTestPlugin> samples; | ||||||
| 
 | 
 | ||||||
|   static { |   static { | ||||||
|     STATIC_CLASS_LOADER = Thread.currentThread().getContextClassLoader(); |     STATIC_CLASS_LOADER = Thread.currentThread().getContextClassLoader(); | ||||||
|  |     instances = Collections.synchronizedList(new ArrayList<>()); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   { |   { | ||||||
|  | @ -61,6 +67,11 @@ public class SamplingConfigProvider extends SamplingTestPlugin implements Config | ||||||
|     return null; |     return null; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   public SamplingConfigProvider() { | ||||||
|  |     logMethodCall(samples); | ||||||
|  |     instances.add(this); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   @Override |   @Override | ||||||
|   public void subscribe(String path, Set<String> keys, ConfigChangeCallback callback) { |   public void subscribe(String path, Set<String> keys, ConfigChangeCallback callback) { | ||||||
|     logMethodCall(samples); |     logMethodCall(samples); | ||||||
|  | @ -100,4 +111,10 @@ public class SamplingConfigProvider extends SamplingTestPlugin implements Config | ||||||
|   public Map<String, SamplingTestPlugin> otherSamples() { |   public Map<String, SamplingTestPlugin> otherSamples() { | ||||||
|     return samples; |     return samples; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   @Override | ||||||
|  |   public List<SamplingTestPlugin> allInstances() { | ||||||
|  |     return instances; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -17,8 +17,12 @@ | ||||||
| 
 | 
 | ||||||
| package test.plugins; | package test.plugins; | ||||||
| 
 | 
 | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
|  | 
 | ||||||
| import org.apache.kafka.common.Configurable; | import org.apache.kafka.common.Configurable; | ||||||
| import org.apache.kafka.connect.data.Schema; | import org.apache.kafka.connect.data.Schema; | ||||||
| import org.apache.kafka.connect.data.SchemaAndValue; | import org.apache.kafka.connect.data.SchemaAndValue; | ||||||
|  | @ -30,14 +34,16 @@ import org.apache.kafka.connect.runtime.isolation.SamplingTestPlugin; | ||||||
|  * See {@link org.apache.kafka.connect.runtime.isolation.TestPlugins}. |  * See {@link org.apache.kafka.connect.runtime.isolation.TestPlugins}. | ||||||
|  * <p>Samples data about its initialization environment for later analysis. |  * <p>Samples data about its initialization environment for later analysis. | ||||||
|  */ |  */ | ||||||
| public class SamplingConfigurable extends SamplingTestPlugin implements Converter, Configurable { | public final class SamplingConfigurable implements SamplingTestPlugin, Converter, Configurable { | ||||||
| 
 | 
 | ||||||
|   private static final ClassLoader STATIC_CLASS_LOADER; |   private static final ClassLoader STATIC_CLASS_LOADER; | ||||||
|  |   private static List<SamplingTestPlugin> instances; | ||||||
|   private final ClassLoader classloader; |   private final ClassLoader classloader; | ||||||
|   private Map<String, SamplingTestPlugin> samples; |   private Map<String, SamplingTestPlugin> samples; | ||||||
| 
 | 
 | ||||||
|   static { |   static { | ||||||
|     STATIC_CLASS_LOADER = Thread.currentThread().getContextClassLoader(); |     STATIC_CLASS_LOADER = Thread.currentThread().getContextClassLoader(); | ||||||
|  |     instances = Collections.synchronizedList(new ArrayList<>()); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   { |   { | ||||||
|  | @ -45,6 +51,11 @@ public class SamplingConfigurable extends SamplingTestPlugin implements Converte | ||||||
|     classloader = Thread.currentThread().getContextClassLoader(); |     classloader = Thread.currentThread().getContextClassLoader(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   public SamplingConfigurable() { | ||||||
|  |     logMethodCall(samples); | ||||||
|  |     instances.add(this); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   @Override |   @Override | ||||||
|   public void configure(final Map<String, ?> configs) { |   public void configure(final Map<String, ?> configs) { | ||||||
|     logMethodCall(samples); |     logMethodCall(samples); | ||||||
|  | @ -78,4 +89,9 @@ public class SamplingConfigurable extends SamplingTestPlugin implements Converte | ||||||
|   public Map<String, SamplingTestPlugin> otherSamples() { |   public Map<String, SamplingTestPlugin> otherSamples() { | ||||||
|     return samples; |     return samples; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   @Override | ||||||
|  |   public List<SamplingTestPlugin> allInstances() { | ||||||
|  |     return instances; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,112 @@ | ||||||
|  | /* | ||||||
|  |  * 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 test.plugins; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.HashMap; | ||||||
|  | 
 | ||||||
|  | import org.apache.kafka.common.config.ConfigDef; | ||||||
|  | import org.apache.kafka.connect.connector.Task; | ||||||
|  | import org.apache.kafka.connect.sink.SinkConnector; | ||||||
|  | import org.apache.kafka.connect.runtime.isolation.SamplingTestPlugin; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Fake plugin class for testing classloading isolation. | ||||||
|  |  * See {@link org.apache.kafka.connect.runtime.isolation.TestPlugins}. | ||||||
|  |  * <p>Samples data about its initialization environment for later analysis. | ||||||
|  |  */ | ||||||
|  | public final class SamplingConnector extends SinkConnector implements SamplingTestPlugin { | ||||||
|  | 
 | ||||||
|  |   private static final ClassLoader STATIC_CLASS_LOADER; | ||||||
|  |   private static List<SamplingTestPlugin> instances; | ||||||
|  |   private final ClassLoader classloader; | ||||||
|  |   private Map<String, SamplingTestPlugin> samples; | ||||||
|  | 
 | ||||||
|  |   static { | ||||||
|  |     STATIC_CLASS_LOADER = Thread.currentThread().getContextClassLoader(); | ||||||
|  |     instances = Collections.synchronizedList(new ArrayList<>()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   { | ||||||
|  |     samples = new HashMap<>(); | ||||||
|  |     classloader = Thread.currentThread().getContextClassLoader(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public SamplingConnector() { | ||||||
|  |     logMethodCall(samples); | ||||||
|  |     instances.add(this); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @Override | ||||||
|  |   public void start(Map<String, String> props) { | ||||||
|  |     logMethodCall(samples); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @Override | ||||||
|  |   public Class<? extends Task> taskClass() { | ||||||
|  |     logMethodCall(samples); | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @Override | ||||||
|  |   public List<Map<String, String>> taskConfigs(int maxTasks) { | ||||||
|  |     logMethodCall(samples); | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @Override | ||||||
|  |   public void stop() { | ||||||
|  |     logMethodCall(samples); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @Override | ||||||
|  |   public ConfigDef config() { | ||||||
|  |     logMethodCall(samples); | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @Override | ||||||
|  |   public String version() { | ||||||
|  |     logMethodCall(samples); | ||||||
|  |     return "1.0.0"; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @Override | ||||||
|  |   public ClassLoader staticClassloader() { | ||||||
|  |     return STATIC_CLASS_LOADER; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @Override | ||||||
|  |   public ClassLoader classloader() { | ||||||
|  |     return classloader; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @Override | ||||||
|  |   public Map<String, SamplingTestPlugin> otherSamples() { | ||||||
|  |     return samples; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @Override | ||||||
|  |   public List<SamplingTestPlugin> allInstances() { | ||||||
|  |     return instances; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -17,8 +17,12 @@ | ||||||
| 
 | 
 | ||||||
| package test.plugins; | package test.plugins; | ||||||
| 
 | 
 | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
|  | 
 | ||||||
| import org.apache.kafka.connect.data.Schema; | import org.apache.kafka.connect.data.Schema; | ||||||
| import org.apache.kafka.connect.data.SchemaAndValue; | import org.apache.kafka.connect.data.SchemaAndValue; | ||||||
| import org.apache.kafka.connect.storage.Converter; | import org.apache.kafka.connect.storage.Converter; | ||||||
|  | @ -29,14 +33,16 @@ import org.apache.kafka.connect.runtime.isolation.SamplingTestPlugin; | ||||||
|  * See {@link org.apache.kafka.connect.runtime.isolation.TestPlugins}. |  * See {@link org.apache.kafka.connect.runtime.isolation.TestPlugins}. | ||||||
|  * <p>Samples data about its initialization environment for later analysis. |  * <p>Samples data about its initialization environment for later analysis. | ||||||
|  */ |  */ | ||||||
| public class SamplingConverter extends SamplingTestPlugin implements Converter { | public final class SamplingConverter implements SamplingTestPlugin, Converter { | ||||||
| 
 | 
 | ||||||
|   private static final ClassLoader STATIC_CLASS_LOADER; |   private static final ClassLoader STATIC_CLASS_LOADER; | ||||||
|  |   private static List<SamplingTestPlugin> instances; | ||||||
|   private final ClassLoader classloader; |   private final ClassLoader classloader; | ||||||
|   private Map<String, SamplingTestPlugin> samples; |   private Map<String, SamplingTestPlugin> samples; | ||||||
| 
 | 
 | ||||||
|   static { |   static { | ||||||
|     STATIC_CLASS_LOADER = Thread.currentThread().getContextClassLoader(); |     STATIC_CLASS_LOADER = Thread.currentThread().getContextClassLoader(); | ||||||
|  |     instances = Collections.synchronizedList(new ArrayList<>()); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   { |   { | ||||||
|  | @ -44,6 +50,11 @@ public class SamplingConverter extends SamplingTestPlugin implements Converter { | ||||||
|     classloader = Thread.currentThread().getContextClassLoader(); |     classloader = Thread.currentThread().getContextClassLoader(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   public SamplingConverter() { | ||||||
|  |     logMethodCall(samples); | ||||||
|  |     instances.add(this); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   @Override |   @Override | ||||||
|   public void configure(final Map<String, ?> configs, final boolean isKey) { |   public void configure(final Map<String, ?> configs, final boolean isKey) { | ||||||
|     logMethodCall(samples); |     logMethodCall(samples); | ||||||
|  | @ -75,4 +86,9 @@ public class SamplingConverter extends SamplingTestPlugin implements Converter { | ||||||
|   public Map<String, SamplingTestPlugin> otherSamples() { |   public Map<String, SamplingTestPlugin> otherSamples() { | ||||||
|     return samples; |     return samples; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   @Override | ||||||
|  |   public List<SamplingTestPlugin> allInstances() { | ||||||
|  |     return instances; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -17,8 +17,12 @@ | ||||||
| 
 | 
 | ||||||
| package test.plugins; | package test.plugins; | ||||||
| 
 | 
 | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
|  | 
 | ||||||
| import org.apache.kafka.common.config.ConfigDef; | import org.apache.kafka.common.config.ConfigDef; | ||||||
| import org.apache.kafka.connect.data.Schema; | import org.apache.kafka.connect.data.Schema; | ||||||
| import org.apache.kafka.connect.data.SchemaAndValue; | import org.apache.kafka.connect.data.SchemaAndValue; | ||||||
|  | @ -31,14 +35,16 @@ import org.apache.kafka.connect.storage.HeaderConverter; | ||||||
|  * See {@link org.apache.kafka.connect.runtime.isolation.TestPlugins}. |  * See {@link org.apache.kafka.connect.runtime.isolation.TestPlugins}. | ||||||
|  * <p>Samples data about its initialization environment for later analysis. |  * <p>Samples data about its initialization environment for later analysis. | ||||||
|  */ |  */ | ||||||
| public class SamplingHeaderConverter extends SamplingTestPlugin implements HeaderConverter { | public final class SamplingHeaderConverter implements SamplingTestPlugin, HeaderConverter { | ||||||
| 
 | 
 | ||||||
|   private static final ClassLoader STATIC_CLASS_LOADER; |   private static final ClassLoader STATIC_CLASS_LOADER; | ||||||
|  |   private static List<SamplingTestPlugin> instances; | ||||||
|   private final ClassLoader classloader; |   private final ClassLoader classloader; | ||||||
|   private Map<String, SamplingTestPlugin> samples; |   private Map<String, SamplingTestPlugin> samples; | ||||||
| 
 | 
 | ||||||
|   static { |   static { | ||||||
|     STATIC_CLASS_LOADER = Thread.currentThread().getContextClassLoader(); |     STATIC_CLASS_LOADER = Thread.currentThread().getContextClassLoader(); | ||||||
|  |     instances = Collections.synchronizedList(new ArrayList<>()); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   { |   { | ||||||
|  | @ -46,6 +52,11 @@ public class SamplingHeaderConverter extends SamplingTestPlugin implements Heade | ||||||
|     classloader = Thread.currentThread().getContextClassLoader(); |     classloader = Thread.currentThread().getContextClassLoader(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   public SamplingHeaderConverter() { | ||||||
|  |     logMethodCall(samples); | ||||||
|  |     instances.add(this); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   @Override |   @Override | ||||||
|   public SchemaAndValue toConnectHeader(String topic, String headerKey, byte[] value) { |   public SchemaAndValue toConnectHeader(String topic, String headerKey, byte[] value) { | ||||||
|     logMethodCall(samples); |     logMethodCall(samples); | ||||||
|  | @ -88,4 +99,9 @@ public class SamplingHeaderConverter extends SamplingTestPlugin implements Heade | ||||||
|   public Map<String, SamplingTestPlugin> otherSamples() { |   public Map<String, SamplingTestPlugin> otherSamples() { | ||||||
|     return samples; |     return samples; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   @Override | ||||||
|  |   public List<SamplingTestPlugin> allInstances() { | ||||||
|  |     return instances; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -22,7 +22,7 @@ import org.apache.kafka.connect.runtime.isolation.SamplingTestPlugin; | ||||||
| /** | /** | ||||||
|  * Superclass for service loaded classes |  * Superclass for service loaded classes | ||||||
|  */ |  */ | ||||||
| public class ServiceLoadedClass extends SamplingTestPlugin { | public class ServiceLoadedClass implements SamplingTestPlugin { | ||||||
| 
 | 
 | ||||||
|   private static final ClassLoader STATIC_CLASS_LOADER; |   private static final ClassLoader STATIC_CLASS_LOADER; | ||||||
|   private final ClassLoader classloader; |   private final ClassLoader classloader; | ||||||
|  |  | ||||||
|  | @ -31,7 +31,7 @@ import org.apache.kafka.connect.runtime.isolation.SamplingTestPlugin; | ||||||
|  * See {@link org.apache.kafka.connect.runtime.isolation.TestPlugins}. |  * See {@link org.apache.kafka.connect.runtime.isolation.TestPlugins}. | ||||||
|  * <p>Samples data about its initialization environment for later analysis. |  * <p>Samples data about its initialization environment for later analysis. | ||||||
|  */ |  */ | ||||||
| public class ServiceLoaderPlugin extends SamplingTestPlugin implements Converter { | public class ServiceLoaderPlugin implements SamplingTestPlugin, Converter { | ||||||
| 
 | 
 | ||||||
|   private static final ClassLoader STATIC_CLASS_LOADER; |   private static final ClassLoader STATIC_CLASS_LOADER; | ||||||
|   private static final Map<String, SamplingTestPlugin> SAMPLES; |   private static final Map<String, SamplingTestPlugin> SAMPLES; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue