Mercurial > hg > graal-compiler
comparison graal/com.oracle.max.base/src/com/sun/max/program/Classpath.java @ 3733:e233f5660da4
Added Java files from Maxine project.
author | Thomas Wuerthinger <thomas.wuerthinger@oracle.com> |
---|---|
date | Sat, 17 Dec 2011 19:59:18 +0100 |
parents | |
children | bc8527f3071c |
comparison
equal
deleted
inserted
replaced
3732:3e2e8b8abdaf | 3733:e233f5660da4 |
---|---|
1 /* | |
2 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 */ | |
23 package com.sun.max.program; | |
24 | |
25 import java.io.*; | |
26 import java.util.*; | |
27 import java.util.zip.*; | |
28 | |
29 import com.sun.max.io.*; | |
30 | |
31 /** | |
32 */ | |
33 public class Classpath { | |
34 | |
35 private static final List<Entry> EMPTY_LIST = Collections.emptyList(); | |
36 | |
37 public static final Classpath EMPTY = new Classpath(EMPTY_LIST); | |
38 | |
39 private final List<Entry> entries; | |
40 | |
41 /** | |
42 * An entry in a classpath is a file system path that denotes an existing {@linkplain Directory directory}, | |
43 * an existing {@linkplain Archive zip/jar} file or a {@linkplain PlainFile neither}. | |
44 */ | |
45 public abstract static class Entry { | |
46 | |
47 /** | |
48 * Gets the string representing the underlying path of this entry. | |
49 */ | |
50 public final String path() { | |
51 return file().getPath(); | |
52 } | |
53 | |
54 /** | |
55 * Gets the File object representing the underlying path of this entry. | |
56 */ | |
57 public abstract File file(); | |
58 | |
59 /** | |
60 * Determines if a given resource can be found under this entry. | |
61 * | |
62 * @param path a file path relative to this classpath entry. This values uses the '/' character as the path | |
63 * separator regardless of the {@linkplain File#separatorChar default} for the underlying platform. | |
64 */ | |
65 public abstract boolean contains(String path); | |
66 | |
67 /** | |
68 * Gets the contents of a file denoted by a given path that is relative to this classpath entry. If the denoted | |
69 * file does not exist under this classpath entry then {@code null} is returned. Any IO exception that occurs | |
70 * when reading is silently ignored. | |
71 * | |
72 * @param path a file path relative to this classpath entry. This values uses the '/' character as the path | |
73 * separator regardless of the {@linkplain File#separatorChar default} for the underlying platform. | |
74 */ | |
75 abstract ClasspathFile readFile(String path); | |
76 | |
77 public boolean isDirectory() { | |
78 return false; | |
79 } | |
80 | |
81 public boolean isArchive() { | |
82 return false; | |
83 } | |
84 | |
85 public boolean isPlainFile() { | |
86 return false; | |
87 } | |
88 | |
89 @Override | |
90 public String toString() { | |
91 return path(); | |
92 } | |
93 | |
94 public ZipFile zipFile() { | |
95 return null; | |
96 } | |
97 } | |
98 | |
99 /** | |
100 * Represents a classpath entry that is neither an existing directory nor an existing zip/jar archive file. | |
101 */ | |
102 static final class PlainFile extends Entry { | |
103 | |
104 private final File file; | |
105 | |
106 public PlainFile(File file) { | |
107 this.file = file; | |
108 } | |
109 | |
110 @Override | |
111 ClasspathFile readFile(String path) { | |
112 return null; | |
113 } | |
114 | |
115 @Override | |
116 public File file() { | |
117 return file; | |
118 } | |
119 | |
120 @Override | |
121 public boolean isPlainFile() { | |
122 return true; | |
123 } | |
124 | |
125 @Override | |
126 public boolean contains(String path) { | |
127 return false; | |
128 } | |
129 } | |
130 | |
131 /** | |
132 * Represents a classpath entry that is a path to an existing directory. | |
133 */ | |
134 static final class Directory extends Entry { | |
135 private final File directory; | |
136 | |
137 public Directory(File directory) { | |
138 this.directory = directory; | |
139 } | |
140 | |
141 @Override | |
142 ClasspathFile readFile(String path) { | |
143 final File file = new File(directory, File.separatorChar == '/' ? path : path.replace('/', File.separatorChar)); | |
144 if (file.exists()) { | |
145 try { | |
146 return new ClasspathFile(Files.toBytes(file), this); | |
147 } catch (IOException ioException) { | |
148 ProgramWarning.message("Error reading from " + file + ": " + ioException); | |
149 return null; | |
150 } | |
151 } | |
152 return null; | |
153 } | |
154 | |
155 @Override | |
156 public File file() { | |
157 return directory; | |
158 } | |
159 | |
160 @Override | |
161 public boolean isDirectory() { | |
162 return true; | |
163 } | |
164 | |
165 @Override | |
166 public boolean contains(String path) { | |
167 return new File(directory, File.separatorChar == '/' ? path : path.replace('/', File.separatorChar)).exists(); | |
168 } | |
169 } | |
170 | |
171 /** | |
172 * Represents a classpath entry that is a path to an existing zip/jar archive file. | |
173 */ | |
174 static final class Archive extends Entry { | |
175 | |
176 private final File file; | |
177 private ZipFile zipFile; | |
178 | |
179 public Archive(File file) { | |
180 this.file = file; | |
181 } | |
182 | |
183 @Override | |
184 public ZipFile zipFile() { | |
185 if (zipFile == null && file != null) { | |
186 try { | |
187 zipFile = new ZipFile(file); | |
188 } catch (IOException e) { | |
189 ProgramWarning.message("Error opening ZIP file: " + file.getPath()); | |
190 e.printStackTrace(); | |
191 } | |
192 } | |
193 return zipFile; | |
194 } | |
195 | |
196 @Override | |
197 public boolean contains(String path) { | |
198 final ZipFile zf = zipFile(); | |
199 if (zf == null) { | |
200 return false; | |
201 } | |
202 return zf.getEntry(path) != null; | |
203 } | |
204 | |
205 @Override | |
206 ClasspathFile readFile(String path) { | |
207 final ZipFile zf = zipFile(); | |
208 if (zf == null) { | |
209 return null; | |
210 } | |
211 try { | |
212 final ZipEntry zipEntry = zf.getEntry(path); | |
213 if (zipEntry != null) { | |
214 return new ClasspathFile(readZipEntry(zf, zipEntry), this); | |
215 } | |
216 } catch (IOException ioException) { | |
217 //ProgramWarning.message("could not read ZIP file: " + file); | |
218 } | |
219 return null; | |
220 } | |
221 | |
222 @Override | |
223 public File file() { | |
224 return file; | |
225 } | |
226 | |
227 @Override | |
228 public boolean isArchive() { | |
229 return true; | |
230 } | |
231 } | |
232 | |
233 /** | |
234 * Gets the ordered entries from which this classpath is composed. | |
235 * | |
236 * @return a sequence of {@code Entry} objects | |
237 */ | |
238 public List<Entry> entries() { | |
239 return entries; | |
240 } | |
241 | |
242 /** | |
243 * Creates a classpath {@link Entry} from a given file system path. | |
244 * | |
245 * @param path a file system path denoting a classpath entry | |
246 */ | |
247 public static Entry createEntry(String path) { | |
248 final File pathFile = new File(path); | |
249 if (pathFile.isDirectory()) { | |
250 return new Directory(pathFile); | |
251 } else if (path.endsWith(".zip") || path.endsWith(".jar")) { | |
252 if (pathFile.exists() && pathFile.isFile()) { | |
253 return new Archive(pathFile); | |
254 } | |
255 } | |
256 //ProgramWarning.message("Class path entry is neither a directory nor a JAR file: " + path); | |
257 return new PlainFile(pathFile); | |
258 } | |
259 | |
260 /** | |
261 * Creates a new classpath from an array of classpath entries. | |
262 * | |
263 * @param paths an array of classpath entries | |
264 */ | |
265 public Classpath(String[] paths) { | |
266 final Entry[] entryArray = new Entry[paths.length]; | |
267 for (int i = 0; i < paths.length; ++i) { | |
268 final String path = paths[i]; | |
269 entryArray[i] = createEntry(path); | |
270 } | |
271 this.entries = Arrays.asList(entryArray); | |
272 } | |
273 | |
274 /** | |
275 * Creates a new classpath from a sequence of classpath entries. | |
276 * | |
277 * @param paths a sequence of classpath entries | |
278 */ | |
279 public Classpath(List<Entry> entries) { | |
280 this.entries = entries; | |
281 } | |
282 | |
283 /** | |
284 * Creates a new classpath by parsing a string of classpath entries separated by the system dependent | |
285 * {@linkplain File#pathSeparator path separator}. | |
286 * | |
287 * @param paths a string of classpath entries separated by ':' or ';' | |
288 */ | |
289 public Classpath(String paths) { | |
290 this(paths.split(File.pathSeparator)); | |
291 } | |
292 | |
293 /** | |
294 * Gets the classpath derived from the value of the {@code "java.ext.dirs"} system property. | |
295 * | |
296 * @see "http://java.sun.com/javase/6/docs/technotes/guides/extensions/extensions.html" | |
297 */ | |
298 private static String extensionClasspath() { | |
299 final String extDirs = System.getProperty("java.ext.dirs"); | |
300 if (extDirs != null) { | |
301 final StringBuilder buf = new StringBuilder(); | |
302 for (String extDirPath : extDirs.split(File.pathSeparator)) { | |
303 final File extDir = new File(extDirPath); | |
304 if (extDir.isDirectory()) { | |
305 for (File file : extDir.listFiles()) { | |
306 if (file.isDirectory() || | |
307 (file.isFile() && (file.getName().endsWith(".jar") || file.getName().endsWith(".zip")))) { | |
308 if (buf.length() != 0) { | |
309 buf.append(File.pathSeparatorChar); | |
310 } | |
311 buf.append(file.getAbsolutePath()); | |
312 } | |
313 } | |
314 } else { | |
315 // Ignore non-directory | |
316 } | |
317 } | |
318 if (buf.length() != 0) { | |
319 buf.append(File.pathSeparatorChar); | |
320 return buf.toString(); | |
321 } | |
322 } | |
323 return ""; | |
324 } | |
325 | |
326 /** | |
327 * Gets a classpath corresponding to the class search order used by the application class loader. | |
328 */ | |
329 public static Classpath fromSystem() { | |
330 final String value = System.getProperty("sun.boot.class.path") + File.pathSeparator + extensionClasspath() + System.getProperty("java.class.path"); | |
331 return new Classpath(value.split(File.pathSeparator)); | |
332 } | |
333 | |
334 /** | |
335 * Gets a classpath corresponding to the class search order used by the boot class loader. | |
336 * */ | |
337 public static Classpath bootClassPath() { | |
338 return bootClassPath(null); | |
339 } | |
340 | |
341 /** | |
342 * Gets a classpath corresponding to the class search order used by the boot class loader. | |
343 * @param extraPath an additional path to append to the system property or null if none | |
344 */ | |
345 public static Classpath bootClassPath(String extraPath) { | |
346 String value = System.getProperty("sun.boot.class.path"); | |
347 if (value == null) { | |
348 return EMPTY; | |
349 } | |
350 if (extraPath != null) { | |
351 value = value + File.pathSeparator + extraPath; | |
352 } | |
353 return new Classpath(value.split(File.pathSeparator)); | |
354 } | |
355 | |
356 /** | |
357 * Gets a new classpath obtained by prepending a given classpath to this class classpath. | |
358 * | |
359 * @param classpath the classpath to prepend to this classpath | |
360 * @return the result of prepending {@code classpath} to this classpath | |
361 */ | |
362 public Classpath prepend(Classpath classpath) { | |
363 ArrayList<Entry> entries = new ArrayList<Entry>(this.entries.size() + classpath.entries.size()); | |
364 entries.addAll(classpath.entries); | |
365 entries.addAll(this.entries); | |
366 return new Classpath(entries); | |
367 } | |
368 | |
369 /** | |
370 * Gets a new classpath obtained by prepending a given classpath to this class classpath. | |
371 * | |
372 * @param classpath the classpath to prepend to this classpath | |
373 * @return the result of prepending {@code classpath} to this classpath | |
374 */ | |
375 public Classpath prepend(String path) { | |
376 ArrayList<Entry> entries = new ArrayList<Entry>(this.entries.size()); | |
377 entries.add(createEntry(path)); | |
378 entries.addAll(this.entries); | |
379 return new Classpath(entries); | |
380 } | |
381 | |
382 /** | |
383 * Searches for a class file denoted by a given class name on this classpath and returns its contents in a byte array if | |
384 * found. Any IO exception that occurs when reading is silently ignored. | |
385 * | |
386 * @param className a fully qualified class name (e.g. "java.lang.Class") | |
387 * @return the contents of the file available on the classpath whose name is computed as | |
388 * {@code className.replace('.', '/')}. If no such file is available on this class path or if | |
389 * reading the file produces an IO exception, then null is returned. | |
390 */ | |
391 public ClasspathFile readClassFile(String className) { | |
392 return readFile(className, ".class"); | |
393 } | |
394 | |
395 /** | |
396 * Searches for a file denoted by a given class name on this classpath and returns its contents in a byte array if | |
397 * found. Any IO exception that occurs when reading is silently ignored. | |
398 * | |
399 * @param className a fully qualified class name (e.g. "java.lang.Class") | |
400 * @param extension a file extension | |
401 * @return the contents of the file available on the classpath whose name is computed as | |
402 * {@code className.replace('.', '/') + extension}. If no such file is available on this class path or if | |
403 * reading the file produces an IO exception, then null is returned. | |
404 */ | |
405 public ClasspathFile readFile(String className, String extension) { | |
406 final String path = className.replace('.', '/') + extension; | |
407 for (Entry entry : entries()) { | |
408 ClasspathFile classpathFile = entry.readFile(path); | |
409 if (classpathFile != null) { | |
410 return classpathFile; | |
411 } | |
412 } | |
413 return null; | |
414 } | |
415 | |
416 /** | |
417 * Searches for an existing file corresponding to a directory entry in this classpath composed with a given path | |
418 * suffix. | |
419 * | |
420 * @param suffix a file path relative to a directory entry of this classpath | |
421 * @return a file corresponding to the {@linkplain File#File(File, String) composition} of the first directory entry | |
422 * of this classpath with {@code suffix} that denotes an existing file or null if so such file exists | |
423 */ | |
424 public File findFile(String suffix) { | |
425 for (Entry entry : entries()) { | |
426 if (entry instanceof Directory) { | |
427 final File file = new File(((Directory) entry).directory, suffix); | |
428 if (file.exists()) { | |
429 return file; | |
430 } | |
431 } | |
432 } | |
433 return null; | |
434 } | |
435 | |
436 public static byte[] readZipEntry(ZipFile zipFile, ZipEntry zipEntry) throws IOException { | |
437 final byte[] bytes = new byte[(int) zipEntry.getSize()]; | |
438 final InputStream zipStream = new BufferedInputStream(zipFile.getInputStream(zipEntry), bytes.length); | |
439 try { | |
440 int offset = 0; | |
441 while (offset < bytes.length) { | |
442 final int n = zipStream.read(bytes, offset, bytes.length - offset); | |
443 if (n <= 0) { | |
444 //ProgramWarning.message("truncated ZIP file: " + zipFile); | |
445 } | |
446 offset += n; | |
447 } | |
448 } finally { | |
449 zipStream.close(); | |
450 } | |
451 return bytes; | |
452 } | |
453 | |
454 @Override | |
455 public String toString() { | |
456 if (entries == null || entries.isEmpty()) { | |
457 return ""; | |
458 } | |
459 String s = entries.toString().replace(", ", File.pathSeparator); | |
460 return s.substring(1, s.length() - 1); | |
461 } | |
462 | |
463 /** | |
464 * Converts this object to a String array with one array element for each classpath entry. | |
465 * | |
466 * @return the newly created String array with one element per classpath entry | |
467 */ | |
468 public String[] toStringArray() { | |
469 final String[] result = new String[entries().size()]; | |
470 int z = 0; | |
471 for (Classpath.Entry e : entries()) { | |
472 result[z] = e.path(); | |
473 z++; | |
474 } | |
475 return result; | |
476 } | |
477 } |