mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-4.0' into cassandra-4.1
This commit is contained in:
commit
1c702382de
|
|
@ -2,6 +2,7 @@
|
|||
* Add Paxos v2 option and informatin in cassandra.yaml (CASSANDRA-21316)
|
||||
* Harden data resurrection startup check with atomic heartbeat file write with fallback (CASSANDRA-21290)
|
||||
Merged from 4.0:
|
||||
* 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);
|
||||
|
|
|
|||
|
|
@ -326,7 +326,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)
|
||||
|
|
@ -1199,8 +1199,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)
|
||||
|
|
@ -1374,7 +1375,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;
|
||||
}
|
||||
|
||||
|
|
@ -1382,7 +1383,7 @@ public class DatabaseDescriptor
|
|||
{
|
||||
if (!detectorClassName.contains("."))
|
||||
detectorClassName = "org.apache.cassandra.gms." + detectorClassName;
|
||||
IFailureDetector detector = FBUtilities.construct(detectorClassName, "failure detector");
|
||||
IFailureDetector detector = FBUtilities.construct(detectorClassName, "failure detector", IFailureDetector.class);
|
||||
return detector;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ public interface GuardrailsConfigProvider
|
|||
*/
|
||||
static GuardrailsConfigProvider build(String customImpl)
|
||||
{
|
||||
return FBUtilities.construct(customImpl, "custom guardrails config provider");
|
||||
return FBUtilities.construct(customImpl, "custom guardrails config provider", GuardrailsConfigProvider.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -743,6 +743,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;
|
||||
|
|
@ -753,7 +758,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;
|
||||
|
|
|
|||
|
|
@ -424,11 +424,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;
|
||||
|
||||
|
|
@ -275,7 +276,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;
|
||||
|
|
@ -283,15 +284,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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,19 +171,25 @@ public final class MemtableParams
|
|||
try
|
||||
{
|
||||
Memtable.Factory factory;
|
||||
Class<?> clazz = Class.forName(className);
|
||||
Class<?> clazz = Class.forName(className, false, MemtableParams.class.getClassLoader());
|
||||
final Map<String, String> parametersCopy = options.parameters != null
|
||||
? new HashMap<>(options.parameters)
|
||||
: new HashMap<>();
|
||||
try
|
||||
{
|
||||
Method factoryMethod = clazz.getDeclaredMethod("factory", Map.class);
|
||||
if (!Memtable.Factory.class.isAssignableFrom(factoryMethod.getReturnType()))
|
||||
throw new ClassCastException("Memtable factory method on " + className +
|
||||
" must return " + Memtable.Factory.class.getName());
|
||||
factory = (Memtable.Factory) factoryMethod.invoke(null, parametersCopy);
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
// continue with FACTORY field
|
||||
Field factoryField = clazz.getDeclaredField("FACTORY");
|
||||
if (!Memtable.Factory.class.isAssignableFrom(factoryField.getType()))
|
||||
throw new ClassCastException("Memtable FACTORY field on " + className +
|
||||
" must be of type " + Memtable.Factory.class.getName());
|
||||
factory = (Memtable.Factory) factoryField.get(null);
|
||||
}
|
||||
if (!parametersCopy.isEmpty())
|
||||
|
|
|
|||
|
|
@ -45,7 +45,8 @@ public class SchemaUpdateHandlerFactoryProvider implements Provider<SchemaUpdate
|
|||
}
|
||||
else
|
||||
{
|
||||
Class<SchemaUpdateHandlerFactory> suhFactoryClass = FBUtilities.classForName(suhFactoryClassName, "schema update handler factory");
|
||||
Class<? extends SchemaUpdateHandlerFactory> suhFactoryClass =
|
||||
FBUtilities.classForNameWithoutInitialization(suhFactoryClassName, "schema update handler factory", SchemaUpdateHandlerFactory.class);
|
||||
try
|
||||
{
|
||||
return suhFactoryClass.newInstance();
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import org.slf4j.LoggerFactory;
|
|||
import io.netty.util.concurrent.FastThreadLocal;
|
||||
import org.apache.cassandra.concurrent.ImmediateExecutor;
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -127,9 +127,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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -117,7 +117,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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ import org.apache.cassandra.exceptions.ConfigurationException;
|
|||
import org.apache.cassandra.io.util.File;
|
||||
import org.apache.cassandra.locator.InetAddressAndPort;
|
||||
import org.apache.cassandra.tools.BulkLoader.CmdLineOptions;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
import static org.apache.cassandra.config.DataRateSpec.DataRateUnit.MEBIBYTES_PER_SECOND;
|
||||
|
||||
|
|
@ -686,11 +687,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());
|
||||
}
|
||||
|
|
@ -717,9 +719,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;
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ public abstract class Tracing extends ExecutorLocals.Impl
|
|||
{
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,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.io.util.File;
|
||||
import org.apache.cassandra.schema.TableId;
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ public interface Clock
|
|||
try
|
||||
{
|
||||
outcome = "Using custom clock implementation: " + classname;
|
||||
clock = (Clock) Class.forName(classname).newInstance();
|
||||
clock = FBUtilities.construct(classname, "clock", Clock.class);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -616,28 +616,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)
|
||||
|
|
@ -650,7 +650,7 @@ 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
|
||||
|
|
@ -660,8 +660,9 @@ public class FBUtilities
|
|||
|
||||
try
|
||||
{
|
||||
Class<?> auditLoggerClass = FBUtilities.classForName(className, "Audit logger");
|
||||
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)
|
||||
{
|
||||
|
|
@ -676,16 +677,22 @@ public class FBUtilities
|
|||
|
||||
try
|
||||
{
|
||||
Class<?> sslContextFactoryClass = Class.forName(className);
|
||||
return (ISslContextFactory) sslContextFactoryClass.getConstructor(Map.class).newInstance(parameters);
|
||||
Class<? extends ISslContextFactory> sslContextFactoryClass =
|
||||
FBUtilities.classForNameWithoutInitialization(className, "ISslContextFactory", ISslContextFactory.class);
|
||||
return sslContextFactoryClass.getConstructor(Map.class).newInstance(parameters);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ConfigurationException("Unable to create instance of ISslContextFactory for " + className, ex);
|
||||
// Surface the underlying load failure (e.g. ClassNotFoundException) as the direct cause rather than the
|
||||
// intermediate ConfigurationException that reports it.
|
||||
Throwable cause = ex instanceof ConfigurationException && ex.getCause() != null ? ex.getCause() : ex;
|
||||
throw new ConfigurationException("Unable to create instance of ISslContextFactory for " + className, cause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
|
@ -703,6 +710,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.
|
||||
|
|
@ -712,6 +766,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");
|
||||
|
|
@ -736,7 +809,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
|
||||
|
|
|
|||
|
|
@ -91,7 +91,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)
|
||||
{
|
||||
|
|
@ -110,7 +110,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;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ 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 org.assertj.core.api.Assertions;
|
||||
|
||||
import static org.apache.cassandra.config.DataStorageSpec.DataStorageUnit.KIBIBYTES;
|
||||
|
|
@ -52,6 +55,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
|
||||
|
|
|
|||
|
|
@ -25,12 +25,26 @@ import org.apache.cassandra.config.DatabaseDescriptor;
|
|||
import org.apache.cassandra.config.GuardrailsOptions;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestNonAssignable;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestSupport;
|
||||
import org.assertj.core.api.Assertions;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
public class GuardrailsConfigProviderTest extends GuardrailTester
|
||||
{
|
||||
@Test
|
||||
public void testBuildWrongTypeRejectedWithoutInitializing()
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
|
||||
Assertions.assertThatThrownBy(() -> GuardrailsConfigProvider.build(ClassLoadingTestNonAssignable.class.getName()))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessageContaining("must extend or implement " + GuardrailsConfigProvider.class.getName());
|
||||
|
||||
Assertions.assertThat(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildCustom() throws Throwable
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.apache.cassandra.utils.ClassLoadingTestSupport;
|
||||
|
||||
public final class MemtableFactoryInvalidFieldType
|
||||
{
|
||||
public static final Object FACTORY = new Object();
|
||||
|
||||
static
|
||||
{
|
||||
ClassLoadingTestSupport.markInitialized(MemtableFactoryInvalidFieldType.class);
|
||||
}
|
||||
|
||||
private MemtableFactoryInvalidFieldType()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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.Map;
|
||||
|
||||
import org.apache.cassandra.utils.ClassLoadingTestSupport;
|
||||
|
||||
public final class MemtableFactoryInvalidReturnType
|
||||
{
|
||||
static
|
||||
{
|
||||
ClassLoadingTestSupport.markInitialized(MemtableFactoryInvalidReturnType.class);
|
||||
}
|
||||
|
||||
private MemtableFactoryInvalidReturnType()
|
||||
{
|
||||
}
|
||||
|
||||
public static Object factory(Map<String, String> parameters)
|
||||
{
|
||||
return new Object();
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
package org.apache.cassandra.schema;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
|
@ -28,7 +30,10 @@ import org.apache.cassandra.config.InheritingClass;
|
|||
import org.apache.cassandra.config.ParameterizedClass;
|
||||
import org.apache.cassandra.db.memtable.SkipListMemtableFactory;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
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;
|
||||
|
||||
public class MemtableParamsTest
|
||||
|
|
@ -42,6 +47,46 @@ public class MemtableParamsTest
|
|||
assertEquals(ImmutableMap.of("default", DEFAULT), map);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidFactoryMethodDoesNotInitializeClass() throws Exception
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(MemtableFactoryInvalidReturnType.class);
|
||||
|
||||
assertThatThrownBy(() -> getMemtableFactory(MemtableFactoryInvalidReturnType.class))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasStackTraceContaining("must return");
|
||||
|
||||
assertThat(ClassLoadingTestSupport.wasInitialized(MemtableFactoryInvalidReturnType.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidFactoryFieldDoesNotInitializeClass() throws Exception
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(MemtableFactoryInvalidFieldType.class);
|
||||
|
||||
assertThatThrownBy(() -> getMemtableFactory(MemtableFactoryInvalidFieldType.class))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasStackTraceContaining("must be of type");
|
||||
|
||||
assertThat(ClassLoadingTestSupport.wasInitialized(MemtableFactoryInvalidFieldType.class)).isFalse();
|
||||
}
|
||||
|
||||
private static void getMemtableFactory(Class<?> memtableClass) throws Exception
|
||||
{
|
||||
Method method = MemtableParams.class.getDeclaredMethod("getMemtableFactory", ParameterizedClass.class);
|
||||
method.setAccessible(true);
|
||||
try
|
||||
{
|
||||
method.invoke(null, new ParameterizedClass(memtableClass.getName(), null));
|
||||
}
|
||||
catch (InvocationTargetException e)
|
||||
{
|
||||
if (e.getCause() instanceof ConfigurationException)
|
||||
throw (ConfigurationException) e.getCause();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultRemapped()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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.distributed.shared.WithProperties;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestNonAssignable;
|
||||
import org.apache.cassandra.utils.ClassLoadingTestSupport;
|
||||
|
||||
import static org.apache.cassandra.schema.SchemaUpdateHandlerFactoryProvider.SUH_FACTORY_CLASS_PROPERTY;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
public class SchemaUpdateHandlerFactoryProviderTest
|
||||
{
|
||||
@Test
|
||||
public void testDefaultFactoryWhenPropertyUnset()
|
||||
{
|
||||
assertThat(SchemaUpdateHandlerFactoryProvider.instance.get()).isSameAs(DefaultSchemaUpdateHandlerFactory.instance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfiguredFactoryResolves()
|
||||
{
|
||||
try (WithProperties properties = new WithProperties(SUH_FACTORY_CLASS_PROPERTY, DefaultSchemaUpdateHandlerFactory.class.getName()))
|
||||
{
|
||||
assertThat(SchemaUpdateHandlerFactoryProvider.instance.get()).isInstanceOf(DefaultSchemaUpdateHandlerFactory.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRejectsNonFactoryWithoutInitializing()
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
try (WithProperties properties = new WithProperties(SUH_FACTORY_CLASS_PROPERTY, ClassLoadingTestNonAssignable.class.getName()))
|
||||
{
|
||||
assertThatThrownBy(() -> SchemaUpdateHandlerFactoryProvider.instance.get())
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessageContaining("must extend or implement " + SchemaUpdateHandlerFactory.class.getName());
|
||||
}
|
||||
|
||||
assertThat(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnknownFactoryClassRejected()
|
||||
{
|
||||
try (WithProperties properties = new WithProperties(SUH_FACTORY_CLASS_PROPERTY, "does.not.ExistFactory"))
|
||||
{
|
||||
assertThatThrownBy(() -> SchemaUpdateHandlerFactoryProvider.instance.get())
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasMessageContaining("Unable to find schema update handler factory class");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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: " +
|
||||
|
|
|
|||
|
|
@ -34,9 +34,12 @@ import org.apache.cassandra.exceptions.ConfigurationException;
|
|||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.schema.TriggerMetadata;
|
||||
import org.apache.cassandra.schema.Triggers;
|
||||
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;
|
||||
|
||||
|
|
@ -364,4 +367,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");
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.charset.CharacterCodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.TreeMap;
|
||||
|
|
@ -44,15 +45,76 @@ 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 org.apache.cassandra.security.ISslContextFactory;
|
||||
|
||||
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.assertFalse;
|
||||
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 testNewSslContextFactoryRejectsWrongTypeWithoutInitializing()
|
||||
{
|
||||
ClassLoadingTestSupport.assertNotInitialized(ClassLoadingTestNonAssignable.class);
|
||||
assertThatThrownBy(() -> FBUtilities.newSslContextFactory(ClassLoadingTestNonAssignable.class.getName(), Collections.emptyMap()))
|
||||
.isInstanceOf(ConfigurationException.class)
|
||||
.hasStackTraceContaining("must extend or implement " + ISslContextFactory.class.getName());
|
||||
|
||||
assertFalse(ClassLoadingTestSupport.wasInitialized(ClassLoadingTestNonAssignable.class));
|
||||
}
|
||||
|
||||
@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