KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > aop > proxy > ProxyFactory


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

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 JavaDoc;
39 import java.lang.reflect.Field JavaDoc;
40 import java.security.AccessController JavaDoc;
41 import java.security.PrivilegedActionException JavaDoc;
42 import java.security.PrivilegedExceptionAction JavaDoc;
43 import java.util.HashSet JavaDoc;
44 import java.util.Map JavaDoc;
45
46 /**
47  * Comment
48  *
49  * @author <a HREF="mailto:bill@jboss.org">Bill Burke</a>
50  * @version $Revision: 45977 $
51  */

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 JavaDoc loader, Class JavaDoc[] interfaces, ProxyMixin[] mixins, InstanceAdvisor advisor) throws Exception JavaDoc
58    {
59       Class JavaDoc 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 JavaDoc getProxyClass(GUID guid)
76    {
77       synchronized (proxyCache)
78       {
79          return (Class JavaDoc) proxyCache.get(guid);
80       }
81    }
82
83    public static Proxy createInterfaceProxy(GUID guid, ClassLoader JavaDoc loader, Class JavaDoc[] interfaces) throws Exception JavaDoc
84    {
85       return createInterfaceProxy(guid, loader, interfaces, null, new ClassInstanceAdvisor());
86    }
87
88    public static Proxy createInterfaceProxy(GUID guid, ClassLoader JavaDoc loader, Class JavaDoc[] interfaces, ProxyMixin[] mixins, InstanceAdvisor advisor) throws Exception JavaDoc
89    {
90       Class JavaDoc 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 JavaDoc createProxyClass(ClassLoader JavaDoc loader, ProxyMixin[] mixins, Class JavaDoc[] interfaces)
116    throws Exception JavaDoc
117    {
118       CtClass proxy = createProxyCtClass(loader, mixins, interfaces);
119
120       Class JavaDoc 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 JavaDoc loader, ProxyMixin[] mixins, Class JavaDoc[] interfaces) throws Exception JavaDoc
129    {
130       Class JavaDoc 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 JavaDoc loader, ProxyMixin[] mixins, Class JavaDoc[] interfaces)
142    throws Exception JavaDoc
143    {
144       ClassPool pool = AspectManager.instance().findClassPool(loader);
145       if (pool == null) throw new NullPointerException JavaDoc("Could not find ClassPool");
146
147       String JavaDoc 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 JavaDoc addedInterfaces = new HashSet JavaDoc();
161       HashSet JavaDoc addedMethods = new HashSet JavaDoc();
162       if (mixins != null)
163       {
164          for (int i = 0; i < mixins.length; i++)
165          {
166             HashSet JavaDoc mixinMethods = new HashSet JavaDoc();
167             Class JavaDoc[] 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 JavaDoc("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 JavaDoc hash = new Long JavaDoc(JavassistMethodHashing.methodHash(methods[m]));
180                   if (mixinMethods.contains(hash)) continue;
181                   if (addedMethods.contains(hash)) throw new Exception JavaDoc("More than one mixin has same method");
182                   mixinMethods.add(hash);
183                   addedMethods.add(hash);
184                   String JavaDoc returnStr = (methods[m].getReturnType().equals(CtClass.voidType)) ? "" : "return ";
185                   String JavaDoc 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 JavaDoc hash = new Long JavaDoc(JavassistMethodHashing.methodHash(methods[m]));
210             if (addedMethods.contains(hash)) continue;
211             addedMethods.add(hash);
212             String JavaDoc aopReturnStr = (methods[m].getReturnType().equals(CtClass.voidType)) ? "" : "return ($r)";
213             String JavaDoc args = "null";
214             if (methods[m].getParameterTypes().length > 0) args = "$args";
215             String JavaDoc 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 JavaDoc accessibleObject);
236       
237       SetAccessibleAction PRIVILEGED = new SetAccessibleAction()
238       {
239          public void setAccessible(final AccessibleObject JavaDoc accessibleObject)
240          {
241             try
242             {
243                AccessController.doPrivileged(new PrivilegedExceptionAction JavaDoc()
244                {
245                   public Object JavaDoc run() throws Exception JavaDoc
246                   {
247                      accessibleObject.setAccessible(true);
248                      return null;
249                   }
250                });
251             }
252             catch (PrivilegedActionException JavaDoc e)
253             {
254                throw new RuntimeException JavaDoc("Error setting " + accessibleObject + " as accessible ", e.getException());
255             }
256          }
257       };
258
259       SetAccessibleAction NON_PRIVILEGED = new SetAccessibleAction()
260       {
261          public void setAccessible(AccessibleObject JavaDoc accessibleObject)
262          {
263             accessibleObject.setAccessible(true);
264          }
265       };
266    }
267
268    static void setAccessible(AccessibleObject JavaDoc 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