1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.bcel.util;
18
19 import java.io.DataInputStream;
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.FilenameFilter;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.Serializable;
26 import java.util.ArrayList;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.StringTokenizer;
31 import java.util.zip.ZipEntry;
32 import java.util.zip.ZipFile;
33
34 /***
35 * Responsible for loading (class) files from the CLASSPATH. Inspired by
36 * sun.tools.ClassPath.
37 *
38 * @version $Id: ClassPath.java 386056 2006-03-15 11:31:56Z tcurdt $
39 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
40 */
41 public class ClassPath implements Serializable {
42
43 public static final ClassPath SYSTEM_CLASS_PATH = new ClassPath();
44 private PathEntry[] paths;
45 private String class_path;
46
47
48 /***
49 * Search for classes in given path.
50 */
51 public ClassPath(String class_path) {
52 this.class_path = class_path;
53 List vec = new ArrayList();
54 for (StringTokenizer tok = new StringTokenizer(class_path, System
55 .getProperty("path.separator")); tok.hasMoreTokens();) {
56 String path = tok.nextToken();
57 if (!path.equals("")) {
58 File file = new File(path);
59 try {
60 if (file.exists()) {
61 if (file.isDirectory()) {
62 vec.add(new Dir(path));
63 } else {
64 vec.add(new Zip(new ZipFile(file)));
65 }
66 }
67 } catch (IOException e) {
68 System.err.println("CLASSPATH component " + file + ": " + e);
69 }
70 }
71 }
72 paths = new PathEntry[vec.size()];
73 vec.toArray(paths);
74 }
75
76
77 /***
78 * Search for classes in CLASSPATH.
79 * @deprecated Use SYSTEM_CLASS_PATH constant
80 */
81 public ClassPath() {
82 this(getClassPath());
83 }
84
85
86 /*** @return used class path string
87 */
88 public String toString() {
89 return class_path;
90 }
91
92
93 public int hashCode() {
94 return class_path.hashCode();
95 }
96
97
98 public boolean equals( Object o ) {
99 if (o instanceof ClassPath) {
100 return class_path.equals(((ClassPath) o).class_path);
101 }
102 return false;
103 }
104
105
106 private static final void getPathComponents( String path, List list ) {
107 if (path != null) {
108 StringTokenizer tok = new StringTokenizer(path, File.pathSeparator);
109 while (tok.hasMoreTokens()) {
110 String name = tok.nextToken();
111 File file = new File(name);
112 if (file.exists()) {
113 list.add(name);
114 }
115 }
116 }
117 }
118
119
120 /*** Checks for class path components in the following properties:
121 * "java.class.path", "sun.boot.class.path", "java.ext.dirs"
122 *
123 * @return class path as used by default by BCEL
124 */
125 public static final String getClassPath() {
126 String class_path = System.getProperty("java.class.path");
127 String boot_path = System.getProperty("sun.boot.class.path");
128 String ext_path = System.getProperty("java.ext.dirs");
129 List list = new ArrayList();
130 getPathComponents(class_path, list);
131 getPathComponents(boot_path, list);
132 List dirs = new ArrayList();
133 getPathComponents(ext_path, dirs);
134 for (Iterator e = dirs.iterator(); e.hasNext();) {
135 File ext_dir = new File((String) e.next());
136 String[] extensions = ext_dir.list(new FilenameFilter() {
137
138 public boolean accept( File dir, String name ) {
139 name = name.toLowerCase(Locale.ENGLISH);
140 return name.endsWith(".zip") || name.endsWith(".jar");
141 }
142 });
143 if (extensions != null) {
144 for (int i = 0; i < extensions.length; i++) {
145 list.add(ext_dir.getPath() + File.separatorChar + extensions[i]);
146 }
147 }
148 }
149 StringBuffer buf = new StringBuffer();
150 for (Iterator e = list.iterator(); e.hasNext();) {
151 buf.append((String) e.next());
152 if (e.hasNext()) {
153 buf.append(File.pathSeparatorChar);
154 }
155 }
156 return buf.toString().intern();
157 }
158
159
160 /***
161 * @param name fully qualified class name, e.g. java.lang.String
162 * @return input stream for class
163 */
164 public InputStream getInputStream( String name ) throws IOException {
165 return getInputStream(name.replace('.', '/'), ".class");
166 }
167
168
169 /***
170 * Return stream for class or resource on CLASSPATH.
171 *
172 * @param name fully qualified file name, e.g. java/lang/String
173 * @param suffix file name ends with suff, e.g. .java
174 * @return input stream for file on class path
175 */
176 public InputStream getInputStream( String name, String suffix ) throws IOException {
177 InputStream is = null;
178 try {
179 is = getClass().getClassLoader().getResourceAsStream(name + suffix);
180 } catch (Exception e) {
181 }
182 if (is != null) {
183 return is;
184 }
185 return getClassFile(name, suffix).getInputStream();
186 }
187
188
189 /***
190 * @param name fully qualified file name, e.g. java/lang/String
191 * @param suffix file name ends with suff, e.g. .java
192 * @return class file for the java class
193 */
194 public ClassFile getClassFile( String name, String suffix ) throws IOException {
195 for (int i = 0; i < paths.length; i++) {
196 ClassFile cf;
197 if ((cf = paths[i].getClassFile(name, suffix)) != null) {
198 return cf;
199 }
200 }
201 throw new IOException("Couldn't find: " + name + suffix);
202 }
203
204
205 /***
206 * @param name fully qualified class name, e.g. java.lang.String
207 * @return input stream for class
208 */
209 public ClassFile getClassFile( String name ) throws IOException {
210 return getClassFile(name, ".class");
211 }
212
213
214 /***
215 * @param name fully qualified file name, e.g. java/lang/String
216 * @param suffix file name ends with suffix, e.g. .java
217 * @return byte array for file on class path
218 */
219 public byte[] getBytes( String name, String suffix ) throws IOException {
220 DataInputStream dis = null;
221 try {
222 InputStream is = getInputStream(name, suffix);
223 if (is == null) {
224 throw new IOException("Couldn't find: " + name + suffix);
225 }
226 dis = new DataInputStream(is);
227 byte[] bytes = new byte[is.available()];
228 dis.readFully(bytes);
229 return bytes;
230 } finally {
231 if (dis != null) {
232 dis.close();
233 }
234 }
235 }
236
237
238 /***
239 * @return byte array for class
240 */
241 public byte[] getBytes( String name ) throws IOException {
242 return getBytes(name, ".class");
243 }
244
245
246 /***
247 * @param name name of file to search for, e.g. java/lang/String.java
248 * @return full (canonical) path for file
249 */
250 public String getPath( String name ) throws IOException {
251 int index = name.lastIndexOf('.');
252 String suffix = "";
253 if (index > 0) {
254 suffix = name.substring(index);
255 name = name.substring(0, index);
256 }
257 return getPath(name, suffix);
258 }
259
260
261 /***
262 * @param name name of file to search for, e.g. java/lang/String
263 * @param suffix file name suffix, e.g. .java
264 * @return full (canonical) path for file, if it exists
265 */
266 public String getPath( String name, String suffix ) throws IOException {
267 return getClassFile(name, suffix).getPath();
268 }
269
270 private static abstract class PathEntry implements Serializable {
271
272 abstract ClassFile getClassFile( String name, String suffix ) throws IOException;
273 }
274
275 /*** Contains information about file/ZIP entry of the Java class.
276 */
277 public interface ClassFile {
278
279 /*** @return input stream for class file.
280 */
281 public abstract InputStream getInputStream() throws IOException;
282
283
284 /*** @return canonical path to class file.
285 */
286 public abstract String getPath();
287
288
289 /*** @return base path of found class, i.e. class is contained relative
290 * to that path, which may either denote a directory, or zip file
291 */
292 public abstract String getBase();
293
294
295 /*** @return modification time of class file.
296 */
297 public abstract long getTime();
298
299
300 /*** @return size of class file.
301 */
302 public abstract long getSize();
303 }
304
305 private static class Dir extends PathEntry {
306
307 private String dir;
308
309
310 Dir(String d) {
311 dir = d;
312 }
313
314
315 ClassFile getClassFile( String name, String suffix ) throws IOException {
316 final File file = new File(dir + File.separatorChar
317 + name.replace('.', File.separatorChar) + suffix);
318 return file.exists() ? new ClassFile() {
319
320 public InputStream getInputStream() throws IOException {
321 return new FileInputStream(file);
322 }
323
324
325 public String getPath() {
326 try {
327 return file.getCanonicalPath();
328 } catch (IOException e) {
329 return null;
330 }
331 }
332
333
334 public long getTime() {
335 return file.lastModified();
336 }
337
338
339 public long getSize() {
340 return file.length();
341 }
342
343
344 public String getBase() {
345 return dir;
346 }
347 } : null;
348 }
349
350
351 public String toString() {
352 return dir;
353 }
354 }
355
356 private static class Zip extends PathEntry {
357
358 private ZipFile zip;
359
360
361 Zip(ZipFile z) {
362 zip = z;
363 }
364
365
366 ClassFile getClassFile( String name, String suffix ) throws IOException {
367 final ZipEntry entry = zip.getEntry(name.replace('.', '/') + suffix);
368 return (entry != null) ? new ClassFile() {
369
370 public InputStream getInputStream() throws IOException {
371 return zip.getInputStream(entry);
372 }
373
374
375 public String getPath() {
376 return entry.toString();
377 }
378
379
380 public long getTime() {
381 return entry.getTime();
382 }
383
384
385 public long getSize() {
386 return entry.getSize();
387 }
388
389
390 public String getBase() {
391 return zip.getName();
392 }
393 } : null;
394 }
395 }
396 }