package com.feedly.cassandra.dao; import java.math.BigInteger; import java.util.Collection; import java.util.List; import me.prettyprint.cassandra.serializers.BytesArraySerializer; import me.prettyprint.cassandra.serializers.CompositeSerializer; import me.prettyprint.cassandra.serializers.DynamicCompositeSerializer; import me.prettyprint.cassandra.serializers.LongSerializer; import me.prettyprint.cassandra.serializers.StringSerializer; import me.prettyprint.hector.api.Serializer; import me.prettyprint.hector.api.beans.AbstractComposite.ComponentEquality; import me.prettyprint.hector.api.beans.DynamicComposite; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.feedly.cassandra.IKeyspaceFactory; import com.feedly.cassandra.entity.EPropertyType; import com.feedly.cassandra.entity.EntityMetadata; import com.feedly.cassandra.entity.EntityUtils; import com.feedly.cassandra.entity.PropertyMetadataBase; import com.feedly.cassandra.entity.enhance.EntityTransformerTask; import com.feedly.cassandra.entity.enhance.IEnhancedEntity; abstract class DaoHelperBase<K,V> { protected final Logger _logger = LoggerFactory.getLogger(getClass().getName()); protected static final BytesArraySerializer SER_BYTES = BytesArraySerializer.get(); protected static final StringSerializer SER_STRING = StringSerializer.get(); protected static final DynamicCompositeSerializer SER_DYNAMIC_COMPOSITE = new DynamicCompositeSerializer(); protected static final CompositeSerializer SER_COMPOSITE = new CompositeSerializer(); protected static final LongSerializer SER_LONG = LongSerializer.get(); protected final EntityMetadata<V> _entityMeta; protected final IKeyspaceFactory _keyspaceFactory; protected final OperationStatistics _stats; protected final int _statsSize; DaoHelperBase(EntityMetadata<V> meta, IKeyspaceFactory factory, int statsSize) { _entityMeta = meta; _keyspaceFactory = factory; _stats = new OperationStatistics(statsSize); _statsSize = statsSize; } protected static boolean isSimpleProp(PropertyMetadataBase pmb) { return pmb.getPropertyType() == EPropertyType.SIMPLE; } public OperationStatistics stats() { return _stats; } /** * generate a property name for a collection property * @param cp * @param keyEq * @return */ protected byte[] collectionPropertyName(CollectionProperty cp, ComponentEquality keyEq) { PropertyMetadataBase pm = _entityMeta.getProperty(cp.getProperty()); if(pm == null || isSimpleProp(pm)) throw new IllegalArgumentException("property " + cp.getProperty() + " is not a collection"); if(pm.getPropertyType() == EPropertyType.LIST && !(cp.getKey() instanceof Integer)) throw new IllegalArgumentException("key for property" + cp.getProperty() + " must be an int"); DynamicComposite dc = new DynamicComposite(); dc.addComponent(0, pm.getPhysicalName(), ComponentEquality.EQUAL); Object colKey = cp.getKey(); if(pm.getFieldType().equals(List.class)) colKey = BigInteger.valueOf(((Integer) colKey).longValue()); dc.addComponent(1, colKey, keyEq); return SER_DYNAMIC_COMPOSITE.toBytes(dc); } /** * generate a property name (column name) * @param from the from value, can be a {@link CollectionProperty} * @param eq * @return the key */ protected byte[] propertyName(Object from, ComponentEquality eq) { if(from instanceof CollectionProperty) return collectionPropertyName((CollectionProperty) from, eq); else return serialize(from, true, null); } /** * helper to serialize values * @param val the value * @param isColName is the value a column name * @param serializer the serializer to use, if null is passed one will try to be inferred * @return the serialized byte[] */ @SuppressWarnings({ "rawtypes", "unchecked" }) protected byte[] serialize(Object val, boolean isColName, Serializer serializer) { if(val == null) { if(isColName) throw new IllegalArgumentException("col name can not be null"); else return null; } if(isColName && _entityMeta.useCompositeColumns()) return SER_DYNAMIC_COMPOSITE.toBytes(new DynamicComposite(val)); if(serializer == null) serializer = EntityUtils.getSerializer(val.getClass()); if(serializer == null) throw new IllegalArgumentException("unable to serialize " + val); return serializer.toBytes(val); } protected IEnhancedEntity asEntity(Object value) { try { return (IEnhancedEntity) value; } catch(ClassCastException cce) { throw new IllegalArgumentException(value.getClass().getSimpleName() + " was not enhanced. Entity classes must be enhanced post compilation See " + EntityTransformerTask.class.getName()); } } protected void resetEntities(Collection<?> entities) { for(Object value : entities) { IEnhancedEntity entity = asEntity(value); entity.getModifiedFields().clear(); entity.setUnmappedFieldsModified(false); } } protected Object invokeGetter(PropertyMetadataBase pm, Object obj) { try { return pm.getGetter().invoke(obj); } catch(Exception e) { throw new IllegalArgumentException("unexpected error invoking " + pm.getGetter(), e); } } protected void invokeSetter(PropertyMetadataBase pm, Object obj, Object propertyValue) { try { pm.getSetter().invoke(obj, propertyValue); } catch(Exception e) { throw new IllegalArgumentException("unexpected error invoking " + pm.getSetter() + " with " + propertyValue, e); } } }