/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.venky.swf.db.model.reflection; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import com.venky.core.collections.SequenceSet; import com.venky.reflection.MethodSignatureCache; import com.venky.reflection.Reflector; import com.venky.reflection.Reflector.MethodMatcher; import com.venky.swf.db.annotations.column.IS_VIRTUAL; import com.venky.swf.db.annotations.model.DBPOOL; import com.venky.swf.db.model.Model; import com.venky.swf.db.table.Table; import com.venky.swf.routing.Config; /** * * @author venky */ public class TableReflector { private static final Map<String , TableReflector> tableReflectorByTableName = new HashMap<String, TableReflector>(); public static void dispose(){ tableReflectorByTableName.clear(); MReflector.dispose(); } public static <M extends Model> TableReflector instance(Class<M> modelClass){ Class<? extends Model> realModelClass = getRealModelClass(modelClass); if (realModelClass == null){ //The whole tree is Virtual. realModelClass = modelClass; } String tableName = Table.tableName(realModelClass); DBPOOL dbpool = realModelClass.getAnnotation(DBPOOL.class); String pool = dbpool == null ? "" : dbpool.value(); String tableKey = pool + "." + tableName; TableReflector reflector = tableReflectorByTableName.get(tableKey); if (reflector == null){ synchronized(tableReflectorByTableName){ reflector = tableReflectorByTableName.get(tableKey); if (reflector == null){ reflector = new TableReflector(tableName,pool); tableReflectorByTableName.put(tableKey, reflector); } } } reflector.registerModelClass(modelClass); return reflector; } private SequenceSet<Class<? extends Model>> modelClassesInClasspathSequence = new SequenceSet<Class<? extends Model>>(); private Map<String,SequenceSet<Class<? extends Model>>> modelClassesInClasspathSequenceByName = new HashMap<String, SequenceSet<Class<? extends Model>>>(); public <M extends Model> void registerModelClass(Class<M> modelClass){ if (!modelClassesInClasspathSequence.contains(modelClass)){ modelClassesInClasspathSequence.add(modelClass); SequenceSet<Class<? extends Model>> modelClassesForName = modelClassesInClasspathSequenceByName.get(modelClass.getSimpleName()); if (modelClassesForName == null){ modelClassesForName = new SequenceSet<Class<? extends Model>>(); modelClassesInClasspathSequenceByName.put(modelClass.getSimpleName(), modelClassesForName); } modelClassesForName.add(modelClass); } } public SequenceSet<Class<? extends Model>> getModelClasses(){ return modelClassesInClasspathSequence; } /** * @param modelClass * @return modelClasses that have the same SimpleName as the the passed modelClass in the order in which they occur in classpath. * If multiple classes with same simple name are present in a classpath entry (jar or a directory) the sequence between them is not guaranteed. */ public SequenceSet<Class<? extends Model>> getSiblingModelClasses(Class<? extends Model> modelClass){ if (modelClass == null){ return modelClassesInClasspathSequence; } return modelClassesInClasspathSequenceByName.get(modelClass.getSimpleName()); } @SuppressWarnings("unchecked") public static <U extends Model> Class<U> getRealModelClass(Class<? extends Model> modelClass){ MReflector<? extends Model> ref = MReflector.instance(modelClass); Class<? extends Model> lastRealClass = null; List<Class<? extends Model>> modelHierarchyClasses = ref.getClassHierarchy(); for (Class<? extends Model> claz:modelHierarchyClasses){ IS_VIRTUAL isVirtual = claz.getAnnotation(IS_VIRTUAL.class); if (isVirtual != null){ if (isVirtual.value()){ lastRealClass = null; }else if (lastRealClass == null){ lastRealClass = claz; break; } }else if (lastRealClass == null){ lastRealClass = claz; } } if (lastRealClass == Model.class){ lastRealClass = null; } return (Class<U>) lastRealClass; } private final String tableName; private final String pool ; private TableReflector(String tableName, String pool) { this.tableName = tableName; this.pool = pool; } public String getPool(){ return pool; } public String getTableName(){ return tableName; } public boolean reflects(Class<? extends Model> other){ return modelClassesInClasspathSequence.contains(other); } public boolean canReflect(Object o){ for (Class<? extends Model> model: modelClassesInClasspathSequence){ if (model.isInstance(o)){ return true; } } return false; } public void loadMethods(Class<? extends Model> inModel , List<Method> into , MethodMatcher matcher ){ if (!into.isEmpty()){ return; } synchronized (into) { if (into.isEmpty()){ HashSet<String> signatures = new HashSet<String>(); for (Class<? extends Model> modelClass:getSiblingModelClasses(inModel)){ List<Method> matchingMethods = MReflector.instance(modelClass).getMethods(matcher); for (Method m: matchingMethods){ String signature = getSignature(m); if (!signatures.contains(signature)){ into.add(m); signatures.add(signature); } } } } } } private MethodSignatureCache signatureCache = new MethodSignatureCache(); public String getSignature(Method method){ return signatureCache.get(method); } public boolean isAnnotationPresent(Class<? extends Model> inModel, Class<? extends Annotation> annotationClass){ return getAnnotation(inModel,annotationClass) != null; } public <A extends Annotation> A getAnnotation(Class<? extends Model> inModel, Class<A> annotationClass){ A a = null; for (Class<? extends Model> sibling: getSiblingModelClasses(inModel)){ MReflector<? extends Model> ref = MReflector.instance(sibling); a = ref.getAnnotation(annotationClass); if (a != null){ break; } } return a; } public boolean isAnnotationPresent(Class<? extends Model> inModel, Method method, Class<? extends Annotation> annotationClass ){ return getAnnotation(inModel, method, annotationClass) != null ; } public <A extends Annotation> A getAnnotation(Class<? extends Model> inModel, Method method, Class<A> annotationClass){ A a = null; for (Class<? extends Model> sibling: getSiblingModelClasses(inModel)) { MReflector<? extends Model> ref = MReflector.instance(sibling); a = ref.getAnnotation(method,annotationClass); if (a != null){ break; } } return a; } public SequenceSet<Class<? extends Model>> getClassHierarchies(Class<? extends Model> modelClass){ if (modelClass == null || modelClassesInClasspathSequence.contains(modelClass)){ SequenceSet<Class<? extends Model>> hierarchy = new SequenceSet<Class<? extends Model>>(); for (Class<? extends Model> sibling : getSiblingModelClasses(modelClass)){ MReflector<?> ref = MReflector.instance(sibling); hierarchy.addAll(ref.getClassHierarchy()); } return hierarchy; }else { return null; } } public SequenceSet<Class<?>> getClassForests(Class<? extends Model> modelClass){ if (modelClass == null || modelClassesInClasspathSequence.contains(modelClass)){ SequenceSet<Class<?>> forest = new SequenceSet<Class<?>>(); for (Class<? extends Model> sibling : getSiblingModelClasses(modelClass) ){ MReflector<?> ref = MReflector.instance(sibling); forest.addAll(ref.getClassForest()); } return forest; }else { return null; } } public static class MReflector<M extends Model> extends Reflector<Model, M>{ private static final Map<Class<? extends Model>, MReflector<? extends Model>> mreflectors = new HashMap<Class<? extends Model>, MReflector<? extends Model>>(); @SuppressWarnings("unchecked") public static <M extends Model> MReflector<M> instance(Class<M> modelClass){ MReflector<M> ref = (MReflector<M>)mreflectors.get(modelClass); if (ref == null){ synchronized (mreflectors) { ref = (MReflector<M>)mreflectors.get(modelClass); if (ref == null){ Config.instance().getLogger(TableReflector.class.getName()).fine("Trying to reflect "+ modelClass.getName()); ref = new MReflector<M>(modelClass); mreflectors.put(modelClass, ref); } } } return ref; } public static void dispose(){ mreflectors.clear(); } private MReflector(Class<M> reflectedClass) { super(reflectedClass, Model.class); } public List<Method> getMethodsForSignature(Method method){ return super.getMethodsForSignature(getMethodSignature(method)); } } }