package me.prettyprint.cassandra.service.template; import java.util.List; import me.prettyprint.cassandra.model.HSlicePredicate; import me.prettyprint.cassandra.serializers.SerializerTypeInferer; import me.prettyprint.hector.api.Keyspace; import me.prettyprint.hector.api.Serializer; import me.prettyprint.hector.api.beans.HColumn; import me.prettyprint.hector.api.factory.HFactory; import me.prettyprint.hector.api.mutation.Mutator; import me.prettyprint.hector.api.query.ColumnQuery; import me.prettyprint.hector.api.query.CountQuery; import me.prettyprint.hector.api.query.QueryResult; /** * This applies a Template Method pattern, much like Spring's JdbcTemplate, to * Cassandra. The ColumnFamilyTemplate instance maintains many of the fields in * common between various query/update operations so that they do not need to be * constantly passed for every operation on the column family. These include the * keyspace, column family name, key serializer, and the column name serializer * (for standard column name or the super column name). * * The Java generic types of the ColumnFamilyTemplate class itself are limited to * the key and column name type. It defers the generic types for super column * child types to the individual update/query operation. * * @author david * @author zznate * @param <K> * The column family key type * @param <N> * The column family name type */ public abstract class ColumnFamilyTemplate<K, N> extends AbstractColumnFamilyTemplate<K, N> { public ColumnFamilyTemplate(Keyspace keyspace, String columnFamily, Serializer<K> keySerializer, Serializer<N> topSerializer) { super(keyspace, columnFamily, keySerializer, topSerializer); } // Just so method chaining will return this type instead of the parent class // for operations down the chain public ColumnFamilyTemplate<K, N> setBatched(boolean batched) { super.setBatched(batched); return this; } public ColumnFamilyUpdater<K, N> createUpdater() { ColumnFamilyUpdater<K, N> updater = new ColumnFamilyUpdater<K, N>(this, columnFactory); return updater; } public ColumnFamilyUpdater<K, N> createUpdater(K key) { ColumnFamilyUpdater<K, N> updater = new ColumnFamilyUpdater<K, N>(this, columnFactory); updater.addKey(key); return updater; } public ColumnFamilyUpdater<K, N> createUpdater(K key, Mutator<K> mutator) { ColumnFamilyUpdater<K, N> updater = new ColumnFamilyUpdater<K, N>(this, columnFactory, mutator); updater.addKey(key); return updater; } public void update(ColumnFamilyUpdater<K, N> updater) { updater.update(); executeIfNotBatched(updater); } /** * Checks if there are any columns at a row specified by key in a standard * column family * * @param key * @return true if columns exist */ public boolean isColumnsExist(K key) { return countColumns(key) > 0; } /** * @param key * @return the number of columns in a standard column family at the specified * row key */ @SuppressWarnings("unchecked") public int countColumns(K key) { return countColumns(key, (N) ALL_COLUMNS_START, (N) ALL_COLUMNS_END, ALL_COLUMNS_COUNT); } /** * Counts columns in the specified range of a standard column family * * @param key * @param start * @param end * @param max * @return */ public int countColumns(K key, N start, N end, int max) { CountQuery<K, N> query = HFactory.createCountQuery(keyspace, keySerializer, topSerializer); query.setKey(key); query.setColumnFamily(columnFamily); query.setRange(start, end, max); return query.execute().get(); } public ColumnFamilyResult<K, N> queryColumns(K key) { return doExecuteSlice(key, activeSlicePredicate); } public ColumnFamilyResult<K, N> queryColumns(Iterable<K> keys) { return doExecuteMultigetSlice(keys, activeSlicePredicate); } public <T> T queryColumns(K key, ColumnFamilyRowMapper<K, N, T> mapper) { return queryColumns(key, activeSlicePredicate, mapper); } /** * Queries a range of columns at the given key and maps them to an object of * type OBJ using the given mapping object * * @param <T> * @param key * @param predicate The {@link HSlicePredicate} which can hold specific column names * or a range of columns * @param mapper * @return */ public <T> T queryColumns(K key, HSlicePredicate<N> predicate, ColumnFamilyRowMapper<K, N, T> mapper) { return doExecuteSlice(key, predicate, mapper); } /** * Queries all columns at a given key and maps them to an object of type OBJ * using the given mapping object * * @param <T> * @param key * @param columns * @param mapper * @return */ public <T> T queryColumns(K key, List<N> columns, ColumnFamilyRowMapper<K, N, T> mapper) { HSlicePredicate<N> predicate = new HSlicePredicate<N>(topSerializer); predicate.setColumnNames(columns); return doExecuteSlice(key, predicate, mapper); } public ColumnFamilyResult<K, N> queryColumns(K key, List<N> columns) { HSlicePredicate<N> predicate = new HSlicePredicate<N>(topSerializer); predicate.setColumnNames(columns); return doExecuteSlice(key, predicate); } public ColumnFamilyResult<K, N> queryColumns(Iterable<K> keys, List<N> columns) { HSlicePredicate<N> predicate = new HSlicePredicate<N>(topSerializer); predicate.setColumnNames(columns); return doExecuteMultigetSlice(keys, predicate); } public ColumnFamilyResult<K, N> queryColumns(K key, HSlicePredicate<N> predicate) { return doExecuteSlice(key, predicate); } public <V> MappedColumnFamilyResult<K,N,V> queryColumns(Iterable<K> keys, ColumnFamilyRowMapper<K, N, V> mapper) { return doExecuteMultigetSlice(keys, activeSlicePredicate, mapper); } public <V> MappedColumnFamilyResult<K,N,V> queryColumns(Iterable<K> keys, HSlicePredicate<N> predicate, ColumnFamilyRowMapper<K, N, V> mapper) { return doExecuteMultigetSlice(keys, predicate, mapper); } public <V> MappedColumnFamilyResult<K,N,V> queryColumns(Iterable<K> keys, List<N> columns, ColumnFamilyRowMapper<K, N, V> mapper) { HSlicePredicate<N> predicate = new HSlicePredicate<N>(topSerializer); predicate.setColumnNames(columns); return doExecuteMultigetSlice(keys, predicate, mapper); } public <V> ColumnFamilyResult<K,N> queryColumns(IndexedSlicesPredicate<K,N,V> predicate) { return doExecuteIndexedSlices(predicate); } public <V> ColumnFamilyResult<K,N> queryColumns(IndexedSlicesPredicate<K,N,V> predicate, HSlicePredicate<N> slicePredicate) { return doExecuteIndexedSlices(predicate, slicePredicate); } public <V> ColumnFamilyResult<K,N> queryColumns(IndexedSlicesPredicate<K,N,V> predicate, List<N> columns) { HSlicePredicate<N> slicePredicate = new HSlicePredicate<N>(topSerializer); slicePredicate.setColumnNames(columns); return doExecuteIndexedSlices(predicate, slicePredicate); } public <R,V> MappedColumnFamilyResult<K,N,R> queryColumns(IndexedSlicesPredicate<K,N,V> predicate, ColumnFamilyRowMapper<K, N, R> mapper) { return doExecuteIndexedSlices(predicate, mapper); } public <R,V> MappedColumnFamilyResult<K,N,R> queryColumns(IndexedSlicesPredicate<K,N,V> predicate, HSlicePredicate<N> slicePredicate, ColumnFamilyRowMapper<K, N, R> mapper) { return doExecuteIndexedSlices(predicate, slicePredicate, mapper); } public <R,V> MappedColumnFamilyResult<K,N,R> queryColumns(IndexedSlicesPredicate<K,N,V> predicate, List<N> columns, ColumnFamilyRowMapper<K, N, R> mapper) { HSlicePredicate<N> slicePredicate = new HSlicePredicate<N>(topSerializer); slicePredicate.setColumnNames(columns); return doExecuteIndexedSlices(predicate, slicePredicate, mapper); } @SuppressWarnings("unchecked") public <V> HColumn<N, V> querySingleColumn(K key, N columnName, Class<V> valueClass) { return querySingleColumn(key, columnName, (Serializer<V>) SerializerTypeInferer.getSerializer(valueClass)); } public <V> HColumn<N, V> querySingleColumn(K key, N columnName, Serializer<V> valueSerializer) { ColumnQuery<K, N, V> query = HFactory.createColumnQuery(keyspace, keySerializer, topSerializer, valueSerializer); query.setColumnFamily(columnFamily); query.setKey(key); query.setName(columnName); QueryResult<HColumn<N, V>> result = query.execute(); return result != null ? result.get() : null; } //-------------------------- delegation methods ---------------------------- protected abstract <T> T doExecuteSlice(K key, HSlicePredicate<N> predicate, ColumnFamilyRowMapper<K, N, T> mapper); protected abstract ColumnFamilyResult<K, N> doExecuteSlice(final K key, final HSlicePredicate<N> workingSlicePredicate); protected abstract ColumnFamilyResult<K, N> doExecuteMultigetSlice(final Iterable<K> keys, final HSlicePredicate<N> workingSlicePredicate); protected abstract <V> MappedColumnFamilyResult<K, N, V> doExecuteMultigetSlice(final Iterable<K> keys, final HSlicePredicate<N> workingSlicePredicate, final ColumnFamilyRowMapper<K, N, V> mapper); protected abstract <V> ColumnFamilyResult<K, N> doExecuteIndexedSlices(final IndexedSlicesPredicate<K, N, V> predicate); protected abstract <V> ColumnFamilyResult<K, N> doExecuteIndexedSlices(final IndexedSlicesPredicate<K, N, V> predicate, final HSlicePredicate<N> slicePredicate); protected abstract <R,V> MappedColumnFamilyResult<K, N, R> doExecuteIndexedSlices(final IndexedSlicesPredicate<K,N,V> predicate, final ColumnFamilyRowMapper<K, N, R> mapper); protected abstract <R,V> MappedColumnFamilyResult<K, N, R> doExecuteIndexedSlices(final IndexedSlicesPredicate<K,N,V> predicate, final HSlicePredicate<N> slicePredicate, final ColumnFamilyRowMapper<K, N, R> mapper); }