001    package com.khubla.pragmatach.plugin.mongodb.proxy;
002    
003    import java.util.Hashtable;
004    
005    import javassist.CannotCompileException;
006    import javassist.ClassPool;
007    import javassist.CtClass;
008    import javassist.CtField;
009    import javassist.Modifier;
010    import javassist.NotFoundException;
011    import javassist.util.proxy.ProxyFactory;
012    import javassist.util.proxy.ProxyObject;
013    
014    import org.apache.commons.lang.reflect.FieldUtils;
015    
016    /**
017     * @author tom
018     */
019    public class MongoProxyFactory {
020       /**
021        * some special names
022        */
023       public static final String LAZYID = "mongolazyid";
024       public static final String LAZYFETCHED = "mongolazyfetched";
025       /**
026        * static registry of lazy loading proxies
027        */
028       private static final Hashtable<Class<?>, Class<?>> lazyProxies = new Hashtable<Class<?>, Class<?>>();
029    
030       /**
031        * create a class which extends the typeClazz with some new members
032        */
033       private static Class<?> createProxyClass(Class<?> typeClazz) throws NotFoundException, CannotCompileException {
034          final ClassPool classPool = ClassPool.getDefault();
035          final CtClass ctClass = classPool.makeClass(typeClazz.getName() + "_monogolazyload");
036          ctClass.setSuperclass(classPool.getCtClass(typeClazz.getName()));
037          final CtClass ctStringClass = ClassPool.getDefault().get("java.lang.String");
038          final CtField ctIdField = new CtField(ctStringClass, LAZYID, ctClass);
039          ctIdField.setModifiers(Modifier.PUBLIC);
040          ctClass.addField(ctIdField);
041          final CtField ctFetchedField = new CtField(CtClass.booleanType, LAZYFETCHED, ctClass);
042          ctFetchedField.setModifiers(Modifier.PUBLIC);
043          ctClass.addField(ctFetchedField);
044          return ctClass.toClass();
045       }
046    
047       /**
048        * get proxy
049        */
050       private static Class<?> getProxyClass(Class<?> clazz) throws NotFoundException, CannotCompileException {
051          Class<?> ret = lazyProxies.get(clazz);
052          if (null == ret) {
053             ret = createProxyClass(clazz);
054             lazyProxies.put(clazz, ret);
055          }
056          return ret;
057       }
058    
059       /**
060        * get a proxy to an instance of a type
061        */
062       public static Object getProxyObject(Class<?> typeClazz) throws NotFoundException, IllegalAccessException, InstantiationException, CannotCompileException {
063          /*
064           * the handler
065           */
066          final MongoMethodHandler mongoMethodHandler = new MongoMethodHandler();
067          /*
068           * factory
069           */
070          final ProxyFactory proxyFactory = new ProxyFactory();
071          /*
072           * create the superclass
073           */
074          final Class<?> superClass = getProxyClass(typeClazz);
075          /*
076           * set the super class
077           */
078          proxyFactory.setSuperclass(superClass);
079          /*
080           * set the filter
081           */
082          proxyFactory.setFilter(mongoMethodHandler);
083          /*
084           * create the proxy class
085           */
086          final Class<?> clazz = proxyFactory.createClass();
087          /*
088           * create the instance
089           */
090          final Object instance = clazz.newInstance();
091          /*
092           * weird magic required to set the handler
093           */
094          ((ProxyObject) instance).setHandler(mongoMethodHandler);
095          /*
096           * done
097           */
098          return instance;
099       }
100    
101       public static void setID(Object o, String id) throws IllegalAccessException {
102          FieldUtils.writeField(o, MongoProxyFactory.LAZYID, id);
103       }
104    
105       public static void setFetched(Object o, boolean fetched) throws IllegalAccessException {
106          FieldUtils.writeField(o, MongoProxyFactory.LAZYFETCHED, false);
107       }
108    
109       public static String getId(Object o) throws IllegalAccessException {
110          return (String) FieldUtils.readField(o, MongoProxyFactory.LAZYID);
111       }
112    
113       public static boolean getFetched(Object o) throws IllegalAccessException {
114          Boolean b = (Boolean) FieldUtils.readField(o, MongoProxyFactory.LAZYFETCHED);
115          return b.booleanValue();
116       }
117    }