001: package org.acm.seguin.completer;
002:
003: /*
004: * Copyright (c) 2002, Beau Tateyama
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: */
020:
021: import java.net.URLClassLoader; //import gnu.regexp.REException;
022: //import gnu.regexp.RE;
023: import java.util.regex.*;
024: import java.io.*;
025: import java.io.FilenameFilter;
026: import java.net.*;
027: import java.util.*;
028: import java.util.zip.*;
029: import org.gjt.sp.jedit.*;
030: import org.acm.seguin.ide.jedit.Navigator;
031:
032: public class ClassNameCache {
033: final static Navigator.NavigatorLogger logger = Completer
034: .getLogger(ClassPathSrcMgr.class);
035: private static Map __mapBootCP;
036: private static List __listBootClasses;
037: static {
038: try {
039: Map mapBootCP = new Hashtable();
040: String strBootCP = System
041: .getProperty("sun.boot.class.path");
042: ClassNameCache cnc = new ClassNameCache(strBootCP,
043: mapBootCP);
044: __mapBootCP = Collections.unmodifiableMap(mapBootCP);
045: __listBootClasses = getClassInfoList(__mapBootCP);
046: Collections.sort(__listBootClasses);
047: } catch (Exception e) {
048: logger.error("Error loading boot CP", e);
049: e.printStackTrace();
050: }
051: }
052:
053: public static List getBootClassList() {
054: return __listBootClasses;
055: }
056:
057: public static class ClassInfo implements Comparable {
058:
059: String _strFullCN = null;
060: File _fileSrc = null;
061:
062: ClassInfo(File argSrc, String argFullClassName) {
063: _fileSrc = argSrc;
064: _strFullCN = argFullClassName;
065: }
066:
067: public int compareTo(Object obj) {
068: if (obj instanceof ClassInfo) {
069: return _strFullCN.compareTo(((ClassInfo) obj)
070: .getFullClassName());
071: } else {
072: return 0;
073: }
074: }
075:
076: public String getSrc() {
077: return _fileSrc.getPath();
078: }
079:
080: public File getSrcFile() {
081: return _fileSrc;
082: }
083:
084: public String getFullClassName() {
085: return _strFullCN;
086: }
087:
088: public String getClassName() {
089: return _strFullCN
090: .substring(_strFullCN.lastIndexOf(".") + 1);
091: }
092:
093: public String toString() {
094: return getClassName();
095: }
096:
097: public boolean equals(Object obj) {
098: boolean bEquals = false;
099: if (obj == this ) {
100: bEquals = true;
101: } else if (obj != null) {
102: ClassInfo ci = (ClassInfo) obj;
103: bEquals = (ci.getSrcFile().equals(getSrcFile()) && ci
104: .getFullClassName().equals(getFullClassName()));
105: }
106: return bEquals;
107: }
108: }
109:
110: static class JarFileMgr {
111: static JarFileMgr _instance = new JarFileMgr();
112:
113: static JarFileMgr getInstance() {
114: return _instance;
115: }
116:
117: Map _mapJarInfos = new HashMap();
118:
119: JarFileMgr() {
120: }
121:
122: synchronized int parseJarFile(File argFile, Map argMap)
123: throws IOException {
124: int iClassCount = 0;
125: JarInfo jarInfo = (JarInfo) _mapJarInfos.get(argFile);
126: if (jarInfo == null
127: || argFile.lastModified() > jarInfo.lastModified()) {
128:
129: Map mapData = new HashMap();
130: int iCount = parseZipFile(argFile, mapData);
131: jarInfo = new JarInfo(argFile, argFile.lastModified(),
132: mapData, iCount);
133: _mapJarInfos.put(argFile, jarInfo);
134: }
135: iClassCount = jarInfo.getClassCount();
136: // now merge the jarinfo into the map.
137: String strCN;
138: Set setNew, setExisting;
139: for (Iterator it = jarInfo.getData().keySet().iterator(); it
140: .hasNext();) {
141: // retrieve new entries
142: strCN = (String) it.next();
143: setNew = (Set) jarInfo.getData().get(strCN);
144: // merge into argMap
145: setExisting = (Set) argMap.get(strCN);
146: if (setExisting == null) {
147: // new, so just add it
148: argMap.put(strCN, setNew);
149: } else {
150: // class name entry exists, so just add to set
151: setExisting.addAll(setNew);
152: }
153: }
154: return iClassCount;
155: }
156: }
157:
158: static class JarInfo {
159: File _file;
160: Map _mapData;
161: long _lastMod;
162: int _iClassCount;
163:
164: JarInfo(File argFile, long argLastMod, Map argData,
165: int argClassCount) {
166: _file = argFile;
167: _lastMod = argLastMod;
168: _mapData = argData;
169: _iClassCount = argClassCount;
170: }
171:
172: int getClassCount() {
173: return _iClassCount;
174: }
175:
176: File getFile() {
177: return _file;
178: }
179:
180: Map getData() {
181: return _mapData;
182: }
183:
184: long lastModified() {
185: return _lastMod;
186: }
187: }
188:
189: String _strPath = null;
190: URL[] _urls = null;
191: Map _mapClassNameToClassList;
192: URLClassLoader _urlClassLoader = null;
193: int _iClassCount = 0;
194: String _strName = null;
195:
196: private ClassNameCache(String argPath, Map argMap) {
197: _mapClassNameToClassList = argMap;
198: parseClasses(argPath);
199:
200: // add a class loader for fun!
201: _urlClassLoader = new URLClassLoader(getClassPathAsURLs());
202: //jEdit.class.getClassLoader());
203: //null);
204: //getClass().getClassLoader());
205:
206: }
207:
208: public void setName(String argName) {
209: _strName = argName;
210: }
211:
212: public String getName() {
213: return _strName;
214: }
215:
216: public ClassNameCache(String argPath) {
217: this (argPath, new Hashtable()); //__mapBootCP));
218: }
219:
220: public URL[] getClassPathAsURLs() {
221: return _urls;
222: }
223:
224: public URLClassLoader getDynamicClassLoader() {
225: return _urlClassLoader;
226: }
227:
228: private void parseClasses(String argPath) {
229: _strPath = argPath;
230: //+ System.getProperty("path.separator") + System.getProperty("sun.boot.class.path");
231: _urls = pathToURLs(_strPath);
232: File file = null;
233: for (int i = 0; i < _urls.length; i++) {
234: file = new File(_urls[i].getFile());
235: if (file.isDirectory()) {
236:
237: logger.msg("Parsing directory: " + file.getPath());
238: long lStart = System.currentTimeMillis();
239: _iClassCount += parseDirectory(file,
240: _mapClassNameToClassList);
241: //logger.msg("time (ms)", System.currentTimeMillis()-lStart);
242: } else if (isJarFile(file)) {
243: logger.msg("Parsing jar file: " + file.getPath());
244: try {
245: long lStart = System.currentTimeMillis();
246: // we use a cache mgr for jar files
247: _iClassCount += JarFileMgr.getInstance()
248: .parseJarFile(file,
249: _mapClassNameToClassList);
250: //parseZipFile(new ZipFile(file), _mapClassNameToClassList);
251: //logger.msg("time (ms)", System.currentTimeMillis()-lStart);
252: } catch (IOException ze) {
253: logger.error("Error parsing jar file : "
254: + file.getPath(), ze);
255: }
256: } else {
257: logger.msg("Skipping item: " + file.getPath());
258: }
259: }
260: }
261:
262: static boolean isJarFile(File argFile) {
263: String strFileName = argFile.getName().toLowerCase();
264: return strFileName.endsWith(".jar")
265: || strFileName.endsWith(".zip");
266: }
267:
268: public Set getClassListForClassName(String argClassName) {
269: Set setResult = null;
270: Set setClasses = (Set) _mapClassNameToClassList
271: .get(argClassName);
272: Set setBootClasses = (Set) __mapBootCP.get(argClassName);
273: if (setClasses == null && setBootClasses != null) {
274: setResult = setBootClasses;
275: } else if (setClasses != null && setBootClasses == null) {
276: setResult = setClasses;
277: } else if (setClasses != null && setBootClasses != null) {
278: setClasses.addAll(setBootClasses);
279: setResult = setClasses;
280: }
281:
282: if (setResult != null) {
283: Set setTemp = new TreeSet();
284: ClassInfo ci = null;
285: for (Iterator it = setResult.iterator(); it.hasNext();) {
286: ci = (ClassInfo) it.next();
287: setTemp.add(ci.getFullClassName());
288: }
289: setResult = setTemp;
290: }
291: return setResult;
292: }
293:
294: public List getAllClassInfos() {
295: return getClassInfoList(_mapClassNameToClassList);
296: }
297:
298: static List getClassInfoList(Map argMap) {
299: List list = new ArrayList();
300: Set setFullClassNames = null;
301: Set setClasses = new TreeSet(argMap.keySet());
302: String strClassName = null;
303: for (Iterator iter = setClasses.iterator(); iter.hasNext();) {
304: strClassName = (String) iter.next();
305: setFullClassNames = (Set) argMap.get(strClassName);
306: for (Iterator it = setFullClassNames.iterator(); it
307: .hasNext();) {
308: list.add(it.next());
309: }
310: }
311: return list;
312: }
313:
314: public String listContents() {
315: return listContents(_mapClassNameToClassList);
316: }
317:
318: public static String listContents(Map argMap) {
319: String NL = "\n", TAB = "\t";
320: StringBuffer sb = new StringBuffer("[" + argMap.size()
321: + " items]" + NL);
322:
323: Set setFullClassNames = null;
324: Set setClasses = new TreeSet(argMap.keySet());
325: String strClassName = null;
326: for (Iterator iter = setClasses.iterator(); iter.hasNext();) {
327: strClassName = (String) iter.next();
328: setFullClassNames = (Set) argMap.get(strClassName);
329: sb.append(strClassName).append(NL);
330: for (Iterator it = setFullClassNames.iterator(); it
331: .hasNext();) {
332: sb.append(TAB).append(it.next().toString()).append(NL);
333: }
334: }
335: return sb.toString();
336:
337: }
338:
339: public String toString() {
340: String NL = "\n", TAB = "\t";
341: StringBuffer sb = new StringBuffer("[" + super .toString()
342: + "] - ");
343: sb.append(getAllClassInfos().size()).append(" classes").append(
344: NL);
345: sb.append(TAB).append("path=").append(_strPath).append(NL);
346: sb.append(TAB).append("urls=").append(NL);
347: if (_urls != null) {
348: for (int i = 0; i < _urls.length; i++) {
349: sb.append(TAB).append(TAB).append(_urls[i].toString())
350: .append(NL);
351: }
352: }
353: return sb.toString();
354: }
355:
356: public boolean equals(Object o) {
357: if (this == o)
358: return true;
359: if (!(o instanceof ClassNameCache)) {
360: return false;
361: }
362: ClassNameCache cnc = (ClassNameCache) o;
363: return (cnc._iClassCount == this ._iClassCount
364: && cnc._strPath.equals(this ._strPath) && cnc._mapClassNameToClassList
365: .keySet()
366: .equals(this ._mapClassNameToClassList.keySet()));
367: }
368:
369: public int hashCode() {
370: return _strPath.hashCode();
371: }
372:
373: /**
374: * Convert the path to an array of <code>URL</code>s
375: * @param argPath a <code>String</code> value
376: * @return an <code>URL[]</code> value
377: */
378: public static URL[] pathToURLs(String argPath) {
379: try {
380: ArrayList alURLs = new ArrayList();
381: String strSep = System.getProperty("path.separator");
382: File file = null;
383: for (StringTokenizer st = new StringTokenizer(argPath,
384: strSep); st.hasMoreTokens();) {
385: file = new File(st.nextToken());
386: if (file.exists()) {
387: alURLs.add(file.toURL());
388: }
389: //alURLs.add(new URL("file:/" + st.nextToken()));
390: }
391: return (URL[]) alURLs.toArray(new URL[0]);
392: } catch (MalformedURLException e) {
393: e.printStackTrace();
394: return null;
395: }
396: }
397:
398: static String parseFullClassName(String argFileName) {
399: argFileName = argFileName.replace('/', '.');
400: argFileName = argFileName.replace('\\', '.');
401: return argFileName.substring(0, argFileName.length() - 6);
402: }
403:
404: static String parseClassName(String argFullClassName) {
405: int iDot = argFullClassName.lastIndexOf('.');
406: if (iDot == -1) {
407: return argFullClassName;
408: } else {
409: return argFullClassName.substring(iDot + 1);
410: }
411: }
412:
413: static int parseDirectory(File argDirectory, Map argMap) {
414: int iClassCount = 0;
415: List listFiles = new ArrayList();
416: JavaUtils.listAllFiles(argDirectory, new ClassFileFilter(),
417: listFiles); //new ClassFileFilter(), listFiles);
418: String strFileName = null, strClassName = null, strFullClassName = null;
419:
420: int iDir = argDirectory.getPath().length();
421: Set setClassNames = null;
422: ClassInfo ci = null;
423:
424: for (Iterator iter = listFiles.iterator(); iter.hasNext();) {
425: strFileName = ((File) iter.next()).getPath();
426: strFileName = strFileName.substring(iDir + 1);
427: strFullClassName = parseFullClassName(strFileName);
428: strClassName = parseClassName(strFullClassName);
429: //System.out.println(strClassName + "->" + strFullClassName);
430: setClassNames = (Set) argMap.get(strClassName);
431: if (setClassNames == null) {
432: setClassNames = new HashSet();
433: argMap.put(strClassName, setClassNames);
434: }
435: ci = new ClassInfo(argDirectory, strFullClassName);
436: setClassNames.add(ci); //strFullClassName);
437: iClassCount++;
438: }
439: return iClassCount;
440: }
441:
442: static int parseZipFile(File argFile, Map argMap) throws IOException, ZipException {
443:
444: int iClassCount = 0;
445: ZipFile zipFile = null;
446: try{
447: zipFile = new ZipFile(argFile);
448: ZipEntry zipEntry = null;
449: String strFileName = null, strClassName = null, strFullClassName = null;
450: Set setClassNames = null;
451: ClassInfo ci = null;
452: for(Enumeration enum = zipFile.entries(); enum.hasMoreElements(); ){
453: zipEntry = (ZipEntry) enum.nextElement();
454: strFileName = zipEntry.getName();
455:
456: // filter the elements
457: if (isClassFile(strFileName) ){
458: //&& !strFileName.startsWith("com/") && !strFileName.startsWith("sun/")){
459: strFullClassName = parseFullClassName(strFileName);
460: strClassName = parseClassName(strFullClassName);
461: //System.out.println(strClassName + "->" + strFullClassName);
462: setClassNames = (Set) argMap.get(strClassName);
463: if (setClassNames == null){
464: setClassNames = new HashSet();
465: argMap.put(strClassName, setClassNames);
466: }
467: ci = new ClassInfo(argFile, strFullClassName);
468: setClassNames.add(ci);
469: iClassCount++;
470: }
471: }
472: }finally{
473: if (zipFile != null){
474: zipFile.close();
475: }
476: }
477: return iClassCount;
478: }
479:
480: public static class ClassFileFilter implements FilenameFilter {
481: public boolean accept(File argDir, String argName) {
482: return isClassFile(argName)
483: || (new File(argDir, argName)).isDirectory();
484: }
485: }
486:
487: static final String RE_ANONYMOUS_INNER_CLASS = "\\$\\d+(\\.class|\\$)";
488:
489: public static boolean isAnonymousInnerClass(String argClassName) {
490: //try{
491: //RE regexp = new RE(RE_ANONYMOUS_INNER_CLASS);
492:
493: //return regexp.getMatch(argClassName) != null;
494: Pattern pattern = Pattern.compile(RE_ANONYMOUS_INNER_CLASS);
495: Matcher m = pattern.matcher(argClassName);
496: return m.matches();
497: //}catch(REException e){
498: // logger.error("Error parsing classname: " + argClassName);
499: // //e.printStackTrace();
500: // return false;
501: //}
502: }
503:
504: static boolean isClassFile(String argFileName) {
505: return argFileName.toLowerCase().endsWith(".class")
506: && argFileName.indexOf("$") == -1;
507: //return argFileName.toLowerCase().endsWith(".class") && !isAnonymousInnerClass(argFileName);
508: }
509:
510: static void testAnonymousInner() throws Exception {
511: if (1 == 2)
512: throw new Exception();
513: String[] strPositiveTests = {
514: "ClassListDialog$1$EnterKeyListener.class",
515: "ClassTreeViewer$1.class",
516: "ConfigDialog$1$CancelButtonHandler.class",
517: "ConfigDialog$2.class" };
518: for (int i = 0; i < strPositiveTests.length; i++) {
519: if (!isAnonymousInnerClass(strPositiveTests[i])) {
520: System.out
521: .println("[+] Error - " + strPositiveTests[i]);
522: }
523: }
524: String[] strNegTests = {
525: "ClassNameCache$ClassFileFilter.class",
526: "ClassNameCache$ClassInfo.class",
527: "ClassNameCache.class",
528: "JavaUtils$ClassSelectionDialog$ListKeyAdapter.class",
529: "JavaUtils$ClassSelectionDialog.class" };
530: for (int i = 0; i < strNegTests.length; i++) {
531: if (isAnonymousInnerClass(strNegTests[i])) {
532: System.out.println("[-] Error - " + strNegTests[i]);
533: }
534: }
535:
536: }
537:
538: static void test() {
539: File argFile = new File("C:/home/work/src/build");
540: String strTestPath = "C:\\home\\work\\src\\build;C:\\home\\work\\src\\classes;C:\\home\\work\\src\\classes\\activation.jar;C:\\home\\work\\src\\classes\\classes12.zip;C:\\home\\work\\src\\classes\\crimson.jar;C:\\home\\work\\src\\classes\\ecs.jar;C:\\home\\work\\src\\classes\\HTTPClient.jar;C:\\home\\work\\src\\classes\\javax.servlet.jar;C:\\home\\work\\src\\classes\\jgen.jar;C:\\home\\work\\src\\classes\\jdom.jar;C:\\home\\work\\src\\classes\\jndi.jar;C:\\home\\work\\src\\classes\\junit.jar;C:\\home\\work\\src\\classes\\mail.jar;C:\\home\\work\\src\\classes\\gnu-regexp-1.1.4.jar;C:\\home\\work\\src\\classes\\sfc.jar;C:\\home\\work\\src\\classes\\symbeans.jar;C:\\home\\work\\src\\classes\\xaa_xmlc.jar;C:\\home\\work\\src\\classes\\xalan.jar;C:\\jdk131\\jre\\lib\\rt.jar;C:\\jdk131\\lib\\tools.jar;C:\\home\\work\\src\\classes\\jcert.jar;C:\\home\\work\\src\\classes\\jnet.jar;C:\\home\\work\\src\\classes\\jsse.jar;C:\\home\\work\\src\\classes\\jce1_2_1.jar;C:\\home\\work\\src\\classes\\local_policy.jar;C:\\home\\work\\src\\classes\\sunjce_provider.jar;C:\\home\\work\\src\\classes\\US_export_policy.jar";
541: //;C\:\\home\\work\\src\\classes;C\:\\home\\work\\src\\classes\\activation.jar;C\:\\home\\work\\src\\classes\\classes12.zip;C\:\\home\\work\\src\\classes\\crimson.jar;C\:\\home\\work\\src\\classes\\ecs.jar;C\:\\home\\work\\src\\classes\\HTTPClient.jar;C\:\\home\\work\\src\\classes\\javax.servlet.jar;C\:\\home\\work\\src\\classes\\jgen.jar;C\:\\home\\work\\src\\classes\\jdom.jar;C\:\\home\\work\\src\\classes\\jndi.jar;C\:\\home\\work\\src\\classes\\junit.jar;C\:\\home\\work\\src\\classes\\mail.jar;C\:\\home\\work\\src\\classes\\gnu-regexp-1.1.4.jar;C\:\\home\\work\\src\\classes\\sfc.jar;C\:\\home\\work\\src\\classes\\symbeans.jar;C\:\\home\\work\\src\\classes\\xaa_xmlc.jar;C\:\\home\\work\\src\\classes\\xalan.jar;C\:\\jdk131\\jre\\lib\\rt.jar;C\:\\jdk131\\lib\\tools.jar;C\:\\home\\work\\src\\classes\\jcert.jar;C\:\\home\\work\\src\\classes\\jnet.jar;C\:\\home\\work\\src\\classes\\jsse.jar;C\:\\home\\work\\src\\classes\\jce1_2_1.jar;C\:\\home\\work\\src\\classes\\local_policy.jar;C\:\\home\\work\\src\\classes\\sunjce_provider.jar;C\:\\home\\work\\src\\classes\\US_export_policy.jar";
542: /*
543: "C:\\home\\work\\src\\build;C:\\home\\work\\src\\classes;C:\\home\\work\\src\\classes\\activation.jar;C:\\home\\work\\src\\classes\\classes12.zip;C:\\home\\work\\src\\classes\\crimson.jar;C:\\home\\work\\src\\classes\\ecs.jar;C:\\home\\work\\src\\classes\\HTTPClient.jar;C:\\home\\work\\src\\classes\\javax.servlet.jar;C:\\home\\work\\src\\classes\\jgen.jar;C:\\home\\work\\src\\classes\\jdom.jar;C:\\home\\work\\src\\classes\\jndi.jar;C:\\home\\work\\src\\classes\\junit.jar;C:\\home\\work\\src\\classes\\mail.jar;C:\\home\\work\\src\\classes\\gnu-regexp-1.1.4.jar;C:\\home\\work\\src\\classes\\sfc.jar;C:\\home\\work\\src\\classes\\symbeans.jar;C:\\home\\work\\src\\classes\\xaa_xmlc.jar;C:\\home\\work\\src\\classes\\xalan.jar;C:\\jdk131\\jre\\lib\\rt.jar;C:\\jdk131\\lib\\tools.jar;C:\\home\\work\\src\\classes\\jcert.jar;C:\\home\\work\\src\\classes\\jnet.jar;C:\\home\\work\\src\\classes\\jsse.jar;C:\\home\\work\\src\\classes\\jce1_2_1.jar;C:\\home\\work\\src\\classes\\local_policy.jar;C:\\home\\work\\src\\classes\\sunjce_provider.jar;C:\\home\\work\\src\\classes\\US_export_policy.jar";
544: */
545: strTestPath = System.getProperty("sun.boot.class.path");
546: long longStart, longEnd, longStartAll = System
547: .currentTimeMillis();
548: int iIter = 10;
549: ClassNameCache cnc = null;
550: for (int i = 0, l = iIter; i < l; i++) {
551: longStart = System.currentTimeMillis();
552: cnc = new ClassNameCache(strTestPath);
553: longEnd = System.currentTimeMillis();
554: logger.msg("[" + i + "] time(ms)=", ""
555: + (longEnd - longStart));
556: }
557: logger.msg("Size", cnc.getAllClassInfos().size());
558: logger.msg("[AVE] time(ms)=", ""
559: + (System.currentTimeMillis() - longStartAll)
560: / (double) iIter);
561: //System.out.println(strTestPath);
562: //System.out.println(cnc.listContents());
563: }
564:
565: public static void main(String[] args) {
566: try {
567: test();
568:
569: //testAnonymousInner();
570: for (Iterator it = new HashMap().keySet().iterator(); it
571: .hasNext();) {
572: }
573: } catch (Throwable t) {
574: t.printStackTrace();
575: }
576: }
577:
578: }
|