Repository: cassandra Updated Branches: refs/heads/trunk 869bdabf4 -> 01d26dd3f
Replace trivial uses of String.replace/replaceAll/split with StringUtils methods patch by Alexander Shopov; reviewed by Robert Stupp for CASSANDRA-8755 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/01d26dd3 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/01d26dd3 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/01d26dd3 Branch: refs/heads/trunk Commit: 01d26dd3fc35a6b22a538f75545b0d9b739ee48d Parents: 869bdab Author: Alexander Shopov <li...@kambanaria.org> Authored: Mon Jan 4 22:33:44 2016 +0100 Committer: Robert Stupp <sn...@snazy.de> Committed: Mon Jan 4 22:33:44 2016 +0100 ---------------------------------------------------------------------- .../org/apache/cassandra/config/CFMetaData.java | 9 ++- .../cassandra/config/DatabaseDescriptor.java | 6 +- .../apache/cassandra/cql3/ColumnIdentifier.java | 5 +- .../statements/CreateKeyspaceStatement.java | 5 +- .../cql3/statements/CreateTableStatement.java | 6 +- .../cql3/statements/PropertyDefinitions.java | 5 +- .../db/commitlog/CommitLogArchiver.java | 18 ++++-- .../db/commitlog/CommitLogReplayer.java | 2 +- .../db/marshal/AbstractCompositeType.java | 9 ++- .../apache/cassandra/db/marshal/TupleType.java | 18 +++++- .../index/internal/CassandraIndex.java | 7 ++- .../metrics/CassandraMetricsRegistry.java | 16 ++++- .../apache/cassandra/schema/IndexMetadata.java | 11 +++- .../cassandra/service/StorageService.java | 4 +- .../cassandra/utils/CassandraVersion.java | 6 +- .../apache/cassandra/config/CFMetaDataTest.java | 20 +++++++ .../config/DatabaseDescriptorTest.java | 15 +++++ .../cassandra/cql3/ColumnIdentifierTest.java | 19 ++++++ .../statements/PropertyDefinitionsTest.java | 61 ++++++++++++++++++++ .../db/marshal/AbstractCompositeTypeTest.java | 35 +++++++++++ .../metrics/CassandraMetricsRegistryTest.java | 34 +++++++++++ .../cassandra/schema/IndexMetadataTest.java | 36 ++++++++++++ .../cassandra/utils/CassandraVersionTest.java | 51 +++++++++++++++- 23 files changed, 363 insertions(+), 35 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/config/CFMetaData.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/config/CFMetaData.java b/src/java/org/apache/cassandra/config/CFMetaData.java index 128255c..ffa55c3 100644 --- a/src/java/org/apache/cassandra/config/CFMetaData.java +++ b/src/java/org/apache/cassandra/config/CFMetaData.java @@ -25,6 +25,7 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; import java.util.stream.Collectors; import com.google.common.annotations.VisibleForTesting; @@ -69,6 +70,8 @@ public final class CFMetaData SUPER, COUNTER, DENSE, COMPOUND } + private static final Pattern PATTERN_WORD_CHARS = Pattern.compile("\\w+"); + private static final Logger logger = LoggerFactory.getLogger(CFMetaData.class); public static final Serializer serializer = new Serializer(); @@ -830,9 +833,9 @@ public final class CFMetaData return columnMetadata.get(name); } - public static boolean isNameValid(String name) - { - return name != null && !name.isEmpty() && name.length() <= Schema.NAME_LENGTH && name.matches("\\w+"); + public static boolean isNameValid(String name) { + return name != null && !name.isEmpty() + && name.length() <= Schema.NAME_LENGTH && PATTERN_WORD_CHARS.matcher(name).matches(); } public CFMetaData validate() throws ConfigurationException http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/config/DatabaseDescriptor.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java index edcbcf5..3fc0b31 100644 --- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java +++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java @@ -54,9 +54,9 @@ import org.apache.cassandra.scheduler.NoScheduler; import org.apache.cassandra.security.EncryptionContext; import org.apache.cassandra.service.CacheService; import org.apache.cassandra.thrift.ThriftServer; -import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.FBUtilities; import org.apache.cassandra.utils.memory.*; +import org.apache.commons.lang3.StringUtils; public class DatabaseDescriptor { @@ -927,8 +927,8 @@ public class DatabaseDescriptor { List<String> tokens = new ArrayList<String>(); if (tokenString != null) - for (String token : tokenString.split(",")) - tokens.add(token.replaceAll("^\\s+", "").replaceAll("\\s+$", "")); + for (String token : StringUtils.split(tokenString, ',')) + tokens.add(token.trim()); return tokens; } http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java index 93734e9..74d0d28 100644 --- a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java +++ b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java @@ -46,7 +46,8 @@ import org.apache.cassandra.utils.memory.AbstractAllocator; public class ColumnIdentifier extends Selectable implements IMeasurableMemory, Comparable<ColumnIdentifier> { private static final Pattern PATTERN_DOUBLE_QUOTE = Pattern.compile("\"", Pattern.LITERAL); - + private static final String ESCAPED_DOUBLE_QUOTE = Matcher.quoteReplacement("\"\""); + public final ByteBuffer bytes; private final String text; /** @@ -332,6 +333,6 @@ public class ColumnIdentifier extends Selectable implements IMeasurableMemory, C { if (UNQUOTED_IDENTIFIER.matcher(text).matches()) return text; - return '"' + PATTERN_DOUBLE_QUOTE.matcher(text).replaceAll(Matcher.quoteReplacement("\"\"")) + '"'; + return '"' + PATTERN_DOUBLE_QUOTE.matcher(text).replaceAll(ESCAPED_DOUBLE_QUOTE) + '"'; } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java index 3eb0ac9..86754b6 100644 --- a/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/CreateKeyspaceStatement.java @@ -17,6 +17,7 @@ */ package org.apache.cassandra.cql3.statements; +import java.util.regex.Pattern; import org.apache.cassandra.auth.*; import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.config.Schema; @@ -31,6 +32,8 @@ import org.apache.cassandra.transport.Event; /** A <code>CREATE KEYSPACE</code> statement parsed from a CQL query. */ public class CreateKeyspaceStatement extends SchemaAlteringStatement { + private static final Pattern PATTERN_WORD_CHARS = Pattern.compile("\\w+"); + private final String name; private final KeyspaceAttributes attrs; private final boolean ifNotExists; @@ -73,7 +76,7 @@ public class CreateKeyspaceStatement extends SchemaAlteringStatement ThriftValidation.validateKeyspaceNotSystem(name); // keyspace name - if (!name.matches("\\w+")) + if (!PATTERN_WORD_CHARS.matcher(name).matches()) throw new InvalidRequestException(String.format("\"%s\" is not a valid keyspace name", name)); if (name.length() > Schema.NAME_LENGTH) throw new InvalidRequestException(String.format("Keyspace names shouldn't be more than %s characters long (got \"%s\")", Schema.NAME_LENGTH, name)); http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java index c19f970..debb200 100644 --- a/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java @@ -19,7 +19,7 @@ package org.apache.cassandra.cql3.statements; import java.nio.ByteBuffer; import java.util.*; - +import java.util.regex.Pattern; import com.google.common.collect.HashMultiset; import com.google.common.collect.Multiset; import org.apache.commons.lang3.StringUtils; @@ -41,6 +41,8 @@ import org.apache.cassandra.transport.Event; /** A {@code CREATE TABLE} parsed from a CQL query statement. */ public class CreateTableStatement extends SchemaAlteringStatement { + private static final Pattern PATTERN_WORD_CHARS = Pattern.compile("\\w+"); + private List<AbstractType<?>> keyTypes; private List<AbstractType<?>> clusteringTypes; @@ -202,7 +204,7 @@ public class CreateTableStatement extends SchemaAlteringStatement public ParsedStatement.Prepared prepare(Types udts) throws RequestValidationException { // Column family name - if (!columnFamily().matches("\\w+")) + if (!PATTERN_WORD_CHARS.matcher(columnFamily()).matches()) throw new InvalidRequestException(String.format("\"%s\" is not a valid table name (must be alphanumeric character or underscore only: [a-zA-Z_0-9]+)", columnFamily())); if (columnFamily().length() > Schema.NAME_LENGTH) throw new InvalidRequestException(String.format("Table names shouldn't be more than %s characters long (got \"%s\")", Schema.NAME_LENGTH, columnFamily())); http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/cql3/statements/PropertyDefinitions.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/statements/PropertyDefinitions.java b/src/java/org/apache/cassandra/cql3/statements/PropertyDefinitions.java index 793285b..590910f 100644 --- a/src/java/org/apache/cassandra/cql3/statements/PropertyDefinitions.java +++ b/src/java/org/apache/cassandra/cql3/statements/PropertyDefinitions.java @@ -18,6 +18,7 @@ package org.apache.cassandra.cql3.statements; import java.util.*; +import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,6 +27,8 @@ import org.apache.cassandra.exceptions.SyntaxException; public class PropertyDefinitions { + private static final Pattern PATTERN_POSITIVE = Pattern.compile("(1|true|yes)"); + protected static final Logger logger = LoggerFactory.getLogger(PropertyDefinitions.class); protected final Map<String, Object> properties = new HashMap<String, Object>(); @@ -91,7 +94,7 @@ public class PropertyDefinitions public Boolean getBoolean(String key, Boolean defaultValue) throws SyntaxException { String value = getSimple(key); - return (value == null) ? defaultValue : value.toLowerCase().matches("(1|true|yes)"); + return (value == null) ? defaultValue : PATTERN_POSITIVE.matcher(value.toLowerCase()).matches(); } // Return a property value, typed as a double http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/db/commitlog/CommitLogArchiver.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/commitlog/CommitLogArchiver.java b/src/java/org/apache/cassandra/db/commitlog/CommitLogArchiver.java index 5547d0e..97b26c7 100644 --- a/src/java/org/apache/cassandra/db/commitlog/CommitLogArchiver.java +++ b/src/java/org/apache/cassandra/db/commitlog/CommitLogArchiver.java @@ -29,6 +29,8 @@ import java.util.Map; import java.util.Properties; import java.util.TimeZone; import java.util.concurrent.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.cassandra.concurrent.JMXEnabledThreadPoolExecutor; import org.apache.cassandra.config.DatabaseDescriptor; @@ -46,6 +48,10 @@ public class CommitLogArchiver private static final Logger logger = LoggerFactory.getLogger(CommitLogArchiver.class); public static final SimpleDateFormat format = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss"); private static final String DELIMITER = ","; + private static final Pattern NAME = Pattern.compile("%name"); + private static final Pattern PATH = Pattern.compile("%path"); + private static final Pattern FROM = Pattern.compile("%from"); + private static final Pattern TO = Pattern.compile("%to"); static { format.setTimeZone(TimeZone.getTimeZone("GMT")); @@ -136,8 +142,8 @@ public class CommitLogArchiver protected void runMayThrow() throws IOException { segment.waitForFinalSync(); - String command = archiveCommand.replace("%name", segment.getName()); - command = command.replace("%path", segment.getPath()); + String command = NAME.matcher(archiveCommand).replaceAll(Matcher.quoteReplacement(segment.getName())); + command = PATH.matcher(command).replaceAll(Matcher.quoteReplacement(segment.getPath())); exec(command); } })); @@ -158,8 +164,8 @@ public class CommitLogArchiver { protected void runMayThrow() throws IOException { - String command = archiveCommand.replace("%name", name); - command = command.replace("%path", path); + String command = NAME.matcher(archiveCommand).replaceAll(Matcher.quoteReplacement(name)); + command = PATH.matcher(command).replaceAll(Matcher.quoteReplacement(path)); exec(command); } })); @@ -244,8 +250,8 @@ public class CommitLogArchiver continue; } - String command = restoreCommand.replace("%from", fromFile.getPath()); - command = command.replace("%to", toFile.getPath()); + String command = FROM.matcher(restoreCommand).replaceAll(Matcher.quoteReplacement(fromFile.getPath())); + command = TO.matcher(command).replaceAll(Matcher.quoteReplacement(toFile.getPath())); try { exec(command); http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/db/commitlog/CommitLogReplayer.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/commitlog/CommitLogReplayer.java b/src/java/org/apache/cassandra/db/commitlog/CommitLogReplayer.java index 0c71871..e97b36e 100644 --- a/src/java/org/apache/cassandra/db/commitlog/CommitLogReplayer.java +++ b/src/java/org/apache/cassandra/db/commitlog/CommitLogReplayer.java @@ -295,7 +295,7 @@ public class CommitLogReplayer Multimap<String, String> toReplay = HashMultimap.create(); for (String rawPair : System.getProperty("cassandra.replayList").split(",")) { - String[] pair = rawPair.trim().split("\\."); + String[] pair = StringUtils.split(rawPair.trim(), '.'); if (pair.length != 2) throw new IllegalArgumentException("Each table to be replayed must be fully qualified with keyspace name, e.g., 'system.peers'"); http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java b/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java index ad4050d..130ed7b 100644 --- a/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java +++ b/src/java/org/apache/cassandra/db/marshal/AbstractCompositeType.java @@ -21,6 +21,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.regex.Pattern; import org.apache.cassandra.cql3.Term; import org.apache.cassandra.serializers.TypeSerializer; @@ -107,6 +108,10 @@ public abstract class AbstractCompositeType extends AbstractType<ByteBuffer> } return l.toArray(new ByteBuffer[l.size()]); } + private static final String COLON = ":"; + private static final Pattern COLON_PAT = Pattern.compile(COLON); + private static final String ESCAPED_COLON = "\\\\:"; + private static final Pattern ESCAPED_COLON_PAT = Pattern.compile(ESCAPED_COLON); /* @@ -118,7 +123,7 @@ public abstract class AbstractCompositeType extends AbstractType<ByteBuffer> if (input.isEmpty()) return input; - String res = input.replaceAll(":", "\\\\:"); + String res = COLON_PAT.matcher(input).replaceAll(ESCAPED_COLON); char last = res.charAt(res.length() - 1); return last == '\\' || last == '!' ? res + '!' : res; } @@ -132,7 +137,7 @@ public abstract class AbstractCompositeType extends AbstractType<ByteBuffer> if (input.isEmpty()) return input; - String res = input.replaceAll("\\\\:", ":"); + String res = ESCAPED_COLON_PAT.matcher(input).replaceAll(COLON); char last = res.charAt(res.length() - 1); return last == '!' ? res.substring(0, res.length() - 1) : res; } http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/db/marshal/TupleType.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/marshal/TupleType.java b/src/java/org/apache/cassandra/db/marshal/TupleType.java index 9480229..362388b 100644 --- a/src/java/org/apache/cassandra/db/marshal/TupleType.java +++ b/src/java/org/apache/cassandra/db/marshal/TupleType.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.regex.Pattern; import com.google.common.base.Objects; @@ -37,6 +38,15 @@ import org.apache.cassandra.utils.ByteBufferUtil; */ public class TupleType extends AbstractType<ByteBuffer> { + private static final String COLON = ":"; + private static final Pattern COLON_PAT = Pattern.compile(COLON); + private static final String ESCAPED_COLON = "\\\\:"; + private static final Pattern ESCAPED_COLON_PAT = Pattern.compile(ESCAPED_COLON); + private static final String AT = "@"; + private static final Pattern AT_PAT = Pattern.compile(AT); + private static final String ESCAPED_AT = "\\\\@"; + private static final Pattern ESCAPED_AT_PAT = Pattern.compile(ESCAPED_AT); + protected final List<AbstractType<?>> types; public TupleType(List<AbstractType<?>> types) @@ -215,7 +225,9 @@ public class TupleType extends AbstractType<ByteBuffer> ByteBuffer field = ByteBufferUtil.readBytes(input, size); // We use ':' as delimiter, and @ to represent null, so escape them in the generated string - sb.append(type.getString(field).replaceAll(":", "\\\\:").replaceAll("@", "\\\\@")); + String fld = COLON_PAT.matcher(type.getString(field)).replaceAll(ESCAPED_COLON); + fld = AT_PAT.matcher(fld).replaceAll(ESCAPED_AT); + sb.append(fld); } return sb.toString(); } @@ -238,7 +250,9 @@ public class TupleType extends AbstractType<ByteBuffer> continue; AbstractType<?> type = type(i); - fields[i] = type.fromString(fieldString.replaceAll("\\\\:", ":").replaceAll("\\\\@", "@")); + fieldString = ESCAPED_COLON_PAT.matcher(fieldString).replaceAll(COLON); + fieldString = ESCAPED_AT_PAT.matcher(fieldString).replaceAll(AT); + fields[i] = type.fromString(fieldString); } return buildValue(fields); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/index/internal/CassandraIndex.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/index/internal/CassandraIndex.java b/src/java/org/apache/cassandra/index/internal/CassandraIndex.java index 4598326..2204a5e 100644 --- a/src/java/org/apache/cassandra/index/internal/CassandraIndex.java +++ b/src/java/org/apache/cassandra/index/internal/CassandraIndex.java @@ -725,6 +725,9 @@ public abstract class CassandraIndex implements Index return getFunctions(indexMetadata, parseTarget(baseCfs.metadata, indexMetadata)).newIndexInstance(baseCfs, indexMetadata); } + private static final Pattern TWO_QUOTES = Pattern.compile("\"\""); + private static final String QUOTE = "\""; + // Public because it's also used to convert index metadata into a thrift-compatible format public static Pair<ColumnDefinition, IndexTarget.Type> parseTarget(CFMetaData cfm, IndexMetadata indexDef) @@ -754,10 +757,10 @@ public abstract class CassandraIndex implements Index // abc"def -> abc""def. // Because the target string is stored in a CQL compatible form, we // need to un-escape any such quotes to get the actual column name - if (columnName.startsWith("\"")) + if (columnName.startsWith(QUOTE)) { columnName = StringUtils.substring(StringUtils.substring(columnName, 1), 0, -1); - columnName = columnName.replaceAll("\"\"", "\""); + columnName = TWO_QUOTES.matcher(columnName).replaceAll(QUOTE); } // if it's not a CQL table, we can't assume that the column name is utf8, so http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/metrics/CassandraMetricsRegistry.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/metrics/CassandraMetricsRegistry.java b/src/java/org/apache/cassandra/metrics/CassandraMetricsRegistry.java index 1cd3b6c..0d9e6d6 100644 --- a/src/java/org/apache/cassandra/metrics/CassandraMetricsRegistry.java +++ b/src/java/org/apache/cassandra/metrics/CassandraMetricsRegistry.java @@ -191,6 +191,18 @@ public class CassandraMetricsRegistry extends MetricRegistry mBeanServer.unregisterMBean(name.getMBeanName()); } catch (Exception ignore) {} } + + /** + * Strips a single final '$' from input + * + * @param s String to strip + * @return a string with one less '$' at end + */ + private static String withoutFinalDollar(String s) + { + int l = s.length(); + return (l!=0 && '$' == s.charAt(l-1))?s.substring(0,l-1):s; + } public interface MetricMBean { @@ -601,7 +613,7 @@ public class CassandraMetricsRegistry extends MetricRegistry public MetricName(Class<?> klass, String name, String scope) { this(klass.getPackage() == null ? "" : klass.getPackage().getName(), - klass.getSimpleName().replaceAll("\\$$", ""), + withoutFinalDollar(klass.getSimpleName()), name, scope); } @@ -811,7 +823,7 @@ public class CassandraMetricsRegistry extends MetricRegistry { if (type == null || type.isEmpty()) { - type = klass.getSimpleName().replaceAll("\\$$", ""); + type = withoutFinalDollar(klass.getSimpleName()); } return type; } http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/schema/IndexMetadata.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/schema/IndexMetadata.java b/src/java/org/apache/cassandra/schema/IndexMetadata.java index ee9179a..59ac1cf 100644 --- a/src/java/org/apache/cassandra/schema/IndexMetadata.java +++ b/src/java/org/apache/cassandra/schema/IndexMetadata.java @@ -21,6 +21,7 @@ package org.apache.cassandra.schema; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.*; +import java.util.regex.Pattern; import java.util.stream.Collectors; import com.google.common.base.Objects; @@ -46,6 +47,10 @@ import org.apache.cassandra.utils.UUIDSerializer; public final class IndexMetadata { private static final Logger logger = LoggerFactory.getLogger(IndexMetadata.class); + + private static final Pattern PATTERN_NON_WORD_CHAR = Pattern.compile("\\W"); + private static final Pattern PATTERN_WORD_CHARS = Pattern.compile("\\w+"); + public static final Serializer serializer = new Serializer(); @@ -127,15 +132,15 @@ public final class IndexMetadata public static boolean isNameValid(String name) { - return name != null && !name.isEmpty() && name.matches("\\w+"); + return name != null && !name.isEmpty() && PATTERN_WORD_CHARS.matcher(name).matches(); } public static String getDefaultIndexName(String cfName, String root) { if (root == null) - return (cfName + "_" + "idx").replaceAll("\\W", ""); + return PATTERN_NON_WORD_CHAR.matcher(cfName + "_" + "idx").replaceAll(""); else - return (cfName + "_" + root + "_idx").replaceAll("\\W", ""); + return PATTERN_NON_WORD_CHAR.matcher(cfName + "_" + root + "_idx").replaceAll(""); } public void validate() http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/service/StorageService.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/service/StorageService.java b/src/java/org/apache/cassandra/service/StorageService.java index 069af53..60ede18 100644 --- a/src/java/org/apache/cassandra/service/StorageService.java +++ b/src/java/org/apache/cassandra/service/StorageService.java @@ -166,7 +166,7 @@ import static java.util.Arrays.asList; public class StorageService extends NotificationBroadcasterSupport implements IEndpointStateChangeSubscriber, StorageServiceMBean { private static final Logger logger = LoggerFactory.getLogger(StorageService.class); - + public static final int RING_DELAY = getRingDelay(); // delay after which we assume ring has stablized private final JMXProgressSupport progressSupport = new JMXProgressSupport(this); @@ -2707,7 +2707,7 @@ public class StorageService extends NotificationBroadcasterSupport implements IE Map<Keyspace, List<String>> keyspaceColumnfamily = new HashMap<Keyspace, List<String>>(); for (String table : tableList) { - String splittedString[] = table.split("\\."); + String splittedString[] = StringUtils.split(table, '.'); if (splittedString.length == 2) { String keyspaceName = splittedString[0]; http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/src/java/org/apache/cassandra/utils/CassandraVersion.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/utils/CassandraVersion.java b/src/java/org/apache/cassandra/utils/CassandraVersion.java index aac7df9..759ca97 100644 --- a/src/java/org/apache/cassandra/utils/CassandraVersion.java +++ b/src/java/org/apache/cassandra/utils/CassandraVersion.java @@ -37,6 +37,8 @@ public class CassandraVersion implements Comparable<CassandraVersion> * this is because 3rd and the last can be identical. **/ private static final String VERSION_REGEXP = "(\\d+)\\.(\\d+)(?:\\.(\\w+))?(\\-[.\\w]+)?([.+][.\\w]+)?"; + private static final Pattern PATTERN_WHITESPACE = Pattern.compile("\\w+"); + private static final Pattern pattern = Pattern.compile(VERSION_REGEXP); private static final Pattern SNAPSHOT = Pattern.compile("-SNAPSHOT"); @@ -83,10 +85,10 @@ public class CassandraVersion implements Comparable<CassandraVersion> { // Drop initial - or + str = str.substring(1); - String[] parts = str.split("\\."); + String[] parts = StringUtils.split(str, '.'); for (String part : parts) { - if (!part.matches("\\w+")) + if (!PATTERN_WHITESPACE.matcher(part).matches()) throw new IllegalArgumentException("Invalid version value: " + version); } return parts; http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/test/unit/org/apache/cassandra/config/CFMetaDataTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/config/CFMetaDataTest.java b/test/unit/org/apache/cassandra/config/CFMetaDataTest.java index 9d91df3..188f72f 100644 --- a/test/unit/org/apache/cassandra/config/CFMetaDataTest.java +++ b/test/unit/org/apache/cassandra/config/CFMetaDataTest.java @@ -49,6 +49,8 @@ import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public class CFMetaDataTest { @@ -173,4 +175,22 @@ public class CFMetaDataTest assertEquals(cfm.params, params); assertEquals(new HashSet<>(cfm.allColumns()), columns); } + + @Test + public void testIsNameValidPositive() + { + assertTrue(CFMetaData.isNameValid("abcdefghijklmnopqrstuvwxyz")); + assertTrue(CFMetaData.isNameValid("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + assertTrue(CFMetaData.isNameValid("_01234567890")); + } + + @Test + public void testIsNameValidNegative() + { + assertFalse(CFMetaData.isNameValid(null)); + assertFalse(CFMetaData.isNameValid("")); + assertFalse(CFMetaData.isNameValid(" ")); + assertFalse(CFMetaData.isNameValid("@")); + assertFalse(CFMetaData.isNameValid("!")); + } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/test/unit/org/apache/cassandra/config/DatabaseDescriptorTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/config/DatabaseDescriptorTest.java b/test/unit/org/apache/cassandra/config/DatabaseDescriptorTest.java index 3a3b6ee..84f0235 100644 --- a/test/unit/org/apache/cassandra/config/DatabaseDescriptorTest.java +++ b/test/unit/org/apache/cassandra/config/DatabaseDescriptorTest.java @@ -23,6 +23,8 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.NetworkInterface; +import java.util.Arrays; +import java.util.Collection; import java.util.Enumeration; import org.junit.BeforeClass; @@ -43,6 +45,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + @RunWith(OrderedJUnit4ClassRunner.class) public class DatabaseDescriptorTest { @@ -265,4 +269,15 @@ public class DatabaseDescriptorTest DatabaseDescriptor.applyAddressConfig(testConfig); } + + @Test + public void testTokensFromString() + { + assertTrue(DatabaseDescriptor.tokensFromString(null).isEmpty()); + Collection<String> tokens = DatabaseDescriptor.tokensFromString(" a,b ,c , d, f,g,h"); + assertEquals(7, tokens.size()); + assertTrue(tokens.containsAll(Arrays.asList(new String[]{"a", "b", "c", "d", "f", "g", "h"}))); + + + } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/test/unit/org/apache/cassandra/cql3/ColumnIdentifierTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/ColumnIdentifierTest.java b/test/unit/org/apache/cassandra/cql3/ColumnIdentifierTest.java index c287883..158110c 100644 --- a/test/unit/org/apache/cassandra/cql3/ColumnIdentifierTest.java +++ b/test/unit/org/apache/cassandra/cql3/ColumnIdentifierTest.java @@ -26,6 +26,7 @@ import org.junit.Test; import junit.framework.Assert; import org.apache.cassandra.db.marshal.BytesType; import org.apache.cassandra.utils.ByteBufferUtil; +import static org.junit.Assert.assertEquals; public class ColumnIdentifierTest { @@ -57,5 +58,23 @@ public class ColumnIdentifierTest { return v < 0 ? -1 : v > 0 ? 1 : 0; } + + @Test + public void testMaybeQuote() + { + String unquotable = "a"; + assertEquals(unquotable, ColumnIdentifier.maybeQuote(unquotable)); + unquotable = "z4"; + assertEquals(unquotable, ColumnIdentifier.maybeQuote(unquotable)); + unquotable = "m_4_"; + assertEquals(unquotable, ColumnIdentifier.maybeQuote(unquotable)); + unquotable = "f__"; + assertEquals(unquotable, ColumnIdentifier.maybeQuote(unquotable)); + + assertEquals("\"A\"", ColumnIdentifier.maybeQuote("A")); + assertEquals("\"4b\"", ColumnIdentifier.maybeQuote("4b")); + assertEquals("\"\"\"\"", ColumnIdentifier.maybeQuote("\"")); + assertEquals("\"\"\"a\"\"b\"\"\"", ColumnIdentifier.maybeQuote("\"a\"b\"")); + } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/test/unit/org/apache/cassandra/cql3/statements/PropertyDefinitionsTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/statements/PropertyDefinitionsTest.java b/test/unit/org/apache/cassandra/cql3/statements/PropertyDefinitionsTest.java new file mode 100644 index 0000000..417fcdc --- /dev/null +++ b/test/unit/org/apache/cassandra/cql3/statements/PropertyDefinitionsTest.java @@ -0,0 +1,61 @@ +package org.apache.cassandra.cql3.statements; + +import org.junit.After; +import org.junit.Test; +import org.junit.Before; + +import static org.junit.Assert.assertEquals; + +public class PropertyDefinitionsTest { + + PropertyDefinitions pd; + + @Before + public void setUp() + { + pd = new PropertyDefinitions(); + } + + @After + public void clear() + { + pd = null; + } + + + @Test + public void testGetBooleanExistant() + { + String key = "one"; + pd.addProperty(key, "1"); + assertEquals(Boolean.TRUE, pd.getBoolean(key, null)); + + key = "TRUE"; + pd.addProperty(key, "TrUe"); + assertEquals(Boolean.TRUE, pd.getBoolean(key, null)); + + key = "YES"; + pd.addProperty(key, "YeS"); + assertEquals(Boolean.TRUE, pd.getBoolean(key, null)); + + key = "BAD_ONE"; + pd.addProperty(key, " 1"); + assertEquals(Boolean.FALSE, pd.getBoolean(key, null)); + + key = "BAD_TRUE"; + pd.addProperty(key, "true "); + assertEquals(Boolean.FALSE, pd.getBoolean(key, null)); + + key = "BAD_YES"; + pd.addProperty(key, "ye s"); + assertEquals(Boolean.FALSE, pd.getBoolean(key, null)); + } + + @Test + public void testGetBooleanNonexistant() + { + assertEquals(Boolean.FALSE, pd.getBoolean("nonexistant", Boolean.FALSE)); + assertEquals(Boolean.TRUE, pd.getBoolean("nonexistant", Boolean.TRUE)); + } + +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/test/unit/org/apache/cassandra/db/marshal/AbstractCompositeTypeTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/db/marshal/AbstractCompositeTypeTest.java b/test/unit/org/apache/cassandra/db/marshal/AbstractCompositeTypeTest.java new file mode 100644 index 0000000..0e91532 --- /dev/null +++ b/test/unit/org/apache/cassandra/db/marshal/AbstractCompositeTypeTest.java @@ -0,0 +1,35 @@ +package org.apache.cassandra.db.marshal; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +public class AbstractCompositeTypeTest +{ + + @Test + public void testEscape() + { + assertEquals("", AbstractCompositeType.escape("")); + assertEquals("Ab!CdXy \\Z123-345", AbstractCompositeType.escape("Ab!CdXy \\Z123-345")); + assertEquals("Ab!CdXy \\Z123-345!!", AbstractCompositeType.escape("Ab!CdXy \\Z123-345!")); + assertEquals("Ab!CdXy \\Z123-345\\!", AbstractCompositeType.escape("Ab!CdXy \\Z123-345\\")); + + assertEquals("A\\:b!CdXy \\\\:Z123-345", AbstractCompositeType.escape("A:b!CdXy \\:Z123-345")); + assertEquals("A\\:b!CdXy \\\\:Z123-345!!", AbstractCompositeType.escape("A:b!CdXy \\:Z123-345!")); + assertEquals("A\\:b!CdXy \\\\:Z123-345\\!", AbstractCompositeType.escape("A:b!CdXy \\:Z123-345\\")); + + } + + @Test + public void testUnescape() + { + assertEquals("", AbstractCompositeType.escape("")); + assertEquals("Ab!CdXy \\Z123-345", AbstractCompositeType.unescape("Ab!CdXy \\Z123-345")); + assertEquals("Ab!CdXy \\Z123-345!", AbstractCompositeType.unescape("Ab!CdXy \\Z123-345!!")); + assertEquals("Ab!CdXy \\Z123-345\\", AbstractCompositeType.unescape("Ab!CdXy \\Z123-345\\!")); + + assertEquals("A:b!CdXy \\:Z123-345", AbstractCompositeType.unescape("A\\:b!CdXy \\\\:Z123-345")); + assertEquals("A:b!CdXy \\:Z123-345!", AbstractCompositeType.unescape("A\\:b!CdXy \\\\:Z123-345!!")); + assertEquals("A:b!CdXy \\:Z123-345\\", AbstractCompositeType.unescape("A\\:b!CdXy \\\\:Z123-345\\!")); + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/test/unit/org/apache/cassandra/metrics/CassandraMetricsRegistryTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/metrics/CassandraMetricsRegistryTest.java b/test/unit/org/apache/cassandra/metrics/CassandraMetricsRegistryTest.java new file mode 100644 index 0000000..0258b8c --- /dev/null +++ b/test/unit/org/apache/cassandra/metrics/CassandraMetricsRegistryTest.java @@ -0,0 +1,34 @@ +package org.apache.cassandra.metrics; + +import org.junit.Test; +import org.apache.cassandra.metrics.CassandraMetricsRegistry.MetricName; +import static org.junit.Assert.*; + + +public class CassandraMetricsRegistryTest +{ + // A class with a name ending in '$' + private static class StrangeName$ + { + } + + @Test + public void testChooseType() + { + assertEquals("StrangeName", MetricName.chooseType(null, StrangeName$.class)); + assertEquals("StrangeName", MetricName.chooseType("", StrangeName$.class)); + assertEquals("String", MetricName.chooseType(null, String.class)); + assertEquals("String", MetricName.chooseType("", String.class)); + + assertEquals("a", MetricName.chooseType("a", StrangeName$.class)); + assertEquals("b", MetricName.chooseType("b", String.class)); + } + + @Test + public void testMetricName() + { + MetricName name = new MetricName(StrangeName$.class, "NaMe", "ScOpE"); + assertEquals("StrangeName", name.getType()); + } + +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/test/unit/org/apache/cassandra/schema/IndexMetadataTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/schema/IndexMetadataTest.java b/test/unit/org/apache/cassandra/schema/IndexMetadataTest.java new file mode 100644 index 0000000..901a5aa --- /dev/null +++ b/test/unit/org/apache/cassandra/schema/IndexMetadataTest.java @@ -0,0 +1,36 @@ +package org.apache.cassandra.schema; + +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class IndexMetadataTest { + + @Test + public void testIsNameValidPositive() + { + assertTrue(IndexMetadata.isNameValid("abcdefghijklmnopqrstuvwxyz")); + assertTrue(IndexMetadata.isNameValid("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + assertTrue(IndexMetadata.isNameValid("_01234567890")); + } + + @Test + public void testIsNameValidNegative() + { + assertFalse(IndexMetadata.isNameValid(null)); + assertFalse(IndexMetadata.isNameValid("")); + assertFalse(IndexMetadata.isNameValid(" ")); + assertFalse(IndexMetadata.isNameValid("@")); + assertFalse(IndexMetadata.isNameValid("!")); + } + + @Test + public void testGetDefaultIndexName() + { + Assert.assertEquals("aB4__idx", IndexMetadata.getDefaultIndexName("a B-4@!_+", null)); + Assert.assertEquals("34_Ddd_F6_idx", IndexMetadata.getDefaultIndexName("34_()Ddd", "#F%6*")); + + } +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/01d26dd3/test/unit/org/apache/cassandra/utils/CassandraVersionTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/utils/CassandraVersionTest.java b/test/unit/org/apache/cassandra/utils/CassandraVersionTest.java index cec668f..73562b7 100644 --- a/test/unit/org/apache/cassandra/utils/CassandraVersionTest.java +++ b/test/unit/org/apache/cassandra/utils/CassandraVersionTest.java @@ -17,10 +17,16 @@ */ package org.apache.cassandra.utils; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; import org.junit.Test; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.matchers.JUnitMatchers.containsString; public class CassandraVersionTest { @@ -153,7 +159,7 @@ public class CassandraVersionTest next = new CassandraVersion("3.2"); assertTrue(prev.compareTo(next) < 0); } - + private static void assertThrows(String str) { try @@ -163,4 +169,47 @@ public class CassandraVersionTest } catch (IllegalArgumentException e) {} } + + @Test + public void testParseIdentifiersPositive() throws Throwable + { + String[] result = parseIdentifiers("DUMMY", "+a.b.cde.f_g."); + String[] expected = {"a", "b", "cde", "f_g"}; + assertArrayEquals(expected, result); + } + + @Test + public void testParseIdentifiersNegative() throws Throwable + { + String version = "DUMMY"; + try + { + parseIdentifiers(version, "+a. .b"); + + } + catch (IllegalArgumentException e) + { + assertThat(e.getMessage(), containsString(version)); + } + } + private static String[] parseIdentifiers(String version, String str) throws Throwable + { + String name = "parseIdentifiers"; + Class[] args = {String.class, String.class}; + for (Method m: CassandraVersion.class.getDeclaredMethods()) + { + if (name.equals(m.getName()) && + Arrays.equals(args, m.getParameterTypes())) + { + m.setAccessible(true); + try + { + return (String[]) m.invoke(null, version, str); + } catch (InvocationTargetException e){ + throw e.getTargetException(); + } + } + } + throw new NoSuchMethodException(CassandraVersion.class + "." + name + Arrays.toString(args)); + } }