package com.carmanconsulting.cassidy.pojo.simple;
import com.carmanconsulting.cassidy.context.CassidyContext;
import com.carmanconsulting.cassidy.pojo.mapper.ColumnMapper;
import com.carmanconsulting.cassidy.util.CassidyUtils;
import com.carmanconsulting.cassidy.util.PersistableField;
import com.carmanconsulting.cassidy.util.SerializedValue;
import me.prettyprint.cassandra.serializers.AsciiSerializer;
import me.prettyprint.cassandra.serializers.ObjectSerializer;
import me.prettyprint.cassandra.serializers.StringSerializer;
import me.prettyprint.hector.api.beans.HColumn;
import me.prettyprint.hector.api.ddl.ComparatorType;
import me.prettyprint.hector.api.factory.HFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class SimpleColumnMapper<V> implements ColumnMapper<String, V> {
//----------------------------------------------------------------------------------------------------------------------
// Fields
//----------------------------------------------------------------------------------------------------------------------
private static final Logger LOGGER = LoggerFactory.getLogger(SimpleColumnMapper.class);
private static final String POJO_TYPE_COLUMN_NAME = "<<<POJO_TYPE>>>";
private final Map<String, PersistableField> fieldsMap = new HashMap<>();
private final CassidyContext context;
//----------------------------------------------------------------------------------------------------------------------
// Constructors
//----------------------------------------------------------------------------------------------------------------------
public SimpleColumnMapper(Class<V> valueType, CassidyContext context) {
this.context = context;
List<PersistableField> fields = PersistableField.getPersistableFields(valueType);
for (PersistableField field : fields) {
fieldsMap.put(field.getColumnName(), field);
}
}
//----------------------------------------------------------------------------------------------------------------------
// ColumnMapper Implementation
//----------------------------------------------------------------------------------------------------------------------
@Override
@SuppressWarnings("unchecked")
public V fromColumns(List<HColumn<String, byte[]>> columns) {
final Iterator<HColumn<String, byte[]>> iterator = columns.iterator();
final V entity = instantiateFromColumn(iterator.next());
while (iterator.hasNext()) {
final HColumn<String, byte[]> column = iterator.next();
final PersistableField field = fieldsMap.get(column.getName());
if (field != null) {
final SerializedValue serializedValue = (SerializedValue) ObjectSerializer.get().fromBytes(column.getValue());
final Object fieldValue = serializedValue.getValue(context);
field.setValue(entity, fieldValue);
} else {
LOGGER.warn("Column {} not mapped to a persistent field on class {}!", column.getName(), entity.getClass().getCanonicalName());
}
}
return entity;
}
@Override
public ComparatorType getComparatorType() {
return ComparatorType.ASCIITYPE;
}
@Override
public String getComparatorTypeAlias() {
return null;
}
@Override
@SuppressWarnings("unchecked")
public List<HColumn<String, ?>> toColumns(V object) {
List<HColumn<String, ?>> columns = new LinkedList<>();
columns.add(HFactory.createStringColumn(POJO_TYPE_COLUMN_NAME, object.getClass().getName()));
for (PersistableField field : fieldsMap.values()) {
final Object fieldValue = field.getValue(object);
if (!CassidyUtils.isDefaultValue(field.getType(), fieldValue)) {
final SerializedValue serializedValue = new SerializedValue(context, fieldValue);
columns.add(HFactory.createColumn(field.getColumnName(), serializedValue, AsciiSerializer.get(), ObjectSerializer.get()));
}
}
return columns;
}
//----------------------------------------------------------------------------------------------------------------------
// Other Methods
//----------------------------------------------------------------------------------------------------------------------
@SuppressWarnings("unchecked")
private V instantiateFromColumn(HColumn<String, byte[]> column) {
final String typeName = StringSerializer.get().fromBytes(column.getValue());
final V object = (V) CassidyUtils.instantiate(context.classPath().resolveClass(typeName));
setFieldsToDefault(object);
return object;
}
private void setFieldsToDefault(V object) {
for (PersistableField field : fieldsMap.values()) {
field.setToDefault(object);
}
}
}