package org.hivedb.configuration; import org.hivedb.HiveRuntimeException; import org.hivedb.annotations.Index; import org.hivedb.annotations.IndexType; import org.hivedb.annotations.PartitionIndex; import org.hivedb.annotations.Validate; import org.hivedb.util.InstanceCollectionValueGetter; import org.hivedb.util.classgen.ReflectionTools; import org.hivedb.util.database.SqlUtils; import org.hivedb.util.functional.Actor; import org.hivedb.util.functional.Transform; import org.hivedb.util.functional.Unary; import org.hivedb.util.validators.NonNullValidator; import org.hivedb.util.validators.Validator; import java.util.Collection; public class EntityIndexConfigImpl implements EntityIndexConfig { /** * Constructor for a primitive type property or collection or primitive types */ @SuppressWarnings("unchecked") public EntityIndexConfigImpl( final Class entityInterface, final String propertyName) { this.propertyName = propertyName; this.indexName = propertyName; this.indexType = resolveIndexType(entityInterface, propertyName); this.secondaryIndexCollectionGetter = new InstanceCollectionValueGetter() { public Collection<Object> get(Object instance) { if (!getValidator().isValid(instance, propertyName)) getValidator().throwInvalid(instance, propertyName); return Actor.forceCollection(ReflectionTools.invokeGetter(instance, propertyName)); }}; this.indexClass = ReflectionTools.getPropertyTypeOrPropertyCollectionItemType(entityInterface, propertyName); this.validator = resolveValidator(entityInterface, propertyName); } /** * Constructor for a property of a collection of complex types. This assumes the complex type's * indexed property is a primitive value, though this could be refactored to support a property * at any depth in the object graph. * * @param propertyName name of the collection property * @param innerClassPropertyName name of the property of the collection item class */ public EntityIndexConfigImpl( final Class<?> entityInterface, final String propertyName, final String innerClassPropertyName) { this.propertyName = propertyName; this.innerClassPropertyName = innerClassPropertyName; this.indexName = SqlUtils.singularize(propertyName) + ReflectionTools.capitalize(innerClassPropertyName); this.indexType = ReflectionTools.getGetterOfProperty(entityInterface, propertyName).getAnnotation(Index.class).type(); this.secondaryIndexCollectionGetter = new InstanceCollectionValueGetter() { @SuppressWarnings("unchecked") public Collection<Object> get(Object instance) { if (!getValidator().isValid(instance, propertyName)) getValidator().throwInvalid(instance, propertyName); return Transform.map(new Unary<Object, Object>() { public Object f(Object collectionItem) { return ReflectionTools.invokeGetter(collectionItem, innerClassPropertyName); }}, (Collection<Object>)ReflectionTools.invokeGetter(instance, propertyName)); }}; this.indexClass = ReflectionTools.getPropertyType( ReflectionTools.getCollectionItemType(entityInterface, propertyName), innerClassPropertyName); this.validator = resolveValidator(entityInterface, propertyName); } @SuppressWarnings("unchecked") private IndexType resolveIndexType(final Class entityInterface, final String propertyName) { Index annotation = ReflectionTools.getGetterOfProperty(entityInterface, propertyName).getAnnotation(Index.class); if (annotation != null) return annotation.type(); if (ReflectionTools.getGetterOfProperty(entityInterface, propertyName).getAnnotation(PartitionIndex.class) != null) return IndexType.Partition; return IndexType.None; } @SuppressWarnings("unchecked") private Validator resolveValidator(final Class entityInterface, final String propertyName) { Validate annotation = (Validate) ReflectionTools.getGetterOfProperty(entityInterface, propertyName).getAnnotation(Validate.class); if (annotation != null) try { return (Validator) Class.forName(annotation.value()).newInstance(); } catch (Exception e) { throw new HiveRuntimeException(e); } return nonNullValidator; } private static Validator nonNullValidator = new NonNullValidator(); private String indexName; public String getIndexName() { return indexName; } private String propertyName; public String getPropertyName() { return propertyName; } private String innerClassPropertyName; public String getInnerClassPropertyName() { if (innerClassPropertyName == null) throw new RuntimeException(String.format("EntityIndexConfig's property %s is not a collection property, but is being treated like one", propertyName)); return innerClassPropertyName; } private InstanceCollectionValueGetter secondaryIndexCollectionGetter; public Collection<Object> getIndexValues(Object instance) { return secondaryIndexCollectionGetter.get(instance); } private Class<?> indexClass; public Class<?> getIndexClass() { return indexClass; } private IndexType indexType; public IndexType getIndexType() { return indexType; } private Validator validator; public Validator getValidator() { return validator; } }