Author: slebresne
Date: Mon May 9 17:08:23 2011
New Revision: 1101116
URL: http://svn.apache.org/viewvc?rev=1101116&view=rev
Log:
Allow comparator parameters and add generic ReverseType
patch by slebresne; reviewed by jbellis for CASSANDRA-2355
Added:
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/ReversedType.java
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/TypeParser.java
cassandra/branches/cassandra-0.8.1/test/unit/org/apache/cassandra/db/marshal/TypeParserTest.java
Modified:
cassandra/branches/cassandra-0.8.1/CHANGES.txt
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cli/CliClient.java
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/config/CFMetaData.java
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/config/ColumnDefinition.java
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/AbstractType.java
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/utils/FBUtilities.java
Modified: cassandra/branches/cassandra-0.8.1/CHANGES.txt
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/CHANGES.txt?rev=1101116&r1=1101115&r2=1101116&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8.1/CHANGES.txt (original)
+++ cassandra/branches/cassandra-0.8.1/CHANGES.txt Mon May 9 17:08:23 2011
@@ -3,6 +3,9 @@
* add support for IN to cql SELECT, UPDATE (CASSANDRA-2553)
* add timestamp support to cql INSERT, UPDATE, and BATCH (CASSANDRA-2555)
+0.8.1
+ * add support for comparator parameters and a generic ReverseType
+ (CASSANDRA-2355)
0.8.0-?
* faster flushes and compaction from fixing excessively pessimistic
Modified:
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cli/CliClient.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cli/CliClient.java?rev=1101116&r1=1101115&r2=1101116&view=diff
==============================================================================
---
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cli/CliClient.java
(original)
+++
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/cli/CliClient.java
Mon May 9 17:08:23 2011
@@ -602,7 +602,7 @@ public class CliClient
// setting value for output
valueAsString =
valueValidator.getString(ByteBuffer.wrap(columnValue));
// updating column value validator class
- updateColumnMetaData(cfDef, columnName,
valueValidator.getClass().getName());
+ updateColumnMetaData(cfDef, columnName, valueValidator.toString());
}
else
{
@@ -2159,7 +2159,7 @@ public class CliClient
// performing ColumnDef local validator update
if (withUpdate)
{
- updateColumnMetaData(columnFamily, columnName,
validator.getClass().getName());
+ updateColumnMetaData(columnFamily, columnName,
validator.toString());
}
return value;
Modified:
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/config/CFMetaData.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/config/CFMetaData.java?rev=1101116&r1=1101115&r2=1101116&view=diff
==============================================================================
---
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/config/CFMetaData.java
(original)
+++
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/config/CFMetaData.java
Mon May 9 17:08:23 2011
@@ -322,17 +322,17 @@ public final class CFMetaData
cf.keyspace = new Utf8(ksName);
cf.name = new Utf8(cfName);
cf.column_type = new Utf8(cfType.name());
- cf.comparator_type = new Utf8(comparator.getClass().getName());
+ cf.comparator_type = new Utf8(comparator.toString());
if (subcolumnComparator != null)
- cf.subcomparator_type = new
Utf8(subcolumnComparator.getClass().getName());
+ cf.subcomparator_type = new Utf8(subcolumnComparator.toString());
cf.comment = new Utf8(comment);
cf.row_cache_size = rowCacheSize;
cf.key_cache_size = keyCacheSize;
cf.read_repair_chance = readRepairChance;
cf.replicate_on_write = replicateOnWrite;
cf.gc_grace_seconds = gcGraceSeconds;
- cf.default_validation_class = new
Utf8(defaultValidator.getClass().getName());
- cf.key_validation_class = new Utf8(keyValidator.getClass().getName());
+ cf.default_validation_class = new Utf8(defaultValidator.toString());
+ cf.key_validation_class = new Utf8(keyValidator.toString());
cf.min_compaction_threshold = minCompactionThreshold;
cf.max_compaction_threshold = maxCompactionThreshold;
cf.row_cache_save_period_in_seconds = rowCacheSavePeriodInSeconds;
@@ -763,10 +763,10 @@ public final class CFMetaData
org.apache.cassandra.thrift.CfDef def = new
org.apache.cassandra.thrift.CfDef(cfm.ksName, cfm.cfName);
def.setId(cfm.cfId);
def.setColumn_type(cfm.cfType.name());
- def.setComparator_type(cfm.comparator.getClass().getName());
+ def.setComparator_type(cfm.comparator.toString());
if (cfm.subcolumnComparator != null)
{
-
def.setSubcomparator_type(cfm.subcolumnComparator.getClass().getName());
+ def.setSubcomparator_type(cfm.subcolumnComparator.toString());
def.setColumn_type("Super");
}
def.setComment(enforceCommentNotNull(cfm.comment));
@@ -775,8 +775,8 @@ public final class CFMetaData
def.setRead_repair_chance(cfm.readRepairChance);
def.setReplicate_on_write(cfm.replicateOnWrite);
def.setGc_grace_seconds(cfm.gcGraceSeconds);
-
def.setDefault_validation_class(cfm.defaultValidator.getClass().getName());
- def.setKey_validation_class(cfm.keyValidator.getClass().getName());
+ def.setDefault_validation_class(cfm.defaultValidator.toString());
+ def.setKey_validation_class(cfm.keyValidator.toString());
def.setMin_compaction_threshold(cfm.minCompactionThreshold);
def.setMax_compaction_threshold(cfm.maxCompactionThreshold);
def.setRow_cache_save_period_in_seconds(cfm.rowCacheSavePeriodInSeconds);
@@ -793,7 +793,7 @@ public final class CFMetaData
tcd.setIndex_name(cd.getIndexName());
tcd.setIndex_type(cd.getIndexType());
tcd.setName(cd.name);
- tcd.setValidation_class(cd.getValidator().getClass().getName());
+ tcd.setValidation_class(cd.getValidator().toString());
column_meta.add(tcd);
}
def.setColumn_metadata(column_meta);
@@ -808,10 +808,10 @@ public final class CFMetaData
def.keyspace = cfm.ksName;
def.id = cfm.cfId;
def.column_type = cfm.cfType.name();
- def.comparator_type = cfm.comparator.getClass().getName();
+ def.comparator_type = cfm.comparator.toString();
if (cfm.subcolumnComparator != null)
{
- def.subcomparator_type =
cfm.subcolumnComparator.getClass().getName();
+ def.subcomparator_type = cfm.subcolumnComparator.toString();
def.column_type = "Super";
}
def.comment = enforceCommentNotNull(cfm.comment);
@@ -820,7 +820,7 @@ public final class CFMetaData
def.read_repair_chance = cfm.readRepairChance;
def.replicate_on_write = cfm.replicateOnWrite;
def.gc_grace_seconds = cfm.gcGraceSeconds;
- def.default_validation_class = cfm.defaultValidator == null ? null :
cfm.defaultValidator.getClass().getName();
+ def.default_validation_class = cfm.defaultValidator == null ? null :
cfm.defaultValidator.toString();
def.min_compaction_threshold = cfm.minCompactionThreshold;
def.max_compaction_threshold = cfm.maxCompactionThreshold;
def.row_cache_save_period_in_seconds = cfm.rowCacheSavePeriodInSeconds;
@@ -838,7 +838,7 @@ public final class CFMetaData
tcd.index_name = cd.getIndexName();
tcd.index_type = cd.getIndexType() == null ? null :
org.apache.cassandra.db.migration.avro.IndexType.valueOf(cd.getIndexType().name());
tcd.name = ByteBufferUtil.clone(cd.name);
- tcd.validation_class = cd.getValidator().getClass().getName();
+ tcd.validation_class = cd.getValidator().toString();
column_meta.add(tcd);
}
def.column_metadata = column_meta;
Modified:
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/config/ColumnDefinition.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/config/ColumnDefinition.java?rev=1101116&r1=1101115&r2=1101116&view=diff
==============================================================================
---
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/config/ColumnDefinition.java
(original)
+++
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/config/ColumnDefinition.java
Mon May 9 17:08:23 2011
@@ -79,7 +79,7 @@ public class ColumnDefinition
{
org.apache.cassandra.db.migration.avro.ColumnDef cd = new
org.apache.cassandra.db.migration.avro.ColumnDef();
cd.name = name;
- cd.validation_class = new Utf8(validator.getClass().getName());
+ cd.validation_class = new Utf8(validator.toString());
cd.index_type = index_type == null ? null :
Enum.valueOf(org.apache.cassandra.db.migration.avro.IndexType.class,
index_type.name());
cd.index_name = index_name == null ? null : new Utf8(index_name);
Modified:
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/AbstractType.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/AbstractType.java?rev=1101116&r1=1101115&r2=1101116&view=diff
==============================================================================
---
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/AbstractType.java
(original)
+++
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/AbstractType.java
Mon May 9 17:08:23 2011
@@ -24,7 +24,9 @@ package org.apache.cassandra.db.marshal;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Comparator;
+import java.util.Map;
+import org.apache.cassandra.config.ConfigurationException;
import org.apache.cassandra.db.IColumn;
import static org.apache.cassandra.io.sstable.IndexHelper.IndexInfo;
@@ -159,4 +161,28 @@ public abstract class AbstractType<T> im
public abstract int getScale(T obj);
public abstract int getJdbcType();
public abstract boolean needsQuotes();
+
+ public static AbstractType parseDefaultParameters(AbstractType baseType,
TypeParser parser) throws ConfigurationException
+ {
+ Map<String, String> parameters = parser.getKeyValueParameters();
+ String reversed = parameters.get("reversed");
+ if (reversed != null && (reversed.isEmpty() ||
reversed.equals("true")))
+ {
+ return ReversedType.getInstance(baseType);
+ }
+ else
+ {
+ return baseType;
+ }
+ }
+
+ /**
+ * This must be overriden by subclasses if necessary so that for any
+ * AbstractType, this == TypeParser.parse(toString()).
+ */
+ @Override
+ public String toString()
+ {
+ return getClass().getName();
+ }
}
Added:
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/ReversedType.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/ReversedType.java?rev=1101116&view=auto
==============================================================================
---
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/ReversedType.java
(added)
+++
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/ReversedType.java
Mon May 9 17:08:23 2011
@@ -0,0 +1,129 @@
+/**
+ * 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.db.marshal;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ReversedType<T> extends AbstractType<T>
+{
+ // interning instances
+ private static final Map<AbstractType, ReversedType> instances = new
HashMap<AbstractType, ReversedType>();
+
+ // package protected for unit tests sake
+ final AbstractType<T> baseType;
+
+ public static synchronized <T> ReversedType<T> getInstance(AbstractType<T>
baseType)
+ {
+ ReversedType type = instances.get(baseType);
+ if (type == null)
+ {
+ type = new ReversedType(baseType);
+ instances.put(baseType, type);
+ }
+ return (ReversedType<T>) type;
+ }
+
+ private ReversedType(AbstractType<T> baseType)
+ {
+ this.baseType = baseType;
+ }
+
+ public int compare(ByteBuffer o1, ByteBuffer o2)
+ {
+ return -baseType.compare(o1, o2);
+ }
+
+ public String getString(ByteBuffer bytes)
+ {
+ return baseType.getString(bytes);
+ }
+
+ public ByteBuffer fromString(String source)
+ {
+ return baseType.fromString(source);
+ }
+
+ public void validate(ByteBuffer bytes) throws MarshalException
+ {
+ baseType.validate(bytes);
+ }
+
+ public T compose(ByteBuffer bytes)
+ {
+ return baseType.compose(bytes);
+ }
+
+ public ByteBuffer decompose(T value)
+ {
+ return baseType.decompose(value);
+ }
+
+ public Class<T> getType()
+ {
+ return baseType.getType();
+ }
+
+ public String toString(T t)
+ {
+ return baseType.toString(t);
+ }
+
+ public boolean isSigned()
+ {
+ return baseType.isSigned();
+ }
+
+ public boolean isCaseSensitive()
+ {
+ return baseType.isCaseSensitive();
+ }
+
+ public boolean isCurrency()
+ {
+ return baseType.isCurrency();
+ }
+
+ public int getPrecision(T obj)
+ {
+ return baseType.getPrecision(obj);
+ }
+
+ public int getScale(T obj)
+ {
+ return baseType.getScale(obj);
+ }
+
+ public int getJdbcType()
+ {
+ return baseType.getJdbcType();
+ }
+
+ public boolean needsQuotes()
+ {
+ return baseType.needsQuotes();
+ }
+
+ @Override
+ public String toString()
+ {
+ return getClass().getName() + "(" + baseType + ")";
+ }
+}
Added:
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/TypeParser.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/TypeParser.java?rev=1101116&view=auto
==============================================================================
---
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/TypeParser.java
(added)
+++
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/db/marshal/TypeParser.java
Mon May 9 17:08:23 2011
@@ -0,0 +1,430 @@
+/**
+ * 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.db.marshal;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cassandra.config.ConfigurationException;
+import org.apache.cassandra.utils.FBUtilities;
+
+/**
+ * Parse a string containing an Type definition.
+ */
+public class TypeParser
+{
+ private final String str;
+ private int idx;
+
+ // A cache of parsed string, specially useful for DynamicCompositeType
+ private static final Map<String, AbstractType> cache = new HashMap<String,
AbstractType>();
+
+ public static final TypeParser EMPTY_PARSER = new TypeParser("", 0);
+
+ private TypeParser(String str, int idx)
+ {
+ this.str = str;
+ this.idx = idx;
+ }
+
+ /**
+ * Parse a string containing an type definition.
+ */
+ public static AbstractType parse(String str) throws ConfigurationException
+ {
+ if (str == null)
+ return BytesType.instance;
+
+ AbstractType type = cache.get(str);
+
+ if (type != null)
+ return type;
+
+ // This could be simplier (i.e. new TypeParser(str).parse()) but we
avoid creating a TypeParser object if not really necessary.
+ int i = 0;
+ i = skipBlank(str, i);
+ int j = i;
+ while (!isEOS(str, i) && isIdentifierChar(str.charAt(i)))
+ ++i;
+
+ if (i == j)
+ return BytesType.instance;
+
+ String name = str.substring(j, i);
+ i = skipBlank(str, i);
+
+ if (!isEOS(str, i) && str.charAt(i) == '(')
+ type = getAbstractType(name, new TypeParser(str, i));
+ else
+ type = getAbstractType(name);
+
+ // We don't really care about concurrency here. Worst case scenario,
we do some parsing unnecessarily
+ cache.put(str, type);
+ return type;
+ }
+
+ /**
+ * Parse an AbstractType from current position of this parser.
+ */
+ private AbstractType parse() throws ConfigurationException
+ {
+ skipBlank();
+ String name = readNextIdentifier();
+
+ skipBlank();
+ if (!isEOS() && str.charAt(idx) == '(')
+ return getAbstractType(name, this);
+ else
+ return getAbstractType(name);
+ }
+
+ public Map<String, String> getKeyValueParameters() throws
ConfigurationException
+ {
+ Map<String, String> map = new HashMap<String, String>();
+
+ if (isEOS())
+ return map;
+
+ if (str.charAt(idx) != '(')
+ throw new IllegalStateException();
+
+ ++idx; // skipping '('
+
+ while (skipBlankAndComma())
+ {
+ if (str.charAt(idx) == ')')
+ {
+ ++idx;
+ return map;
+ }
+
+ String k = readNextIdentifier();
+ String v = "";
+ skipBlank();
+ if (str.charAt(idx) == '=')
+ {
+ ++idx;
+ skipBlank();
+ v = readNextIdentifier();
+ }
+ else if (str.charAt(idx) != ',' && str.charAt(idx) != ')')
+ {
+ throwSyntaxError("unexpected character '" + str.charAt(idx) +
"'");
+ }
+ map.put(k, v);
+ }
+ throw new ConfigurationException(String.format("Syntax error parsing
'%s' at char %d: unexpected end of string", str, idx));
+ }
+
+ public List<AbstractType> getTypeParameters() throws ConfigurationException
+ {
+ List<AbstractType> list = new ArrayList<AbstractType>();
+
+ if (isEOS())
+ return list;
+
+ if (str.charAt(idx) != '(')
+ throw new IllegalStateException();
+
+ ++idx; // skipping '('
+
+ while (skipBlankAndComma())
+ {
+ if (str.charAt(idx) == ')')
+ {
+ ++idx;
+ return list;
+ }
+
+ try
+ {
+ list.add(parse());
+ }
+ catch (ConfigurationException e)
+ {
+ ConfigurationException ex = new
ConfigurationException(String.format("Exception while parsing '%s' around char
%d", str, idx));
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+ throw new ConfigurationException(String.format("Syntax error parsing
'%s' at char %d: unexpected end of string", str, idx));
+ }
+
+ public Map<Byte, AbstractType> getAliasParameters() throws
ConfigurationException
+ {
+ Map<Byte, AbstractType> map = new HashMap<Byte, AbstractType>();
+
+ if (isEOS())
+ return map;
+
+ if (str.charAt(idx) != '(')
+ throw new IllegalStateException();
+
+ ++idx; // skipping '('
+
+
+ while (skipBlankAndComma())
+ {
+ if (str.charAt(idx) == ')')
+ {
+ ++idx;
+ return map;
+ }
+
+ String alias = readNextIdentifier();
+ if (alias.length() != 1)
+ throwSyntaxError("An alias should be a single character");
+ char aliasChar = alias.charAt(0);
+ if (aliasChar < 33 || aliasChar > 127)
+ throwSyntaxError("An alias should be a single character in
[0..9a..bA..B-+._&]");
+
+ skipBlank();
+ if (!(str.charAt(idx) == '=' && str.charAt(idx+1) == '>'))
+ throwSyntaxError("expecting '=>' token");
+
+ idx += 2;
+ skipBlank();
+ try
+ {
+ map.put((byte)aliasChar, parse());
+ }
+ catch (ConfigurationException e)
+ {
+ ConfigurationException ex = new
ConfigurationException(String.format("Exception while parsing '%s' around char
%d", str, idx));
+ ex.initCause(e);
+ throw ex;
+ }
+ }
+ throw new ConfigurationException(String.format("Syntax error parsing
'%s' at char %d: unexpected end of string", str, idx));
+ }
+
+ 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");
+ try
+ {
+ Field field = typeClass.getDeclaredField("instance");
+ return (AbstractType) field.get(null);
+ }
+ catch (NoSuchFieldException e)
+ {
+ // Trying with empty parser
+ return getRawAbstractType(typeClass, EMPTY_PARSER);
+ }
+ catch (IllegalAccessException e)
+ {
+ // Trying with empty parser
+ return getRawAbstractType(typeClass, EMPTY_PARSER);
+ }
+ }
+
+ private static AbstractType getAbstractType(String compareWith, TypeParser
parser) throws ConfigurationException
+ {
+ String className = compareWith.contains(".") ? compareWith :
"org.apache.cassandra.db.marshal." + compareWith;
+ Class<? extends AbstractType> typeClass =
FBUtilities.<AbstractType>classForName(className, "abstract-type");
+ try
+ {
+ Method method = typeClass.getDeclaredMethod("getInstance",
TypeParser.class);
+ return (AbstractType) method.invoke(null, parser);
+ }
+ catch (NoSuchMethodException e)
+ {
+ // Trying to see if we have an instance field and apply the
default parameter to it
+ AbstractType type = getRawAbstractType(typeClass);
+ return AbstractType.parseDefaultParameters(type, parser);
+ }
+ catch (IllegalAccessException e)
+ {
+ // Trying to see if we have an instance field and apply the
default parameter to it
+ AbstractType type = getRawAbstractType(typeClass);
+ return AbstractType.parseDefaultParameters(type, parser);
+ }
+ catch (InvocationTargetException e)
+ {
+ ConfigurationException ex = new ConfigurationException("Invalid
definition for comparator " + typeClass.getName() + ".");
+ ex.initCause(e.getTargetException());
+ throw ex;
+ }
+ }
+
+ private static AbstractType getRawAbstractType(Class<? extends
AbstractType> typeClass) throws ConfigurationException
+ {
+ try
+ {
+ Field field = typeClass.getDeclaredField("instance");
+ return (AbstractType) field.get(null);
+ }
+ catch (NoSuchFieldException e)
+ {
+ throw new ConfigurationException("Invalid comparator class " +
typeClass.getName() + ": must define a public static instance field or a public
static method getInstance(TypeParser).");
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new ConfigurationException("Invalid comparator class " +
typeClass.getName() + ": must define a public static instance field or a public
static method getInstance(TypeParser).");
+ }
+ }
+
+ private static AbstractType getRawAbstractType(Class<? extends
AbstractType> typeClass, TypeParser parser) throws ConfigurationException
+ {
+ try
+ {
+ Method method = typeClass.getDeclaredMethod("getInstance",
TypeParser.class);
+ return (AbstractType) method.invoke(null, parser);
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw new ConfigurationException("Invalid comparator class " +
typeClass.getName() + ": must define a public static instance field or a public
static method getInstance(TypeParser).");
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new ConfigurationException("Invalid comparator class " +
typeClass.getName() + ": must define a public static instance field or a public
static method getInstance(TypeParser).");
+ }
+ catch (InvocationTargetException e)
+ {
+ ConfigurationException ex = new ConfigurationException("Invalid
definition for comparator " + typeClass.getName() + ".");
+ ex.initCause(e.getTargetException());
+ throw ex;
+ }
+ }
+
+ private void throwSyntaxError(String msg) throws ConfigurationException
+ {
+ throw new ConfigurationException(String.format("Syntax error parsing
'%s' at char %d: %s", str, idx, msg));
+ }
+
+ private boolean isEOS()
+ {
+ return isEOS(str, idx);
+ }
+
+ private static boolean isEOS(String str, int i)
+ {
+ return i >= str.length();
+ }
+
+ private static boolean isBlank(int c)
+ {
+ return c == ' ' || c == '\t' || c == '\n';
+ }
+
+ private void skipBlank()
+ {
+ idx = skipBlank(str, idx);
+ }
+
+ private static int skipBlank(String str, int i)
+ {
+ while (!isEOS(str, i) && isBlank(str.charAt(i)))
+ ++i;
+
+ return i;
+ }
+
+ // skip all blank and at best one comma, return true if there not EOS
+ private boolean skipBlankAndComma()
+ {
+ boolean commaFound = false;
+ while (!isEOS())
+ {
+ int c = str.charAt(idx);
+ if (c == ',')
+ {
+ if (commaFound)
+ return true;
+ else
+ commaFound = true;
+ }
+ else if (!isBlank(c))
+ {
+ return true;
+ }
+ ++idx;
+ }
+ return false;
+ }
+
+ /*
+ * [0..9a..bA..B-+._&]
+ */
+ private static boolean isIdentifierChar(int c)
+ {
+ return (c >= '0' && c <= '9')
+ || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+ || c == '-' || c == '+' || c == '.' || c == '_' || c == '&';
+ }
+
+ // left idx positioned on the character stopping the read
+ private String readNextIdentifier()
+ {
+ int i = idx;
+ while (!isEOS() && isIdentifierChar(str.charAt(idx)))
+ ++idx;
+
+ return str.substring(i, idx);
+ }
+
+ /**
+ * Helper function to ease the writing of AbstractType.toString() methods.
+ */
+ public static String stringifyAliasesParameters(Map<Byte, AbstractType>
aliases)
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append('(');
+ Iterator<Map.Entry<Byte, AbstractType>> iter =
aliases.entrySet().iterator();
+ if (iter.hasNext())
+ {
+ Map.Entry<Byte, AbstractType> entry = iter.next();
+
sb.append((char)(byte)entry.getKey()).append("=>").append(entry.getValue());
+ }
+ while (iter.hasNext())
+ {
+ Map.Entry<Byte, AbstractType> entry = iter.next();
+
sb.append(',').append((char)(byte)entry.getKey()).append("=>").append(entry.getValue());
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+
+ /**
+ * Helper function to ease the writing of AbstractType.toString() methods.
+ */
+ public static String stringifyTypeParameters(List<AbstractType> types)
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append('(');
+ Iterator<AbstractType> iter = types.iterator();
+ if (iter.hasNext())
+ {
+ sb.append(iter.next());
+ }
+ while (iter.hasNext())
+ {
+ sb.append(',').append(iter.next());
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+}
Modified:
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/utils/FBUtilities.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/utils/FBUtilities.java?rev=1101116&r1=1101115&r2=1101116&view=diff
==============================================================================
---
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/utils/FBUtilities.java
(original)
+++
cassandra/branches/cassandra-0.8.1/src/java/org/apache/cassandra/utils/FBUtilities.java
Mon May 9 17:08:23 2011
@@ -44,6 +44,7 @@ import org.apache.cassandra.config.Confi
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.db.DecoratedKey;
import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.TypeParser;
import org.apache.cassandra.dht.IPartitioner;
import org.apache.cassandra.dht.Range;
import org.apache.cassandra.dht.Token;
@@ -523,25 +524,7 @@ public class FBUtilities
public static AbstractType getComparator(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");
- try
- {
- Field field = typeClass.getDeclaredField("instance");
- return (AbstractType) field.get(null);
- }
- catch (NoSuchFieldException e)
- {
- ConfigurationException ex = new ConfigurationException("Invalid
comparator " + compareWith + " : must define a public static instance field.");
- ex.initCause(e);
- throw ex;
- }
- catch (IllegalAccessException e)
- {
- ConfigurationException ex = new ConfigurationException("Invalid
comparator " + compareWith + " : must define a public static instance field.");
- ex.initCause(e);
- throw ex;
- }
+ return TypeParser.parse(compareWith);
}
/**
Added:
cassandra/branches/cassandra-0.8.1/test/unit/org/apache/cassandra/db/marshal/TypeParserTest.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8.1/test/unit/org/apache/cassandra/db/marshal/TypeParserTest.java?rev=1101116&view=auto
==============================================================================
---
cassandra/branches/cassandra-0.8.1/test/unit/org/apache/cassandra/db/marshal/TypeParserTest.java
(added)
+++
cassandra/branches/cassandra-0.8.1/test/unit/org/apache/cassandra/db/marshal/TypeParserTest.java
Mon May 9 17:08:23 2011
@@ -0,0 +1,93 @@
+/**
+ * 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.db.marshal;
+
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.junit.Test;
+import static org.junit.Assert.fail;
+
+import org.apache.cassandra.CleanupHelper;
+import org.apache.cassandra.Util;
+import org.apache.cassandra.config.ConfigurationException;
+import org.apache.cassandra.db.*;
+import org.apache.cassandra.db.columniterator.IdentityQueryFilter;
+import org.apache.cassandra.db.filter.QueryFilter;
+import org.apache.cassandra.db.filter.QueryPath;
+import org.apache.cassandra.utils.*;
+
+public class TypeParserTest
+{
+ @Test
+ public void testParse() throws ConfigurationException
+ {
+ AbstractType type;
+
+ type = TypeParser.parse(null);
+ assert type == BytesType.instance;
+
+ type = TypeParser.parse("");
+ assert type == BytesType.instance;
+
+ type = TypeParser.parse(" ");
+ assert type == BytesType.instance;
+
+ type = TypeParser.parse("LongType");
+ assert type == LongType.instance;
+
+ type = TypeParser.parse(" LongType ");
+ assert type == LongType.instance;
+
+ type = TypeParser.parse("LongType()");
+ assert type == LongType.instance;
+
+ type = TypeParser.parse("LongType(reversed=false)");
+ assert type == LongType.instance;
+
+ type = TypeParser.parse("LongType(reversed=true)");
+ assert type == ReversedType.getInstance(LongType.instance);
+ assert ((ReversedType)type).baseType == LongType.instance;
+
+ type = TypeParser.parse("LongType(reversed)");
+ assert type == ReversedType.getInstance(LongType.instance);
+ assert ((ReversedType)type).baseType == LongType.instance;
+ }
+
+ @Test
+ public void testParseError() throws ConfigurationException
+ {
+ try
+ {
+ TypeParser.parse("y");
+ fail("Should not pass");
+ }
+ catch (ConfigurationException e) {}
+
+ try
+ {
+ TypeParser.parse("LongType(reversed@)");
+ fail("Should not pass");
+ }
+ catch (ConfigurationException e) {}
+ }
+}