This is NOT part of any API supported by Sun Microsystems. * If you write code that depends on this, you do so at your own risk. @@ -74,14 +76,7 @@ protected abstract String inferBinaryName(Iterable extends File> path); protected static JavaFileObject.Kind getKind(String filename) { - if (filename.endsWith(CLASS.extension)) - return CLASS; - else if (filename.endsWith(SOURCE.extension)) - return SOURCE; - else if (filename.endsWith(HTML.extension)) - return HTML; - else - return OTHER; + return BaseFileManager.getKind(filename); } protected static String removeExtension(String fileName) { diff -r 5c18795ef8e4 -r bc0d5b3c3b2d langtools/src/share/classes/com/sun/tools/javac/file/CloseableURLClassLoader.java --- a/langtools/src/share/classes/com/sun/tools/javac/file/CloseableURLClassLoader.java Thu Dec 10 20:35:31 2009 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * Copyright 2007 Sun Microsystems, Inc. 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. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun in the LICENSE file that accompanied this code. - * - * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. - */ - -package com.sun.tools.javac.file; - -import java.io.Closeable; -import java.io.IOException; -import java.lang.reflect.Field; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.jar.JarFile; - -/** - * A URLClassLoader that also implements Closeable. - * Reflection is used to access internal data structures in the URLClassLoader, - * since no public API exists for this purpose. Therefore this code is somewhat - * fragile. Caveat emptor. - * @throws Error if the internal data structures are not as expected. - * - *
This is NOT part of any API supported by Sun Microsystems. If
- * you write code that depends on this, you do so at your own risk.
- * This code and its internal interfaces are subject to change or
- * deletion without notice.
- */
-class CloseableURLClassLoader
- extends URLClassLoader implements Closeable {
- CloseableURLClassLoader(URL[] urls, ClassLoader parent) throws Error {
- super(urls, parent);
- try {
- getLoaders(); //proactive check that URLClassLoader is as expected
- } catch (Throwable t) {
- throw new Error("cannot create CloseableURLClassLoader", t);
- }
- }
-
- /**
- * Close any jar files that may have been opened by the class loader.
- * Reflection is used to access the jar files in the URLClassLoader's
- * internal data structures.
- * @throws java.io.IOException if the jar files cannot be found for any
- * reson, or if closing the jar file itself causes an IOException.
- */
- public void close() throws IOException {
- try {
- for (Object l: getLoaders()) {
- if (l.getClass().getName().equals("sun.misc.URLClassPath$JarLoader")) {
- Field jarField = l.getClass().getDeclaredField("jar");
- JarFile jar = (JarFile) getField(l, jarField);
- if (jar != null) {
- //System.err.println("CloseableURLClassLoader: closing " + jar);
- jar.close();
- }
- }
- }
- } catch (Throwable t) {
- IOException e = new IOException("cannot close class loader");
- e.initCause(t);
- throw e;
- }
- }
-
- private ArrayList> getLoaders()
- throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException
- {
- Field ucpField = URLClassLoader.class.getDeclaredField("ucp");
- Object urlClassPath = getField(this, ucpField);
- if (urlClassPath == null)
- throw new AssertionError("urlClassPath not set in URLClassLoader");
- Field loadersField = urlClassPath.getClass().getDeclaredField("loaders");
- return (ArrayList>) getField(urlClassPath, loadersField);
- }
-
- private Object getField(Object o, Field f)
- throws IllegalArgumentException, IllegalAccessException {
- boolean prev = f.isAccessible();
- try {
- f.setAccessible(true);
- return f.get(o);
- } finally {
- f.setAccessible(prev);
- }
- }
-
-}
diff -r 5c18795ef8e4 -r bc0d5b3c3b2d langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java
--- a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Thu Dec 10 20:35:31 2009 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Fri Dec 11 14:26:27 2009 -0800
@@ -26,29 +26,16 @@
package com.sun.tools.javac.file;
import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStreamWriter;
-import java.lang.ref.SoftReference;
-import java.lang.reflect.Constructor;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
-import java.net.URLClassLoader;
-import java.nio.ByteBuffer;
import java.nio.CharBuffer;
-import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CoderResult;
-import java.nio.charset.CodingErrorAction;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -66,18 +53,13 @@
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
-import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.file.RelativePath.RelativeFile;
import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
-import com.sun.tools.javac.main.JavacOption;
import com.sun.tools.javac.main.OptionName;
-import com.sun.tools.javac.main.RecognizedOptions;
+import com.sun.tools.javac.util.BaseFileManager;
import com.sun.tools.javac.util.Context;
-import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
-import com.sun.tools.javac.util.Log;
-import com.sun.tools.javac.util.Options;
import static javax.tools.StandardLocation.*;
import static com.sun.tools.javac.main.OptionName.*;
@@ -91,7 +73,7 @@
* This code and its internal interfaces are subject to change or
* deletion without notice.
*/
-public class JavacFileManager implements StandardJavaFileManager {
+public class JavacFileManager extends BaseFileManager implements StandardJavaFileManager {
boolean useZipFileIndex;
@@ -102,17 +84,10 @@
return buffer.toString().toCharArray();
}
- /**
- * The log to be used for error reporting.
- */
- protected Log log;
-
/** Encapsulates knowledge of paths
*/
private Paths paths;
- private Options options;
-
private FSInfo fsInfo;
private final File uninited = new File("U N I N I T E D");
@@ -134,12 +109,6 @@
protected boolean mmappedIO;
protected boolean ignoreSymbolFile;
- protected String classLoaderClass;
-
- /**
- * User provided charset (through javax.tools).
- */
- protected Charset charset;
/**
* Register a Context.Factory to create a JavacFileManager.
@@ -157,18 +126,18 @@
* it as the JavaFileManager for that context.
*/
public JavacFileManager(Context context, boolean register, Charset charset) {
+ super(charset);
if (register)
context.put(JavaFileManager.class, this);
- byteBufferCache = new ByteBufferCache();
- this.charset = charset;
setContext(context);
}
/**
* Set the context for JavacFileManager.
*/
+ @Override
public void setContext(Context context) {
- log = Log.instance(context);
+ super.setContext(context);
if (paths == null) {
paths = Paths.instance(context);
} else {
@@ -177,14 +146,12 @@
paths.setContext(context);
}
- options = Options.instance(context);
fsInfo = FSInfo.instance(context);
useZipFileIndex = System.getProperty("useJavaUtilZip") == null;// TODO: options.get("useJavaUtilZip") == null;
mmappedIO = options.get("mmappedIO") != null;
ignoreSymbolFile = options.get("ignore.symbol.file") != null;
- classLoaderClass = options.get("procloader");
}
public JavaFileObject getFileForInput(String name) {
@@ -214,17 +181,6 @@
return getJavaFileObjectsFromStrings(Arrays.asList(nullCheck(names)));
}
- protected JavaFileObject.Kind getKind(String extension) {
- if (extension.equals(JavaFileObject.Kind.CLASS.extension))
- return JavaFileObject.Kind.CLASS;
- else if (extension.equals(JavaFileObject.Kind.SOURCE.extension))
- return JavaFileObject.Kind.SOURCE;
- else if (extension.equals(JavaFileObject.Kind.HTML.extension))
- return JavaFileObject.Kind.HTML;
- else
- return JavaFileObject.Kind.OTHER;
- }
-
private static boolean isValidName(String name) {
// Arguably, isValidName should reject keywords (such as in SourceVersion.isName() ),
// but the set of keywords depends on the source level, and we don't want
@@ -359,9 +315,7 @@
}
private boolean isValidFile(String s, Set Just as a Path is somewhat analagous to a File, so too is this
+ * JavacPathFileManager analogous to JavacFileManager, as it relates to the
+ * support of FileObjects based on File objects (i.e. just RegularFileObject,
+ * not ZipFileObject and its variants.)
+ *
+ * The default values for the standard locations supported by this file
+ * manager are the same as the default values provided by JavacFileManager --
+ * i.e. as determined by the javac.file.Paths class. To override these values,
+ * call {@link #setLocation}.
+ *
+ * To reduce confusion with Path objects, the locations such as "class path",
+ * "source path", etc, are generically referred to here as "search paths".
+ *
+ * This is NOT part of any API supported by Sun Microsystems. If
+ * you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.
+ */
+public class JavacPathFileManager extends BaseFileManager implements PathFileManager {
+ protected FileSystem defaultFileSystem;
+
+ /**
+ * Create a JavacPathFileManager using a given context, optionally registering
+ * it as the JavaFileManager for that context.
+ */
+ public JavacPathFileManager(Context context, boolean register, Charset charset) {
+ super(charset);
+ if (register)
+ context.put(JavaFileManager.class, this);
+ pathsForLocation = new HashMap This is NOT part of any API supported by Sun Microsystems. If
+ * you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.
+ */
+public interface PathFileManager extends JavaFileManager {
+ /**
+ * Get the default file system used to create paths. If no value has been
+ * set, the default file system is {@link FileSystems#getDefault}.
+ */
+ FileSystem getDefaultFileSystem();
+
+ /**
+ * Set the default file system used to create paths.
+ * @param fs the default file system used to create any new paths.
+ */
+ void setDefaultFileSystem(FileSystem fs);
+
+ /**
+ * Get file objects representing the given files.
+ *
+ * @param paths a list of paths
+ * @return a list of file objects
+ * @throws IllegalArgumentException if the list of paths includes
+ * a directory
+ */
+ Iterable extends JavaFileObject> getJavaFileObjectsFromPaths(
+ Iterable extends Path> paths);
+
+ /**
+ * Get file objects representing the given paths.
+ * Convenience method equivalent to:
+ *
+ * PathFileObjects are, for the most part, straightforward wrappers around
+ * Path objects. The primary complexity is the support for "inferBinaryName".
+ * This is left as an abstract method, implemented by each of a number of
+ * different factory methods, which compute the binary name based on
+ * information available at the time the file object is created.
+ *
+ * This is NOT part of any API supported by Sun Microsystems. If
+ * you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.
+ */
+abstract class PathFileObject implements JavaFileObject {
+ private JavacPathFileManager fileManager;
+ private Path path;
+
+ /**
+ * Create a PathFileObject within a directory, such that the binary name
+ * can be inferred from the relationship to the parent directory.
+ */
+ static PathFileObject createDirectoryPathFileObject(JavacPathFileManager fileManager,
+ final Path path, final Path dir) {
+ return new PathFileObject(fileManager, path) {
+ @Override
+ String inferBinaryName(Iterable extends Path> paths) {
+ return toBinaryName(dir.relativize(path));
+ }
+ };
+ }
+
+ /**
+ * Create a PathFileObject in a file system such as a jar file, such that
+ * the binary name can be inferred from its position within the filesystem.
+ */
+ static PathFileObject createJarPathFileObject(JavacPathFileManager fileManager,
+ final Path path) {
+ return new PathFileObject(fileManager, path) {
+ @Override
+ String inferBinaryName(Iterable extends Path> paths) {
+ return toBinaryName(path);
+ }
+ };
+ }
+
+ /**
+ * Create a PathFileObject whose binary name can be inferred from the
+ * relative path to a sibling.
+ */
+ static PathFileObject createSiblingPathFileObject(JavacPathFileManager fileManager,
+ final Path path, final String relativePath) {
+ return new PathFileObject(fileManager, path) {
+ @Override
+ String inferBinaryName(Iterable extends Path> paths) {
+ return toBinaryName(relativePath, "/");
+ }
+ };
+ }
+
+ /**
+ * Create a PathFileObject whose binary name might be inferred from its
+ * position on a search path.
+ */
+ static PathFileObject createSimplePathFileObject(JavacPathFileManager fileManager,
+ final Path path) {
+ return new PathFileObject(fileManager, path) {
+ @Override
+ String inferBinaryName(Iterable extends Path> paths) {
+ Path absPath = path.toAbsolutePath();
+ for (Path p: paths) {
+ Path ap = p.toAbsolutePath();
+ if (absPath.startsWith(ap)) {
+ try {
+ Path rp = ap.relativize(absPath);
+ if (rp != null) // maybe null if absPath same as ap
+ return toBinaryName(rp);
+ } catch (IllegalArgumentException e) {
+ // ignore this p if cannot relativize path to p
+ }
+ }
+ }
+ return null;
+ }
+ };
+ }
+
+ protected PathFileObject(JavacPathFileManager fileManager, Path path) {
+ fileManager.getClass(); // null check
+ path.getClass(); // null check
+ this.fileManager = fileManager;
+ this.path = path;
+ }
+
+ abstract String inferBinaryName(Iterable extends Path> paths);
+
+ /**
+ * Return the Path for this object.
+ * @return the Path for this object.
+ */
+ Path getPath() {
+ return path;
+ }
+
+ @Override
+ public Kind getKind() {
+ return BaseFileManager.getKind(path.getName().toString());
+ }
+
+ @Override
+ public boolean isNameCompatible(String simpleName, Kind kind) {
+ simpleName.getClass();
+ // null check
+ if (kind == Kind.OTHER && getKind() != kind) {
+ return false;
+ }
+ String sn = simpleName + kind.extension;
+ String pn = path.getName().toString();
+ if (pn.equals(sn)) {
+ return true;
+ }
+ if (pn.equalsIgnoreCase(sn)) {
+ try {
+ // allow for Windows
+ return path.toRealPath(false).getName().toString().equals(sn);
+ } catch (IOException e) {
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public NestingKind getNestingKind() {
+ return null;
+ }
+
+ @Override
+ public Modifier getAccessLevel() {
+ return null;
+ }
+
+ @Override
+ public URI toUri() {
+ return path.toUri();
+ }
+
+ @Override
+ public String getName() {
+ return path.toString();
+ }
+
+ @Override
+ public InputStream openInputStream() throws IOException {
+ return path.newInputStream();
+ }
+
+ @Override
+ public OutputStream openOutputStream() throws IOException {
+ ensureParentDirectoriesExist();
+ return path.newOutputStream();
+ }
+
+ @Override
+ public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
+ CharsetDecoder decoder = fileManager.getDecoder(fileManager.getEncodingName(), ignoreEncodingErrors);
+ return new InputStreamReader(openInputStream(), decoder);
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ CharBuffer cb = fileManager.getCachedContent(this);
+ if (cb == null) {
+ InputStream in = openInputStream();
+ try {
+ ByteBuffer bb = fileManager.makeByteBuffer(in);
+ JavaFileObject prev = fileManager.log.useSource(this);
+ try {
+ cb = fileManager.decode(bb, ignoreEncodingErrors);
+ } finally {
+ fileManager.log.useSource(prev);
+ }
+ fileManager.recycleByteBuffer(bb);
+ if (!ignoreEncodingErrors) {
+ fileManager.cache(this, cb);
+ }
+ } finally {
+ in.close();
+ }
+ }
+ return cb;
+ }
+
+ @Override
+ public Writer openWriter() throws IOException {
+ ensureParentDirectoriesExist();
+ return new OutputStreamWriter(path.newOutputStream(), fileManager.getEncodingName());
+ }
+
+ @Override
+ public long getLastModified() {
+ try {
+ BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path);
+ return attrs.lastModifiedTime().toMillis();
+ } catch (IOException e) {
+ return -1;
+ }
+ }
+
+ @Override
+ public boolean delete() {
+ try {
+ path.delete();
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ public boolean isSameFile(PathFileObject other) {
+ try {
+ return path.isSameFile(other.path);
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return (other instanceof PathFileObject && path.equals(((PathFileObject) other).path));
+ }
+
+ @Override
+ public int hashCode() {
+ return path.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[" + path + "]";
+ }
+
+ private void ensureParentDirectoriesExist() throws IOException {
+ Path parent = path.getParent();
+ if (parent != null)
+ Files.createDirectories(parent);
+ }
+
+ private long size() {
+ try {
+ BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path);
+ return attrs.size();
+ } catch (IOException e) {
+ return -1;
+ }
+ }
+
+ protected static String toBinaryName(Path relativePath) {
+ return toBinaryName(relativePath.toString(),
+ relativePath.getFileSystem().getSeparator());
+ }
+
+ protected static String toBinaryName(String relativePath, String sep) {
+ return removeExtension(relativePath).replaceAll(sep, ".");
+ }
+
+ protected static String removeExtension(String fileName) {
+ int lastDot = fileName.lastIndexOf(".");
+ return (lastDot == -1 ? fileName : fileName.substring(0, lastDot));
+ }
+}
diff -r 5c18795ef8e4 -r bc0d5b3c3b2d langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java Fri Dec 11 14:26:27 2009 -0800
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.util;
+
+import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.main.JavacOption;
+import com.sun.tools.javac.main.OptionName;
+import com.sun.tools.javac.main.RecognizedOptions;
+import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+
+/**
+ * Utility methods for building a filemanager.
+ * There are no references here to file-system specific objects such as
+ * java.io.File or java.nio.file.Path.
+ */
+public class BaseFileManager {
+ protected BaseFileManager(Charset charset) {
+ this.charset = charset;
+ byteBufferCache = new ByteBufferCache();
+ }
+
+ /**
+ * Set the context for JavacPathFileManager.
+ */
+ protected void setContext(Context context) {
+ log = Log.instance(context);
+ options = Options.instance(context);
+ classLoaderClass = options.get("procloader");
+ }
+
+ /**
+ * The log to be used for error reporting.
+ */
+ public Log log;
+
+ /**
+ * User provided charset (through javax.tools).
+ */
+ protected Charset charset;
+
+ protected Options options;
+
+ protected String classLoaderClass;
+
+ protected Source getSource() {
+ String sourceName = options.get(OptionName.SOURCE);
+ Source source = null;
+ if (sourceName != null)
+ source = Source.lookup(sourceName);
+ return (source != null ? source : Source.DEFAULT);
+ }
+
+ protected ClassLoader getClassLoader(URL[] urls) {
+ ClassLoader thisClassLoader = getClass().getClassLoader();
+
+ // Bug: 6558476
+ // Ideally, ClassLoader should be Closeable, but before JDK7 it is not.
+ // On older versions, try the following, to get a closeable classloader.
+
+ // 1: Allow client to specify the class to use via hidden option
+ if (classLoaderClass != null) {
+ try {
+ Class extends ClassLoader> loader =
+ Class.forName(classLoaderClass).asSubclass(ClassLoader.class);
+ Class>[] constrArgTypes = { URL[].class, ClassLoader.class };
+ Constructor extends ClassLoader> constr = loader.getConstructor(constrArgTypes);
+ return constr.newInstance(new Object[] { urls, thisClassLoader });
+ } catch (Throwable t) {
+ // ignore errors loading user-provided class loader, fall through
+ }
+ }
+
+ // 2: If URLClassLoader implements Closeable, use that.
+ if (Closeable.class.isAssignableFrom(URLClassLoader.class))
+ return new URLClassLoader(urls, thisClassLoader);
+
+ // 3: Try using private reflection-based CloseableURLClassLoader
+ try {
+ return new CloseableURLClassLoader(urls, thisClassLoader);
+ } catch (Throwable t) {
+ // ignore errors loading workaround class loader, fall through
+ }
+
+ // 4: If all else fails, use plain old standard URLClassLoader
+ return new URLClassLoader(urls, thisClassLoader);
+ }
+
+ // This is NOT part of any API supported by Sun Microsystems. If
+ * you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.
+ */
+public class CloseableURLClassLoader
+ extends URLClassLoader implements Closeable {
+ public CloseableURLClassLoader(URL[] urls, ClassLoader parent) throws Error {
+ super(urls, parent);
+ try {
+ getLoaders(); //proactive check that URLClassLoader is as expected
+ } catch (Throwable t) {
+ throw new Error("cannot create CloseableURLClassLoader", t);
+ }
+ }
+
+ /**
+ * Close any jar files that may have been opened by the class loader.
+ * Reflection is used to access the jar files in the URLClassLoader's
+ * internal data structures.
+ * @throws java.io.IOException if the jar files cannot be found for any
+ * reson, or if closing the jar file itself causes an IOException.
+ */
+ @Override
+ public void close() throws IOException {
+ try {
+ for (Object l: getLoaders()) {
+ if (l.getClass().getName().equals("sun.misc.URLClassPath$JarLoader")) {
+ Field jarField = l.getClass().getDeclaredField("jar");
+ JarFile jar = (JarFile) getField(l, jarField);
+ if (jar != null) {
+ //System.err.println("CloseableURLClassLoader: closing " + jar);
+ jar.close();
+ }
+ }
+ }
+ } catch (Throwable t) {
+ IOException e = new IOException("cannot close class loader");
+ e.initCause(t);
+ throw e;
+ }
+ }
+
+ private ArrayList> getLoaders()
+ throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException
+ {
+ Field ucpField = URLClassLoader.class.getDeclaredField("ucp");
+ Object urlClassPath = getField(this, ucpField);
+ if (urlClassPath == null)
+ throw new AssertionError("urlClassPath not set in URLClassLoader");
+ Field loadersField = urlClassPath.getClass().getDeclaredField("loaders");
+ return (ArrayList>) getField(urlClassPath, loadersField);
+ }
+
+ private Object getField(Object o, Field f)
+ throws IllegalArgumentException, IllegalAccessException {
+ boolean prev = f.isAccessible();
+ try {
+ f.setAccessible(true);
+ return f.get(o);
+ } finally {
+ f.setAccessible(prev);
+ }
+ }
+
+}
diff -r 5c18795ef8e4 -r bc0d5b3c3b2d langtools/src/share/classes/javax/tools/StandardJavaFileManager.java
--- a/langtools/src/share/classes/javax/tools/StandardJavaFileManager.java Thu Dec 10 20:35:31 2009 -0800
+++ b/langtools/src/share/classes/javax/tools/StandardJavaFileManager.java Fri Dec 11 14:26:27 2009 -0800
@@ -28,7 +28,6 @@
import java.io.File;
import java.io.IOException;
import java.util.*;
-import java.util.concurrent.*;
/**
* File manager based on {@linkplain File java.io.File}. A common way
diff -r 5c18795ef8e4 -r bc0d5b3c3b2d langtools/test/tools/javac/nio/compileTest/CompileTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/nio/compileTest/CompileTest.java Fri Dec 11 14:26:27 2009 -0800
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @compile HelloPathWorld.java
+ * @run main CompileTest
+ */
+
+import java.io.*;
+import java.nio.file.*;
+import java.util.*;
+import java.util.jar.*;
+import javax.tools.*;
+
+import com.sun.tools.javac.nio.*;
+import com.sun.tools.javac.util.Context;
+import java.nio.file.spi.FileSystemProvider;
+
+
+public class CompileTest {
+ public static void main(String[] args) throws Exception {
+ new CompileTest().run();
+ }
+
+ public void run() throws Exception {
+ File rtDir = new File("rt.dir");
+ File javaHome = new File(System.getProperty("java.home"));
+ if (javaHome.getName().equals("jre"))
+ javaHome = javaHome.getParentFile();
+ File rtJar = new File(new File(new File(javaHome, "jre"), "lib"), "rt.jar");
+ expand(rtJar, rtDir);
+
+ String[] rtDir_opts = {
+ "-bootclasspath", rtDir.toString(),
+ "-classpath", "",
+ "-sourcepath", "",
+ "-extdirs", ""
+ };
+ test(rtDir_opts, "HelloPathWorld");
+
+ if (isJarFileSystemAvailable()) {
+ String[] rtJar_opts = {
+ "-bootclasspath", rtJar.toString(),
+ "-classpath", "",
+ "-sourcepath", "",
+ "-extdirs", ""
+ };
+ test(rtJar_opts, "HelloPathWorld");
+
+ String[] default_opts = { };
+ test(default_opts, "HelloPathWorld");
+
+ // finally, a non-trivial program
+ test(default_opts, "CompileTest");
+ } else
+ System.err.println("jar file system not available: test skipped");
+ }
+
+ void test(String[] opts, String className) throws Exception {
+ count++;
+ System.err.println("Test " + count + " " + Arrays.asList(opts) + " " + className);
+ Path testSrcDir = Paths.get(System.getProperty("test.src"));
+ Path testClassesDir = Paths.get(System.getProperty("test.classes"));
+ Path classes = Paths.get("classes." + count);
+ classes.createDirectory();
+
+ Context ctx = new Context();
+ PathFileManager fm = new JavacPathFileManager(ctx, true, null);
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ List
+ * getJavaFileObjectsFromPaths({@linkplain java.util.Arrays#asList Arrays.asList}(paths))
+ *
+ *
+ * @param paths an array of paths
+ * @return a list of file objects
+ * @throws IllegalArgumentException if the array of files includes
+ * a directory
+ * @throws NullPointerException if the given array contains null
+ * elements
+ */
+ Iterable extends JavaFileObject> getJavaFileObjects(Path... paths);
+
+ /**
+ * Return the Path for a file object that has been obtained from this
+ * file manager.
+ *
+ * @param fo A file object that has been obtained from this file manager.
+ * @return The underlying Path object.
+ * @throws IllegalArgumentException is the file object was not obtained from
+ * from this file manager.
+ */
+ Path getPath(FileObject fo);
+
+ /**
+ * Get the search path associated with the given location.
+ *
+ * @param location a location
+ * @return a list of paths or {@code null} if this location has no
+ * associated search path
+ * @see #setLocation
+ */
+ Iterable extends Path> getLocation(Location location);
+
+ /**
+ * Associate the given search path with the given location. Any
+ * previous value will be discarded.
+ *
+ * @param location a location
+ * @param searchPath a list of files, if {@code null} use the default
+ * search path for this location
+ * @see #getLocation
+ * @throws IllegalArgumentException if location is an output
+ * location and searchpath does not contain exactly one element
+ * @throws IOException if location is an output location and searchpath
+ * does not represent an existing directory
+ */
+ void setLocation(Location location, Iterable extends Path> searchPath) throws IOException;
+}
diff -r 5c18795ef8e4 -r bc0d5b3c3b2d langtools/src/share/classes/com/sun/tools/javac/nio/PathFileObject.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/nio/PathFileObject.java Fri Dec 11 14:26:27 2009 -0800
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javac.nio;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharsetDecoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.Attributes;
+import java.nio.file.attribute.BasicFileAttributes;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.NestingKind;
+import javax.tools.JavaFileObject;
+
+import com.sun.tools.javac.util.BaseFileManager;
+
+
+/**
+ * Implementation of JavaFileObject using java.nio.file API.
+ *
+ *