1 22 package org.jboss.aop.proxy; 23 24 import javassist.ClassPool; 25 import javassist.CtClass; 26 import javassist.CtField; 27 import javassist.CtMethod; 28 import javassist.CtNewMethod; 29 import javassist.Modifier; 30 import org.jboss.aop.AspectManager; 31 import org.jboss.aop.ClassInstanceAdvisor; 32 import org.jboss.aop.InstanceAdvisor; 33 import org.jboss.aop.instrument.TransformerCommon; 34 import org.jboss.aop.util.JavassistMethodHashing; 35 import org.jboss.util.collection.WeakValueHashMap; 36 import org.jboss.util.id.GUID; 37 38 import java.lang.reflect.AccessibleObject ; 39 import java.lang.reflect.Field ; 40 import java.security.AccessController ; 41 import java.security.PrivilegedActionException ; 42 import java.security.PrivilegedExceptionAction ; 43 import java.util.HashSet ; 44 import java.util.Map ; 45 46 52 public class ProxyFactory 53 { 54 private static long counter = 0; 55 private static WeakValueHashMap proxyCache = new WeakValueHashMap(); 56 57 public static Proxy createInterfaceProxy(ClassLoader loader, Class [] interfaces, ProxyMixin[] mixins, InstanceAdvisor advisor) throws Exception 58 { 59 Class clazz = createProxyClass(loader, mixins, interfaces); 60 61 Proxy instance = (Proxy) clazz.newInstance(); 62 instance.instanceAdvisor = advisor; 63 instance.mixins = mixins; 64 instance.interfaces = interfaces; 65 instance.guid = new GUID(); 66 67 synchronized (proxyCache) 68 { 69 proxyCache.put(instance.guid, clazz); 70 } 71 72 return instance; 73 } 74 75 public static Class getProxyClass(GUID guid) 76 { 77 synchronized (proxyCache) 78 { 79 return (Class ) proxyCache.get(guid); 80 } 81 } 82 83 public static Proxy createInterfaceProxy(GUID guid, ClassLoader loader, Class [] interfaces) throws Exception 84 { 85 return createInterfaceProxy(guid, loader, interfaces, null, new ClassInstanceAdvisor()); 86 } 87 88 public static Proxy createInterfaceProxy(GUID guid, ClassLoader loader, Class [] interfaces, ProxyMixin[] mixins, InstanceAdvisor advisor) throws Exception 89 { 90 Class clazz = getProxyClass(guid); 91 boolean wasFound = true; 92 if (clazz == null) 93 { 94 wasFound = false; 95 clazz = createProxyClass(loader, mixins, interfaces); 96 } 97 98 Proxy instance = (Proxy) clazz.newInstance(); 99 instance.instanceAdvisor = advisor; 100 instance.mixins = mixins; 101 instance.interfaces = interfaces; 102 instance.guid = guid; 103 104 if (!wasFound) 105 { 106 synchronized (proxyCache) 107 { 108 proxyCache.put(guid, clazz); 109 } 110 } 111 112 return instance; 113 } 114 115 private static Class createProxyClass(ClassLoader loader, ProxyMixin[] mixins, Class [] interfaces) 116 throws Exception 117 { 118 CtClass proxy = createProxyCtClass(loader, mixins, interfaces); 119 120 Class clazz = TransformerCommon.toClass(proxy, loader); 121 Map methodmap = ClassProxyFactory.getMethodMap(clazz); 122 Field field = clazz.getDeclaredField("methodMap"); 123 setAccessible(field); 124 field.set(null, methodmap); 125 return clazz; 126 } 127 128 public static GUID generateProxyClass(ClassLoader loader, ProxyMixin[] mixins, Class [] interfaces) throws Exception 129 { 130 Class clazz = createProxyClass(loader, mixins, interfaces); 131 GUID guid = new GUID(); 132 133 synchronized (proxyCache) 134 { 135 proxyCache.put(guid, clazz); 136 } 137 138 return guid; 139 } 140 141 private static CtClass createProxyCtClass(ClassLoader loader, ProxyMixin[] mixins, Class [] interfaces) 142 throws Exception 143 { 144 ClassPool pool = AspectManager.instance().findClassPool(loader); 145 if (pool == null) throw new NullPointerException ("Could not find ClassPool"); 146 147 String classname = "AOPProxy$" + counter++; 148 149 CtClass base = pool.get("org.jboss.aop.proxy.Proxy"); 150 CtClass proxy = TransformerCommon.makeClass(pool, classname, base); 151 proxy.addInterface(pool.get("org.jboss.aop.instrument.Untransformable")); 152 CtClass map = pool.get("java.util.Map"); 153 CtField methodMap = new CtField(map, "methodMap", proxy); 154 methodMap.setModifiers(Modifier.PRIVATE | Modifier.STATIC); 155 proxy.addField(methodMap); 156 CtMethod getMethodMap = CtNewMethod.getter("getMethodMap", methodMap); 157 getMethodMap.setModifiers(Modifier.PUBLIC); 158 proxy.addMethod(getMethodMap); 159 160 HashSet addedInterfaces = new HashSet (); 161 HashSet addedMethods = new HashSet (); 162 if (mixins != null) 163 { 164 for (int i = 0; i < mixins.length; i++) 165 { 166 HashSet mixinMethods = new HashSet (); 167 Class [] mixinf = mixins[i].getInterfaces(); 168 ClassPool mixPool = AspectManager.instance().findClassPool(mixins[i].getMixin().getClass().getClassLoader()); 169 CtClass mixClass = mixPool.get(mixins[i].getMixin().getClass().getName()); 170 for (int j = 0; j < mixinf.length; j++) 171 { 172 if (addedInterfaces.contains(mixinf[j].getName())) throw new Exception ("2 mixins are implementing the same interfaces"); 173 ClassPool mixIntfPool = AspectManager.instance().findClassPool(mixinf[j].getClassLoader()); 174 CtClass intfClass = mixIntfPool.get(mixinf[j].getName()); 175 CtMethod[] methods = intfClass.getMethods(); 176 for (int m = 0; m < methods.length; m++) 177 { 178 if (methods[m].getDeclaringClass().getName().equals("java.lang.Object")) continue; 179 Long hash = new Long (JavassistMethodHashing.methodHash(methods[m])); 180 if (mixinMethods.contains(hash)) continue; 181 if (addedMethods.contains(hash)) throw new Exception ("More than one mixin has same method"); 182 mixinMethods.add(hash); 183 addedMethods.add(hash); 184 String returnStr = (methods[m].getReturnType().equals(CtClass.voidType)) ? "" : "return "; 185 String code = "{" + 186 " " + mixClass.getName() + " mixin = (" + mixClass.getName() + ")mixins[" + i + "].getMixin();" + 187 " " + returnStr + " mixin." + methods[m].getName() + "($$);" + 188 "}"; 189 CtMethod newMethod = CtNewMethod.make(methods[m].getReturnType(), methods[m].getName(), methods[m].getParameterTypes(), methods[m].getExceptionTypes(), code, proxy); 190 newMethod.setModifiers(Modifier.PUBLIC); 191 proxy.addMethod(newMethod); 192 } 193 194 proxy.addInterface(intfClass); 195 addedInterfaces.add(intfClass.getName()); 196 } 197 } 198 } 199 200 for (int i = 0; i < interfaces.length; i++) 201 { 202 if (addedInterfaces.contains(interfaces[i].getName())) continue; 203 ClassPool mixPool = AspectManager.instance().findClassPool(interfaces[i].getClassLoader()); 204 CtClass intfClass = mixPool.get(interfaces[i].getName()); 205 CtMethod[] methods = intfClass.getMethods(); 206 for (int m = 0; m < methods.length; m++) 207 { 208 if (methods[m].getDeclaringClass().getName().equals("java.lang.Object")) continue; 209 Long hash = new Long (JavassistMethodHashing.methodHash(methods[m])); 210 if (addedMethods.contains(hash)) continue; 211 addedMethods.add(hash); 212 String aopReturnStr = (methods[m].getReturnType().equals(CtClass.voidType)) ? "" : "return ($r)"; 213 String args = "null"; 214 if (methods[m].getParameterTypes().length > 0) args = "$args"; 215 String code = "{ " + 216 " org.jboss.aop.advice.Interceptor[] aspects = instanceAdvisor.getInterceptors(); " + 217 " org.jboss.aop.MethodInfo mi = new org.jboss.aop.MethodInfo(); " + 218 " mi.setHash(" + hash.longValue() + "L);" + 219 " org.jboss.aop.proxy.ProxyMethodInvocation invocation = new org.jboss.aop.proxy.ProxyMethodInvocation(this, mi, aspects); " + 220 " invocation.setInstanceResolver(instanceAdvisor.getMetaData()); " + 221 " invocation.setArguments(" + args + "); " + 222 " " + aopReturnStr + " invocation.invokeNext(); " + 223 "}"; 224 CtMethod newMethod = CtNewMethod.make(methods[m].getReturnType(), methods[m].getName(), methods[m].getParameterTypes(), methods[m].getExceptionTypes(), code, proxy); 225 newMethod.setModifiers(Modifier.PUBLIC); 226 proxy.addMethod(newMethod); 227 } 228 proxy.addInterface(intfClass); 229 } 230 return proxy; 231 } 232 233 interface SetAccessibleAction 234 { 235 void setAccessible(AccessibleObject accessibleObject); 236 237 SetAccessibleAction PRIVILEGED = new SetAccessibleAction() 238 { 239 public void setAccessible(final AccessibleObject accessibleObject) 240 { 241 try 242 { 243 AccessController.doPrivileged(new PrivilegedExceptionAction () 244 { 245 public Object run() throws Exception 246 { 247 accessibleObject.setAccessible(true); 248 return null; 249 } 250 }); 251 } 252 catch (PrivilegedActionException e) 253 { 254 throw new RuntimeException ("Error setting " + accessibleObject + " as accessible ", e.getException()); 255 } 256 } 257 }; 258 259 SetAccessibleAction NON_PRIVILEGED = new SetAccessibleAction() 260 { 261 public void setAccessible(AccessibleObject accessibleObject) 262 { 263 accessibleObject.setAccessible(true); 264 } 265 }; 266 } 267 268 static void setAccessible(AccessibleObject accessibleObject) 269 { 270 if (System.getSecurityManager() == null) 271 { 272 SetAccessibleAction.NON_PRIVILEGED.setAccessible(accessibleObject); 273 } 274 else 275 { 276 SetAccessibleAction.PRIVILEGED.setAccessible(accessibleObject); 277 } 278 } 279 280 } 281 | Popular Tags |