View Javadoc

1   /*
2    * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
3    *
4    * This software is distributable under the BSD license. See the terms of the
5    * BSD license in the documentation provided with this software.
6    */
7   package jline;
8   
9   import java.io.*;
10  import java.net.*;
11  import java.util.*;
12  import java.util.jar.JarEntry;
13  import java.util.jar.JarFile;
14  
15  /***
16   *  A Completor implementation that completes java class names. By default,
17   *  it scans the java class path to locate all the classes.
18   *
19   *  @author  <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
20   */
21  public class ClassNameCompletor extends SimpleCompletor {
22  
23      /***
24       *  Complete candidates using all the classes available in the
25       *  java <em>CLASSPATH</em>.
26       */
27      public ClassNameCompletor() throws IOException {
28          this(null);
29      }
30  
31      public ClassNameCompletor(final SimpleCompletorFilter filter)
32          throws IOException {
33          super(getClassNames(), filter);
34          setDelimiter(".");
35      }
36  
37      public static String[] getClassNames() throws IOException {
38          Set urls = new HashSet();
39  
40          for (ClassLoader loader = ClassNameCompletor.class
41              .getClassLoader(); loader != null;
42                   loader = loader.getParent()) {
43              if (!(loader instanceof URLClassLoader)) {
44                  continue;
45              }
46  
47              urls.addAll(Arrays.asList(((URLClassLoader) loader).getURLs()));
48          }
49  
50          // Now add the URL that holds java.lang.String. This is because
51          // some JVMs do not report the core classes jar in the list of
52          // class loaders.
53          Class[] systemClasses = new Class[] {
54              String.class, javax.swing.JFrame.class
55              };
56  
57          for (int i = 0; i < systemClasses.length; i++) {
58              URL classURL = systemClasses[i].getResource("/"
59                  + systemClasses[i].getName() .replace('.', '/') + ".class");
60  
61              if (classURL != null) {
62                  URLConnection uc = (URLConnection) classURL.openConnection();
63  
64                  if (uc instanceof JarURLConnection) {
65                      urls.add(((JarURLConnection) uc).getJarFileURL());
66                  }
67              }
68          }
69  
70          Set classes = new HashSet();
71  
72          for (Iterator i = urls.iterator(); i.hasNext();) {
73              URL url = (URL) i.next();
74              File file = new File(url.getFile());
75  
76              if (file.isDirectory()) {
77                  Set files = getClassFiles(file.getAbsolutePath(),
78                      new HashSet(), file, new int[] { 200 });
79                  classes.addAll(files);
80  
81                  continue;
82              }
83  
84              if ((file == null) || !file.isFile()) // TODO: handle directories
85               {
86                  continue;
87              }
88  
89              JarFile jf = new JarFile(file);
90  
91              for (Enumeration e = jf.entries(); e.hasMoreElements();) {
92                  JarEntry entry = (JarEntry) e.nextElement();
93  
94                  if (entry == null) {
95                      continue;
96                  }
97  
98                  String name = entry.getName();
99  
100                 if (!name.endsWith(".class")) // only use class files
101                  {
102                     continue;
103                 }
104 
105                 classes.add(name);
106             }
107         }
108 
109         // now filter classes by changing "/" to "." and trimming the
110         // trailing ".class"
111         Set classNames = new TreeSet();
112 
113         for (Iterator i = classes.iterator(); i.hasNext();) {
114             String name = (String) i.next();
115             classNames.add(name.replace('/', '.').
116                 substring(0, name.length() - 6));
117         }
118 
119         return (String[]) classNames.toArray(new String[classNames.size()]);
120     }
121 
122     private static Set getClassFiles(String root, Set holder, File directory,
123         int[] maxDirectories) {
124         // we have passed the maximum number of directories to scan
125         if (maxDirectories[0]-- < 0) {
126             return holder;
127         }
128 
129         File[] files = directory.listFiles();
130 
131         for (int i = 0; (files != null) && (i < files.length); i++) {
132             String name = files[i].getAbsolutePath();
133 
134             if (!(name.startsWith(root))) {
135                 continue;
136             } else if (files[i].isDirectory()) {
137                 getClassFiles(root, holder, files[i], maxDirectories);
138             } else if (files[i].getName().endsWith(".class")) {
139                 holder.add(files[i].getAbsolutePath().
140                     substring(root.length() + 1));
141             }
142         }
143 
144         return holder;
145     }
146 }