001: /*
002: * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
003: *
004: * This software is distributable under the BSD license. See the terms of the
005: * BSD license in the documentation provided with this software.
006: */
007: package jline;
008:
009: import java.io.*;
010: import java.net.*;
011: import java.util.*;
012: import java.util.jar.JarEntry;
013: import java.util.jar.JarFile;
014:
015: /**
016: * A Completor implementation that completes java class names. By default,
017: * it scans the java class path to locate all the classes.
018: *
019: * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
020: */
021: public class ClassNameCompletor extends SimpleCompletor {
022:
023: /**
024: * Complete candidates using all the classes available in the
025: * java <em>CLASSPATH</em>.
026: */
027: public ClassNameCompletor() throws IOException {
028: this (null);
029: }
030:
031: public ClassNameCompletor(final SimpleCompletorFilter filter)
032: throws IOException {
033: super (getClassNames(), filter);
034: setDelimiter(".");
035: }
036:
037: public static String[] getClassNames() throws IOException {
038: Set urls = new HashSet();
039:
040: for (ClassLoader loader = ClassNameCompletor.class
041: .getClassLoader(); loader != null; loader = loader
042: .getParent()) {
043: if (!(loader instanceof URLClassLoader)) {
044: continue;
045: }
046:
047: urls.addAll(Arrays.asList(((URLClassLoader) loader)
048: .getURLs()));
049: }
050:
051: // Now add the URL that holds java.lang.String. This is because
052: // some JVMs do not report the core classes jar in the list of
053: // class loaders.
054: Class[] systemClasses = new Class[] { String.class,
055: javax.swing.JFrame.class };
056:
057: for (int i = 0; i < systemClasses.length; i++) {
058: URL classURL = systemClasses[i].getResource("/"
059: + systemClasses[i].getName().replace('.', '/')
060: + ".class");
061:
062: if (classURL != null) {
063: URLConnection uc = (URLConnection) classURL
064: .openConnection();
065:
066: if (uc instanceof JarURLConnection) {
067: urls.add(((JarURLConnection) uc).getJarFileURL());
068: }
069: }
070: }
071:
072: Set classes = new HashSet();
073:
074: for (Iterator i = urls.iterator(); i.hasNext();) {
075: URL url = (URL) i.next();
076: File file = new File(url.getFile());
077:
078: if (file.isDirectory()) {
079: Set files = getClassFiles(file.getAbsolutePath(),
080: new HashSet(), file, new int[] { 200 });
081: classes.addAll(files);
082:
083: continue;
084: }
085:
086: if ((file == null) || !file.isFile()) // TODO: handle directories
087: {
088: continue;
089: }
090:
091: JarFile jf = new JarFile(file);
092:
093: for (Enumeration e = jf.entries(); e.hasMoreElements();) {
094: JarEntry entry = (JarEntry) e.nextElement();
095:
096: if (entry == null) {
097: continue;
098: }
099:
100: String name = entry.getName();
101:
102: if (!name.endsWith(".class")) // only use class files
103: {
104: continue;
105: }
106:
107: classes.add(name);
108: }
109: }
110:
111: // now filter classes by changing "/" to "." and trimming the
112: // trailing ".class"
113: Set classNames = new TreeSet();
114:
115: for (Iterator i = classes.iterator(); i.hasNext();) {
116: String name = (String) i.next();
117: classNames.add(name.replace('/', '.').substring(0,
118: name.length() - 6));
119: }
120:
121: return (String[]) classNames.toArray(new String[classNames
122: .size()]);
123: }
124:
125: private static Set getClassFiles(String root, Set holder,
126: File directory, int[] maxDirectories) {
127: // we have passed the maximum number of directories to scan
128: if (maxDirectories[0]-- < 0) {
129: return holder;
130: }
131:
132: File[] files = directory.listFiles();
133:
134: for (int i = 0; (files != null) && (i < files.length); i++) {
135: String name = files[i].getAbsolutePath();
136:
137: if (!(name.startsWith(root))) {
138: continue;
139: } else if (files[i].isDirectory()) {
140: getClassFiles(root, holder, files[i], maxDirectories);
141: } else if (files[i].getName().endsWith(".class")) {
142: holder.add(files[i].getAbsolutePath().substring(
143: root.length() + 1));
144: }
145: }
146:
147: return holder;
148: }
149: }
|