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,7 +469,10 @@ 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) {
|
||||||
|
assertInstanceOf(SamplingTestPlugin.class, plugin, "Cannot collect samples");
|
||||||
|
for (SamplingTestPlugin instance : ((SamplingTestPlugin) plugin).allInstances()) {
|
||||||
|
Map<String, SamplingTestPlugin> samples = instance.flatten();
|
||||||
for (Entry<String, SamplingTestPlugin> e : samples.entrySet()) {
|
for (Entry<String, SamplingTestPlugin> e : samples.entrySet()) {
|
||||||
String sampleName = "\"" + e.getKey() + "\" (" + e.getValue() + ")";
|
String sampleName = "\"" + e.getKey() + "\" (" + e.getValue() + ")";
|
||||||
assertInstanceOf(
|
assertInstanceOf(
|
||||||
|
|
@ -475,6 +487,7 @@ public class PluginsTest {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void assertInstanceOf(Class<?> expected, Object actual, String message) {
|
public static void assertInstanceOf(Class<?> expected, Object actual, String message) {
|
||||||
assertTrue(
|
assertTrue(
|
||||||
|
|
|
||||||
|
|
@ -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