mirror of https://github.com/apache/cassandra
Verify extension type before initializing reflectively-loaded classes
Cassandra resolves pluggable extensions by class name from configuration, schema, and tooling inputs. These names were loaded with an initializing Class.forName(name) and type-checked only afterward, so the named class ran its static initializer before its type was confirmed. After this change such classes will be loaded without initialization, verified against the expected interface or base class, and initialized only through normal use after validation. A shared FBUtilities.classForNameWithoutInitialization helper and typed instanceOrConstruct/construct overloads apply this to the configurable extension points loaded by class name: the authentication, authorization, role-management, network and internode-authenticator backends, the partitioner, audit logger, configuration loader, seed provider, snitch, abstract types, secondary and custom indexes, compaction strategy, compressor, replication strategy, SASI analyzers, key and cache providers, query handler, storage and stream hooks, tracing, the JMX authorization proxy, MBeans, the monotonic clock, nodetool Sjk, triggers, the sstableloader and stress class options, and diagnostic event classes (loaded without initialization and checked against DiagnosticEvent, preserving the InvalidClassException contract and the existing package restriction). Regression tests confirm that an invalid-type load is rejected without initializing the target class, and that valid implementations still resolve. Hadoop client integration and hard-coded JDK and internal class probes are left unchanged. patch by Jeremiah Jordan; reviewed by Stefan Miklosovic for CASSANDRA-21525
This commit is contained in:
parent
33c1dbe5b8
commit
26d7b166ba
|
|
@ -1,4 +1,5 @@
|
|||
4.0.21
|
||||
* Verify extension type before initializing reflectively-loaded classes (CASSANDRA-21525)
|
||||
* Rename conflicting nodetool import --copy-data short option from -p to -cd (CASSANDRA-20214)
|
||||
* Fix PasswordObfuscator failing to obfuscate certain passwords (CASSANDRA-21113)
|
||||
* Fix negative memtable allocator ownership when an update is shadowed by an existing row deletion (CASSANDRA-21469)
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ public final class AuthConfig
|
|||
// authenticator
|
||||
|
||||
if (conf.internode_authenticator != null)
|
||||
DatabaseDescriptor.setInternodeAuthenticator(FBUtilities.construct(conf.internode_authenticator, "internode_authenticator"));
|
||||
DatabaseDescriptor.setInternodeAuthenticator(FBUtilities.construct(conf.internode_authenticator, "internode_authenticator", IInternodeAuthenticator.class));
|
||||
|
||||
// network authorizer
|
||||
INetworkAuthorizer networkAuthorizer = FBUtilities.newNetworkAuthorizer(conf.network_authorizer);
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ public class DatabaseDescriptor
|
|||
String loaderClass = System.getProperty(Config.PROPERTY_PREFIX + "config.loader");
|
||||
ConfigurationLoader loader = loaderClass == null
|
||||
? new YamlConfigurationLoader()
|
||||
: FBUtilities.construct(loaderClass, "configuration loading");
|
||||
: FBUtilities.construct(loaderClass, "configuration loading", ConfigurationLoader.class);
|
||||
Config config = loader.loadConfig();
|
||||
|
||||
if (!hasLoggedConfig)
|
||||
|
|
@ -1036,8 +1036,9 @@ public class DatabaseDescriptor
|
|||
}
|
||||
try
|
||||
{
|
||||
Class<?> seedProviderClass = Class.forName(conf.seed_provider.class_name);
|
||||
seedProvider = (SeedProvider)seedProviderClass.getConstructor(Map.class).newInstance(conf.seed_provider.parameters);
|
||||
Class<? extends SeedProvider> seedProviderClass =
|
||||
FBUtilities.classForNameWithoutInitialization(conf.seed_provider.class_name, "seed provider", SeedProvider.class);
|
||||
seedProvider = seedProviderClass.getConstructor(Map.class).newInstance(conf.seed_provider.parameters);
|
||||
}
|
||||
// there are about 5 checked exceptions that could be thrown here.
|
||||
catch (Exception e)
|
||||
|
|
@ -1243,7 +1244,7 @@ public class DatabaseDescriptor
|
|||
{
|
||||
if (!snitchClassName.contains("."))
|
||||
snitchClassName = "org.apache.cassandra.locator." + snitchClassName;
|
||||
IEndpointSnitch snitch = FBUtilities.construct(snitchClassName, "snitch");
|
||||
IEndpointSnitch snitch = FBUtilities.construct(snitchClassName, "snitch", IEndpointSnitch.class);
|
||||
return dynamic ? new DynamicEndpointSnitch(snitch) : snitch;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public interface StorageHook
|
|||
String className = System.getProperty("cassandra.storage_hook");
|
||||
if (className != null)
|
||||
{
|
||||
return FBUtilities.construct(className, StorageHook.class.getSimpleName());
|
||||
return FBUtilities.construct(className, StorageHook.class.getSimpleName(), StorageHook.class);
|
||||
}
|
||||
|
||||
return new StorageHook()
|
||||
|
|
|
|||
|
|
@ -353,8 +353,7 @@ public class TypeParser
|
|||
|
||||
private static AbstractType<?> getAbstractType(String compareWith) throws ConfigurationException
|
||||
{
|
||||
String className = compareWith.contains(".") ? compareWith : "org.apache.cassandra.db.marshal." + compareWith;
|
||||
Class<? extends AbstractType<?>> typeClass = FBUtilities.<AbstractType<?>>classForName(className, "abstract-type");
|
||||
Class<? extends AbstractType<?>> typeClass = getAbstractTypeClass(compareWith);
|
||||
try
|
||||
{
|
||||
Field field = typeClass.getDeclaredField("instance");
|
||||
|
|
@ -367,10 +366,22 @@ public class TypeParser
|
|||
}
|
||||
}
|
||||
|
||||
private static AbstractType<?> getAbstractType(String compareWith, TypeParser parser) throws SyntaxException, ConfigurationException
|
||||
private static Class<? extends AbstractType<?>> getAbstractTypeClass(String compareWith) throws ConfigurationException
|
||||
{
|
||||
String className = compareWith.contains(".") ? compareWith : "org.apache.cassandra.db.marshal." + compareWith;
|
||||
Class<? extends AbstractType<?>> typeClass = FBUtilities.<AbstractType<?>>classForName(className, "abstract-type");
|
||||
// Defer class initialization until after confirming this is an AbstractType. The static instance field
|
||||
// access or getInstance(TypeParser) invocation below performs the initialization for valid types.
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends AbstractType<?>> typeClass =
|
||||
(Class<? extends AbstractType<?>>) FBUtilities.classForNameWithoutInitialization(className,
|
||||
"abstract-type",
|
||||
AbstractType.class);
|
||||
return typeClass;
|
||||
}
|
||||
|
||||
private static AbstractType<?> getAbstractType(String compareWith, TypeParser parser) throws SyntaxException, ConfigurationException
|
||||
{
|
||||
Class<? extends AbstractType<?>> typeClass = getAbstractTypeClass(compareWith);
|
||||
try
|
||||
{
|
||||
Method method = typeClass.getDeclaredMethod("getInstance", TypeParser.class);
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ public final class DiagnosticEventPersistence
|
|||
LastEventIdBroadcaster.instance().setLastEventId(event.getClass().getName(), store.getLastEventId());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class<DiagnosticEvent> getEventClass(String eventClazz) throws ClassNotFoundException, InvalidClassException
|
||||
{
|
||||
// get class by eventClazz argument name
|
||||
|
|
@ -136,12 +137,13 @@ public final class DiagnosticEventPersistence
|
|||
if (!eventClazz.startsWith("org.apache.cassandra."))
|
||||
throw new RuntimeException("Not a Cassandra event class: " + eventClazz);
|
||||
|
||||
Class<DiagnosticEvent> clazz = (Class<DiagnosticEvent>) Class.forName(eventClazz);
|
||||
// Load without initialization so the type can be verified before the class's static initializer runs.
|
||||
Class<?> clazz = Class.forName(eventClazz, false, DiagnosticEventPersistence.class.getClassLoader());
|
||||
|
||||
if (!(DiagnosticEvent.class.isAssignableFrom(clazz)))
|
||||
throw new InvalidClassException("Event class must be of type DiagnosticEvent");
|
||||
|
||||
return clazz;
|
||||
return (Class<DiagnosticEvent>) clazz.asSubclass(DiagnosticEvent.class);
|
||||
}
|
||||
|
||||
private DiagnosticEventStore<Long> getStore(Class cls)
|
||||
|
|
|
|||
|
|
@ -767,6 +767,11 @@ public class SecondaryIndexManager implements IndexRegistry, INotificationConsum
|
|||
return indexes.get(indexName);
|
||||
}
|
||||
|
||||
static Class<? extends Index> loadIndexClass(String className)
|
||||
{
|
||||
return FBUtilities.classForNameWithoutInitialization(className, "Index", Index.class);
|
||||
}
|
||||
|
||||
private Index createInstance(IndexMetadata indexDef)
|
||||
{
|
||||
Index newIndex;
|
||||
|
|
@ -777,7 +782,7 @@ public class SecondaryIndexManager implements IndexRegistry, INotificationConsum
|
|||
assert !Strings.isNullOrEmpty(className);
|
||||
try
|
||||
{
|
||||
Class<? extends Index> indexClass = FBUtilities.classForName(className, "Index");
|
||||
Class<? extends Index> indexClass = loadIndexClass(className);
|
||||
Constructor<? extends Index> ctor = indexClass.getConstructor(ColumnFamilyStore.class, IndexMetadata.class);
|
||||
newIndex = ctor.newInstance(baseCfs, indexDef);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import org.apache.cassandra.db.marshal.UTF8Type;
|
|||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.index.sasi.plan.Expression.Op;
|
||||
import org.apache.cassandra.schema.IndexMetadata;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -60,10 +61,10 @@ public class IndexMode
|
|||
|
||||
public final Mode mode;
|
||||
public final boolean isAnalyzed, isLiteral;
|
||||
public final Class analyzerClass;
|
||||
public final Class<? extends AbstractAnalyzer> analyzerClass;
|
||||
public final long maxCompactionFlushMemoryInBytes;
|
||||
|
||||
private IndexMode(Mode mode, boolean isLiteral, boolean isAnalyzed, Class analyzerClass, long maxMemBytes)
|
||||
private IndexMode(Mode mode, boolean isLiteral, boolean isAnalyzed, Class<? extends AbstractAnalyzer> analyzerClass, long maxMemBytes)
|
||||
{
|
||||
this.mode = mode;
|
||||
this.isLiteral = isLiteral;
|
||||
|
|
@ -81,7 +82,7 @@ public class IndexMode
|
|||
if (isAnalyzed)
|
||||
{
|
||||
if (analyzerClass != null)
|
||||
analyzer = (AbstractAnalyzer) analyzerClass.newInstance();
|
||||
analyzer = analyzerClass.newInstance();
|
||||
else if (TOKENIZABLE_TYPES.contains(validator))
|
||||
analyzer = new StandardAnalyzer();
|
||||
}
|
||||
|
|
@ -99,21 +100,14 @@ public class IndexMode
|
|||
// validate that a valid analyzer class was provided if specified
|
||||
if (indexOptions.containsKey(INDEX_ANALYZER_CLASS_OPTION))
|
||||
{
|
||||
Class<?> analyzerClass;
|
||||
try
|
||||
{
|
||||
analyzerClass = Class.forName(indexOptions.get(INDEX_ANALYZER_CLASS_OPTION));
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
throw new ConfigurationException(String.format("Invalid analyzer class option specified [%s]",
|
||||
indexOptions.get(INDEX_ANALYZER_CLASS_OPTION)));
|
||||
}
|
||||
Class<? extends AbstractAnalyzer> analyzerClass = FBUtilities.classForNameWithoutInitialization(indexOptions.get(INDEX_ANALYZER_CLASS_OPTION),
|
||||
"analyzer",
|
||||
AbstractAnalyzer.class);
|
||||
|
||||
AbstractAnalyzer analyzer;
|
||||
try
|
||||
{
|
||||
analyzer = (AbstractAnalyzer) analyzerClass.newInstance();
|
||||
analyzer = analyzerClass.newInstance();
|
||||
analyzer.validate(indexOptions, cd);
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
|
|
@ -148,25 +142,30 @@ public class IndexMode
|
|||
}
|
||||
|
||||
boolean isAnalyzed = false;
|
||||
Class analyzerClass = null;
|
||||
try
|
||||
Class<? extends AbstractAnalyzer> analyzerClass = null;
|
||||
if (indexOptions.get(INDEX_ANALYZER_CLASS_OPTION) != null)
|
||||
{
|
||||
if (indexOptions.get(INDEX_ANALYZER_CLASS_OPTION) != null)
|
||||
try
|
||||
{
|
||||
analyzerClass = Class.forName(indexOptions.get(INDEX_ANALYZER_CLASS_OPTION));
|
||||
analyzerClass = FBUtilities.classForNameWithoutInitialization(indexOptions.get(INDEX_ANALYZER_CLASS_OPTION),
|
||||
"analyzer",
|
||||
AbstractAnalyzer.class);
|
||||
isAnalyzed = indexOptions.get(INDEX_ANALYZED_OPTION) == null
|
||||
? true : Boolean.parseBoolean(indexOptions.get(INDEX_ANALYZED_OPTION));
|
||||
? true : Boolean.parseBoolean(indexOptions.get(INDEX_ANALYZED_OPTION));
|
||||
}
|
||||
else if (indexOptions.get(INDEX_ANALYZED_OPTION) != null)
|
||||
catch (ConfigurationException e)
|
||||
{
|
||||
isAnalyzed = Boolean.parseBoolean(indexOptions.get(INDEX_ANALYZED_OPTION));
|
||||
if (!(e.getCause() instanceof ClassNotFoundException))
|
||||
throw e;
|
||||
|
||||
// Should not happen as we already validated we could instantiate an instance in validateAnalyzer().
|
||||
logger.error("Failed to find specified analyzer class [{}]. Falling back to default analyzer",
|
||||
indexOptions.get(INDEX_ANALYZER_CLASS_OPTION));
|
||||
}
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
else if (indexOptions.get(INDEX_ANALYZED_OPTION) != null)
|
||||
{
|
||||
// should not happen as we already validated we could instantiate an instance in validateAnalyzer()
|
||||
logger.error("Failed to find specified analyzer class [{}]. Falling back to default analyzer",
|
||||
indexOptions.get(INDEX_ANALYZER_CLASS_OPTION));
|
||||
isAnalyzed = Boolean.parseBoolean(indexOptions.get(INDEX_ANALYZED_OPTION));
|
||||
}
|
||||
|
||||
boolean isLiteral = false;
|
||||
|
|
|
|||
|
|
@ -405,11 +405,11 @@ public abstract class AbstractReplicationStrategy
|
|||
if ("org.apache.cassandra.locator.OldNetworkTopologyStrategy".equals(className)) // see CASSANDRA-16301
|
||||
throw new ConfigurationException("The support for the OldNetworkTopologyStrategy has been removed in C* version 4.0. The keyspace strategy should be switch to NetworkTopologyStrategy");
|
||||
|
||||
Class<AbstractReplicationStrategy> strategyClass = FBUtilities.classForName(className, "replication strategy");
|
||||
if (!AbstractReplicationStrategy.class.isAssignableFrom(strategyClass))
|
||||
{
|
||||
throw new ConfigurationException(String.format("Specified replication strategy class (%s) is not derived from AbstractReplicationStrategy", className));
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<AbstractReplicationStrategy> strategyClass =
|
||||
(Class<AbstractReplicationStrategy>) FBUtilities.classForNameWithoutInitialization(className,
|
||||
"replication strategy",
|
||||
AbstractReplicationStrategy.class);
|
||||
return strategyClass;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -277,15 +277,7 @@ public final class CompactionParams
|
|||
String className = name.contains(".")
|
||||
? name
|
||||
: "org.apache.cassandra.db.compaction." + name;
|
||||
Class<AbstractCompactionStrategy> strategyClass = FBUtilities.classForName(className, "compaction strategy");
|
||||
|
||||
if (!AbstractCompactionStrategy.class.isAssignableFrom(strategyClass))
|
||||
{
|
||||
throw new ConfigurationException(format("Compaction strategy class %s is not derived from AbstractReplicationStrategy",
|
||||
className));
|
||||
}
|
||||
|
||||
return strategyClass;
|
||||
return FBUtilities.classForNameWithoutInitialization(className, "compaction strategy", AbstractCompactionStrategy.class);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import org.apache.cassandra.io.compress.*;
|
|||
import org.apache.cassandra.io.util.DataInputPlus;
|
||||
import org.apache.cassandra.io.util.DataOutputPlus;
|
||||
import org.apache.cassandra.net.MessagingService;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
|
|
@ -273,7 +274,7 @@ public final class CompressionParams
|
|||
return maxCompressedLength;
|
||||
}
|
||||
|
||||
private static Class<?> parseCompressorClass(String className) throws ConfigurationException
|
||||
private static Class<? extends ICompressor> parseCompressorClass(String className) throws ConfigurationException
|
||||
{
|
||||
if (className == null || className.isEmpty())
|
||||
return null;
|
||||
|
|
@ -281,15 +282,17 @@ public final class CompressionParams
|
|||
className = className.contains(".") ? className : "org.apache.cassandra.io.compress." + className;
|
||||
try
|
||||
{
|
||||
return Class.forName(className);
|
||||
return FBUtilities.classForNameWithoutInitialization(className, "compression", ICompressor.class);
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (ConfigurationException e)
|
||||
{
|
||||
throw new ConfigurationException("Could not create Compression for type " + className, e);
|
||||
if (e.getCause() instanceof ClassNotFoundException || e.getCause() instanceof NoClassDefFoundError)
|
||||
throw new ConfigurationException("Could not create Compression for type " + className, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static ICompressor createCompressor(Class<?> compressorClass, Map<String, String> compressionOptions) throws ConfigurationException
|
||||
private static ICompressor createCompressor(Class<? extends ICompressor> compressorClass, Map<String, String> compressionOptions) throws ConfigurationException
|
||||
{
|
||||
if (compressorClass == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -117,9 +117,7 @@ public final class IndexMetadata
|
|||
throw new ConfigurationException(String.format("Required option missing for index %s : %s",
|
||||
name, IndexTarget.CUSTOM_INDEX_OPTION_NAME));
|
||||
String className = options.get(IndexTarget.CUSTOM_INDEX_OPTION_NAME);
|
||||
Class<Index> indexerClass = FBUtilities.classForName(className, "custom indexer");
|
||||
if (!Index.class.isAssignableFrom(indexerClass))
|
||||
throw new ConfigurationException(String.format("Specified Indexer class (%s) does not implement the Indexer interface", className));
|
||||
Class<? extends Index> indexerClass = FBUtilities.classForNameWithoutInitialization(className, "custom indexer", Index.class);
|
||||
validateCustomIndexOptions(table, indexerClass, options);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import io.netty.util.concurrent.FastThreadLocal;
|
||||
import org.apache.cassandra.config.TransparentDataEncryptionOptions;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
/**
|
||||
* A factory for loading encryption keys from {@link KeyProvider} instances.
|
||||
|
|
@ -70,9 +71,10 @@ public class CipherFactory
|
|||
try
|
||||
{
|
||||
secureRandom = SecureRandom.getInstance("SHA1PRNG");
|
||||
Class<KeyProvider> keyProviderClass = (Class<KeyProvider>)Class.forName(options.key_provider.class_name);
|
||||
Constructor ctor = keyProviderClass.getConstructor(TransparentDataEncryptionOptions.class);
|
||||
keyProvider = (KeyProvider)ctor.newInstance(options);
|
||||
Class<? extends KeyProvider> keyProviderClass =
|
||||
FBUtilities.classForNameWithoutInitialization(options.key_provider.class_name, "key provider", KeyProvider.class);
|
||||
Constructor<? extends KeyProvider> ctor = keyProviderClass.getConstructor(TransparentDataEncryptionOptions.class);
|
||||
keyProvider = ctor.newInstance(options);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -129,9 +129,11 @@ public class CacheService implements CacheServiceMBean
|
|||
? DatabaseDescriptor.getRowCacheClassName() : "org.apache.cassandra.cache.NopCacheProvider";
|
||||
try
|
||||
{
|
||||
Class<CacheProvider<RowCacheKey, IRowCacheEntry>> cacheProviderClass =
|
||||
(Class<CacheProvider<RowCacheKey, IRowCacheEntry>>) Class.forName(cacheProviderClassName);
|
||||
cacheProvider = cacheProviderClass.newInstance();
|
||||
Class<? extends CacheProvider> cacheProviderClass =
|
||||
FBUtilities.classForNameWithoutInitialization(cacheProviderClassName, "row cache provider", CacheProvider.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
CacheProvider<RowCacheKey, IRowCacheEntry> typedCacheProvider = cacheProviderClass.newInstance();
|
||||
cacheProvider = typedCacheProvider;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ public class ClientState
|
|||
{
|
||||
try
|
||||
{
|
||||
handler = FBUtilities.construct(customHandlerClass, "QueryHandler");
|
||||
handler = FBUtilities.construct(customHandlerClass, "QueryHandler", QueryHandler.class);
|
||||
logger.info("Using {} as query handler for native protocol queries (as requested with -Dcassandra.custom_query_handler_class)", customHandlerClass);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ public interface StreamHook
|
|||
String className = System.getProperty("cassandra.stream_hook");
|
||||
if (className != null)
|
||||
{
|
||||
return FBUtilities.construct(className, StreamHook.class.getSimpleName());
|
||||
return FBUtilities.construct(className, StreamHook.class.getSimpleName(), StreamHook.class);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import org.apache.cassandra.config.*;
|
|||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.locator.InetAddressAndPort;
|
||||
import org.apache.cassandra.tools.BulkLoader.CmdLineOptions;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
import com.datastax.driver.core.AuthProvider;
|
||||
import com.datastax.driver.core.PlainTextAuthProvider;
|
||||
|
|
@ -551,11 +552,12 @@ public class LoaderOptions
|
|||
{
|
||||
try
|
||||
{
|
||||
Class authProviderClass = Class.forName(authProviderName);
|
||||
Constructor constructor = authProviderClass.getConstructor(String.class, String.class);
|
||||
authProvider = (AuthProvider)constructor.newInstance(user, passwd);
|
||||
Class<? extends AuthProvider> authProviderClass =
|
||||
FBUtilities.classForNameWithoutInitialization(authProviderName, "auth provider", AuthProvider.class);
|
||||
Constructor<? extends AuthProvider> constructor = authProviderClass.getConstructor(String.class, String.class);
|
||||
authProvider = constructor.newInstance(user, passwd);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
catch (ConfigurationException e)
|
||||
{
|
||||
errorMsg("Unknown auth provider: " + e.getMessage(), getCmdLineOptions());
|
||||
}
|
||||
|
|
@ -582,9 +584,9 @@ public class LoaderOptions
|
|||
{
|
||||
try
|
||||
{
|
||||
authProvider = (AuthProvider)Class.forName(authProviderName).newInstance();
|
||||
authProvider = FBUtilities.construct(authProviderName, "auth provider", AuthProvider.class);
|
||||
}
|
||||
catch (ClassNotFoundException | InstantiationException | IllegalAccessException e)
|
||||
catch (ConfigurationException e)
|
||||
{
|
||||
errorMsg("Unknown auth provider: " + e.getMessage(), getCmdLineOptions());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -405,6 +405,7 @@ public class Sjk extends NodeToolCmd
|
|||
List<Class<?>> result = new ArrayList<>();
|
||||
try
|
||||
{
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
String path = packageName.replace('.', '/');
|
||||
for (String f : findFiles(path))
|
||||
{
|
||||
|
|
@ -412,7 +413,7 @@ public class Sjk extends NodeToolCmd
|
|||
{
|
||||
f = f.substring(0, f.length() - ".class".length());
|
||||
f = f.replace('/', '.');
|
||||
result.add(Class.forName(f));
|
||||
result.add(Class.forName(f, false, cl));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ public abstract class Tracing implements ExecutorLocal<TraceState>
|
|||
{
|
||||
try
|
||||
{
|
||||
tracing = FBUtilities.construct(customTracingClass, "Tracing");
|
||||
tracing = FBUtilities.construct(customTracingClass, "Tracing", Tracing.class);
|
||||
logger.info("Using {} as tracing queries (as requested with -Dcassandra.custom_tracing_class)", customTracingClass);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import org.apache.cassandra.cql3.QueryProcessor;
|
|||
import org.apache.cassandra.db.*;
|
||||
import org.apache.cassandra.db.partitions.PartitionUpdate;
|
||||
import org.apache.cassandra.exceptions.CassandraException;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.schema.TableId;
|
||||
import org.apache.cassandra.schema.TriggerMetadata;
|
||||
|
|
@ -252,11 +253,26 @@ public class TriggerExecutor
|
|||
}
|
||||
}
|
||||
|
||||
public synchronized Class<? extends ITrigger> loadTriggerClass(String triggerClass) throws Exception
|
||||
{
|
||||
// Load without initialization so the type can be verified before the class's static initializer runs.
|
||||
try
|
||||
{
|
||||
return FBUtilities.classForNameWithoutInitialization(triggerClass, "trigger", ITrigger.class, customClassLoader);
|
||||
}
|
||||
catch (ConfigurationException e)
|
||||
{
|
||||
if (e.getCause() instanceof ClassNotFoundException)
|
||||
throw (ClassNotFoundException) e.getCause();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized ITrigger loadTriggerInstance(String triggerClass) throws Exception
|
||||
{
|
||||
// double check.
|
||||
if (cachedTriggers.get(triggerClass) != null)
|
||||
return cachedTriggers.get(triggerClass);
|
||||
return (ITrigger) customClassLoader.loadClass(triggerClass).getConstructor().newInstance();
|
||||
return loadTriggerClass(triggerClass).getConstructor().newInstance();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -634,28 +634,28 @@ public class FBUtilities
|
|||
assert comparator.isPresent() : "Expected a comparator for local partitioner";
|
||||
return new LocalPartitioner(comparator.get());
|
||||
}
|
||||
return FBUtilities.instanceOrConstruct(partitionerClassName, "partitioner");
|
||||
return FBUtilities.instanceOrConstruct(partitionerClassName, "partitioner", IPartitioner.class);
|
||||
}
|
||||
|
||||
public static IAuthorizer newAuthorizer(String className) throws ConfigurationException
|
||||
{
|
||||
if (!className.contains("."))
|
||||
className = "org.apache.cassandra.auth." + className;
|
||||
return FBUtilities.construct(className, "authorizer");
|
||||
return FBUtilities.construct(className, "authorizer", IAuthorizer.class);
|
||||
}
|
||||
|
||||
public static IAuthenticator newAuthenticator(String className) throws ConfigurationException
|
||||
{
|
||||
if (!className.contains("."))
|
||||
className = "org.apache.cassandra.auth." + className;
|
||||
return FBUtilities.construct(className, "authenticator");
|
||||
return FBUtilities.construct(className, "authenticator", IAuthenticator.class);
|
||||
}
|
||||
|
||||
public static IRoleManager newRoleManager(String className) throws ConfigurationException
|
||||
{
|
||||
if (!className.contains("."))
|
||||
className = "org.apache.cassandra.auth." + className;
|
||||
return FBUtilities.construct(className, "role manager");
|
||||
return FBUtilities.construct(className, "role manager", IRoleManager.class);
|
||||
}
|
||||
|
||||
public static INetworkAuthorizer newNetworkAuthorizer(String className)
|
||||
|
|
@ -668,9 +668,9 @@ public class FBUtilities
|
|||
{
|
||||
className = "org.apache.cassandra.auth." + className;
|
||||
}
|
||||
return FBUtilities.construct(className, "network authorizer");
|
||||
return FBUtilities.construct(className, "network authorizer", INetworkAuthorizer.class);
|
||||
}
|
||||
|
||||
|
||||
public static IAuditLogger newAuditLogger(String className, Map<String, String> parameters) throws ConfigurationException
|
||||
{
|
||||
if (!className.contains("."))
|
||||
|
|
@ -678,8 +678,9 @@ public class FBUtilities
|
|||
|
||||
try
|
||||
{
|
||||
Class<?> auditLoggerClass = Class.forName(className);
|
||||
return (IAuditLogger) auditLoggerClass.getConstructor(Map.class).newInstance(parameters);
|
||||
Class<? extends IAuditLogger> auditLoggerClass =
|
||||
FBUtilities.classForNameWithoutInitialization(className, "Audit logger", IAuditLogger.class);
|
||||
return auditLoggerClass.getConstructor(Map.class).newInstance(parameters);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -694,7 +695,7 @@ public class FBUtilities
|
|||
|
||||
try
|
||||
{
|
||||
FBUtilities.classForName(className, "Audit logger");
|
||||
FBUtilities.classForNameWithoutInitialization(className, "Audit logger", IAuditLogger.class);
|
||||
}
|
||||
catch (ConfigurationException e)
|
||||
{
|
||||
|
|
@ -704,6 +705,8 @@ public class FBUtilities
|
|||
}
|
||||
|
||||
/**
|
||||
* Loads and initializes a class.
|
||||
*
|
||||
* @return The Class for the given name.
|
||||
* @param classname Fully qualified classname.
|
||||
* @param readable Descriptive noun for the role the class plays.
|
||||
|
|
@ -721,6 +724,53 @@ public class FBUtilities
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a class without initializing it, then verifies it extends or implements the expected base type.
|
||||
*
|
||||
* @return The Class for the given name.
|
||||
* @param classname Fully qualified classname.
|
||||
* @param readable Descriptive noun for the role the class plays.
|
||||
* @param expectedType Required superclass or interface.
|
||||
* @throws ConfigurationException If the class cannot be found or is not assignable to {@code expectedType}.
|
||||
*/
|
||||
public static <T> Class<? extends T> classForNameWithoutInitialization(String classname,
|
||||
String readable,
|
||||
Class<T> expectedType) throws ConfigurationException
|
||||
{
|
||||
return classForNameWithoutInitialization(classname, readable, expectedType, FBUtilities.class.getClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a class without initializing it, then verifies it extends or implements the expected base type.
|
||||
*
|
||||
* @return The Class for the given name.
|
||||
* @param classname Fully qualified classname.
|
||||
* @param readable Descriptive noun for the role the class plays.
|
||||
* @param expectedType Required superclass or interface.
|
||||
* @param classLoader ClassLoader to use.
|
||||
* @throws ConfigurationException If the class cannot be found or is not assignable to {@code expectedType}.
|
||||
*/
|
||||
public static <T> Class<? extends T> classForNameWithoutInitialization(String classname,
|
||||
String readable,
|
||||
Class<T> expectedType,
|
||||
ClassLoader classLoader) throws ConfigurationException
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<?> klass = Class.forName(classname, false, classLoader);
|
||||
if (!expectedType.isAssignableFrom(klass))
|
||||
throw new ConfigurationException(String.format("Invalid %s class '%s': must extend or implement %s",
|
||||
readable,
|
||||
classname,
|
||||
expectedType.getName()));
|
||||
return klass.asSubclass(expectedType);
|
||||
}
|
||||
catch (ClassNotFoundException | NoClassDefFoundError e)
|
||||
{
|
||||
throw new ConfigurationException(String.format("Unable to find %s class '%s'", readable, classname), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the given class, which must have a no-arg or default constructor.
|
||||
* @param classname Fully qualified classname.
|
||||
|
|
@ -730,6 +780,25 @@ public class FBUtilities
|
|||
public static <T> T instanceOrConstruct(String classname, String readable) throws ConfigurationException
|
||||
{
|
||||
Class<T> cls = FBUtilities.classForName(classname, readable);
|
||||
return instanceOrConstruct(cls, classname, readable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the given class, or gets its static {@code instance} field, after verifying the
|
||||
* class without initializing it.
|
||||
* @param classname Fully qualified classname.
|
||||
* @param readable Descriptive noun for the role the class plays.
|
||||
* @param expectedType Required superclass or interface.
|
||||
* @throws ConfigurationException If the class cannot be found or is not assignable to {@code expectedType}.
|
||||
*/
|
||||
public static <T> T instanceOrConstruct(String classname, String readable, Class<T> expectedType) throws ConfigurationException
|
||||
{
|
||||
Class<? extends T> cls = FBUtilities.classForNameWithoutInitialization(classname, readable, expectedType);
|
||||
return instanceOrConstruct(cls, classname, readable);
|
||||
}
|
||||
|
||||
private static <T> T instanceOrConstruct(Class<? extends T> cls, String classname, String readable) throws ConfigurationException
|
||||
{
|
||||
try
|
||||
{
|
||||
Field instance = cls.getField("instance");
|
||||
|
|
@ -754,7 +823,20 @@ public class FBUtilities
|
|||
return construct(cls, classname, readable);
|
||||
}
|
||||
|
||||
private static <T> T construct(Class<T> cls, String classname, String readable) throws ConfigurationException
|
||||
/**
|
||||
* Constructs an instance of the given class after verifying it without initializing it.
|
||||
* @param classname Fully qualified classname.
|
||||
* @param readable Descriptive noun for the role the class plays.
|
||||
* @param expectedType Required superclass or interface.
|
||||
* @throws ConfigurationException If the class cannot be found or is not assignable to {@code expectedType}.
|
||||
*/
|
||||
public static <T> T construct(String classname, String readable, Class<T> expectedType) throws ConfigurationException
|
||||
{
|
||||
Class<? extends T> cls = FBUtilities.classForNameWithoutInitialization(classname, readable, expectedType);
|
||||
return construct(cls, classname, readable);
|
||||
}
|
||||
|
||||
private static <T> T construct(Class<? extends T> cls, String classname, String readable) throws ConfigurationException
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@ public class JMXServerUtils
|
|||
String authzProxyClass = System.getProperty("cassandra.jmx.authorizer");
|
||||
if (authzProxyClass != null)
|
||||
{
|
||||
final InvocationHandler handler = FBUtilities.construct(authzProxyClass, "JMX authz proxy");
|
||||
final InvocationHandler handler = FBUtilities.construct(authzProxyClass, "JMX authz proxy", InvocationHandler.class);
|
||||
final Class[] interfaces = { MBeanServerForwarder.class };
|
||||
|
||||
Object proxy = Proxy.newProxyInstance(MBeanServerForwarder.class.getClassLoader(), interfaces, handler);
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ public interface MBeanWrapper
|
|||
return new PlatformMBeanWrapper();
|
||||
}
|
||||
}
|
||||
return FBUtilities.construct(klass, "mbean");
|
||||
return FBUtilities.construct(klass, "mbean", MBeanWrapper.class);
|
||||
}
|
||||
|
||||
// Passing true for graceful will log exceptions instead of rethrowing them
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public interface MonotonicClock
|
|||
try
|
||||
{
|
||||
logger.debug("Using custom clock implementation: {}", sclock);
|
||||
return (MonotonicClock) Class.forName(sclock).newInstance();
|
||||
return FBUtilities.construct(sclock, "monotonic clock", MonotonicClock.class);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
@ -104,7 +104,8 @@ public interface MonotonicClock
|
|||
try
|
||||
{
|
||||
logger.debug("Using custom clock implementation: {}", sclock);
|
||||
Class<? extends MonotonicClock> clazz = (Class<? extends MonotonicClock>) Class.forName(sclock);
|
||||
Class<? extends MonotonicClock> clazz =
|
||||
FBUtilities.classForNameWithoutInitialization(sclock, "monotonic clock", MonotonicClock.class);
|
||||
|
||||
if (SystemClock.class.equals(clazz) && SystemClock.class.equals(precise.getClass()))
|
||||
return precise;
|
||||
|
|
|
|||
|
|
@ -34,8 +34,12 @@ import org.junit.Test;
|
|||
|
||||
import org.apache.cassandra.db.Keyspace;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.locator.IEndpointSnitch;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestNonAssignable;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestSupport;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
|
@ -48,6 +52,25 @@ public class DatabaseDescriptorTest
|
|||
DatabaseDescriptor.daemonInitialization();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEndpointSnitchWrongTypeRejectedWithoutInitializing()
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
|
||||
assertThatThrownBy(() -> DatabaseDescriptor.createEndpointSnitch(false, ClassLoadingTestNonAssignable.class.getName()))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessageContaining("must extend or implement " + IEndpointSnitch.class.getName());
|
||||
|
||||
assertThat(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEndpointSnitchValidClassResolves()
|
||||
{
|
||||
IEndpointSnitch snitch = DatabaseDescriptor.createEndpointSnitch(false, "SimpleSnitch");
|
||||
assertThat(snitch).isNotNull();
|
||||
}
|
||||
|
||||
// this came as a result of CASSANDRA-995
|
||||
@Test
|
||||
public void testConfigurationLoader() throws Exception
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ package org.apache.cassandra.db.marshal;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
|
|
@ -28,6 +30,8 @@ import org.apache.cassandra.config.DatabaseDescriptor;
|
|||
import org.apache.cassandra.dht.*;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.exceptions.SyntaxException;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestNonAssignable;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestSupport;
|
||||
|
||||
public class TypeParserTest
|
||||
{
|
||||
|
|
@ -37,6 +41,17 @@ public class TypeParserTest
|
|||
DatabaseDescriptor.daemonInitialization();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRejectsNonAbstractTypeWithoutInitializing() throws SyntaxException
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
assertThatThrownBy(() -> TypeParser.parse(ClassLoadingTestNonAssignable.class.getName()))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessageContaining("must extend or implement " + AbstractType.class.getName());
|
||||
|
||||
assertFalse(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParse() throws ConfigurationException, SyntaxException
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.diag;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A minimal, valid {@link DiagnosticEvent} subclass used by {@code DiagnosticEventPersistenceTest} to confirm that
|
||||
* the type-checked load path in {@link DiagnosticEventPersistence} resolves a correct subtype. Lives in the
|
||||
* {@code org.apache.cassandra} namespace so it passes the persistence package-prefix guard.
|
||||
*/
|
||||
public final class ClassLoadingTestDiagnosticEvent extends DiagnosticEvent
|
||||
{
|
||||
public enum TestType { TEST }
|
||||
|
||||
@Override
|
||||
public Enum<?> getType()
|
||||
{
|
||||
return TestType.TEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Serializable> toMap()
|
||||
{
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.diag;
|
||||
|
||||
import java.io.InvalidClassException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.utils.ClassLoadingTestNonAssignable;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestSupport;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
public class DiagnosticEventPersistenceTest
|
||||
{
|
||||
/**
|
||||
* Reflectively drives the (private) bespoke type-checked load path
|
||||
* {@link DiagnosticEventPersistence#getEventClass(String)}.
|
||||
*/
|
||||
private static Class<?> getEventClass(String eventClazz) throws Throwable
|
||||
{
|
||||
Method method = DiagnosticEventPersistence.class.getDeclaredMethod("getEventClass", String.class);
|
||||
method.setAccessible(true);
|
||||
try
|
||||
{
|
||||
return (Class<?>) method.invoke(DiagnosticEventPersistence.instance(), eventClazz);
|
||||
}
|
||||
catch (InvocationTargetException e)
|
||||
{
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonDiagnosticEventRejectedWithoutInitializing() throws Throwable
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
|
||||
assertThatThrownBy(() -> getEventClass(ClassLoadingTestNonAssignable.class.getName()))
|
||||
.isInstanceOf(InvalidClassException.class)
|
||||
.hasMessageContaining("must be of type DiagnosticEvent");
|
||||
|
||||
assertThat(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidDiagnosticEventSubclassResolves() throws Throwable
|
||||
{
|
||||
Class<?> resolved = getEventClass(ClassLoadingTestDiagnosticEvent.class.getName());
|
||||
assertThat(resolved).isEqualTo(ClassLoadingTestDiagnosticEvent.class);
|
||||
}
|
||||
}
|
||||
|
|
@ -38,11 +38,15 @@ import org.apache.cassandra.db.compaction.CompactionInfo;
|
|||
import org.apache.cassandra.db.lifecycle.SSTableSet;
|
||||
import org.apache.cassandra.io.sstable.format.SSTableReader;
|
||||
import org.apache.cassandra.notifications.SSTableAddedNotification;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.schema.IndexMetadata;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestNonAssignable;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestSupport;
|
||||
import org.apache.cassandra.utils.JVMStabilityInspector;
|
||||
import org.apache.cassandra.utils.KillerForTests;
|
||||
import org.apache.cassandra.utils.concurrent.Refs;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
|
@ -57,6 +61,17 @@ public class SecondaryIndexManagerTest extends CQLTester
|
|||
TestingIndex.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectsNonIndexClassWithoutInitializing()
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
assertThatThrownBy(() -> SecondaryIndexManager.loadIndexClass(ClassLoadingTestNonAssignable.class.getName()))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessageContaining("must extend or implement " + Index.class.getName());
|
||||
|
||||
assertFalse(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void creatingIndexMarksTheIndexAsBuilt() throws Throwable
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,10 +30,16 @@ import org.apache.cassandra.db.marshal.AsciiType;
|
|||
import org.apache.cassandra.db.marshal.BytesType;
|
||||
import org.apache.cassandra.db.marshal.UTF8Type;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.index.sasi.analyzer.AbstractAnalyzer;
|
||||
import org.apache.cassandra.index.sasi.analyzer.NonTokenizingAnalyzer;
|
||||
import org.apache.cassandra.index.sasi.disk.OnDiskIndexBuilder.Mode;
|
||||
import org.apache.cassandra.schema.ColumnMetadata;
|
||||
import org.apache.cassandra.schema.TableMetadata;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestNonAssignable;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestSupport;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
|
||||
public class IndexModeTest
|
||||
|
|
@ -184,8 +190,8 @@ public class IndexModeTest
|
|||
{
|
||||
ColumnMetadata cd = ColumnMetadata.regularColumn(cfm, ByteBufferUtil.bytes("TestColumnMetadata"), BytesType.instance);
|
||||
|
||||
IndexMode result = IndexMode.getMode(cd, Collections.singletonMap("analyzer_class", "java.lang.Object"));
|
||||
Assert.assertEquals(Object.class, result.analyzerClass);
|
||||
IndexMode result = IndexMode.getMode(cd, Collections.singletonMap("analyzer_class", NonTokenizingAnalyzer.class.getName()));
|
||||
Assert.assertEquals(NonTokenizingAnalyzer.class, result.analyzerClass);
|
||||
Assert.assertTrue(result.isAnalyzed);
|
||||
Assert.assertFalse(result.isLiteral);
|
||||
Assert.assertEquals((long)(1073741824 * 0.15), result.maxCompactionFlushMemoryInBytes);
|
||||
|
|
@ -197,16 +203,55 @@ public class IndexModeTest
|
|||
{
|
||||
ColumnMetadata cd = ColumnMetadata.regularColumn(cfm, ByteBufferUtil.bytes("TestColumnMetadata"), BytesType.instance);
|
||||
|
||||
IndexMode result = IndexMode.getMode(cd, ImmutableMap.of("analyzer_class", "java.lang.Object",
|
||||
IndexMode result = IndexMode.getMode(cd, ImmutableMap.of("analyzer_class", NonTokenizingAnalyzer.class.getName(),
|
||||
"analyzed", "false"));
|
||||
|
||||
Assert.assertEquals(Object.class, result.analyzerClass);
|
||||
Assert.assertEquals(NonTokenizingAnalyzer.class, result.analyzerClass);
|
||||
Assert.assertFalse(result.isAnalyzed);
|
||||
Assert.assertFalse(result.isLiteral);
|
||||
Assert.assertEquals((long)(1073741824 * 0.15), result.maxCompactionFlushMemoryInBytes);
|
||||
Assert.assertEquals(Mode.PREFIX, result.mode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_bytesType_rejectsNonAnalyzerWithoutInitializing()
|
||||
{
|
||||
ColumnMetadata cd = ColumnMetadata.regularColumn(cfm, ByteBufferUtil.bytes("TestColumnMetadata"), BytesType.instance);
|
||||
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
assertThatThrownBy(() -> IndexMode.getMode(cd, Collections.singletonMap("analyzer_class", ClassLoadingTestNonAssignable.class.getName())))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessageContaining("must extend or implement " + AbstractAnalyzer.class.getName());
|
||||
|
||||
Assert.assertFalse(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_bytesType_missingAnalyzerFallsBack()
|
||||
{
|
||||
ColumnMetadata cd = ColumnMetadata.regularColumn(cfm, ByteBufferUtil.bytes("TestColumnMetadata"), BytesType.instance);
|
||||
|
||||
IndexMode result = IndexMode.getMode(cd, Collections.singletonMap("analyzer_class", "does.not.ExistAnalyzer"));
|
||||
Assert.assertNull(result.analyzerClass);
|
||||
Assert.assertFalse(result.isAnalyzed);
|
||||
Assert.assertFalse(result.isLiteral);
|
||||
Assert.assertEquals((long)(1073741824 * 0.15), result.maxCompactionFlushMemoryInBytes);
|
||||
Assert.assertEquals(Mode.PREFIX, result.mode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_validateAnalyzer_rejectsNonAnalyzerWithoutInitializing()
|
||||
{
|
||||
ColumnMetadata cd = ColumnMetadata.regularColumn(cfm, ByteBufferUtil.bytes("TestColumnMetadata"), UTF8Type.instance);
|
||||
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
assertThatThrownBy(() -> IndexMode.validateAnalyzer(Collections.singletonMap("analyzer_class", ClassLoadingTestNonAssignable.class.getName()), cd))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessageContaining("must extend or implement " + AbstractAnalyzer.class.getName());
|
||||
|
||||
Assert.assertFalse(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_bytesType_maxCompactionFlushMemoryInBytes()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.cassandra.schema;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.db.compaction.AbstractCompactionStrategy;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestNonAssignable;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestSupport;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
public class CompactionParamsTest
|
||||
{
|
||||
@Test
|
||||
public void testRejectsNonCompactionStrategyWithoutInitializing()
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
|
||||
assertThatThrownBy(() -> CompactionParams.classFromName(ClassLoadingTestNonAssignable.class.getName()))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessageContaining("must extend or implement " + AbstractCompactionStrategy.class.getName());
|
||||
|
||||
assertThat(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class)).isFalse();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.schema;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.io.compress.ICompressor;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestNonAssignable;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestSupport;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
public class CompressionParamsTest
|
||||
{
|
||||
@Test
|
||||
public void testRejectsNonCompressorWithoutInitializing()
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
|
||||
assertThatThrownBy(() -> CompressionParams.fromMap(Collections.singletonMap(CompressionParams.CLASS,
|
||||
ClassLoadingTestNonAssignable.class.getName())))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessageContaining("must extend or implement " + ICompressor.class.getName());
|
||||
|
||||
assertThat(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class)).isFalse();
|
||||
}
|
||||
}
|
||||
|
|
@ -20,10 +20,21 @@
|
|||
*/
|
||||
package org.apache.cassandra.schema;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.cql3.statements.schema.IndexTarget;
|
||||
import org.apache.cassandra.db.marshal.UTF8Type;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.index.Index;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestNonAssignable;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestSupport;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
public class IndexMetadataTest
|
||||
{
|
||||
|
|
@ -33,4 +44,24 @@ public class IndexMetadataTest
|
|||
Assert.assertEquals("aB4__idx", IndexMetadata.generateDefaultIndexName("a B-4@!_+"));
|
||||
Assert.assertEquals("34_Ddd_F6_idx", IndexMetadata.generateDefaultIndexName("34_()Ddd", new ColumnIdentifier("#F%6*", true)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRejectsNonCustomIndexWithoutInitializing()
|
||||
{
|
||||
TableMetadata table = TableMetadata.builder("ks", "tbl")
|
||||
.addPartitionKeyColumn("pk", UTF8Type.instance)
|
||||
.build();
|
||||
IndexMetadata index = IndexMetadata.fromSchemaMetadata("idx",
|
||||
IndexMetadata.Kind.CUSTOM,
|
||||
Collections.singletonMap(IndexTarget.CUSTOM_INDEX_OPTION_NAME,
|
||||
ClassLoadingTestNonAssignable.class.getName()));
|
||||
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
|
||||
assertThatThrownBy(() -> index.validate(table))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessageContaining("must extend or implement " + Index.class.getName());
|
||||
|
||||
assertThat(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class)).isFalse();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,12 +34,34 @@ import org.junit.Before;
|
|||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.config.TransparentDataEncryptionOptions;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestNonAssignable;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestSupport;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class CipherFactoryTest
|
||||
{
|
||||
@Test
|
||||
public void keyProviderWrongTypeRejectedWithoutInitializing()
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
|
||||
TransparentDataEncryptionOptions options = EncryptionContextGenerator.createEncryptionOptions();
|
||||
options.key_provider.class_name = ClassLoadingTestNonAssignable.class.getName();
|
||||
|
||||
// CipherFactory wraps the load failure; the cause is the type-check ConfigurationException
|
||||
assertThatThrownBy(() -> new CipherFactory(options))
|
||||
.isInstanceOf(RuntimeException.class)
|
||||
.hasCauseInstanceOf(ConfigurationException.class)
|
||||
.hasStackTraceContaining("must extend or implement " + KeyProvider.class.getName());
|
||||
|
||||
assertThat(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class)).isFalse();
|
||||
}
|
||||
|
||||
// http://www.gutenberg.org/files/4300/4300-h/4300-h.htm
|
||||
static final String ULYSSEUS = "Stately, plump Buck Mulligan came from the stairhead, bearing a bowl of lather on which a mirror and a razor lay crossed. " +
|
||||
"A yellow dressinggown, ungirdled, was sustained gently behind him on the mild morning air. He held the bowl aloft and intoned: " +
|
||||
|
|
|
|||
|
|
@ -35,9 +35,12 @@ import org.apache.cassandra.exceptions.InvalidRequestException;
|
|||
import org.apache.cassandra.schema.TriggerMetadata;
|
||||
import org.apache.cassandra.schema.Triggers;
|
||||
import org.apache.cassandra.triggers.TriggerExecutorTest.SameKeySameCfTrigger;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestSupport;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
import static org.apache.cassandra.utils.ByteBufferUtil.bytes;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
|
@ -366,4 +369,28 @@ public class TriggerExecutorTest
|
|||
return cmp != 0 ? cmp : m1.key().compareTo(m2.key());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonTriggerClassRejectedWithoutInitializing() throws Exception
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(NonTrigger.class);
|
||||
|
||||
assertThatExceptionOfType(ConfigurationException.class)
|
||||
.isThrownBy(() -> TriggerExecutor.instance.loadTriggerClass(NonTrigger.class.getName()))
|
||||
.withMessageContaining("must extend or implement " + ITrigger.class.getName());
|
||||
|
||||
assertThat(ClassLoadingTestSupport.wasInitialized(NonTrigger.class)).isFalse();
|
||||
}
|
||||
|
||||
public static class NonTrigger
|
||||
{
|
||||
static
|
||||
{
|
||||
ClassLoadingTestSupport.markInitialized(NonTrigger.class);
|
||||
}
|
||||
|
||||
public NonTrigger()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.cassandra.utils;
|
||||
|
||||
public final class ClassLoadingTestNonAssignable
|
||||
{
|
||||
static
|
||||
{
|
||||
ClassLoadingTestSupport.markInitialized(ClassLoadingTestNonAssignable.class);
|
||||
}
|
||||
|
||||
private ClassLoadingTestNonAssignable()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.cassandra.utils;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public final class ClassLoadingTestSupport
|
||||
{
|
||||
private static final Set<String> initializedClasses = ConcurrentHashMap.newKeySet();
|
||||
|
||||
private ClassLoadingTestSupport()
|
||||
{
|
||||
}
|
||||
|
||||
public static void markInitialized(Class<?> initializedClass)
|
||||
{
|
||||
initializedClasses.add(initializedClass.getName());
|
||||
}
|
||||
|
||||
public static boolean wasInitialized(Class<?> initializedClass)
|
||||
{
|
||||
return initializedClasses.contains(initializedClass.getName());
|
||||
}
|
||||
|
||||
public static void assertNotInitialized(Class<?> initializedClass)
|
||||
{
|
||||
if (wasInitialized(initializedClass))
|
||||
throw new AssertionError(initializedClass.getName() + " has already been initialized");
|
||||
}
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ import java.net.InetAddress;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeMap;
|
||||
|
|
@ -43,14 +44,75 @@ import org.junit.Test;
|
|||
import org.apache.cassandra.db.marshal.*;
|
||||
import org.apache.cassandra.dht.*;
|
||||
|
||||
import org.apache.cassandra.audit.IAuditLogger;
|
||||
import org.apache.cassandra.config.Config;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class FBUtilitiesTest
|
||||
{
|
||||
@Test
|
||||
public void testTypedClassForNameRejectsWithoutInitializing()
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
assertThatThrownBy(() -> FBUtilities.classForNameWithoutInitialization(ClassLoadingTestNonAssignable.class.getName(), "test class", Runnable.class))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessageContaining("must extend or implement " + Runnable.class.getName());
|
||||
|
||||
assertFalse(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypedConstructRejectsWithoutInitializing()
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
assertThatThrownBy(() -> FBUtilities.construct(ClassLoadingTestNonAssignable.class.getName(), "test class", Runnable.class))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessageContaining("must extend or implement " + Runnable.class.getName());
|
||||
|
||||
assertFalse(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypedInstanceOrConstructRejectsWithoutInitializing()
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
assertThatThrownBy(() -> FBUtilities.instanceOrConstruct(ClassLoadingTestNonAssignable.class.getName(), "test class", Runnable.class))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessageContaining("must extend or implement " + Runnable.class.getName());
|
||||
|
||||
assertFalse(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewAuditLoggerRejectsWrongTypeWithoutInitializing()
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
assertThatThrownBy(() -> FBUtilities.newAuditLogger(ClassLoadingTestNonAssignable.class.getName(), Collections.emptyMap()))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasRootCauseInstanceOf(ConfigurationException.class)
|
||||
.hasStackTraceContaining("must extend or implement " + IAuditLogger.class.getName());
|
||||
|
||||
assertFalse(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAuditLoggerClassExistsRejectsWrongTypeWithoutInitializing()
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
assertFalse(FBUtilities.isAuditLoggerClassExists(ClassLoadingTestNonAssignable.class.getName()));
|
||||
assertFalse(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class));
|
||||
|
||||
assertTrue(FBUtilities.isAuditLoggerClassExists("NoOpAuditLogger"));
|
||||
assertFalse(FBUtilities.isAuditLoggerClassExists("does.not.ExistAuditLogger"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareByteSubArrays()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import java.util.Map;
|
|||
import com.google.common.base.Function;
|
||||
|
||||
import org.apache.cassandra.locator.AbstractReplicationStrategy;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
/**
|
||||
* For specifying replication options
|
||||
|
|
@ -76,9 +77,9 @@ class OptionReplication extends OptionMulti
|
|||
{
|
||||
try
|
||||
{
|
||||
Class<?> clazz = Class.forName(fullname);
|
||||
if (!AbstractReplicationStrategy.class.isAssignableFrom(clazz))
|
||||
throw new IllegalArgumentException(clazz + " is not a replication strategy");
|
||||
FBUtilities.classForNameWithoutInitialization(fullname,
|
||||
"replication strategy",
|
||||
AbstractReplicationStrategy.class);
|
||||
strategy = fullname;
|
||||
break;
|
||||
} catch (Exception ignore)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import com.datastax.driver.core.PlainTextAuthProvider;
|
|||
import com.datastax.driver.core.ProtocolOptions;
|
||||
import com.datastax.driver.core.ProtocolVersion;
|
||||
import org.apache.cassandra.stress.util.ResultLogger;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
public class SettingsMode implements Serializable
|
||||
{
|
||||
|
|
@ -72,9 +73,10 @@ public class SettingsMode implements Serializable
|
|||
{
|
||||
try
|
||||
{
|
||||
Class<?> clazz = Class.forName(authProviderClassname);
|
||||
if (!AuthProvider.class.isAssignableFrom(clazz))
|
||||
throw new IllegalArgumentException(clazz + " is not a valid auth provider");
|
||||
Class<? extends AuthProvider> clazz =
|
||||
FBUtilities.classForNameWithoutInitialization(authProviderClassname,
|
||||
"auth provider",
|
||||
AuthProvider.class);
|
||||
// check we can instantiate it
|
||||
if (PlainTextAuthProvider.class.equals(clazz))
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue