Mercurial > hg > truffle
view graal/com.oracle.max.base/src/com/sun/max/program/Classpath.java @ 4186:71a2cd79c375
Made stdout for mx unbuffered.
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Tue, 03 Jan 2012 13:53:38 +0100 |
parents | bc8527f3071c |
children |
line wrap: on
line source
/* * 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> newEntries = new ArrayList<>(this.entries.size() + classpath.entries.size()); newEntries.addAll(classpath.entries); newEntries.addAll(this.entries); return new Classpath(newEntries); } /** * 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> newEntries = new ArrayList<>(this.entries.size()); newEntries.add(createEntry(path)); newEntries.addAll(this.entries); return new Classpath(newEntries); } /** * 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; } }