KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > javasupport > proxy > JavaProxyClassFactory


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2006 Kresten Krab Thorup <krab@gnu.org>
15  *
16  * Alternatively, the contents of this file may be used under the terms of
17  * either of the GNU General Public License Version 2 or later (the "GPL"),
18  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19  * in which case the provisions of the GPL or the LGPL are applicable instead
20  * of those above. If you wish to allow use of your version of this file only
21  * under the terms of either the GPL or the LGPL, and not to allow others to
22  * use your version of this file under the terms of the CPL, indicate your
23  * decision by deleting the provisions above and replace them with the notice
24  * and other provisions required by the GPL or the LGPL. If you do not delete
25  * the provisions above, a recipient may use your version of this file under
26  * the terms of any one of the CPL, the GPL or the LGPL.
27  ***** END LICENSE BLOCK *****/

28
29 package org.jruby.javasupport.proxy;
30
31 import java.lang.reflect.Constructor JavaDoc;
32 import java.lang.reflect.Field JavaDoc;
33 import java.lang.reflect.InvocationTargetException JavaDoc;
34 import java.lang.reflect.Method JavaDoc;
35 import java.lang.reflect.Modifier JavaDoc;
36 import java.lang.reflect.UndeclaredThrowableException JavaDoc;
37 import java.security.AccessController JavaDoc;
38 import java.security.PrivilegedAction JavaDoc;
39 import java.util.Arrays JavaDoc;
40 import java.util.HashMap JavaDoc;
41 import java.util.HashSet JavaDoc;
42 import java.util.Iterator JavaDoc;
43 import java.util.Map JavaDoc;
44 import java.util.Set JavaDoc;
45
46 import org.objectweb.asm.ClassVisitor;
47 import org.objectweb.asm.ClassWriter;
48 import org.objectweb.asm.FieldVisitor;
49 import org.objectweb.asm.Label;
50 import org.objectweb.asm.Opcodes;
51 import org.objectweb.asm.Type;
52 import org.objectweb.asm.commons.GeneratorAdapter;
53
54 public class JavaProxyClassFactory {
55
56     private static final Type JAVA_LANG_CLASS_TYPE = Type.getType(Class JavaDoc.class);
57
58     private static final Type[] EMPTY_TYPE_ARR = new Type[0];
59
60     private static final org.objectweb.asm.commons.Method HELPER_GET_PROXY_CLASS_METHOD = org.objectweb.asm.commons.Method
61             .getMethod(JavaProxyClass.class.getName()
62                     + " initProxyClass(java.lang.Class)");
63
64     private static final org.objectweb.asm.commons.Method CLASS_FORNAME_METHOD = org.objectweb.asm.commons.Method
65             .getMethod("java.lang.Class forName(java.lang.String)");
66
67     private static final String JavaDoc INVOCATION_HANDLER_FIELD_NAME = "__handler";
68
69     private static final String JavaDoc PROXY_CLASS_FIELD_NAME = "__proxy_class";
70
71     private static final Class JavaDoc[] EMPTY_CLASS_ARR = new Class JavaDoc[0];
72
73     private static final Type INVOCATION_HANDLER_TYPE = Type
74             .getType(JavaProxyInvocationHandler.class);
75
76     private static final Type PROXY_METHOD_TYPE = Type
77             .getType(JavaProxyMethod.class);
78
79     private static final Type PROXY_CLASS_TYPE = Type
80             .getType(JavaProxyClass.class);
81
82     private static final org.objectweb.asm.commons.Method INVOCATION_HANDLER_INVOKE_METHOD = org.objectweb.asm.commons.Method
83             .getMethod("java.lang.Object invoke(java.lang.Object, "
84                     + PROXY_METHOD_TYPE.getClassName()
85                     + ", java.lang.Object[])");
86
87     private static final Type PROXY_HELPER_TYPE = Type
88             .getType(InternalJavaProxyHelper.class);
89
90     private static final org.objectweb.asm.commons.Method PROXY_HELPER_GET_METHOD = org.objectweb.asm.commons.Method
91             .getMethod(PROXY_METHOD_TYPE.getClassName() + " initProxyMethod("
92                     + JavaProxyClass.class.getName()
93                     + ",java.lang.String,java.lang.String,boolean)");
94
95     private static final Type JAVA_PROXY_TYPE = Type
96             .getType(InternalJavaProxy.class);
97
98     private static int counter;
99
100     private static Map JavaDoc proxies = new HashMap JavaDoc();
101
102     private static Method JavaDoc defineClass_method;
103
104     static JavaProxyClass newProxyClass(ClassLoader JavaDoc loader,
105             String JavaDoc targetClassName, Class JavaDoc superClass, Class JavaDoc[] interfaces)
106             throws InvocationTargetException JavaDoc {
107         if (loader == null) {
108             loader = JavaProxyClassFactory.class.getClassLoader();
109         }
110
111         if (superClass == null) {
112             superClass = Object JavaDoc.class;
113         }
114
115         if (interfaces == null) {
116             interfaces = EMPTY_CLASS_ARR;
117         }
118
119         if (targetClassName == null) {
120             String JavaDoc pkg = packageName(superClass);
121             String JavaDoc fullName = superClass.getName();
122             int ix = fullName.lastIndexOf('.');
123             String JavaDoc cName = fullName;
124             if(ix != -1) {
125                 cName = fullName.substring(ix+1);
126             }
127             if (pkg.startsWith("java.") || pkg.startsWith("javax.")) {
128                 pkg = packageName(JavaProxyClassFactory.class) + ".gen";
129             }
130             if(ix == -1) {
131                 targetClassName = cName + "$Proxy" + counter++;
132             } else {
133                 targetClassName = pkg + "." + cName + "$Proxy"
134                     + counter++;
135             }
136         }
137
138         Set JavaDoc key = new HashSet JavaDoc();
139         key.add(superClass);
140         for (int i = 0; i < interfaces.length; i++) {
141             key.add(interfaces[i]);
142         }
143
144         JavaProxyClass proxyClass = (JavaProxyClass) proxies.get(key);
145         if (proxyClass == null) {
146
147             validateArgs(targetClassName, superClass);
148
149             Map JavaDoc methods = new HashMap JavaDoc();
150             collectMethods(superClass, interfaces, methods);
151
152             Type selfType = Type.getType("L"
153                     + toInternalClassName(targetClassName) + ";");
154             proxyClass = generate(loader, targetClassName, superClass,
155                     interfaces, methods, selfType);
156
157             proxies.put(key, proxyClass);
158         }
159
160         return proxyClass;
161     }
162
163     private static JavaProxyClass generate(final ClassLoader JavaDoc loader,
164             final String JavaDoc targetClassName, final Class JavaDoc superClass,
165             final Class JavaDoc[] interfaces, final Map JavaDoc methods, final Type selfType) {
166         ClassWriter cw = beginProxyClass(targetClassName, superClass,
167                 interfaces);
168
169         GeneratorAdapter clazzInit = createClassInitializer(selfType, cw);
170
171         generateConstructors(superClass, selfType, cw);
172
173         generateGetProxyClass(selfType, cw);
174
175         generateGetInvocationHandler(selfType, cw);
176
177         generateProxyMethods(superClass, methods, selfType, cw, clazzInit);
178
179         // finish class initializer
180
clazzInit.returnValue();
181         clazzInit.endMethod();
182
183         // end class
184
cw.visitEnd();
185
186         byte[] data = cw.toByteArray();
187
188         /*
189          * try { FileOutputStream o = new
190          * FileOutputStream(targetClassName.replace( '/', '.') + ".class");
191          * o.write(data); o.close(); } catch (IOException ex) {
192          * ex.printStackTrace(); }
193          */

194
195         Class JavaDoc clazz = invokeDefineClass(loader, selfType.getClassName(), data);
196
197         // trigger class initialization for the class
198
try {
199             Field JavaDoc proxy_class = clazz.getDeclaredField(PROXY_CLASS_FIELD_NAME);
200             proxy_class.setAccessible(true);
201             return (JavaProxyClass) proxy_class.get(clazz);
202         } catch (Exception JavaDoc ex) {
203             InternalError JavaDoc ie = new InternalError JavaDoc();
204             ie.initCause(ex);
205             throw ie;
206         }
207     }
208
209     static {
210         AccessController.doPrivileged(new PrivilegedAction JavaDoc() {
211             public Object JavaDoc run() {
212                 try {
213                     defineClass_method = ClassLoader JavaDoc.class.getDeclaredMethod(
214                             "defineClass", new Class JavaDoc[] { String JavaDoc.class,
215                                     byte[].class, int.class, int.class });
216                 } catch (Exception JavaDoc e) {
217                     // should not happen!
218
e.printStackTrace();
219                     return null;
220                 }
221                 defineClass_method.setAccessible(true);
222                 return null;
223             }
224         });
225     }
226
227     private static Class JavaDoc invokeDefineClass(ClassLoader JavaDoc loader,
228             String JavaDoc className, byte[] data) {
229         try {
230             return (Class JavaDoc) defineClass_method
231                     .invoke(loader, new Object JavaDoc[] { className, data,
232                             new Integer JavaDoc(0), new Integer JavaDoc(data.length) });
233         } catch (IllegalArgumentException JavaDoc e) {
234             // TODO Auto-generated catch block
235
e.printStackTrace();
236             return null;
237         } catch (IllegalAccessException JavaDoc e) {
238             // TODO Auto-generated catch block
239
e.printStackTrace();
240             return null;
241         } catch (InvocationTargetException JavaDoc e) {
242             // TODO Auto-generated catch block
243
e.printStackTrace();
244             return null;
245         }
246     }
247
248     private static ClassWriter beginProxyClass(final String JavaDoc targetClassName,
249             final Class JavaDoc superClass, final Class JavaDoc[] interfaces) {
250
251         ClassWriter cw = new ClassWriter(true);
252
253         int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC;
254         String JavaDoc name = toInternalClassName(targetClassName);
255         String JavaDoc signature = null;
256         String JavaDoc supername = toInternalClassName(superClass);
257         String JavaDoc[] interfaceNames = new String JavaDoc[interfaces.length + 1];
258         for (int i = 0; i < interfaces.length; i++) {
259             interfaceNames[i] = toInternalClassName(interfaces[i]);
260         }
261         interfaceNames[interfaces.length] = toInternalClassName(InternalJavaProxy.class);
262
263         // start class
264
cw.visit(Opcodes.V1_3, access, name, signature, supername,
265                 interfaceNames);
266
267         cw.visitField(Opcodes.ACC_PRIVATE, INVOCATION_HANDLER_FIELD_NAME,
268                 INVOCATION_HANDLER_TYPE.getDescriptor(), null, null).visitEnd();
269
270         cw.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
271                 PROXY_CLASS_FIELD_NAME, PROXY_CLASS_TYPE.getDescriptor(), null,
272                 null).visitEnd();
273
274         return cw;
275     }
276
277     private static void generateProxyMethods(Class JavaDoc superClass, Map JavaDoc methods,
278             Type selfType, ClassVisitor cw, GeneratorAdapter clazzInit) {
279         Iterator JavaDoc it = methods.values().iterator();
280         while (it.hasNext()) {
281             MethodData md = (MethodData) it.next();
282             Type superClassType = Type.getType(superClass);
283             generateProxyMethod(selfType, superClassType, cw, clazzInit, md);
284         }
285     }
286
287     private static void generateGetInvocationHandler(Type selfType,
288             ClassVisitor cw) {
289         // make getter for handler
290
GeneratorAdapter gh = new GeneratorAdapter(Opcodes.ACC_PUBLIC,
291                 new org.objectweb.asm.commons.Method("___getInvocationHandler",
292                         INVOCATION_HANDLER_TYPE, EMPTY_TYPE_ARR), null,
293                 EMPTY_TYPE_ARR, cw);
294
295         gh.loadThis();
296         gh.getField(selfType, INVOCATION_HANDLER_FIELD_NAME,
297                 INVOCATION_HANDLER_TYPE);
298         gh.returnValue();
299         gh.endMethod();
300     }
301
302     private static void generateGetProxyClass(Type selfType, ClassVisitor cw) {
303         // make getter for proxy class
304
GeneratorAdapter gpc = new GeneratorAdapter(Opcodes.ACC_PUBLIC,
305                 new org.objectweb.asm.commons.Method("___getProxyClass",
306                         PROXY_CLASS_TYPE, EMPTY_TYPE_ARR), null,
307                 EMPTY_TYPE_ARR, cw);
308         gpc.getStatic(selfType, PROXY_CLASS_FIELD_NAME, PROXY_CLASS_TYPE);
309         gpc.returnValue();
310         gpc.endMethod();
311     }
312
313     private static void generateConstructors(Class JavaDoc superClass, Type selfType,
314             ClassVisitor cw) {
315         Constructor JavaDoc[] cons = superClass.getConstructors();
316         for (int i = 0; i < cons.length; i++) {
317             Constructor JavaDoc constructor = cons[i];
318
319             int acc = constructor.getModifiers();
320             if (Modifier.isProtected(acc) || Modifier.isPublic(acc)) {
321                 // ok, it's publix or protected
322
} else if (!Modifier.isPrivate(acc)
323                     && packageName(constructor.getDeclaringClass()).equals(
324                             packageName(selfType.getClassName()))) {
325                 // ok, it's package scoped and we're in the same package
326
} else {
327                 // it's unaccessible
328
continue;
329             }
330
331             generateConstructor(selfType, constructor, cw);
332         }
333     }
334
335     private static GeneratorAdapter createClassInitializer(Type selfType,
336             ClassVisitor cw) {
337         GeneratorAdapter clazzInit;
338         clazzInit = new GeneratorAdapter(Opcodes.ACC_PRIVATE
339                 | Opcodes.ACC_STATIC, new org.objectweb.asm.commons.Method(
340                 "<clinit>", Type.VOID_TYPE, EMPTY_TYPE_ARR), null,
341                 EMPTY_TYPE_ARR, cw);
342
343         clazzInit.visitLdcInsn(selfType.getClassName());
344         clazzInit.invokeStatic(JAVA_LANG_CLASS_TYPE, CLASS_FORNAME_METHOD);
345         clazzInit
346                 .invokeStatic(PROXY_HELPER_TYPE, HELPER_GET_PROXY_CLASS_METHOD);
347         clazzInit.dup();
348         clazzInit.putStatic(selfType, PROXY_CLASS_FIELD_NAME, PROXY_CLASS_TYPE);
349         return clazzInit;
350     }
351
352     private static void generateProxyMethod(Type selfType, Type superType,
353             ClassVisitor cw, GeneratorAdapter clazzInit, MethodData md) {
354         if (!md.generateProxyMethod()) {
355             return;
356         }
357
358         org.objectweb.asm.commons.Method m = md.getMethod();
359         Type[] ex = toType(md.getExceptions());
360
361         String JavaDoc field_name = "__mth$" + md.getName() + md.scrabmledSignature();
362
363         // create static private method field
364
FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE
365                 | Opcodes.ACC_STATIC, field_name, PROXY_METHOD_TYPE
366                 .getDescriptor(), null, null);
367         fv.visitEnd();
368
369         clazzInit.dup();
370         clazzInit.push(m.getName());
371         clazzInit.push(m.getDescriptor());
372         clazzInit.push(md.isImplemented());
373         clazzInit.invokeStatic(PROXY_HELPER_TYPE, PROXY_HELPER_GET_METHOD);
374         clazzInit.putStatic(selfType, field_name, PROXY_METHOD_TYPE);
375
376         org.objectweb.asm.commons.Method sm = new org.objectweb.asm.commons.Method(
377                 "__super$" + m.getName(), m.getReturnType(), m
378                         .getArgumentTypes());
379
380         //
381
// construct the proxy method
382
//
383
GeneratorAdapter ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC, m, null,
384                 ex, cw);
385
386         ga.loadThis();
387         ga.getField(selfType, INVOCATION_HANDLER_FIELD_NAME,
388                 INVOCATION_HANDLER_TYPE);
389
390         // if the method is extending something, then we have
391
// to test if the handler is initialized...
392

393         if (md.isImplemented()) {
394             ga.dup();
395             Label ok = ga.newLabel();
396             ga.ifNonNull(ok);
397
398             ga.loadThis();
399             ga.loadArgs();
400             ga.invokeConstructor(superType, m);
401             ga.returnValue();
402             ga.mark(ok);
403         }
404
405         ga.loadThis();
406         ga.getStatic(selfType, field_name, PROXY_METHOD_TYPE);
407
408         if (m.getArgumentTypes().length == 0) {
409             // load static empty array
410
ga.getStatic(JAVA_PROXY_TYPE, "NO_ARGS", Type
411                     .getType(Object JavaDoc[].class));
412         } else {
413             // box arguments
414
ga.loadArgArray();
415         }
416
417         Label before = ga.mark();
418
419         ga.invokeInterface(INVOCATION_HANDLER_TYPE,
420                 INVOCATION_HANDLER_INVOKE_METHOD);
421
422         Label after = ga.mark();
423
424         ga.unbox(m.getReturnType());
425         ga.returnValue();
426
427         // this is a simple rethrow handler
428
Label rethrow = ga.mark();
429         ga.visitInsn(Opcodes.ATHROW);
430
431         for (int i = 0; i < ex.length; i++) {
432             ga.visitTryCatchBlock(before, after, rethrow, ex[i]
433                     .getInternalName());
434         }
435
436         ga.visitTryCatchBlock(before, after, rethrow, "java/lang/Error");
437         ga.visitTryCatchBlock(before, after, rethrow,
438                 "java/lang/RuntimeException");
439
440         Type thr = Type.getType(Throwable JavaDoc.class);
441         Label handler = ga.mark();
442         Type udt = Type.getType(UndeclaredThrowableException JavaDoc.class);
443         int loc = ga.newLocal(thr);
444         ga.storeLocal(loc, thr);
445         ga.newInstance(udt);
446         ga.dup();
447         ga.loadLocal(loc, thr);
448         ga.invokeConstructor(udt, org.objectweb.asm.commons.Method
449                 .getMethod("void <init>(java.lang.Throwable)"));
450         ga.throwException();
451
452         ga.visitTryCatchBlock(before, after, handler, "java/lang/Throwable");
453
454         ga.endMethod();
455
456         //
457
// construct the super-proxy method
458
//
459
if (md.isImplemented()) {
460
461             GeneratorAdapter ga2 = new GeneratorAdapter(Opcodes.ACC_PUBLIC, sm,
462                     null, ex, cw);
463
464             ga2.loadThis();
465             ga2.loadArgs();
466             ga2.invokeConstructor(superType, m);
467             ga2.returnValue();
468             ga2.endMethod();
469         }
470     }
471
472     private static Class JavaDoc[] generateConstructor(Type selfType,
473             Constructor JavaDoc constructor, ClassVisitor cw) {
474
475         Class JavaDoc[] superConstructorParameterTypes = constructor
476                 .getParameterTypes();
477         Class JavaDoc[] newConstructorParameterTypes = new Class JavaDoc[superConstructorParameterTypes.length + 1];
478         System.arraycopy(superConstructorParameterTypes, 0,
479                 newConstructorParameterTypes, 0,
480                 superConstructorParameterTypes.length);
481         newConstructorParameterTypes[superConstructorParameterTypes.length] = JavaProxyInvocationHandler.class;
482
483         int access = Opcodes.ACC_PUBLIC;
484         String JavaDoc name1 = "<init>";
485         String JavaDoc signature = null;
486         Class JavaDoc[] superConstructorExceptions = constructor.getExceptionTypes();
487
488         org.objectweb.asm.commons.Method super_m = new org.objectweb.asm.commons.Method(
489                 name1, Type.VOID_TYPE, toType(superConstructorParameterTypes));
490         org.objectweb.asm.commons.Method m = new org.objectweb.asm.commons.Method(
491                 name1, Type.VOID_TYPE, toType(newConstructorParameterTypes));
492
493         GeneratorAdapter ga = new GeneratorAdapter(access, m, signature,
494                 toType(superConstructorExceptions), cw);
495
496         ga.loadThis();
497         ga.loadArgs(0, superConstructorParameterTypes.length);
498         ga.invokeConstructor(Type.getType(constructor.getDeclaringClass()),
499                 super_m);
500
501         ga.loadThis();
502         ga.loadArg(superConstructorParameterTypes.length);
503         ga.putField(selfType, INVOCATION_HANDLER_FIELD_NAME,
504                 INVOCATION_HANDLER_TYPE);
505
506         // do a void return
507
ga.returnValue();
508         ga.endMethod();
509         return newConstructorParameterTypes;
510     }
511
512     private static String JavaDoc toInternalClassName(Class JavaDoc clazz) {
513         return toInternalClassName(clazz.getName());
514     }
515
516     private static String JavaDoc toInternalClassName(String JavaDoc name) {
517         return name.replace('.', '/');
518     }
519
520     private static Type[] toType(Class JavaDoc[] parameterTypes) {
521         Type[] result = new Type[parameterTypes.length];
522         for (int i = 0; i < result.length; i++) {
523             result[i] = Type.getType(parameterTypes[i]);
524         }
525         return result;
526     }
527
528     private static void collectMethods(Class JavaDoc superClass, Class JavaDoc[] interfaces,
529             Map JavaDoc methods) {
530         HashSet JavaDoc allClasses = new HashSet JavaDoc();
531         addClass(allClasses, methods, superClass);
532         addInterfaces(allClasses, methods, interfaces);
533     }
534
535     static class MethodData {
536         Set JavaDoc methods = new HashSet JavaDoc();
537
538         final Method JavaDoc mostSpecificMethod;
539
540         boolean hasPublicDecl = false;
541
542         MethodData(Method JavaDoc method) {
543             this.mostSpecificMethod = method;
544             hasPublicDecl = method.getDeclaringClass().isInterface()
545                     || Modifier.isPublic(method.getModifiers());
546         }
547
548         public String JavaDoc scrabmledSignature() {
549             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
550             Class JavaDoc[] parms = getParameterTypes();
551             for (int i = 0; i < parms.length; i++) {
552                 sb.append('$');
553                 String JavaDoc name = parms[i].getName();
554                 name = name.replace('[', '1');
555                 name = name.replace('.', '_');
556                 name = name.replace(';', '2');
557                 sb.append(name);
558             }
559             return sb.toString();
560         }
561
562         public Class JavaDoc getDeclaringClass() {
563             return mostSpecificMethod.getDeclaringClass();
564         }
565
566         public org.objectweb.asm.commons.Method getMethod() {
567             return new org.objectweb.asm.commons.Method(getName(), Type
568                     .getType(getReturnType()), getType(getParameterTypes()));
569         }
570
571         private Type[] getType(Class JavaDoc[] parameterTypes) {
572             Type[] result = new Type[parameterTypes.length];
573             for (int i = 0; i < parameterTypes.length; i++) {
574                 result[i] = Type.getType(parameterTypes[i]);
575             }
576             return result;
577         }
578
579         private String JavaDoc getName() {
580             return mostSpecificMethod.getName();
581         }
582
583         private Class JavaDoc[] getParameterTypes() {
584             return mostSpecificMethod.getParameterTypes();
585         }
586
587         public Class JavaDoc[] getExceptions() {
588
589             Set JavaDoc all = new HashSet JavaDoc();
590
591             Iterator JavaDoc it = methods.iterator();
592             while (it.hasNext()) {
593                 Method JavaDoc m = (Method JavaDoc) it.next();
594                 Class JavaDoc[] ex = m.getExceptionTypes();
595                 for (int i = 0; i < ex.length; i++) {
596                     Class JavaDoc exx = ex[i];
597
598                     if (all.contains(exx)) {
599                         continue;
600                     }
601
602                     boolean add = true;
603                     Iterator JavaDoc it2 = all.iterator();
604                     while (it2.hasNext()) {
605                         Class JavaDoc de = (Class JavaDoc) it2.next();
606
607                         if (de.isAssignableFrom(exx)) {
608                             add = false;
609                             break;
610                         } else if (exx.isAssignableFrom(de)) {
611                             it2.remove();
612                             add = true;
613                         }
614
615                     }
616
617                     if (add) {
618                         all.add(exx);
619                     }
620                 }
621             }
622
623             return (Class JavaDoc[]) all.toArray(new Class JavaDoc[all.size()]);
624         }
625
626         public boolean generateProxyMethod() {
627             return !isFinal() && hasPublicDecl;
628         }
629
630         public void add(Method JavaDoc method) {
631             methods.add(method);
632             hasPublicDecl |= Modifier.isPublic(method.getModifiers());
633         }
634
635         Class JavaDoc getReturnType() {
636             return mostSpecificMethod.getReturnType();
637         }
638
639         boolean isFinal() {
640             if (mostSpecificMethod.getDeclaringClass().isInterface()) {
641                 return false;
642             }
643
644             int mod = mostSpecificMethod.getModifiers();
645             return Modifier.isFinal(mod);
646         }
647
648         boolean isImplemented() {
649             if (mostSpecificMethod.getDeclaringClass().isInterface()) {
650                 return false;
651             }
652
653             int mod = mostSpecificMethod.getModifiers();
654             return !Modifier.isAbstract(mod);
655         }
656     }
657
658     static class MethodKey {
659         private String JavaDoc name;
660
661         private Class JavaDoc[] arguments;
662
663         MethodKey(Method JavaDoc m) {
664             this.name = m.getName();
665             this.arguments = m.getParameterTypes();
666         }
667
668         public boolean equals(Object JavaDoc obj) {
669             if (obj instanceof MethodKey) {
670                 MethodKey key = (MethodKey) obj;
671
672                 return name.equals(key.name)
673                         && Arrays.equals(arguments, key.arguments);
674             }
675
676             return false;
677         }
678
679         public int hashCode() {
680             return name.hashCode();
681         }
682     }
683
684     private static void addInterfaces(Set JavaDoc allClasses, Map JavaDoc methods,
685             Class JavaDoc[] interfaces) {
686         for (int i = 0; i < interfaces.length; i++) {
687             addInterface(allClasses, methods, interfaces[i]);
688         }
689     }
690
691     private static void addInterface(Set JavaDoc allClasses, Map JavaDoc methods,
692             Class JavaDoc interfaze) {
693         if (allClasses.add(interfaze)) {
694             addMethods(methods, interfaze);
695             addInterfaces(allClasses, methods, interfaze.getInterfaces());
696         }
697     }
698
699     private static void addMethods(Map JavaDoc methods, Class JavaDoc classOrInterface) {
700         Method JavaDoc[] mths = classOrInterface.getDeclaredMethods();
701         for (int i = 0; i < mths.length; i++) {
702             addMethod(methods, mths[i]);
703         }
704     }
705
706     private static void addMethod(Map JavaDoc methods, Method JavaDoc method) {
707
708         int acc = method.getModifiers();
709         if (Modifier.isStatic(acc) || Modifier.isPrivate(acc)) {
710             return;
711         }
712
713         MethodKey mk = new MethodKey(method);
714         MethodData md = (MethodData) methods.get(mk);
715         if (md == null) {
716             md = new MethodData(method);
717             methods.put(mk, md);
718         }
719         md.add(method);
720     }
721
722     private static void addClass(Set JavaDoc allClasses, Map JavaDoc methods, Class JavaDoc clazz) {
723         if (allClasses.add(clazz)) {
724             addMethods(methods, clazz);
725             Class JavaDoc superClass = clazz.getSuperclass();
726             if (superClass != null) {
727                 addClass(allClasses, methods, superClass);
728             }
729
730             addInterfaces(allClasses, methods, clazz.getInterfaces());
731         }
732     }
733
734     private static void validateArgs(String JavaDoc targetClassName, Class JavaDoc superClass) {
735
736         if (Modifier.isFinal(superClass.getModifiers())) {
737             throw new IllegalArgumentException JavaDoc("cannot extend final class");
738         }
739
740         String JavaDoc targetPackage = packageName(targetClassName);
741
742         String JavaDoc pkg = targetPackage.replace('.', '/');
743         if (pkg.startsWith("java")) {
744             throw new IllegalArgumentException JavaDoc("cannor add classes to package "
745                     + pkg);
746         }
747
748         Package JavaDoc p = Package.getPackage(pkg);
749         if (p != null) {
750             if (p.isSealed()) {
751                 throw new IllegalArgumentException JavaDoc("package " + p
752                         + " is sealed");
753             }
754         }
755     }
756
757     private static String JavaDoc packageName(Class JavaDoc clazz) {
758         String JavaDoc clazzName = clazz.getName();
759         return packageName(clazzName);
760     }
761
762     private static String JavaDoc packageName(String JavaDoc clazzName) {
763         int idx = clazzName.lastIndexOf('.');
764         if (idx == -1) {
765             return "";
766         } else {
767             return clazzName.substring(0, idx);
768         }
769     }
770
771 }
772
Popular Tags