package me.prettyprint.cassandra.service.template; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.UUID; import me.prettyprint.cassandra.model.ExecutionResult; import me.prettyprint.cassandra.model.HColumnImpl; 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.UUIDSerializer; import me.prettyprint.hector.api.Serializer; import me.prettyprint.hector.api.beans.HColumn; import me.prettyprint.hector.api.beans.HSuperColumn; import me.prettyprint.hector.api.factory.HFactory; import org.apache.cassandra.thrift.Column; import org.apache.cassandra.thrift.ColumnOrSuperColumn; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Provides access to the current row of data during super column queries. * * @author zznate * @param <N> the super column's sub column name type */ public class SuperCfResultWrapper<K,SN,N> extends AbstractResultWrapper<K,N> implements SuperCfResult<K,SN,N> { private static final Logger log = LoggerFactory.getLogger(SuperCfResultWrapper.class); private Map<SN,Map<N,HColumn<N,ByteBuffer>>> columns = new LinkedHashMap<SN,Map<N,HColumn<N,ByteBuffer>>>(); private Iterator<Map.Entry<ByteBuffer, List<ColumnOrSuperColumn>>> rows; private Map.Entry<ByteBuffer, List<ColumnOrSuperColumn>> entry; private List<SN> superColumns; private Map<N,HColumn<N,ByteBuffer>> subColumns = new LinkedHashMap<N,HColumn<N,ByteBuffer>>(); private SN currentSuperColumn; private boolean hasEntries; private Serializer<SN> sNameSerializer; public SuperCfResultWrapper(Serializer<K> keySerializer, Serializer<SN> sNameSerializer, Serializer<N> subSerializer, ExecutionResult<Map<ByteBuffer, List<ColumnOrSuperColumn>>> executionResult) { super(keySerializer, subSerializer, executionResult); this.sNameSerializer = sNameSerializer; this.rows = executionResult.get().entrySet().iterator(); next(); hasEntries = getSuperColumns() != null && getSuperColumns().size() > 0; } @Override public SuperCfResult<K, SN, N> next() { if ( !hasNext() ) { throw new NoSuchElementException("No more rows left on this HColumnFamily"); } entry = rows.next(); log.debug("found entry {} with value {}", getKey(), entry.getValue()); applyToRow(entry.getValue()); return this; } private void applyToRow(List<ColumnOrSuperColumn> cosclist) { superColumns = new ArrayList<SN>(cosclist.size()); for (Iterator<ColumnOrSuperColumn> iterator = cosclist.iterator(); iterator.hasNext();) { ColumnOrSuperColumn cosc = iterator.next(); SN sColName = sNameSerializer.fromByteBuffer(cosc.super_column.name.duplicate()); log.debug("cosc {}", cosc.super_column); superColumns.add(sColName); Iterator<Column> tcolumns = cosc.getSuper_column().getColumnsIterator(); Map<N,HColumn<N,ByteBuffer>> subColMap = new LinkedHashMap<N, HColumn<N,ByteBuffer>>(); while ( tcolumns.hasNext() ) { Column col = tcolumns.next(); subColMap.put(columnNameSerializer.fromByteBuffer(col.name.duplicate()), new HColumnImpl<N, ByteBuffer>(col, columnNameSerializer, ByteBufferSerializer.get())); } columns.put(sColName, subColMap); } } public List<SN> getSuperColumns() { return superColumns; } @Override public ByteBuffer getColumnValue(N columnName) { HColumn<N,ByteBuffer> col = getColumn( columnName ); return col != null ? col.getValue() : null; } @Override public K getKey() { return keySerializer.fromByteBuffer(entry.getKey().duplicate()); } @Override public HColumn<N, ByteBuffer> getColumn(N columnName) { return subColumns == null ? null : subColumns.get( columnName ); } @Override public Collection<N> getColumnNames() { return subColumns != null ? subColumns.keySet() : new ArrayList<N>(); } @Override public boolean hasNext() { return rows.hasNext(); } @Override public void remove() { rows.remove(); } private <V> V extractType(SN sColumnName, N columnName, Serializer<V> valueSerializer) { Map<N, HColumn<N, ByteBuffer>> map = columns.get(sColumnName); if ( map != null && map.get(columnName) != null ) return valueSerializer.fromByteBuffer(map.get(columnName).getValue()); return null; } @Override public Boolean getBoolean(SN sColumnName, N columnName) { return extractType(sColumnName, columnName, BooleanSerializer.get()); } @Override public byte[] getByteArray(SN sColumnName, N columnName) { return extractType(sColumnName, columnName, BytesArraySerializer.get()); } @Override public Date getDate(SN sColumnName, N columnName) { return extractType(sColumnName, columnName, DateSerializer.get()); } @Override public Integer getInteger(SN sColumnName, N columnName) { return extractType(sColumnName, columnName, IntegerSerializer.get()); } @Override public Long getLong(SN sColumnName, N columnName) { return extractType(sColumnName, columnName, LongSerializer.get()); } @Override public Float getFloat(SN sColumnName, N columnName) { return extractType(sColumnName, columnName, FloatSerializer.get()); } @Override public Double getDouble(SN sColumnName, N columnName) { return extractType(sColumnName, columnName, DoubleSerializer.get()); } @Override public String getString(SN sColumnName, N columnName) { return extractType(sColumnName, columnName, StringSerializer.get()); } @Override public UUID getUUID(SN sColumnName, N columnName) { return extractType(sColumnName, columnName, UUIDSerializer.get()); } @Override public ByteBuffer getByteBuffer(SN sColumnName, N columnName) { return extractType(sColumnName, columnName, ByteBufferSerializer.get()); } @Override public SN getActiveSuperColumn() { return currentSuperColumn; } @Override public HSuperColumn<SN, N, ByteBuffer> getSuperColumn(SN sColumnName) { Map<N, HColumn<N, ByteBuffer>> subCols = columns.get(sColumnName); HSuperColumnImpl<SN, N, ByteBuffer> scol = new HSuperColumnImpl<SN, N, ByteBuffer>(sColumnName, new ArrayList<HColumn<N,ByteBuffer>>(subCols.values()), HFactory.createClock(), sNameSerializer, columnNameSerializer, ByteBufferSerializer.get()); return scol; } @Override public void applySuperColumn(SN sColumnName) { this.currentSuperColumn = sColumnName; this.subColumns = columns.get(currentSuperColumn); } @Override public boolean hasResults() { return hasEntries; } }