package me.prettyprint.hom;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import me.prettyprint.cassandra.serializers.ObjectSerializer;
import me.prettyprint.hector.api.beans.HColumn;
import me.prettyprint.hom.cache.HectorObjectMapperException;
import com.google.common.base.Splitter;
public class CollectionMapperHelper {
private ReflectionHelper reflectionHelper = new ReflectionHelper();
private ObjectSerializer objSer = ObjectSerializer.get();
public String createCollectionItemColName(String propName, int order) {
return propName + ":" + order;
}
public CollectionItemColName parseCollectionItemColName(String colName) {
try {
Iterable<String> split = Splitter.on(':').split(colName);
Iterator<String> iter = split.iterator();
return new CollectionItemColName(iter.next(), Integer.parseInt(iter.next()));
} catch (Throwable e) {
throw new HectorObjectMapperException("exception while parsing collection item column name, "
+ colName, e);
}
}
public byte[] createCollectionInfoColValue(Collection<Object> coll) {
// translate some classes that don't make as much sense when loaded
String className = coll.getClass().getName();
if ( className.endsWith("$SingletonList")) {
className = "java.util.ArrayList";
}
else if ( className.endsWith("$SingletonMap")) {
className = "java.util.HashMap";
}
else if ( className.endsWith("$SingletonSet")) {
className = "java.util.HashSet";
}
return String.valueOf(className + ":" + coll.size()).getBytes();
}
public CollectionInfoColValue parseCollectionInfoColValue(byte[] val) {
try {
String tmp = new String(val);
Iterable<String> split = Splitter.on(':').split(tmp);
Iterator<String> iter = split.iterator();
String className = iter.next();
return new CollectionInfoColValue(className, Integer.parseInt(iter.next()));
} catch (Throwable e) {
throw new HectorObjectMapperException("exception while parsing collection info column value",
e);
}
}
@SuppressWarnings("rawtypes")
public void instantiateCollection(Object obj, HColumn<String, byte[]> col,
PropertyMappingDefinition md) {
CollectionInfoColValue colValue = parseCollectionInfoColValue(col.getValue());
try {
// type name is Class that needs instantiating. examine for special class
// features, like ArrayList taking a size hint in constructor
Collection<?> collObj;
Class clazz = Class.forName(colValue.getCollTypeName());
if (ArrayList.class.isAssignableFrom(clazz)) {
Constructor<ArrayList> cons = ArrayList.class.getConstructor(int.class);
collObj = cons.newInstance(colValue.getSize());
} else {
collObj = (Collection<?>) clazz.newInstance();
}
// now save collection to object
PropertyDescriptor pd = md.getPropDesc();
if (null == pd.getWriteMethod()) {
throw new RuntimeException("property, " + pd.getName()
+ ", does not have a setter and therefore cannot be set");
}
pd.getWriteMethod().invoke(obj, collObj);
} catch (Throwable e) {
throw new HectorObjectMapperException("exception while instantiating Collection type, "
+ colValue.getCollTypeName(), e);
}
}
@SuppressWarnings("unchecked")
public boolean addColumnToCollection(CFMappingDef<?> cfMapDef, Object obj, String colName,
byte[] colValue) {
// if can parse, then at least adheres to formatting
CollectionItemColName collColumnName;
try {
collColumnName = parseCollectionItemColName(colName);
} catch (HectorObjectMapperException e) {
return false;
}
// get property from mapping def - if not there, then isn't a collection
// (but probably a problem elsewhere)
PropertyMappingDefinition md = cfMapDef.getPropMapByColumnName(collColumnName.getPropertyName());
if (null == md) {
return false;
}
Collection<Object> coll;
try {
coll = (Collection<Object>) reflectionHelper.invokeGetter(obj, md);
} catch (HectorObjectMapperException e) {
return false;
}
Object value = deserializeCollectionValue(colValue);
coll.add(value);
return true;
}
public byte[] serializeCollectionValue(Object obj) {
return objSer.toBytes(obj);
}
public Object deserializeCollectionValue(byte[] bytes) {
return objSer.fromBytes(bytes);
}
// ------------------------------------------------
public class CollectionItemColName {
private String propertyName;
private int order;
public CollectionItemColName(String propertyName, int order) {
this.propertyName = propertyName;
this.order = order;
}
public String getPropertyName() {
return propertyName;
}
public int getOrder() {
return order;
}
private CollectionMapperHelper getOuterType() {
return CollectionMapperHelper.this;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + order;
result = prime * result + ((propertyName == null) ? 0 : propertyName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CollectionItemColName other = (CollectionItemColName) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (order != other.order)
return false;
if (propertyName == null) {
if (other.propertyName != null)
return false;
} else if (!propertyName.equals(other.propertyName))
return false;
return true;
}
@Override
public String toString() {
return "CollectionItemColName [propertyName=" + propertyName + ", order=" + order + "]";
}
}
public class CollectionInfoColValue {
private String collTypeName;
private int size;
public CollectionInfoColValue(String collTypeName, int size) {
this.collTypeName = collTypeName;
this.size = size;
}
public String getCollTypeName() {
return collTypeName;
}
public int getSize() {
return size;
}
private CollectionMapperHelper getOuterType() {
return CollectionMapperHelper.this;
}
@Override
public String toString() {
return "CollectionInfoColValue [collTypeName=" + collTypeName + ", size=" + size + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + ((collTypeName == null) ? 0 : collTypeName.hashCode());
result = prime * result + size;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CollectionInfoColValue other = (CollectionInfoColValue) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (collTypeName == null) {
if (other.collTypeName != null)
return false;
} else if (!collTypeName.equals(other.collTypeName))
return false;
if (size != other.size)
return false;
return true;
}
}
}