package me.prettyprint.cassandra.service.template;
import java.util.HashMap;
import java.util.Map;
import me.prettyprint.cassandra.model.HSlicePredicate;
import me.prettyprint.cassandra.model.thrift.ThriftColumnFactory;
import me.prettyprint.cassandra.service.ExceptionsTranslator;
import me.prettyprint.cassandra.service.ExceptionsTranslatorImpl;
import me.prettyprint.hector.api.ColumnFactory;
import me.prettyprint.hector.api.ConsistencyLevelPolicy;
import me.prettyprint.hector.api.Keyspace;
import me.prettyprint.hector.api.Serializer;
import me.prettyprint.hector.api.factory.HFactory;
import me.prettyprint.hector.api.mutation.MutationResult;
import me.prettyprint.hector.api.mutation.Mutator;
import org.apache.cassandra.thrift.ColumnParent;
public class AbstractColumnFamilyTemplate<K, N> {
// Used for queries where we just ask for all columns
public static final int ALL_COLUMNS_COUNT = Integer.MAX_VALUE;
public static final Object ALL_COLUMNS_START = null;
public static final Object ALL_COLUMNS_END = null;
protected Keyspace keyspace;
protected String columnFamily;
protected Serializer<K> keySerializer;
protected Map<N, Serializer<?>> columnValueSerializers;
protected ColumnParent columnParent;
protected HSlicePredicate<N> activeSlicePredicate;
protected ColumnFactory columnFactory;
protected ConsistencyLevelPolicy consistencyLevelPolicy;
/** The serializer for a standard column name or a super-column name */
protected Serializer<N> topSerializer;
/**
* By default, execute updates automatically at common-sense points such as
* after queuing the updates of all an object's properties. Or, in the case of
* multiple objects, at the end of the list. No Mutator executes() will be
* called if this is set to true. This allows an arbitrary number of updates
* to be performed and executed manually.
*/
protected boolean batched;
/**
* An optional clock value to pass to deletes. If null, the default value
* generated by Hector is used
*/
protected Long clock;
protected ExceptionsTranslator exceptionsTranslator;
public AbstractColumnFamilyTemplate(Keyspace keyspace, String columnFamily,
Serializer<K> keySerializer, Serializer<N> topSerializer) {
// ugly, but safe
this.keyspace = keyspace;
this.columnFamily = columnFamily;
this.keySerializer = keySerializer;
this.topSerializer = topSerializer;
columnValueSerializers = new HashMap<N, Serializer<?>>();
this.columnParent = new ColumnParent(columnFamily);
this.activeSlicePredicate = new HSlicePredicate<N>(topSerializer);
exceptionsTranslator = new ExceptionsTranslatorImpl();
this.columnFactory = new ThriftColumnFactory();
setCount(100);
}
/**
* Add a column to the static set of columns which will be used in constructing
* the single-argument form of slicing operations
* @param columnName
* @param valueSerializer
*/
public AbstractColumnFamilyTemplate<K,N> addColumn(N columnName, Serializer<?> valueSerializer) {
columnValueSerializers.put(columnName, valueSerializer);
activeSlicePredicate.addColumnName(columnName);
return this;
}
/**
* Get the value serializer for a given column. Returns null if none found
* @param columnName
* @return
*/
public Serializer<?> getValueSerializer(N columnName) {
return columnValueSerializers.get(columnName);
}
public boolean isBatched() {
return batched;
}
public AbstractColumnFamilyTemplate<K, N> setBatched(boolean batched) {
this.batched = batched;
return this;
}
public String getColumnFamily() {
return columnFamily;
}
public Serializer<K> getKeySerializer() {
return keySerializer;
}
public Serializer<N> getTopSerializer() {
return topSerializer;
}
public MutationResult executeBatch(Mutator<K> mutator) {
MutationResult result = mutator.execute();
mutator.discardPendingMutations();
return result;
}
public Mutator<K> createMutator() {
return HFactory.createMutator(keyspace, keySerializer);
}
/**
* Wrapped call to keyspace.createClock
* To Specify a clock for a group of operations, use {@link AbstractTemplateUpdater} instead
* @return
*/
public long getClock() {
return keyspace.createClock();
}
/**
* @deprecated (and not thread-safe). Set clocks on the {@link AbstractTemplateUpdater}
* implementation as needed.
* @param clock
*/
public void setClock(Long clock) {
this.clock = clock;
}
/**
* @deprecated does the same thing as getClock() will be removed in a future release
* @return
*/
public long getEffectiveClock() {
return keyspace.createClock();
}
public void setExceptionsTranslator(ExceptionsTranslator exceptionsTranslator) {
this.exceptionsTranslator = exceptionsTranslator;
}
public void setColumnFactory(ColumnFactory columnFactory) {
this.columnFactory = columnFactory;
}
protected MutationResult executeIfNotBatched(Mutator<K> mutator) {
return !isBatched() ? executeBatch(mutator) : null;
}
protected MutationResult executeIfNotBatched(AbstractTemplateUpdater<K, N> updater) {
return !isBatched() ? executeBatch(updater.getCurrentMutator()) : null;
}
/**
* Immediately delete this row in a single mutation operation
* @param key
*/
public void deleteRow(K key) {
createMutator().addDeletion(key, columnFamily, null, topSerializer).execute();
}
/**
* Stage this deletion into the provided mutator calling {@linkplain #executeIfNotBatched(Mutator)}
* @param mutator
* @param key
*/
public void deleteRow(Mutator<K> mutator, K key) {
mutator.addDeletion(key, columnFamily, null, topSerializer);
executeIfNotBatched(mutator);
}
/**
* Immediately delete this column as a single mutation operation
* @param key
* @param columnName
*/
public void deleteColumn(K key, N columnName) {
createMutator().addDeletion(key, columnFamily, columnName, topSerializer).execute();
}
/**
* Stage this column deletion into the pending mutator. Calls {@linkplain #executeIfNotBatched(Mutator)}
* @param mutator
* @param key
* @param columnName
*/
public void deleteColumn(Mutator<K> mutator, K key, N columnName) {
mutator.addDeletion(key, columnFamily, columnName, topSerializer);
executeIfNotBatched(mutator);
}
/**
* The number of columns to return when not doing a name-based template
* @param count
*/
public void setCount(int count) {
activeSlicePredicate.setCount(count);
}
}