KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > sape > carbon > core > util > reflection > ClassFinder


1 /*
2  * The contents of this file are subject to the Sapient Public License
3  * Version 1.0 (the "License"); you may not use this file except in compliance
4  * with the License. You may obtain a copy of the License at
5  * http://carbon.sf.net/License.html.
6  *
7  * Software distributed under the License is distributed on an "AS IS" basis,
8  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
9  * the specific language governing rights and limitations under the License.
10  *
11  * The Original Code is The Carbon Component Framework.
12  *
13  * The Initial Developer of the Original Code is Sapient Corporation
14  *
15  * Copyright (C) 2003 Sapient Corporation. All Rights Reserved.
16  */

17
18 package org.sape.carbon.core.util.reflection;
19
20 import java.io.File JavaDoc;
21 import java.util.Enumeration JavaDoc;
22 import java.util.HashSet JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.Set JavaDoc;
25 import java.util.StringTokenizer JavaDoc;
26 import java.util.zip.ZipEntry JavaDoc;
27 import java.util.zip.ZipFile JavaDoc;
28
29
30 /**
31  * <p>This class implements the capability to search over the current classpath
32  * retrieving classes that implement a certain interface.</p>
33  *
34  * Copyright 2001 Sapient
35  * @since carbon 1.0
36  * @author Greg Hinkle, June 2001
37  * @version $Revision: 1.10 $($Author: dvoet $ / $Date: 2003/05/05 21:21:23 $)
38  */

39 public class ClassFinder {
40
41     /**
42      * Tracks the count of classes found that match the
43      * provided criteria.
44      */

45     protected long foundClasses = 0;
46
47     /**
48      * The super class criteria
49      */

50     protected Class JavaDoc superClass = null;
51     /**
52      * The required substring path criteria for this searcher
53      */

54     protected String JavaDoc requiredPathSubstring = null;
55     /**
56      * The set of classes found matching the provided criteria.
57      */

58     protected Set JavaDoc classes = new HashSet JavaDoc(2000);
59
60
61     /**
62      * <p>Instantiates the type of MBeanHarvester that will return all classes
63      * in the entire classpath.</p>
64      */

65     public ClassFinder() {
66
67     }
68
69     /**
70      * <p>Instantiates the type of MBeanHarvester that will return all classes
71      * that are assignable to the supplied class. This would include all
72      * implementations of it, if it is an interface or it and all subclasses
73      * of it if it's a class.</p>
74      *
75      * @param superClass the Class that should be searched for along with
76      * implementations and subclasses
77      */

78     public ClassFinder(Class JavaDoc superClass) {
79         this.superClass = superClass;
80
81     }
82
83     /**
84      * <p>Instantiates the type of MBeanHarvester that will return all classes
85      * that are assignable to the supplied class and are part of the supplied
86      * package. This would include all implementations of it, if it is an
87      * interface or it and all subclasses of it if it's a class. The
88      * supplied <code>requiredPathSubstring must be part of the fully
89      * qualified classname.</p>
90      *
91      * @param superClass the Class that should be searched for along with
92      * implementations and subclasses
93      * @param requiredPathSubstring the String part that must be found in the
94      * classes FQN
95      */

96     public ClassFinder(Class JavaDoc superClass, String JavaDoc requiredPathSubstring) {
97         this.superClass = superClass;
98
99         this.requiredPathSubstring = requiredPathSubstring;
100     }
101
102
103
104     /**
105      * <p>Adds a class name to the list of found classes if and only if it meets
106      * the configured requirements.</p>
107      *
108      * @param className the FQN String name of the class to add
109      */

110     protected void addClassName(String JavaDoc className) {
111
112         // Only add this class if we're not checking for a particular
113
// substring of the FQN or we find that substring
114
if ((this.requiredPathSubstring == null) ||
115             (className.indexOf(this.requiredPathSubstring) >= 0)) {
116
117             if (this.superClass == null) {
118                 this.classes.add(className);
119             } else {
120                 try {
121
122                     // TODO: GH - add a way to search other classpaths and the
123
// system classpath.
124
Class JavaDoc theClass =
125                         Class.forName(
126                             className,
127                             false,
128                             this.getClass().getClassLoader());
129
130                     if (this.superClass.isAssignableFrom(theClass)) {
131                         this.classes.add(className);
132                     }
133                 } catch (ClassNotFoundException JavaDoc cnfe) {
134                     // Used to catch mis-parsed classnames
135
} catch (Throwable JavaDoc t) {
136                     // Used to catch JVM security and linkage errors
137
}
138             }
139         }
140     }
141
142
143     /**
144      * <p>Used to retrieve the results <code>Set</code> from this harvester's
145      * search.</p>
146      *
147      * @return Set the set of classes that meet this harvester's requirements
148      */

149     public Set JavaDoc getClasses() {
150
151         // 1) tokenize classpath
152
String JavaDoc classpath = System.getProperty("java.class.path");
153         String JavaDoc pathSeparator = System.getProperty("path.separator");
154
155         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(classpath,pathSeparator);
156
157         // 2) for each element in the classpath
158
while (st.hasMoreTokens()) {
159             File JavaDoc currentDirectory = new File JavaDoc(st.nextToken());
160
161             processFile(currentDirectory.getAbsolutePath(),"");
162
163         }
164
165         return this.classes;
166     }
167
168
169     /**
170      * Recursively search through Directories with special checks to recognize
171      * zip and jar files. (Zip and Jar files return true from
172      * &lt;File&gt;.isDirectory())
173      * @param base the base file path to search
174      * @param current the current recursively searched file path being searched
175      */

176     private void processFile(String JavaDoc base, String JavaDoc current) {
177         File JavaDoc currentDirectory = new File JavaDoc(base + File.separatorChar + current);
178
179         // Handle special for archives
180
if (isArchive(currentDirectory.getName())) {
181             try {
182                 processZip(new ZipFile JavaDoc(currentDirectory));
183             } catch (Exception JavaDoc e) {
184                 // The directory was not found so the classpath was probably in
185
// error or we don't have rights to it
186
}
187             return;
188         } else {
189
190             Set JavaDoc directories = new HashSet JavaDoc();
191
192             File JavaDoc[] children = currentDirectory.listFiles();
193
194             // if no children, return
195
if (children == null || children.length == 0) {
196                 return;
197             }
198
199             // check for classfiles
200
for (int i = 0; i < children.length; i++) {
201                 File JavaDoc child = children[i];
202                 if (child.isDirectory()) {
203                     directories.add(children[i]);
204                 } else {
205                     if (child.getName().endsWith(".class")) {
206                         String JavaDoc className =
207                             getClassName(
208                                 current +
209                                 ((current == "") ? "" : File.separator) +
210                                 child.getName());
211                         addClassName(className);
212                         this.foundClasses++;
213                     }
214                 }
215             }
216
217             //call process file on each directory. This is an iterative call!!
218
for (Iterator JavaDoc i = directories.iterator(); i.hasNext(); ) {
219                 processFile(base, current + ((current=="")?"":File.separator) +
220                     ((File JavaDoc)i.next()).getName());
221             }
222         }
223     }
224
225
226     /**
227      * <p>Looks at the name of a file to determine if it is an archive</p>
228      * @param name the name of a file
229      * @return true if a file in the classpath is an archive
230      * such as a Jar or Zip file
231      */

232     protected boolean isArchive(String JavaDoc name) {
233         if ((name.endsWith(".jar") ||
234             (name.endsWith(".zip")))) {
235
236             return true;
237         } else {
238             return false;
239         }
240     }
241
242     /**
243      * <p>Returns the Fully Qualified Class name of a class from it's path
244      * @param fileName the full path to a class
245      * @return the FQN of a class
246      */

247     protected String JavaDoc getClassName(String JavaDoc fileName) {
248         String JavaDoc newName = fileName.replace(File.separatorChar,'.');
249         // Because zipfiles don't have platform specific seperators
250
newName = newName.replace('/','.');
251         return newName.substring(0, fileName.length() - 6);
252     }
253
254
255     /**
256      * <P>Iterates through the files in a zip looking for files that may be
257      * classes. This is not recursive as zip's in zip's are not searched by the
258      * classloader either.</p>
259      *
260      * @param file The ZipFile to be searched
261      */

262     protected void processZip(ZipFile JavaDoc file) {
263         Enumeration JavaDoc files = file.entries();
264
265         while (files.hasMoreElements()) {
266             Object JavaDoc tfile = files.nextElement();
267             ZipEntry JavaDoc child = (ZipEntry JavaDoc) tfile;
268             if (child.getName().endsWith(".class")) {
269                 addClassName(getClassName(child.getName()));
270
271                 this.foundClasses++;
272             }
273         }
274     }
275 }
Popular Tags