package me.prettyprint.cassandra.service.template;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import me.prettyprint.cassandra.model.HSuperColumnImpl;
import me.prettyprint.cassandra.serializers.BooleanSerializer;
import me.prettyprint.cassandra.serializers.ByteBufferSerializer;
import me.prettyprint.cassandra.serializers.BytesArraySerializer;
import me.prettyprint.cassandra.serializers.DateSerializer;
import me.prettyprint.cassandra.serializers.DoubleSerializer;
import me.prettyprint.cassandra.serializers.FloatSerializer;
import me.prettyprint.cassandra.serializers.IntegerSerializer;
import me.prettyprint.cassandra.serializers.LongSerializer;
import me.prettyprint.cassandra.serializers.StringSerializer;
import me.prettyprint.cassandra.serializers.TypeInferringSerializer;
import me.prettyprint.cassandra.serializers.UUIDSerializer;
import me.prettyprint.hector.api.ColumnFactory;
import me.prettyprint.hector.api.Serializer;
import me.prettyprint.hector.api.beans.HColumn;
/**
* This provides an interface of updating a specified row, most likely with the
* contents of an object. This would likely by implemented as an anonymous inner
* class with access to a final object in scope. It would update the given row
* with the object's data.
*
* This is currently implemented as an abstract base class instead of an
* interface. This could change in the future. Being an abstract base class
* allows CassandraTemplate to initialize this instance through package scope
* field access. This means that implementation of update() simply makes
* consecutive calls to various set****() methods which already have the
* contextual information they need to update the correct row.
*
* The downside of this approach is that the updater is essentially stateful and
* cannot be used concurrently. The alternative is to pass an object in to
* update() as a parameter with the setter methods, leaving the updater to be
* stateless.
*
* @author david
* @since Mar 10, 2011
* @param <K>
* the key's data type
* @param <SN>
* the standard or super column's data type
* @param <N>
* the child column name type in a super column
*/
public class SuperCfUpdater<K,SN,N> extends AbstractTemplateUpdater<K, N> {
private static final Logger log = LoggerFactory.getLogger(SuperCfUpdater.class);
protected SuperCfTemplate<K,SN, N> template;
private List<SN> sColumnNames;
private int sColPos;
private HSuperColumnImpl<SN,N,?> activeColumn;
private List<HColumn> subColumns;
public SuperCfUpdater(SuperCfTemplate<K,SN,N> sTemplate, ColumnFactory columnFactory) {
super((AbstractColumnFamilyTemplate<K, N>) sTemplate, columnFactory, sTemplate.createMutator());
this.template = sTemplate;
}
@Override
public SuperCfUpdater<K, SN, N> addKey(K key) {
if ( keys != null && keys.size() > 0 ) {
updateInternal();
}
super.addKey(key);
sColumnNames = new ArrayList<SN>();
sColPos = 0;
return this;
}
public SuperCfUpdater<K,SN,N> addSuperColumn(SN sColumnName) {
if ( sColumnNames.size() > 0 ) {
updateInternal();
sColPos++;
}
subColumns = new ArrayList<HColumn>();
sColumnNames.add(sColumnName);
return this;
}
public SN getCurrentSuperColumn() {
return sColumnNames.get(sColPos);
}
/**
* collapse the state of the active HSuperColumn
*/
void updateInternal() {
// HSuperColumnImpl needs a refactor, this construction is lame.
// the value serializer is not used in HSuperColumnImpl, so this is safe for name
if ( !subColumns.isEmpty() ) {
log.debug("Adding column {} for key {} and cols {}", new Object[]{getCurrentSuperColumn(), getCurrentKey(), subColumns});
HSuperColumnImpl<SN, N, ?> column = new HSuperColumnImpl(getCurrentSuperColumn(), subColumns,
0, template.getTopSerializer(), template.getSubSerializer(), TypeInferringSerializer.get());
mutator.addInsertion(getCurrentKey(), template.getColumnFamily(), column);
}
}
/**
* Deletes the super column and all of its sub columns
*/
public void deleteSuperColumn() {
//template.getMutator().addDeletion(getCurrentKey(), template.getColumnFamily(),
// getCurrentSuperColumn(), template.getTopSerializer());
mutator.addSuperDelete(getCurrentKey(), template.getColumnFamily(),
getCurrentSuperColumn(), template.getTopSerializer());
}
public void deleteSubColumn(N columnName) {
mutator.addSubDelete(getCurrentKey(), template.getColumnFamily(),
getCurrentSuperColumn(), columnName, template.getTopSerializer(), template.getSubSerializer());
}
public void setString(N subColumnName, String value) {
addToSubColumns(subColumnName, value, StringSerializer.get(), globalTtl);
}
public void setUUID(N subColumnName, UUID value) {
addToSubColumns(subColumnName, value, UUIDSerializer.get(), globalTtl);
}
public void setLong(N subColumnName, Long value) {
addToSubColumns(subColumnName, value, LongSerializer.get(), globalTtl);
}
public void setInteger(N subColumnName, Integer value) {
addToSubColumns(subColumnName, value, IntegerSerializer.get(), globalTtl);
}
public void setBoolean(N subColumnName, Boolean value) {
addToSubColumns(subColumnName, value, BooleanSerializer.get(), globalTtl);
}
public void setByteArray(N subColumnName, byte[] value) {
addToSubColumns(subColumnName, value, BytesArraySerializer.get(), globalTtl);
}
public void setByteBuffer(N subColumnName, ByteBuffer value) {
addToSubColumns(subColumnName, value, ByteBufferSerializer.get(), globalTtl);
}
public void setDate(N subColumnName, Date value) {
addToSubColumns(subColumnName, value, DateSerializer.get(), globalTtl);
}
public void setFloat(N subColumnName, Float value) {
subColumns.add(columnFactory.createColumn(subColumnName, value, clock,
template.getSubSerializer(), FloatSerializer.get()));
}
public void setDouble(N subColumnName, Double value) {
addToSubColumns(subColumnName, value, DoubleSerializer.get(), globalTtl);
}
public <V> void setValue(N subColumnName, V value, Serializer<V> serializer) {
addToSubColumns(subColumnName, value, serializer, globalTtl);
}
private <V> void addToSubColumns(N subColumnName, V value, Serializer<V> valueSerializer, int ttl) {
HColumn<N,V> col = columnFactory.createColumn(subColumnName, value, template.getSubSerializer(), valueSerializer);
if(ttl > DEF_TTL) {
col.setTtl(globalTtl);
}
subColumns.add(col);
}
}