KickJava   Java API By Example, From Geeks To Geeks.

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


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 gnu.regexp.RE;
22 import java.lang.reflect.InvocationTargetException JavaDoc;
23 import java.lang.reflect.Modifier JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.Hashtable JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Vector JavaDoc;
29 import org.apache.log4j.Logger;
30 import java.lang.reflect.Constructor JavaDoc;
31
32 /**
33  * This class defines a meta item that corresponds to the
34  * <code>java.lang.reflect.Class</code> meta element.<p>
35  *
36  * @author Renaud Pawlak
37  * @author Laurent Martelli
38  */

39
40 public class ClassItem extends MetaItemDelegate {
41
42     static Logger logger = Logger.getLogger("rtti.class");
43
44     static Class JavaDoc wrappeeClass = ClassRepository.wrappeeClass;
45
46     /**
47      * Default contructor to create a new class item object.<p>
48      *
49      * @param delegate the <code>java.lang.reflect.Class</code> actual
50      * meta item
51      */

52     public ClassItem(Class JavaDoc delegate) throws InvalidDelegateException {
53         super(delegate);
54         Class JavaDoc superClass = delegate.getSuperclass();
55         if (superClass!=Object JavaDoc.class && superClass!=null) {
56             try {
57                 setSuperClass(ClassRepository.get().getClass(superClass));
58             } catch(Exception JavaDoc e) {
59                 logger.error("ClassItem("+delegate.getName()+"): "+e);
60             }
61         }
62     }
63
64     private int collsCount = 0;
65     private int refsCount = 0;
66     private int primsCount = 0;
67     private int methodsCount = 0;
68     private int constructorsCount = 0;
69
70     /**
71      * Stores the fields of the class.<p> */

72
73     protected Hashtable JavaDoc fields = new Hashtable JavaDoc();
74
75     /**
76      * Stores the methods of the class. */

77
78     protected Hashtable JavaDoc methods = new Hashtable JavaDoc();
79
80     boolean rttiBuilt = false;
81
82     protected void buildFieldInfo() {
83         if (!rttiBuilt) {
84             rttiBuilt = true;
85             ClassRepository.get().buildDefaultFieldRTTI(this);
86         }
87     }
88
89     /**
90      * Gets a field from its name. Throw an exception if the field does
91      * not exist.<p>
92      *
93      * @param name the field name. If name contains a dot, it is
94      * considered an expression field and is automatically created if
95      * it does not exist yet.
96      * @return a <code>FieldItem</code> instance
97      * @see #getFieldNoError(String)
98      */

99     public FieldItem getField(String JavaDoc name) {
100         buildFieldInfo();
101         FieldItem ret = getFieldNoError(name);
102         if (ret==null) {
103             throw new NoSuchFieldException JavaDoc(this,name);
104         }
105         return ret;
106     }
107
108     /**
109      * Gets a field from its name. Don't throw an exception if the
110      * field does not exist.<p>
111      *
112      * @param name the field name
113      * @return a <code>FieldItem</code> instance, or null if no such
114      * field exists in the class
115      * @see #getField(String)
116      */

117     public FieldItem getFieldNoError(String JavaDoc name) {
118         buildFieldInfo();
119         FieldItem field = (FieldItem)fields.get(name);
120         if (field==null) {
121             if (name.indexOf('.')!=-1) {
122                 try {
123                     List JavaDoc path = parseExpression(name);
124                     if (path.get(path.size()-1) instanceof CollectionItem) {
125                         field = new CollectionItem(name,path,this);
126                     } else {
127                         field = new FieldItem(name,path,this);
128                     }
129                     addField(field);
130                 } catch (Exception JavaDoc e) {
131                     field = null;
132                     logger.error("Expression field "+this.getName()+"."+name+
133                                  " instanciation failed: "+e);
134                     e.printStackTrace();
135                 }
136             }
137         }
138         if (field==null && superClass!=null) {
139             field = superClass.getFieldNoError(name);
140             if (field!=null) {
141                 field = field.clone(this);
142                 addField(field);
143             }
144         }
145         return field;
146     }
147
148     /**
149      * Parse the expression and computes its type.
150      * @param expression the expression (<field>.<field>.<field>...)
151      */

152     public List JavaDoc parseExpression(String JavaDoc expression) {
153         Vector JavaDoc path = new Vector JavaDoc();
154         String JavaDoc current = expression;
155         ClassItem curClass = this;
156         int dot = current.indexOf('.');
157         FieldItem field = null;
158         while (dot!=-1) {
159             String JavaDoc fieldName = current.substring(0,dot);
160             field = curClass.getField(fieldName);
161             path.add(field);
162             if (field instanceof CollectionItem)
163                 curClass = ((CollectionItem)field).getComponentType();
164             else
165                 curClass = field.getTypeItem();
166             current = current.substring(dot+1);
167             dot = current.indexOf('.');
168         }
169
170         field = curClass.getField(current);
171         path.add(field);
172       
173         /*
174           if (field!=null) {
175           type = field.getType();
176           setter = field.getSetter();
177           }
178         */

179
180         return path;
181     }
182
183     /**
184      * Gets a collection from its name.<p>
185      *
186      * @param name the collection name
187      * @return a <code>CollectionItem</code> instance
188      */

189
190     public CollectionItem getCollection(String JavaDoc name) {
191         buildFieldInfo();
192         return (CollectionItem) fields.get(name);
193     }
194
195     /**
196      * Gets all the fields for this class item.<p>
197      *
198      * @return an array of field items
199      */

200
201     public FieldItem[] getFields() {
202         buildFieldInfo();
203         Collection JavaDoc c = fields.values();
204         FieldItem[] res = new FieldItem[c.size()];
205         Iterator JavaDoc it = c.iterator();
206         int i = 0;
207         while (it.hasNext()) {
208             res[i] = (FieldItem) it.next();
209             i++;
210         }
211         return res;
212     }
213
214     /**
215      * Gets all the fields for this class item
216      *
217      * @return the fields as a collection
218      */

219
220     public Collection JavaDoc getAllFields() {
221         buildFieldInfo();
222         return fields.values();
223     }
224
225     /**
226      * Gets all the current class item's fields that are tagged or not
227      * tagged with the given attribute.<p>
228      *
229      * @param attribute the attribute
230      * @param not if true, returns fields not tagged with attribute
231      *
232      * @return a collection of field items
233      */

234     public Collection JavaDoc getTaggedFields(String JavaDoc attribute, boolean not) {
235         buildFieldInfo();
236         Collection JavaDoc c = fields.values();
237         Iterator JavaDoc it = c.iterator();
238         Vector JavaDoc result = new Vector JavaDoc();
239         int i = 0;
240         while (it.hasNext()) {
241             FieldItem field = (FieldItem) it.next();
242             if (field.getAttribute(attribute)!=null ^ not) {
243                 result.add(field);
244             }
245         }
246         return result;
247     }
248
249     /**
250      * @param expression something like [!](static|transient|private|public|protected)
251      */

252     public Collection JavaDoc filterFields(String JavaDoc expression) {
253         logger.debug(this+".filterFields "+expression);
254         String JavaDoc keyword;
255         boolean not = false;
256         if (expression.charAt(0)=='!') {
257             not = true;
258             expression = expression.substring(1,expression.length());
259         }
260         int filter = 0;
261         if (expression.equals("static"))
262             filter = Modifier.STATIC;
263         else if (expression.equals("public"))
264             filter = Modifier.PUBLIC;
265         else if (expression.equals("transient"))
266             filter = Modifier.TRANSIENT;
267         else if (expression.equals("private"))
268             filter = Modifier.PRIVATE;
269         else if (expression.equals("protected"))
270             filter = Modifier.PROTECTED;
271         Vector JavaDoc result = new Vector JavaDoc();
272         Iterator JavaDoc it = fields.values().iterator();
273         while (it.hasNext()) {
274             FieldItem field = (FieldItem) it.next();
275             if (((field.getModifiers() & filter) != 0) ^ not) {
276                 result.add(field);
277             }
278         }
279         logger.debug(" -> "+result);
280         return result;
281     }
282
283     public Collection JavaDoc getTaggedMethods(String JavaDoc attribute, boolean not) {
284         Collection JavaDoc c = getAllMethods();
285         Iterator JavaDoc it = c.iterator();
286         Vector JavaDoc result = new Vector JavaDoc();
287         int i = 0;
288         while (it.hasNext()) {
289             AbstractMethodItem method = (AbstractMethodItem) it.next();
290             if (method.getAttribute(attribute)!=null ^ not) {
291                 result.add(method);
292             }
293         }
294         return result;
295     }
296
297     public Collection JavaDoc getTaggedMembers(String JavaDoc attribute, boolean not) {
298         Collection JavaDoc result = getTaggedMethods(attribute,not);
299         result.addAll(getTaggedFields(attribute,not));
300         return result;
301     }
302
303     /**
304      * Returns the members that are tagged by a given attribute that
305      * has a given value.
306      *
307      * @param attribute the attribute id
308      * @param value the value of the attribute (must not be null!!) */

309
310     public Collection JavaDoc getTaggedMembers(String JavaDoc attribute, Object JavaDoc value) {
311         Collection JavaDoc result = getAllMembers();
312         Collection JavaDoc result2 = new Vector JavaDoc();
313         Iterator JavaDoc it = result.iterator();
314         while (it.hasNext()) {
315             MemberItem member = (MemberItem)it.next();
316             if (member.getAttribute(attribute)!=null
317                 && value.equals(member.getAttribute(attribute)))
318             {
319                 result2.add(member);
320             }
321         }
322         return result2;
323     }
324
325     /**
326      * Returns the member (method or field) of this class with the
327      * specified name.
328      * @param name the name of the member that you want.
329      * @return the member with the specified name
330      * @see #getMembers(String[]) */

331     public MemberItem getMember(String JavaDoc name) {
332         MemberItem result = null;
333         try {
334             if (name.indexOf('(')!=-1)
335                 result = getAbstractMethod(name);
336             else
337                 result = getField(name);
338         } catch(NoSuchFieldException JavaDoc e) {
339             if (result==null) {
340                 try {
341                     result = getAbstractMethod(name);
342                 } catch (NoSuchMethodException JavaDoc e2) {
343                     throw new NoSuchMemberException(this,name);
344                 }
345             }
346         }
347         return result;
348     }
349
350     /**
351      * Returns a MemberItem array.
352      *
353      * @param names the names of the members
354      * @return a MemberItem array members such as
355      * members[i].getName().equals(names[i]). If no member with a given
356      * name is found, it is ignored (but a warning is issued).
357      * @see #getMember(String)
358      */

359     public MemberItem[] getMembers(String JavaDoc[] names) {
360         MemberItem[] tmp = new MemberItem[names.length];
361         int j = 0;
362         for(int i=0; i<names.length; i++) {
363             try {
364                 tmp[j] = getMember(names[i]);
365                 j++;
366             } catch (NoSuchMemberException e) {
367                 logger.warn(e);
368             }
369         }
370         MemberItem[] members = new MemberItem[j];
371         System.arraycopy(tmp,0,members,0,j);
372         return members;
373     }
374
375     public Collection JavaDoc getAllMembers() {
376         Collection JavaDoc result = getAllMethods();
377         result.addAll(getAllFields());
378         return result;
379     }
380
381     /**
382      * Returns a FieldItem array.
383      *
384      * @param names the names of the members
385      * @return a FieldItem array fields such as
386      * fields[i].getName().equals(names[i]). If no field with a given
387      * name is found, it is ignored (but a warning is issued).
388      * @see #getField(String) */

389     public FieldItem[] getFields(String JavaDoc[] names) {
390         FieldItem[] tmp = new FieldItem[names.length];
391         int j=0;
392         for(int i=0;i<names.length;i++) {
393             try {
394                 tmp[j] = getField(names[i]);
395                 j++;
396             } catch (NoSuchFieldException JavaDoc e) {
397                 logger.warn(e);
398             }
399         }
400         FieldItem[] fields = new FieldItem[j];
401         System.arraycopy(tmp,0,fields,0,j);
402         return fields;
403     }
404
405
406     /**
407      * Returns a MethodItem array.
408      *
409      * @param names the names of the members
410      * @return a MethodItem array methods such as
411      * methods[i].getName().equals(names[i]). If no method with a given
412      * name is found, it is ignored (but a warning is issued).
413      * @see #getMethod(String)
414      */

415     public MethodItem[] getMethods(String JavaDoc[] names) {
416         MethodItem[] tmp = new MethodItem[names.length];
417         int j=0;
418         for(int i=0;i<names.length;i++) {
419             try {
420                 tmp[j] = getMethod(names[i]);
421                 j++;
422             } catch (NoSuchMethodException JavaDoc e) {
423                 logger.warn(e);
424             }
425         }
426         MethodItem[] methods = new MethodItem[j];
427         System.arraycopy(tmp,0,methods,0,j);
428         return methods;
429     }
430
431     /**
432      * Gets all the primitive fields for this class item.<p>
433      *
434      * @return an array of field items
435      */

436
437     public FieldItem[] getPrimitiveFields() {
438         buildFieldInfo();
439         Collection JavaDoc c = fields.values();
440         FieldItem[] res = new FieldItem[primsCount];
441         Iterator JavaDoc it = c.iterator();
442         int i = 0;
443         while ( it.hasNext() ) {
444             FieldItem field = (FieldItem) it.next();
445             if (field.isPrimitive()) {
446                 res[i] = field;
447                 i++;
448             }
449         }
450         return res;
451     }
452
453     /**
454      * Gets all the references for this class item.<p>
455      *
456      * @return an array of field items
457      */

458
459     public FieldItem[] getReferences() {
460         buildFieldInfo();
461         Collection JavaDoc c = fields.values();
462         FieldItem[] res = new FieldItem[refsCount];
463         Iterator JavaDoc it = c.iterator();
464         int i = 0;
465         while ( it.hasNext() ) {
466             FieldItem field = (FieldItem) it.next();
467             if (field.isReference()) {
468                 res[i] = field;
469                 i++;
470             }
471         }
472         return res;
473     }
474
475     /**
476      * Gets all the references and collections that match the
477      * expression for this class item.<p>
478      *
479      * @return a vector of field items */

480
481     public Collection JavaDoc getMatchingRelations(String JavaDoc expr) {
482         buildFieldInfo();
483         Vector JavaDoc res = new Vector JavaDoc();
484         Collection JavaDoc c = fields.values();
485         Iterator JavaDoc it = c.iterator();
486         RE re;
487         try {
488             re = new RE(expr);
489         } catch (Exception JavaDoc e) {
490             logger.error("getMatchingRelations "+expr,e);
491             return null;
492         }
493         while (it.hasNext()) {
494             FieldItem field = (FieldItem) it.next();
495             if (field.isReference() || (field instanceof CollectionItem)) {
496                 if (re.isMatch(field.getName())) {
497                     res.add( field );
498                 }
499             }
500         }
501         return res;
502     }
503
504     /**
505      * Gets all the collections for this class item.<p>
506      *
507      * @return an array of field items
508      */

509
510     public CollectionItem[] getCollections() {
511         buildFieldInfo();
512         Collection JavaDoc c = fields.values();
513         CollectionItem[] res = new CollectionItem[collsCount];
514         Iterator JavaDoc it = c.iterator();
515         int i = 0;
516         while ( it.hasNext() ) {
517             FieldItem field = (FieldItem) it.next();
518             if (field instanceof CollectionItem) {
519                 res[i] = (CollectionItem)field;
520                 i++;
521             }
522         }
523         return res;
524     }
525
526     /**
527      * Add a field item to this class item. The parent of the field is
528      * set to this.<p>
529      *
530      * @param field the new field
531      */

532     void addField(FieldItem field) {
533         buildFieldInfo();
534         boolean override = fields.containsKey(field.getName());
535         if (override) {
536             logger.warn("Overriding field "+fields.get(field.getName())+
537                         " with "+field);
538         }
539         try {
540             field.setParent(this);
541         } catch(Exception JavaDoc e) {
542             logger.error("addField "+field.getName(),e);
543             return;
544         }
545         fields.put(field.getName(), field);
546         if (field instanceof CollectionItem && !override) {
547             collsCount++;
548         } else if (field.isReference() && !override) {
549             refsCount++;
550         } else if (!override) {
551             primsCount++;
552         }
553     }
554    
555     /**
556      * Gets a set of homonym methods (including constructors) from
557      * their names.<p>
558      *
559      * @param name the name of the methods
560      * @return a <code>MethodItem</code> instance
561      */

562     public AbstractMethodItem[] getAbstractMethods(String JavaDoc name)
563         throws NoSuchMethodException JavaDoc
564     {
565         if (name.startsWith("<init>"))
566             name = getShortName()+name.substring(6);
567         //Log.trace("rtti.method","getAbstractMethods("+name+")");
568
AbstractMethodItem[] res=null;
569         if (name.endsWith(")")) {
570             String JavaDoc name2 = name.substring(0,name.indexOf("("));
571             //Log.trace("rtti.method","name2 : "+name2);
572
AbstractMethodItem[] meths =
573                 (AbstractMethodItem[])methods.get(name2);
574             if (meths!=null) {
575                 for (int i=0; i<meths.length; i++) {
576                     //Log.trace("rtti.method","trying "+meths[i].getFullName());
577
if (meths[i].getFullName().endsWith(name)) {
578                         res = new AbstractMethodItem[] {meths[i]};
579                     }
580                 }
581             }
582         } else {
583             res = (AbstractMethodItem[])methods.get(name);
584         }
585         if (res == null) {
586             throw new NoSuchMethodException JavaDoc(
587                 "ClassItem.getAbstractMethods: no such method "+name+" in "+this);
588         }
589         return res;
590     }
591
592     Hashtable JavaDoc methodCache = new Hashtable JavaDoc();
593
594     /**
595      * Gets an abstract method from its name.
596      *
597      * <p>If this method has homonym(s), then an
598      * <code>AmbiguousMethodNameException</code> is thrown.
599      *
600      * <p>An abstract method can be a static, an instance method or a
601      * constructor.
602      *
603      * @param name the name of the method to search
604      * @return the corresponding method if found
605      * @see #getMethod(String)
606      * @see #getAbstractMethods(String)
607      */

608     public AbstractMethodItem getAbstractMethod(String JavaDoc name)
609         throws NoSuchMethodException JavaDoc, AmbiguousMethodNameException
610     {
611         AbstractMethodItem cachedMethod =
612             (AbstractMethodItem)methodCache.get(name);
613         if (cachedMethod!=null) {
614             return cachedMethod;
615         } else {
616             AbstractMethodItem[] res = getAbstractMethods(name);
617             if (res.length>1) {
618                 throw new NoSuchMethodException JavaDoc("Ambiguous method name "+
619                                                 this+"."+name);
620             }
621             methodCache.put(name,res[0]);
622             return res[0];
623         }
624     }
625
626     /**
627      * Tells wether the class contains a method. All methods of the
628      * class are examined (even the private and protected ones wich
629      * are not regisered as MethodItem)
630      *
631      * @param name name of the searched method
632      * @param paramTypes types of the parameters of the searched method
633      * @see Class#getDeclaredMethod(String,Class[])
634      */

635     public boolean hasMethod(String JavaDoc name, Class JavaDoc[] paramTypes) {
636         try {
637             ((Class JavaDoc)delegate).getDeclaredMethod(name,paramTypes);
638             return true;
639         } catch(java.lang.NoSuchMethodException JavaDoc e) {
640             return false;
641         }
642     }
643
644     /**
645      * Strip the arguments part from a full method name.
646      * aMethod(aType) -> aMethod
647      * aMethod -> aMethod
648      * @param name a method name
649      */

650     static String JavaDoc stripArgs(String JavaDoc name) {
651         int index = name.indexOf("(");
652         if (index!=-1)
653             return name.substring(0,index);
654         else
655             return name;
656     }
657
658     /**
659      * Gets a set of homonym methods (excluding constructors) from
660      * their names.<p>
661      *
662      * @param name the name of the methods
663      * @return a <code>MethodItem</code> instance */

664
665     public MethodItem[] getMethods(String JavaDoc name)
666         throws NoSuchMethodException JavaDoc
667     {
668         MethodItem[] res = null;
669
670         //Log.trace("rtti.method","getMethods("+name+")");
671
if (name.endsWith(")")) {
672             String JavaDoc name2 = name.substring(0,name.indexOf("("));
673             //Log.trace("rtti.method","name2 : "+name2);
674
MethodItem[] meths = (MethodItem[])methods.get(name2);
675             if (meths!=null) {
676                 for (int i=0; i<meths.length; i++) {
677                     //Log.trace("rtti.method","trying "+meths[i].getFullName());
678
if (meths[i].getFullName().endsWith(name)) {
679                         res = new MethodItem[] {meths[i]};
680                     }
681                 }
682             }
683         } else {
684             res = (MethodItem[])methods.get(name);
685         }
686
687         /*ClassItem superClass=getSuperclass();
688      
689           if(res==null && superClass!=null) {
690           res=superClass.getMethods(name);
691           }*/

692
693         if (res == null) {
694             //Log.trace("rtti.method",2,"methods = "+methods);
695
throw new NoSuchMethodException JavaDoc(
696                 "ClassItem.getMethods: no such method "+name+" in class "+this);
697         }
698         return res;
699     }
700
701     /**
702      * Gets a method from its name.
703      *
704      * <p>If this method has homonym(s), then an
705      * <code>AmbiguousMethodNameException</code> is thrown.
706      *
707      * <p>A method can be a static or instance method but not a
708      * constructor.
709      *
710      * @param name the name of the method to search
711      * @return the corresponding method if found
712      * @see #getAbstractMethod(String)
713      * @see #getMethods(String) */

714
715     public MethodItem getMethod(String JavaDoc name)
716         throws NoSuchMethodException JavaDoc, AmbiguousMethodNameException
717     {
718         //Log.trace("rtti.method","getMethod("+name+")");
719
MethodItem[] res= getMethods(name);
720         if (res.length>1) {
721             throw new AmbiguousMethodNameException(
722                 "Ambiguous method name "+this+"."+name+" choice is:"
723                 +java.util.Arrays.asList(res));
724         }
725         return res[0];
726     }
727
728     /**
729      * Gets a set of arrays containing all the method items for this
730      * class item.
731      *
732      * <p>Each arrays contains the methods of the same name.
733      *
734      * @return a collection containing the methods
735      */

736     public Collection JavaDoc getMethods() {
737         Collection JavaDoc c = methods.values();
738         Vector JavaDoc res = new Vector JavaDoc();
739         Iterator JavaDoc it = c.iterator();
740         while (it.hasNext()) {
741             Object JavaDoc[] methods = (Object JavaDoc[]) it.next();
742             if (methods[0] instanceof MethodItem) {
743                 res.add(methods);
744             }
745         }
746         return res;
747     }
748
749     /**
750      * Gets all the method items for this class item.<p>
751      *
752      * @return a collection containing the methods
753      */

754     public Collection JavaDoc getAllMethods() {
755         Collection JavaDoc c = methods.values();
756         Vector JavaDoc res = new Vector JavaDoc();
757         Iterator JavaDoc it = c.iterator();
758         while (it.hasNext()) {
759             Object JavaDoc[] methods = (Object JavaDoc[]) it.next();
760             for (int i=0; i<methods.length; i++) {
761                 if ( methods[i] instanceof MethodItem &&
762                      !ClassRepository.isJacMethod(
763                          ((MethodItem)methods[i]).getName()) ) {
764                     res.add(methods[i]);
765                 }
766             }
767         }
768         return res;
769     }
770
771     /**
772      * Gets all the method items for this class item.<p>
773      *
774      * @return a collection containing the methods
775      */

776     public Collection JavaDoc getMixinMethods() {
777         Collection JavaDoc c = methods.values();
778         Vector JavaDoc res = new Vector JavaDoc();
779         Iterator JavaDoc it = c.iterator();
780         while (it.hasNext()) {
781             Object JavaDoc[] methods = (Object JavaDoc[]) it.next();
782             for (int i=0; i<methods.length; i++) {
783                 if ( methods[i] instanceof MixinMethodItem &&
784                      !ClassRepository.isJacMethod(
785                          ((MethodItem)methods[i]).getName()) ) {
786                     res.add(methods[i]);
787                 }
788             }
789         }
790         return res;
791     }
792
793     /**
794      * @return a collection of static MethodItem
795      */

796     public Collection JavaDoc getAllStaticMethods() {
797         Collection JavaDoc c = methods.values();
798         Vector JavaDoc res = new Vector JavaDoc();
799         Iterator JavaDoc it = c.iterator();
800         while (it.hasNext()) {
801             Object JavaDoc[] methods = (Object JavaDoc[]) it.next();
802             //Log.trace("rtti.static","getStatic checks "+methods[0]);
803
for (int i=0; i<methods.length; i++) {
804                 if ( methods[i] instanceof MethodItem &&
805                      !ClassRepository.isJacMethod(
806                          ((MethodItem)methods[i]).getName()) &&
807                      ((MethodItem)methods[i]).isStatic()) {
808                     //Log.trace("rtti.static","getStatic adds "+methods[0]);
809
res.add(methods[i]);
810                 }
811             }
812         }
813         return res;
814     }
815
816     /**
817      * @return a collection of non static MethodItem
818      */

819     public Collection JavaDoc getAllInstanceMethods() {
820         Collection JavaDoc c = methods.values();
821         Vector JavaDoc res = new Vector JavaDoc();
822         Iterator JavaDoc it = c.iterator();
823         while (it.hasNext()) {
824             Object JavaDoc[] methods = (Object JavaDoc[]) it.next();
825             for (int i=0; i<methods.length; i++) {
826                 if ( methods[i] instanceof MethodItem &&
827                      !ClassRepository.isJacMethod(
828                          ((MethodItem)methods[i]).getName()) &&
829                      !((MethodItem)methods[i]).isStatic()) {
830                     res.add(methods[i]);
831                 }
832             }
833         }
834         return res;
835     }
836
837     /**
838      * Gets all the method items that modify the state of the instances
839      * for this class item.
840      *
841      * @return a collection of MethodItem containing the modifiers
842      */

843     public Collection JavaDoc getAllModifiers() {
844         Iterator JavaDoc it = getAllMethods().iterator();
845         Vector JavaDoc modifiers = new Vector JavaDoc();
846         while(it.hasNext()) {
847             MethodItem method = (MethodItem)it.next();
848             if (method.isModifier()) {
849                 modifiers.add(method);
850             }
851         }
852         return modifiers;
853     }
854
855
856     /**
857      * Gets all the method items that modify the state of the instances
858      * for this class item.
859      *
860      * @return a collection of MethodItem containing the modifiers
861      */

862     public Collection JavaDoc getAllSetters() {
863         Iterator JavaDoc it = getAllMethods().iterator();
864         Vector JavaDoc modifiers = new Vector JavaDoc();
865         while(it.hasNext()) {
866             MethodItem method = (MethodItem)it.next();
867             if (method.isSetter()) {
868                 modifiers.add(method);
869             }
870         }
871         return modifiers;
872     }
873
874     /**
875      * Gets all the method items that modify a field of the instances
876      * for this class item.
877      *
878      * @return a collection of MethodItem containing the writers
879      */

880     public Collection JavaDoc getAllWriters() {
881         Iterator JavaDoc it = getAllMethods().iterator();
882         Vector JavaDoc modifiers = new Vector JavaDoc();
883         while(it.hasNext()) {
884             MethodItem method = (MethodItem)it.next();
885             if (method.hasWrittenFields()) {
886                 modifiers.add(method);
887             }
888         }
889         return modifiers;
890     }
891
892     /**
893      * Gets all the getter methods of the class.
894      *
895      * @return a collection containing the getters
896      * @see MethodItem#isGetter()
897      */

898     public Collection JavaDoc getAllGetters() {
899         Vector JavaDoc modifiers = new Vector JavaDoc();
900         Iterator JavaDoc it = getAllMethods().iterator();
901         while(it.hasNext()) {
902             MethodItem method = (MethodItem)it.next();
903             if (method.isGetter()) {
904                 modifiers.add(method);
905             }
906         }
907         return modifiers;
908     }
909
910     /**
911      * Gets all the method items that access the state of the instances
912      * for this class item.
913      *
914      * @return a collection containing the accessors
915      */

916     public Collection JavaDoc getAllAccessors() {
917         Vector JavaDoc accessors = new Vector JavaDoc();
918         Iterator JavaDoc it = getAllMethods().iterator();
919         while(it.hasNext()) {
920             MethodItem method = (MethodItem)it.next();
921             if (method.isAccessor()) {
922                 accessors.add(method);
923             }
924         }
925         return accessors;
926     }
927
928
929     /**
930      * Gets all the method items that removes an object from a
931      * collection of this class item.
932      *
933      * @return a collection containing the modifiers
934      */

935     public Collection JavaDoc getAllRemovers() {
936         Vector JavaDoc removers = new Vector JavaDoc();
937         Iterator JavaDoc it = getAllMethods().iterator();
938         while(it.hasNext()) {
939             MethodItem method = (MethodItem)it.next();
940             if (method.isRemover()) {
941                 removers.add(method);
942             }
943         }
944         return removers;
945     }
946
947     /**
948      * Gets all the method items that adds an object from a
949      * collection of this class item.
950      *
951      * @return a collection containing the modifiers
952      */

953     public Collection JavaDoc getAllAdders() {
954         Collection JavaDoc methods = getAllMethods();
955         Iterator JavaDoc it = methods.iterator();
956         Vector JavaDoc adders = new Vector JavaDoc();
957
958         while(it.hasNext()) {
959             MethodItem method = (MethodItem)it.next();
960             if (method.getAddedCollections() != null &&
961                 method.getAddedCollections().length>0) {
962                 adders.add(method);
963             }
964         }
965         return adders;
966     }
967
968     /**
969      * Gets all the constructors items for this class item.<p>
970      *
971      * @return a collection containing the constructors
972      */

973     public Collection JavaDoc getConstructors() {
974         Collection JavaDoc c = methods.values();
975         Vector JavaDoc res = new Vector JavaDoc();
976         Iterator JavaDoc it = c.iterator();
977         while ( it.hasNext() ) {
978             Object JavaDoc[] methods = (Object JavaDoc[]) it.next();
979             //Log.trace("rtti.constructor","checking "+methods[0]);
980
if (methods[0] instanceof ConstructorItem) {
981                 //Log.trace("rtti.constructor","adding "+methods[0]);
982
res.addAll(java.util.Arrays.asList(methods));
983             }
984         }
985         return res;
986     }
987
988     public ConstructorItem getConstructor(Class JavaDoc[] parameterTypes)
989         throws NoSuchMethodException JavaDoc
990     {
991         Iterator JavaDoc i = getConstructors().iterator();
992         while (i.hasNext()) {
993             ConstructorItem constructor = (ConstructorItem)i.next();
994             if (java.util.Arrays.equals(constructor.getParameterTypes(),
995                                         parameterTypes)) {
996                 return constructor;
997             }
998         }
999         return null;
1000    }
1001
1002    /**
1003     * Get a constructor with given parameter types
1004     * @param parameterTypes the types of the constructor
1005     * parameters. For instance "(java.lang.Object,java.lang.String)".
1006     */

1007    public ConstructorItem getConstructor(String JavaDoc parameterTypes) {
1008        return (ConstructorItem)getAbstractMethod(getShortName()+parameterTypes);
1009    }
1010
1011    /**
1012     * Gets the constructor item of this class item that matches the
1013     * given <code>java.lang.reflect.Constructor</code>.
1014     *
1015     * @return the corresponding constructor item
1016     */

1017    public ConstructorItem getConstructor(Constructor JavaDoc constructor) {
1018        //Log.trace("rtti","getConstructor("+constructor+")");
1019
Collection JavaDoc constructors = getConstructors();
1020        Iterator JavaDoc it = constructors.iterator();
1021        while ( it.hasNext() ) {
1022            ConstructorItem[] current = (ConstructorItem[])it.next();
1023            for (int i=0; i<current.length; i++) {
1024                //Log.trace("rtti","compare with "+current[i]);
1025
if (current[i].getActualConstructor().toString().equals(constructor.toString())) {
1026                    return current[i];
1027                }
1028            }
1029        }
1030        return null;
1031    }
1032
1033    /**
1034     * Creates a new instance of this class item by using the default
1035     * constructor (the one with no parameters).
1036     *
1037     * @return the newly created instance */

1038
1039    public Object JavaDoc newInstance()
1040        throws InstantiationException JavaDoc, IllegalAccessException JavaDoc {
1041        return getActualClass().newInstance();
1042    }
1043
1044    /**
1045     * Creates a new instance of this class item by using the
1046     * constructor that matches the given parameter types.
1047     *
1048     * @param types the types of the constructor arguments
1049     * @param values the arguments values
1050     * @return the newly created instance */

1051
1052    public Object JavaDoc newInstance(Class JavaDoc[] types,Object JavaDoc[] values)
1053        throws InstantiationException JavaDoc, IllegalAccessException JavaDoc,
1054        java.lang.NoSuchMethodException JavaDoc, InvocationTargetException JavaDoc {
1055        Constructor JavaDoc c = getActualClass().getConstructor(types);
1056        return c.newInstance(values);
1057    }
1058
1059    /**
1060     * Create a new instance of the class, using the first constructor
1061     * suitable for the given parameters.
1062     *
1063     * @param parameters parameters of the constructor */

1064    public Object JavaDoc newInstance(Object JavaDoc[] parameters)
1065        throws InstantiationException JavaDoc, IllegalAccessException JavaDoc,
1066        java.lang.NoSuchMethodException JavaDoc, InvocationTargetException JavaDoc
1067    {
1068        Iterator JavaDoc i = getConstructors().iterator();
1069        ConstructorItem constructor = null;
1070        while (i.hasNext()) {
1071            constructor = (ConstructorItem)i.next();
1072            Class JavaDoc[] parameterTypes = constructor.getParameterTypes();
1073            if (parameterTypes.length==parameters.length) {
1074                int j;
1075                for (j=0; j<parameters.length; j++) {
1076                    // WARNING: this test does not work for primitive typed
1077
// parameters
1078
if (!parameterTypes[j]
1079                        .isAssignableFrom(parameters[j].getClass())) {
1080                        break;
1081                    }
1082                }
1083                if (j==parameters.length) {
1084                    return constructor.newInstance(parameters);
1085                }
1086            }
1087        }
1088        throw new InstantiationException JavaDoc(
1089            "Could not find a suitable constructor for class "+getName()+
1090            " with arguments "+java.util.Arrays.asList(parameters));
1091    }
1092
1093    /**
1094     * Gets the class represented by this class item.<p>
1095     *
1096     * @return the actual class
1097     * @see #getType()
1098     */

1099
1100    public Class JavaDoc getActualClass() {
1101        return (Class JavaDoc)delegate;
1102    }
1103
1104    ClassItem[] interfaceItems = null;
1105    /**
1106     * Returns the interfaces implemented by this class.
1107     */

1108    public ClassItem[] getInterfaceItems() {
1109        if (interfaceItems==null) {
1110            Class JavaDoc[] interfaces = getActualClass().getInterfaces();
1111            interfaceItems = new ClassItem[interfaces.length];
1112            ClassRepository cr = ClassRepository.get();
1113            for (int i=0; i<interfaces.length; i++) {
1114                interfaceItems[i] = cr.getClass(interfaces[i]);
1115            }
1116        }
1117        return interfaceItems;
1118    }
1119
1120    /** the super class */
1121    ClassItem superClass;
1122
1123    /**
1124     * Set the super class of this class and updates the children of
1125     * the super class.
1126     * @param superClass the super class
1127     */

1128    protected void setSuperClass(ClassItem superClass) {
1129        this.superClass = superClass;
1130        superClass.addChild(this);
1131    }
1132
1133    /**
1134     * Gets the superclass of this class item.<p>
1135     *
1136     * @return the superclass, null if the superclass is Object
1137     */

1138    public ClassItem getSuperclass() {
1139        return superClass;
1140    }
1141
1142    /** A list of ClassItem whose super class is this class */
1143    Vector JavaDoc children = new Vector JavaDoc();
1144
1145    public Collection JavaDoc getChildren() {
1146        return children;
1147    }
1148
1149    public void addChild(ClassItem child) {
1150        children.add(child);
1151    }
1152
1153    /**
1154     * Tells wether the class inherits from a subclass whose name
1155     * matches a regular expression.
1156     * @param classNameRE the regular expression
1157     */

1158    public boolean isSubClassOf(RE classNameRE) {
1159        if (classNameRE.isMatch(getName())) {
1160            return true;
1161        } else if (superClass!=null) {
1162            return superClass.isSubClassOf(classNameRE);
1163        } else {
1164            ClassItem[] interfaces = getInterfaceItems();
1165            for (int i=0; i<interfaces.length; i++) {
1166                if (interfaces[i].isSubClassOf(classNameRE))
1167                    return true;
1168            }
1169            return false;
1170        }
1171    }
1172
1173    /**
1174     * Tells wether the class inherits from a subclass
1175     *
1176     * @param cl the regular expression
1177     */

1178    public boolean isSubClassOf(ClassItem cl) {
1179        if (cl==this) {
1180            return true;
1181        } else if (superClass!=null) {
1182            return superClass.isSubClassOf(cl);
1183        } else {
1184            ClassItem[] interfaces = getInterfaceItems();
1185            for (int i=0; i<interfaces.length; i++) {
1186                if (interfaces[i].isSubClassOf(cl))
1187                    return true;
1188            }
1189            return false;
1190        }
1191    }
1192
1193    public int getModifiers() {
1194        return ((Class JavaDoc)delegate).getModifiers();
1195    }
1196
1197    /**
1198     * Synonym of <code>getActualClass</code>.
1199     *
1200     * @return the actual class
1201     * @see #getActualClass()
1202     */

1203
1204    public Class JavaDoc getType() {
1205        return getActualClass();
1206    }
1207
1208    /**
1209     * Add a method item to this class item.
1210     *
1211     * @param method the new method
1212     */

1213    public void addMethod(MethodItem method) {
1214        String JavaDoc name = method.getName();
1215        //Log.trace("rtti.method","addMethod: "+name+" -> "+getName()+"."+method);
1216
if (!methods.containsKey(name)) {
1217            methods.put(name, new MethodItem[] { method } );
1218        } else {
1219            MethodItem[] meths = (MethodItem[])methods.get(name);
1220            MethodItem[] newMeths = new MethodItem[meths.length + 1];
1221            System.arraycopy(meths, 0, newMeths, 0, meths.length);
1222            newMeths[meths.length] = method;
1223            methods.remove(name);
1224            methods.put(name, newMeths);
1225        }
1226        methodsCount++;
1227        if (method instanceof MixinMethodItem) {
1228            Iterator JavaDoc i = children.iterator();
1229            while (i.hasNext()) {
1230                ClassItem subclass = (ClassItem)i.next();
1231                subclass.addMethod(method);
1232            }
1233        }
1234        try {
1235            method.setParent(this);
1236        } catch(Exception JavaDoc e) {
1237            logger.error("addMethod "+method.getFullName()+
1238                         ": could not set the parent of the method",e);
1239        }
1240    }
1241
1242    Vector JavaDoc mixinMethods = new Vector JavaDoc();
1243
1244    /**
1245     * Add a constructor item to this class item.<p>
1246     *
1247     * @param constructor the new constructor
1248     */

1249    public void addConstructor(ConstructorItem constructor) {
1250        String JavaDoc name = NamingConventions.getShortConstructorName(constructor.getActualConstructor());
1251        //Log.trace("rtti.method","addConstructor: "+name+" -> "+constructor);
1252
if ( ! methods.containsKey( name )) {
1253            methods.put( name, new ConstructorItem[] { constructor } );
1254        } else {
1255            ConstructorItem[] constructors =
1256                (ConstructorItem[]) methods.get( name );
1257            ConstructorItem[] newConstructors =
1258                new ConstructorItem[constructors.length + 1];
1259            System.arraycopy(constructors, 0, newConstructors, 0, constructors.length);
1260            newConstructors[constructors.length] = constructor;
1261            methods.remove(constructor.getName());
1262            methods.put(name, newConstructors);
1263        }
1264        constructorsCount++;
1265        try {
1266            constructor.setParent(this);
1267        } catch( Exception JavaDoc e ) {
1268            logger.error("addConstructor "+constructor.getFullName(),e);
1269        }
1270    }
1271   
1272    /**
1273     * Tests if a method exist in this class item.<p>
1274     *
1275     * @return true if exist
1276     */

1277    public boolean hasMethod(String JavaDoc name) {
1278        try {
1279            getAbstractMethod(name);
1280            return true;
1281        } catch (NoSuchMethodException JavaDoc e) {
1282            return false;
1283        } catch (AmbiguousMethodNameException e) {
1284            return true;
1285        }
1286    }
1287
1288    public boolean hasMethod(MethodItem method) {
1289        return method.parent==this;
1290    }
1291
1292    /**
1293     * Tests if a field exist in this class item.<p>
1294     *
1295     * @return true if exist
1296     */

1297
1298    public boolean hasField( String JavaDoc name ) {
1299        buildFieldInfo();
1300        return (name!=null) && fields.containsKey( name );
1301    }
1302
1303    public String JavaDoc getName() {
1304        return ((Class JavaDoc)delegate).getName();
1305    }
1306
1307    public String JavaDoc getShortName() {
1308        String JavaDoc name = getName();
1309        int index = name.lastIndexOf('.');
1310        return index==-1 ? name : name.substring(index+1);
1311    }
1312
1313    /**
1314     * A shortcut to invoke a method (avoid to get the method item).
1315     *
1316     * @param object the object to perform the invocation on (may be
1317     * null for a static method)
1318     * @param methodName the name of the method to invoke
1319     * @param parameters the parameters passed to the method
1320     * @see MethodItem#invoke(Object,Object[]) */

1321
1322    public Object JavaDoc invoke(Object JavaDoc object, String JavaDoc methodName, Object JavaDoc[] parameters)
1323        throws IllegalAccessException JavaDoc, InvocationTargetException JavaDoc
1324    {
1325        return getMethod(methodName).invoke(object, parameters);
1326    }
1327
1328    /**
1329     * Tells wether this class is an inner class of some other class
1330     *
1331     * @return true if the class is an inner class
1332     */

1333    public boolean isInner() {
1334        return getName().indexOf('$')!=-1;
1335    }
1336
1337    public boolean isAbstract() {
1338        return Modifier.isAbstract(getModifiers());
1339    }
1340
1341    /**
1342     * Gets the class this class is an inner class of.
1343     *
1344     * @return the ClassItem this class is an inner class of, or null.
1345     */

1346    public ClassItem getOwnerClassItem() {
1347        int index = getName().indexOf('$');
1348        if (index==-1) {
1349            return null;
1350        } else {
1351            return ClassRepository.get().getClass(getName().substring(0,index));
1352        }
1353    }
1354
1355    /**
1356     * Finds the collection of this class item that contains the given
1357     * object.
1358     *
1359     * @param substance the instance of the current class item to seek
1360     * in
1361     * @param object the object to find
1362     * @return the collection item, null if not found */

1363
1364    public CollectionItem findCollectionFor(Object JavaDoc substance,Object JavaDoc object) {
1365        CollectionItem[] collections=getCollections();
1366        for(int i=0;i<collections.length;i++) {
1367            Collection JavaDoc cur=collections[i].getActualCollection(substance);
1368            if(cur.contains(object)) {
1369                return collections[i];
1370            }
1371        }
1372        return null;
1373    }
1374
1375    /**
1376     * Get an attribute by searching recursively through all super classes.
1377     */

1378    public Object JavaDoc getAttribute(String JavaDoc name) {
1379        ClassItem cur = this;
1380        Object JavaDoc result = null;
1381        while (cur!=null && result==null) {
1382            result = cur.superGetAttribute(name);
1383            cur = cur.getSuperclass();
1384        }
1385        return result;
1386    }
1387
1388    public Object JavaDoc superGetAttribute(String JavaDoc name) {
1389        return super.getAttribute(name);
1390    }
1391
1392    Vector JavaDoc constraints;
1393    /**
1394     * Return all field and collection items whose component type is
1395     * this class.
1396     * @return a collection of FieldItem
1397     */

1398    public Collection JavaDoc getConstraints() {
1399        if (constraints==null) {
1400            constraints = new Vector JavaDoc();
1401            Object JavaDoc[] classes = ClassRepository.get().getClasses();
1402            for (int i=0; i<classes.length;i++) {
1403                if (classes[i] instanceof ClassItem) {
1404                    ClassItem cl = (ClassItem)classes[i];
1405                    FieldItem[] fields = cl.getFields();
1406                    for (int j=0; j<fields.length; j++) {
1407                        if (fields[j] instanceof CollectionItem) {
1408                            if (((CollectionItem)fields[j]).getComponentType()==this)
1409                                constraints.add(fields[j]);
1410                        } else if (fields[j].getTypeItem()==this) {
1411                            constraints.add(fields[j]);
1412                        }
1413                    }
1414                }
1415            }
1416        }
1417        return constraints;
1418    }
1419
1420    /**
1421     * The exception that is thrown when the accessed method has some
1422     * synonymes (methods with same names but different parameter
1423     * types). */

1424    public static class AmbiguousMethodNameException extends RuntimeException JavaDoc {
1425        public AmbiguousMethodNameException(String JavaDoc msg) { super(msg); }
1426        public AmbiguousMethodNameException() { super(); }
1427    }
1428}
1429
Popular Tags