Mercurial > hg > graal-compiler
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.base/src/com/sun/max/program/Classpath.java Sat Dec 17 19:59:18 2011 +0100 @@ -0,0 +1,477 @@ +/* + * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.max.program; + +import java.io.*; +import java.util.*; +import java.util.zip.*; + +import com.sun.max.io.*; + +/** + */ +public class Classpath { + + private static final List<Entry> EMPTY_LIST = Collections.emptyList(); + + public static final Classpath EMPTY = new Classpath(EMPTY_LIST); + + private final List<Entry> entries; + + /** + * An entry in a classpath is a file system path that denotes an existing {@linkplain Directory directory}, + * an existing {@linkplain Archive zip/jar} file or a {@linkplain PlainFile neither}. + */ + public abstract static class Entry { + + /** + * Gets the string representing the underlying path of this entry. + */ + public final String path() { + return file().getPath(); + } + + /** + * Gets the File object representing the underlying path of this entry. + */ + public abstract File file(); + + /** + * Determines if a given resource can be found under this entry. + * + * @param path a file path relative to this classpath entry. This values uses the '/' character as the path + * separator regardless of the {@linkplain File#separatorChar default} for the underlying platform. + */ + public abstract boolean contains(String path); + + /** + * Gets the contents of a file denoted by a given path that is relative to this classpath entry. If the denoted + * file does not exist under this classpath entry then {@code null} is returned. Any IO exception that occurs + * when reading is silently ignored. + * + * @param path a file path relative to this classpath entry. This values uses the '/' character as the path + * separator regardless of the {@linkplain File#separatorChar default} for the underlying platform. + */ + abstract ClasspathFile readFile(String path); + + public boolean isDirectory() { + return false; + } + + public boolean isArchive() { + return false; + } + + public boolean isPlainFile() { + return false; + } + + @Override + public String toString() { + return path(); + } + + public ZipFile zipFile() { + return null; + } + } + + /** + * Represents a classpath entry that is neither an existing directory nor an existing zip/jar archive file. + */ + static final class PlainFile extends Entry { + + private final File file; + + public PlainFile(File file) { + this.file = file; + } + + @Override + ClasspathFile readFile(String path) { + return null; + } + + @Override + public File file() { + return file; + } + + @Override + public boolean isPlainFile() { + return true; + } + + @Override + public boolean contains(String path) { + return false; + } + } + + /** + * Represents a classpath entry that is a path to an existing directory. + */ + static final class Directory extends Entry { + private final File directory; + + public Directory(File directory) { + this.directory = directory; + } + + @Override + ClasspathFile readFile(String path) { + final File file = new File(directory, File.separatorChar == '/' ? path : path.replace('/', File.separatorChar)); + if (file.exists()) { + try { + return new ClasspathFile(Files.toBytes(file), this); + } catch (IOException ioException) { + ProgramWarning.message("Error reading from " + file + ": " + ioException); + return null; + } + } + return null; + } + + @Override + public File file() { + return directory; + } + + @Override + public boolean isDirectory() { + return true; + } + + @Override + public boolean contains(String path) { + return new File(directory, File.separatorChar == '/' ? path : path.replace('/', File.separatorChar)).exists(); + } + } + + /** + * Represents a classpath entry that is a path to an existing zip/jar archive file. + */ + static final class Archive extends Entry { + + private final File file; + private ZipFile zipFile; + + public Archive(File file) { + this.file = file; + } + + @Override + public ZipFile zipFile() { + if (zipFile == null && file != null) { + try { + zipFile = new ZipFile(file); + } catch (IOException e) { + ProgramWarning.message("Error opening ZIP file: " + file.getPath()); + e.printStackTrace(); + } + } + return zipFile; + } + + @Override + public boolean contains(String path) { + final ZipFile zf = zipFile(); + if (zf == null) { + return false; + } + return zf.getEntry(path) != null; + } + + @Override + ClasspathFile readFile(String path) { + final ZipFile zf = zipFile(); + if (zf == null) { + return null; + } + try { + final ZipEntry zipEntry = zf.getEntry(path); + if (zipEntry != null) { + return new ClasspathFile(readZipEntry(zf, zipEntry), this); + } + } catch (IOException ioException) { + //ProgramWarning.message("could not read ZIP file: " + file); + } + return null; + } + + @Override + public File file() { + return file; + } + + @Override + public boolean isArchive() { + return true; + } + } + + /** + * Gets the ordered entries from which this classpath is composed. + * + * @return a sequence of {@code Entry} objects + */ + public List<Entry> entries() { + return entries; + } + + /** + * Creates a classpath {@link Entry} from a given file system path. + * + * @param path a file system path denoting a classpath entry + */ + public static Entry createEntry(String path) { + final File pathFile = new File(path); + if (pathFile.isDirectory()) { + return new Directory(pathFile); + } else if (path.endsWith(".zip") || path.endsWith(".jar")) { + if (pathFile.exists() && pathFile.isFile()) { + return new Archive(pathFile); + } + } + //ProgramWarning.message("Class path entry is neither a directory nor a JAR file: " + path); + return new PlainFile(pathFile); + } + + /** + * Creates a new classpath from an array of classpath entries. + * + * @param paths an array of classpath entries + */ + public Classpath(String[] paths) { + final Entry[] entryArray = new Entry[paths.length]; + for (int i = 0; i < paths.length; ++i) { + final String path = paths[i]; + entryArray[i] = createEntry(path); + } + this.entries = Arrays.asList(entryArray); + } + + /** + * Creates a new classpath from a sequence of classpath entries. + * + * @param paths a sequence of classpath entries + */ + public Classpath(List<Entry> entries) { + this.entries = entries; + } + + /** + * Creates a new classpath by parsing a string of classpath entries separated by the system dependent + * {@linkplain File#pathSeparator path separator}. + * + * @param paths a string of classpath entries separated by ':' or ';' + */ + public Classpath(String paths) { + this(paths.split(File.pathSeparator)); + } + + /** + * Gets the classpath derived from the value of the {@code "java.ext.dirs"} system property. + * + * @see "http://java.sun.com/javase/6/docs/technotes/guides/extensions/extensions.html" + */ + private static String extensionClasspath() { + final String extDirs = System.getProperty("java.ext.dirs"); + if (extDirs != null) { + final StringBuilder buf = new StringBuilder(); + for (String extDirPath : extDirs.split(File.pathSeparator)) { + final File extDir = new File(extDirPath); + if (extDir.isDirectory()) { + for (File file : extDir.listFiles()) { + if (file.isDirectory() || + (file.isFile() && (file.getName().endsWith(".jar") || file.getName().endsWith(".zip")))) { + if (buf.length() != 0) { + buf.append(File.pathSeparatorChar); + } + buf.append(file.getAbsolutePath()); + } + } + } else { + // Ignore non-directory + } + } + if (buf.length() != 0) { + buf.append(File.pathSeparatorChar); + return buf.toString(); + } + } + return ""; + } + + /** + * Gets a classpath corresponding to the class search order used by the application class loader. + */ + public static Classpath fromSystem() { + final String value = System.getProperty("sun.boot.class.path") + File.pathSeparator + extensionClasspath() + System.getProperty("java.class.path"); + return new Classpath(value.split(File.pathSeparator)); + } + + /** + * Gets a classpath corresponding to the class search order used by the boot class loader. + * */ + public static Classpath bootClassPath() { + return bootClassPath(null); + } + + /** + * Gets a classpath corresponding to the class search order used by the boot class loader. + * @param extraPath an additional path to append to the system property or null if none + */ + public static Classpath bootClassPath(String extraPath) { + String value = System.getProperty("sun.boot.class.path"); + if (value == null) { + return EMPTY; + } + if (extraPath != null) { + value = value + File.pathSeparator + extraPath; + } + return new Classpath(value.split(File.pathSeparator)); + } + + /** + * Gets a new classpath obtained by prepending a given classpath to this class classpath. + * + * @param classpath the classpath to prepend to this classpath + * @return the result of prepending {@code classpath} to this classpath + */ + public Classpath prepend(Classpath classpath) { + ArrayList<Entry> entries = new ArrayList<Entry>(this.entries.size() + classpath.entries.size()); + entries.addAll(classpath.entries); + entries.addAll(this.entries); + return new Classpath(entries); + } + + /** + * Gets a new classpath obtained by prepending a given classpath to this class classpath. + * + * @param classpath the classpath to prepend to this classpath + * @return the result of prepending {@code classpath} to this classpath + */ + public Classpath prepend(String path) { + ArrayList<Entry> entries = new ArrayList<Entry>(this.entries.size()); + entries.add(createEntry(path)); + entries.addAll(this.entries); + return new Classpath(entries); + } + + /** + * Searches for a class file denoted by a given class name on this classpath and returns its contents in a byte array if + * found. Any IO exception that occurs when reading is silently ignored. + * + * @param className a fully qualified class name (e.g. "java.lang.Class") + * @return the contents of the file available on the classpath whose name is computed as + * {@code className.replace('.', '/')}. If no such file is available on this class path or if + * reading the file produces an IO exception, then null is returned. + */ + public ClasspathFile readClassFile(String className) { + return readFile(className, ".class"); + } + + /** + * Searches for a file denoted by a given class name on this classpath and returns its contents in a byte array if + * found. Any IO exception that occurs when reading is silently ignored. + * + * @param className a fully qualified class name (e.g. "java.lang.Class") + * @param extension a file extension + * @return the contents of the file available on the classpath whose name is computed as + * {@code className.replace('.', '/') + extension}. If no such file is available on this class path or if + * reading the file produces an IO exception, then null is returned. + */ + public ClasspathFile readFile(String className, String extension) { + final String path = className.replace('.', '/') + extension; + for (Entry entry : entries()) { + ClasspathFile classpathFile = entry.readFile(path); + if (classpathFile != null) { + return classpathFile; + } + } + return null; + } + + /** + * Searches for an existing file corresponding to a directory entry in this classpath composed with a given path + * suffix. + * + * @param suffix a file path relative to a directory entry of this classpath + * @return a file corresponding to the {@linkplain File#File(File, String) composition} of the first directory entry + * of this classpath with {@code suffix} that denotes an existing file or null if so such file exists + */ + public File findFile(String suffix) { + for (Entry entry : entries()) { + if (entry instanceof Directory) { + final File file = new File(((Directory) entry).directory, suffix); + if (file.exists()) { + return file; + } + } + } + return null; + } + + public static byte[] readZipEntry(ZipFile zipFile, ZipEntry zipEntry) throws IOException { + final byte[] bytes = new byte[(int) zipEntry.getSize()]; + final InputStream zipStream = new BufferedInputStream(zipFile.getInputStream(zipEntry), bytes.length); + try { + int offset = 0; + while (offset < bytes.length) { + final int n = zipStream.read(bytes, offset, bytes.length - offset); + if (n <= 0) { + //ProgramWarning.message("truncated ZIP file: " + zipFile); + } + offset += n; + } + } finally { + zipStream.close(); + } + return bytes; + } + + @Override + public String toString() { + if (entries == null || entries.isEmpty()) { + return ""; + } + String s = entries.toString().replace(", ", File.pathSeparator); + return s.substring(1, s.length() - 1); + } + + /** + * Converts this object to a String array with one array element for each classpath entry. + * + * @return the newly created String array with one element per classpath entry + */ + public String[] toStringArray() { + final String[] result = new String[entries().size()]; + int z = 0; + for (Classpath.Entry e : entries()) { + result[z] = e.path(); + z++; + } + return result; + } +}