feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,128 @@
/*
* Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.file;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.CharsetDecoder;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.NestingKind;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import static javax.tools.JavaFileObject.Kind.*;
import com.sun.tools.javac.util.BaseFileManager;
/**
* <p><b>This is NOT part of any supported API.
* 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 abstract class BaseFileObject implements JavaFileObject {
protected BaseFileObject(JavacFileManager fileManager) {
this.fileManager = fileManager;
}
/** Return a short name for the object, such as for use in raw diagnostics
*/
public abstract String getShortName();
@Override
public String toString() {
return getClass().getSimpleName() + "[" + getName() + "]";
}
public NestingKind getNestingKind() { return null; }
public Modifier getAccessLevel() { return null; }
public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
return new InputStreamReader(openInputStream(), getDecoder(ignoreEncodingErrors));
}
protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) {
throw new UnsupportedOperationException();
}
protected abstract String inferBinaryName(Iterable<? extends File> path);
protected static JavaFileObject.Kind getKind(String filename) {
return BaseFileManager.getKind(filename);
}
protected static String removeExtension(String fileName) {
int lastDot = fileName.lastIndexOf(".");
return (lastDot == -1 ? fileName : fileName.substring(0, lastDot));
}
protected static URI createJarUri(File jarFile, String entryName) {
URI jarURI = jarFile.toURI().normalize();
String separator = entryName.startsWith("/") ? "!" : "!/";
try {
// The jar URI convention appears to be not to re-encode the jarURI
return new URI("jar:" + jarURI + separator + entryName);
} catch (URISyntaxException e) {
throw new CannotCreateUriError(jarURI + separator + entryName, e);
}
}
/** Used when URLSyntaxException is thrown unexpectedly during
* implementations of (Base)FileObject.toURI(). */
protected static class CannotCreateUriError extends Error {
private static final long serialVersionUID = 9101708840997613546L;
public CannotCreateUriError(String value, Throwable cause) {
super(value, cause);
}
}
/** Return the last component of a presumed hierarchical URI.
* From the scheme specific part of the URI, it returns the substring
* after the last "/" if any, or everything if no "/" is found.
*/
public static String getSimpleName(FileObject fo) {
URI uri = fo.toUri();
String s = uri.getSchemeSpecificPart();
return s.substring(s.lastIndexOf("/") + 1); // safe when / not found
}
// force subtypes to define equals
@Override
public abstract boolean equals(Object other);
// force subtypes to define hashCode
@Override
public abstract int hashCode();
/** The file manager that created this JavaFileObject. */
protected final JavacFileManager fileManager;
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.file;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.sun.tools.javac.util.Context;
/**
* Caching implementation of FSInfo.
*
* <p><b>This is NOT part of any supported API.
* 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 CacheFSInfo extends FSInfo {
/**
* Register a Context.Factory to create a CacheFSInfo.
*/
public static void preRegister(Context context) {
context.put(FSInfo.class, new Context.Factory<FSInfo>() {
public FSInfo make(Context c) {
FSInfo instance = new CacheFSInfo();
c.put(FSInfo.class, instance);
return instance;
}
});
}
public void clearCache() {
cache.clear();
}
@Override
public File getCanonicalFile(File file) {
Entry e = getEntry(file);
return e.canonicalFile;
}
@Override
public boolean exists(File file) {
Entry e = getEntry(file);
return e.exists;
}
@Override
public boolean isDirectory(File file) {
Entry e = getEntry(file);
return e.isDirectory;
}
@Override
public boolean isFile(File file) {
Entry e = getEntry(file);
return e.isFile;
}
@Override
public List<File> getJarClassPath(File file) throws IOException {
// don't bother to lock the cache, because it is thread-safe, and
// because the worst that can happen would be to create two identical
// jar class paths together and have one overwrite the other.
Entry e = getEntry(file);
if (e.jarClassPath == null)
e.jarClassPath = super.getJarClassPath(file);
return e.jarClassPath;
}
private Entry getEntry(File file) {
// don't bother to lock the cache, because it is thread-safe, and
// because the worst that can happen would be to create two identical
// entries together and have one overwrite the other.
Entry e = cache.get(file);
if (e == null) {
e = new Entry();
e.canonicalFile = super.getCanonicalFile(file);
e.exists = super.exists(file);
e.isDirectory = super.isDirectory(file);
e.isFile = super.isFile(file);
cache.put(file, e);
}
return e;
}
// could also be a Map<File,SoftReference<Entry>> ?
private Map<File,Entry> cache = new ConcurrentHashMap<File,Entry>();
private static class Entry {
File canonicalFile;
boolean exists;
boolean isFile;
boolean isDirectory;
List<File> jarClassPath;
}
}

View File

@@ -0,0 +1,94 @@
package com.sun.tools.javac.file;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import com.sun.tools.javac.util.Context;
/**
* Get meta-info about files. Default direct (non-caching) implementation.
* @see CacheFSInfo
*
* <p><b>This is NOT part of any supported API.
* 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 FSInfo {
/** Get the FSInfo instance for this context.
* @param context the context
* @return the Paths instance for this context
*/
public static FSInfo instance(Context context) {
FSInfo instance = context.get(FSInfo.class);
if (instance == null)
instance = new FSInfo();
return instance;
}
protected FSInfo() {
}
protected FSInfo(Context context) {
context.put(FSInfo.class, this);
}
public File getCanonicalFile(File file) {
try {
return file.getCanonicalFile();
} catch (IOException e) {
return file.getAbsoluteFile();
}
}
public boolean exists(File file) {
return file.exists();
}
public boolean isDirectory(File file) {
return file.isDirectory();
}
public boolean isFile(File file) {
return file.isFile();
}
public List<File> getJarClassPath(File file) throws IOException {
String parent = file.getParent();
JarFile jarFile = new JarFile(file);
try {
Manifest man = jarFile.getManifest();
if (man == null)
return Collections.emptyList();
Attributes attr = man.getMainAttributes();
if (attr == null)
return Collections.emptyList();
String path = attr.getValue(Attributes.Name.CLASS_PATH);
if (path == null)
return Collections.emptyList();
List<File> list = new ArrayList<File>();
for (StringTokenizer st = new StringTokenizer(path); st.hasMoreTokens(); ) {
String elt = st.nextToken();
File f = (parent == null ? new File(elt) : new File(parent, elt));
list.add(f);
}
return list;
} finally {
jarFile.close();
}
}
}

View File

@@ -0,0 +1,881 @@
/*
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.file;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipFile;
import javax.lang.model.SourceVersion;
import javax.tools.FileObject;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import com.sun.tools.javac.file.RelativePath.RelativeFile;
import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
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 javax.tools.StandardLocation.*;
/**
* This class provides access to the source, class and other files
* used by the compiler and related tools.
*
* <p><b>This is NOT part of any supported API.
* 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 JavacFileManager extends BaseFileManager implements StandardJavaFileManager {
public static char[] toArray(CharBuffer buffer) {
if (buffer.hasArray())
return ((CharBuffer)buffer.compact().flip()).array();
else
return buffer.toString().toCharArray();
}
private FSInfo fsInfo;
private boolean contextUseOptimizedZip;
private ZipFileIndexCache zipFileIndexCache;
private final Set<JavaFileObject.Kind> sourceOrClass =
EnumSet.of(JavaFileObject.Kind.SOURCE, JavaFileObject.Kind.CLASS);
protected boolean mmappedIO;
protected boolean symbolFileEnabled;
protected enum SortFiles implements Comparator<File> {
FORWARD {
public int compare(File f1, File f2) {
return f1.getName().compareTo(f2.getName());
}
},
REVERSE {
public int compare(File f1, File f2) {
return -f1.getName().compareTo(f2.getName());
}
};
};
protected SortFiles sortFiles;
/**
* Register a Context.Factory to create a JavacFileManager.
*/
public static void preRegister(Context context) {
context.put(JavaFileManager.class, new Context.Factory<JavaFileManager>() {
public JavaFileManager make(Context c) {
return new JavacFileManager(c, true, null);
}
});
}
/**
* Create a JavacFileManager using a given context, optionally registering
* it as the JavaFileManager for that context.
*/
public JavacFileManager(Context context, boolean register, Charset charset) {
super(charset);
if (register)
context.put(JavaFileManager.class, this);
setContext(context);
}
/**
* Set the context for JavacFileManager.
*/
@Override
public void setContext(Context context) {
super.setContext(context);
fsInfo = FSInfo.instance(context);
contextUseOptimizedZip = options.getBoolean("useOptimizedZip", true);
if (contextUseOptimizedZip)
zipFileIndexCache = ZipFileIndexCache.getSharedInstance();
mmappedIO = options.isSet("mmappedIO");
symbolFileEnabled = !options.isSet("ignore.symbol.file");
String sf = options.get("sortFiles");
if (sf != null) {
sortFiles = (sf.equals("reverse") ? SortFiles.REVERSE : SortFiles.FORWARD);
}
}
/**
* Set whether or not to use ct.sym as an alternate to rt.jar.
*/
public void setSymbolFileEnabled(boolean b) {
symbolFileEnabled = b;
}
@Override
public boolean isDefaultBootClassPath() {
return locations.isDefaultBootClassPath();
}
public JavaFileObject getFileForInput(String name) {
return getRegularFile(new File(name));
}
public JavaFileObject getRegularFile(File file) {
return new RegularFileObject(this, file);
}
public JavaFileObject getFileForOutput(String classname,
JavaFileObject.Kind kind,
JavaFileObject sibling)
throws IOException
{
return getJavaFileForOutput(CLASS_OUTPUT, classname, kind, sibling);
}
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) {
ListBuffer<File> files = new ListBuffer<File>();
for (String name : names)
files.append(new File(nullCheck(name)));
return getJavaFileObjectsFromFiles(files.toList());
}
public Iterable<? extends JavaFileObject> getJavaFileObjects(String... names) {
return getJavaFileObjectsFromStrings(Arrays.asList(nullCheck(names)));
}
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
// impls of JavaFileManager to have to be dependent on the source level.
// Therefore we simply check that the argument is a sequence of identifiers
// separated by ".".
for (String s : name.split("\\.", -1)) {
if (!SourceVersion.isIdentifier(s))
return false;
}
return true;
}
private static void validateClassName(String className) {
if (!isValidName(className))
throw new IllegalArgumentException("Invalid class name: " + className);
}
private static void validatePackageName(String packageName) {
if (packageName.length() > 0 && !isValidName(packageName))
throw new IllegalArgumentException("Invalid packageName name: " + packageName);
}
public static void testName(String name,
boolean isValidPackageName,
boolean isValidClassName)
{
try {
validatePackageName(name);
if (!isValidPackageName)
throw new AssertionError("Invalid package name accepted: " + name);
printAscii("Valid package name: \"%s\"", name);
} catch (IllegalArgumentException e) {
if (isValidPackageName)
throw new AssertionError("Valid package name rejected: " + name);
printAscii("Invalid package name: \"%s\"", name);
}
try {
validateClassName(name);
if (!isValidClassName)
throw new AssertionError("Invalid class name accepted: " + name);
printAscii("Valid class name: \"%s\"", name);
} catch (IllegalArgumentException e) {
if (isValidClassName)
throw new AssertionError("Valid class name rejected: " + name);
printAscii("Invalid class name: \"%s\"", name);
}
}
private static void printAscii(String format, Object... args) {
String message;
try {
final String ascii = "US-ASCII";
message = new String(String.format(null, format, args).getBytes(ascii), ascii);
} catch (java.io.UnsupportedEncodingException ex) {
throw new AssertionError(ex);
}
System.out.println(message);
}
/**
* Insert all files in subdirectory subdirectory of directory directory
* which match fileKinds into resultList
*/
private void listDirectory(File directory,
RelativeDirectory subdirectory,
Set<JavaFileObject.Kind> fileKinds,
boolean recurse,
ListBuffer<JavaFileObject> resultList) {
File d = subdirectory.getFile(directory);
if (!caseMapCheck(d, subdirectory))
return;
File[] files = d.listFiles();
if (files == null)
return;
if (sortFiles != null)
Arrays.sort(files, sortFiles);
for (File f: files) {
String fname = f.getName();
if (f.isDirectory()) {
if (recurse && SourceVersion.isIdentifier(fname)) {
listDirectory(directory,
new RelativeDirectory(subdirectory, fname),
fileKinds,
recurse,
resultList);
}
} else {
if (isValidFile(fname, fileKinds)) {
JavaFileObject fe =
new RegularFileObject(this, fname, new File(d, fname));
resultList.append(fe);
}
}
}
}
/**
* Insert all files in subdirectory subdirectory of archive archive
* which match fileKinds into resultList
*/
private void listArchive(Archive archive,
RelativeDirectory subdirectory,
Set<JavaFileObject.Kind> fileKinds,
boolean recurse,
ListBuffer<JavaFileObject> resultList) {
// Get the files directly in the subdir
List<String> files = archive.getFiles(subdirectory);
if (files != null) {
for (; !files.isEmpty(); files = files.tail) {
String file = files.head;
if (isValidFile(file, fileKinds)) {
resultList.append(archive.getFileObject(subdirectory, file));
}
}
}
if (recurse) {
for (RelativeDirectory s: archive.getSubdirectories()) {
if (subdirectory.contains(s)) {
// Because the archive map is a flat list of directories,
// the enclosing loop will pick up all child subdirectories.
// Therefore, there is no need to recurse deeper.
listArchive(archive, s, fileKinds, false, resultList);
}
}
}
}
/**
* container is a directory, a zip file, or a non-existant path.
* Insert all files in subdirectory subdirectory of container which
* match fileKinds into resultList
*/
private void listContainer(File container,
RelativeDirectory subdirectory,
Set<JavaFileObject.Kind> fileKinds,
boolean recurse,
ListBuffer<JavaFileObject> resultList) {
Archive archive = archives.get(container);
if (archive == null) {
// archives are not created for directories.
if (fsInfo.isDirectory(container)) {
listDirectory(container,
subdirectory,
fileKinds,
recurse,
resultList);
return;
}
// Not a directory; either a file or non-existant, create the archive
try {
archive = openArchive(container);
} catch (IOException ex) {
log.error("error.reading.file",
container, getMessage(ex));
return;
}
}
listArchive(archive,
subdirectory,
fileKinds,
recurse,
resultList);
}
private boolean isValidFile(String s, Set<JavaFileObject.Kind> fileKinds) {
JavaFileObject.Kind kind = getKind(s);
return fileKinds.contains(kind);
}
private static final boolean fileSystemIsCaseSensitive =
File.separatorChar == '/';
/** Hack to make Windows case sensitive. Test whether given path
* ends in a string of characters with the same case as given name.
* Ignore file separators in both path and name.
*/
private boolean caseMapCheck(File f, RelativePath name) {
if (fileSystemIsCaseSensitive) return true;
// Note that getCanonicalPath() returns the case-sensitive
// spelled file name.
String path;
try {
path = f.getCanonicalPath();
} catch (IOException ex) {
return false;
}
char[] pcs = path.toCharArray();
char[] ncs = name.path.toCharArray();
int i = pcs.length - 1;
int j = ncs.length - 1;
while (i >= 0 && j >= 0) {
while (i >= 0 && pcs[i] == File.separatorChar) i--;
while (j >= 0 && ncs[j] == '/') j--;
if (i >= 0 && j >= 0) {
if (pcs[i] != ncs[j]) return false;
i--;
j--;
}
}
return j < 0;
}
/**
* An archive provides a flat directory structure of a ZipFile by
* mapping directory names to lists of files (basenames).
*/
public interface Archive {
void close() throws IOException;
boolean contains(RelativePath name);
JavaFileObject getFileObject(RelativeDirectory subdirectory, String file);
List<String> getFiles(RelativeDirectory subdirectory);
Set<RelativeDirectory> getSubdirectories();
}
public class MissingArchive implements Archive {
final File zipFileName;
public MissingArchive(File name) {
zipFileName = name;
}
public boolean contains(RelativePath name) {
return false;
}
public void close() {
}
public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
return null;
}
public List<String> getFiles(RelativeDirectory subdirectory) {
return List.nil();
}
public Set<RelativeDirectory> getSubdirectories() {
return Collections.emptySet();
}
@Override
public String toString() {
return "MissingArchive[" + zipFileName + "]";
}
}
/** A directory of zip files already opened.
*/
Map<File, Archive> archives = new HashMap<File,Archive>();
private static final String[] symbolFileLocation = { "lib", "ct.sym" };
private static final RelativeDirectory symbolFilePrefix
= new RelativeDirectory("META-INF/sym/rt.jar/");
/*
* This method looks for a ZipFormatException and takes appropriate
* evasive action. If there is a failure in the fast mode then we
* fail over to the platform zip, and allow it to deal with a potentially
* non compliant zip file.
*/
protected Archive openArchive(File zipFilename) throws IOException {
try {
return openArchive(zipFilename, contextUseOptimizedZip);
} catch (IOException ioe) {
if (ioe instanceof ZipFileIndex.ZipFormatException) {
return openArchive(zipFilename, false);
} else {
throw ioe;
}
}
}
/** Open a new zip file directory, and cache it.
*/
private Archive openArchive(File zipFileName, boolean useOptimizedZip) throws IOException {
File origZipFileName = zipFileName;
if (symbolFileEnabled && locations.isDefaultBootClassPathRtJar(zipFileName)) {
File file = zipFileName.getParentFile().getParentFile(); // ${java.home}
if (new File(file.getName()).equals(new File("jre")))
file = file.getParentFile();
// file == ${jdk.home}
for (String name : symbolFileLocation)
file = new File(file, name);
// file == ${jdk.home}/lib/ct.sym
if (file.exists())
zipFileName = file;
}
Archive archive;
try {
ZipFile zdir = null;
boolean usePreindexedCache = false;
String preindexCacheLocation = null;
if (!useOptimizedZip) {
zdir = new ZipFile(zipFileName);
} else {
usePreindexedCache = options.isSet("usezipindex");
preindexCacheLocation = options.get("java.io.tmpdir");
String optCacheLoc = options.get("cachezipindexdir");
if (optCacheLoc != null && optCacheLoc.length() != 0) {
if (optCacheLoc.startsWith("\"")) {
if (optCacheLoc.endsWith("\"")) {
optCacheLoc = optCacheLoc.substring(1, optCacheLoc.length() - 1);
}
else {
optCacheLoc = optCacheLoc.substring(1);
}
}
File cacheDir = new File(optCacheLoc);
if (cacheDir.exists() && cacheDir.canWrite()) {
preindexCacheLocation = optCacheLoc;
if (!preindexCacheLocation.endsWith("/") &&
!preindexCacheLocation.endsWith(File.separator)) {
preindexCacheLocation += File.separator;
}
}
}
}
if (origZipFileName == zipFileName) {
if (!useOptimizedZip) {
archive = new ZipArchive(this, zdir);
} else {
archive = new ZipFileIndexArchive(this,
zipFileIndexCache.getZipFileIndex(zipFileName,
null,
usePreindexedCache,
preindexCacheLocation,
options.isSet("writezipindexfiles")));
}
} else {
if (!useOptimizedZip) {
archive = new SymbolArchive(this, origZipFileName, zdir, symbolFilePrefix);
} else {
archive = new ZipFileIndexArchive(this,
zipFileIndexCache.getZipFileIndex(zipFileName,
symbolFilePrefix,
usePreindexedCache,
preindexCacheLocation,
options.isSet("writezipindexfiles")));
}
}
} catch (FileNotFoundException ex) {
archive = new MissingArchive(zipFileName);
} catch (ZipFileIndex.ZipFormatException zfe) {
throw zfe;
} catch (IOException ex) {
if (zipFileName.exists())
log.error("error.reading.file", zipFileName, getMessage(ex));
archive = new MissingArchive(zipFileName);
}
archives.put(origZipFileName, archive);
return archive;
}
/** Flush any output resources.
*/
public void flush() {
contentCache.clear();
}
/**
* Close the JavaFileManager, releasing resources.
*/
public void close() {
for (Iterator<Archive> i = archives.values().iterator(); i.hasNext(); ) {
Archive a = i.next();
i.remove();
try {
a.close();
} catch (IOException e) {
}
}
}
private String defaultEncodingName;
private String getDefaultEncodingName() {
if (defaultEncodingName == null) {
defaultEncodingName =
new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding();
}
return defaultEncodingName;
}
public ClassLoader getClassLoader(Location location) {
nullCheck(location);
Iterable<? extends File> path = getLocation(location);
if (path == null)
return null;
ListBuffer<URL> lb = new ListBuffer<URL>();
for (File f: path) {
try {
lb.append(f.toURI().toURL());
} catch (MalformedURLException e) {
throw new AssertionError(e);
}
}
return getClassLoader(lb.toArray(new URL[lb.size()]));
}
public Iterable<JavaFileObject> list(Location location,
String packageName,
Set<JavaFileObject.Kind> kinds,
boolean recurse)
throws IOException
{
// validatePackageName(packageName);
nullCheck(packageName);
nullCheck(kinds);
Iterable<? extends File> path = getLocation(location);
if (path == null)
return List.nil();
RelativeDirectory subdirectory = RelativeDirectory.forPackage(packageName);
ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
for (File directory : path)
listContainer(directory, subdirectory, kinds, recurse, results);
return results.toList();
}
public String inferBinaryName(Location location, JavaFileObject file) {
file.getClass(); // null check
location.getClass(); // null check
// Need to match the path semantics of list(location, ...)
Iterable<? extends File> path = getLocation(location);
if (path == null) {
return null;
}
if (file instanceof BaseFileObject) {
return ((BaseFileObject) file).inferBinaryName(path);
} else
throw new IllegalArgumentException(file.getClass().getName());
}
public boolean isSameFile(FileObject a, FileObject b) {
nullCheck(a);
nullCheck(b);
if (!(a instanceof BaseFileObject))
throw new IllegalArgumentException("Not supported: " + a);
if (!(b instanceof BaseFileObject))
throw new IllegalArgumentException("Not supported: " + b);
return a.equals(b);
}
public boolean hasLocation(Location location) {
return getLocation(location) != null;
}
public JavaFileObject getJavaFileForInput(Location location,
String className,
JavaFileObject.Kind kind)
throws IOException
{
nullCheck(location);
// validateClassName(className);
nullCheck(className);
nullCheck(kind);
if (!sourceOrClass.contains(kind))
throw new IllegalArgumentException("Invalid kind: " + kind);
return getFileForInput(location, RelativeFile.forClass(className, kind));
}
public FileObject getFileForInput(Location location,
String packageName,
String relativeName)
throws IOException
{
nullCheck(location);
// validatePackageName(packageName);
nullCheck(packageName);
if (!isRelativeUri(relativeName))
throw new IllegalArgumentException("Invalid relative name: " + relativeName);
RelativeFile name = packageName.length() == 0
? new RelativeFile(relativeName)
: new RelativeFile(RelativeDirectory.forPackage(packageName), relativeName);
return getFileForInput(location, name);
}
private JavaFileObject getFileForInput(Location location, RelativeFile name) throws IOException {
Iterable<? extends File> path = getLocation(location);
if (path == null)
return null;
for (File dir: path) {
Archive a = archives.get(dir);
if (a == null) {
if (fsInfo.isDirectory(dir)) {
File f = name.getFile(dir);
if (f.exists())
return new RegularFileObject(this, f);
continue;
}
// Not a directory, create the archive
a = openArchive(dir);
}
// Process the archive
if (a.contains(name)) {
return a.getFileObject(name.dirname(), name.basename());
}
}
return null;
}
public JavaFileObject getJavaFileForOutput(Location location,
String className,
JavaFileObject.Kind kind,
FileObject sibling)
throws IOException
{
nullCheck(location);
// validateClassName(className);
nullCheck(className);
nullCheck(kind);
if (!sourceOrClass.contains(kind))
throw new IllegalArgumentException("Invalid kind: " + kind);
return getFileForOutput(location, RelativeFile.forClass(className, kind), sibling);
}
public FileObject getFileForOutput(Location location,
String packageName,
String relativeName,
FileObject sibling)
throws IOException
{
nullCheck(location);
// validatePackageName(packageName);
nullCheck(packageName);
if (!isRelativeUri(relativeName))
throw new IllegalArgumentException("Invalid relative name: " + relativeName);
RelativeFile name = packageName.length() == 0
? new RelativeFile(relativeName)
: new RelativeFile(RelativeDirectory.forPackage(packageName), relativeName);
return getFileForOutput(location, name, sibling);
}
private JavaFileObject getFileForOutput(Location location,
RelativeFile fileName,
FileObject sibling)
throws IOException
{
File dir;
if (location == CLASS_OUTPUT) {
if (getClassOutDir() != null) {
dir = getClassOutDir();
} else {
File siblingDir = null;
if (sibling != null && sibling instanceof RegularFileObject) {
siblingDir = ((RegularFileObject)sibling).file.getParentFile();
}
return new RegularFileObject(this, new File(siblingDir, fileName.basename()));
}
} else if (location == SOURCE_OUTPUT) {
dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir());
} else {
Iterable<? extends File> path = locations.getLocation(location);
dir = null;
for (File f: path) {
dir = f;
break;
}
}
File file = fileName.getFile(dir); // null-safe
return new RegularFileObject(this, file);
}
public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(
Iterable<? extends File> files)
{
ArrayList<RegularFileObject> result;
if (files instanceof Collection<?>)
result = new ArrayList<RegularFileObject>(((Collection<?>)files).size());
else
result = new ArrayList<RegularFileObject>();
for (File f: files)
result.add(new RegularFileObject(this, nullCheck(f)));
return result;
}
public Iterable<? extends JavaFileObject> getJavaFileObjects(File... files) {
return getJavaFileObjectsFromFiles(Arrays.asList(nullCheck(files)));
}
public void setLocation(Location location,
Iterable<? extends File> path)
throws IOException
{
nullCheck(location);
locations.setLocation(location, path);
}
public Iterable<? extends File> getLocation(Location location) {
nullCheck(location);
return locations.getLocation(location);
}
private File getClassOutDir() {
return locations.getOutputLocation(CLASS_OUTPUT);
}
private File getSourceOutDir() {
return locations.getOutputLocation(SOURCE_OUTPUT);
}
/**
* Enforces the specification of a "relative" name as used in
* {@linkplain #getFileForInput(Location,String,String)
* getFileForInput}. This method must follow the rules defined in
* that method, do not make any changes without consulting the
* specification.
*/
protected static boolean isRelativeUri(URI uri) {
if (uri.isAbsolute())
return false;
String path = uri.normalize().getPath();
if (path.length() == 0 /* isEmpty() is mustang API */)
return false;
if (!path.equals(uri.getPath())) // implicitly checks for embedded . and ..
return false;
if (path.startsWith("/") || path.startsWith("./") || path.startsWith("../"))
return false;
return true;
}
// Convenience method
protected static boolean isRelativeUri(String u) {
try {
return isRelativeUri(new URI(u));
} catch (URISyntaxException e) {
return false;
}
}
/**
* Converts a relative file name to a relative URI. This is
* different from File.toURI as this method does not canonicalize
* the file before creating the URI. Furthermore, no schema is
* used.
* @param file a relative file name
* @return a relative URI
* @throws IllegalArgumentException if the file name is not
* relative according to the definition given in {@link
* javax.tools.JavaFileManager#getFileForInput}
*/
public static String getRelativeName(File file) {
if (!file.isAbsolute()) {
String result = file.getPath().replace(File.separatorChar, '/');
if (isRelativeUri(result))
return result;
}
throw new IllegalArgumentException("Invalid relative path: " + file);
}
/**
* Get a detail message from an IOException.
* Most, but not all, instances of IOException provide a non-null result
* for getLocalizedMessage(). But some instances return null: in these
* cases, fallover to getMessage(), and if even that is null, return the
* name of the exception itself.
* @param e an IOException
* @return a string to include in a compiler diagnostic
*/
public static String getMessage(IOException e) {
String s = e.getLocalizedMessage();
if (s != null)
return s;
s = e.getMessage();
if (s != null)
return s;
return e.toString();
}
}

View File

@@ -0,0 +1,777 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.file;
import java.io.FileNotFoundException;
import java.util.Iterator;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.zip.ZipFile;
import javax.tools.JavaFileManager.Location;
import javax.tools.StandardLocation;
import com.sun.tools.javac.code.Lint;
import com.sun.tools.javac.main.Option;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Options;
import com.sun.tools.javac.util.StringUtils;
import javax.tools.JavaFileManager;
import javax.tools.StandardJavaFileManager;
import static javax.tools.StandardLocation.*;
import static com.sun.tools.javac.main.Option.*;
/** This class converts command line arguments, environment variables
* and system properties (in File.pathSeparator-separated String form)
* into a boot class path, user class path, and source path (in
* {@code Collection<String>} form).
*
* <p><b>This is NOT part of any supported API.
* 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 Locations {
/** The log to use for warning output */
private Log log;
/** Collection of command-line options */
private Options options;
/** Handler for -Xlint options */
private Lint lint;
/** Access to (possibly cached) file info */
private FSInfo fsInfo;
/** Whether to warn about non-existent path elements */
private boolean warn;
// TODO: remove need for this
private boolean inited = false; // TODO? caching bad?
public Locations() {
initHandlers();
}
public void update(Log log, Options options, Lint lint, FSInfo fsInfo) {
this.log = log;
this.options = options;
this.lint = lint;
this.fsInfo = fsInfo;
}
public Collection<File> bootClassPath() {
return getLocation(PLATFORM_CLASS_PATH);
}
public boolean isDefaultBootClassPath() {
BootClassPathLocationHandler h =
(BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH);
return h.isDefault();
}
boolean isDefaultBootClassPathRtJar(File file) {
BootClassPathLocationHandler h =
(BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH);
return h.isDefaultRtJar(file);
}
public Collection<File> userClassPath() {
return getLocation(CLASS_PATH);
}
public Collection<File> sourcePath() {
Collection<File> p = getLocation(SOURCE_PATH);
// TODO: this should be handled by the LocationHandler
return p == null || p.isEmpty() ? null : p;
}
/**
* Split a path into its elements. Empty path elements will be ignored.
* @param path The path to be split
* @return The elements of the path
*/
private static Iterable<File> getPathEntries(String path) {
return getPathEntries(path, null);
}
/**
* Split a path into its elements. If emptyPathDefault is not null, all
* empty elements in the path, including empty elements at either end of
* the path, will be replaced with the value of emptyPathDefault.
* @param path The path to be split
* @param emptyPathDefault The value to substitute for empty path elements,
* or null, to ignore empty path elements
* @return The elements of the path
*/
private static Iterable<File> getPathEntries(String path, File emptyPathDefault) {
ListBuffer<File> entries = new ListBuffer<File>();
int start = 0;
while (start <= path.length()) {
int sep = path.indexOf(File.pathSeparatorChar, start);
if (sep == -1)
sep = path.length();
if (start < sep)
entries.add(new File(path.substring(start, sep)));
else if (emptyPathDefault != null)
entries.add(emptyPathDefault);
start = sep + 1;
}
return entries;
}
/**
* Utility class to help evaluate a path option.
* Duplicate entries are ignored, jar class paths can be expanded.
*/
private class Path extends LinkedHashSet<File> {
private static final long serialVersionUID = 0;
private boolean expandJarClassPaths = false;
private Set<File> canonicalValues = new HashSet<File>();
public Path expandJarClassPaths(boolean x) {
expandJarClassPaths = x;
return this;
}
/** What to use when path element is the empty string */
private File emptyPathDefault = null;
public Path emptyPathDefault(File x) {
emptyPathDefault = x;
return this;
}
public Path() { super(); }
public Path addDirectories(String dirs, boolean warn) {
boolean prev = expandJarClassPaths;
expandJarClassPaths = true;
try {
if (dirs != null)
for (File dir : getPathEntries(dirs))
addDirectory(dir, warn);
return this;
} finally {
expandJarClassPaths = prev;
}
}
public Path addDirectories(String dirs) {
return addDirectories(dirs, warn);
}
private void addDirectory(File dir, boolean warn) {
if (!dir.isDirectory()) {
if (warn)
log.warning(Lint.LintCategory.PATH,
"dir.path.element.not.found", dir);
return;
}
File[] files = dir.listFiles();
if (files == null)
return;
for (File direntry : files) {
if (isArchive(direntry))
addFile(direntry, warn);
}
}
public Path addFiles(String files, boolean warn) {
if (files != null) {
addFiles(getPathEntries(files, emptyPathDefault), warn);
}
return this;
}
public Path addFiles(String files) {
return addFiles(files, warn);
}
public Path addFiles(Iterable<? extends File> files, boolean warn) {
if (files != null) {
for (File file: files)
addFile(file, warn);
}
return this;
}
public Path addFiles(Iterable<? extends File> files) {
return addFiles(files, warn);
}
public void addFile(File file, boolean warn) {
if (contains(file)) {
// discard duplicates
return;
}
if (! fsInfo.exists(file)) {
/* No such file or directory exists */
if (warn) {
log.warning(Lint.LintCategory.PATH,
"path.element.not.found", file);
}
super.add(file);
return;
}
File canonFile = fsInfo.getCanonicalFile(file);
if (canonicalValues.contains(canonFile)) {
/* Discard duplicates and avoid infinite recursion */
return;
}
if (fsInfo.isFile(file)) {
/* File is an ordinary file. */
if (!isArchive(file)) {
/* Not a recognized extension; open it to see if
it looks like a valid zip file. */
try {
ZipFile z = new ZipFile(file);
z.close();
if (warn) {
log.warning(Lint.LintCategory.PATH,
"unexpected.archive.file", file);
}
} catch (IOException e) {
// FIXME: include e.getLocalizedMessage in warning
if (warn) {
log.warning(Lint.LintCategory.PATH,
"invalid.archive.file", file);
}
return;
}
}
}
/* Now what we have left is either a directory or a file name
conforming to archive naming convention */
super.add(file);
canonicalValues.add(canonFile);
if (expandJarClassPaths && fsInfo.isFile(file))
addJarClassPath(file, warn);
}
// Adds referenced classpath elements from a jar's Class-Path
// Manifest entry. In some future release, we may want to
// update this code to recognize URLs rather than simple
// filenames, but if we do, we should redo all path-related code.
private void addJarClassPath(File jarFile, boolean warn) {
try {
for (File f: fsInfo.getJarClassPath(jarFile)) {
addFile(f, warn);
}
} catch (IOException e) {
log.error("error.reading.file", jarFile, JavacFileManager.getMessage(e));
}
}
}
/**
* Base class for handling support for the representation of Locations.
* Implementations are responsible for handling the interactions between
* the command line options for a location, and API access via setLocation.
* @see #initHandlers
* @see #getHandler
*/
protected abstract class LocationHandler {
final Location location;
final Set<Option> options;
/**
* Create a handler. The location and options provide a way to map
* from a location or an option to the corresponding handler.
* @see #initHandlers
*/
protected LocationHandler(Location location, Option... options) {
this.location = location;
this.options = options.length == 0 ?
EnumSet.noneOf(Option.class):
EnumSet.copyOf(Arrays.asList(options));
}
// TODO: TEMPORARY, while Options still used for command line options
void update(Options optionTable) {
for (Option o: options) {
String v = optionTable.get(o);
if (v != null) {
handleOption(o, v);
}
}
}
/** @see JavaFileManager#handleOption */
abstract boolean handleOption(Option option, String value);
/** @see StandardJavaFileManager#getLocation */
abstract Collection<File> getLocation();
/** @see StandardJavaFileManager#setLocation */
abstract void setLocation(Iterable<? extends File> files) throws IOException;
}
/**
* General purpose implementation for output locations,
* such as -d/CLASS_OUTPUT and -s/SOURCE_OUTPUT.
* All options are treated as equivalent (i.e. aliases.)
* The value is a single file, possibly null.
*/
private class OutputLocationHandler extends LocationHandler {
private File outputDir;
OutputLocationHandler(Location location, Option... options) {
super(location, options);
}
@Override
boolean handleOption(Option option, String value) {
if (!options.contains(option))
return false;
// TODO: could/should validate outputDir exists and is a directory
// need to decide how best to report issue for benefit of
// direct API call on JavaFileManager.handleOption(specifies IAE)
// vs. command line decoding.
outputDir = new File(value);
return true;
}
@Override
Collection<File> getLocation() {
return (outputDir == null) ? null : Collections.singleton(outputDir);
}
@Override
void setLocation(Iterable<? extends File> files) throws IOException {
if (files == null) {
outputDir = null;
} else {
Iterator<? extends File> pathIter = files.iterator();
if (!pathIter.hasNext())
throw new IllegalArgumentException("empty path for directory");
File dir = pathIter.next();
if (pathIter.hasNext())
throw new IllegalArgumentException("path too long for directory");
if (!dir.exists())
throw new FileNotFoundException(dir + ": does not exist");
else if (!dir.isDirectory())
throw new IOException(dir + ": not a directory");
outputDir = dir;
}
}
}
/**
* General purpose implementation for search path locations,
* such as -sourcepath/SOURCE_PATH and -processorPath/ANNOTATION_PROCESS_PATH.
* All options are treated as equivalent (i.e. aliases.)
* The value is an ordered set of files and/or directories.
*/
private class SimpleLocationHandler extends LocationHandler {
protected Collection<File> searchPath;
SimpleLocationHandler(Location location, Option... options) {
super(location, options);
}
@Override
boolean handleOption(Option option, String value) {
if (!options.contains(option))
return false;
searchPath = value == null ? null :
Collections.unmodifiableCollection(createPath().addFiles(value));
return true;
}
@Override
Collection<File> getLocation() {
return searchPath;
}
@Override
void setLocation(Iterable<? extends File> files) {
Path p;
if (files == null) {
p = computePath(null);
} else {
p = createPath().addFiles(files);
}
searchPath = Collections.unmodifiableCollection(p);
}
protected Path computePath(String value) {
return createPath().addFiles(value);
}
protected Path createPath() {
return new Path();
}
}
/**
* Subtype of SimpleLocationHandler for -classpath/CLASS_PATH.
* If no value is given, a default is provided, based on system properties
* and other values.
*/
private class ClassPathLocationHandler extends SimpleLocationHandler {
ClassPathLocationHandler() {
super(StandardLocation.CLASS_PATH,
Option.CLASSPATH, Option.CP);
}
@Override
Collection<File> getLocation() {
lazy();
return searchPath;
}
@Override
protected Path computePath(String value) {
String cp = value;
// CLASSPATH environment variable when run from `javac'.
if (cp == null) cp = System.getProperty("env.class.path");
// If invoked via a java VM (not the javac launcher), use the
// platform class path
if (cp == null && System.getProperty("application.home") == null)
cp = System.getProperty("java.class.path");
// Default to current working directory.
if (cp == null) cp = ".";
return createPath().addFiles(cp);
}
@Override
protected Path createPath() {
return new Path()
.expandJarClassPaths(true) // Only search user jars for Class-Paths
.emptyPathDefault(new File(".")); // Empty path elt ==> current directory
}
private void lazy() {
if (searchPath == null)
setLocation(null);
}
}
/**
* Custom subtype of LocationHandler for PLATFORM_CLASS_PATH.
* Various options are supported for different components of the
* platform class path.
* Setting a value with setLocation overrides all existing option values.
* Setting any option overrides any value set with setLocation, and reverts
* to using default values for options that have not been set.
* Setting -bootclasspath or -Xbootclasspath overrides any existing
* value for -Xbootclasspath/p: and -Xbootclasspath/a:.
*/
private class BootClassPathLocationHandler extends LocationHandler {
private Collection<File> searchPath;
final Map<Option, String> optionValues = new EnumMap<Option,String>(Option.class);
/**
* rt.jar as found on the default bootclasspath.
* If the user specified a bootclasspath, null is used.
*/
private File defaultBootClassPathRtJar = null;
/**
* Is bootclasspath the default?
*/
private boolean isDefaultBootClassPath;
BootClassPathLocationHandler() {
super(StandardLocation.PLATFORM_CLASS_PATH,
Option.BOOTCLASSPATH, Option.XBOOTCLASSPATH,
Option.XBOOTCLASSPATH_PREPEND,
Option.XBOOTCLASSPATH_APPEND,
Option.ENDORSEDDIRS, Option.DJAVA_ENDORSED_DIRS,
Option.EXTDIRS, Option.DJAVA_EXT_DIRS);
}
boolean isDefault() {
lazy();
return isDefaultBootClassPath;
}
boolean isDefaultRtJar(File file) {
lazy();
return file.equals(defaultBootClassPathRtJar);
}
@Override
boolean handleOption(Option option, String value) {
if (!options.contains(option))
return false;
option = canonicalize(option);
optionValues.put(option, value);
if (option == BOOTCLASSPATH) {
optionValues.remove(XBOOTCLASSPATH_PREPEND);
optionValues.remove(XBOOTCLASSPATH_APPEND);
}
searchPath = null; // reset to "uninitialized"
return true;
}
// where
// TODO: would be better if option aliasing was handled at a higher
// level
private Option canonicalize(Option option) {
switch (option) {
case XBOOTCLASSPATH:
return Option.BOOTCLASSPATH;
case DJAVA_ENDORSED_DIRS:
return Option.ENDORSEDDIRS;
case DJAVA_EXT_DIRS:
return Option.EXTDIRS;
default:
return option;
}
}
@Override
Collection<File> getLocation() {
lazy();
return searchPath;
}
@Override
void setLocation(Iterable<? extends File> files) {
if (files == null) {
searchPath = null; // reset to "uninitialized"
} else {
defaultBootClassPathRtJar = null;
isDefaultBootClassPath = false;
Path p = new Path().addFiles(files, false);
searchPath = Collections.unmodifiableCollection(p);
optionValues.clear();
}
}
Path computePath() {
defaultBootClassPathRtJar = null;
Path path = new Path();
String bootclasspathOpt = optionValues.get(BOOTCLASSPATH);
String endorseddirsOpt = optionValues.get(ENDORSEDDIRS);
String extdirsOpt = optionValues.get(EXTDIRS);
String xbootclasspathPrependOpt = optionValues.get(XBOOTCLASSPATH_PREPEND);
String xbootclasspathAppendOpt = optionValues.get(XBOOTCLASSPATH_APPEND);
path.addFiles(xbootclasspathPrependOpt);
if (endorseddirsOpt != null)
path.addDirectories(endorseddirsOpt);
else
path.addDirectories(System.getProperty("java.endorsed.dirs"), false);
if (bootclasspathOpt != null) {
path.addFiles(bootclasspathOpt);
} else {
// Standard system classes for this compiler's release.
String files = System.getProperty("sun.boot.class.path");
path.addFiles(files, false);
File rt_jar = new File("rt.jar");
for (File file : getPathEntries(files)) {
if (new File(file.getName()).equals(rt_jar))
defaultBootClassPathRtJar = file;
}
}
path.addFiles(xbootclasspathAppendOpt);
// Strictly speaking, standard extensions are not bootstrap
// classes, but we treat them identically, so we'll pretend
// that they are.
if (extdirsOpt != null)
path.addDirectories(extdirsOpt);
else
path.addDirectories(System.getProperty("java.ext.dirs"), false);
isDefaultBootClassPath =
(xbootclasspathPrependOpt == null) &&
(bootclasspathOpt == null) &&
(xbootclasspathAppendOpt == null);
return path;
}
private void lazy() {
if (searchPath == null)
searchPath = Collections.unmodifiableCollection(computePath());
}
}
Map<Location, LocationHandler> handlersForLocation;
Map<Option, LocationHandler> handlersForOption;
void initHandlers() {
handlersForLocation = new HashMap<Location, LocationHandler>();
handlersForOption = new EnumMap<Option, LocationHandler>(Option.class);
LocationHandler[] handlers = {
new BootClassPathLocationHandler(),
new ClassPathLocationHandler(),
new SimpleLocationHandler(StandardLocation.SOURCE_PATH, Option.SOURCEPATH),
new SimpleLocationHandler(StandardLocation.ANNOTATION_PROCESSOR_PATH, Option.PROCESSORPATH),
new OutputLocationHandler((StandardLocation.CLASS_OUTPUT), Option.D),
new OutputLocationHandler((StandardLocation.SOURCE_OUTPUT), Option.S),
new OutputLocationHandler((StandardLocation.NATIVE_HEADER_OUTPUT), Option.H)
};
for (LocationHandler h: handlers) {
handlersForLocation.put(h.location, h);
for (Option o: h.options)
handlersForOption.put(o, h);
}
}
boolean handleOption(Option option, String value) {
LocationHandler h = handlersForOption.get(option);
return (h == null ? false : h.handleOption(option, value));
}
Collection<File> getLocation(Location location) {
LocationHandler h = getHandler(location);
return (h == null ? null : h.getLocation());
}
File getOutputLocation(Location location) {
if (!location.isOutputLocation())
throw new IllegalArgumentException();
LocationHandler h = getHandler(location);
return ((OutputLocationHandler) h).outputDir;
}
void setLocation(Location location, Iterable<? extends File> files) throws IOException {
LocationHandler h = getHandler(location);
if (h == null) {
if (location.isOutputLocation())
h = new OutputLocationHandler(location);
else
h = new SimpleLocationHandler(location);
handlersForLocation.put(location, h);
}
h.setLocation(files);
}
protected LocationHandler getHandler(Location location) {
location.getClass(); // null check
lazy();
return handlersForLocation.get(location);
}
// TOGO
protected void lazy() {
if (!inited) {
warn = lint.isEnabled(Lint.LintCategory.PATH);
for (LocationHandler h: handlersForLocation.values()) {
h.update(options);
}
inited = true;
}
}
/** Is this the name of an archive file? */
private boolean isArchive(File file) {
String n = StringUtils.toLowerCase(file.getName());
return fsInfo.isFile(file)
&& (n.endsWith(".jar") || n.endsWith(".zip"));
}
/**
* Utility method for converting a search path string to an array
* of directory and JAR file URLs.
*
* Note that this method is called by apt and the DocletInvoker.
*
* @param path the search path string
* @return the resulting array of directory and JAR file URLs
*/
public static URL[] pathToURLs(String path) {
StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
URL[] urls = new URL[st.countTokens()];
int count = 0;
while (st.hasMoreTokens()) {
URL url = fileToURL(new File(st.nextToken()));
if (url != null) {
urls[count++] = url;
}
}
urls = Arrays.copyOf(urls, count);
return urls;
}
/**
* Returns the directory or JAR file URL corresponding to the specified
* local file name.
*
* @param file the File object
* @return the resulting directory or JAR file URL, or null if unknown
*/
private static URL fileToURL(File file) {
String name;
try {
name = file.getCanonicalPath();
} catch (IOException e) {
name = file.getAbsolutePath();
}
name = name.replace(File.separatorChar, '/');
if (!name.startsWith("/")) {
name = "/" + name;
}
// If the file does not exist, then assume that it's a directory
if (!file.isFile()) {
name = name + "/";
}
try {
return new URL("file", "", name);
} catch (MalformedURLException e) {
throw new IllegalArgumentException(file.toString());
}
}
}

View File

@@ -0,0 +1,251 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.file;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder;
import javax.tools.JavaFileObject;
import java.text.Normalizer;
/**
* A subclass of JavaFileObject representing regular files.
*
* <p><b>This is NOT part of any supported API.
* 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>
*/
class RegularFileObject extends BaseFileObject {
/** Have the parent directories been created?
*/
private boolean hasParents = false;
private String name;
final File file;
private Reference<File> absFileRef;
final static boolean isMacOS = System.getProperty("os.name", "").contains("OS X");
public RegularFileObject(JavacFileManager fileManager, File f) {
this(fileManager, f.getName(), f);
}
public RegularFileObject(JavacFileManager fileManager, String name, File f) {
super(fileManager);
if (f.isDirectory()) {
throw new IllegalArgumentException("directories not supported");
}
this.name = name;
this.file = f;
}
@Override
public URI toUri() {
return file.toURI().normalize();
}
@Override
public String getName() {
return file.getPath();
}
@Override
public String getShortName() {
return name;
}
@Override
public JavaFileObject.Kind getKind() {
return getKind(name);
}
@Override
public InputStream openInputStream() throws IOException {
return new FileInputStream(file);
}
@Override
public OutputStream openOutputStream() throws IOException {
fileManager.flushCache(this);
ensureParentDirectoriesExist();
return new FileOutputStream(file);
}
@Override
public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException {
CharBuffer cb = fileManager.getCachedContent(this);
if (cb == null) {
InputStream in = new FileInputStream(file);
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 {
fileManager.flushCache(this);
ensureParentDirectoriesExist();
return new OutputStreamWriter(new FileOutputStream(file), fileManager.getEncodingName());
}
@Override
public long getLastModified() {
return file.lastModified();
}
@Override
public boolean delete() {
return file.delete();
}
@Override
protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) {
return fileManager.getDecoder(fileManager.getEncodingName(), ignoreEncodingErrors);
}
@Override
protected String inferBinaryName(Iterable<? extends File> path) {
String fPath = file.getPath();
//System.err.println("RegularFileObject " + file + " " +r.getPath());
for (File dir: path) {
//System.err.println("dir: " + dir);
String dPath = dir.getPath();
if (dPath.length() == 0)
dPath = System.getProperty("user.dir");
if (!dPath.endsWith(File.separator))
dPath += File.separator;
if (fPath.regionMatches(true, 0, dPath, 0, dPath.length())
&& new File(fPath.substring(0, dPath.length())).equals(new File(dPath))) {
String relativeName = fPath.substring(dPath.length());
return removeExtension(relativeName).replace(File.separatorChar, '.');
}
}
return null;
}
@Override
public boolean isNameCompatible(String cn, JavaFileObject.Kind kind) {
cn.getClass();
// null check
if (kind == Kind.OTHER && getKind() != kind) {
return false;
}
String n = cn + kind.extension;
if (name.equals(n)) {
return true;
}
if (isMacOS && Normalizer.isNormalized(name, Normalizer.Form.NFD)
&& Normalizer.isNormalized(n, Normalizer.Form.NFC)) {
// On Mac OS X it is quite possible to file name and class
// name normalized in a different way - in that case we have to normalize file name
// to the Normal Form Compised (NFC)
String normName = Normalizer.normalize(name, Normalizer.Form.NFC);
if (normName.equals(n)) {
this.name = normName;
return true;
}
}
if (name.equalsIgnoreCase(n)) {
try {
// allow for Windows
return file.getCanonicalFile().getName().equals(n);
} catch (IOException e) {
}
}
return false;
}
private void ensureParentDirectoriesExist() throws IOException {
if (!hasParents) {
File parent = file.getParentFile();
if (parent != null && !parent.exists()) {
if (!parent.mkdirs()) {
if (!parent.exists() || !parent.isDirectory()) {
throw new IOException("could not create parent directories");
}
}
}
hasParents = true;
}
}
/**
* Check if two file objects are equal.
* Two RegularFileObjects are equal if the absolute paths of the underlying
* files are equal.
*/
@Override
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof RegularFileObject))
return false;
RegularFileObject o = (RegularFileObject) other;
return getAbsoluteFile().equals(o.getAbsoluteFile());
}
@Override
public int hashCode() {
return getAbsoluteFile().hashCode();
}
private File getAbsoluteFile() {
File absFile = (absFileRef == null ? null : absFileRef.get());
if (absFile == null) {
absFile = file.getAbsoluteFile();
absFileRef = new SoftReference<File>(absFile);
}
return absFile;
}
}

View File

@@ -0,0 +1,196 @@
/*
* Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.file;
import java.io.File;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.tools.JavaFileObject;
/**
* Used to represent a platform-neutral path within a platform-specific
* container, such as a directory or zip file.
* Internally, the file separator is always '/'.
*
* <p><b>This is NOT part of any supported API.
* 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 abstract class RelativePath implements Comparable<RelativePath> {
/**
* @param p must use '/' as an internal separator
*/
protected RelativePath(String p) {
path = p;
}
public abstract RelativeDirectory dirname();
public abstract String basename();
public File getFile(File directory) {
if (path.length() == 0)
return directory;
return new File(directory, path.replace('/', File.separatorChar));
}
public int compareTo(RelativePath other) {
return path.compareTo(other.path);
}
@Override
public boolean equals(Object other) {
if (!(other instanceof RelativePath))
return false;
return path.equals(((RelativePath) other).path);
}
@Override
public int hashCode() {
return path.hashCode();
}
@Override
public String toString() {
return "RelPath[" + path + "]";
}
public String getPath() {
return path;
}
protected final String path;
/**
* Used to represent a platform-neutral subdirectory within a platform-specific
* container, such as a directory or zip file.
* Internally, the file separator is always '/', and if the path is not empty,
* it always ends in a '/' as well.
*/
public static class RelativeDirectory extends RelativePath {
static RelativeDirectory forPackage(CharSequence packageName) {
return new RelativeDirectory(packageName.toString().replace('.', '/'));
}
/**
* @param p must use '/' as an internal separator
*/
public RelativeDirectory(String p) {
super(p.length() == 0 || p.endsWith("/") ? p : p + "/");
}
/**
* @param p must use '/' as an internal separator
*/
public RelativeDirectory(RelativeDirectory d, String p) {
this(d.path + p);
}
@Override
public RelativeDirectory dirname() {
int l = path.length();
if (l == 0)
return this;
int sep = path.lastIndexOf('/', l - 2);
return new RelativeDirectory(path.substring(0, sep + 1));
}
@Override
public String basename() {
int l = path.length();
if (l == 0)
return path;
int sep = path.lastIndexOf('/', l - 2);
return path.substring(sep + 1, l - 1);
}
/**
* Return true if this subdirectory "contains" the other path.
* A subdirectory path does not contain itself.
**/
boolean contains(RelativePath other) {
return other.path.length() > path.length() && other.path.startsWith(path);
}
@Override
public String toString() {
return "RelativeDirectory[" + path + "]";
}
}
/**
* Used to represent a platform-neutral file within a platform-specific
* container, such as a directory or zip file.
* Internally, the file separator is always '/'. It never ends in '/'.
*/
public static class RelativeFile extends RelativePath {
static RelativeFile forClass(CharSequence className, JavaFileObject.Kind kind) {
return new RelativeFile(className.toString().replace('.', '/') + kind.extension);
}
public RelativeFile(String p) {
super(p);
if (p.endsWith("/"))
throw new IllegalArgumentException(p);
}
/**
* @param p must use '/' as an internal separator
*/
public RelativeFile(RelativeDirectory d, String p) {
this(d.path + p);
}
RelativeFile(RelativeDirectory d, RelativePath p) {
this(d, p.path);
}
@Override
public RelativeDirectory dirname() {
int sep = path.lastIndexOf('/');
return new RelativeDirectory(path.substring(0, sep + 1));
}
@Override
public String basename() {
int sep = path.lastIndexOf('/');
return path.substring(sep + 1);
}
ZipEntry getZipEntry(ZipFile zip) {
return zip.getEntry(path);
}
@Override
public String toString() {
return "RelativeFile[" + path + "]";
}
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.file;
import java.io.File;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
import com.sun.tools.javac.file.RelativePath.RelativeFile;
import com.sun.tools.javac.util.List;
/**
* <p><b>This is NOT part of any supported API.
* 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 SymbolArchive extends ZipArchive {
final File origFile;
final RelativeDirectory prefix;
public SymbolArchive(JavacFileManager fileManager, File orig, ZipFile zdir, RelativeDirectory prefix) throws IOException {
super(fileManager, zdir, false);
this.origFile = orig;
this.prefix = prefix;
initMap();
}
@Override
void addZipEntry(ZipEntry entry) {
String name = entry.getName();
if (!name.startsWith(prefix.path)) {
return;
}
name = name.substring(prefix.path.length());
int i = name.lastIndexOf('/');
RelativeDirectory dirname = new RelativeDirectory(name.substring(0, i+1));
String basename = name.substring(i + 1);
if (basename.length() == 0) {
return;
}
List<String> list = map.get(dirname);
if (list == null)
list = List.nil();
list = list.prepend(basename);
map.put(dirname, list);
}
@Override
public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
RelativeDirectory prefix_subdir = new RelativeDirectory(prefix, subdirectory.path);
ZipEntry ze = new RelativeFile(prefix_subdir, file).getZipEntry(zfile);
return new SymbolFileObject(this, file, ze);
}
@Override
public String toString() {
return "SymbolArchive[" + zfile.getName() + "]";
}
/**
* A subclass of JavaFileObject representing zip entries in a symbol file.
*/
public static class SymbolFileObject extends ZipFileObject {
protected SymbolFileObject(SymbolArchive zarch, String name, ZipEntry entry) {
super(zarch, name, entry);
}
@Override
protected String inferBinaryName(Iterable<? extends File> path) {
String entryName = entry.getName();
String prefix = ((SymbolArchive) zarch).prefix.path;
if (entryName.startsWith(prefix))
entryName = entryName.substring(prefix.length());
return removeExtension(entryName).replace('/', '.');
}
}
}

View File

@@ -0,0 +1,288 @@
/*
* Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.file;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.file.JavacFileManager.Archive;
import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
import com.sun.tools.javac.file.RelativePath.RelativeFile;
import com.sun.tools.javac.util.List;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
/**
* <p><b>This is NOT part of any supported API.
* 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 ZipArchive implements Archive {
public ZipArchive(JavacFileManager fm, ZipFile zfile) throws IOException {
this(fm, zfile, true);
}
protected ZipArchive(JavacFileManager fm, ZipFile zfile, boolean initMap) throws IOException {
this.fileManager = fm;
this.zfile = zfile;
this.map = new HashMap<RelativeDirectory,List<String>>();
if (initMap)
initMap();
}
protected void initMap() throws IOException {
for (Enumeration<? extends ZipEntry> e = zfile.entries(); e.hasMoreElements(); ) {
ZipEntry entry;
try {
entry = e.nextElement();
} catch (InternalError ex) {
IOException io = new IOException();
io.initCause(ex); // convenience constructors added in Mustang :-(
throw io;
}
addZipEntry(entry);
}
}
void addZipEntry(ZipEntry entry) {
String name = entry.getName();
int i = name.lastIndexOf('/');
RelativeDirectory dirname = new RelativeDirectory(name.substring(0, i+1));
String basename = name.substring(i+1);
if (basename.length() == 0)
return;
List<String> list = map.get(dirname);
if (list == null)
list = List.nil();
list = list.prepend(basename);
map.put(dirname, list);
}
public boolean contains(RelativePath name) {
RelativeDirectory dirname = name.dirname();
String basename = name.basename();
if (basename.length() == 0)
return false;
List<String> list = map.get(dirname);
return (list != null && list.contains(basename));
}
public List<String> getFiles(RelativeDirectory subdirectory) {
return map.get(subdirectory);
}
public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
ZipEntry ze = new RelativeFile(subdirectory, file).getZipEntry(zfile);
return new ZipFileObject(this, file, ze);
}
public Set<RelativeDirectory> getSubdirectories() {
return map.keySet();
}
public void close() throws IOException {
zfile.close();
}
@Override
public String toString() {
return "ZipArchive[" + zfile.getName() + "]";
}
private File getAbsoluteFile() {
File absFile = (absFileRef == null ? null : absFileRef.get());
if (absFile == null) {
absFile = new File(zfile.getName()).getAbsoluteFile();
absFileRef = new SoftReference<File>(absFile);
}
return absFile;
}
/**
* The file manager that created this archive.
*/
protected JavacFileManager fileManager;
/**
* The index for the contents of this archive.
*/
protected final Map<RelativeDirectory,List<String>> map;
/**
* The zip file for the archive.
*/
protected final ZipFile zfile;
/**
* A reference to the absolute filename for the zip file for the archive.
*/
protected Reference<File> absFileRef;
/**
* A subclass of JavaFileObject representing zip entries.
*/
public static class ZipFileObject extends BaseFileObject {
private String name;
ZipArchive zarch;
ZipEntry entry;
protected ZipFileObject(ZipArchive zarch, String name, ZipEntry entry) {
super(zarch.fileManager);
this.zarch = zarch;
this.name = name;
this.entry = entry;
}
public URI toUri() {
File zipFile = new File(zarch.zfile.getName());
return createJarUri(zipFile, entry.getName());
}
@Override
public String getName() {
return zarch.zfile.getName() + "(" + entry.getName() + ")";
}
@Override
public String getShortName() {
return new File(zarch.zfile.getName()).getName() + "(" + entry + ")";
}
@Override
public JavaFileObject.Kind getKind() {
return getKind(entry.getName());
}
@Override
public InputStream openInputStream() throws IOException {
return zarch.zfile.getInputStream(entry);
}
@Override
public OutputStream openOutputStream() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException {
CharBuffer cb = fileManager.getCachedContent(this);
if (cb == null) {
InputStream in = zarch.zfile.getInputStream(entry);
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 {
throw new UnsupportedOperationException();
}
@Override
public long getLastModified() {
return entry.getTime();
}
@Override
public boolean delete() {
throw new UnsupportedOperationException();
}
@Override
protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) {
return fileManager.getDecoder(fileManager.getEncodingName(), ignoreEncodingErrors);
}
@Override
protected String inferBinaryName(Iterable<? extends File> path) {
String entryName = entry.getName();
return removeExtension(entryName).replace('/', '.');
}
@Override
public boolean isNameCompatible(String cn, JavaFileObject.Kind k) {
cn.getClass();
// null check
if (k == Kind.OTHER && getKind() != k) {
return false;
}
return name.equals(cn + k.extension);
}
/**
* Check if two file objects are equal.
* Two ZipFileObjects are equal if the absolute paths of the underlying
* zip files are equal and if the paths within those zip files are equal.
*/
@Override
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof ZipFileObject))
return false;
ZipFileObject o = (ZipFileObject) other;
return zarch.getAbsoluteFile().equals(o.zarch.getAbsoluteFile())
&& name.equals(o.name);
}
@Override
public int hashCode() {
return zarch.getAbsoluteFile().hashCode() + name.hashCode();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,254 @@
/*
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.file;
import java.io.IOException;
import java.util.Set;
import javax.tools.JavaFileObject;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder;
import com.sun.tools.javac.file.JavacFileManager.Archive;
import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
import com.sun.tools.javac.file.RelativePath.RelativeFile;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.List;
/**
* <p><b>This is NOT part of any supported API.
* 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 ZipFileIndexArchive implements Archive {
private final ZipFileIndex zfIndex;
private JavacFileManager fileManager;
public ZipFileIndexArchive(JavacFileManager fileManager, ZipFileIndex zdir) throws IOException {
super();
this.fileManager = fileManager;
this.zfIndex = zdir;
}
public boolean contains(RelativePath name) {
return zfIndex.contains(name);
}
public List<String> getFiles(RelativeDirectory subdirectory) {
return zfIndex.getFiles(subdirectory);
}
public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
RelativeFile fullZipFileName = new RelativeFile(subdirectory, file);
ZipFileIndex.Entry entry = zfIndex.getZipIndexEntry(fullZipFileName);
JavaFileObject ret = new ZipFileIndexFileObject(fileManager, zfIndex, entry, zfIndex.getZipFile());
return ret;
}
public Set<RelativeDirectory> getSubdirectories() {
return zfIndex.getAllDirectories();
}
public void close() throws IOException {
zfIndex.close();
}
@Override
public String toString() {
return "ZipFileIndexArchive[" + zfIndex + "]";
}
/**
* A subclass of JavaFileObject representing zip entries using the com.sun.tools.javac.file.ZipFileIndex implementation.
*/
public static class ZipFileIndexFileObject extends BaseFileObject {
/** The entry's name.
*/
private String name;
/** The zipfile containing the entry.
*/
ZipFileIndex zfIndex;
/** The underlying zip entry object.
*/
ZipFileIndex.Entry entry;
/** The InputStream for this zip entry (file.)
*/
InputStream inputStream = null;
/** The name of the zip file where this entry resides.
*/
File zipName;
ZipFileIndexFileObject(JavacFileManager fileManager, ZipFileIndex zfIndex, ZipFileIndex.Entry entry, File zipFileName) {
super(fileManager);
this.name = entry.getFileName();
this.zfIndex = zfIndex;
this.entry = entry;
this.zipName = zipFileName;
}
@Override
public URI toUri() {
return createJarUri(zipName, getPrefixedEntryName());
}
@Override
public String getName() {
return zipName + "(" + getPrefixedEntryName() + ")";
}
@Override
public String getShortName() {
return zipName.getName() + "(" + entry.getName() + ")";
}
@Override
public JavaFileObject.Kind getKind() {
return getKind(entry.getName());
}
@Override
public InputStream openInputStream() throws IOException {
if (inputStream == null) {
Assert.checkNonNull(entry); // see constructor
inputStream = new ByteArrayInputStream(zfIndex.read(entry));
}
return inputStream;
}
@Override
public OutputStream openOutputStream() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException {
CharBuffer cb = fileManager.getCachedContent(this);
if (cb == null) {
InputStream in = new ByteArrayInputStream(zfIndex.read(entry));
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); // save for next time
if (!ignoreEncodingErrors)
fileManager.cache(this, cb);
} finally {
in.close();
}
}
return cb;
}
@Override
public Writer openWriter() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public long getLastModified() {
return entry.getLastModified();
}
@Override
public boolean delete() {
throw new UnsupportedOperationException();
}
@Override
protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) {
return fileManager.getDecoder(fileManager.getEncodingName(), ignoreEncodingErrors);
}
@Override
protected String inferBinaryName(Iterable<? extends File> path) {
String entryName = entry.getName();
if (zfIndex.symbolFilePrefix != null) {
String prefix = zfIndex.symbolFilePrefix.path;
if (entryName.startsWith(prefix))
entryName = entryName.substring(prefix.length());
}
return removeExtension(entryName).replace('/', '.');
}
@Override
public boolean isNameCompatible(String cn, JavaFileObject.Kind k) {
cn.getClass(); // null check
if (k == Kind.OTHER && getKind() != k)
return false;
return name.equals(cn + k.extension);
}
/**
* Check if two file objects are equal.
* Two ZipFileIndexFileObjects are equal if the absolute paths of the underlying
* zip files are equal and if the paths within those zip files are equal.
*/
@Override
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof ZipFileIndexFileObject))
return false;
ZipFileIndexFileObject o = (ZipFileIndexFileObject) other;
return zfIndex.getAbsoluteFile().equals(o.zfIndex.getAbsoluteFile())
&& name.equals(o.name);
}
@Override
public int hashCode() {
return zfIndex.getAbsoluteFile().hashCode() + name.hashCode();
}
private String getPrefixedEntryName() {
if (zfIndex.symbolFilePrefix != null)
return zfIndex.symbolFilePrefix.path + entry.getName();
else
return entry.getName();
}
}
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.javac.file;
import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
import com.sun.tools.javac.util.Context;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/** A cache for ZipFileIndex objects. */
public class ZipFileIndexCache {
private final Map<File, ZipFileIndex> map =
new HashMap<File, ZipFileIndex>();
/** Get a shared instance of the cache. */
private static ZipFileIndexCache sharedInstance;
public synchronized static ZipFileIndexCache getSharedInstance() {
if (sharedInstance == null)
sharedInstance = new ZipFileIndexCache();
return sharedInstance;
}
/** Get a context-specific instance of a cache. */
public static ZipFileIndexCache instance(Context context) {
ZipFileIndexCache instance = context.get(ZipFileIndexCache.class);
if (instance == null)
context.put(ZipFileIndexCache.class, instance = new ZipFileIndexCache());
return instance;
}
/**
* Returns a list of all ZipFileIndex entries
*
* @return A list of ZipFileIndex entries, or an empty list
*/
public List<ZipFileIndex> getZipFileIndexes() {
return getZipFileIndexes(false);
}
/**
* Returns a list of all ZipFileIndex entries
*
* @param openedOnly If true it returns a list of only opened ZipFileIndex entries, otherwise
* all ZipFileEntry(s) are included into the list.
* @return A list of ZipFileIndex entries, or an empty list
*/
public synchronized List<ZipFileIndex> getZipFileIndexes(boolean openedOnly) {
List<ZipFileIndex> zipFileIndexes = new ArrayList<ZipFileIndex>();
zipFileIndexes.addAll(map.values());
if (openedOnly) {
for(ZipFileIndex elem : zipFileIndexes) {
if (!elem.isOpen()) {
zipFileIndexes.remove(elem);
}
}
}
return zipFileIndexes;
}
public synchronized ZipFileIndex getZipFileIndex(File zipFile,
RelativeDirectory symbolFilePrefix,
boolean useCache, String cacheLocation,
boolean writeIndex) throws IOException {
ZipFileIndex zi = getExistingZipIndex(zipFile);
if (zi == null || (zi != null && zipFile.lastModified() != zi.zipFileLastModified)) {
zi = new ZipFileIndex(zipFile, symbolFilePrefix, writeIndex,
useCache, cacheLocation);
map.put(zipFile, zi);
}
return zi;
}
public synchronized ZipFileIndex getExistingZipIndex(File zipFile) {
return map.get(zipFile);
}
public synchronized void clearCache() {
map.clear();
}
public synchronized void clearCache(long timeNotUsed) {
Iterator<File> cachedFileIterator = map.keySet().iterator();
while (cachedFileIterator.hasNext()) {
File cachedFile = cachedFileIterator.next();
ZipFileIndex cachedZipIndex = map.get(cachedFile);
if (cachedZipIndex != null) {
long timeToTest = cachedZipIndex.lastReferenceTimeStamp + timeNotUsed;
if (timeToTest < cachedZipIndex.lastReferenceTimeStamp || // Overflow...
System.currentTimeMillis() > timeToTest) {
map.remove(cachedFile);
}
}
}
}
public synchronized void removeFromCache(File file) {
map.remove(file);
}
/** Sets already opened list of ZipFileIndexes from an outside client
* of the compiler. This functionality should be used in a non-batch clients of the compiler.
*/
public synchronized void setOpenedIndexes(List<ZipFileIndex>indexes) throws IllegalStateException {
if (map.isEmpty()) {
String msg =
"Setting opened indexes should be called only when the ZipFileCache is empty. "
+ "Call JavacFileManager.flush() before calling this method.";
throw new IllegalStateException(msg);
}
for (ZipFileIndex zfi : indexes) {
map.put(zfi.zipFile, zfi);
}
}
}