package org.hivedb.configuration;
import org.hivedb.annotations.AnnotationHelper;
import org.hivedb.annotations.Index;
import org.hivedb.annotations.IndexType;
import org.hivedb.util.classgen.ReflectionTools;
import org.hivedb.util.functional.Filter;
import org.hivedb.util.functional.Filter.BinaryPredicate;
import org.hivedb.util.functional.Predicate;
import org.hivedb.util.functional.Transform;
import org.hivedb.util.functional.Unary;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.EnumSet;
public class EntityConfigImpl implements EntityConfig {
private Class<?> representedInterface;
private String partitionDimensionName, resourceName, primaryIndexKeyPropertyName, idPropertyName, versionPropertyName;
private Collection<EntityIndexConfig> entityIndexConfigs;
private boolean isPartitioningResource;
private Collection<Class<?>> associatedClasses;
public static EntityConfig createEntity(
Class<?> representedInterface,
String partitionDimensionName,
String resourceName,
String primaryIndexPropertyName,
String idPropertyName,
String versionPropertyName,
Collection<EntityIndexConfig> indexConfigs) {
return new EntityConfigImpl(
representedInterface,
partitionDimensionName,
resourceName,
primaryIndexPropertyName,
idPropertyName,
versionPropertyName,
indexConfigs,
false);
}
/***
* Create a configuration for an entity where the resource and partition dimension have the same index
* @param representedInterface
* @param partitionDimensionName
* @param resourceName
* @param secondaryIndexIdentifiables
* @param isPartitioningResource
* @param idPropertyName
* @return
*/
public static EntityConfig createPartitioningResourceEntity(
Class<?> representedInterface,
String partitionDimensionName,
String idPropertyName,
String versionPropertyName,
Collection<EntityIndexConfig> secondaryIndexIdentifiables) {
return new EntityConfigImpl(
representedInterface,
partitionDimensionName,
partitionDimensionName,
idPropertyName,
idPropertyName,
versionPropertyName,
secondaryIndexIdentifiables,
true);
}
public EntityConfigImpl(
Class<?> representedInterface,
String partitionDimensionName,
String resourceName,
String primaryIndexKeyPropertyName,
String idPropertyName,
String versionPropertyName,
Collection<EntityIndexConfig> entityIndexConfigs,
boolean isPartitioningResource) {
this.representedInterface = representedInterface;
this.partitionDimensionName = partitionDimensionName;
this.resourceName = resourceName;
this.primaryIndexKeyPropertyName = primaryIndexKeyPropertyName;
this.idPropertyName = idPropertyName;
this.entityIndexConfigs = entityIndexConfigs;
this.isPartitioningResource = isPartitioningResource;
this.versionPropertyName = versionPropertyName;
this.associatedClasses = findAssociatedClasses(representedInterface);
}
private Collection<Class<?>> findAssociatedClasses(final Class<?> representedInterface) {
// Search for indexed properties with complex class types of collections therein of.
// Ingore properties that delegate, since such classes are not mapped.
return Transform.map(new Unary<Method, Class<?>>() {
public Class<?> f(Method method) {
String property = ReflectionTools.getPropertyNameOfAccessor(method);
return ReflectionTools.isCollectionProperty(representedInterface, property)
? ReflectionTools.getCollectionItemType(representedInterface, property)
: method.getReturnType();
}},
Filter.grep(new Predicate<Method>() {
public boolean f(Method method) {
String property = ReflectionTools.getPropertyNameOfAccessor(method);
if (ReflectionTools.isCollectionProperty(representedInterface, property)
&& !ReflectionTools.isComplexCollectionItemProperty(representedInterface, property))
return false;
Index index = AnnotationHelper.getAnnotationDeeply(method, Index.class);
return index != null && index.type() != IndexType.Delegates;
}}, ReflectionTools.getComplexGetters(representedInterface)));
}
public String getResourceName() {
return resourceName;
}
public Collection<EntityIndexConfig> getEntityIndexConfigs() {
return entityIndexConfigs;
}
public String getIdPropertyName() {
return this.idPropertyName;
}
public Serializable getId(Object instance) {
return (Serializable) ReflectionTools.invokeGetter(instance, idPropertyName);
}
public boolean isPartitioningResource() {
return isPartitioningResource;
}
public Class<?> getRepresentedInterface() {
return representedInterface;
}
public String getPartitionDimensionName() {
return partitionDimensionName;
}
public String getPrimaryIndexKeyPropertyName() {
return primaryIndexKeyPropertyName;
}
public Object getPrimaryIndexKey(Object resourceInstance) {
return ReflectionTools.invokeGetter(resourceInstance, primaryIndexKeyPropertyName);
}
public Class<?> getPrimaryKeyClass() {
return ReflectionTools.getPropertyType(getRepresentedInterface(), getPrimaryIndexKeyPropertyName());
}
public Class<?> getIdClass() {
return ReflectionTools.getPropertyType(getRepresentedInterface(), getIdPropertyName());
}
public Collection<EntityIndexConfig> getEntityIndexConfigs(EnumSet<IndexType> indexTypes) {
return Filter.grepAgainstList(
indexTypes, entityIndexConfigs,new BinaryPredicate<IndexType, EntityIndexConfig>() {
public boolean f(IndexType indexType, EntityIndexConfig entityIndexConfig) {
return entityIndexConfig.getIndexType().equals(indexType);
}});
}
public Collection<EntityIndexConfig> getEntityIndexConfigs(final IndexType indexType) {
return getEntityIndexConfigs(EnumSet.of(indexType));
}
public EntityIndexConfig getEntityIndexConfig(final String propertyName) {
return Filter.grepSingleOrNull(new Predicate<EntityIndexConfig>() {
public boolean f(EntityIndexConfig entityIndexConfig) {
return entityIndexConfig.getPropertyName().equals(propertyName);
}},
entityIndexConfigs);
}
public int getVersion(Object instance) {
Integer version = null;
if(versionPropertyName != null)
version = ((Integer) ReflectionTools.invokeGetter(instance, versionPropertyName));
return version == null ? 0 : version;
}
public EntityIndexConfig getPrimaryIndexKeyEntityIndexConfig() {
return getEntityIndexConfig(getPrimaryIndexKeyPropertyName());
}
public Collection<Class<?>> getAssociatedClasses() {
return associatedClasses;
}
}