001: /*
002: * ClassTable.java - part of the CodeAid plugin.
003: * Copyright (C) 1999 Jason Ginchereau
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * as published by the Free Software Foundation; either version 2
008: * of the License, or any later version.
009: *
010: * This program is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: * GNU General Public License for more details.
014: *
015: * You should have received a copy of the GNU General Public License
016: * along with this program; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
018: */
019: package org.acm.seguin.completer.info;
020:
021: // Collections API
022: import org.acm.seguin.completer.*;
023: import java.util.StringTokenizer; //import anthelper.ClassNameCache;
024: import org.acm.seguin.ide.jedit.Navigator.NavigatorLogger;
025: import org.acm.seguin.completer.Completer;
026: import gnu.regexp.RE;
027: import java.io.EOFException;
028: import java.io.IOException;
029: import java.io.ObjectInputStream;
030: import java.io.ObjectOutputStream;
031: import java.lang.reflect.Modifier;
032: import java.net.URL;
033: import java.net.URLClassLoader;
034: import java.util.ArrayList;
035: import java.util.Collection;
036: import java.util.Enumeration;
037: import java.util.HashMap;
038: import java.util.HashSet;
039: import java.util.Iterator;
040: import java.util.LinkedList;
041: import java.util.List;
042: import java.util.Map;
043: import java.util.Set;
044: import java.util.SortedMap;
045: import java.util.TreeMap;
046: import java.util.TreeSet;
047: import java.util.zip.ZipEntry;
048: import java.util.zip.ZipFile;
049: import java.util.zip.ZipInputStream;
050: import java.util.zip.ZipOutputStream;
051:
052: /**
053: * Maps class names to information that is known about those classes.
054: * Information about each class is stored in a <code>ClassInfo</code> object.
055: * All methods are thread-safe.
056: *
057: * @author Jason Ginchereau
058: * @created December 12, 2002
059: * @see ClassInfo
060: */
061: public final class ClassTable implements java.io.Serializable {
062: /**
063: * Description of the Field
064: */
065: public final static String UNNAMED_PACKAGE = "<unnamed package>";
066:
067: private static Map staticInstanceTable = new HashMap();
068: private final static Object DEFAULT_KEY = new String();
069:
070: final static NavigatorLogger logger = Completer
071: .getLogger(ClassTable.class);
072: final static boolean DEBUG = true;
073:
074: /**
075: * Gets a static instance of a <code>ClassTable</code> that can be shared by
076: * everyone with the same key.
077: *
078: * @param key Description of the Parameter
079: * @return The instance value
080: */
081: private static synchronized ClassTable getInstance(Object key) {
082: ClassTable instance = (ClassTable) staticInstanceTable.get(key);
083: if (instance == null) {
084: instance = new ClassTable();
085: staticInstanceTable.put(key, instance);
086: }
087: return instance;
088: }
089:
090: /**
091: * Gets the existingInstance attribute of the ClassTable class
092: *
093: * @param argSource the class path src
094: * @return The existingInstance value
095: */
096: public static synchronized ClassTable getExistingInstance(
097: ClassPathSrc argSource) {
098: return (ClassTable) staticInstanceTable.get(argSource.getKey());
099: }
100:
101: /**
102: * Remove the instance
103: *
104: * @param argSource the class path src
105: * @return The existingInstance value
106: */
107: public static synchronized ClassTable removeInstance(
108: ClassPathSrc argSource) {
109: ClassTable ct = (ClassTable) staticInstanceTable
110: .remove(argSource.getKey());
111: //printAll();
112: return ct;
113: }
114:
115: /**
116: * Gets a static instance of a <code>ClassTable</code> that can be shared by
117: * everyone with the same key.
118: *
119: * @param argSource the class path src
120: * @return The instance value
121: */
122: public static synchronized ClassTable getInstance(
123: ClassPathSrc argSource) {
124: ClassTable instance = (ClassTable) staticInstanceTable
125: .get(argSource.getKey());
126: if (instance == null) {
127: ClassNameCache cnc = argSource.getCNC();
128: // this will be a very verbose message...but helpful
129: //logger.debug("** Creating ClassTable for ClassNameCache: ", cnc.toString());
130: instance = new ClassTable(getInstance(), cnc
131: .getAllClassInfos(), createClassLoader(cnc));
132: staticInstanceTable.put(argSource.getKey(), instance);
133: }
134: //printAll();
135: return instance;
136: }
137:
138: static void printAll() {
139: Object objKey;
140: Object objVal;
141: ClassNameCache cnc = null;
142: for (Iterator it = staticInstanceTable.keySet().iterator(); it
143: .hasNext();) {
144: objKey = it.next();
145: objVal = staticInstanceTable.get(objKey);
146: if (objKey instanceof ClassNameCache) {
147: cnc = (ClassNameCache) objKey;
148: logger.debug("cnc=" + cnc.getName(), "ct="
149: + objVal.hashCode());
150: } else {
151: logger.debug("cnc=" + objKey.toString(), "ct="
152: + objVal.hashCode());
153: }
154:
155: }
156: }
157:
158: private static ClassLoader createClassLoader(ClassNameCache argCNC) {
159: // 1 arg cons will make system class loader parent
160: // which do we want?
161: URLClassLoader classLoader = new URLClassLoader(argCNC
162: .getClassPathAsURLs(), Completer.class.getClassLoader());
163: return classLoader;
164: }
165:
166: /**
167: * Gets a static instance of a <code>ClassTable</code> using the default
168: * key.
169: *
170: * @return The instance value
171: */
172: public static ClassTable getInstance() {
173: return getInstance(DEFAULT_KEY);
174: }
175:
176: private transient ClassTable parent;
177: private transient SortedMap arrays;
178: private SortedMap packages;
179: private SortedMap classes;
180: private ClassLoader _classLoader = null;
181:
182: /**
183: * Creates a new <code>ClassTable</code>.
184: */
185: public ClassTable() {
186: // by default, use
187: this (null, ClassNameCache.getBootClassList(), Completer.class
188: .getClassLoader());
189:
190: }
191:
192: /**
193: * Creates a new <code>ClassTable</code> which will delegate to a parent
194: * <code>ClassTable</code> for unrecognized classes.
195: *
196: * @param argParent Description of the Parameter
197: * @param argListCNCClassInfos Description of the Parameter
198: * @param argClassLoader Description of the Parameter
199: */
200:
201: /**
202: * Constructor for the ClassTable object
203: *
204: * @param argParent Description of the Parameter
205: * @param argListCNCClassInfos Description of the Parameter
206: * @param argClassLoader Description of the Parameter
207: */
208: public ClassTable(ClassTable argParent, List argListCNCClassInfos,
209: ClassLoader argClassLoader) {
210: this .parent = argParent;
211: arrays = new TreeMap(new StringComparator());
212: packages = new TreeMap(new StringComparator());
213: classes = new TreeMap(new StringComparator());
214: // load all classes
215: init(argListCNCClassInfos, argClassLoader);
216: }
217:
218: /**
219: * Description of the Method
220: *
221: * @param argCNC Description of the Parameter
222: */
223: public synchronized void reinit(ClassPathSrc argSource) {
224: ClassNameCache cnc = argSource.getCNC();
225: List listAll = cnc.getAllClassInfos();
226: logger.msg("reinit", listAll.size());
227: arrays.clear();
228: packages.clear();
229: classes.clear();
230: init(listAll, createClassLoader(cnc));
231: }
232:
233: private void init(List argListCNCClassInfos,
234: ClassLoader argClassLoader) {
235: preLoad(argListCNCClassInfos);
236: _classLoader = argClassLoader;
237:
238: }
239:
240: /**
241: * Gets the parent <code>ClassTable</code>, which is be queried for classes
242: * that are not recognized by this <code>ClassTable</code>.
243: *
244: * @return The parent value
245: */
246: public ClassTable getParent() {
247: return parent;
248: }
249:
250: /**
251: * Sets the parent <code>ClassTable</code>, which will be queried for
252: * classes that are not recognized by this <code>ClassTable</code>.
253: *
254: * @param parent The new parent value
255: */
256: public synchronized void setParent(ClassTable parent) {
257: this .parent = parent;
258: }
259:
260: /**
261: * Gets a list of all packages in the database.
262: *
263: * @return a sorted <code>List</code> of <code>Strings</code>, where each
264: * <code>String</code> is a name of a package in the database. This
265: * <code>List</code> may be safely modified by the user, as it is no
266: * longer connected to the database after it is returned.
267: */
268: public synchronized List getPackages() {
269: return new LinkedList(packages.keySet());
270: }
271:
272: /**
273: * Gets a list of all known classes in a package.
274: *
275: * @param packageName the name of the package, using the java . notation.
276: * @return a sorted <code>List</code> of <code>String</code>
277: * names, or <code>null</code> if the package is unknown. This <code>List</code>
278: * may be safely modified by the user, as it is no longer connected to
279: * the database after it is returned.
280: */
281: public synchronized List getClassesInPackage(String packageName) {
282: Map pmap = (Map) packages.get(packageName);
283: if (pmap != null) {
284: return new LinkedList(pmap.keySet());
285: } else if (parent != null) {
286: return parent.getClassesInPackage(packageName);
287: } else {
288: return null;
289: }
290: }
291:
292: /**
293: * Returns a list of all classes in the given package. Items in this list
294: * may not have been fully loaded into the class table yet. The list
295: * contains _full_ class names
296: *
297: * @param argPackage The package name (java.util) or (java.util.*)
298: * @return The allClassesInPackage value
299: */
300: public synchronized List getAllClassesInPackage(String argPackage) {
301: List listClasses = new ArrayList();
302: String strPkg = argPackage;
303: if (strPkg.endsWith(".*")) {
304: strPkg = strPkg.substring(0, strPkg.length() - 2);
305: }
306: String strFullName;
307: for (Iterator it = classes.keySet().iterator(); it.hasNext();) {
308: strFullName = it.next().toString();
309: if (strFullName.startsWith(strPkg)
310: && strFullName.indexOf(".", strPkg.length() + 1) == -1) {
311: listClasses.add(strFullName);
312: }
313: }
314: if (parent != null) {
315: listClasses.addAll(parent.getAllClassesInPackage(strPkg));
316: }
317: return listClasses;
318: }
319:
320: int _iLastClassCount = -1;
321: Set _setClassNames = null;
322: String _strExclusionRE = null;
323:
324: /**
325: * Returns a set of all class names in this table except classes whose full
326: * names match the given regexp.
327: *
328: * @param argExclusionRE a regexp
329: * @return The allClassNames valuere
330: */
331: public synchronized Set getAllClassNames(String argExclusionRE) {
332:
333: if (_setClassNames == null
334: || _setClassNames.size() != _iLastClassCount
335: || !argExclusionRE.equals(_strExclusionRE)) {
336:
337: RE reExclude = null;
338: try {
339: reExclude = new RE(argExclusionRE);
340: } catch (Exception e) {
341: logger
342: .error("Error filtering on: " + argExclusionRE,
343: e);
344: }
345: _setClassNames = new HashSet();
346:
347: logger.msg("Creating new class list with RE",
348: argExclusionRE);
349: if (reExclude == null) {
350: // reexp failed...return all
351: for (Iterator it = classes.keySet().iterator(); it
352: .hasNext();) {
353: _setClassNames.add(it.next().toString());
354: }
355: } else {
356: String strCN;
357: for (Iterator it = classes.keySet().iterator(); it
358: .hasNext();) {
359: strCN = it.next().toString();
360: if (!reExclude.isMatch(strCN)) {
361: _setClassNames.add(strCN);
362: }
363: }
364:
365: }
366: if (parent != null) {
367: // get parent's classes
368: _setClassNames.addAll(this .parent
369: .getAllClassNames(argExclusionRE));
370: }
371: _iLastClassCount = _setClassNames.size();
372: _strExclusionRE = argExclusionRE;
373: }
374: return _setClassNames;
375: }
376:
377: /**
378: * The main program for the ClassTable class
379: *
380: * @param args The command line arguments
381: */
382: public static void main(String[] args) {
383: try {
384:
385: ClassTable ct = new ClassTable();
386: //ClassNameCache cnc = new ClassNameCache(System.getProperty("sun.boot.class.path"));
387:
388: } catch (Throwable t) {
389: t.printStackTrace();
390: }
391: }
392:
393: static void oldTest() {
394: try {
395: /*
396: * ClassTable ct = new ClassTable();
397: * List list = ct.getAllClassesInPackage("java.util.*");
398: * for (Iterator it = list.iterator(); it.hasNext(); ) {
399: * logger.msg(it.next().toString());
400: * }
401: */
402: ClassTable ct = new ClassTable();
403: Set setClasses = null;
404: for (int i = 0; i < 1; i++) {
405: long lStart = System.currentTimeMillis();
406: setClasses = ct
407: .getAllClassNames("^sun\\..*|^COM\\.rsa\\..*|^com\\.sun\\..*|^org\\.omg\\.CORBA\\..*");
408: logger.msg("time(ms)", ""
409: + (System.currentTimeMillis() - lStart));
410: }
411: int iMax = 0;
412: String str = null;
413: ArrayList listMaxes = new ArrayList();
414: for (Iterator it = setClasses.iterator(); it.hasNext();) {
415: str = it.next().toString();
416: //if (str.length() > iMax){
417: if (str.length() > 40) {
418: iMax = str.length();
419: listMaxes.add(str);
420: }
421: }
422: logger.msg("max size", iMax);
423: String strCN = null;
424: String strPkg = null;
425: String strFN = null;
426: for (Iterator it = listMaxes.iterator(); it.hasNext();) {
427: strFN = it.next().toString();
428: strPkg = strFN.substring(0, strFN.lastIndexOf(".") + 1);
429: if (strPkg.endsWith(".")) {
430: //strPkg = strPkg.substring(0, strPkg.length() - 1);
431: }
432: StringTokenizer st = new StringTokenizer(strPkg, ".");
433: int iN = st.countTokens();
434: if (iN <= 2) {
435: // skip stuff liek java.util.Vector
436: } else {
437: // remove parts, 3-> N-1
438: StringBuffer sbPkg = new StringBuffer();
439: sbPkg.append(st.nextToken()).append(".");
440: sbPkg.append(st.nextToken()).append(".");
441: for (; st.hasMoreTokens(); st.nextToken()) {
442: if (st.hasMoreTokens()) {
443: sbPkg.append("~");
444: } else {
445: sbPkg.append(".");
446: }
447: }
448: strPkg = sbPkg.toString();
449: }
450: strCN = strFN.substring(strFN.lastIndexOf(".") + 1);
451: logger.msg(strPkg + strCN);
452: }
453: int iSize = setClasses.size();
454: logger.msg("size", iSize);
455: int i = 0;
456: /*
457: * for (Iterator it = setClasses.iterator();
458: * i < 10 && it.hasNext(); i++) {
459: * logger.msg(it.next().toString());
460: * }
461: */
462: } catch (Throwable t) {
463: t.printStackTrace();
464: }
465: }
466:
467: /**
468: * Gets information about a class, given a class name.
469: *
470: * @param fullClassName a fully-qualified class name. Note that for inner
471: * classes, the <code>$</code> notation is used in the class name.
472: * Example: <code>java.lang.Character$Subset</code>
473: * @return the <code>ClassInfo</code> object for the class, or
474: * <code>null</code> if the class is not in the database.
475: */
476: public synchronized ClassInfo get(String fullClassName) {
477: if (fullClassName.endsWith("[]")) {
478: ClassInfo aci = (ClassInfo) arrays.get(fullClassName);
479:
480: if (aci == null) {
481: String originalName = fullClassName;
482: int dimensions = 0;
483: do {
484: fullClassName = fullClassName.substring(0,
485: fullClassName.length() - 2);
486: dimensions++;
487: } while (fullClassName.endsWith("[]"));
488:
489: ClassInfo ci = get(fullClassName);
490: if (ci != null) {
491: aci = new ArrayClassInfo(ci, dimensions);
492: arrays.put(originalName, aci);
493: }
494: }
495: return aci;
496: } else {
497: ClassInfo ci = getAndLazyLoad(fullClassName);
498: if (ci == null && parent != null) {
499: // try parent
500: return parent.get(fullClassName);
501: } else {
502: return ci;
503: }
504:
505: /*
506: * OLD code
507: * Object o = classes.get(fullClassName);
508: * /logger.msg("[" + fullClassName + "] o is a ", o == null ? "null" : o.getClass().getName());
509: * if (o instanceof ClassNameCache.ClassInfo) {
510: * ClassNameCache.ClassInfo ci = (ClassNameCache.ClassInfo) o;
511: * logger.debug("Loading class" + ci.getClassName());
512: * load(fullClassName);
513: * o = classes.get(fullClassName);
514: * if (o instanceof ClassNameCache.ClassInfo) {
515: * logger.debug("ClassInfo could not be created for (" + ci.getClassName() +
516: * ") found in (" + ci.getSrc() + ")");
517: * }
518: * }
519: * /logger.msg("now, o is a", o.getClass().getName());
520: * if (o != null && o instanceof ClassInfo) {
521: * return (ClassInfo) o;
522: * } else if (parent != null) {
523: * return parent.get(fullClassName);
524: * } else {
525: * return null;
526: * }
527: */
528: }
529: }
530:
531: /**
532: * Attempts to get the ClassInfo object for the given class name. This
533: * method does the lazy loading that will convert a ClassNameCache.ClassInfo
534: * into ClassInfo. If not ClassInfo can be loaded, null is returned.
535: *
536: * @param argFullClassName Description of the Parameter
537: * @return The andLazyLoad value
538: */
539: public ClassInfo getAndLazyLoad(String argFullClassName) {
540: ClassInfo ciResult = null;
541: Object o = classes.get(argFullClassName);
542: if (o == null) {
543: //logger.msg("Class !found, class (" + argFullClassName + "), parent (" + parent + ")");
544: } else if (o instanceof ClassNameCache.ClassInfo) {
545: //logger.msg("Lazy loading, class", argFullClassName);
546: ClassNameCache.ClassInfo ci = (ClassNameCache.ClassInfo) o;
547:
548: load(argFullClassName);
549: o = classes.get(argFullClassName);
550: if (o instanceof ClassNameCache.ClassInfo) {
551: if (Completer.DEBUG) {
552: logger
553: .debug("## ClassInfo could not be created for ("
554: + ci.getFullClassName()
555: + ") found in ("
556: + ci.getSrc()
557: + ")");
558: }
559: } else {
560: ciResult = (ClassInfo) o;
561: }
562: } else {
563: //if (o instanceof ClassInfo){g
564: ciResult = (ClassInfo) o;
565: }
566: return ciResult;
567: }
568:
569: /**
570: * Enters class information into the database.
571: *
572: * @param classInfo a <code>ClassInfo</code> object that information about
573: * a class to be put in the database. This object should not be
574: * modified after it is put in the database.
575: */
576: public synchronized void put(ClassInfo classInfo) {
577: if (classInfo instanceof ArrayClassInfo) {
578: throw new IllegalArgumentException(
579: "Can't put array classes in ClassTable.");
580: }
581: //logger.msg("putting", classInfo.getFullName());
582: // Don't put inner classes in the package map.
583: if (classInfo.getDeclaringClass() == null) {
584: String packageName = classInfo.getPackage();
585: if (packageName == null) {
586: packageName = UNNAMED_PACKAGE;
587: }
588: Map pmap = (Map) packages.get(packageName);
589: if (pmap == null) {
590: packages.put(packageName, pmap = new TreeMap(
591: new StringComparator()));
592: }
593: pmap.put(classInfo.getName(), classInfo);
594: } else {
595: //if (DEBUG)logger.msg("----INNER: ", classInfo.getFullName());
596: }
597: String strFN = classInfo.getFullName();
598: classes.put(classInfo.getFullName(), classInfo);
599: }
600:
601: /**
602: * Removes a class from the database.
603: *
604: * @param fullClassName a fully-qualified class name. Note that for inner
605: * classes, the <code>$</code> notation is used in the class name.
606: * @return the <code>ClassInfo</code> object that was removed
607: * from the database, or <code>null</code> if there was not one.
608: */
609: public synchronized ClassInfo remove(String fullClassName) {
610: logger.msg("Removing", fullClassName);
611:
612: ClassInfo ci = (ClassInfo) classes.remove(fullClassName);
613: if (ci != null) {
614: String packageName = ci.getPackage();
615: if (packageName == null) {
616: packageName = UNNAMED_PACKAGE;
617: }
618: Map pmap = (Map) packages.get(packageName);
619: if (pmap != null) {
620: pmap.remove(ci.getName());
621: if (pmap.isEmpty()) {
622: packages.remove(packageName);
623: }
624: }
625: }
626: return ci;
627: }
628:
629: /**
630: * Tests if a class is contained in the database.
631: *
632: * @param fullClassName a fully-qualified class name. Note that for inner
633: * classes, the <code>$</code> notation is used in the class name.
634: * @return <code>true</code> if information about the class is
635: * in the database.
636: */
637: public synchronized boolean contains(String fullClassName) {
638: return classes.containsKey(fullClassName);
639: }
640:
641: /**
642: * Gets the assignableTo attribute of the ClassTable object
643: *
644: * @param fromClass Description of the Parameter
645: * @param toClass Description of the Parameter
646: * @param defaultAnswer Description of the Parameter
647: * @return The assignableTo value
648: */
649: public boolean isAssignableTo(String fromClass, String toClass,
650: boolean defaultAnswer) {
651: ClassInfo fci = get(fromClass);
652: ClassInfo tci = get(toClass);
653:
654: // return defaultAnswer when one or both classes are unrecognized
655: if (fci == null || tci == null) {
656: return defaultAnswer;
657: }
658:
659: // a class is assignable to itself
660: if (fci.equals(tci)) {
661: return true;
662: }
663:
664: // handling arrays
665: if (fci instanceof ArrayClassInfo
666: && tci instanceof ArrayClassInfo) {
667: ArrayClassInfo afci = (ArrayClassInfo) fci;
668: ArrayClassInfo atci = (ArrayClassInfo) tci;
669: if (afci.getDimensions() != atci.getDimensions()) {
670: return false;
671: }
672: return isAssignableTo(afci.getArrayType().getFullName(),
673: atci.getArrayType().getFullName(), defaultAnswer);
674: }
675:
676: // a class is assignable if its superclass is assignable
677: if (fci.getSuperclass() != null
678: && isAssignableTo(fci.getSuperclass(), toClass,
679: defaultAnswer)) {
680: return true;
681: }
682:
683: // a class is assignable if any of its interfaces are assignable
684: String[] ifs = fci.getInterfaces();
685: for (int i = 0; i < ifs.length; i++) {
686: if (isAssignableTo(ifs[i], toClass, defaultAnswer)) {
687: return true;
688: }
689: }
690:
691: return false;
692: }
693:
694: /**
695: * Gets the accessAllowed attribute of the ClassTable object
696: *
697: * @param in Description of the Parameter
698: * @param target Description of the Parameter
699: * @param requireStatic Description of the Parameter
700: * @param defaultAnswer Description of the Parameter
701: * @return The accessAllowed value
702: */
703: public boolean isAccessAllowed(ClassInfo in, MemberInfo target,
704: boolean requireStatic, boolean defaultAnswer) {
705: int mods = target.getModifiers();
706: if (requireStatic && (mods & Modifier.STATIC) == 0) {
707: return false;
708: }
709:
710: String dc = target.getDeclaringClass();
711: ClassInfo dci = (dc != null ? (ClassInfo) get(dc) : null);
712: if (dci != null) {
713: if (!isAccessAllowed(in, dci, false, defaultAnswer)) {
714: return false;
715: }
716: } else if (dc != null) {
717: if (!defaultAnswer) {
718: return false;
719: }
720: }
721:
722: if (target instanceof ClassInfo && dc == null) {
723: // top-level class
724: if ((mods & Modifier.PUBLIC) != 0) {
725: return true;
726: } else {
727: String ip = (in != null ? in.getPackage() : null);
728: String cp = ((ClassInfo) target).getPackage();
729: if ((ip == null && cp == null)
730: || (ip != null && cp != null && ip.equals(cp))) {
731: return true;
732: }
733: }
734: return false;
735: }
736:
737: if ((mods & Modifier.PUBLIC) != 0) {
738: // public access
739: return true;
740: }
741:
742: if (in != null && dci != null) {
743: String cn = dci.getFullName();
744: String cp = dci.getPackage();
745: String icn = in.getFullName();
746: String icp = in.getPackage();
747:
748: if ((mods & Modifier.PROTECTED) != 0) {
749: // protected access
750: if (isAssignableTo(icn, cn, false)
751: || (cp == null && icp == null)
752: || (cp != null && icp != null && cp.equals(icp))) {
753: return true;
754: }
755: } else if ((mods & Modifier.PRIVATE) == 0) {
756: // package access
757: if ((cp == null && icp == null)
758: || (cp != null && icp != null && cp.equals(icp))) {
759: return true;
760: }
761: } else {
762: // private access
763: if (cn.equals(icn)) {
764: return true;
765: }
766: }
767:
768: // Allow inner classes to access anything that their declaring
769: // classes can access.. is this correct?
770: String idc = in.getDeclaringClass();
771: if (idc != null) {
772: ClassInfo idci = (ClassInfo) get(idc);
773: if (idci != null) {
774: return isAccessAllowed(idci, target, requireStatic,
775: defaultAnswer);
776: }
777: }
778: }
779:
780: return defaultAnswer;
781: }
782:
783: /**
784: * Gets the size of the database.
785: *
786: * @return the number of classes in the database.
787: */
788: public synchronized int size() {
789: return classes.size();
790: }
791:
792: private void load(String name) {
793:
794: ClassNameCache.ClassInfo cncCI = (ClassNameCache.ClassInfo) classes
795: .get(name);
796: Class cls = null;
797:
798: // 1st try the cnc class loader
799: try {
800: cls = _classLoader.loadClass(cncCI.getFullClassName());
801: } catch (Exception ex) {
802: logger.msg("Could not load class via cnc class loader: "
803: + ex.toString());
804:
805: }
806:
807: // 2nd, try the parent
808: if (cls == null && parent != null) {
809: logger.msg("Calling parent.load");
810: parent.load(name);
811: return;
812: }
813:
814: if (cls != null) {
815: Class clsDec = null;
816: try {
817: clsDec = cls.getDeclaringClass();
818: } catch (IllegalAccessError err) {
819: logger
820: .warning("Encountered IllegalAccessError getting declaring class for: ("
821: + name + ")");
822: }
823: ClassInfo ci = new ClassInfo(cls, clsDec);
824: put(ci);
825: // put all inner classes
826: Set setInnerClasses = ci.getClasses();
827: for (Iterator it = setInnerClasses.iterator(); it.hasNext();) {
828: put((ClassInfo) it.next());
829: }
830:
831: //if (DEBUG)logger.msg("*********LOAD success", ci.getFullName());
832: }
833: }
834:
835: /**
836: * Loads <code>ClassInfo</code> entry information out of a <code>ClassNameCache</code>
837: * . The entries themselves will not actually be loaded into memory until
838: * they are needed.
839: *
840: * @param argListCNCClassInfos Description of the Parameter
841: */
842: public synchronized void preLoad(List argListCNCClassInfos) {
843: List listAll = argListCNCClassInfos;
844: String name;
845: String packageName;
846: int i = 0;
847: Map pmap;
848: ClassNameCache.ClassInfo ci = null;
849: for (Iterator it = listAll.iterator(); it.hasNext();) {
850: ci = (ClassNameCache.ClassInfo) it.next();
851: name = ci.getFullClassName();
852: packageName = UNNAMED_PACKAGE;
853: i = name.lastIndexOf('.');
854: if (i >= 0) {
855: packageName = name.substring(0, i);
856: }
857: pmap = (Map) packages.get(packageName);
858: if (pmap == null) {
859: packages.put(packageName, pmap = new TreeMap(
860: new StringComparator()));
861: }
862: classes.put(name, ci);
863: }
864: }
865:
866: }
|