KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > aop > proxy > container > ContainerProxyFactory


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.container;
23
24 import java.lang.reflect.Method JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.Set JavaDoc;
31 import java.util.WeakHashMap JavaDoc;
32
33 import javassist.ClassPool;
34 import javassist.CtClass;
35 import javassist.CtConstructor;
36 import javassist.CtField;
37 import javassist.CtMethod;
38 import javassist.CtNewConstructor;
39 import javassist.CtNewMethod;
40 import javassist.Modifier;
41 import javassist.NotFoundException;
42 import javassist.SerialVersionUID;
43
44 import org.jboss.aop.Advised;
45 import org.jboss.aop.Advisor;
46 import org.jboss.aop.AspectManager;
47 import org.jboss.aop.ClassContainer;
48 import org.jboss.aop.InstanceAdvised;
49 import org.jboss.aop.MethodInfo;
50 import org.jboss.aop.instrument.TransformerCommon;
51 import org.jboss.aop.introduction.InterfaceIntroduction;
52 import org.jboss.aop.util.JavassistMethodHashing;
53
54
55 /**
56  * @author <a HREF="mailto:bill@jboss.org">Bill Burke</a>
57  * @version $Revision: 45977 $
58  */

59 public class ContainerProxyFactory
60 {
61    private static final String JavaDoc ADVISED = Advised.class.getName();
62    private static final String JavaDoc INSTANCE_ADVISED = InstanceAdvised.class.getName();
63    private static final CtClass[] EMPTY_CTCLASS_ARRAY = new CtClass[0];
64    public static final String JavaDoc PROXY_NAME_PREFIX = "AOPContainerProxy$";
65    
66    private static Object JavaDoc maplock = new Object JavaDoc();
67    private static WeakHashMap JavaDoc proxyCache = new WeakHashMap JavaDoc();
68    private static volatile int counter = 0;
69    
70    private static CtMethod setDelegateMethod;
71
72
73    /** True if java.lang.Object should be used as the super class for this proxy */
74    private boolean objectAsSuper;
75
76    /** The Advisor for this proxy */
77    private Advisor advisor;
78
79    /** The class we are generating this proxy for */
80    private Class JavaDoc clazz;
81
82    /** The generated proxy */
83    private CtClass proxy;
84    
85    /** The class pool for the proxy (i.e for the class we are proxying */
86    private ClassPool pool;
87    
88    /** The interface introductions and mixins that should be used for this proxy*/
89    private ArrayList JavaDoc mixins;
90    
91    /** True if we are proxying a class already woven by jboss aop, false otherwise */
92    private boolean isAdvised;
93    
94    public static Class JavaDoc getProxyClass(Class JavaDoc clazz, AspectManager manager) throws Exception JavaDoc
95    {
96       ContainerProxyCacheKey key = new ContainerProxyCacheKey(clazz);
97       ClassContainer container = getTempClassContainer(clazz, manager);
98       return getProxyClass(false, key, container);
99    }
100    
101    public static Class JavaDoc getProxyClass(boolean objectAsSuper, ContainerProxyCacheKey key, Advisor advisor)
102            throws Exception JavaDoc
103    {
104       Class JavaDoc clazz = key.getClazz();
105       // Don't make a proxy of a proxy !
106
if (Delegate.class.isAssignableFrom(clazz)) clazz = clazz.getSuperclass();
107
108       Class JavaDoc proxyClass = null;
109       synchronized (maplock)
110       {
111          Map JavaDoc map = (Map JavaDoc)proxyCache.get(clazz);
112          if (map == null)
113          {
114             map = new HashMap JavaDoc();
115             proxyCache.put(clazz, map);
116          }
117          else
118          {
119             proxyClass = (Class JavaDoc) map.get(key);
120          }
121          
122          if (proxyClass == null)
123          {
124             proxyClass = generateProxy(objectAsSuper, clazz, advisor);
125             map.put(key, proxyClass);
126          }
127       }
128       return proxyClass;
129    }
130
131    private static Class JavaDoc generateProxy(boolean objectAsSuper, Class JavaDoc clazz, Advisor advisor) throws Exception JavaDoc
132    {
133       ArrayList JavaDoc introductions = advisor.getInterfaceIntroductions();
134       CtClass proxy = createProxyCtClass(objectAsSuper, introductions, clazz, advisor);
135       
136       Class JavaDoc proxyClass = TransformerCommon.toClass(proxy);
137       return proxyClass;
138    }
139
140    private static ClassProxyContainer getTempClassContainer(Class JavaDoc clazz, AspectManager manager)
141    {
142       ClassProxyContainer container = new ClassProxyContainer("temp", manager);
143       container.setClass(clazz);
144
145       Iterator JavaDoc it = container.getManager().getInterfaceIntroductions().values().iterator();
146       while (it.hasNext())
147       {
148          InterfaceIntroduction intro = (InterfaceIntroduction) it.next();
149          if (intro.matches(container, container.getClazz()))
150          {
151             container.addInterfaceIntroduction(intro);
152          }
153       }
154
155       return container;
156    }
157    
158    public static CtClass createProxyCtClass(boolean objectAsSuper, ArrayList JavaDoc mixins, Class JavaDoc clazz, Advisor advisor)
159            throws Exception JavaDoc
160    {
161       ContainerProxyFactory factory = new ContainerProxyFactory(objectAsSuper, mixins, clazz, advisor);
162       return factory.createProxyCtClass();
163    }
164
165    
166    private ContainerProxyFactory(boolean objectAsSuper, ArrayList JavaDoc mixins, Class JavaDoc clazz, Advisor advisor)
167    {
168       this.objectAsSuper = objectAsSuper;
169       this.mixins = mixins;
170       this.clazz = clazz;
171       this.advisor = advisor;
172       isAdvised = Advised.class.isAssignableFrom(clazz);
173    }
174   
175    
176    private CtClass createProxyCtClass() throws Exception JavaDoc
177    {
178       this.pool = AspectManager.instance().findClassPool(clazz.getClassLoader());
179       if (pool == null) throw new NullPointerException JavaDoc("Could not find ClassPool");
180
181       createBasics();
182       addMethodsAndMixins();
183       overrideSpecialMethods(clazz, proxy);
184       
185       SerialVersionUID.setSerialVersionUID(proxy);
186       
187       return proxy;
188    }
189    
190
191    private CtClass createBasics() throws Exception JavaDoc
192    {
193       Class JavaDoc proxySuper = (objectAsSuper) ? Object JavaDoc.class : this.clazz;
194       String JavaDoc classname = getClassName();
195
196       CtClass template = pool.get("org.jboss.aop.proxy.container.ProxyTemplate");
197       CtClass superclass = pool.get(proxySuper.getName());
198
199       this.proxy = TransformerCommon.makeClass(pool, classname, superclass);
200       proxy.addInterface(pool.get("org.jboss.aop.instrument.Untransformable"));
201       
202       //Add all the interfaces of the class
203
Class JavaDoc[] interfaces = proxySuper.getInterfaces();
204       for (int i = 0 ; i < interfaces.length ; i++)
205       {
206          CtClass interfaze = pool.get(interfaces[i].getName());
207          proxy.addInterface(interfaze);
208       }
209       
210       ensureDefaultConstructor(superclass, proxy);
211       addFieldFromTemplate(template, "mixins");
212
213       //Add methods/fields needed for Delegate interface
214
proxy.addInterface(pool.get("org.jboss.aop.proxy.container.Delegate"));
215       
216       addFieldFromTemplate(template, "delegate", superclass);
217       addMethodFromTemplate(template, "getDelegate", "{ return delegate; }");
218       setDelegateMethod = addMethodFromTemplate(template, "setDelegate", "{ this.delegate = (" + proxySuper.getName() + ")$1; }");
219
220       //Add methods/fields needed for AspectManaged interface
221
proxy.addInterface(pool.get("org.jboss.aop.proxy.container.AspectManaged"));
222
223       addFieldFromTemplate(template, "currentAdvisor");
224       addFieldFromTemplate(template, "classAdvisor");
225       addMethodFromTemplate(template, "getAdvisor", "{return classAdvisor;}");
226       addMethodFromTemplate(template, "setAdvisor", "{this.classAdvisor = $1;currentAdvisor = classAdvisor;}");
227       
228       addFieldFromTemplate(template, "metadata");
229       addMethodFromTemplate(template, "setMetadata", "{this.metadata = $1;}");
230       
231       addFieldFromTemplate(template, "instanceAdvisor");
232       addMethodFromTemplate(template, "setInstanceAdvisor", instanceAdvisorSetterBody());
233       addMethodFromTemplate(template, "getInstanceAdvisor", instanceAdvisorGetterBody());
234       
235       return proxy;
236    }
237    
238    private String JavaDoc instanceAdvisorSetterBody()
239    {
240       return
241          "{" +
242          " synchronized (this)" +
243          " {" +
244          " if (this.instanceAdvisor != null)" +
245          " {" +
246          " throw new RuntimeException(\"InstanceAdvisor already set\");" +
247          " }" +
248          " if (!($1 instanceof org.jboss.aop.proxy.container.InstanceProxyContainer))" +
249          " {" +
250          " throw new RuntimeException(\"Wrong type for instance advisor: \" + $1);" +
251          " }" +
252          " this.instanceAdvisor = $1;" +
253          " currentAdvisor = (org.jboss.aop.proxy.container.InstanceProxyContainer)$1;" +
254          " }" +
255          "}";
256    }
257
258    private String JavaDoc instanceAdvisorGetterBody()
259    {
260       return
261          "{" +
262          " synchronized(this)" +
263          " {" +
264          " if (instanceAdvisor == null)" +
265          " {" +
266          " org.jboss.aop.proxy.container.InstanceProxyContainer ipc = ((org.jboss.aop.proxy.container.ClassProxyContainer)currentAdvisor).createInstanceProxyContainer();" +
267          " setInstanceAdvisor(ipc);" +
268          " }" +
269          " }" +
270          " return instanceAdvisor;" +
271          "}";
272    }
273
274    private CtField addFieldFromTemplate(CtClass template, String JavaDoc name) throws Exception JavaDoc
275    {
276       return addFieldFromTemplate(template, name, null);
277    }
278
279    private CtField addFieldFromTemplate(CtClass template, String JavaDoc name, CtClass type) throws Exception JavaDoc
280    {
281       CtField templateField = template.getField(name);
282       CtClass fieldType = (type == null) ? templateField.getType() : type;
283       CtField field = new CtField(fieldType, name, proxy);
284       field.setModifiers(Modifier.PRIVATE);
285       proxy.addField(field);
286       return field;
287    }
288    
289    private CtMethod addMethodFromTemplate(CtClass template, String JavaDoc name, String JavaDoc body) throws Exception JavaDoc
290    {
291       CtMethod templateMethod = template.getDeclaredMethod(name);
292       CtMethod method = CtNewMethod.make(templateMethod.getReturnType(), name, templateMethod.getParameterTypes(), templateMethod.getExceptionTypes(), body, proxy);
293       method.setModifiers(templateMethod.getModifiers());
294       proxy.addMethod(method);
295       return method;
296    }
297    
298    private void ensureDefaultConstructor(CtClass superclass, CtClass proxy) throws Exception JavaDoc
299    {
300       
301       CtConstructor[] ctors = superclass.getConstructors();
302       int minParameters = Integer.MAX_VALUE;
303       CtConstructor bestCtor = null;
304       for (int i = 0 ; i < ctors.length ; i++)
305       {
306          CtClass[] params = ctors[i].getParameterTypes();
307          if (params.length < minParameters)
308          {
309             bestCtor = ctors[i];
310             minParameters = params.length;
311          }
312       }
313       
314       if (minParameters > 0)
315       {
316          //We don't have a default constructor, we need to create one passing in null to the super ctor
317

318          //TODO We will get problems if the super class does some validation of the parameters, resulting in exceptions thrown
319
CtClass params[] = bestCtor.getParameterTypes();
320          
321          StringBuffer JavaDoc superCall = new StringBuffer JavaDoc("super(");
322          
323          for (int i = 0 ; i < params.length ; i++)
324          {
325             if (i > 0)
326             {
327                superCall.append(", ");
328             }
329             
330             if (!params[i].isPrimitive())
331             {
332                superCall.append("null");
333             }
334             else
335             {
336                if (params[i].equals(CtClass.booleanType)) superCall.append("false");
337                else if (params[i].equals(CtClass.charType)) superCall.append("'0'");
338                else if (params[i].equals(CtClass.byteType)) superCall.append("0");
339                else if (params[i].equals(CtClass.shortType)) superCall.append("0");
340                else if (params[i].equals(CtClass.intType)) superCall.append("0");
341                else if (params[i].equals(CtClass.longType)) superCall.append("0L");
342                else if (params[i].equals(CtClass.floatType)) superCall.append("0f");
343                else if (params[i].equals(CtClass.doubleType)) superCall.append("0d");
344             }
345          }
346          
347          superCall.append(");");
348          
349          CtConstructor ctor = CtNewConstructor.make(EMPTY_CTCLASS_ARRAY, EMPTY_CTCLASS_ARRAY, "{" + superCall.toString() + "}", proxy);
350          proxy.addConstructor(ctor);
351       }
352    }
353    
354    private void addMethodsAndMixins()throws Exception JavaDoc
355    {
356       HashSet JavaDoc addedMethods = new HashSet JavaDoc();
357
358       createMixinsAndIntroductions(addedMethods);
359       createProxyMethods(addedMethods);
360    }
361
362    private void createMixinsAndIntroductions(HashSet JavaDoc addedMethods) throws Exception JavaDoc
363    {
364       HashSet JavaDoc addedInterfaces = new HashSet JavaDoc();
365       Set JavaDoc implementedInterfaces = interfacesAsSet();
366       
367       if (mixins != null)
368       {
369          HashMap JavaDoc intfs = new HashMap JavaDoc();
370          HashMap JavaDoc mixinIntfs = new HashMap JavaDoc();
371          ArrayList JavaDoc mixes = new ArrayList JavaDoc();
372          for (int i = 0; i < mixins.size(); i++)
373          {
374             InterfaceIntroduction introduction = (InterfaceIntroduction) mixins.get(i);
375             getIntroductionInterfaces(introduction, intfs, mixinIntfs, mixes, i);
376          }
377          if (mixes.size() > 0)
378          {
379             CtConstructor con = CtNewConstructor.defaultConstructor(proxy);
380             con.insertAfter("mixins = new Object[" + mixes.size() + "];");
381             for (int i = 0; i < mixes.size(); i++)
382             {
383                //If using a constructor and passing "this" as the parameters, the proxy gets used. The delegate (instance wrapped by proxy) is not
384
//set in the proxy until later, and if the mixin implements Delegate it will get set with the "real" instance at this point.
385
InterfaceIntroduction.Mixin mixin = (InterfaceIntroduction.Mixin) mixes.get(i);
386                String JavaDoc initializer = (mixin.getConstruction() == null) ? ("new " + mixin.getClassName() + "()") : mixin.getConstruction();
387                String JavaDoc code = "mixins[" + i + "] = " + initializer + ";";
388                con.insertAfter(code);
389                setDelegateMethod.insertAfter("{if (org.jboss.aop.proxy.container.Delegate.class.isAssignableFrom(mixins[" + i + "].getClass())) " +
390                      "((org.jboss.aop.proxy.container.Delegate)mixins[" + i + "]).setDelegate($1);}");
391             }
392             proxy.addConstructor(con);
393          }
394          
395          createMixins(addedMethods, mixes, addedInterfaces, implementedInterfaces);
396          createIntroductions(addedMethods, intfs, addedInterfaces, implementedInterfaces);
397       }
398    }
399    
400    /**
401     * Split the interface introduction into something we can work with
402     *
403     * @param intro The InterfaceIntroduction
404     * @param intfs receives the interfaces from plain interface introductions
405     * @param mixins receives the interfaces from mixins
406     * @param mixes receives the actual InterfaceIntroduction.Mixin objects
407     * @@param the index interface introduction this data comes from
408     */

409    private void getIntroductionInterfaces(InterfaceIntroduction intro, HashMap JavaDoc intfs, HashMap JavaDoc mixins, ArrayList JavaDoc mixes, int idx)
410    {
411       if (intro.getInterfaces() != null)
412       {
413          for (int i = 0; i < intro.getInterfaces().length; i++)
414          {
415             if (intfs.containsKey(intro.getInterfaces()[i]) || mixins.containsKey(intro.getInterfaces()[i])) throw new RuntimeException JavaDoc("cannot have an IntroductionInterface that introduces same interfaces");
416             intfs.put(intro.getInterfaces()[i], new Integer JavaDoc(idx));
417          }
418       }
419       Iterator JavaDoc it = intro.getMixins().iterator();
420       while (it.hasNext())
421       {
422          InterfaceIntroduction.Mixin mixin = (InterfaceIntroduction.Mixin) it.next();
423          mixes.add(mixin);
424          for (int i = 0; i < mixin.getInterfaces().length; i++)
425          {
426             if (intfs.containsKey(mixin.getInterfaces()[i]) || mixins.containsKey(mixin.getInterfaces()[i])) throw new RuntimeException JavaDoc("cannot have an IntroductionInterface that introduces same interfaces");
427             mixins.put(mixin.getInterfaces()[i], new Integer JavaDoc(idx));
428          }
429       }
430    }
431
432    private void createMixins(HashSet JavaDoc addedMethods, ArrayList JavaDoc mixes, HashSet JavaDoc addedInterfaces, Set JavaDoc implementedInterfaces) throws Exception JavaDoc
433    {
434       for (int mixinId = 0 ; mixinId < mixes.size() ; mixinId++)
435       {
436          InterfaceIntroduction.Mixin mixin = (InterfaceIntroduction.Mixin)mixes.get(mixinId);
437          
438          String JavaDoc[] intfs = mixin.getInterfaces();
439          
440          for (int ifId = 0 ; ifId < intfs.length ; ifId++)
441          {
442             String JavaDoc intf = intfs[ifId];
443             if (addedInterfaces.contains(intf)) throw new Exception JavaDoc("2 mixins are implementing the same interfaces " + intf);
444             if (implementedInterfaces.contains(intf)) throw new Exception JavaDoc("Attempting to mixin interface already used by class " + intf);
445
446             CtClass intfClass = pool.get(intf);
447             CtMethod[] methods = intfClass.getMethods();
448             HashSet JavaDoc mixinMethods = new HashSet JavaDoc();
449             for (int m = 0; m < methods.length; m++)
450             {
451                if (methods[m].getDeclaringClass().getName().equals("java.lang.Object")) continue;
452                Long JavaDoc hash = new Long JavaDoc(JavassistMethodHashing.methodHash(methods[m]));
453                if (mixinMethods.contains(hash)) continue;
454                if (addedMethods.contains(hash)) throw new Exception JavaDoc("More than one mixin has same method");
455                mixinMethods.add(hash);
456                addedMethods.add(hash);
457                String JavaDoc aopReturnStr = (methods[m].getReturnType().equals(CtClass.voidType)) ? "" : "return ($r)";
458                String JavaDoc returnStr = (methods[m].getReturnType().equals(CtClass.voidType)) ? "" : "return ";
459                String JavaDoc args = "null";
460                if (methods[m].getParameterTypes().length > 0) args = "$args";
461                String JavaDoc code = "{ " +
462                              " try{" +
463                              " " + intf + " mixin = (" + intf + ")mixins[" + mixinId + "];" +
464                              " org.jboss.aop.MethodInfo mi = currentAdvisor.getMethodInfo(" + hash.longValue() + "L); " +
465                              " org.jboss.aop.advice.Interceptor[] interceptors = mi.getInterceptors();" +
466                              " if (mi != null && interceptors != (Object[])null && interceptors.length > 0) { " +
467                              " org.jboss.aop.proxy.container.ContainerProxyMethodInvocation invocation = new org.jboss.aop.proxy.container.ContainerProxyMethodInvocation(mi, interceptors, this); " +
468                              " invocation.setArguments(" + args + "); " +
469                              " invocation.setTargetObject(mixin); " +
470                              " invocation.setMetaData(metadata);" +
471                              " " + aopReturnStr + " invocation.invokeNext(); " +
472                              " } else { " +
473                              " " + returnStr + " mixin." + methods[m].getName() + "($$);" +
474                              " } " +
475                              " }finally{" +
476                              " }" +
477                              "}";
478                CtMethod newMethod = CtNewMethod.make(methods[m].getReturnType(), methods[m].getName(), methods[m].getParameterTypes(), methods[m].getExceptionTypes(), code, proxy);
479                newMethod.setModifiers(Modifier.PUBLIC);
480                proxy.addMethod(newMethod);
481                //System.out.println("=====> Created mixin method " + methods[m].getName());
482
}
483
484             proxy.addInterface(intfClass);
485             addedInterfaces.add(intfClass.getName());
486          }
487       }
488    }
489
490    private void createProxyMethods(HashSet JavaDoc addedMethods) throws Exception JavaDoc
491    {
492       HashMap JavaDoc allMethods = JavassistMethodHashing.getMethodMap(proxy.getSuperclass());
493
494       Iterator JavaDoc it = allMethods.entrySet().iterator();
495       while (it.hasNext())
496       {
497          Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
498          CtMethod m = (CtMethod) entry.getValue();
499          if (!Modifier.isPublic(m.getModifiers()) || Modifier.isStatic(m.getModifiers())) continue;
500
501          Long JavaDoc hash = (Long JavaDoc) entry.getKey();
502          if (addedMethods.contains(hash)) continue;
503          addedMethods.add(hash);
504          String JavaDoc aopReturnStr = (m.getReturnType().equals(CtClass.voidType)) ? "" : "return ($r)";
505          String JavaDoc returnStr = (m.getReturnType().equals(CtClass.voidType)) ? "" : "return ";
506          String JavaDoc args = "null";
507          
508          String JavaDoc name = null;
509          if (isAdvised)
510          {
511             MethodInfo info = advisor.getMethodInfo(hash.longValue());
512             Method JavaDoc originalMethod = info.getUnadvisedMethod();
513             name = originalMethod.getName();
514          }
515          else
516          {
517             name = m.getName();
518          }
519          
520          if (m.getParameterTypes().length > 0) args = "$args";
521          String JavaDoc code = "{ " +
522                        " try{" +
523                        " org.jboss.aop.MethodInfo mi = currentAdvisor.getMethodInfo(" + hash.longValue() + "L); " +
524                        " if (mi == null) " +
525                        " throw new java.lang.NoSuchMethodError(\"" + m.getName() + m.getSignature() + "\");" +
526                        " org.jboss.aop.advice.Interceptor[] interceptors = mi.getInterceptors(); " +
527                        " if (interceptors != (Object[])null && interceptors.length > 0) { " +
528                        " org.jboss.aop.proxy.container.ContainerProxyMethodInvocation invocation = new org.jboss.aop.proxy.container.ContainerProxyMethodInvocation(mi, interceptors, this); " +
529                        " invocation.setArguments(" + args + "); " +
530                        " invocation.setTargetObject(delegate); " +
531                        " invocation.setMetaData(metadata);" +
532                        " " + aopReturnStr + " invocation.invokeNext(); " +
533                        " } else { " +
534                        " " + returnStr + " delegate." + name + "($$); " +
535                        " }" +
536                        " }finally{" +
537                        " }" +
538                        "}";
539          CtMethod newMethod = CtNewMethod.make(m.getReturnType(), m.getName(), m.getParameterTypes(), m.getExceptionTypes(), code, proxy);
540          newMethod.setModifiers(Modifier.PUBLIC);
541          proxy.addMethod(newMethod);
542          //System.out.println("=====> Created proxy method " + m.getName());
543
}
544    }
545    
546    private void createIntroductions(HashSet JavaDoc addedMethods, HashMap JavaDoc intfs, HashSet JavaDoc addedInterfaces, Set JavaDoc implementedInterfaces) throws Exception JavaDoc
547    {
548       Iterator JavaDoc it = intfs.keySet().iterator();
549       while (it.hasNext())
550       {
551          String JavaDoc intf = (String JavaDoc) it.next();
552          if (addedInterfaces.contains(intf)) throw new Exception JavaDoc("2 mixins are implementing the same interfaces");
553          if (implementedInterfaces.contains(intf))
554          {
555             continue;
556          }
557
558          CtClass intfClass = pool.get(intf);
559          CtMethod[] methods = intfClass.getMethods();
560          HashSet JavaDoc mixinMethods = new HashSet JavaDoc();
561          for (int m = 0; m < methods.length; m++)
562          {
563             if (methods[m].getDeclaringClass().getName().equals("java.lang.Object")) continue;
564             
565             Long JavaDoc hash = new Long JavaDoc(JavassistMethodHashing.methodHash(methods[m]));
566             if (mixinMethods.contains(hash)) continue;
567             if (addedMethods.contains(hash)) continue;
568             
569             mixinMethods.add(hash);
570             addedMethods.add(hash);
571             String JavaDoc aopReturnStr = (methods[m].getReturnType().equals(CtClass.voidType)) ? "" : "return ($r)";
572             String JavaDoc args = "null";
573             if (methods[m].getParameterTypes().length > 0) args = "$args";
574             String JavaDoc code = "{ " +
575                           " try{" +
576                           " org.jboss.aop.MethodInfo mi = currentAdvisor.getMethodInfo(" + hash.longValue() + "L); " +
577                           " if (mi == null) " +
578                           " throw new java.lang.NoSuchMethodError(\"" + methods[m].getName() + methods[m].getSignature() + "\");" +
579                           " org.jboss.aop.advice.Interceptor[] interceptors = mi.getInterceptors();" +
580                           " org.jboss.aop.proxy.container.ContainerProxyMethodInvocation invocation = new org.jboss.aop.proxy.container.ContainerProxyMethodInvocation(mi, interceptors, this); " +
581                           " invocation.setArguments(" + args + "); " +
582                           " invocation.setTargetObject(delegate); " +
583                           " invocation.setMetaData(metadata);" +
584                           " " + aopReturnStr + " invocation.invokeNext(); " +
585                           " }finally{" +
586                           " }" +
587                           "}";
588             
589             CtMethod newMethod = CtNewMethod.make(methods[m].getReturnType(), methods[m].getName(), methods[m].getParameterTypes(), methods[m].getExceptionTypes(), code, proxy);
590             newMethod.setModifiers(Modifier.PUBLIC);
591             proxy.addMethod(newMethod);
592             //System.out.println("=====> Created introduced method " + methods[m].getName());
593
}
594
595          proxy.addInterface(intfClass);
596          addedInterfaces.add(intfClass.getName());
597       }
598    }
599
600    private Set JavaDoc interfacesAsSet() throws NotFoundException
601    {
602       HashSet JavaDoc set = new HashSet JavaDoc();
603       CtClass[] interfaces = proxy.getInterfaces();
604       
605       for (int i = 0 ; i < interfaces.length ; i++)
606       {
607          set.add(interfaces[i].getName());
608       }
609       
610       return set;
611    }
612    
613    private String JavaDoc getClassName()
614    {
615       String JavaDoc packageName = clazz.getPackage().getName();
616       if (packageName.indexOf("java.") != -1 && packageName.indexOf("sun.") != -1)
617       {
618          packageName += ".";
619       }
620       else
621       {
622          packageName = "";
623       }
624       
625       return packageName + PROXY_NAME_PREFIX + counter++;
626    }
627
628    private void overrideSpecialMethods(Class JavaDoc clazz, CtClass proxy) throws Exception JavaDoc
629    {
630       addInstanceAdvisedMethods(clazz, proxy);
631    }
632
633    /**
634     * If the class is Advised, the _getInstanceAdvisor() and _setInstanceAdvisor() methods will
635     * not have been overridden. Make sure that these methods work with the instance proxy container.
636     */

637    private void addInstanceAdvisedMethods(Class JavaDoc clazz, CtClass proxy) throws Exception JavaDoc
638    {
639       CtClass advisedInterface = null;
640       CtClass interfaces[] = proxy.getInterfaces();
641       
642       for (int i = 0 ; i < interfaces.length ; i++)
643       {
644          if (interfaces[i].getName().equals(ADVISED))
645          {
646             advisedInterface = interfaces[i];
647             break;
648          }
649       }
650       
651       if (advisedInterface != null)
652       {
653          CtMethod[] methods = advisedInterface.getMethods();
654          for (int i = 0 ; i < methods.length ; i++)
655          {
656             if (methods[i].getDeclaringClass().getName().equals(INSTANCE_ADVISED))
657             {
658                String JavaDoc name = methods[i].getName();
659                String JavaDoc body = null;
660                if (name.equals("_getInstanceAdvisor"))
661                {
662                   body = "{ return getInstanceAdvisor(); }";
663                }
664                else if (name.equals("_setInstanceAdvisor"))
665                {
666                   body = "{ setInstanceAdvisor($1); }";
667                }
668                
669                if (body != null)
670                {
671                   CtMethod m = CtNewMethod.make(methods[i].getReturnType(), methods[i].getName(), methods[i].getParameterTypes(), methods[i].getExceptionTypes(), body, proxy);
672                   m.setModifiers(Modifier.PUBLIC);
673                   proxy.addMethod(m);
674                }
675             }
676          }
677       }
678    }
679 }
680
Popular Tags