package com.kryptnostic.rhizome.mapstores.cassandra;
import java.nio.ByteBuffer;
import java.util.Collection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Select;
import com.google.common.base.Preconditions;
import com.kryptnostic.rhizome.mappers.SelfRegisteringValueMapper;
import com.kryptnostic.rhizome.mapstores.MappingException;
public class DefaultCassandraSetProxy<K, T> extends BaseCassandraSetProxy<K, T> {
private static final Logger logger = LoggerFactory.getLogger( DefaultCassandraSetProxy.class );
final SelfRegisteringValueMapper<T> typeMapper;
private static final String MAPPING_ERROR = "Exception while mapping";
private final PreparedStatement CONTAINS_STATEMENT;
private final PreparedStatement ADD_STATEMENT;
private final PreparedStatement DELETE_STATEMENT;
private final String setId;
private final Class<T> innerClass;
public DefaultCassandraSetProxy(
Session session,
String keyspace,
String table,
String mappedSetId,
Class<T> innerClass,
SelfRegisteringValueMapper<T> typeMapper ) {
super(
session,
keyspace,
table,
getStatement( keyspace, table, mappedSetId ),
size( keyspace, table, mappedSetId ) );
// use cluster.newSession() here to avoid having to connect to cassandra on object creation
this.setId = mappedSetId;
this.innerClass = innerClass;
this.typeMapper = typeMapper;
ProxyKey key = new ProxyKey( keyspace, table );
ADD_STATEMENT = SetProxyBackedCassandraMapStore.SP_ADD_STATEMENTS.getIfPresent( key );
DELETE_STATEMENT = SetProxyBackedCassandraMapStore.SP_DELETE_STATEMENTS.getIfPresent( key );
CONTAINS_STATEMENT = SetProxyBackedCassandraMapStore.SP_CONTAINS_STATEMENTS.getIfPresent( key );
Preconditions.checkNotNull( ADD_STATEMENT,
"something terribly terribly wrong happenend to the SetProxy add statement" );
Preconditions.checkNotNull( DELETE_STATEMENT,
"something terribly terribly wrong happenend to the SetProxy delete statement" );
Preconditions.checkNotNull( CONTAINS_STATEMENT,
"something terribly terribly wrong happenend to the SetProxy contains statement" );
}
private static Select.Where size( String keyspace, String table, String mappedSetId ) {
return QueryBuilder.select().countAll()
.from( keyspace, table )
.where( QueryBuilder.eq( KEY_COLUMN_NAME, mappedSetId ) );
}
private static Select.Where getStatement( String keyspace, String table, String mappedSetId ) {
return QueryBuilder.select( VALUE_COLUMN_NAME )
.from( keyspace, table )
.where( QueryBuilder.eq( KEY_COLUMN_NAME, mappedSetId ) );
}
@Override
public boolean contains( Object o ) {
if( innerClass.isAssignableFrom( o.getClass() ) ) {
return containsValue( innerClass.cast( o ) );
}
return false;
}
public boolean containsValue( T value ) {
ResultSet execute;
try {
execute = session.execute( CONTAINS_STATEMENT.bind( setId, valueToBytes( value ) ) );
int results = getCountResult( execute );
return results == 1;
} catch ( MappingException e ) {
logger.error( MAPPING_ERROR, e );
}
return false;
}
@Override
public boolean add( T e ) {
try {
// append to the set as a new row
session.execute( ADD_STATEMENT.bind( setId, valueToBytes( e ) ) );
return true;
} catch ( MappingException e1 ) {
logger.error( MAPPING_ERROR, e1 );
}
return false;
}
@Override
public boolean remove( Object o ) {
try {
session.execute( DELETE_STATEMENT.bind( setId, valueToBytes( (T) o ) ) );
return true;
} catch ( MappingException e ) {
logger.error( MAPPING_ERROR, e );
}
return false;
}
@Override
public boolean containsAll( Collection<?> c ) {
for ( Object x : c ) {
if ( !contains( x ) ) {
return false;
}
}
return true;
}
@Override
public boolean addAll( Collection<? extends T> c ) {
// TODO: p1: make this efficient
boolean ret = false;
for ( T element : c ) {
boolean modified = add( element );
if ( modified ) {
ret = true;
}
}
return ret;
}
private ByteBuffer valueToBytes( T value ) throws MappingException {
return ByteBuffer.wrap( typeMapper.toBytes( value ) );
}
/**
* @return the typeMapper
*/
public SelfRegisteringValueMapper<T> getTypeMapper() {
return typeMapper;
}
public String getSetId() {
return setId;
}
@Override
public Class<T> getTypeClazz() {
return innerClass;
}
@Override
protected T mapRowToValue( Row row ) {
ByteBuffer bytes = row.getBytes( VALUE_COLUMN_NAME );
byte[] array = bytes.array();
try {
T fromBytes = typeMapper.fromBytes( array );
return fromBytes;
} catch ( MappingException e ) {
logger.error( MAPPING_ERROR, e );
}
return null;
}
}