提交 10e7c2c7 编写于 作者: J jjg

6906175: bridge JSR199 and JSR 203 APIs

Reviewed-by: darcy, alanb
上级 980b6c24
...@@ -149,11 +149,26 @@ apt.tests = \ ...@@ -149,11 +149,26 @@ apt.tests = \
# #
# The following files require the import JDK to be available # The following files require the import JDK to be available
require.import.jdk.files = require.import.jdk.files = \
com/sun/tools/javac/nio/*.java
# The following files in the import jdk source directory are required # The following files in the import jdk source directory are required
# in order to compile the files defined in ${require.import.jdk.files} # in order to compile the files defined in ${require.import.jdk.files}
import.jdk.stub.files = #
# For NIO, the list of stub files is defined by the contents of the primary
# API packages, together with such types that may be required in order to
# compile the stubs. Some of these dependencies would go away if the stub
# generator were to be improved -- e.g. by removing unnecessary imports.
#
import.jdk.stub.files = \
java/io/File.java \
java/nio/file/**.java \
java/nio/file/attribute/**.java \
java/nio/file/spi/**.java \
java/nio/channels/AsynchronousChannel.java \
java/nio/channels/AsynchronousFileChannel.java \
java/nio/channels/CompletionHandler.java \
java/nio/channels/SeekableByteChannel.java
# The following value is used by the main jtreg target. # The following value is used by the main jtreg target.
# An empty value means all tests # An empty value means all tests
......
...@@ -98,7 +98,7 @@ ...@@ -98,7 +98,7 @@
import.jdk should be unset, or set to jdk home (to use rt.jar) import.jdk should be unset, or set to jdk home (to use rt.jar)
or to jdk repo (to use src/share/classes). or to jdk repo (to use src/share/classes).
Based on the value, if any, set up default values for javac's sourcepath, Based on the value, if any, set up default values for javac's sourcepath,
classpath and bootclasspath. Note: the default values are overridden classpath and bootclasspath. Note: the default values are overridden
in the build-bootstrap-classes macro. --> in the build-bootstrap-classes macro. -->
<available property="import.jdk.src.dir" value="${import.jdk}/src/share/classes" <available property="import.jdk.src.dir" value="${import.jdk}/src/share/classes"
...@@ -552,8 +552,8 @@ ...@@ -552,8 +552,8 @@
<compilerarg line="${javac.version.opt}"/> <compilerarg line="${javac.version.opt}"/>
<compilerarg line="${javac.lint.opts}"/> <compilerarg line="${javac.lint.opts}"/>
</javac> </javac>
<copy todir="@{classes.dir}"> <copy todir="@{classes.dir}" includeemptydirs="false">
<fileset dir="${src.classes.dir}" includes="@{includes}"> <fileset dir="${src.classes.dir}" includes="@{includes}" excludes="@{excludes}">
<exclude name="**/*.java"/> <exclude name="**/*.java"/>
<exclude name="**/*.properties"/> <exclude name="**/*.properties"/>
<exclude name="**/*-template"/> <exclude name="**/*-template"/>
......
...@@ -39,6 +39,8 @@ import javax.tools.JavaFileObject; ...@@ -39,6 +39,8 @@ import javax.tools.JavaFileObject;
import static javax.tools.JavaFileObject.Kind.*; import static javax.tools.JavaFileObject.Kind.*;
import com.sun.tools.javac.util.BaseFileManager;
/** /**
* <p><b>This is NOT part of any API supported by Sun Microsystems. * <p><b>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. * If you write code that depends on this, you do so at your own risk.
...@@ -74,14 +76,7 @@ public abstract class BaseFileObject implements JavaFileObject { ...@@ -74,14 +76,7 @@ public abstract class BaseFileObject implements JavaFileObject {
protected abstract String inferBinaryName(Iterable<? extends File> path); protected abstract String inferBinaryName(Iterable<? extends File> path);
protected static JavaFileObject.Kind getKind(String filename) { protected static JavaFileObject.Kind getKind(String filename) {
if (filename.endsWith(CLASS.extension)) return BaseFileManager.getKind(filename);
return CLASS;
else if (filename.endsWith(SOURCE.extension))
return SOURCE;
else if (filename.endsWith(HTML.extension))
return HTML;
else
return OTHER;
} }
protected static String removeExtension(String fileName) { protected static String removeExtension(String fileName) {
......
...@@ -26,29 +26,16 @@ ...@@ -26,29 +26,16 @@
package com.sun.tools.javac.file; package com.sun.tools.javac.file;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.lang.ref.SoftReference;
import java.lang.reflect.Constructor;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader;
import java.nio.ByteBuffer;
import java.nio.CharBuffer; import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset; 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.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
...@@ -66,18 +53,13 @@ import javax.tools.JavaFileManager; ...@@ -66,18 +53,13 @@ import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject; import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager; 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.RelativeFile;
import com.sun.tools.javac.file.RelativePath.RelativeDirectory; 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.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.Context;
import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer; 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 javax.tools.StandardLocation.*;
import static com.sun.tools.javac.main.OptionName.*; import static com.sun.tools.javac.main.OptionName.*;
...@@ -91,7 +73,7 @@ import static com.sun.tools.javac.main.OptionName.*; ...@@ -91,7 +73,7 @@ import static com.sun.tools.javac.main.OptionName.*;
* This code and its internal interfaces are subject to change or * This code and its internal interfaces are subject to change or
* deletion without notice.</b> * deletion without notice.</b>
*/ */
public class JavacFileManager implements StandardJavaFileManager { public class JavacFileManager extends BaseFileManager implements StandardJavaFileManager {
boolean useZipFileIndex; boolean useZipFileIndex;
...@@ -102,17 +84,10 @@ public class JavacFileManager implements StandardJavaFileManager { ...@@ -102,17 +84,10 @@ public class JavacFileManager implements StandardJavaFileManager {
return buffer.toString().toCharArray(); return buffer.toString().toCharArray();
} }
/**
* The log to be used for error reporting.
*/
protected Log log;
/** Encapsulates knowledge of paths /** Encapsulates knowledge of paths
*/ */
private Paths paths; private Paths paths;
private Options options;
private FSInfo fsInfo; private FSInfo fsInfo;
private final File uninited = new File("U N I N I T E D"); private final File uninited = new File("U N I N I T E D");
...@@ -134,12 +109,6 @@ public class JavacFileManager implements StandardJavaFileManager { ...@@ -134,12 +109,6 @@ public class JavacFileManager implements StandardJavaFileManager {
protected boolean mmappedIO; protected boolean mmappedIO;
protected boolean ignoreSymbolFile; protected boolean ignoreSymbolFile;
protected String classLoaderClass;
/**
* User provided charset (through javax.tools).
*/
protected Charset charset;
/** /**
* Register a Context.Factory to create a JavacFileManager. * Register a Context.Factory to create a JavacFileManager.
...@@ -157,18 +126,18 @@ public class JavacFileManager implements StandardJavaFileManager { ...@@ -157,18 +126,18 @@ public class JavacFileManager implements StandardJavaFileManager {
* it as the JavaFileManager for that context. * it as the JavaFileManager for that context.
*/ */
public JavacFileManager(Context context, boolean register, Charset charset) { public JavacFileManager(Context context, boolean register, Charset charset) {
super(charset);
if (register) if (register)
context.put(JavaFileManager.class, this); context.put(JavaFileManager.class, this);
byteBufferCache = new ByteBufferCache();
this.charset = charset;
setContext(context); setContext(context);
} }
/** /**
* Set the context for JavacFileManager. * Set the context for JavacFileManager.
*/ */
@Override
public void setContext(Context context) { public void setContext(Context context) {
log = Log.instance(context); super.setContext(context);
if (paths == null) { if (paths == null) {
paths = Paths.instance(context); paths = Paths.instance(context);
} else { } else {
...@@ -177,14 +146,12 @@ public class JavacFileManager implements StandardJavaFileManager { ...@@ -177,14 +146,12 @@ public class JavacFileManager implements StandardJavaFileManager {
paths.setContext(context); paths.setContext(context);
} }
options = Options.instance(context);
fsInfo = FSInfo.instance(context); fsInfo = FSInfo.instance(context);
useZipFileIndex = System.getProperty("useJavaUtilZip") == null;// TODO: options.get("useJavaUtilZip") == null; useZipFileIndex = System.getProperty("useJavaUtilZip") == null;// TODO: options.get("useJavaUtilZip") == null;
mmappedIO = options.get("mmappedIO") != null; mmappedIO = options.get("mmappedIO") != null;
ignoreSymbolFile = options.get("ignore.symbol.file") != null; ignoreSymbolFile = options.get("ignore.symbol.file") != null;
classLoaderClass = options.get("procloader");
} }
public JavaFileObject getFileForInput(String name) { public JavaFileObject getFileForInput(String name) {
...@@ -214,17 +181,6 @@ public class JavacFileManager implements StandardJavaFileManager { ...@@ -214,17 +181,6 @@ public class JavacFileManager implements StandardJavaFileManager {
return getJavaFileObjectsFromStrings(Arrays.asList(nullCheck(names))); 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) { private static boolean isValidName(String name) {
// Arguably, isValidName should reject keywords (such as in SourceVersion.isName() ), // 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 // but the set of keywords depends on the source level, and we don't want
...@@ -359,9 +315,7 @@ public class JavacFileManager implements StandardJavaFileManager { ...@@ -359,9 +315,7 @@ public class JavacFileManager implements StandardJavaFileManager {
} }
private boolean isValidFile(String s, Set<JavaFileObject.Kind> fileKinds) { private boolean isValidFile(String s, Set<JavaFileObject.Kind> fileKinds) {
int lastDot = s.lastIndexOf("."); JavaFileObject.Kind kind = getKind(s);
String extn = (lastDot == -1 ? s : s.substring(lastDot));
JavaFileObject.Kind kind = getKind(extn);
return fileKinds.contains(kind); return fileKinds.contains(kind);
} }
...@@ -564,18 +518,6 @@ public class JavacFileManager implements StandardJavaFileManager { ...@@ -564,18 +518,6 @@ public class JavacFileManager implements StandardJavaFileManager {
} }
} }
CharBuffer getCachedContent(JavaFileObject file) {
SoftReference<CharBuffer> r = contentCache.get(file);
return (r == null ? null : r.get());
}
void cache(JavaFileObject file, CharBuffer cb) {
contentCache.put(file, new SoftReference<CharBuffer>(cb));
}
private final Map<JavaFileObject, SoftReference<CharBuffer>> contentCache
= new HashMap<JavaFileObject, SoftReference<CharBuffer>>();
private String defaultEncodingName; private String defaultEncodingName;
private String getDefaultEncodingName() { private String getDefaultEncodingName() {
if (defaultEncodingName == null) { if (defaultEncodingName == null) {
...@@ -585,161 +527,6 @@ public class JavacFileManager implements StandardJavaFileManager { ...@@ -585,161 +527,6 @@ public class JavacFileManager implements StandardJavaFileManager {
return defaultEncodingName; return defaultEncodingName;
} }
protected String getEncodingName() {
String encName = options.get(OptionName.ENCODING);
if (encName == null)
return getDefaultEncodingName();
else
return encName;
}
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);
}
/**
* Make a byte buffer from an input stream.
*/
ByteBuffer makeByteBuffer(InputStream in)
throws IOException {
int limit = in.available();
if (mmappedIO && in instanceof FileInputStream) {
// Experimental memory mapped I/O
FileInputStream fin = (FileInputStream)in;
return fin.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, limit);
}
if (limit < 1024) limit = 1024;
ByteBuffer result = byteBufferCache.get(limit);
int position = 0;
while (in.available() != 0) {
if (position >= limit)
// expand buffer
result = ByteBuffer.
allocate(limit <<= 1).
put((ByteBuffer)result.flip());
int count = in.read(result.array(),
position,
limit - position);
if (count < 0) break;
result.position(position += count);
}
return (ByteBuffer)result.flip();
}
void recycleByteBuffer(ByteBuffer bb) {
byteBufferCache.put(bb);
}
/**
* A single-element cache of direct byte buffers.
*/
private static class ByteBufferCache {
private ByteBuffer cached;
ByteBuffer get(int capacity) {
if (capacity < 20480) capacity = 20480;
ByteBuffer result =
(cached != null && cached.capacity() >= capacity)
? (ByteBuffer)cached.clear()
: ByteBuffer.allocate(capacity + capacity>>1);
cached = null;
return result;
}
void put(ByteBuffer x) {
cached = x;
}
}
private final ByteBufferCache byteBufferCache;
CharsetDecoder getDecoder(String encodingName, boolean ignoreEncodingErrors) {
Charset cs = (this.charset == null)
? Charset.forName(encodingName)
: this.charset;
CharsetDecoder decoder = cs.newDecoder();
CodingErrorAction action;
if (ignoreEncodingErrors)
action = CodingErrorAction.REPLACE;
else
action = CodingErrorAction.REPORT;
return decoder
.onMalformedInput(action)
.onUnmappableCharacter(action);
}
/**
* Decode a ByteBuffer into a CharBuffer.
*/
CharBuffer decode(ByteBuffer inbuf, boolean ignoreEncodingErrors) {
String encodingName = getEncodingName();
CharsetDecoder decoder;
try {
decoder = getDecoder(encodingName, ignoreEncodingErrors);
} catch (IllegalCharsetNameException e) {
log.error("unsupported.encoding", encodingName);
return (CharBuffer)CharBuffer.allocate(1).flip();
} catch (UnsupportedCharsetException e) {
log.error("unsupported.encoding", encodingName);
return (CharBuffer)CharBuffer.allocate(1).flip();
}
// slightly overestimate the buffer size to avoid reallocation.
float factor =
decoder.averageCharsPerByte() * 0.8f +
decoder.maxCharsPerByte() * 0.2f;
CharBuffer dest = CharBuffer.
allocate(10 + (int)(inbuf.remaining()*factor));
while (true) {
CoderResult result = decoder.decode(inbuf, dest, true);
dest.flip();
if (result.isUnderflow()) { // done reading
// make sure there is at least one extra character
if (dest.limit() == dest.capacity()) {
dest = CharBuffer.allocate(dest.capacity()+1).put(dest);
dest.flip();
}
return dest;
} else if (result.isOverflow()) { // buffer too small; expand
int newCapacity =
10 + dest.capacity() +
(int)(inbuf.remaining()*decoder.maxCharsPerByte());
dest = CharBuffer.allocate(newCapacity).put(dest);
} else if (result.isMalformed() || result.isUnmappable()) {
// bad character in input
// report coding error (warn only pre 1.5)
if (!getSource().allowEncodingErrors()) {
log.error(new SimpleDiagnosticPosition(dest.limit()),
"illegal.char.for.encoding",
charset == null ? encodingName : charset.name());
} else {
log.warning(new SimpleDiagnosticPosition(dest.limit()),
"illegal.char.for.encoding",
charset == null ? encodingName : charset.name());
}
// skip past the coding error
inbuf.position(inbuf.position() + result.length());
// undo the flip() to prepare the output buffer
// for more translation
dest.position(dest.limit());
dest.limit(dest.capacity());
dest.put((char)0xfffd); // backward compatible
} else {
throw new AssertionError(result);
}
}
// unreached
}
public ClassLoader getClassLoader(Location location) { public ClassLoader getClassLoader(Location location) {
nullCheck(location); nullCheck(location);
Iterable<? extends File> path = getLocation(location); Iterable<? extends File> path = getLocation(location);
...@@ -754,39 +541,7 @@ public class JavacFileManager implements StandardJavaFileManager { ...@@ -754,39 +541,7 @@ public class JavacFileManager implements StandardJavaFileManager {
} }
} }
URL[] urls = lb.toArray(new URL[lb.size()]); return getClassLoader(lb.toArray(new URL[lb.size()]));
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);
} }
public Iterable<JavaFileObject> list(Location location, public Iterable<JavaFileObject> list(Location location,
...@@ -836,38 +591,6 @@ public class JavacFileManager implements StandardJavaFileManager { ...@@ -836,38 +591,6 @@ public class JavacFileManager implements StandardJavaFileManager {
return a.equals(b); return a.equals(b);
} }
public boolean handleOption(String current, Iterator<String> remaining) {
for (JavacOption o: javacFileManagerOptions) {
if (o.matches(current)) {
if (o.hasArg()) {
if (remaining.hasNext()) {
if (!o.process(options, current, remaining.next()))
return true;
}
} else {
if (!o.process(options, current))
return true;
}
// operand missing, or process returned false
throw new IllegalArgumentException(current);
}
}
return false;
}
// where
private static JavacOption[] javacFileManagerOptions =
RecognizedOptions.getJavacFileManagerOptions(
new RecognizedOptions.GrumpyHelper());
public int isSupportedOption(String option) {
for (JavacOption o : javacFileManagerOptions) {
if (o.matches(option))
return o.hasArg() ? 1 : 0;
}
return -1;
}
public boolean hasLocation(Location location) { public boolean hasLocation(Location location) {
return getLocation(location) != null; return getLocation(location) != null;
} }
...@@ -1115,15 +838,4 @@ public class JavacFileManager implements StandardJavaFileManager { ...@@ -1115,15 +838,4 @@ public class JavacFileManager implements StandardJavaFileManager {
} }
throw new IllegalArgumentException("Invalid relative path: " + file); throw new IllegalArgumentException("Invalid relative path: " + file);
} }
private static <T> T nullCheck(T o) {
o.getClass(); // null check
return o;
}
private static <T> Iterable<T> nullCheck(Iterable<T> it) {
for (T t : it)
t.getClass(); // null check
return it;
}
} }
...@@ -66,7 +66,7 @@ public class Paths { ...@@ -66,7 +66,7 @@ public class Paths {
* @param context the context * @param context the context
* @return the Paths instance for this context * @return the Paths instance for this context
*/ */
static Paths instance(Context context) { public static Paths instance(Context context) {
Paths instance = context.get(pathsKey); Paths instance = context.get(pathsKey);
if (instance == null) if (instance == null)
instance = new Paths(context); instance = new Paths(context);
......
/*
* 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.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.Attributes;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.lang.model.SourceVersion;
import javax.tools.FileObject;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.StandardLocation;
import static java.nio.file.FileVisitOption.*;
import static javax.tools.StandardLocation.*;
import com.sun.tools.javac.file.Paths;
import com.sun.tools.javac.util.BaseFileManager;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import static com.sun.tools.javac.main.OptionName.*;
// NOTE the imports carefully for this compilation unit.
//
// Path: java.nio.file.Path -- the new NIO type for which this file manager exists
//
// Paths: com.sun.tools.javac.file.Paths -- legacy javac type for handling path options
// The other Paths (java.nio.file.Paths) is not used
// NOTE this and related classes depend on new API in JDK 7.
// This requires special handling while bootstrapping the JDK build,
// when these classes might not yet have been compiled. To workaround
// this, the build arranges to make stubs of these classes available
// when compiling this and related classes. The set of stub files
// is specified in make/build.properties.
/**
* Implementation of PathFileManager: a JavaFileManager based on the use
* of java.nio.file.Path.
*
* <p>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.)
*
* <p>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}.
*
* <p>To reduce confusion with Path objects, the locations such as "class path",
* "source path", etc, are generically referred to here as "search paths".
*
* <p><b>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.</b>
*/
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<Location, PathsForLocation>();
fileSystems = new HashMap<Path,FileSystem>();
setContext(context);
}
/**
* Set the context for JavacPathFileManager.
*/
@Override
protected void setContext(Context context) {
super.setContext(context);
searchPaths = Paths.instance(context);
}
@Override
public FileSystem getDefaultFileSystem() {
if (defaultFileSystem == null)
defaultFileSystem = FileSystems.getDefault();
return defaultFileSystem;
}
@Override
public void setDefaultFileSystem(FileSystem fs) {
defaultFileSystem = fs;
}
@Override
public void flush() throws IOException {
contentCache.clear();
}
@Override
public void close() throws IOException {
for (FileSystem fs: fileSystems.values())
fs.close();
}
@Override
public ClassLoader getClassLoader(Location location) {
nullCheck(location);
Iterable<? extends Path> path = getLocation(location);
if (path == null)
return null;
ListBuffer<URL> lb = new ListBuffer<URL>();
for (Path p: path) {
try {
lb.append(p.toUri().toURL());
} catch (MalformedURLException e) {
throw new AssertionError(e);
}
}
return getClassLoader(lb.toArray(new URL[lb.size()]));
}
// <editor-fold defaultstate="collapsed" desc="Location handling">
public boolean hasLocation(Location location) {
return (getLocation(location) != null);
}
public Iterable<? extends Path> getLocation(Location location) {
nullCheck(location);
lazyInitSearchPaths();
PathsForLocation path = pathsForLocation.get(location);
if (path == null && !pathsForLocation.containsKey(location)) {
setDefaultForLocation(location);
path = pathsForLocation.get(location);
}
return path;
}
private Path getOutputLocation(Location location) {
Iterable<? extends Path> paths = getLocation(location);
return (paths == null ? null : paths.iterator().next());
}
public void setLocation(Location location, Iterable<? extends Path> searchPath)
throws IOException
{
nullCheck(location);
lazyInitSearchPaths();
if (searchPath == null) {
setDefaultForLocation(location);
} else {
if (location.isOutputLocation())
checkOutputPath(searchPath);
PathsForLocation pl = new PathsForLocation();
for (Path p: searchPath)
pl.add(p); // TODO -Xlint:path warn if path not found
pathsForLocation.put(location, pl);
}
}
private void checkOutputPath(Iterable<? extends Path> searchPath) throws IOException {
Iterator<? extends Path> pathIter = searchPath.iterator();
if (!pathIter.hasNext())
throw new IllegalArgumentException("empty path for directory");
Path path = pathIter.next();
if (pathIter.hasNext())
throw new IllegalArgumentException("path too long for directory");
if (!path.exists())
throw new FileNotFoundException(path + ": does not exist");
else if (!isDirectory(path))
throw new IOException(path + ": not a directory");
}
private void setDefaultForLocation(Location locn) {
Collection<File> files = null;
if (locn instanceof StandardLocation) {
switch ((StandardLocation) locn) {
case CLASS_PATH:
files = searchPaths.userClassPath();
break;
case PLATFORM_CLASS_PATH:
files = searchPaths.bootClassPath();
break;
case SOURCE_PATH:
files = searchPaths.sourcePath();
break;
case CLASS_OUTPUT: {
String arg = options.get(D);
files = (arg == null ? null : Collections.singleton(new File(arg)));
break;
}
case SOURCE_OUTPUT: {
String arg = options.get(S);
files = (arg == null ? null : Collections.singleton(new File(arg)));
break;
}
}
}
PathsForLocation pl = new PathsForLocation();
if (files != null) {
for (File f: files)
pl.add(f.toPath());
}
pathsForLocation.put(locn, pl);
}
private void lazyInitSearchPaths() {
if (!inited) {
setDefaultForLocation(PLATFORM_CLASS_PATH);
setDefaultForLocation(CLASS_PATH);
setDefaultForLocation(SOURCE_PATH);
inited = true;
}
}
// where
private boolean inited = false;
private Map<Location, PathsForLocation> pathsForLocation;
private Paths searchPaths;
private static class PathsForLocation extends LinkedHashSet<Path> {
private static final long serialVersionUID = 6788510222394486733L;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="FileObject handling">
@Override
public Path getPath(FileObject fo) {
nullCheck(fo);
if (!(fo instanceof PathFileObject))
throw new IllegalArgumentException();
return ((PathFileObject) fo).getPath();
}
@Override
public boolean isSameFile(FileObject a, FileObject b) {
nullCheck(a);
nullCheck(b);
if (!(a instanceof PathFileObject))
throw new IllegalArgumentException("Not supported: " + a);
if (!(b instanceof PathFileObject))
throw new IllegalArgumentException("Not supported: " + b);
return ((PathFileObject) a).isSameFile((PathFileObject) b);
}
@Override
public Iterable<JavaFileObject> list(Location location,
String packageName, Set<Kind> kinds, boolean recurse)
throws IOException {
// validatePackageName(packageName);
nullCheck(packageName);
nullCheck(kinds);
Iterable<? extends Path> paths = getLocation(location);
if (paths == null)
return List.nil();
ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
for (Path path : paths)
list(path, packageName, kinds, recurse, results);
return results.toList();
}
private void list(Path path, String packageName, final Set<Kind> kinds,
boolean recurse, final ListBuffer<JavaFileObject> results)
throws IOException {
if (!path.exists())
return;
final Path pathDir;
if (isDirectory(path))
pathDir = path;
else {
FileSystem fs = getFileSystem(path);
if (fs == null)
return;
pathDir = fs.getRootDirectories().iterator().next();
}
String sep = path.getFileSystem().getSeparator();
Path packageDir = packageName.isEmpty() ? pathDir
: pathDir.resolve(packageName.replace(".", sep));
if (!packageDir.exists())
return;
/* Alternate impl of list, superceded by use of Files.walkFileTree */
// Deque<Path> queue = new LinkedList<Path>();
// queue.add(packageDir);
//
// Path dir;
// while ((dir = queue.poll()) != null) {
// DirectoryStream<Path> ds = dir.newDirectoryStream();
// try {
// for (Path p: ds) {
// String name = p.getName().toString();
// if (isDirectory(p)) {
// if (recurse && SourceVersion.isIdentifier(name)) {
// queue.add(p);
// }
// } else {
// if (kinds.contains(getKind(name))) {
// JavaFileObject fe =
// PathFileObject.createDirectoryPathFileObject(this, p, pathDir);
// results.append(fe);
// }
// }
// }
// } finally {
// ds.close();
// }
// }
int maxDepth = (recurse ? Integer.MAX_VALUE : 1);
Set<FileVisitOption> opts = EnumSet.of(DETECT_CYCLES, FOLLOW_LINKS);
Files.walkFileTree(packageDir, opts, maxDepth,
new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir) {
if (SourceVersion.isIdentifier(dir.getName().toString())) // JSR 292?
return FileVisitResult.CONTINUE;
else
return FileVisitResult.SKIP_SUBTREE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (attrs.isRegularFile() && kinds.contains(getKind(file.getName().toString()))) {
JavaFileObject fe =
PathFileObject.createDirectoryPathFileObject(
JavacPathFileManager.this, file, pathDir);
results.append(fe);
}
return FileVisitResult.CONTINUE;
}
});
}
@Override
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(
Iterable<? extends Path> paths) {
ArrayList<PathFileObject> result;
if (paths instanceof Collection<?>)
result = new ArrayList<PathFileObject>(((Collection<?>)paths).size());
else
result = new ArrayList<PathFileObject>();
for (Path p: paths)
result.add(PathFileObject.createSimplePathFileObject(this, nullCheck(p)));
return result;
}
@Override
public Iterable<? extends JavaFileObject> getJavaFileObjects(Path... paths) {
return getJavaFileObjectsFromPaths(Arrays.asList(nullCheck(paths)));
}
@Override
public JavaFileObject getJavaFileForInput(Location location,
String className, Kind kind) throws IOException {
return getFileForInput(location, getRelativePath(className, kind));
}
@Override
public FileObject getFileForInput(Location location,
String packageName, String relativeName) throws IOException {
return getFileForInput(location, getRelativePath(packageName, relativeName));
}
private JavaFileObject getFileForInput(Location location, String relativePath)
throws IOException {
for (Path p: getLocation(location)) {
if (isDirectory(p)) {
Path f = resolve(p, relativePath);
if (f.exists())
return PathFileObject.createDirectoryPathFileObject(this, f, p);
} else {
FileSystem fs = getFileSystem(p);
if (fs != null) {
Path file = getPath(fs, relativePath);
if (file.exists())
return PathFileObject.createJarPathFileObject(this, file);
}
}
}
return null;
}
@Override
public JavaFileObject getJavaFileForOutput(Location location,
String className, Kind kind, FileObject sibling) throws IOException {
return getFileForOutput(location, getRelativePath(className, kind), sibling);
}
@Override
public FileObject getFileForOutput(Location location, String packageName,
String relativeName, FileObject sibling)
throws IOException {
return getFileForOutput(location, getRelativePath(packageName, relativeName), sibling);
}
private JavaFileObject getFileForOutput(Location location,
String relativePath, FileObject sibling) {
Path dir = getOutputLocation(location);
if (dir == null) {
if (location == CLASS_OUTPUT) {
Path siblingDir = null;
if (sibling != null && sibling instanceof PathFileObject) {
siblingDir = ((PathFileObject) sibling).getPath().getParent();
}
return PathFileObject.createSiblingPathFileObject(this,
siblingDir.resolve(getBaseName(relativePath)),
relativePath);
} else if (location == SOURCE_OUTPUT) {
dir = getOutputLocation(CLASS_OUTPUT);
}
}
Path file;
if (dir != null) {
file = resolve(dir, relativePath);
return PathFileObject.createDirectoryPathFileObject(this, file, dir);
} else {
file = getPath(getDefaultFileSystem(), relativePath);
return PathFileObject.createSimplePathFileObject(this, file);
}
}
@Override
public String inferBinaryName(Location location, JavaFileObject fo) {
nullCheck(fo);
// Need to match the path semantics of list(location, ...)
Iterable<? extends Path> paths = getLocation(location);
if (paths == null) {
return null;
}
if (!(fo instanceof PathFileObject))
throw new IllegalArgumentException(fo.getClass().getName());
return ((PathFileObject) fo).inferBinaryName(paths);
}
private FileSystem getFileSystem(Path p) throws IOException {
FileSystem fs = fileSystems.get(p);
if (fs == null) {
fs = FileSystems.newFileSystem(p, Collections.<String,Void>emptyMap(), null);
fileSystems.put(p, fs);
}
return fs;
}
private Map<Path,FileSystem> fileSystems;
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Utility methods">
private static String getRelativePath(String className, Kind kind) {
return className.replace(".", "/") + kind.extension;
}
private static String getRelativePath(String packageName, String relativeName) {
return packageName.replace(".", "/") + relativeName;
}
private static String getBaseName(String relativePath) {
int lastSep = relativePath.lastIndexOf("/");
return relativePath.substring(lastSep + 1); // safe if "/" not found
}
private static boolean isDirectory(Path path) throws IOException {
BasicFileAttributes attrs = Attributes.readBasicFileAttributes(path);
return attrs.isDirectory();
}
private static Path getPath(FileSystem fs, String relativePath) {
return fs.getPath(relativePath.replace("/", fs.getSeparator()));
}
private static Path resolve(Path base, String relativePath) {
FileSystem fs = base.getFileSystem();
Path rp = fs.getPath(relativePath.replace("/", fs.getSeparator()));
return base.resolve(rp);
}
// </editor-fold>
}
/*
* 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.nio.file.FileSystem;
import java.nio.file.Path;
import javax.tools.FileObject;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
/**
* File manager based on {@linkplain File java.nio.file.Path}.
*
* Eventually, this should be moved to javax.tools.
* Also, JavaCompiler might reasonably provide a method getPathFileManager,
* similar to {@link javax.tools.JavaCompiler#getStandardFileManager
* getStandardFileManager}. However, would need to be handled carefully
* as another forward reference from langtools to jdk.
*
* <p><b>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.</b>
*/
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:
*
* <pre>
* getJavaFileObjectsFromPaths({@linkplain java.util.Arrays#asList Arrays.asList}(paths))
* </pre>
*
* @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;
}
/*
* 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.
*
* <p>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.
*
* <p><b>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.</b>
*/
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));
}
}
/*
* 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);
}
// <editor-fold defaultstate="collapsed" desc="Option handling">
public boolean handleOption(String current, Iterator<String> remaining) {
for (JavacOption o: javacFileManagerOptions) {
if (o.matches(current)) {
if (o.hasArg()) {
if (remaining.hasNext()) {
if (!o.process(options, current, remaining.next()))
return true;
}
} else {
if (!o.process(options, current))
return true;
}
// operand missing, or process returned false
throw new IllegalArgumentException(current);
}
}
return false;
}
// where
private static JavacOption[] javacFileManagerOptions =
RecognizedOptions.getJavacFileManagerOptions(
new RecognizedOptions.GrumpyHelper());
public int isSupportedOption(String option) {
for (JavacOption o : javacFileManagerOptions) {
if (o.matches(option))
return o.hasArg() ? 1 : 0;
}
return -1;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Encoding">
private String defaultEncodingName;
private String getDefaultEncodingName() {
if (defaultEncodingName == null) {
defaultEncodingName =
new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding();
}
return defaultEncodingName;
}
public String getEncodingName() {
String encName = options.get(OptionName.ENCODING);
if (encName == null)
return getDefaultEncodingName();
else
return encName;
}
public CharBuffer decode(ByteBuffer inbuf, boolean ignoreEncodingErrors) {
String encodingName = getEncodingName();
CharsetDecoder decoder;
try {
decoder = getDecoder(encodingName, ignoreEncodingErrors);
} catch (IllegalCharsetNameException e) {
log.error("unsupported.encoding", encodingName);
return (CharBuffer)CharBuffer.allocate(1).flip();
} catch (UnsupportedCharsetException e) {
log.error("unsupported.encoding", encodingName);
return (CharBuffer)CharBuffer.allocate(1).flip();
}
// slightly overestimate the buffer size to avoid reallocation.
float factor =
decoder.averageCharsPerByte() * 0.8f +
decoder.maxCharsPerByte() * 0.2f;
CharBuffer dest = CharBuffer.
allocate(10 + (int)(inbuf.remaining()*factor));
while (true) {
CoderResult result = decoder.decode(inbuf, dest, true);
dest.flip();
if (result.isUnderflow()) { // done reading
// make sure there is at least one extra character
if (dest.limit() == dest.capacity()) {
dest = CharBuffer.allocate(dest.capacity()+1).put(dest);
dest.flip();
}
return dest;
} else if (result.isOverflow()) { // buffer too small; expand
int newCapacity =
10 + dest.capacity() +
(int)(inbuf.remaining()*decoder.maxCharsPerByte());
dest = CharBuffer.allocate(newCapacity).put(dest);
} else if (result.isMalformed() || result.isUnmappable()) {
// bad character in input
// report coding error (warn only pre 1.5)
if (!getSource().allowEncodingErrors()) {
log.error(new SimpleDiagnosticPosition(dest.limit()),
"illegal.char.for.encoding",
charset == null ? encodingName : charset.name());
} else {
log.warning(new SimpleDiagnosticPosition(dest.limit()),
"illegal.char.for.encoding",
charset == null ? encodingName : charset.name());
}
// skip past the coding error
inbuf.position(inbuf.position() + result.length());
// undo the flip() to prepare the output buffer
// for more translation
dest.position(dest.limit());
dest.limit(dest.capacity());
dest.put((char)0xfffd); // backward compatible
} else {
throw new AssertionError(result);
}
}
// unreached
}
public CharsetDecoder getDecoder(String encodingName, boolean ignoreEncodingErrors) {
Charset cs = (this.charset == null)
? Charset.forName(encodingName)
: this.charset;
CharsetDecoder decoder = cs.newDecoder();
CodingErrorAction action;
if (ignoreEncodingErrors)
action = CodingErrorAction.REPLACE;
else
action = CodingErrorAction.REPORT;
return decoder
.onMalformedInput(action)
.onUnmappableCharacter(action);
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="ByteBuffers">
/**
* Make a byte buffer from an input stream.
*/
public ByteBuffer makeByteBuffer(InputStream in)
throws IOException {
int limit = in.available();
if (limit < 1024) limit = 1024;
ByteBuffer result = byteBufferCache.get(limit);
int position = 0;
while (in.available() != 0) {
if (position >= limit)
// expand buffer
result = ByteBuffer.
allocate(limit <<= 1).
put((ByteBuffer)result.flip());
int count = in.read(result.array(),
position,
limit - position);
if (count < 0) break;
result.position(position += count);
}
return (ByteBuffer)result.flip();
}
public void recycleByteBuffer(ByteBuffer bb) {
byteBufferCache.put(bb);
}
/**
* A single-element cache of direct byte buffers.
*/
private static class ByteBufferCache {
private ByteBuffer cached;
ByteBuffer get(int capacity) {
if (capacity < 20480) capacity = 20480;
ByteBuffer result =
(cached != null && cached.capacity() >= capacity)
? (ByteBuffer)cached.clear()
: ByteBuffer.allocate(capacity + capacity>>1);
cached = null;
return result;
}
void put(ByteBuffer x) {
cached = x;
}
}
private final ByteBufferCache byteBufferCache;
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Content cache">
public CharBuffer getCachedContent(JavaFileObject file) {
SoftReference<CharBuffer> r = contentCache.get(file);
return (r == null ? null : r.get());
}
public void cache(JavaFileObject file, CharBuffer cb) {
contentCache.put(file, new SoftReference<CharBuffer>(cb));
}
protected final Map<JavaFileObject, SoftReference<CharBuffer>> contentCache
= new HashMap<JavaFileObject, SoftReference<CharBuffer>>();
// </editor-fold>
public static Kind getKind(String name) {
if (name.endsWith(Kind.CLASS.extension))
return Kind.CLASS;
else if (name.endsWith(Kind.SOURCE.extension))
return Kind.SOURCE;
else if (name.endsWith(Kind.HTML.extension))
return Kind.HTML;
else
return Kind.OTHER;
}
protected static <T> T nullCheck(T o) {
o.getClass(); // null check
return o;
}
protected static <T> Collection<T> nullCheck(Collection<T> it) {
for (T t : it)
t.getClass(); // null check
return it;
}
}
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
* have any questions. * have any questions.
*/ */
package com.sun.tools.javac.file; package com.sun.tools.javac.util;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
...@@ -45,9 +45,9 @@ import java.util.jar.JarFile; ...@@ -45,9 +45,9 @@ import java.util.jar.JarFile;
* This code and its internal interfaces are subject to change or * This code and its internal interfaces are subject to change or
* deletion without notice.</b> * deletion without notice.</b>
*/ */
class CloseableURLClassLoader public class CloseableURLClassLoader
extends URLClassLoader implements Closeable { extends URLClassLoader implements Closeable {
CloseableURLClassLoader(URL[] urls, ClassLoader parent) throws Error { public CloseableURLClassLoader(URL[] urls, ClassLoader parent) throws Error {
super(urls, parent); super(urls, parent);
try { try {
getLoaders(); //proactive check that URLClassLoader is as expected getLoaders(); //proactive check that URLClassLoader is as expected
...@@ -63,6 +63,7 @@ class CloseableURLClassLoader ...@@ -63,6 +63,7 @@ class CloseableURLClassLoader
* @throws java.io.IOException if the jar files cannot be found for any * @throws java.io.IOException if the jar files cannot be found for any
* reson, or if closing the jar file itself causes an IOException. * reson, or if closing the jar file itself causes an IOException.
*/ */
@Override
public void close() throws IOException { public void close() throws IOException {
try { try {
for (Object l: getLoaders()) { for (Object l: getLoaders()) {
......
...@@ -28,7 +28,6 @@ package javax.tools; ...@@ -28,7 +28,6 @@ package javax.tools;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.concurrent.*;
/** /**
* File manager based on {@linkplain File java.io.File}. A common way * File manager based on {@linkplain File java.io.File}. A common way
......
/*
* 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<String> options = new ArrayList<String>();
options.addAll(Arrays.asList(opts));
options.addAll(Arrays.asList(
"-verbose", "-XDverboseCompilePolicy",
"-d", classes.toString()
));
Iterable<? extends JavaFileObject> compilationUnits =
fm.getJavaFileObjects(testSrcDir.resolve(className + ".java"));
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
JavaCompiler.CompilationTask t =
compiler.getTask(out, fm, null, options, null, compilationUnits);
boolean ok = t.call();
System.err.println(sw.toString());
if (!ok) {
throw new Exception("compilation failed");
}
File expect = new File("classes." + count + "/" + className + ".class");
if (!expect.exists())
throw new Exception("expected file not found: " + expect);
long expectedSize = new File(testClassesDir.toString(), className + ".class").length();
long actualSize = expect.length();
if (expectedSize != actualSize)
throw new Exception("wrong size found: " + actualSize + "; expected: " + expectedSize);
}
boolean isJarFileSystemAvailable() {
boolean result = false;
for (FileSystemProvider fsp: FileSystemProvider.installedProviders()) {
String scheme = fsp.getScheme();
System.err.println("Provider: " + scheme + " " + fsp);
if (scheme.equalsIgnoreCase("jar") || scheme.equalsIgnoreCase("zip"))
result = true;
}
return result;
}
void expand(File jar, File dir) throws IOException {
JarFile jarFile = new JarFile(jar);
try {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry je = entries.nextElement();
if (!je.isDirectory()) {
copy(jarFile.getInputStream(je), new File(dir, je.getName()));
}
}
} finally {
jarFile.close();
}
}
void copy(InputStream in, File dest) throws IOException {
dest.getParentFile().mkdirs();
OutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
try {
byte[] data = new byte[8192];
int n;
while ((n = in.read(data, 0, data.length)) > 0)
out.write(data, 0, n);
} finally {
out.close();
in.close();
}
}
void error(String message) {
System.err.println("Error: " + message);
errors++;
}
int errors;
int count;
}
/*
* 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.
*/
class HelloPathWorld {
public static void main(String... args) {
System.out.println("Hello World!");
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册