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 }