All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.venky.swf.db.model.reflection.TableReflector Maven / Gradle / Ivy

The newest version!
/*
 * 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.core.util.ObjectUtil;
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.jdbc.ConnectionManager;
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  tableReflectorByTableName = new HashMap();
    public static void dispose(){
    	tableReflectorByTableName.clear();
    	MReflector.dispose();
    }
    
    public static  TableReflector instance(Class modelClass){
    	Class 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();
    	if (ObjectUtil.isVoid(pool)){
    		pool = ConnectionManager.instance().getDefaultPool();
    	}
    	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> modelClassesInClasspathSequence  = new SequenceSet>();
    private Map>> modelClassesInClasspathSequenceByName = new HashMap>>();
    
    public  void  registerModelClass(Class modelClass){
    	if (!modelClassesInClasspathSequence.contains(modelClass)){
    		modelClassesInClasspathSequence.add(modelClass);
    		SequenceSet> modelClassesForName = modelClassesInClasspathSequenceByName.get(modelClass.getSimpleName());
    		if (modelClassesForName == null){
    			modelClassesForName = new SequenceSet>();
    			modelClassesInClasspathSequenceByName.put(modelClass.getSimpleName(), modelClassesForName);
    		}
    		modelClassesForName.add(modelClass);
    	}
    }
    
    public SequenceSet> 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> getSiblingModelClasses(Class modelClass){
    	if (modelClass == null){
    		return modelClassesInClasspathSequence;
    	}
    	return modelClassesInClasspathSequenceByName.get(modelClass.getSimpleName());
    }
    
    @SuppressWarnings("unchecked")
	public static  Class getRealModelClass(Class modelClass){
    	MReflector ref = MReflector.instance(modelClass);
    	Class lastRealClass = null;
    	List> modelHierarchyClasses = ref.getClassHierarchy(); 
    	for (Class 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 {
    				break;
				}
    		}else if (lastRealClass == null){
    			lastRealClass = claz;
    		}
    	}
    	if (lastRealClass == Model.class){
    		lastRealClass = null;
    	}
    	return (Class) 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 other){
    	return modelClassesInClasspathSequence.contains(other);
    }
    
    public boolean canReflect(Object o){
    	for (Class model: modelClassesInClasspathSequence){
    		if (model.isInstance(o)){
    			return true;
    		}
    	}
    	return false;
    }

    
    public void loadMethods(Class inModel , List into , MethodMatcher matcher ){
    	if (!into.isEmpty()){
    		return;
    	}
    	synchronized (into) {
    		if (into.isEmpty()){
    			HashSet signatures = new HashSet(); 
    			for (Class modelClass:getSiblingModelClasses(inModel)){
    				List 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 transient MethodSignatureCache signatureCache = new MethodSignatureCache();
    public String getSignature(Method method){
    	return signatureCache.get(method);
    }

    public boolean isAnnotationPresent(Class inModel, Class annotationClass){
    	return getAnnotation(inModel,annotationClass) != null;
    }
    
    public  A getAnnotation(Class inModel, Class annotationClass){
    	A a = null; 
    	for (Class sibling: getSiblingModelClasses(inModel)){
        	MReflector ref = MReflector.instance(sibling);
        	a =  ref.getAnnotation(annotationClass);
        	if (a != null){
        		break;
        	}        	
    	}
    	return a;
    }

    public boolean isAnnotationPresent(Class inModel, Method method,  Class annotationClass ){
    	return getAnnotation(inModel, method, annotationClass) != null ; 
    }
    
    public  A getAnnotation(Class inModel, Method method, Class annotationClass){
    	A a = null;
    	for (Class sibling: getSiblingModelClasses(inModel)) {
        	MReflector ref = MReflector.instance(sibling);
        	a = ref.getAnnotation(method,annotationClass);
        	if (a != null){
        		break;
        	}
    	}
    	return a; 
    }
    

    public SequenceSet> getClassHierarchies(Class modelClass){
    	if (modelClass == null || modelClassesInClasspathSequence.contains(modelClass)){
    		SequenceSet> hierarchy = new SequenceSet>();
    		for (Class sibling : getSiblingModelClasses(modelClass)){
            	MReflector ref = MReflector.instance(sibling);
            	hierarchy.addAll(ref.getClassHierarchy());
    		}
    		return hierarchy;
    	}else {
    		return null;
    	}
    }

    public SequenceSet> getClassForests(Class modelClass){
    	if (modelClass == null || modelClassesInClasspathSequence.contains(modelClass)){
    		SequenceSet> forest = new SequenceSet>();
    		for (Class sibling : getSiblingModelClasses(modelClass) ){
    			MReflector ref = MReflector.instance(sibling);
    			forest.addAll(ref.getClassForest());
    		}
        	return forest;
		}else {
			return null;
		}
    }
    
    public static class MReflector extends Reflector{
    	
        private static final Map, MReflector> mreflectors = new HashMap, MReflector>();
        
    	@SuppressWarnings("unchecked")
        public static  MReflector instance(Class modelClass){
        	MReflector ref = (MReflector)mreflectors.get(modelClass);
        	if (ref == null){
        		synchronized (mreflectors) {
        			ref = (MReflector)mreflectors.get(modelClass);
        			if (ref == null){
        				Config.instance().getLogger(TableReflector.class.getName()).fine("Trying to reflect "+ modelClass.getName());
        				ref = new MReflector(modelClass);
        				mreflectors.put(modelClass, ref);
        			}
    			}
        	}
        	return ref;
        }
    	
    	public static void dispose(){
    		mreflectors.clear();
    	}
		private MReflector(Class reflectedClass) {
			super(reflectedClass, Model.class);
		}
		
		public List getMethodsForSignature(Method method){
			return super.getMethodsForSignature(getMethodSignature(method));
		}
    }
}