KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jac > core > rtti > ClassRepository


1 /*
2   Copyright (C) 2001-2003 Renaud Pawlak <renaud@aopsys.com>,
3                           Laurent Martelli <laurent@aopsys.com>
4   
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU Lesser General Public License as
7   published by the Free Software Foundation; either version 2 of the
8   License, or (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   GNU Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */

18
19 package org.objectweb.jac.core.rtti;
20
21 import java.lang.reflect.Constructor JavaDoc;
22 import java.lang.reflect.Field JavaDoc;
23 import java.lang.reflect.InvocationTargetException JavaDoc;
24 import java.lang.reflect.Method JavaDoc;
25 import java.lang.reflect.Modifier JavaDoc;
26 import java.util.Arrays JavaDoc;
27 import java.util.Collection JavaDoc;
28 import java.util.Enumeration JavaDoc;
29 import java.util.Hashtable JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.Vector JavaDoc;
33 import org.apache.log4j.Logger;
34 import org.objectweb.jac.util.Classes;
35 import org.objectweb.jac.util.Strings;
36
37 /**
38  * This class defines the class repository of the rtti aspect.<p>
39  *
40  * It contains class items that are field and method items
41  * agregates.<p>
42  *
43  * @see ClassItem
44  * @see MethodItem
45  * @see FieldItem
46  * @see CollectionItem
47  *
48  * @author Renaud Pawlak
49  * @author Laurent Martelli
50  */

51
52 public class ClassRepository implements LoadtimeRTTI {
53     static Logger logger = Logger.getLogger("rtti.repository");
54     static Logger loggerlt = Logger.getLogger("rtti.lt");
55
56     Map JavaDoc ltClassInfos = new Hashtable JavaDoc();
57
58     public ClassInfo getClassInfo(String JavaDoc className) {
59         ClassInfo classinfo=(ClassInfo)ltClassInfos.get(className);
60         if (classinfo==null) {
61             classinfo=new ClassInfo();
62             ltClassInfos.put(className,classinfo);
63         }
64         return classinfo;
65     }
66
67     public void setClassInfo(String JavaDoc className, ClassInfo classInfo) {
68         ltClassInfos.put(className,classInfo);
69     }
70
71     public MethodInfo getMethodInfo(String JavaDoc className, String JavaDoc method) {
72         return getClassInfo(className).getMethodInfo(method);
73     }
74
75     /**
76      * Adds a modified field for a given method.
77      *
78      * <p>This method is automatically called at load-time by the JAC
79      * classloader through bytecode analysis.
80      *
81      * @param methodSign the method signature of the form
82      * <code>packagepath.classname.methodname</code>
83      * @param fieldName the name of the field that is modified by the
84      * method */

85
86     public void addltModifiedField(String JavaDoc className, String JavaDoc methodSign,
87                                    String JavaDoc fieldName) {
88         getClassInfo(className).addModifiedField(methodSign,fieldName);
89     }
90
91     public void addltSetField(String JavaDoc className, String JavaDoc methodSign,
92                               String JavaDoc fieldName) {
93         getClassInfo(className).addSetField(methodSign,fieldName);
94     }
95
96     /**
97      * Adds an accessed field for a given method.
98      *
99      * <p>This method is automatically called at load-time by the JAC
100      * classloader through bytecode analysis.
101      *
102      * @param methodSign the method signature of the form
103      * <code>packagepath.classname.methodname</code>
104      * @param fieldName the name of the field that is accessed by the
105      * method */

106
107     public void addltAccessedField(String JavaDoc className, String JavaDoc methodSign,
108                                    String JavaDoc fieldName) {
109         getClassInfo(className).addAccessedField(methodSign,fieldName);
110     }
111
112     public void addltReturnedField(String JavaDoc className, String JavaDoc methodSign,
113                                    String JavaDoc fieldName) {
114         getClassInfo(className).setReturnedField(methodSign,fieldName);
115     }
116
117     public void setltIsGetter(String JavaDoc className, String JavaDoc methodSign,
118                               boolean isGetter) {
119         getClassInfo(className).setIsGetter(methodSign,isGetter);
120     }
121
122     public void addltAddedCollection(String JavaDoc className, String JavaDoc methodSign,
123                                      String JavaDoc fieldName) {
124         getClassInfo(className).addAddedCollection(methodSign,fieldName);
125     }
126
127     public void addltRemovedCollection(String JavaDoc className, String JavaDoc methodSign,
128                                        String JavaDoc fieldName) {
129         getClassInfo(className).addRemovedCollection(methodSign,fieldName);
130     }
131
132     public void addltModifiedCollection(String JavaDoc className, String JavaDoc methodSign,
133                                         String JavaDoc fieldName) {
134         getClassInfo(className).addModifiedCollection(methodSign,fieldName);
135     }
136
137     public void setCollectionIndexArgument(String JavaDoc className, String JavaDoc methodSign,
138                                            int argument) {
139         getClassInfo(className).setCollectionIndexArgument(methodSign,argument);
140     }
141
142     public void setCollectionItemArgument(String JavaDoc className, String JavaDoc methodSign,
143                                           int argument) {
144         getClassInfo(className).setCollectionItemArgument(methodSign,argument);
145     }
146
147     public void addInvokedMethod(String JavaDoc className, String JavaDoc methodSign,
148                                  InvokeInfo invokeInfo) {
149         getClassInfo(className).addInvokedMethod(methodSign,invokeInfo);
150     }
151
152     public void setCallSuper(String JavaDoc className, String JavaDoc method) {
153         getMethodInfo(className,method).callSuper = true;
154     }
155
156     /**
157      * Get the sole instance of class repository.<p>
158      *
159      * @return the class repository */

160    
161     public static ClassRepository get() {
162         if ( classRepository == null ) {
163             classRepository = new ClassRepository();
164         }
165         return classRepository;
166     }
167    
168     /**
169      * Store the sole instance of class repository. */

170
171     protected static transient ClassRepository classRepository = null;
172
173     /** Stores the Jac objects root class. */
174     //public static Class jacObjectClass;
175
/** Stores the Wrappee class. */
176     public static Class JavaDoc wrappeeClass;
177     static {
178         try {
179             //jacObjectClass = Class.forName( "org.objectweb.jac.core.JacObject" );
180
wrappeeClass = Class.forName("org.objectweb.jac.core.Wrappee");
181         } catch(Exception JavaDoc e) {
182             e.printStackTrace();
183             System.exit( -1 );
184         }
185     }
186
187     /**
188      * Store direct access to the methods of all the classes by name on
189      * optimization purpose. */

190     transient static Hashtable JavaDoc directMethodAccess = new Hashtable JavaDoc();
191
192     /**
193      * Store direct access to the fields of all the classes by name on
194      * optimization purpose. */

195     transient static Hashtable JavaDoc directFieldAccess = new Hashtable JavaDoc();
196
197     /**
198      * Fill the direct access to methods hashtable for a given class.
199      *
200      * <p>This is used to optimize the method calls when you only have
201      * the method name.
202      *
203      * @param cl the class to treat.
204      *
205      * @see #getDirectMethodAccess(Class,String) */

206
207     public static Hashtable JavaDoc fillDirectMethodAccess(final Class JavaDoc cl) {
208         if( cl == null ) return null;
209         if ( directMethodAccess == null ) directMethodAccess = new Hashtable JavaDoc();
210         Hashtable JavaDoc methods = new Hashtable JavaDoc();
211         final Method JavaDoc[] meths = cl.getMethods();
212         // AccessibleObject.setAccessible( meths, true );
213
for (int i=meths.length-1; i>=0; i--) {
214             meths[i].setAccessible(true);
215             if ( methods.containsKey(meths[i].getName()) ) {
216                 Method JavaDoc[] oldms = (Method JavaDoc[]) methods.get( meths[i].getName() );
217                 Method JavaDoc[] newms = new Method JavaDoc[oldms.length+1];
218                 System.arraycopy( oldms, 0, newms, 0, oldms.length );
219                 newms[oldms.length] = meths[i];
220                 methods.remove( meths[i].getName() );
221                 methods.put( meths[i].getName(), newms );
222             } else {
223                 methods.put( meths[i].getName(), new Method JavaDoc[] { meths[i] } );
224             }
225         }
226         directMethodAccess.put(cl,methods);
227         return methods;
228     }
229
230     /**
231      * Fill the direct access to fields hashtable for a given class.
232      *
233      * <p>This is used to optimize the access of protected and private
234      * fields.
235      *
236      * @param cl the class to treat. */

237
238     public static void fillDirectFieldAccess(final Class JavaDoc cl) {
239         if (cl==null || cl==Object JavaDoc.class)
240             return;
241         if (directFieldAccess == null )
242             directFieldAccess = new Hashtable JavaDoc();
243         if (directFieldAccess.containsKey(cl))
244             return;
245         Hashtable JavaDoc fields = new Hashtable JavaDoc();
246         Class JavaDoc superClass = cl.getSuperclass();
247         if (superClass!=Object JavaDoc.class && superClass!=null) {
248             fillDirectFieldAccess(superClass);
249             Map JavaDoc inheritedFields = (Map JavaDoc)directFieldAccess.get(superClass);
250             if (inheritedFields!=null)
251                 fields.putAll(inheritedFields);
252         }
253         final Field JavaDoc[] fs = cl.getDeclaredFields();
254         // AccessibleObject.setAccessible( fs, true );
255
for (int i = 0; i<fs.length; i++) {
256             if (!isJacField(fs[i].getName()) && !isSystemField(fs[i].getName())) {
257                 fs[i].setAccessible(true);
258                 fields.put(fs[i].getName(),fs[i]);
259             }
260         }
261         directFieldAccess.put(cl,fields);
262     }
263
264     /**
265      * Returns a Hashtable that maps fields with their names.
266      *
267      * <p>For efficiency, the programmer should use this method instead
268      * of using the Java refection API to retrives values of protected
269      * or private fields within a class and all its superclasses.
270      *
271      * @param cl the class
272      * @return a Map (String(field name) -> Field)
273      *
274      * @see #fillDirectFieldAccess(Class) */

275
276     public static Hashtable JavaDoc getDirectFieldAccess(Class JavaDoc cl) {
277         fillDirectFieldAccess(cl);
278         return ((Hashtable JavaDoc)directFieldAccess.get(cl));
279     }
280
281     /**
282      * Call a directly acceded method.
283      *
284      * @param cl the class that supports the method
285      * @param methodName the method to call
286      * @param o the object to call the method on
287      * @param params the arguments
288      *
289      * @see #getDirectMethodAccess(Class,String)
290      */

291     public static Object JavaDoc invokeDirect(Class JavaDoc cl,
292                                       String JavaDoc methodName,
293                                       Object JavaDoc o,
294                                       Object JavaDoc[] params)
295         throws java.lang.NoSuchMethodException JavaDoc,
296         InvocationTargetException JavaDoc, IllegalAccessException JavaDoc
297     {
298         Method JavaDoc[] directMethods = getDirectMethodAccess(cl,methodName);
299         logger.debug("direct invocation of "+methodName+" => "+
300                      java.util.Arrays.asList(directMethods));
301         boolean ok = false;
302         boolean lengthOk = false;
303         Object JavaDoc ret = null;
304         for (int i=0; i<directMethods.length; i++) {
305             if (directMethods[i].getParameterTypes().length==params.length) {
306                 lengthOk = true;
307                 try {
308                     ret = directMethods[i].invoke(o, params);
309                     ok = true;
310                 } catch (IllegalArgumentException JavaDoc e1) {
311                 }
312             }
313         }
314         if (!ok) {
315             if (lengthOk) {
316                 logger.error("No such method "+cl.getName()+"."+methodName+Arrays.asList(params));
317             } else {
318                 logger.error("Wrong number of parameters for "+cl.getName()+"."+methodName+Arrays.asList(params));
319             }
320             throw new java.lang.NoSuchMethodException JavaDoc();
321         }
322         return ret;
323     }
324
325     /**
326      * Return an array of methods that correspond to the given class
327      * and given method name.
328      *
329      * <p>For efficiency, the programmer should use this method instead
330      * of using the Java refection API.
331      *
332      * @param cl the class where the method is supposed to be
333      * @param name the method name
334      * @return an array containing the matching methods (homonyms), a
335      * one array element with <code>null</code> inside if none method
336      * matched (this ugly result was introduced for backward
337      * compatibility)
338      *
339      * @see #fillDirectMethodAccess(Class)
340      */

341     public static Method JavaDoc[] getDirectMethodAccess(Class JavaDoc cl, String JavaDoc name) {
342         Hashtable JavaDoc methods = (Hashtable JavaDoc)directMethodAccess.get(cl);
343         if (methods==null)
344             methods = fillDirectMethodAccess(cl);
345         Method JavaDoc[] ret = (Method JavaDoc[]) methods.get(name);
346         if (ret == null ) {
347             return new Method JavaDoc[] { };
348         } else {
349             return ret;
350         }
351     }
352
353     /**
354      * Returns true is this class defautlt constructor (the one with no
355      * parameter) has been added by JAC at class load-time.
356      *
357      * @param cl the class to test
358      * @return true if added, false if programmer defined
359      */

360     public static boolean isDefaultConstructorAdded(Class JavaDoc cl) {
361         try {
362             cl.getField("__JAC_ADDED_DEFAULT_CONSTRUCTOR");
363         } catch (Exception JavaDoc e) {
364             return false;
365         }
366         return true;
367     }
368
369     /**
370      * Return true if the method is added by JAC at class load-time.
371      *
372      * @param methodName the method to check
373      * @return true if added at load-time
374      */

375     public static boolean isJacMethod (String JavaDoc methodName) {
376         if (methodName.startsWith("_"))
377             return true;
378         return false;
379     }
380
381     /**
382      * Return true if the field is added by JAC at class load-time.
383      * @param fieldName name of the field
384      */

385     public static boolean isJacField (String JavaDoc fieldName) {
386         return
387             fieldName.startsWith("__JAC_") ||
388             fieldName.equals("JUST4LOG_OPTIMIZED");
389     }
390
391     /**
392      * Tells if the field is a "system" field, such as a field added by
393      * the compiler for class objects.
394      * @param fieldName name of the field
395      */

396     public static boolean isSystemField(String JavaDoc fieldName) {
397         return fieldName.indexOf('$')!=-1;
398     }
399
400     /**
401      * Gets the method names of a class
402      *
403      * @param cl the class
404      * @return the method names as an array of strings
405      */

406     public static String JavaDoc[] getMethodsName(Class JavaDoc cl) {
407    
408         String JavaDoc[] methodNames = null;
409         Vector JavaDoc tmp = new Vector JavaDoc();
410       
411         try {
412       
413             Method JavaDoc[] methods = cl.getMethods();
414
415             for (int i=0; i<methods.length; i++) {
416                 if ( ! ( Modifier.isStatic(methods[i].getModifiers()) ||
417                          isJacMethod(methods[i].getName()) ) ) {
418                     tmp.add (methods[i].getName());
419                 }
420             }
421
422             methodNames = new String JavaDoc[tmp.size()];
423
424             for (int i=0 ; i<tmp.size(); i++) {
425                 methodNames[i] = (String JavaDoc)tmp.get(i);
426             }
427
428         } catch(Exception JavaDoc e) {
429             logger.error("getMethodsName "+cl.getName()+" failed",e);
430         }
431       
432         return methodNames;
433     }
434
435     /**
436      * Get modifiers names.
437      *
438      * @param cl the class
439      * @return the modifiers method names as an array of strings
440      */

441     public static String JavaDoc[] getModifiersNames(Class JavaDoc cl) {
442    
443         ClassItem cli = ClassRepository.get().getClass(cl);
444         Collection JavaDoc modifiers = cli.getAllModifiers();
445       
446         String JavaDoc[] methodNames = new String JavaDoc[modifiers.size()];
447
448         Iterator JavaDoc it = modifiers.iterator();
449         for( int i=0; i<methodNames.length; i++ ) {
450             methodNames[i]=((MethodItem)it.next()).getName();
451         }
452         return methodNames;
453     }
454
455     /**
456      * Get getter names.
457      *
458      * @param cl the class
459      * @return the modifiers names as an array of strings
460      */

461     public static String JavaDoc[] getGettersNames(Class JavaDoc cl) {
462    
463         ClassItem cli = ClassRepository.get().getClass(cl);
464         Collection JavaDoc getters = cli.getAllGetters();
465       
466         String JavaDoc[] methodNames = new String JavaDoc[getters.size()];
467
468         Iterator JavaDoc it = getters.iterator();
469         for( int i=0; i<methodNames.length; i++ ) {
470             methodNames[i]=((MethodItem)it.next()).getName();
471         }
472         return methodNames;
473     }
474
475     /**
476      * Adds a set of written fields to a method.<p>
477      *
478      * This method shortcuts the writting of RTTI aspects for
479      * programs. Equivalent effects can be achieved by using the RTTI
480      * aspect API.<p>
481      *
482      * @param cl the involved class
483      * @param methodName the method name
484      * @param fieldNames the set of fields that are written by this
485      * method
486      * @see MethodItem#addWrittenField(FieldItem)
487      */

488     public static void addWrittenFields(Class JavaDoc cl,
489                                         String JavaDoc methodName,
490                                         String JavaDoc[] fieldNames)
491     {
492         ClassItem cli = ((ClassRepository)ClassRepository.get()).getClass(cl);
493         MethodItem[] mis = cli.getMethods(methodName);
494
495         if ( mis != null ) {
496             for ( int i = 0; i < mis.length; i++ ) {
497                 for ( int j = 0; j < fieldNames.length; j++ ) {
498                     FieldItem fi = cli.getField( fieldNames[j] );
499                     if ( fi != null ) {
500                         mis[i].addWrittenField(fi);
501                     }
502                 }
503             }
504         }
505       
506     }
507
508     /**
509      * Adds a set of accessed fields to a method.<p>
510      *
511      * This method shortcuts the writting of RTTI aspects for
512      * programs. Equivalent effects can be achieved by using the RTTI
513      * aspect API.<p>
514      *
515      * @param cl the involved class
516      * @param methodName the method name
517      * @param fieldNames the set of fields that are accessed by this
518      * method
519      * @see MethodItem#addAccessedField(FieldItem)
520      */

521     public static void addAccessedFields(Class JavaDoc cl,
522                                          String JavaDoc methodName,
523                                          String JavaDoc[] fieldNames) {
524       
525         ClassItem cli = ClassRepository.get().getClass(cl);
526         MethodItem[] mis = cli.getMethods(methodName);
527
528         if ( mis != null ) {
529             for ( int i = 0; i < mis.length; i++ ) {
530                 for ( int j = 0; j < fieldNames.length; j++ ) {
531                     FieldItem fi = cli.getField( fieldNames[j] );
532                     if ( fi != null ) {
533                         mis[i].addAccessedField(fi);
534                     }
535                 }
536             }
537         }
538       
539     }
540
541     /**
542      * Adds a set of added collections to a method.<p>
543      *
544      * This method shortcuts the writting of RTTI aspects for
545      * programs. Equivalent effects can be achieved by using the RTTI
546      * aspect API.<p>
547      *
548      * @param cl the involved class
549      * @param methodName the method name
550      * @param collectionNames the set of collections that are added by this
551      * method
552      * @see MethodItem#addAddedCollection(CollectionItem)
553      */

554     public static void addAddedCollections(Class JavaDoc cl,
555                                            String JavaDoc methodName,
556                                            String JavaDoc[] collectionNames) {
557       
558         ClassItem cli = ClassRepository.get().getClass(cl);
559         MethodItem[] mis = cli.getMethods(methodName);
560
561         if ( mis != null ) {
562             for ( int i = 0; i < mis.length; i++ ) {
563                 for ( int j = 0; j < collectionNames.length; j++ ) {
564                     CollectionItem ci = (CollectionItem)cli.getField(collectionNames[j]);
565                     if ( ci != null ) {
566                         mis[i].addAddedCollection(ci);
567                     }
568                 }
569             }
570         }
571       
572     }
573
574     /**
575      * Adds a set of removed collections to a method.<p>
576      *
577      * This method shortcuts the writting of RTTI aspects for
578      * programs. Equivalent effects can be achieved by using the RTTI
579      * aspect API.<p>
580      *
581      * @param cl the involved class
582      * @param methodName the method name
583      * @param collectionNames the set of collections that are removed by this
584      * method
585      * @see MethodItem#addRemovedCollection(CollectionItem)
586      */

587     public static void addRemovedCollections(Class JavaDoc cl,
588                                              String JavaDoc methodName,
589                                              String JavaDoc[] collectionNames) {
590       
591         ClassItem cli = ClassRepository.get().getClass(cl);
592         MethodItem[] mis = cli.getMethods(methodName);
593
594         if (mis != null) {
595             for (int i=0; i<mis.length; i++) {
596                 for (int j=0; j<collectionNames.length; j++) {
597                     CollectionItem ci = (CollectionItem)cli.getField(collectionNames[j]);
598                     if (ci != null) {
599                         mis[i].addRemovedCollection(ci);
600                     }
601                 }
602             }
603         }
604       
605     }
606
607     /**
608      * The default constructor will set the classRepository field to
609      * the right value (singleton pattern). */

610
611     public ClassRepository () {
612         classRepository = this;
613     }
614
615     /**
616      * This method returns an existing class from its name.
617      *
618      * <p>If the class is not registered yet, the class repository
619      * automatically builds default runtime informations (using naming
620      * conventions), and seamlessly registers the new
621      * <code>ClassItem</code> instance into the class repository.
622      *
623      * <p>Note: in case of manual class registrations, a class must be
624      * registered with its full name to avoid name conflicts.<p>
625      *
626      * @param name the name of the class to get
627      * @return the class if exist, null otherwise
628      *
629      * @see #getVirtualClass(String)
630      */

631     public ClassItem getClass(String JavaDoc name)
632     {
633         String JavaDoc wrappedName = Classes.getPrimitiveTypeWrapper(name);
634         MetaItem res = (MetaItem)getObject(wrappedName);
635         if (res == null) {
636             try {
637                 res = getClass(Class.forName(name));
638             } catch (ClassNotFoundException JavaDoc e) {
639                 throw new NoSuchClassException(name);
640             }
641         }
642         if (res!=null && res instanceof ClassItem)
643             return (ClassItem)res;
644         else
645             throw new NoSuchClassException(name);
646     }
647
648     /**
649      * Returns a ClassItem or a VirtualClassItem from its name. It
650      * first tries to find a ClassItem, and if it fails, it returns a
651      * VirtualClassItem.
652      *
653      * @param name the name of the class to find
654      * @return a ClassItem or a VirtualClassItem
655      *
656      * @see #getClass(String)
657      * @see #getVirtualClassStrict(String)
658      */

659
660     public MetaItem getVirtualClass(String JavaDoc name)
661     {
662         MetaItem ret;
663         try {
664             ret = getClass(name);
665         } catch (NoSuchClassException e) {
666             ret = (MetaItem)getObject(name);
667             if (ret == null)
668                 throw e;
669         }
670         return ret;
671     }
672
673     /**
674      * Returns a VirtualClassItem from its name.
675      * @param name the name of the class to find
676      * @return the VirtualClassItem with the requested name
677      * @see #getClass(String)
678      * @see #getVirtualClass(String)
679      */

680     public VirtualClassItem getVirtualClassStrict(String JavaDoc name)
681     {
682         MetaItem ret;
683         ret = (MetaItem)getObject(name);
684         if (ret == null || !(ret instanceof VirtualClassItem))
685             throw new NoSuchClassException(name);
686         return (VirtualClassItem)ret;
687     }
688
689     /**
690      * This method returns the class item that corresponds to the given
691      * object class.<p>
692      *
693      * @param object the object to get the class item
694      * @return the class item
695      * @see #getClass(String) */

696
697     public ClassItem getClass(Object JavaDoc object) {
698         return getNonPrimitiveClass(object.getClass().getName());
699     }
700     /**
701      * This method returns the class item that corresponds to the given
702      * class.<p>
703      *
704      * @param cl the class to get the class item of
705      * @return the class item
706      * @see #getClass(String)
707      */

708     public ClassItem getClass(Class JavaDoc cl) {
709         String JavaDoc wrappedName = Classes.getPrimitiveTypeWrapper(cl.getName());
710         MetaItem res = (MetaItem)getObject(wrappedName);
711         if (res == null) {
712             res = buildDefaultRTTI(cl);
713             if (res != null)
714                 register(wrappedName, res);
715         }
716         if (res!=null && res instanceof ClassItem)
717             return (ClassItem)res;
718         else
719             throw new NoSuchClassException(cl.getName());
720         /* return getClass(cl.getName()); */
721     }
722
723     public ClassItem getNonPrimitiveClass(String JavaDoc className) {
724         try {
725             // !!! Class.forName() can trigger the instantiation of
726
// !!! the ClassItem
727
Class JavaDoc cl = Class.forName(className);
728             MetaItem res = (MetaItem)getObject(className);
729             if (res == null) {
730                 try {
731                     res = buildDefaultRTTI(cl);
732                 } catch(Exception JavaDoc e) {
733                     throw new NoSuchClassException(className);
734                 }
735                 if (res != null) {
736                     register(className, res);
737                     return (ClassItem)res;
738                 }
739             } else {
740                 return (ClassItem)res;
741             }
742             throw new NoSuchClassException(className);
743         } catch(ClassNotFoundException JavaDoc e) {
744             throw new NoSuchClassException(className);
745         }
746     }
747
748     String JavaDoc ignoreFields = null;
749     public void ignoreFields(String JavaDoc packageExpr) {
750         ignoreFields = packageExpr;
751     }
752
753     /**
754      * This method builds the default RTTI for a given class name and
755      * returns a corresponding class item.<p>
756      *
757      * @param cl the class to build
758      * @return the corresponding class item, null if the given name is
759      * not a class name
760      */

761     public ClassItem buildDefaultRTTI(Class JavaDoc cl) {
762         ClassItem cli = null;
763         logger.debug( ">>> Constructing RTTI infos for class "+cl.getName()+Strings.hash(cl));
764         try {
765
766             cli = new ClassItem(cl);
767
768             // methods
769
Method JavaDoc[] meths = cl.getMethods();
770             //Log.trace("rtti.methods","adding methods for "+cli);
771
for(int i=0; i<meths.length; i++) {
772                 if (meths[i].getDeclaringClass() == Object JavaDoc.class
773                     /*|| meths[i].getName().startsWith("_")*/ ) continue;
774                 Logger.getLogger("rtti."+cl.getName()).debug(" adding method "+meths[i]);
775                 MethodItem mi = new MethodItem(meths[i],cli);
776                 cli.addMethod(mi);
777             }
778
779             // constructors
780
Constructor JavaDoc[] constructors = cl.getConstructors();
781             for(int i=0; i<constructors.length; i++) {
782                 if ( ! ( isDefaultConstructorAdded(cl) &&
783                          constructors[i].getParameterTypes().length == 0 ) ) {
784                     cli.addConstructor(new ConstructorItem(constructors[i],cli));
785                 }
786             }
787
788         } catch (InvalidDelegateException e) {
789             logger.error("buildDefaultRTTI("+cl.getName()+"): "+e);
790             return null;
791         } catch (NoClassDefFoundError JavaDoc e) {
792             logger.error("buildDefaultRTTI("+cl.getName()+")",e);
793             throw e;
794         }
795         logger.debug( ">>> DONE Constructing RTTI infos for class "+cl.getName()+Strings.hash(cl)+
796                       " -> "+cli+Strings.hash(cli));
797         return cli;
798     }
799
800     public void buildDefaultFieldRTTI(ClassItem cli) {
801         loggerlt.debug("constructing fields info for "+cli.getName());
802         Class JavaDoc cl = cli.getActualClass();
803         Collection JavaDoc fields = getDirectFieldAccess(cl).values();
804         Iterator JavaDoc it = fields.iterator();
805         while (it.hasNext()) {
806             Field JavaDoc f = (Field JavaDoc) it.next();
807             //logger.debug( "constructing " + f );
808
Class JavaDoc t = f.getType();
809             FieldItem fi = null;
810             MethodItem mis[] = null;
811             Method JavaDoc m = null;
812             try {
813                 if (RttiAC.isCollectionType(t))
814                 {
815                     logger.debug(t.getName()+" -> "+f.getName()+ " is a collection");
816                     fi = new CollectionItem(f,cli);
817                 } else {
818                     logger.debug(f.getName()+ " is a field");
819                     fi = new FieldItem(f,cli);
820                 }
821             } catch (InvalidDelegateException e) {
822                 e.printStackTrace();
823             }
824             cli.addField(fi);
825         }
826         Logger logger = Logger.getLogger("rtti."+cli.getName());
827         logger.debug("extracting bytecoded info for "+cli.getName());
828         logger.debug("methods "+cli.getAllMethods());
829         Iterator JavaDoc methods = cli.getAllMethods().iterator();
830         while (methods.hasNext()) {
831             MethodItem method = (MethodItem)methods.next();
832             try {
833                 logger.debug(" "+method.getFullName());
834                 AbstractMethodItem realMethod = method.getConcreteMethod();
835                 String JavaDoc key = realMethod.getOwningClass().getName()+"."+realMethod.getFullName();
836                 ClassInfo classinfo = getClassInfo(realMethod.getOwningClass().getName());
837                 MethodInfo methodinfo = classinfo.getMethodInfo(key);
838                 if (methodinfo.accessedFields.size()>0) {
839                     logger.debug(" accessed fields: "+methodinfo.accessedFields);
840                     it = methodinfo.accessedFields.iterator();
841                     while (it.hasNext()) {
842                         String JavaDoc fieldName = (String JavaDoc)it.next();
843                         FieldItem fi = cli.getField(fieldName);
844                         method.addAccessedField(fi);
845                         fi.addAccessingMethod(method);
846                     }
847                 }
848                 if (methodinfo.returnedField!=null && methodinfo.isGetter) {
849                     logger.debug(" returned field: "+
850                                  methodinfo.returnedField);
851                     FieldItem fi = cli.getField(methodinfo.returnedField);
852                     method.setReturnedField(fi);
853                     fi.setGetter(method);
854                 }
855                 if (methodinfo.collectionIndexArgument!=-1) {
856                     logger.debug(" collectionIndexArgument : "+
857                                  methodinfo.collectionIndexArgument);
858                     method.setCollectionIndexArgument(methodinfo.collectionIndexArgument);
859                 }
860                 if (methodinfo.collectionItemArgument!=-1) {
861                     logger.debug(" collectionItemArgument : "+
862                                  methodinfo.collectionItemArgument);
863                     method.setCollectionItemArgument(methodinfo.collectionItemArgument);
864                 }
865                 if (methodinfo.modifiedFields.size()>0) {
866                     logger.debug(" modified fields: "+methodinfo.modifiedFields);
867                     it = methodinfo.modifiedFields.iterator();
868                     while(it.hasNext()) {
869                         String JavaDoc fieldName = (String JavaDoc)it.next();
870                         try {
871                             FieldItem fi = cli.getField(fieldName);
872                             method.addWrittenField(fi);
873                             fi.addWritingMethod(method);
874                         } catch (NoSuchFieldException JavaDoc e) {
875                             // On Windows, JDK 1.4.0_02, static private fields
876
// used for <MyClass>.class are not found here
877
}
878                     }
879                 }
880                 if (methodinfo.setFields.size()==1) {
881                     logger.debug(" set fields: "+methodinfo.setFields);
882                     it = methodinfo.setFields.iterator();
883                     while(it.hasNext()) {
884                         String JavaDoc fieldName = (String JavaDoc)it.next();
885                         FieldItem fi = cli.getField(fieldName);
886                         method.setSetField(fi);
887                         fi.setSetter(method);
888                     }
889                 } else if (methodinfo.setFields.size()>1) {
890                     logger.warn(
891                         cli.getName()+" sets more than one field: "+
892                         methodinfo.setFields);
893                 }
894                 if (methodinfo.addedCollections.size()>0) {
895                     logger.debug(" added collections: "+
896                                  methodinfo.addedCollections);
897                     it = methodinfo.addedCollections.iterator();
898                     while(it.hasNext()) {
899                         String JavaDoc fieldName = (String JavaDoc)it.next();
900                         CollectionItem ci = cli.getCollection(fieldName);
901                         method.addAddedCollection(ci);
902                         ci.addAddingMethod(method);
903                     }
904                 }
905                 if (methodinfo.removedCollections.size()>0) {
906                     logger.debug(" removed collections: "+
907                                  methodinfo.removedCollections);
908                     it = methodinfo.removedCollections.iterator();
909                     while(it.hasNext()) {
910                         String JavaDoc fieldName = (String JavaDoc)it.next();
911                         CollectionItem ci = cli.getCollection(fieldName);
912                         method.addRemovedCollection(ci);
913                         ci.addRemovingMethod(method);
914                     }
915                 }
916                 if (methodinfo.modifiedCollections.size()>0) {
917                     logger.debug(" modified collections: "+
918                                  methodinfo.modifiedCollections);
919                     it = methodinfo.modifiedCollections.iterator();
920                     while(it.hasNext()) {
921                         String JavaDoc fieldName = (String JavaDoc)it.next();
922                         CollectionItem ci = cli.getCollection(fieldName);
923                         method.addModifiedCollection(ci);
924                         ci.addWritingMethod(method);
925                     }
926                 }
927                 if (method.getType()!=void.class &&
928                     methodinfo.invokedMethods.size()>0) {
929                     logger.debug(" invoked methods: "+methodinfo.invokedMethods);
930                     it = methodinfo.invokedMethods.iterator();
931                     while(it.hasNext()) {
932                         InvokeInfo invokeInfo = (InvokeInfo)it.next();
933                         ClassItem invokedClass = getClass(invokeInfo.className);
934                         try {
935                             MethodItem invokedMethod =
936                                 invokedClass.getMethod(invokeInfo.method);
937                             if (invokedMethod.getType()!=void.class)
938                                 invokedMethod.addDependentMethod(method);
939                         } catch(Exception JavaDoc e) {
940                         }
941                     }
942                 }
943                 if (methodinfo.callSuper) {
944                     ClassItem superClass = cli.getSuperclass();
945                     logger.debug(" calls super");
946                     if (superClass!=null) {
947                         try {
948                             MethodItem superMethod =
949                                 superClass.getMethod(method.getFullName());
950                             if (superMethod.isAdder()) {
951                                 CollectionItem[] addedCollections =
952                                     superMethod.getAddedCollections();
953                                 logger.debug(" added collections: "+
954                                              Arrays.asList(addedCollections));
955                                 for (int i=0; i<addedCollections.length; i++) {
956                                     CollectionItem collection =
957                                         cli.getCollection(addedCollections[i].getName());
958                                     method.addAddedCollection(collection);
959                                     collection.addAddingMethod(method);
960                                 }
961                             }
962                             if (superMethod.isRemover()) {
963                                 CollectionItem[] removedCollections =
964                                     superMethod.getRemovedCollections();
965                                 logger.debug(" removed collections: "+
966                                              Arrays.asList(removedCollections));
967                                 for (int i=0; i<removedCollections.length; i++) {
968                                     CollectionItem collection =
969                                         cli.getCollection(removedCollections[i].getName());
970                                     method.addRemovedCollection(collection);
971                                     collection.addRemovingMethod(method);
972                                 }
973                             }
974                             if (superMethod.hasModifiedCollections()) {
975                                 CollectionItem[] modifiedCollections =
976                                     method.getModifiedCollections();
977                                 logger.debug(" modified collections: "+
978                                              Arrays.asList(modifiedCollections));
979                                 for (int i=0; i<modifiedCollections.length; i++) {
980                                     CollectionItem collection =
981                                         cli.getCollection(modifiedCollections[i].getName());
982                                     method.addModifiedCollection(collection);
983                                     collection.addWritingMethod(method);
984                                 }
985                             }
986                             if (superMethod.isSetter()) {
987                                 FieldItem field =
988                                     cli.getField(superMethod.getSetField().getName());
989                                 method.setSetField(field);
990                                 field.setSetter(method);
991                                 logger.debug(" set field: "+field);
992                             }
993                             if (superMethod.hasWrittenFields()) {
994                                 FieldItem[] writtenFields =
995                                     superMethod.getWrittenFields();
996                                 for (int i=0; i<writtenFields.length; i++) {
997                                     FieldItem field = cli.getField(writtenFields[i].getName());
998                                     method.addWrittenField(field);
999                                     field.addWritingMethod(method);
1000                                }
1001                            }
1002                        } catch (NoSuchMethodException JavaDoc e) {
1003                            // The superclass' method may be
1004
// protected, and we shouldn't issue a
1005
// warning in this case
1006
if (!superClass.hasMethod(method.getName(),method.getParameterTypes()))
1007                                logger.warn(
1008                                    "Method "+method.getFullName()+
1009                                    " calls super but super class "+superClass.getName()+
1010                                    " does not have a public method with that name");
1011                        }
1012                    } else {
1013                        logger.warn("Method "+method.getFullName()+
1014                                    " calls super but class does not have a super class");
1015                    }
1016                }
1017            } catch (Exception JavaDoc e) {
1018                logger.error("Failed RTTI build for "+method,e);
1019            }
1020        }
1021
1022        // Inherited mixin methods
1023
ClassItem superClass = cli.getSuperclass();
1024        if (superClass!=null) {
1025            Iterator JavaDoc i = superClass.getMixinMethods().iterator();
1026            while (i.hasNext()) {
1027                MixinMethodItem method = (MixinMethodItem)i.next();
1028                try {
1029                    cli.addMethod(new MixinMethodItem((Method JavaDoc)method.getDelegate(),cli));
1030                    logger.debug("Adding inherited mixin method "+method.getFullName());
1031                } catch(InvalidDelegateException e) {
1032                    logger.error("Failed to add inherited mixin method "+
1033                                 method.getFullName(),e);
1034                }
1035            }
1036        }
1037    }
1038
1039    /**
1040     * Link class items to their names */

1041    public Hashtable JavaDoc objects = new Hashtable JavaDoc();
1042
1043    /**
1044     * Reverse hashtable to find an class item from its name */

1045    public Hashtable JavaDoc names = new Hashtable JavaDoc();
1046
1047    /**
1048     * Register a new class into the class repository.
1049     *
1050     * @param logicalName the key that allows to find the class
1051     * @param object the class to register
1052     * @return true if the class registered, false if already
1053     * registered
1054     *
1055     * @see #unregister(String)
1056     */

1057    public void register(String JavaDoc logicalName, Object JavaDoc object) {
1058        Object JavaDoc o = objects.get(logicalName);
1059        boolean result = true;
1060        if (o != null && !(object instanceof VirtualClassItem)) {
1061            throw new RuntimeException JavaDoc("Class "+logicalName+" is already registered: "+o);
1062        }
1063        objects.put(logicalName, object);
1064        names.put(object, logicalName);
1065    }
1066
1067    /**
1068     * Unregister a class from the repository.
1069     *
1070     * @param logicalName the class name
1071     *
1072     * @see #register(String,Object)
1073     */

1074    public void unregister(String JavaDoc logicalName) {
1075        if (objects.get(logicalName) == null) {
1076            return;
1077        }
1078        names.remove(objects.get(logicalName));
1079        objects.remove(logicalName);
1080    }
1081
1082    /**
1083     * Returns true if a class is registered with this name.
1084     *
1085     * @param logicalName the key that allows to find the class
1086     *
1087     * @see #register(String,Object)
1088     */

1089    public boolean isRegistered(String JavaDoc logicalName) {
1090        if (names.contains(logicalName)) {
1091            return true;
1092        }
1093        return false;
1094    }
1095
1096    /**
1097     * Return all the registered classes as an array.
1098     *
1099     * <p>Reverse operation is <code>getNames()</code>.
1100     *
1101     * @return the registered classes in this repository
1102     *
1103     * @see #register(String,Object)
1104     * @see #getNames()
1105     */

1106    public Object JavaDoc[] getClasses() {
1107        return objects.values().toArray();
1108    }
1109
1110    /**
1111     * Return the names of the registered classes as an array.
1112     *
1113     * @return the registered classes names in this repository
1114     *
1115     * @see #register(String,Object)
1116     */

1117    public Object JavaDoc[] getNames() {
1118        return names.values().toArray();
1119    }
1120
1121    /**
1122     * Return a registered classes for a given logical name.
1123     *
1124     * <p>Return <code>null</code> if the name does not correspond to
1125     * any registered class or if <code>logicalName</code> is null.
1126     *
1127     * <p>Reverse operation is <code>getName(Object)</code>.
1128     *
1129     * @param logicalName the key that allows to find the class
1130     * @return the corresponding object, null if not registered
1131     *
1132     * @see #register(String,Object)
1133     * @see #getName(Object)
1134     */

1135    public Object JavaDoc getObject(String JavaDoc logicalName) {
1136        if (logicalName == null) return null;
1137        return objects.get(logicalName);
1138    }
1139
1140    /**
1141     * Returns the name of a registered class. Null if not
1142     * registered.
1143     *
1144     * <p>Reverse operation is <code>getObject(String)</code>.
1145     *
1146     * @param object the class to get the name of
1147     * @return the class name, null if not registered
1148     *
1149     * @see #register(String,Object)
1150     * @see #getObject(String)
1151     */

1152    public String JavaDoc getName (Object JavaDoc object) {
1153        if (object == null) {
1154            return null;
1155        }
1156        return (String JavaDoc)names.get(object);
1157    }
1158
1159    /**
1160     * Returns a field whose owning class is the class of an object
1161     *
1162     * @param substance the object whose class to user
1163     * @param field the field to return
1164     */

1165    public FieldItem getActualField(Object JavaDoc substance, FieldItem field) {
1166        return getClass(substance).getField(field.getName());
1167    }
1168
1169    /**
1170     * Dump all the registered classes in this class repository.
1171     */

1172    public void dump() {
1173        Enumeration JavaDoc keys = objects.keys();
1174      
1175        System.out.println ( getClass().getName() + " dump:");
1176        while (keys.hasMoreElements()) {
1177            String JavaDoc key = (String JavaDoc) keys.nextElement();
1178            System.out.println(" - " + key + " : " + objects.get( key ) );
1179        }
1180    }
1181
1182    /* instantiate an object from a string */
1183    public static Object JavaDoc instantiate(Class JavaDoc type, String JavaDoc value) {
1184        if (type==int.class) {
1185            type = Integer JavaDoc.class;
1186        } else if (type==float.class) {
1187            type = Float JavaDoc.class;
1188        } else if (type==double.class) {
1189            type = Double JavaDoc.class;
1190        } else if (type==boolean.class) {
1191            type = Boolean JavaDoc.class;
1192        } else if (type==byte.class) {
1193            type = Byte JavaDoc.class;
1194        } else if (type==char.class) {
1195            type = Character JavaDoc.class;
1196        } else if (type==long.class) {
1197            type = Long JavaDoc.class;
1198        } else if (type==short.class) {
1199            type = Short JavaDoc.class;
1200        }
1201        try {
1202            Constructor JavaDoc constructor = type.getConstructor(new Class JavaDoc[] {String JavaDoc.class});
1203            return constructor.newInstance(new Object JavaDoc[] {value});
1204        } catch (Exception JavaDoc e) {
1205            e.printStackTrace();
1206            return null;
1207        }
1208    }
1209}
1210
Popular Tags