Mercurial > hg > openjdk > jdk6 > langtools
changeset 106:5c2858bccb3f
6962236: backport JavacFileManager fixes from 7 to 6-open
6410637: Make decision on deprecated methods in DefaultFileManager and BaseFileObject.
6419701: DefaultFileManager clean up: URI.create
6483788: DefaultFileManager.ZipFileObject.toUri() fails to escape space characters
6501502: JSR 199: FileObject.toUri should return file:///c:/ or file:/c:/ not file://c:/
6508981: cleanup file separator handling in JavacFileManager
6625520: javac handles missing entries on classpath badly
6705935: javac reports path name of entry in ZipFileIndex incorectly
6705945: com.sun.tools.javac.zip files do not have valid copyright
6714364: refactor javac File handling code into new javac.file package
6714365: refactor JavacFileManager to move nested classes to top level
6743107: clean up use of static caches in file manager
6794582: javadoc should read files using a FileManager
6832154: refactor Paths to be just a utility class for JavacFileManager
6838467: JSR199 FileObjects don't obey general contract of equals.
6877206: JavaFileObject.toUri returns bogus URI (win)
6877223: tests @ignored because of issues with File.toURI on Windows
6885123: JavaFileObject getName issues
6907660: stupid typo in ZipFileIndex guarantees NPE
6930076: "null" can incorrectly appear in error message compiler.err.error.reading.file
Reviewed-by: darcy
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/apt/main/JavaCompiler.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/apt/main/JavaCompiler.java Tue Jun 22 18:30:16 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -26,20 +26,14 @@ package com.sun.tools.apt.main; import java.io.*; -import java.nio.CharBuffer; -import java.util.Set; -import java.util.HashSet; import java.util.Map; -import java.util.HashMap; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.util.*; import com.sun.tools.javac.code.*; -import com.sun.tools.javac.tree.*; -import com.sun.tools.javac.parser.*; -import com.sun.tools.javac.comp.*; import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.code.Symbol.*; @@ -239,6 +233,7 @@ ListBuffer<ClassSymbol> classes = new ListBuffer<ClassSymbol>(); try { + JavacFileManager fm = (JavacFileManager)fileManager; //parse all files ListBuffer<JCCompilationUnit> trees = new ListBuffer<JCCompilationUnit>(); for (List<String> l = filenames; l.nonEmpty(); l = l.tail) { @@ -256,7 +251,8 @@ continue; } } - trees.append(parse(l.head)); + JavaFileObject fo = fm.getJavaFileObjectsFromStrings(List.of(l.head)).iterator().next(); + trees.append(parse(fo)); } //enter symbols for all files
--- a/src/share/classes/com/sun/tools/apt/main/Main.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/apt/main/Main.java Tue Jun 22 18:30:16 2010 -0700 @@ -26,7 +26,6 @@ package com.sun.tools.apt.main; import java.io.File; -import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; @@ -37,14 +36,15 @@ import java.util.Map; import java.util.HashMap; import java.util.Collections; -import java.util.Collection; import java.net.URLClassLoader; import java.net.URL; -import java.io.File; import java.net.MalformedURLException; -import com.sun.tools.javac.util.Paths; +import javax.tools.JavaFileManager; +import javax.tools.StandardLocation; + +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.code.Source; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Type; @@ -56,6 +56,8 @@ import com.sun.tools.apt.util.Bark; import com.sun.mirror.apt.AnnotationProcessorFactory; +import static com.sun.tools.javac.file.Paths.pathToURLs; + /** This class provides a commandline interface to the apt build-time * tool. * @@ -766,6 +768,7 @@ providedFactory = factory; Context context = new Context(); + JavacFileManager.preRegister(context); options = Options.instance(context); Bark bark; @@ -779,7 +782,6 @@ // prefixed to command line arguments. processArgs(forcedOpts); - /* * A run of apt only gets passed the most recently generated * files; the initial run of apt gets passed the files from @@ -862,14 +864,14 @@ } origOptions = Collections.unmodifiableMap(origOptions); + JavacFileManager fm = (JavacFileManager) context.get(JavaFileManager.class); { // Note: it might be necessary to check for an empty // component ("") of the source path or class path - Paths paths = Paths.instance(context); String sourceDest = options.get("-s"); - if (paths.sourcePath() != null) { - for(File f: paths.sourcePath()) + if (fm.hasLocation(StandardLocation.SOURCE_PATH)) { + for(File f: fm.getLocation(StandardLocation.SOURCE_PATH)) augmentedSourcePath += (f + File.pathSeparator); augmentedSourcePath += (sourceDest == null)?".":sourceDest; } else { @@ -880,8 +882,8 @@ } String classDest = options.get("-d"); - if (paths.userClassPath() != null) { - for(File f: paths.userClassPath()) + if (fm.hasLocation(StandardLocation.CLASS_PATH)) { + for(File f: fm.getLocation(StandardLocation.CLASS_PATH)) baseClassPath += (f + File.pathSeparator); // put baseClassPath into map to handle any // value needed for the classloader @@ -908,9 +910,8 @@ * uses. */ String aptclasspath = ""; - Paths paths = Paths.instance(context); String bcp = ""; - Collection<File> bootclasspath = paths.bootClassPath(); + Iterable<? extends File> bootclasspath = fm.getLocation(StandardLocation.PLATFORM_CLASS_PATH); if (bootclasspath != null) { for(File f: bootclasspath) @@ -1271,59 +1272,4 @@ } } } - - // Borrowed from DocletInvoker - /** - * Utility method for converting a search path string to an array - * of directory and JAR file URLs. - * - * @param path the search path string - * @return the resulting array of directory and JAR file URLs - */ - 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; - } - } - if (urls.length != count) { - URL[] tmp = new URL[count]; - System.arraycopy(urls, 0, tmp, 0, count); - urls = tmp; - } - 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 - */ - 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"); - } - } }
--- a/src/share/classes/com/sun/tools/apt/mirror/util/SourcePositionImpl.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/apt/mirror/util/SourcePositionImpl.java Tue Jun 22 18:30:16 2010 -0700 @@ -67,15 +67,15 @@ public String toString() { int ln = line(); return (ln == Position.NOPOS) - ? sourcefile.toString() - : sourcefile + ":" + ln; + ? sourcefile.getName() + : sourcefile.getName() + ":" + ln; } /** * {@inheritDoc} */ public File file() { - return new File(sourcefile.toString()); + return new File(sourcefile.toUri()); } /**
--- a/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java Tue Jun 22 18:30:16 2010 -0700 @@ -25,12 +25,11 @@ package com.sun.tools.doclets.formats.html.markup; -import com.sun.tools.doclets.internal.toolkit.*; +import java.io.*; +import java.util.*; import com.sun.javadoc.*; -import java.io.*; -import java.util.*; -import com.sun.tools.doclets.internal.toolkit.util.*; +import com.sun.tools.doclets.internal.toolkit.*; /** @@ -56,8 +55,9 @@ super(configuration, null, configuration.destDirName + filename, configuration.docencoding); + // use File to normalize file separators configuration.message.notice("doclet.Generating_0", - configuration.destDirName + filename); + new File(configuration.destDirName, filename)); } public HtmlDocWriter(Configuration configuration, @@ -65,10 +65,10 @@ super(configuration, configuration.destDirName + path, filename, configuration.docencoding); + // use File to normalize file separators configuration.message.notice("doclet.Generating_0", - configuration.destDirName + - ((path.length() > 0)? - path + File.separator: "") + filename); + new File(configuration.destDirName, + ((path.length() > 0)? path + File.separator: "") + filename)); } /**
--- a/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/MessageRetriever.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/MessageRetriever.java Tue Jun 22 18:30:16 2010 -0700 @@ -81,46 +81,14 @@ } /** - * get and format message string from resource - * - * @param key selects message from resource - */ - public String getText(String key) { - return getText(key, (String)null); - } - - /** * Get and format message string from resource * * @param key selects message from resource - * @param a1 Argument, to be repalced in the message. - */ - public String getText(String key, String a1) { - return getText(key, a1, null); - } - - /** - * Get and format message string from resource - * - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - * @param a2 second argument to be replaced in the message. - */ - public String getText(String key, String a1, String a2) { - return getText(key, a1, a2, null); - } - - /** - * Get and format message string from resource - * - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - * @param a2 second argument to be replaced in the message. - * @param a3 third argument to be replaced in the message. + * @param args arguments to be replaced in the message. * @throws MissingResourceException when the key does not * exist in the properties file. */ - public String getText(String key, String a1, String a2, String a3) throws MissingResourceException { + public String getText(String key, Object... args) throws MissingResourceException { if (messageRB == null) { try { messageRB = ResourceBundle.getBundle(resourcelocation); @@ -130,7 +98,7 @@ } } String message = messageRB.getString(key); - return MessageFormat.format(message, a1, a2, a3); + return MessageFormat.format(message, args); } /** @@ -195,127 +163,20 @@ * * @param pos the position of the source * @param key selects message from resource - */ - public void error(SourcePosition pos, String key) { - printError(pos, getText(key)); - } - - /** - * Print error message, increment error count. - * - * @param key selects message from resource - */ - public void error(String key) { - printError(getText(key)); - } - - /** - * Print error message, increment error count. - * - * @param pos the position of the source - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. + * @param args arguments to be replaced in the message. */ - public void error(SourcePosition pos, String key, String a1) { - printError(pos, getText(key, a1)); - } - - /** - * Print error message, increment error count. - * - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - */ - public void error(String key, String a1) { - printError(getText(key, a1)); - } - - /** - * Print error message, increment error count. - * - * @param pos the position of the source - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - * @param a2 second argument to be replaced in the message. - */ - public void error(SourcePosition pos, String key, String a1, String a2) { - printError(pos, getText(key, a1, a2)); + public void error(SourcePosition pos, String key, Object... args) { + printError(pos, getText(key, args)); } /** * Print error message, increment error count. * * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - * @param a2 second argument to be replaced in the message. - */ - public void error(String key, String a1, String a2) { - printError(getText(key, a1, a2)); - } - - /** - * Print error message, increment error count. - * - * @param pos the position of the source - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - * @param a2 second argument to be replaced in the message. - * @param a3 third argument to be replaced in the message. - */ - public void error(SourcePosition pos, String key, String a1, String a2, String a3) { - printError(pos, getText(key, a1, a2, a3)); - } - - /** - * Print error message, increment error count. - * - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - * @param a2 second argument to be replaced in the message. - * @param a3 third argument to be replaced in the message. + * @param args arguments to be replaced in the message. */ - public void error(String key, String a1, String a2, String a3) { - printError(getText(key, a1, a2, a3)); - } - - /** - * Print warning message, increment warning count. - * - * @param pos the position of the source - * @param key selects message from resource - */ - public void warning(SourcePosition pos, String key) { - printWarning(pos, getText(key)); - } - - /** - * Print warning message, increment warning count. - * - * @param key selects message from resource - */ - public void warning(String key) { - printWarning(getText(key)); - } - - /** - * Print warning message, increment warning count. - * - * @param pos the position of the source - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - */ - public void warning(SourcePosition pos, String key, String a1) { - printWarning(pos, getText(key, a1)); - } - - /** - * Print warning message, increment warning count. - * - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - */ - public void warning(String key, String a1) { - printWarning(getText(key, a1)); + public void error(String key, Object... args) { + printError(getText(key, args)); } /** @@ -323,47 +184,20 @@ * * @param pos the position of the source * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - * @param a2 second argument to be replaced in the message. + * @param args arguments to be replaced in the message. */ - public void warning(SourcePosition pos, String key, String a1, String a2) { - printWarning(pos, getText(key, a1, a2)); + public void warning(SourcePosition pos, String key, Object... args) { + printWarning(pos, getText(key, args)); } /** * Print warning message, increment warning count. * * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - * @param a2 second argument to be replaced in the message. + * @param args arguments to be replaced in the message. */ - public void warning(String key, String a1, String a2) { - printWarning(getText(key, a1, a2)); - } - - /** - * Print warning message, increment warning count. - * - * @param pos the position of the source - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - * @param a2 second argument to be replaced in the message. - * @param a3 third argument to be replaced in the message. - */ - public void warning(SourcePosition pos, String key, String a1, String a2, String a3) { - printWarning(pos, getText(key, a1, a2, a3)); - } - - /** - * Print warning message, increment warning count. - * - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - * @param a2 second argument to be replaced in the message. - * @param a3 third argument to be replaced in the message. - */ - public void warning(String key, String a1, String a2, String a3) { - printWarning(getText(key, a1, a2, a3)); + public void warning(String key, Object... args) { + printWarning(getText(key, args)); } /** @@ -371,85 +205,19 @@ * * @param pos the position of the source * @param key selects message from resource - */ - public void notice(SourcePosition pos, String key) { - printNotice(pos, getText(key)); - } - - /** - * Print a message. - * - * @param key selects message from resource + * @param args arguments to be replaced in the message. */ - public void notice(String key) { - printNotice(getText(key)); - } - - /** - * Print a message. - * @param pos the position of the source - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - */ - public void notice(SourcePosition pos, String key, String a1) { - printNotice(pos, getText(key, a1)); + public void notice(SourcePosition pos, String key, Object... args) { + printNotice(pos, getText(key, args)); } /** * Print a message. * * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - */ - public void notice(String key, String a1) { - printNotice(getText(key, a1)); - } - - /** - * Print a message. - * - * @param pos the position of the source - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - * @param a2 second argument to be replaced in the message. - */ - public void notice(SourcePosition pos, String key, String a1, String a2) { - printNotice(pos, getText(key, a1, a2)); - } - - /** - * Print a message. - * - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - * @param a2 second argument to be replaced in the message. + * @param args arguments to be replaced in the message. */ - public void notice(String key, String a1, String a2) { - printNotice(getText(key, a1, a2)); - } - - /** - * Print a message. - * - * @param pos the position of the source - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - * @param a2 second argument to be replaced in the message. - * @param a3 third argument to be replaced in the message. - */ - public void notice(SourcePosition pos, String key, String a1, String a2, String a3) { - printNotice(pos, getText(key, a1, a2, a3)); - } - - /** - * Print a message. - * - * @param key selects message from resource - * @param a1 first argument to be replaced in the message. - * @param a2 second argument to be replaced in the message. - * @param a3 third argument to be replaced in the message. - */ - public void notice(String key, String a1, String a2, String a3) { - printNotice(getText(key, a1, a2, a3)); + public void notice(String key, Object... args) { + printNotice(getText(key, args)); } }
--- a/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/SourceToHTMLConverter.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/SourceToHTMLConverter.java Tue Jun 22 18:30:16 2010 -0700 @@ -25,10 +25,12 @@ package com.sun.tools.doclets.internal.toolkit.util; -import com.sun.tools.doclets.internal.toolkit.*; -import com.sun.javadoc.*; import java.io.*; import java.util.*; +import javax.tools.FileObject; + +import com.sun.javadoc.*; +import com.sun.tools.doclets.internal.toolkit.*; /** * Converts Java Source Code to HTML. @@ -123,16 +125,27 @@ if (cd == null || outputdir == null) { return; } - File file; - SourcePosition sp = cd.position(); - if (sp == null || (file = sp.file()) == null) { - return; - } try { + SourcePosition sp = cd.position(); + if (sp == null) + return; + Reader r; + // temp hack until we can update SourcePosition API. + if (sp instanceof com.sun.tools.javadoc.SourcePositionImpl) { + FileObject fo = ((com.sun.tools.javadoc.SourcePositionImpl) sp).fileObject(); + if (fo == null) + return; + r = fo.openReader(true); + } else { + File file = sp.file(); + if (file == null) + return; + r = new FileReader(file); + } + LineNumberReader reader = new LineNumberReader(r); int lineno = 1; String line; StringBuffer output = new StringBuffer(); - LineNumberReader reader = new LineNumberReader(new FileReader(file)); try { while ((line = reader.readLine()) != null) { output.append(formatLine(line, configuration.sourcetab, lineno)); @@ -260,12 +273,12 @@ * @param docs the array of <code>Doc</code>s to add anchors for. * @param hash the <code>HashMap</code> to add to. */ - protected static void addToHash(Doc[] docs, HashMap hash) { + protected static void addToHash(Doc[] docs, HashMap<Integer,String> hash) { if(docs == null) { return; } for(int i = 0; i < docs.length; i++) { - hash.put(new Integer(docs[i].position().line()), getAnchor(docs[i])); + hash.put(docs[i].position().line(), getAnchor(docs[i])); } }
--- a/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java Tue Jun 22 18:30:16 2010 -0700 @@ -25,10 +25,11 @@ package com.sun.tools.doclets.internal.toolkit.util; +import java.io.*; +import java.util.*; + import com.sun.javadoc.*; import com.sun.tools.doclets.internal.toolkit.*; -import java.util.*; -import java.io.*; /** * Utilities Class for Doclets. @@ -579,7 +580,7 @@ * @param docencoding Encoding to be used for this file. * @exception IOException Exception raised by the FileWriter is passed on * to next level. - * @exception UnSupportedEncodingException Exception raised by the + * @exception UnsupportedEncodingException Exception raised by the * OutputStreamWriter is passed on to next level. * @return Writer Writer for the file getting generated. * @see java.io.FileOutputStream @@ -598,9 +599,7 @@ fos = new FileOutputStream(filename); } if (docencoding == null) { - OutputStreamWriter oswriter = new OutputStreamWriter(fos); - docencoding = oswriter.getEncoding(); - return oswriter; + return new OutputStreamWriter(fos); } else { return new OutputStreamWriter(fos, docencoding); }
--- a/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Tue Jun 22 18:30:16 2010 -0700 @@ -42,6 +42,7 @@ import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.comp.*; +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.*; import com.sun.tools.javac.model.*; import com.sun.tools.javac.parser.Parser;
--- a/src/share/classes/com/sun/tools/javac/api/JavacTool.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javac/api/JavacTool.java Tue Jun 22 18:30:16 2010 -0700 @@ -31,7 +31,6 @@ import java.io.PrintWriter; import java.io.Writer; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.Iterator; @@ -42,13 +41,13 @@ import javax.tools.*; import com.sun.source.util.JavacTask; +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.JavacOption.OptionKind; import com.sun.tools.javac.main.JavacOption; import com.sun.tools.javac.main.Main; import com.sun.tools.javac.main.RecognizedOptions.GrumpyHelper; import com.sun.tools.javac.main.RecognizedOptions; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.JavacFileManager; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Options; import com.sun.tools.javac.util.Pair;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java Tue Jun 22 18:30:16 2010 -0700 @@ -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; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/file/CacheFSInfo.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2005, 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.io.IOException; +import java.util.List; + +import com.sun.tools.javac.util.Context; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 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 singleton CacheFSInfo. + */ + public static void preRegister(final Context context) { + context.put(FSInfo.class, new Context.Factory<FSInfo>() { + public FSInfo make() { + if (singleton == null) + singleton = new CacheFSInfo(); + context.put(FSInfo.class, singleton); + return singleton; + } + }); + } + + static CacheFSInfo singleton; + + 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; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/file/FSInfo.java Tue Jun 22 18:30:16 2010 -0700 @@ -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(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,860 @@ +/* + * 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.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.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.main.OptionName; +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.*; +import static com.sun.tools.javac.main.OptionName.*; + +/** + * 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 { + + boolean useZipFileIndex; + + public static char[] toArray(CharBuffer buffer) { + if (buffer.hasArray()) + return ((CharBuffer)buffer.compact().flip()).array(); + else + return buffer.toString().toCharArray(); + } + + /** Encapsulates knowledge of paths + */ + private Paths paths; + + private FSInfo fsInfo; + + private final File uninited = new File("U N I N I T E D"); + + private final Set<JavaFileObject.Kind> sourceOrClass = + EnumSet.of(JavaFileObject.Kind.SOURCE, JavaFileObject.Kind.CLASS); + + /** The standard output directory, primarily used for classes. + * Initialized by the "-d" option. + * If classOutDir = null, files are written into same directory as the sources + * they were generated from. + */ + private File classOutDir = uninited; + + /** The output directory, used when generating sources while processing annotations. + * Initialized by the "-s" option. + */ + private File sourceOutDir = uninited; + + protected boolean mmappedIO; + protected boolean ignoreSymbolFile; + + /** + * Register a Context.Factory to create a JavacFileManager. + */ + public static void preRegister(final Context context) { + context.put(JavaFileManager.class, new Context.Factory<JavaFileManager>() { + public JavaFileManager make() { + return new JavacFileManager(context, 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); + if (paths == null) { + paths = Paths.instance(context); + } else { + // Reuse the Paths object as it stores the locations that + // have been set with setLocation, etc. + paths.setContext(context); + } + + fsInfo = FSInfo.instance(context); + + useZipFileIndex = System.getProperty("useJavaUtilZip") == null;// TODO: options.get("useJavaUtilZip") == null; + + mmappedIO = options.get("mmappedIO") != null; + ignoreSymbolFile = options.get("ignore.symbol.file") != null; + } + + 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' which end + * in one of the extensions in `extensions' into packageSym. + */ + private void listDirectory(File directory, + RelativeDirectory subdirectory, + Set<JavaFileObject.Kind> fileKinds, + boolean recurse, + ListBuffer<JavaFileObject> l) { + Archive archive = archives.get(directory); + + boolean isFile = fsInfo.isFile(directory); + + if (archive != null || isFile) { + if (archive == null) { + try { + archive = openArchive(directory); + } catch (IOException ex) { + log.error("error.reading.file", + directory, getMessage(ex)); + return; + } + } + + List<String> files = archive.getFiles(subdirectory); + if (files != null) { + for (String file; !files.isEmpty(); files = files.tail) { + file = files.head; + if (isValidFile(file, fileKinds)) { + l.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. + listDirectory(directory, s, fileKinds, false, l); + } + } + } + } else { + File d = subdirectory.getFile(directory); + if (!caseMapCheck(d, subdirectory)) + return; + + File[] files = d.listFiles(); + if (files == null) + return; + + for (File f: files) { + String fname = f.getName(); + if (f.isDirectory()) { + if (recurse && SourceVersion.isIdentifier(fname)) { + listDirectory(directory, + new RelativeDirectory(subdirectory, fname), + fileKinds, + recurse, + l); + } + } else { + if (isValidFile(fname, fileKinds)) { + JavaFileObject fe = + new RegularFileObject(this, fname, new File(d, fname)); + l.append(fe); + } + } + } + } + } + + 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/"); + + /** Open a new zip file directory. + */ + protected Archive openArchive(File zipFileName) throws IOException { + Archive archive = archives.get(zipFileName); + if (archive == null) { + File origZipFileName = zipFileName; + if (!ignoreSymbolFile && paths.isBootClassPathRtJar(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; + } + + try { + + ZipFile zdir = null; + + boolean usePreindexedCache = false; + String preindexCacheLocation = null; + + if (!useZipFileIndex) { + zdir = new ZipFile(zipFileName); + } + else { + usePreindexedCache = options.get("usezipindex") != null; + 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 (!useZipFileIndex) { + archive = new ZipArchive(this, zdir); + } else { + archive = new ZipFileIndexArchive(this, + ZipFileIndex.getZipFileIndex(zipFileName, + null, + usePreindexedCache, + preindexCacheLocation, + options.get("writezipindexfiles") != null)); + } + } + else { + if (!useZipFileIndex) { + archive = new SymbolArchive(this, origZipFileName, zdir, symbolFilePrefix); + } + else { + archive = new ZipFileIndexArchive(this, + ZipFileIndex.getZipFileIndex(zipFileName, + symbolFilePrefix, + usePreindexedCache, + preindexCacheLocation, + options.get("writezipindexfiles") != null)); + } + } + } catch (FileNotFoundException ex) { + archive = new MissingArchive(zipFileName); + } 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) + listDirectory(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) { + if (dir.isDirectory()) { + File f = name.getFile(dir); + if (f.exists()) + return new RegularFileObject(this, f); + } else { + Archive a = openArchive(dir); + 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("relativeName is invalid"); + 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 = paths.getPathForLocation(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); + paths.lazy(); + + final File dir = location.isOutputLocation() ? getOutputDirectory(path) : null; + + if (location == CLASS_OUTPUT) + classOutDir = getOutputLocation(dir, D); + else if (location == SOURCE_OUTPUT) + sourceOutDir = getOutputLocation(dir, S); + else + paths.setPathForLocation(location, path); + } + // where + private File getOutputDirectory(Iterable<? extends File> path) throws IOException { + if (path == null) + return null; + Iterator<? extends File> pathIter = path.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"); + return dir; + } + + private File getOutputLocation(File dir, OptionName defaultOptionName) { + if (dir != null) + return dir; + String arg = options.get(defaultOptionName); + if (arg == null) + return null; + return new File(arg); + } + + public Iterable<? extends File> getLocation(Location location) { + nullCheck(location); + paths.lazy(); + if (location == CLASS_OUTPUT) { + return (getClassOutDir() == null ? null : List.of(getClassOutDir())); + } else if (location == SOURCE_OUTPUT) { + return (getSourceOutDir() == null ? null : List.of(getSourceOutDir())); + } else + return paths.getPathForLocation(location); + } + + private File getClassOutDir() { + if (classOutDir == uninited) + classOutDir = getOutputLocation(null, D); + return classOutDir; + } + + private File getSourceOutDir() { + if (sourceOutDir == uninited) + sourceOutDir = getOutputLocation(null, S); + return sourceOutDir; + } + + /** + * Enforces the specification of a "relative" URI as used in + * {@linkplain #getFileForInput(Location,String,URI) + * 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; + char first = path.charAt(0); + return first != '.' && first != '/'; + } + + // 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(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/file/Paths.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,511 @@ +/* + * Copyright (c) 2003, 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.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.StringTokenizer; +import java.util.zip.ZipFile; +import javax.tools.JavaFileManager.Location; + +import com.sun.tools.javac.code.Lint; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Options; + +import static javax.tools.StandardLocation.*; +import static com.sun.tools.javac.main.OptionName.*; + +/** 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 + * 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 Paths { + + /** The context key for the todo list */ + protected static final Context.Key<Paths> pathsKey = + new Context.Key<Paths>(); + + /** Get the Paths instance for this context. + * @param context the context + * @return the Paths instance for this context + */ + public static Paths instance(Context context) { + Paths instance = context.get(pathsKey); + if (instance == null) + instance = new Paths(context); + return instance; + } + + /** 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; + + protected Paths(Context context) { + context.put(pathsKey, this); + pathsForLocation = new HashMap<Location,Path>(16); + setContext(context); + } + + void setContext(Context context) { + log = Log.instance(context); + options = Options.instance(context); + lint = Lint.instance(context); + fsInfo = FSInfo.instance(context); + } + + /** Whether to warn about non-existent path elements */ + private boolean warn; + + private Map<Location, Path> pathsForLocation; + + private boolean inited = false; // TODO? caching bad? + + /** + * rt.jar as found on the default bootclass path. If the user specified a + * bootclasspath, null is used. + */ + private File bootClassPathRtJar = null; + + Path getPathForLocation(Location location) { + Path path = pathsForLocation.get(location); + if (path == null) + setPathForLocation(location, null); + return pathsForLocation.get(location); + } + + void setPathForLocation(Location location, Iterable<? extends File> path) { + // TODO? if (inited) throw new IllegalStateException + // TODO: otherwise reset sourceSearchPath, classSearchPath as needed + Path p; + if (path == null) { + if (location == CLASS_PATH) + p = computeUserClassPath(); + else if (location == PLATFORM_CLASS_PATH) + p = computeBootClassPath(); + else if (location == ANNOTATION_PROCESSOR_PATH) + p = computeAnnotationProcessorPath(); + else if (location == SOURCE_PATH) + p = computeSourcePath(); + else + // no defaults for other paths + p = null; + } else { + p = new Path(); + for (File f: path) + p.addFile(f, warn); // TODO: is use of warn appropriate? + } + pathsForLocation.put(location, p); + } + + protected void lazy() { + if (!inited) { + warn = lint.isEnabled(Lint.LintCategory.PATH); + + pathsForLocation.put(PLATFORM_CLASS_PATH, computeBootClassPath()); + pathsForLocation.put(CLASS_PATH, computeUserClassPath()); + pathsForLocation.put(SOURCE_PATH, computeSourcePath()); + + inited = true; + } + } + + public Collection<File> bootClassPath() { + lazy(); + return Collections.unmodifiableCollection(getPathForLocation(PLATFORM_CLASS_PATH)); + } + public Collection<File> userClassPath() { + lazy(); + return Collections.unmodifiableCollection(getPathForLocation(CLASS_PATH)); + } + public Collection<File> sourcePath() { + lazy(); + Path p = getPathForLocation(SOURCE_PATH); + return p == null || p.size() == 0 + ? null + : Collections.unmodifiableCollection(p); + } + + boolean isBootClassPathRtJar(File file) { + return file.equals(bootClassPathRtJar); + } + + /** + * 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; + } + + 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) { + if (dirs != null) + for (File dir : getPathEntries(dirs)) + addDirectory(dir, warn); + return this; + } + + public Path addDirectories(String dirs) { + return addDirectories(dirs, warn); + } + + private void addDirectory(File dir, boolean warn) { + if (!dir.isDirectory()) { + if (warn) + log.warning("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) + for (File file : getPathEntries(files, emptyPathDefault)) + addFile(file, warn); + return this; + } + + public Path addFiles(String files) { + return addFiles(files, warn); + } + + public void addFile(File file, boolean warn) { + File canonFile = fsInfo.getCanonicalFile(file); + if (contains(file) || canonicalValues.contains(canonFile)) { + /* Discard duplicates and avoid infinite recursion */ + return; + } + + if (! fsInfo.exists(file)) { + /* No such file or directory exists */ + if (warn) + log.warning("path.element.not.found", file); + } else 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("unexpected.archive.file", file); + } catch (IOException e) { + // FIXME: include e.getLocalizedMessage in warning + if (warn) + log.warning("invalid.archive.file", file); + return; + } + } + } + + /* Now what we have left is either a directory or a file name + confirming to archive naming convention */ + super.add(file); + canonicalValues.add(canonFile); + + if (expandJarClassPaths && fsInfo.exists(file) && 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)); + } + } + } + + private Path computeBootClassPath() { + bootClassPathRtJar = null; + String optionValue; + Path path = new Path(); + + path.addFiles(options.get(XBOOTCLASSPATH_PREPEND)); + + if ((optionValue = options.get(ENDORSEDDIRS)) != null) + path.addDirectories(optionValue); + else + path.addDirectories(System.getProperty("java.endorsed.dirs"), false); + + if ((optionValue = options.get(BOOTCLASSPATH)) != null) { + path.addFiles(optionValue); + } 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)) + bootClassPathRtJar = file; + } + } + + path.addFiles(options.get(XBOOTCLASSPATH_APPEND)); + + // Strictly speaking, standard extensions are not bootstrap + // classes, but we treat them identically, so we'll pretend + // that they are. + if ((optionValue = options.get(EXTDIRS)) != null) + path.addDirectories(optionValue); + else + path.addDirectories(System.getProperty("java.ext.dirs"), false); + + return path; + } + + private Path computeUserClassPath() { + String cp = options.get(CLASSPATH); + + // 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 new Path() + .expandJarClassPaths(true) // Only search user jars for Class-Paths + .emptyPathDefault(new File(".")) // Empty path elt ==> current directory + .addFiles(cp); + } + + private Path computeSourcePath() { + String sourcePathArg = options.get(SOURCEPATH); + if (sourcePathArg == null) + return null; + + return new Path().addFiles(sourcePathArg); + } + + private Path computeAnnotationProcessorPath() { + String processorPathArg = options.get(PROCESSORPATH); + if (processorPathArg == null) + return null; + + return new Path().addFiles(processorPathArg); + } + + /** The actual effective locations searched for sources */ + private Path sourceSearchPath; + + public Collection<File> sourceSearchPath() { + if (sourceSearchPath == null) { + lazy(); + Path sourcePath = getPathForLocation(SOURCE_PATH); + Path userClassPath = getPathForLocation(CLASS_PATH); + sourceSearchPath = sourcePath != null ? sourcePath : userClassPath; + } + return Collections.unmodifiableCollection(sourceSearchPath); + } + + /** The actual effective locations searched for classes */ + private Path classSearchPath; + + public Collection<File> classSearchPath() { + if (classSearchPath == null) { + lazy(); + Path bootClassPath = getPathForLocation(PLATFORM_CLASS_PATH); + Path userClassPath = getPathForLocation(CLASS_PATH); + classSearchPath = new Path(); + classSearchPath.addAll(bootClassPath); + classSearchPath.addAll(userClassPath); + } + return Collections.unmodifiableCollection(classSearchPath); + } + + /** The actual effective locations for non-source, non-class files */ + private Path otherSearchPath; + + Collection<File> otherSearchPath() { + if (otherSearchPath == null) { + lazy(); + Path userClassPath = getPathForLocation(CLASS_PATH); + Path sourcePath = getPathForLocation(SOURCE_PATH); + if (sourcePath == null) + otherSearchPath = userClassPath; + else { + otherSearchPath = new Path(); + otherSearchPath.addAll(userClassPath); + otherSearchPath.addAll(sourcePath); + } + } + return Collections.unmodifiableCollection(otherSearchPath); + } + + /** Is this the name of an archive file? */ + private boolean isArchive(File file) { + String n = file.getName().toLowerCase(); + 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; + } + } + if (urls.length != count) { + URL[] tmp = new URL[count]; + System.arraycopy(urls, 0, tmp, 0, count); + urls = tmp; + } + 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()); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/file/RegularFileObject.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,235 @@ +/* + * 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.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; + +/** + * 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; + + 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 { + 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 { + 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 (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; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/file/RelativePath.java Tue Jun 22 18:30:16 2010 -0700 @@ -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 + "]"; + } + + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/file/SymbolArchive.java Tue Jun 22 18:30:16 2010 -0700 @@ -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('/', '.'); + } + } + + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/file/ZipArchive.java Tue Jun 22 18:30:16 2010 -0700 @@ -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(); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,1338 @@ +/* + * Copyright (c) 2007, 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.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.locks.ReentrantLock; +import java.util.zip.DataFormatException; +import java.util.zip.Inflater; +import java.util.zip.ZipException; + +import com.sun.tools.javac.file.RelativePath.RelativeDirectory; +import com.sun.tools.javac.file.RelativePath.RelativeFile; + +/** This class implements building of index of a zip archive and access to it's context. + * It also uses prebuild index if available. It supports invocations where it will + * serialize an optimized zip index file to disk. + * + * In oreder to use secondary index file make sure the option "usezipindex" is in the Options object, + * when JavacFileManager is invoked. (You can pass "-XDusezipindex" on the command line. + * + * Location where to look for/generate optimized zip index files can be provided using + * "-XDcachezipindexdir=<directory>". If this flag is not provided, the dfault location is + * the value of the "java.io.tmpdir" system property. + * + * If key "-XDwritezipindexfiles" is specified, there will be new optimized index file + * created for each archive, used by the compiler for compilation, at location, + * specified by "cachezipindexdir" option. + * + * If nonBatchMode option is specified (-XDnonBatchMode) the compiler will use timestamp + * checking to reindex the zip files if it is needed. In batch mode the timestamps are not checked + * and the compiler uses the cached indexes. + * + * <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 ZipFileIndex { + private static final String MIN_CHAR = String.valueOf(Character.MIN_VALUE); + private static final String MAX_CHAR = String.valueOf(Character.MAX_VALUE); + + public final static long NOT_MODIFIED = Long.MIN_VALUE; + + private static Map<File, ZipFileIndex> zipFileIndexCache = new HashMap<File, ZipFileIndex>(); + private static ReentrantLock lock = new ReentrantLock(); + + private static boolean NON_BATCH_MODE = System.getProperty("nonBatchMode") != null;// TODO: Use -XD compiler switch for this. + + private Map<RelativeDirectory, DirectoryEntry> directories = Collections.<RelativeDirectory, DirectoryEntry>emptyMap(); + private Set<RelativeDirectory> allDirs = Collections.<RelativeDirectory>emptySet(); + + // ZipFileIndex data entries + private File zipFile; + private Reference<File> absFileRef; + private long zipFileLastModified = NOT_MODIFIED; + private RandomAccessFile zipRandomFile; + private Entry[] entries; + + private boolean readFromIndex = false; + private File zipIndexFile = null; + private boolean triedToReadIndex = false; + final RelativeDirectory symbolFilePrefix; + private int symbolFilePrefixLength = 0; + private boolean hasPopulatedData = false; + private long lastReferenceTimeStamp = NOT_MODIFIED; + + private boolean usePreindexedCache = false; + private String preindexedCacheLocation = null; + + private boolean writeIndex = false; + + private Map <String, SoftReference<RelativeDirectory>> relativeDirectoryCache = + new HashMap<String, SoftReference<RelativeDirectory>>(); + + /** + * Returns a list of all ZipFileIndex entries + * + * @return A list of ZipFileIndex entries, or an empty list + */ + public static 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 static List<ZipFileIndex> getZipFileIndexes(boolean openedOnly) { + List<ZipFileIndex> zipFileIndexes = new ArrayList<ZipFileIndex>(); + lock.lock(); + try { + zipFileIndexes.addAll(zipFileIndexCache.values()); + + if (openedOnly) { + for(ZipFileIndex elem : zipFileIndexes) { + if (!elem.isOpen()) { + zipFileIndexes.remove(elem); + } + } + } + } + finally { + lock.unlock(); + } + return zipFileIndexes; + } + + public boolean isOpen() { + lock.lock(); + try { + return zipRandomFile != null; + } + finally { + lock.unlock(); + } + } + + public static ZipFileIndex getZipFileIndex(File zipFile, + RelativeDirectory symbolFilePrefix, + boolean useCache, String cacheLocation, + boolean writeIndex) throws IOException { + ZipFileIndex zi = null; + lock.lock(); + try { + zi = getExistingZipIndex(zipFile); + + if (zi == null || (zi != null && zipFile.lastModified() != zi.zipFileLastModified)) { + zi = new ZipFileIndex(zipFile, symbolFilePrefix, writeIndex, + useCache, cacheLocation); + zipFileIndexCache.put(zipFile, zi); + } + } + finally { + lock.unlock(); + } + return zi; + } + + public static ZipFileIndex getExistingZipIndex(File zipFile) { + lock.lock(); + try { + return zipFileIndexCache.get(zipFile); + } + finally { + lock.unlock(); + } + } + + public static void clearCache() { + lock.lock(); + try { + zipFileIndexCache.clear(); + } + finally { + lock.unlock(); + } + } + + public static void clearCache(long timeNotUsed) { + lock.lock(); + try { + Iterator<File> cachedFileIterator = zipFileIndexCache.keySet().iterator(); + while (cachedFileIterator.hasNext()) { + File cachedFile = cachedFileIterator.next(); + ZipFileIndex cachedZipIndex = zipFileIndexCache.get(cachedFile); + if (cachedZipIndex != null) { + long timeToTest = cachedZipIndex.lastReferenceTimeStamp + timeNotUsed; + if (timeToTest < cachedZipIndex.lastReferenceTimeStamp || // Overflow... + System.currentTimeMillis() > timeToTest) { + zipFileIndexCache.remove(cachedFile); + } + } + } + } + finally { + lock.unlock(); + } + } + + public static void removeFromCache(File file) { + lock.lock(); + try { + zipFileIndexCache.remove(file); + } + finally { + lock.unlock(); + } + } + + /** 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 static void setOpenedIndexes(List<ZipFileIndex>indexes) throws IllegalStateException { + lock.lock(); + try { + if (zipFileIndexCache.isEmpty()) { + throw new IllegalStateException("Setting opened indexes should be called only when the ZipFileCache is empty. Call JavacFileManager.flush() before calling this method."); + } + + for (ZipFileIndex zfi : indexes) { + zipFileIndexCache.put(zfi.zipFile, zfi); + } + } + finally { + lock.unlock(); + } + } + + private ZipFileIndex(File zipFile, RelativeDirectory symbolFilePrefix, boolean writeIndex, + boolean useCache, String cacheLocation) throws IOException { + this.zipFile = zipFile; + this.symbolFilePrefix = symbolFilePrefix; + this.symbolFilePrefixLength = (symbolFilePrefix == null ? 0 : + symbolFilePrefix.getPath().getBytes("UTF-8").length); + this.writeIndex = writeIndex; + this.usePreindexedCache = useCache; + this.preindexedCacheLocation = cacheLocation; + + if (zipFile != null) { + this.zipFileLastModified = zipFile.lastModified(); + } + + // Validate integrity of the zip file + checkIndex(); + } + + public String toString() { + return "ZipFileIndex[" + zipFile + "]"; + } + + // Just in case... + protected void finalize() { + closeFile(); + } + + private boolean isUpToDate() { + if (zipFile != null && + ((!NON_BATCH_MODE) || zipFileLastModified == zipFile.lastModified()) && + hasPopulatedData) { + return true; + } + + return false; + } + + /** + * Here we need to make sure that the ZipFileIndex is valid. Check the timestamp of the file and + * if its the same as the one at the time the index was build we don't need to reopen anything. + */ + private void checkIndex() throws IOException { + boolean isUpToDate = true; + if (!isUpToDate()) { + closeFile(); + isUpToDate = false; + } + + if (zipRandomFile != null || isUpToDate) { + lastReferenceTimeStamp = System.currentTimeMillis(); + return; + } + + hasPopulatedData = true; + + if (readIndex()) { + lastReferenceTimeStamp = System.currentTimeMillis(); + return; + } + + directories = Collections.<RelativeDirectory, DirectoryEntry>emptyMap(); + allDirs = Collections.<RelativeDirectory>emptySet(); + + try { + openFile(); + long totalLength = zipRandomFile.length(); + ZipDirectory directory = new ZipDirectory(zipRandomFile, 0L, totalLength, this); + directory.buildIndex(); + } finally { + if (zipRandomFile != null) { + closeFile(); + } + } + + lastReferenceTimeStamp = System.currentTimeMillis(); + } + + private void openFile() throws FileNotFoundException { + if (zipRandomFile == null && zipFile != null) { + zipRandomFile = new RandomAccessFile(zipFile, "r"); + } + } + + private void cleanupState() { + // Make sure there is a valid but empty index if the file doesn't exist + entries = Entry.EMPTY_ARRAY; + directories = Collections.<RelativeDirectory, DirectoryEntry>emptyMap(); + zipFileLastModified = NOT_MODIFIED; + allDirs = Collections.<RelativeDirectory>emptySet(); + } + + public void close() { + lock.lock(); + try { + writeIndex(); + closeFile(); + } + finally { + lock.unlock(); + } + } + + private void closeFile() { + if (zipRandomFile != null) { + try { + zipRandomFile.close(); + } catch (IOException ex) { + } + zipRandomFile = null; + } + } + + /** + * Returns the ZipFileIndexEntry for an absolute path, if there is one. + */ + Entry getZipIndexEntry(RelativePath path) { + lock.lock(); + try { + checkIndex(); + DirectoryEntry de = directories.get(path.dirname()); + String lookFor = path.basename(); + return de == null ? null : de.getEntry(lookFor); + } + catch (IOException e) { + return null; + } + finally { + lock.unlock(); + } + } + + /** + * Returns a javac List of filenames within an absolute path in the ZipFileIndex. + */ + public com.sun.tools.javac.util.List<String> getFiles(RelativeDirectory path) { + lock.lock(); + try { + checkIndex(); + + DirectoryEntry de = directories.get(path); + com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getFiles(); + + if (ret == null) { + return com.sun.tools.javac.util.List.<String>nil(); + } + return ret; + } + catch (IOException e) { + return com.sun.tools.javac.util.List.<String>nil(); + } + finally { + lock.unlock(); + } + } + + public List<String> getDirectories(RelativeDirectory path) { + lock.lock(); + try { + checkIndex(); + + DirectoryEntry de = directories.get(path); + com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getDirectories(); + + if (ret == null) { + return com.sun.tools.javac.util.List.<String>nil(); + } + + return ret; + } + catch (IOException e) { + return com.sun.tools.javac.util.List.<String>nil(); + } + finally { + lock.unlock(); + } + } + + public Set<RelativeDirectory> getAllDirectories() { + lock.lock(); + try { + checkIndex(); + if (allDirs == Collections.EMPTY_SET) { + allDirs = new HashSet<RelativeDirectory>(directories.keySet()); + } + + return allDirs; + } + catch (IOException e) { + return Collections.<RelativeDirectory>emptySet(); + } + finally { + lock.unlock(); + } + } + + /** + * Tests if a specific path exists in the zip. This method will return true + * for file entries and directories. + * + * @param path A path within the zip. + * @return True if the path is a file or dir, false otherwise. + */ + public boolean contains(RelativePath path) { + lock.lock(); + try { + checkIndex(); + return getZipIndexEntry(path) != null; + } + catch (IOException e) { + return false; + } + finally { + lock.unlock(); + } + } + + public boolean isDirectory(RelativePath path) throws IOException { + lock.lock(); + try { + // The top level in a zip file is always a directory. + if (path.getPath().length() == 0) { + lastReferenceTimeStamp = System.currentTimeMillis(); + return true; + } + + checkIndex(); + return directories.get(path) != null; + } + finally { + lock.unlock(); + } + } + + public long getLastModified(RelativeFile path) throws IOException { + lock.lock(); + try { + Entry entry = getZipIndexEntry(path); + if (entry == null) + throw new FileNotFoundException(); + return entry.getLastModified(); + } + finally { + lock.unlock(); + } + } + + public int length(RelativeFile path) throws IOException { + lock.lock(); + try { + Entry entry = getZipIndexEntry(path); + if (entry == null) + throw new FileNotFoundException(); + + if (entry.isDir) { + return 0; + } + + byte[] header = getHeader(entry); + // entry is not compressed? + if (get2ByteLittleEndian(header, 8) == 0) { + return entry.compressedSize; + } else { + return entry.size; + } + } + finally { + lock.unlock(); + } + } + + public byte[] read(RelativeFile path) throws IOException { + lock.lock(); + try { + Entry entry = getZipIndexEntry(path); + if (entry == null) + throw new FileNotFoundException("Path not found in ZIP: " + path.path); + return read(entry); + } + finally { + lock.unlock(); + } + } + + byte[] read(Entry entry) throws IOException { + lock.lock(); + try { + openFile(); + byte[] result = readBytes(entry); + closeFile(); + return result; + } + finally { + lock.unlock(); + } + } + + public int read(RelativeFile path, byte[] buffer) throws IOException { + lock.lock(); + try { + Entry entry = getZipIndexEntry(path); + if (entry == null) + throw new FileNotFoundException(); + return read(entry, buffer); + } + finally { + lock.unlock(); + } + } + + int read(Entry entry, byte[] buffer) + throws IOException { + lock.lock(); + try { + int result = readBytes(entry, buffer); + return result; + } + finally { + lock.unlock(); + } + } + + private byte[] readBytes(Entry entry) throws IOException { + byte[] header = getHeader(entry); + int csize = entry.compressedSize; + byte[] cbuf = new byte[csize]; + zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28)); + zipRandomFile.readFully(cbuf, 0, csize); + + // is this compressed - offset 8 in the ZipEntry header + if (get2ByteLittleEndian(header, 8) == 0) + return cbuf; + + int size = entry.size; + byte[] buf = new byte[size]; + if (inflate(cbuf, buf) != size) + throw new ZipException("corrupted zip file"); + + return buf; + } + + /** + * + */ + private int readBytes(Entry entry, byte[] buffer) throws IOException { + byte[] header = getHeader(entry); + + // entry is not compressed? + if (get2ByteLittleEndian(header, 8) == 0) { + zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28)); + int offset = 0; + int size = buffer.length; + while (offset < size) { + int count = zipRandomFile.read(buffer, offset, size - offset); + if (count == -1) + break; + offset += count; + } + return entry.size; + } + + int csize = entry.compressedSize; + byte[] cbuf = new byte[csize]; + zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28)); + zipRandomFile.readFully(cbuf, 0, csize); + + int count = inflate(cbuf, buffer); + if (count == -1) + throw new ZipException("corrupted zip file"); + + return entry.size; + } + + //---------------------------------------------------------------------------- + // Zip utilities + //---------------------------------------------------------------------------- + + private byte[] getHeader(Entry entry) throws IOException { + zipRandomFile.seek(entry.offset); + byte[] header = new byte[30]; + zipRandomFile.readFully(header); + if (get4ByteLittleEndian(header, 0) != 0x04034b50) + throw new ZipException("corrupted zip file"); + if ((get2ByteLittleEndian(header, 6) & 1) != 0) + throw new ZipException("encrypted zip file"); // offset 6 in the header of the ZipFileEntry + return header; + } + + /* + * Inflate using the java.util.zip.Inflater class + */ + private static Inflater inflater; + private int inflate(byte[] src, byte[] dest) { + + // construct the inflater object or reuse an existing one + if (inflater == null) + inflater = new Inflater(true); + + synchronized (inflater) { + inflater.reset(); + inflater.setInput(src); + try { + return inflater.inflate(dest); + } catch (DataFormatException ex) { + return -1; + } + } + } + + /** + * return the two bytes buf[pos], buf[pos+1] as an unsigned integer in little + * endian format. + */ + private static int get2ByteLittleEndian(byte[] buf, int pos) { + return (buf[pos] & 0xFF) + ((buf[pos+1] & 0xFF) << 8); + } + + /** + * return the 4 bytes buf[i..i+3] as an integer in little endian format. + */ + private static int get4ByteLittleEndian(byte[] buf, int pos) { + return (buf[pos] & 0xFF) + ((buf[pos + 1] & 0xFF) << 8) + + ((buf[pos + 2] & 0xFF) << 16) + ((buf[pos + 3] & 0xFF) << 24); + } + + /* ---------------------------------------------------------------------------- + * ZipDirectory + * ----------------------------------------------------------------------------*/ + + private class ZipDirectory { + private RelativeDirectory lastDir; + private int lastStart; + private int lastLen; + + byte[] zipDir; + RandomAccessFile zipRandomFile = null; + ZipFileIndex zipFileIndex = null; + + public ZipDirectory(RandomAccessFile zipRandomFile, long start, long end, ZipFileIndex index) throws IOException { + this.zipRandomFile = zipRandomFile; + this.zipFileIndex = index; + + findCENRecord(start, end); + } + + /* + * Reads zip file central directory. + * For more details see readCEN in zip_util.c from the JDK sources. + * This is a Java port of that function. + */ + private void findCENRecord(long start, long end) throws IOException { + long totalLength = end - start; + int endbuflen = 1024; + byte[] endbuf = new byte[endbuflen]; + long endbufend = end - start; + + // There is a variable-length field after the dir offset record. We need to do consequential search. + while (endbufend >= 22) { + if (endbufend < endbuflen) + endbuflen = (int)endbufend; + long endbufpos = endbufend - endbuflen; + zipRandomFile.seek(start + endbufpos); + zipRandomFile.readFully(endbuf, 0, endbuflen); + int i = endbuflen - 22; + while (i >= 0 && + !(endbuf[i] == 0x50 && + endbuf[i + 1] == 0x4b && + endbuf[i + 2] == 0x05 && + endbuf[i + 3] == 0x06 && + endbufpos + i + 22 + + get2ByteLittleEndian(endbuf, i + 20) == totalLength)) { + i--; + } + + if (i >= 0) { + zipDir = new byte[get4ByteLittleEndian(endbuf, i + 12) + 2]; + zipDir[0] = endbuf[i + 10]; + zipDir[1] = endbuf[i + 11]; + zipRandomFile.seek(start + get4ByteLittleEndian(endbuf, i + 16)); + zipRandomFile.readFully(zipDir, 2, zipDir.length - 2); + return; + } else { + endbufend = endbufpos + 21; + } + } + throw new ZipException("cannot read zip file"); + } + + private void buildIndex() throws IOException { + int entryCount = get2ByteLittleEndian(zipDir, 0); + + // Add each of the files + if (entryCount > 0) { + directories = new HashMap<RelativeDirectory, DirectoryEntry>(); + ArrayList<Entry> entryList = new ArrayList<Entry>(); + int pos = 2; + for (int i = 0; i < entryCount; i++) { + pos = readEntry(pos, entryList, directories); + } + + // Add the accumulated dirs into the same list + for (RelativeDirectory d: directories.keySet()) { + // use shared RelativeDirectory objects for parent dirs + RelativeDirectory parent = getRelativeDirectory(d.dirname().getPath()); + String file = d.basename(); + Entry zipFileIndexEntry = new Entry(parent, file); + zipFileIndexEntry.isDir = true; + entryList.add(zipFileIndexEntry); + } + + entries = entryList.toArray(new Entry[entryList.size()]); + Arrays.sort(entries); + } else { + cleanupState(); + } + } + + private int readEntry(int pos, List<Entry> entryList, + Map<RelativeDirectory, DirectoryEntry> directories) throws IOException { + if (get4ByteLittleEndian(zipDir, pos) != 0x02014b50) { + throw new ZipException("cannot read zip file entry"); + } + + int dirStart = pos + 46; + int fileStart = dirStart; + int fileEnd = fileStart + get2ByteLittleEndian(zipDir, pos + 28); + + if (zipFileIndex.symbolFilePrefixLength != 0 && + ((fileEnd - fileStart) >= symbolFilePrefixLength)) { + dirStart += zipFileIndex.symbolFilePrefixLength; + fileStart += zipFileIndex.symbolFilePrefixLength; + } + // Force any '\' to '/'. Keep the position of the last separator. + for (int index = fileStart; index < fileEnd; index++) { + byte nextByte = zipDir[index]; + if (nextByte == (byte)'\\') { + zipDir[index] = (byte)'/'; + fileStart = index + 1; + } else if (nextByte == (byte)'/') { + fileStart = index + 1; + } + } + + RelativeDirectory directory = null; + if (fileStart == dirStart) + directory = getRelativeDirectory(""); + else if (lastDir != null && lastLen == fileStart - dirStart - 1) { + int index = lastLen - 1; + while (zipDir[lastStart + index] == zipDir[dirStart + index]) { + if (index == 0) { + directory = lastDir; + break; + } + index--; + } + } + + // Sub directories + if (directory == null) { + lastStart = dirStart; + lastLen = fileStart - dirStart - 1; + + directory = getRelativeDirectory(new String(zipDir, dirStart, lastLen, "UTF-8")); + lastDir = directory; + + // Enter also all the parent directories + RelativeDirectory tempDirectory = directory; + + while (directories.get(tempDirectory) == null) { + directories.put(tempDirectory, new DirectoryEntry(tempDirectory, zipFileIndex)); + if (tempDirectory.path.indexOf("/") == tempDirectory.path.length() - 1) + break; + else { + // use shared RelativeDirectory objects for parent dirs + tempDirectory = getRelativeDirectory(tempDirectory.dirname().getPath()); + } + } + } + else { + if (directories.get(directory) == null) { + directories.put(directory, new DirectoryEntry(directory, zipFileIndex)); + } + } + + // For each dir create also a file + if (fileStart != fileEnd) { + Entry entry = new Entry(directory, + new String(zipDir, fileStart, fileEnd - fileStart, "UTF-8")); + + entry.setNativeTime(get4ByteLittleEndian(zipDir, pos + 12)); + entry.compressedSize = get4ByteLittleEndian(zipDir, pos + 20); + entry.size = get4ByteLittleEndian(zipDir, pos + 24); + entry.offset = get4ByteLittleEndian(zipDir, pos + 42); + entryList.add(entry); + } + + return pos + 46 + + get2ByteLittleEndian(zipDir, pos + 28) + + get2ByteLittleEndian(zipDir, pos + 30) + + get2ByteLittleEndian(zipDir, pos + 32); + } + } + + /** + * Returns the last modified timestamp of a zip file. + * @return long + */ + public long getZipFileLastModified() throws IOException { + lock.lock(); + try { + checkIndex(); + return zipFileLastModified; + } + finally { + lock.unlock(); + } + } + + /** ------------------------------------------------------------------------ + * DirectoryEntry class + * -------------------------------------------------------------------------*/ + + static class DirectoryEntry { + private boolean filesInited; + private boolean directoriesInited; + private boolean zipFileEntriesInited; + private boolean entriesInited; + + private long writtenOffsetOffset = 0; + + private RelativeDirectory dirName; + + private com.sun.tools.javac.util.List<String> zipFileEntriesFiles = com.sun.tools.javac.util.List.<String>nil(); + private com.sun.tools.javac.util.List<String> zipFileEntriesDirectories = com.sun.tools.javac.util.List.<String>nil(); + private com.sun.tools.javac.util.List<Entry> zipFileEntries = com.sun.tools.javac.util.List.<Entry>nil(); + + private List<Entry> entries = new ArrayList<Entry>(); + + private ZipFileIndex zipFileIndex; + + private int numEntries; + + DirectoryEntry(RelativeDirectory dirName, ZipFileIndex index) { + filesInited = false; + directoriesInited = false; + entriesInited = false; + + this.dirName = dirName; + this.zipFileIndex = index; + } + + private com.sun.tools.javac.util.List<String> getFiles() { + if (!filesInited) { + initEntries(); + for (Entry e : entries) { + if (!e.isDir) { + zipFileEntriesFiles = zipFileEntriesFiles.append(e.name); + } + } + filesInited = true; + } + return zipFileEntriesFiles; + } + + private com.sun.tools.javac.util.List<String> getDirectories() { + if (!directoriesInited) { + initEntries(); + for (Entry e : entries) { + if (e.isDir) { + zipFileEntriesDirectories = zipFileEntriesDirectories.append(e.name); + } + } + directoriesInited = true; + } + return zipFileEntriesDirectories; + } + + private com.sun.tools.javac.util.List<Entry> getEntries() { + if (!zipFileEntriesInited) { + initEntries(); + zipFileEntries = com.sun.tools.javac.util.List.nil(); + for (Entry zfie : entries) { + zipFileEntries = zipFileEntries.append(zfie); + } + zipFileEntriesInited = true; + } + return zipFileEntries; + } + + private Entry getEntry(String rootName) { + initEntries(); + int index = Collections.binarySearch(entries, new Entry(dirName, rootName)); + if (index < 0) { + return null; + } + + return entries.get(index); + } + + private void initEntries() { + if (entriesInited) { + return; + } + + if (!zipFileIndex.readFromIndex) { + int from = -Arrays.binarySearch(zipFileIndex.entries, + new Entry(dirName, ZipFileIndex.MIN_CHAR)) - 1; + int to = -Arrays.binarySearch(zipFileIndex.entries, + new Entry(dirName, MAX_CHAR)) - 1; + + for (int i = from; i < to; i++) { + entries.add(zipFileIndex.entries[i]); + } + } else { + File indexFile = zipFileIndex.getIndexFile(); + if (indexFile != null) { + RandomAccessFile raf = null; + try { + raf = new RandomAccessFile(indexFile, "r"); + raf.seek(writtenOffsetOffset); + + for (int nFiles = 0; nFiles < numEntries; nFiles++) { + // Read the name bytes + int zfieNameBytesLen = raf.readInt(); + byte [] zfieNameBytes = new byte[zfieNameBytesLen]; + raf.read(zfieNameBytes); + String eName = new String(zfieNameBytes, "UTF-8"); + + // Read isDir + boolean eIsDir = raf.readByte() == (byte)0 ? false : true; + + // Read offset of bytes in the real Jar/Zip file + int eOffset = raf.readInt(); + + // Read size of the file in the real Jar/Zip file + int eSize = raf.readInt(); + + // Read compressed size of the file in the real Jar/Zip file + int eCsize = raf.readInt(); + + // Read java time stamp of the file in the real Jar/Zip file + long eJavaTimestamp = raf.readLong(); + + Entry rfie = new Entry(dirName, eName); + rfie.isDir = eIsDir; + rfie.offset = eOffset; + rfie.size = eSize; + rfie.compressedSize = eCsize; + rfie.javatime = eJavaTimestamp; + entries.add(rfie); + } + } catch (Throwable t) { + // Do nothing + } finally { + try { + if (raf != null) { + raf.close(); + } + } catch (Throwable t) { + // Do nothing + } + } + } + } + + entriesInited = true; + } + + List<Entry> getEntriesAsCollection() { + initEntries(); + + return entries; + } + } + + private boolean readIndex() { + if (triedToReadIndex || !usePreindexedCache) { + return false; + } + + boolean ret = false; + lock.lock(); + try { + triedToReadIndex = true; + RandomAccessFile raf = null; + try { + File indexFileName = getIndexFile(); + raf = new RandomAccessFile(indexFileName, "r"); + + long fileStamp = raf.readLong(); + if (zipFile.lastModified() != fileStamp) { + ret = false; + } else { + directories = new HashMap<RelativeDirectory, DirectoryEntry>(); + int numDirs = raf.readInt(); + for (int nDirs = 0; nDirs < numDirs; nDirs++) { + int dirNameBytesLen = raf.readInt(); + byte [] dirNameBytes = new byte[dirNameBytesLen]; + raf.read(dirNameBytes); + + RelativeDirectory dirNameStr = getRelativeDirectory(new String(dirNameBytes, "UTF-8")); + DirectoryEntry de = new DirectoryEntry(dirNameStr, this); + de.numEntries = raf.readInt(); + de.writtenOffsetOffset = raf.readLong(); + directories.put(dirNameStr, de); + } + ret = true; + zipFileLastModified = fileStamp; + } + } catch (Throwable t) { + // Do nothing + } finally { + if (raf != null) { + try { + raf.close(); + } catch (Throwable tt) { + // Do nothing + } + } + } + if (ret == true) { + readFromIndex = true; + } + } + finally { + lock.unlock(); + } + + return ret; + } + + private boolean writeIndex() { + boolean ret = false; + if (readFromIndex || !usePreindexedCache) { + return true; + } + + if (!writeIndex) { + return true; + } + + File indexFile = getIndexFile(); + if (indexFile == null) { + return false; + } + + RandomAccessFile raf = null; + long writtenSoFar = 0; + try { + raf = new RandomAccessFile(indexFile, "rw"); + + raf.writeLong(zipFileLastModified); + writtenSoFar += 8; + + List<DirectoryEntry> directoriesToWrite = new ArrayList<DirectoryEntry>(); + Map<RelativeDirectory, Long> offsets = new HashMap<RelativeDirectory, Long>(); + raf.writeInt(directories.keySet().size()); + writtenSoFar += 4; + + for (RelativeDirectory dirName: directories.keySet()) { + DirectoryEntry dirEntry = directories.get(dirName); + + directoriesToWrite.add(dirEntry); + + // Write the dir name bytes + byte [] dirNameBytes = dirName.getPath().getBytes("UTF-8"); + int dirNameBytesLen = dirNameBytes.length; + raf.writeInt(dirNameBytesLen); + writtenSoFar += 4; + + raf.write(dirNameBytes); + writtenSoFar += dirNameBytesLen; + + // Write the number of files in the dir + List<Entry> dirEntries = dirEntry.getEntriesAsCollection(); + raf.writeInt(dirEntries.size()); + writtenSoFar += 4; + + offsets.put(dirName, new Long(writtenSoFar)); + + // Write the offset of the file's data in the dir + dirEntry.writtenOffsetOffset = 0L; + raf.writeLong(0L); + writtenSoFar += 8; + } + + for (DirectoryEntry de : directoriesToWrite) { + // Fix up the offset in the directory table + long currFP = raf.getFilePointer(); + + long offsetOffset = offsets.get(de.dirName).longValue(); + raf.seek(offsetOffset); + raf.writeLong(writtenSoFar); + + raf.seek(currFP); + + // Now write each of the files in the DirectoryEntry + List<Entry> entries = de.getEntriesAsCollection(); + for (Entry zfie : entries) { + // Write the name bytes + byte [] zfieNameBytes = zfie.name.getBytes("UTF-8"); + int zfieNameBytesLen = zfieNameBytes.length; + raf.writeInt(zfieNameBytesLen); + writtenSoFar += 4; + raf.write(zfieNameBytes); + writtenSoFar += zfieNameBytesLen; + + // Write isDir + raf.writeByte(zfie.isDir ? (byte)1 : (byte)0); + writtenSoFar += 1; + + // Write offset of bytes in the real Jar/Zip file + raf.writeInt(zfie.offset); + writtenSoFar += 4; + + // Write size of the file in the real Jar/Zip file + raf.writeInt(zfie.size); + writtenSoFar += 4; + + // Write compressed size of the file in the real Jar/Zip file + raf.writeInt(zfie.compressedSize); + writtenSoFar += 4; + + // Write java time stamp of the file in the real Jar/Zip file + raf.writeLong(zfie.getLastModified()); + writtenSoFar += 8; + } + } + } catch (Throwable t) { + // Do nothing + } finally { + try { + if (raf != null) { + raf.close(); + } + } catch(IOException ioe) { + // Do nothing + } + } + + return ret; + } + + public boolean writeZipIndex() { + lock.lock(); + try { + return writeIndex(); + } + finally { + lock.unlock(); + } + } + + private File getIndexFile() { + if (zipIndexFile == null) { + if (zipFile == null) { + return null; + } + + zipIndexFile = new File((preindexedCacheLocation == null ? "" : preindexedCacheLocation) + + zipFile.getName() + ".index"); + } + + return zipIndexFile; + } + + public File getZipFile() { + return zipFile; + } + + File getAbsoluteFile() { + File absFile = (absFileRef == null ? null : absFileRef.get()); + if (absFile == null) { + absFile = zipFile.getAbsoluteFile(); + absFileRef = new SoftReference<File>(absFile); + } + return absFile; + } + + private RelativeDirectory getRelativeDirectory(String path) { + RelativeDirectory rd; + SoftReference<RelativeDirectory> ref = relativeDirectoryCache.get(path); + if (ref != null) { + rd = ref.get(); + if (rd != null) + return rd; + } + rd = new RelativeDirectory(path); + relativeDirectoryCache.put(path, new SoftReference<RelativeDirectory>(rd)); + return rd; + } + + static class Entry implements Comparable<Entry> { + public static final Entry[] EMPTY_ARRAY = {}; + + // Directory related + RelativeDirectory dir; + boolean isDir; + + // File related + String name; + + int offset; + int size; + int compressedSize; + long javatime; + + private int nativetime; + + public Entry(RelativePath path) { + this(path.dirname(), path.basename()); + } + + public Entry(RelativeDirectory directory, String name) { + this.dir = directory; + this.name = name; + } + + public String getName() { + return new RelativeFile(dir, name).getPath(); + } + + public String getFileName() { + return name; + } + + public long getLastModified() { + if (javatime == 0) { + javatime = dosToJavaTime(nativetime); + } + return javatime; + } + + // based on dosToJavaTime in java.util.Zip, but avoiding the + // use of deprecated Date constructor + private static long dosToJavaTime(int dtime) { + Calendar c = Calendar.getInstance(); + c.set(Calendar.YEAR, ((dtime >> 25) & 0x7f) + 1980); + c.set(Calendar.MONTH, ((dtime >> 21) & 0x0f) - 1); + c.set(Calendar.DATE, ((dtime >> 16) & 0x1f)); + c.set(Calendar.HOUR_OF_DAY, ((dtime >> 11) & 0x1f)); + c.set(Calendar.MINUTE, ((dtime >> 5) & 0x3f)); + c.set(Calendar.SECOND, ((dtime << 1) & 0x3e)); + c.set(Calendar.MILLISECOND, 0); + return c.getTimeInMillis(); + } + + void setNativeTime(int natTime) { + nativetime = natTime; + } + + public boolean isDirectory() { + return isDir; + } + + public int compareTo(Entry other) { + RelativeDirectory otherD = other.dir; + if (dir != otherD) { + int c = dir.compareTo(otherD); + if (c != 0) + return c; + } + return name.compareTo(other.name); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Entry)) + return false; + Entry other = (Entry) o; + return dir.equals(other.dir) && name.equals(other.name); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + (this.dir != null ? this.dir.hashCode() : 0); + hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0); + return hash; + } + + + public String toString() { + return isDir ? ("Dir:" + dir + " : " + name) : + (dir + ":" + name); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,253 @@ +/* + * 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.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.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 entry != null; // 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(); + } + } + +}
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Tue Jun 22 18:30:16 2010 -0700 @@ -25,6 +25,7 @@ package com.sun.tools.javac.jvm; +import java.net.URISyntaxException; import java.io.*; import java.net.URI; import java.nio.CharBuffer; @@ -42,6 +43,7 @@ import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.file.BaseFileObject; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.List; @@ -1047,7 +1049,7 @@ void readClassAttr(ClassSymbol c, Name attrName, int attrLen) { if (attrName == names.SourceFile) { Name n = readName(nextChar()); - c.sourcefile = new SourceFileObject(n); + c.sourcefile = new SourceFileObject(n, c.flatname); } else if (attrName == names.InnerClasses) { readInnerClasses(c); } else if (allowGenerics && attrName == names.Signature) { @@ -2212,69 +2214,103 @@ /** The file's name. */ private Name name; + private Name flatname; - public SourceFileObject(Name name) { + public SourceFileObject(Name name, Name flatname) { + super(null); // no file manager; never referenced for this file object this.name = name; + this.flatname = flatname; + } + + //@Override + public URI toUri() { + try { + return new URI(null, name.toString(), null); + } catch (URISyntaxException e) { + throw new CannotCreateUriError(name.toString(), e); + } } + //@Override + public String getName() { + return name.toString(); + } + + //@Override + public String getShortName() { + return getName(); + } + + //@Override + public JavaFileObject.Kind getKind() { + return getKind(getName()); + } + + //@Override public InputStream openInputStream() { throw new UnsupportedOperationException(); } + //@Override public OutputStream openOutputStream() { throw new UnsupportedOperationException(); } - public Reader openReader() { + //@Override + public CharBuffer getCharContent(boolean ignoreEncodingErrors) { throw new UnsupportedOperationException(); } + //@Override + public Reader openReader(boolean ignoreEncodingErrors) { + throw new UnsupportedOperationException(); + } + + //@Override public Writer openWriter() { throw new UnsupportedOperationException(); } - /** @deprecated see bug 6410637 */ - @Deprecated - public String getName() { - return name.toString(); - } - + //@Override public long getLastModified() { throw new UnsupportedOperationException(); } + //@Override public boolean delete() { throw new UnsupportedOperationException(); } - public CharBuffer getCharContent(boolean ignoreEncodingErrors) { - throw new UnsupportedOperationException(); + //@Override + protected String inferBinaryName(Iterable<? extends File> path) { + return flatname.toString(); + } + + //@Override + public boolean isNameCompatible(String simpleName, JavaFileObject.Kind kind) { + return true; // fail-safe mode } - @Override + /** + * Check if two file objects are equal. + * SourceFileObjects are just placeholder objects for the value of a + * SourceFile attribute, and do not directly represent specific files. + * Two SourceFileObjects are equal if their names are equal. + */ + //@Override public boolean equals(Object other) { + if (this == other) + return true; + if (!(other instanceof SourceFileObject)) return false; SourceFileObject o = (SourceFileObject) other; return name.equals(o.name); } - @Override + //@Override public int hashCode() { return name.hashCode(); } - - public boolean isNameCompatible(String simpleName, JavaFileObject.Kind kind) { - return true; // fail-safe mode - } - - public URI toUri() { - return URI.create(name.toString()); - } - - public Reader openReader(boolean ignoreEncodingErrors) throws IOException { - throw new UnsupportedOperationException(); - } - } }
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Tue Jun 22 18:30:16 2010 -0700 @@ -37,6 +37,7 @@ import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Type.*; +import com.sun.tools.javac.file.BaseFileObject; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.List; @@ -1546,13 +1547,8 @@ // the last possible moment because the sourcefile may be used // elsewhere in error diagnostics. Fixes 4241573. //databuf.appendChar(c.pool.put(c.sourcefile)); - String filename = c.sourcefile.toString(); - int sepIdx = filename.lastIndexOf(File.separatorChar); - // Allow '/' as separator on all platforms, e.g., on Win32. - int slashIdx = filename.lastIndexOf('/'); - if (slashIdx > sepIdx) sepIdx = slashIdx; - if (sepIdx >= 0) filename = filename.substring(sepIdx + 1); - databuf.appendChar(c.pool.put(names.fromString(filename))); + String simpleName = BaseFileObject.getSimpleName(c.sourcefile); + databuf.appendChar(c.pool.put(names.fromString(simpleName))); endAttr(alenIdx); acount++; }
--- a/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Tue Jun 22 18:30:16 2010 -0700 @@ -44,6 +44,7 @@ import com.sun.source.util.TaskEvent; import com.sun.source.util.TaskListener; +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.util.*; import com.sun.tools.javac.code.*; import com.sun.tools.javac.tree.*; @@ -553,7 +554,7 @@ inputFiles.add(filename); return filename.getCharContent(false); } catch (IOException e) { - log.error("error.reading.file", filename, e.getLocalizedMessage()); + log.error("error.reading.file", filename, JavacFileManager.getMessage(e)); return null; } } @@ -716,7 +717,7 @@ try { tree = parse(filename, filename.getCharContent(false)); } catch (IOException e) { - log.error("error.reading.file", filename, e); + log.error("error.reading.file", filename, JavacFileManager.getMessage(e)); tree = make.TopLevel(List.<JCTree.JCAnnotation>nil(), null, List.<JCTree>nil()); } finally { log.useSource(prev);
--- a/src/share/classes/com/sun/tools/javac/main/Main.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javac/main/Main.java Tue Jun 22 18:30:16 2010 -0700 @@ -32,6 +32,8 @@ import java.util.MissingResourceException; import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.file.CacheFSInfo; +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.jvm.Target; import com.sun.tools.javac.main.JavacOption.Option; import com.sun.tools.javac.main.RecognizedOptions.OptionHelper; @@ -331,13 +333,13 @@ return EXIT_CMDERR; } - List<File> filenames; + List<File> files; try { - filenames = processArgs(CommandLine.parse(args)); - if (filenames == null) { + files = processArgs(CommandLine.parse(args)); + if (files == null) { // null signals an error in options, abort return EXIT_CMDERR; - } else if (filenames.isEmpty() && fileObjects.isEmpty() && classnames.isEmpty()) { + } else if (files.isEmpty() && fileObjects.isEmpty() && classnames.isEmpty()) { // it is allowed to compile nothing if just asking for help or version info if (options.get("-help") != null || options.get("-X") != null @@ -362,17 +364,23 @@ context.put(Log.outKey, out); + // allow System property in following line as a Mustang legacy + boolean batchMode = (options.get("nonBatchMode") == null + && System.getProperty("nonBatchMode") == null); + if (batchMode) + CacheFSInfo.preRegister(context); + fileManager = context.get(JavaFileManager.class); comp = JavaCompiler.instance(context); if (comp == null) return EXIT_SYSERR; - if (!filenames.isEmpty()) { + if (!files.isEmpty()) { // add filenames to fileObjects comp = JavaCompiler.instance(context); List<JavaFileObject> otherFiles = List.nil(); JavacFileManager dfm = (JavacFileManager)fileManager; - for (JavaFileObject fo : dfm.getJavaFileObjectsFromFiles(filenames)) + for (JavaFileObject fo : dfm.getJavaFileObjectsFromFiles(files)) otherFiles = otherFiles.prepend(fo); for (JavaFileObject fo : otherFiles) fileObjects = fileObjects.prepend(fo);
--- a/src/share/classes/com/sun/tools/javac/parser/Scanner.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javac/parser/Scanner.java Tue Jun 22 18:30:16 2010 -0700 @@ -32,6 +32,7 @@ import java.nio.channels.*; import java.util.regex.*; +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.util.*; import com.sun.tools.javac.code.Source;
--- a/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java Tue Jun 22 18:30:16 2010 -0700 @@ -28,6 +28,7 @@ import com.sun.source.util.TaskEvent; import com.sun.source.util.TaskListener; import com.sun.tools.javac.api.JavacTaskImpl; +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.*; import com.sun.tools.javac.code.*; @@ -169,7 +170,6 @@ } private void initProcessorIterator(Context context, Iterable<? extends Processor> processors) { - Paths paths = Paths.instance(context); Log log = Log.instance(context); Iterator<? extends Processor> processorIterator;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,355 @@ +/* + * Copyright (c) 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.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; + } +}
--- a/src/share/classes/com/sun/tools/javac/util/BaseFileObject.java Mon Jun 21 11:43:28 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2005, 2006, 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.util; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.CharsetDecoder; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.NestingKind; -import javax.tools.JavaFileObject; - -import static javax.tools.JavaFileObject.Kind.*; - -public abstract class BaseFileObject implements JavaFileObject { - - public JavaFileObject.Kind getKind() { - String n = getName(); - if (n.endsWith(CLASS.extension)) - return CLASS; - else if (n.endsWith(SOURCE.extension)) - return SOURCE; - else if (n.endsWith(HTML.extension)) - return HTML; - else - return OTHER; - } - - @Override - public String toString() { - return getPath(); - } - - /** @deprecated see bug 6410637 */ - @Deprecated - public String getPath() { - return getName(); - } - - /** @deprecated see bug 6410637 */ - @Deprecated - abstract public String 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(); - } - -}
--- a/src/share/classes/com/sun/tools/javac/util/DiagnosticFormatter.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javac/util/DiagnosticFormatter.java Tue Jun 22 18:30:16 2010 -0700 @@ -27,6 +27,8 @@ import javax.tools.JavaFileObject; +import com.sun.tools.javac.file.BaseFileObject; +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticSource; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; @@ -143,8 +145,10 @@ sb.append(format_raw((JCDiagnostic) arg)); sb.append(')'); } + else if (arg instanceof BaseFileObject) + sb.append(((BaseFileObject) arg).getShortName()); else if (arg instanceof JavaFileObject) - sb.append(JavacFileManager.getJavacBaseFileName((JavaFileObject) arg)); + sb.append(BaseFileObject.getSimpleName((JavaFileObject) arg)); else sb.append(arg); sep = ", ";
--- a/src/share/classes/com/sun/tools/javac/util/JCDiagnostic.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javac/util/JCDiagnostic.java Tue Jun 22 18:30:16 2010 -0700 @@ -25,12 +25,8 @@ package com.sun.tools.javac.util; -import java.net.URI; -import java.text.MessageFormat; import java.util.Locale; import java.util.Map; -import java.util.MissingResourceException; -import java.util.ResourceBundle; import javax.tools.Diagnostic; import javax.tools.FileObject; @@ -341,7 +337,7 @@ */ public String getSourceName() { JavaFileObject s = getSource(); - return s == null ? null : JavacFileManager.getJavacFileName(s); + return s == null ? null : s.getName(); } /** @@ -445,6 +441,8 @@ Object arg = args[i]; if (arg == null) strings[i] = null; + else if (arg instanceof FileObject) + strings[i] = ((FileObject) arg).getName(); else if (arg instanceof JCDiagnostic) strings[i] = ((JCDiagnostic) arg).getMessage(null); else
--- a/src/share/classes/com/sun/tools/javac/util/JavacFileManager.java Mon Jun 21 11:43:28 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1754 +0,0 @@ -/* - * Copyright (c) 2005, 2006, 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.util; - -import java.io.ByteArrayOutputStream; -import java.io.Closeable; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -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.SoftReference; -import java.lang.reflect.Constructor; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.channels.FileChannel; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; -import java.nio.charset.IllegalCharsetNameException; -import java.nio.charset.UnsupportedCharsetException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.zip.ZipEntry; -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.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 com.sun.tools.javac.zip.*; -import java.io.ByteArrayInputStream; - -import static com.sun.tools.javac.main.OptionName.*; -import static javax.tools.StandardLocation.*; - -/** - * This class provides access to the source, class and other files - * used by the compiler and related tools. - */ -public class JavacFileManager implements StandardJavaFileManager { - - private static final String[] symbolFileLocation = { "lib", "ct.sym" }; - private static final String symbolFilePrefix = "META-INF/sym/rt.jar/"; - - boolean useZipFileIndex; - - private static int symbolFilePrefixLength = 0; - static { - try { - symbolFilePrefixLength = symbolFilePrefix.getBytes("UTF-8").length; - } catch (java.io.UnsupportedEncodingException uee) { - // Can't happen...UTF-8 is always supported. - } - } - - private static boolean CHECK_ZIP_TIMESTAMP = false; - private static Map<File, Boolean> isDirectory = new ConcurrentHashMap<File, Boolean>(); - - - public static char[] toArray(CharBuffer buffer) { - if (buffer.hasArray()) - return ((CharBuffer)buffer.compact().flip()).array(); - else - return buffer.toString().toCharArray(); - } - - /** - * The log to be used for error reporting. - */ - protected Log log; - - /** Encapsulates knowledge of paths - */ - private Paths paths; - - private Options options; - - private final File uninited = new File("U N I N I T E D"); - - private final Set<JavaFileObject.Kind> sourceOrClass = - EnumSet.of(JavaFileObject.Kind.SOURCE, JavaFileObject.Kind.CLASS); - - /** The standard output directory, primarily used for classes. - * Initialized by the "-d" option. - * If classOutDir = null, files are written into same directory as the sources - * they were generated from. - */ - private File classOutDir = uninited; - - /** The output directory, used when generating sources while processing annotations. - * Initialized by the "-s" option. - */ - private File sourceOutDir = uninited; - - protected boolean mmappedIO; - protected boolean ignoreSymbolFile; - protected String classLoaderClass; - - /** - * User provided charset (through javax.tools). - */ - protected Charset charset; - - /** - * Register a Context.Factory to create a JavacFileManager. - */ - public static void preRegister(final Context context) { - context.put(JavaFileManager.class, new Context.Factory<JavaFileManager>() { - public JavaFileManager make() { - return new JavacFileManager(context, 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) { - if (register) - context.put(JavaFileManager.class, this); - byteBufferCache = new ByteBufferCache(); - this.charset = charset; - setContext(context); - } - - /** - * Set the context for JavacFileManager. - */ - public void setContext(Context context) { - log = Log.instance(context); - if (paths == null) { - paths = Paths.instance(context); - } else { - // Reuse the Paths object as it stores the locations that - // have been set with setLocation, etc. - paths.setContext(context); - } - - options = Options.instance(context); - - useZipFileIndex = System.getProperty("useJavaUtilZip") == null;// TODO: options.get("useJavaUtilZip") == null; - CHECK_ZIP_TIMESTAMP = System.getProperty("checkZipIndexTimestamp") != null;// TODO: options.get("checkZipIndexTimestamp") != null; - - mmappedIO = options.get("mmappedIO") != null; - ignoreSymbolFile = options.get("ignore.symbol.file") != null; - classLoaderClass = options.get("procloader"); - } - - public JavaFileObject getFileForInput(String name) { - return getRegularFile(new File(name)); - } - - public JavaFileObject getRegularFile(File file) { - return new RegularFileObject(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))); - } - - protected JavaFileObject.Kind getKind(String extension) { - if (extension.equals(JavaFileObject.Kind.CLASS.extension)) - return JavaFileObject.Kind.CLASS; - else if (extension.equals(JavaFileObject.Kind.SOURCE.extension)) - return JavaFileObject.Kind.SOURCE; - else if (extension.equals(JavaFileObject.Kind.HTML.extension)) - return JavaFileObject.Kind.HTML; - else - return JavaFileObject.Kind.OTHER; - } - - private static boolean isValidName(String name) { - // Arguably, isValidName should reject keywords (such as in SourceVersion.isName() ), - // but the set of keywords depends on the source level, and we don't want - // 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); - } - - /** Return external representation of name, - * converting '.' to File.separatorChar. - */ - private static String externalizeFileName(CharSequence name) { - return name.toString().replace('.', File.separatorChar); - } - - private static String externalizeFileName(CharSequence n, JavaFileObject.Kind kind) { - return externalizeFileName(n) + kind.extension; - } - - private static String baseName(String fileName) { - return fileName.substring(fileName.lastIndexOf(File.separatorChar) + 1); - } - - /** - * Insert all files in subdirectory `subdirectory' of `directory' which end - * in one of the extensions in `extensions' into packageSym. - */ - private void listDirectory(File directory, - String subdirectory, - Set<JavaFileObject.Kind> fileKinds, - boolean recurse, - ListBuffer<JavaFileObject> l) { - Archive archive = archives.get(directory); - - boolean isFile = false; - if (CHECK_ZIP_TIMESTAMP) { - Boolean isf = isDirectory.get(directory); - if (isf == null) { - isFile = directory.isFile(); - isDirectory.put(directory, isFile); - } - else { - isFile = directory.isFile(); - } - } - else { - isFile = directory.isFile(); - } - - if (archive != null || isFile) { - if (archive == null) { - try { - archive = openArchive(directory); - } catch (IOException ex) { - log.error("error.reading.file", - directory, ex.getLocalizedMessage()); - return; - } - } - if (subdirectory.length() != 0) { - if (!useZipFileIndex) { - subdirectory = subdirectory.replace('\\', '/'); - if (!subdirectory.endsWith("/")) subdirectory = subdirectory + "/"; - } - else { - if (File.separatorChar == '/') { - subdirectory = subdirectory.replace('\\', '/'); - } - else { - subdirectory = subdirectory.replace('/', '\\'); - } - - if (!subdirectory.endsWith(File.separator)) subdirectory = subdirectory + File.separator; - } - } - - List<String> files = archive.getFiles(subdirectory); - if (files != null) { - for (String file; !files.isEmpty(); files = files.tail) { - file = files.head; - if (isValidFile(file, fileKinds)) { - l.append(archive.getFileObject(subdirectory, file)); - } - } - } - if (recurse) { - for (String s: archive.getSubdirectories()) { - if (s.startsWith(subdirectory) && !s.equals(subdirectory)) { - // 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. - listDirectory(directory, s, fileKinds, false, l); - } - } - } - } else { - File d = subdirectory.length() != 0 - ? new File(directory, subdirectory) - : directory; - if (!caseMapCheck(d, subdirectory)) - return; - - File[] files = d.listFiles(); - if (files == null) - return; - - for (File f: files) { - String fname = f.getName(); - if (f.isDirectory()) { - if (recurse && SourceVersion.isIdentifier(fname)) { - listDirectory(directory, - subdirectory + File.separator + fname, - fileKinds, - recurse, - l); - } - } else { - if (isValidFile(fname, fileKinds)) { - JavaFileObject fe = - new RegularFileObject(fname, new File(d, fname)); - l.append(fe); - } - } - } - } - } - - private boolean isValidFile(String s, Set<JavaFileObject.Kind> fileKinds) { - int lastDot = s.lastIndexOf("."); - String extn = (lastDot == -1 ? s : s.substring(lastDot)); - JavaFileObject.Kind kind = getKind(extn); - 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, String 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.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] == File.separatorChar) 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(String name); - - JavaFileObject getFileObject(String subdirectory, String file); - - List<String> getFiles(String subdirectory); - - Set<String> getSubdirectories(); - } - - public class ZipArchive implements Archive { - protected final Map<String,List<String>> map; - protected final ZipFile zdir; - public ZipArchive(ZipFile zdir) throws IOException { - this.zdir = zdir; - this.map = new HashMap<String,List<String>>(); - for (Enumeration<? extends ZipEntry> e = zdir.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('/'); - String dirname = 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(String name) { - int i = name.lastIndexOf('/'); - String dirname = name.substring(0, i+1); - String basename = name.substring(i+1); - if (basename.length() == 0) - return false; - List<String> list = map.get(dirname); - return (list != null && list.contains(basename)); - } - - public List<String> getFiles(String subdirectory) { - return map.get(subdirectory); - } - - public JavaFileObject getFileObject(String subdirectory, String file) { - ZipEntry ze = zdir.getEntry(subdirectory + file); - return new ZipFileObject(file, zdir, ze); - } - - public Set<String> getSubdirectories() { - return map.keySet(); - } - - public void close() throws IOException { - zdir.close(); - } - } - - public class SymbolArchive extends ZipArchive { - final File origFile; - public SymbolArchive(File orig, ZipFile zdir) throws IOException { - super(zdir); - this.origFile = orig; - } - - @Override - void addZipEntry(ZipEntry entry) { - // called from super constructor, may not refer to origFile. - String name = entry.getName(); - if (!name.startsWith(symbolFilePrefix)) - return; - name = name.substring(symbolFilePrefix.length()); - int i = name.lastIndexOf('/'); - String dirname = 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(String subdirectory, String file) { - return super.getFileObject(symbolFilePrefix + subdirectory, file); - } - } - - public class MissingArchive implements Archive { - final File zipFileName; - public MissingArchive(File name) { - zipFileName = name; - } - public boolean contains(String name) { - return false; - } - - public void close() { - } - - public JavaFileObject getFileObject(String subdirectory, String file) { - return null; - } - - public List<String> getFiles(String subdirectory) { - return List.nil(); - } - - public Set<String> getSubdirectories() { - return Collections.emptySet(); - } - } - - /** A directory of zip files already opened. - */ - Map<File, Archive> archives = new HashMap<File,Archive>(); - - /** Open a new zip file directory. - */ - protected Archive openArchive(File zipFileName) throws IOException { - Archive archive = archives.get(zipFileName); - if (archive == null) { - File origZipFileName = zipFileName; - if (!ignoreSymbolFile && paths.isBootClassPathRtJar(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; - } - - try { - - ZipFile zdir = null; - - boolean usePreindexedCache = false; - String preindexCacheLocation = null; - - if (!useZipFileIndex) { - zdir = new ZipFile(zipFileName); - } - else { - usePreindexedCache = options.get("usezipindex") != null; - 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 (!useZipFileIndex) { - archive = new ZipArchive(zdir); - } else { - archive = new ZipFileIndexArchive(this, ZipFileIndex.getZipFileIndex(zipFileName, 0, - usePreindexedCache, preindexCacheLocation, options.get("writezipindexfiles") != null)); - } - } - else { - if (!useZipFileIndex) { - archive = new SymbolArchive(origZipFileName, zdir); - } - else { - archive = new ZipFileIndexArchive(this, ZipFileIndex.getZipFileIndex(zipFileName, symbolFilePrefixLength, - usePreindexedCache, preindexCacheLocation, options.get("writezipindexfiles") != null)); - } - } - } catch (FileNotFoundException ex) { - archive = new MissingArchive(zipFileName); - } catch (IOException ex) { - log.error("error.reading.file", zipFileName, ex.getLocalizedMessage()); - 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 Map<JavaFileObject, SoftReference<CharBuffer>> contentCache = new HashMap<JavaFileObject, SoftReference<CharBuffer>>(); - - private String defaultEncodingName; - private String getDefaultEncodingName() { - if (defaultEncodingName == null) { - defaultEncodingName = - new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding(); - } - 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. - */ - private 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(); - } - - /** - * 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; - - private CharsetDecoder getDecoder(String encodingName, boolean ignoreEncodingErrors) { - Charset charset = (this.charset == null) - ? Charset.forName(encodingName) - : this.charset; - CharsetDecoder decoder = charset.newDecoder(); - - CodingErrorAction action; - if (ignoreEncodingErrors) - action = CodingErrorAction.REPLACE; - else - action = CodingErrorAction.REPORT; - - return decoder - .onMalformedInput(action) - .onUnmappableCharacter(action); - } - - /** - * Decode a ByteBuffer into a CharBuffer. - */ - private 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) { - 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); - } - } - - URL[] urls = 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, - 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(); - // allow use of binary package names, per the JavaFileManager spec - String subdirectory = externalizeFileName(packageName.replace('/', '.')); - ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>(); - - for (File directory : path) - listDirectory(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) { - //System.err.println("Path for " + location + " is null"); - return null; - } - //System.err.println("Path for " + location + " is " + path); - - if (file instanceof RegularFileObject) { - RegularFileObject r = (RegularFileObject) file; - String rPath = r.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 (rPath.regionMatches(true, 0, dPath, 0, dPath.length()) - && new File(rPath.substring(0, dPath.length())).equals(new File(dPath))) { - String relativeName = rPath.substring(dPath.length()); - return removeExtension(relativeName).replace(File.separatorChar, '.'); - } - } - } else if (file instanceof ZipFileObject) { - ZipFileObject z = (ZipFileObject) file; - String entryName = z.getZipEntryName(); - if (entryName.startsWith(symbolFilePrefix)) - entryName = entryName.substring(symbolFilePrefix.length()); - return removeExtension(entryName).replace('/', '.'); - } else if (file instanceof ZipFileIndexFileObject) { - ZipFileIndexFileObject z = (ZipFileIndexFileObject) file; - String entryName = z.getZipEntryName(); - if (entryName.startsWith(symbolFilePrefix)) - entryName = entryName.substring(symbolFilePrefix.length()); - return removeExtension(entryName).replace(File.separatorChar, '.'); - } else - throw new IllegalArgumentException(file.getClass().getName()); - // System.err.println("inferBinaryName failed for " + file); - return null; - } - // where - private static String removeExtension(String fileName) { - int lastDot = fileName.lastIndexOf("."); - return (lastDot == -1 ? fileName : fileName.substring(0, lastDot)); - } - - 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 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) { - 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, externalizeFileName(className, kind)); - } - - public FileObject getFileForInput(Location location, - String packageName, - String relativeName) - throws IOException - { - nullCheck(location); - // validatePackageName(packageName); - nullCheck(packageName); - if (!isRelativeUri(URI.create(relativeName))) // FIXME 6419701 - throw new IllegalArgumentException("Invalid relative name: " + relativeName); - String name = packageName.length() == 0 - ? relativeName - : new File(externalizeFileName(packageName), relativeName).getPath(); - return getFileForInput(location, name); - } - - private JavaFileObject getFileForInput(Location location, String name) throws IOException { - Iterable<? extends File> path = getLocation(location); - if (path == null) - return null; - - for (File dir: path) { - if (dir.isDirectory()) { - File f = new File(dir, name.replace('/', File.separatorChar)); - if (f.exists()) - return new RegularFileObject(f); - } else { - Archive a = openArchive(dir); - if (a.contains(name)) { - int i = name.lastIndexOf('/'); - String dirname = name.substring(0, i+1); - String basename = name.substring(i+1); - return a.getFileObject(dirname, 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, externalizeFileName(className, kind), sibling); - } - - public FileObject getFileForOutput(Location location, - String packageName, - String relativeName, - FileObject sibling) - throws IOException - { - nullCheck(location); - // validatePackageName(packageName); - nullCheck(packageName); - if (!isRelativeUri(URI.create(relativeName))) // FIXME 6419701 - throw new IllegalArgumentException("relativeName is invalid"); - String name = packageName.length() == 0 - ? relativeName - : new File(externalizeFileName(packageName), relativeName).getPath(); - return getFileForOutput(location, name, sibling); - } - - private JavaFileObject getFileForOutput(Location location, - String 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).f.getParentFile(); - } - return new RegularFileObject(new File(siblingDir, baseName(fileName))); - } - } else if (location == SOURCE_OUTPUT) { - dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir()); - } else { - Iterable<? extends File> path = paths.getPathForLocation(location); - dir = null; - for (File f: path) { - dir = f; - break; - } - } - - File file = (dir == null ? new File(fileName) : new File(dir, fileName)); - return new RegularFileObject(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(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); - paths.lazy(); - - final File dir = location.isOutputLocation() ? getOutputDirectory(path) : null; - - if (location == CLASS_OUTPUT) - classOutDir = getOutputLocation(dir, D); - else if (location == SOURCE_OUTPUT) - sourceOutDir = getOutputLocation(dir, S); - else - paths.setPathForLocation(location, path); - } - // where - private File getOutputDirectory(Iterable<? extends File> path) throws IOException { - if (path == null) - return null; - Iterator<? extends File> pathIter = path.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"); - return dir; - } - - private File getOutputLocation(File dir, OptionName defaultOptionName) { - if (dir != null) - return dir; - String arg = options.get(defaultOptionName); - if (arg == null) - return null; - return new File(arg); - } - - public Iterable<? extends File> getLocation(Location location) { - nullCheck(location); - paths.lazy(); - if (location == CLASS_OUTPUT) { - return (getClassOutDir() == null ? null : List.of(getClassOutDir())); - } else if (location == SOURCE_OUTPUT) { - return (getSourceOutDir() == null ? null : List.of(getSourceOutDir())); - } else - return paths.getPathForLocation(location); - } - - private File getClassOutDir() { - if (classOutDir == uninited) - classOutDir = getOutputLocation(null, D); - return classOutDir; - } - - private File getSourceOutDir() { - if (sourceOutDir == uninited) - sourceOutDir = getOutputLocation(null, S); - return sourceOutDir; - } - - /** - * Enforces the specification of a "relative" URI as used in - * {@linkplain #getFileForInput(Location,String,URI) - * 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; - char first = path.charAt(0); - return first != '.' && first != '/'; - } - - /** - * 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 (JavacFileManager.isRelativeUri(URI.create(result))) // FIXME 6419701 - return result; - } - throw new IllegalArgumentException("Invalid relative path: " + file); - } - - @SuppressWarnings("deprecation") // bug 6410637 - protected static String getJavacFileName(FileObject file) { - if (file instanceof BaseFileObject) - return ((BaseFileObject)file).getPath(); - URI uri = file.toUri(); - String scheme = uri.getScheme(); - if (scheme == null || scheme.equals("file") || scheme.equals("jar")) - return uri.getPath(); - else - return uri.toString(); - } - - @SuppressWarnings("deprecation") // bug 6410637 - protected static String getJavacBaseFileName(FileObject file) { - if (file instanceof BaseFileObject) - return ((BaseFileObject)file).getName(); - URI uri = file.toUri(); - String scheme = uri.getScheme(); - if (scheme == null || scheme.equals("file") || scheme.equals("jar")) { - String path = uri.getPath(); - if (path == null) - return null; - if (scheme != null && scheme.equals("jar")) - path = path.substring(path.lastIndexOf('!') + 1); - return path.substring(path.lastIndexOf('/') + 1); - } else { - return uri.toString(); - } - } - - 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; - } - - /** - * A subclass of JavaFileObject representing regular files. - */ - private class RegularFileObject extends BaseFileObject { - /** Have the parent directories been created? - */ - private boolean hasParents=false; - - /** The file's name. - */ - private String name; - - /** The underlying file. - */ - final File f; - - public RegularFileObject(File f) { - this(f.getName(), f); - } - - public RegularFileObject(String name, File f) { - if (f.isDirectory()) - throw new IllegalArgumentException("directories not supported"); - this.name = name; - this.f = f; - } - - public InputStream openInputStream() throws IOException { - return new FileInputStream(f); - } - - protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) { - return JavacFileManager.this.getDecoder(getEncodingName(), ignoreEncodingErrors); - } - - public OutputStream openOutputStream() throws IOException { - ensureParentDirectoriesExist(); - return new FileOutputStream(f); - } - - public Writer openWriter() throws IOException { - ensureParentDirectoriesExist(); - return new OutputStreamWriter(new FileOutputStream(f), getEncodingName()); - } - - private void ensureParentDirectoriesExist() throws IOException { - if (!hasParents) { - File parent = f.getParentFile(); - if (parent != null && !parent.exists()) { - if (!parent.mkdirs()) { - // if the mkdirs failed, it may be because another process concurrently - // created the directory, so check if the directory got created - // anyway before throwing an exception - if (!parent.exists() || !parent.isDirectory()) - throw new IOException("could not create parent directories"); - } - } - hasParents = true; - } - } - - /** @deprecated see bug 6410637 */ - @Deprecated - public String getName() { - return name; - } - - 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 (name.equalsIgnoreCase(n)) { - try { - // allow for Windows - return (f.getCanonicalFile().getName().equals(n)); - } catch (IOException e) { - } - } - return false; - } - - /** @deprecated see bug 6410637 */ - @Deprecated - public String getPath() { - return f.getPath(); - } - - public long getLastModified() { - return f.lastModified(); - } - - public boolean delete() { - return f.delete(); - } - - public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException { - SoftReference<CharBuffer> r = contentCache.get(this); - CharBuffer cb = (r == null ? null : r.get()); - if (cb == null) { - InputStream in = new FileInputStream(f); - try { - ByteBuffer bb = makeByteBuffer(in); - JavaFileObject prev = log.useSource(this); - try { - cb = decode(bb, ignoreEncodingErrors); - } finally { - log.useSource(prev); - } - byteBufferCache.put(bb); // save for next time - if (!ignoreEncodingErrors) - contentCache.put(this, new SoftReference<CharBuffer>(cb)); - } finally { - in.close(); - } - } - return cb; - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof RegularFileObject)) - return false; - RegularFileObject o = (RegularFileObject) other; - try { - return f.equals(o.f) - || f.getCanonicalFile().equals(o.f.getCanonicalFile()); - } catch (IOException e) { - return false; - } - } - - @Override - public int hashCode() { - return f.hashCode(); - } - - public URI toUri() { - try { - // Do no use File.toURI to avoid file system access - String path = f.getAbsolutePath().replace(File.separatorChar, '/'); - return new URI("file://" + path).normalize(); - } catch (URISyntaxException ex) { - return f.toURI(); - } - } - - } - - /** - * A subclass of JavaFileObject representing zip entries. - */ - public class ZipFileObject extends BaseFileObject { - - /** The entry's name. - */ - private String name; - - /** The zipfile containing the entry. - */ - ZipFile zdir; - - /** The underlying zip entry object. - */ - ZipEntry entry; - - public ZipFileObject(String name, ZipFile zdir, ZipEntry entry) { - this.name = name; - this.zdir = zdir; - this.entry = entry; - } - - public InputStream openInputStream() throws IOException { - return zdir.getInputStream(entry); - } - - public OutputStream openOutputStream() throws IOException { - throw new UnsupportedOperationException(); - } - - protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) { - return JavacFileManager.this.getDecoder(getEncodingName(), ignoreEncodingErrors); - } - - public Writer openWriter() throws IOException { - throw new UnsupportedOperationException(); - } - - /** @deprecated see bug 6410637 */ - @Deprecated - public String getName() { - return name; - } - - 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); - } - - /** @deprecated see bug 6410637 */ - @Deprecated - public String getPath() { - return zdir.getName() + "(" + entry + ")"; - } - - public long getLastModified() { - return entry.getTime(); - } - - public boolean delete() { - throw new UnsupportedOperationException(); - } - - public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException { - SoftReference<CharBuffer> r = contentCache.get(this); - CharBuffer cb = (r == null ? null : r.get()); - if (cb == null) { - InputStream in = zdir.getInputStream(entry); - try { - ByteBuffer bb = makeByteBuffer(in); - JavaFileObject prev = log.useSource(this); - try { - cb = decode(bb, ignoreEncodingErrors); - } finally { - log.useSource(prev); - } - byteBufferCache.put(bb); // save for next time - if (!ignoreEncodingErrors) - contentCache.put(this, new SoftReference<CharBuffer>(cb)); - } finally { - in.close(); - } - } - return cb; - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof ZipFileObject)) - return false; - ZipFileObject o = (ZipFileObject) other; - return zdir.equals(o.zdir) || name.equals(o.name); - } - - @Override - public int hashCode() { - return zdir.hashCode() + name.hashCode(); - } - - public String getZipName() { - return zdir.getName(); - } - - public String getZipEntryName() { - return entry.getName(); - } - - public URI toUri() { - String zipName = new File(getZipName()).toURI().normalize().getPath(); - String entryName = getZipEntryName(); - return URI.create("jar:" + zipName + "!" + entryName); - } - - } - - /** - * A subclass of JavaFileObject representing zip entries using the com.sun.tools.javac.zip.ZipFileIndex implementation. - */ - public class ZipFileIndexFileObject extends BaseFileObject { - - /** The entry's name. - */ - private String name; - - /** The zipfile containing the entry. - */ - ZipFileIndex zfIndex; - - /** The underlying zip entry object. - */ - ZipFileIndexEntry entry; - - /** The InputStream for this zip entry (file.) - */ - InputStream inputStream = null; - - /** The name of the zip file where this entry resides. - */ - String zipName; - - JavacFileManager defFileManager = null; - - public ZipFileIndexFileObject(JavacFileManager fileManager, ZipFileIndex zfIndex, ZipFileIndexEntry entry, String zipFileName) { - super(); - this.name = entry.getFileName(); - this.zfIndex = zfIndex; - this.entry = entry; - this.zipName = zipFileName; - defFileManager = fileManager; - } - - public InputStream openInputStream() throws IOException { - - if (inputStream == null) { - inputStream = new ByteArrayInputStream(read()); - } - return inputStream; - } - - protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) { - return JavacFileManager.this.getDecoder(getEncodingName(), ignoreEncodingErrors); - } - - public OutputStream openOutputStream() throws IOException { - throw new UnsupportedOperationException(); - } - - public Writer openWriter() throws IOException { - throw new UnsupportedOperationException(); - } - - /** @deprecated see bug 6410637 */ - @Deprecated - public String getName() { - return name; - } - - 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); - } - - /** @deprecated see bug 6410637 */ - @Deprecated - public String getPath() { - return entry.getName() + "(" + entry + ")"; - } - - public long getLastModified() { - return entry.getLastModified(); - } - - public boolean delete() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof ZipFileIndexFileObject)) - return false; - ZipFileIndexFileObject o = (ZipFileIndexFileObject) other; - return entry.equals(o.entry); - } - - @Override - public int hashCode() { - return zipName.hashCode() + (name.hashCode() << 10); - } - - public String getZipName() { - return zipName; - } - - public String getZipEntryName() { - return entry.getName(); - } - - public URI toUri() { - String zipName = new File(getZipName()).toURI().normalize().getPath(); - String entryName = getZipEntryName(); - if (File.separatorChar != '/') { - entryName = entryName.replace(File.separatorChar, '/'); - } - return URI.create("jar:" + zipName + "!" + entryName); - } - - private byte[] read() throws IOException { - if (entry == null) { - entry = zfIndex.getZipIndexEntry(name); - if (entry == null) - throw new FileNotFoundException(); - } - return zfIndex.read(entry); - } - - public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException { - SoftReference<CharBuffer> r = defFileManager.contentCache.get(this); - CharBuffer cb = (r == null ? null : r.get()); - if (cb == null) { - InputStream in = new ByteArrayInputStream(zfIndex.read(entry)); - try { - ByteBuffer bb = makeByteBuffer(in); - JavaFileObject prev = log.useSource(this); - try { - cb = decode(bb, ignoreEncodingErrors); - } finally { - log.useSource(prev); - } - byteBufferCache.put(bb); // save for next time - if (!ignoreEncodingErrors) - defFileManager.contentCache.put(this, new SoftReference<CharBuffer>(cb)); - } finally { - in.close(); - } - } - return cb; - } - } - - public class ZipFileIndexArchive implements Archive { - private final ZipFileIndex zfIndex; - private JavacFileManager fileManager; - - public ZipFileIndexArchive(JavacFileManager fileManager, ZipFileIndex zdir) throws IOException { - this.fileManager = fileManager; - this.zfIndex = zdir; - } - - public boolean contains(String name) { - return zfIndex.contains(name); - } - - public com.sun.tools.javac.util.List<String> getFiles(String subdirectory) { - return zfIndex.getFiles(((subdirectory.endsWith("/") || subdirectory.endsWith("\\"))? subdirectory.substring(0, subdirectory.length() - 1) : subdirectory)); - } - - public JavaFileObject getFileObject(String subdirectory, String file) { - String fullZipFileName = subdirectory + file; - ZipFileIndexEntry entry = zfIndex.getZipIndexEntry(fullZipFileName); - JavaFileObject ret = new ZipFileIndexFileObject(fileManager, zfIndex, entry, zfIndex.getZipFile().getPath()); - return ret; - } - - public Set<String> getSubdirectories() { - return zfIndex.getAllDirectories(); - } - - public void close() throws IOException { - zfIndex.close(); - } - } -}
--- a/src/share/classes/com/sun/tools/javac/util/Log.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javac/util/Log.java Tue Jun 22 18:30:16 2010 -0700 @@ -33,6 +33,8 @@ import java.util.Set; import javax.tools.DiagnosticListener; import javax.tools.JavaFileObject; +import com.sun.tools.javac.file.BaseFileObject; +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; @@ -233,7 +235,10 @@ return name; } public CharSequence getName() { - return JavacFileManager.getJavacBaseFileName(getFile()); + if (name instanceof BaseFileObject) + return ((BaseFileObject) name).getShortName(); + else + return BaseFileObject.getSimpleName(name); } public int getLineNumber(int pos) { return Log.this.getLineNumber(pos); @@ -522,7 +527,10 @@ return file; } public CharSequence getName() { - return JavacFileManager.getJavacBaseFileName(getFile()); + if (file instanceof BaseFileObject) + return ((BaseFileObject) file).getShortName(); + else + return BaseFileObject.getSimpleName(file); } public int getLineNumber(int pos) { return Log.this.getLineNumber(pos); @@ -660,7 +668,7 @@ JavaFileObject file = currentSource(); if (file != null) printLines(errWriter, - JavacFileManager.getJavacFileName(file) + ":" + + file.getName() + ":" + line + ": " + msg); printErrLine(pos, errWriter); }
--- a/src/share/classes/com/sun/tools/javac/util/Old199.java Mon Jun 21 11:43:28 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2006, 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.util; - -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import javax.tools.*; - -import static javax.tools.StandardLocation.SOURCE_PATH; - -/** - * Provides an easy migration to JSR 199 v3.3. The class is - * deprecated as we should remove it as soon as possible. - * - * <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></p> - * - * @author Peter von der Ah\u00e9 - */ -@Deprecated -public class Old199 { - - private Old199() {} - - public static String getPath(FileObject jfo) { - return JavacFileManager.getJavacFileName(jfo); - } - - public static String getName(FileObject jfo) { - return JavacFileManager.getJavacBaseFileName(jfo); - } - -}
--- a/src/share/classes/com/sun/tools/javac/util/Paths.java Mon Jun 21 11:43:28 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,568 +0,0 @@ -/* - * Copyright (c) 2003, 2006, 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.util; -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.jar.JarFile; -import java.util.jar.Manifest; -import java.util.jar.Attributes; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Iterator; -import java.util.StringTokenizer; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; -import com.sun.tools.javac.code.Lint; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.Log; -import com.sun.tools.javac.util.Options; -import com.sun.tools.javac.util.Position; -import java.util.ArrayList; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import javax.tools.JavaFileManager.Location; - -import static com.sun.tools.javac.main.OptionName.*; -import static javax.tools.StandardLocation.*; - -/** 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 - * 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 Paths { - - /** The context key for the todo list */ - protected static final Context.Key<Paths> pathsKey = - new Context.Key<Paths>(); - - /** Get the Paths instance for this context. */ - public static Paths instance(Context context) { - Paths instance = context.get(pathsKey); - if (instance == null) - instance = new Paths(context); - return instance; - } - - /** 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; - - private static boolean NON_BATCH_MODE = System.getProperty("nonBatchMode") != null;// TODO: Use -XD compiler switch for this. - private static Map<File, PathEntry> pathExistanceCache = new ConcurrentHashMap<File, PathEntry>(); - private static Map<File, java.util.List<File>> manifestEntries = new ConcurrentHashMap<File, java.util.List<File>>(); - private static Map<File, Boolean> isDirectory = new ConcurrentHashMap<File, Boolean>(); - private static Lock lock = new ReentrantLock(); - - public static void clearPathExistanceCache() { - pathExistanceCache.clear(); - } - - static class PathEntry { - boolean exists = false; - boolean isFile = false; - File cannonicalPath = null; - } - - protected Paths(Context context) { - context.put(pathsKey, this); - pathsForLocation = new HashMap<Location,Path>(16); - setContext(context); - } - - void setContext(Context context) { - log = Log.instance(context); - options = Options.instance(context); - lint = Lint.instance(context); - } - - /** Whether to warn about non-existent path elements */ - private boolean warn; - - private Map<Location, Path> pathsForLocation; - - private boolean inited = false; // TODO? caching bad? - - /** - * rt.jar as found on the default bootclass path. If the user specified a - * bootclasspath, null is used. - */ - private File bootClassPathRtJar = null; - - Path getPathForLocation(Location location) { - Path path = pathsForLocation.get(location); - if (path == null) - setPathForLocation(location, null); - return pathsForLocation.get(location); - } - - void setPathForLocation(Location location, Iterable<? extends File> path) { - // TODO? if (inited) throw new IllegalStateException - // TODO: otherwise reset sourceSearchPath, classSearchPath as needed - Path p; - if (path == null) { - if (location == CLASS_PATH) - p = computeUserClassPath(); - else if (location == PLATFORM_CLASS_PATH) - p = computeBootClassPath(); - else if (location == ANNOTATION_PROCESSOR_PATH) - p = computeAnnotationProcessorPath(); - else if (location == SOURCE_PATH) - p = computeSourcePath(); - else - // no defaults for other paths - p = null; - } else { - p = new Path(); - for (File f: path) - p.addFile(f, warn); // TODO: is use of warn appropriate? - } - pathsForLocation.put(location, p); - } - - protected void lazy() { - if (!inited) { - warn = lint.isEnabled(Lint.LintCategory.PATH); - - pathsForLocation.put(PLATFORM_CLASS_PATH, computeBootClassPath()); - pathsForLocation.put(CLASS_PATH, computeUserClassPath()); - pathsForLocation.put(SOURCE_PATH, computeSourcePath()); - - inited = true; - } - } - - public Collection<File> bootClassPath() { - lazy(); - return Collections.unmodifiableCollection(getPathForLocation(PLATFORM_CLASS_PATH)); - } - public Collection<File> userClassPath() { - lazy(); - return Collections.unmodifiableCollection(getPathForLocation(CLASS_PATH)); - } - public Collection<File> sourcePath() { - lazy(); - Path p = getPathForLocation(SOURCE_PATH); - return p == null || p.size() == 0 - ? null - : Collections.unmodifiableCollection(p); - } - - boolean isBootClassPathRtJar(File file) { - return file.equals(bootClassPathRtJar); - } - - /** - * 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.append(new File(path.substring(start, sep))); - else if (emptyPathDefault != null) - entries.append(emptyPathDefault); - start = sep + 1; - } - return entries; - } - - 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) { - if (dirs != null) - for (File dir : getPathEntries(dirs)) - addDirectory(dir, warn); - return this; - } - - public Path addDirectories(String dirs) { - return addDirectories(dirs, warn); - } - - private void addDirectory(File dir, boolean warn) { - if (!dir.isDirectory()) { - if (warn) - log.warning("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) - for (File file : getPathEntries(files, emptyPathDefault)) - addFile(file, warn); - return this; - } - - public Path addFiles(String files) { - return addFiles(files, warn); - } - - public void addFile(File file, boolean warn) { - boolean foundInCache = false; - PathEntry pe = null; - if (!NON_BATCH_MODE) { - pe = pathExistanceCache.get(file); - if (pe != null) { - foundInCache = true; - } - else { - pe = new PathEntry(); - } - } - else { - pe = new PathEntry(); - } - - File canonFile; - try { - if (!foundInCache) { - pe.cannonicalPath = file.getCanonicalFile(); - } - else { - canonFile = pe.cannonicalPath; - } - } catch (IOException e) { - pe.cannonicalPath = canonFile = file; - } - - if (contains(file) || canonicalValues.contains(pe.cannonicalPath)) { - /* Discard duplicates and avoid infinite recursion */ - return; - } - - if (!foundInCache) { - pe.exists = file.exists(); - pe.isFile = file.isFile(); - if (!NON_BATCH_MODE) { - pathExistanceCache.put(file, pe); - } - } - - if (! pe.exists) { - /* No such file or directory exists */ - if (warn) - log.warning("path.element.not.found", file); - } else if (pe.isFile) { - /* 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("unexpected.archive.file", file); - } catch (IOException e) { - // FIXME: include e.getLocalizedMessage in warning - if (warn) - log.warning("invalid.archive.file", file); - return; - } - } - } - - /* Now what we have left is either a directory or a file name - confirming to archive naming convention */ - super.add(file); - canonicalValues.add(pe.cannonicalPath); - - if (expandJarClassPaths && file.exists() && file.isFile()) - 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 { - java.util.List<File> manifestsList = manifestEntries.get(jarFile); - if (!NON_BATCH_MODE) { - lock.lock(); - try { - if (manifestsList != null) { - for (File entr : manifestsList) { - addFile(entr, warn); - } - return; - } - } - finally { - lock.unlock(); - } - } - - if (!NON_BATCH_MODE) { - manifestsList = new ArrayList<File>(); - manifestEntries.put(jarFile, manifestsList); - } - - String jarParent = jarFile.getParent(); - JarFile jar = new JarFile(jarFile); - - try { - Manifest man = jar.getManifest(); - if (man == null) return; - - Attributes attr = man.getMainAttributes(); - if (attr == null) return; - - String path = attr.getValue(Attributes.Name.CLASS_PATH); - if (path == null) return; - - for (StringTokenizer st = new StringTokenizer(path); - st.hasMoreTokens();) { - String elt = st.nextToken(); - File f = (jarParent == null ? new File(elt) : new File(jarParent, elt)); - addFile(f, warn); - - if (!NON_BATCH_MODE) { - lock.lock(); - try { - manifestsList.add(f); - } - finally { - lock.unlock(); - } - } - } - } finally { - jar.close(); - } - } catch (IOException e) { - log.error("error.reading.file", jarFile, e.getLocalizedMessage()); - } - } - } - - private Path computeBootClassPath() { - bootClassPathRtJar = null; - String optionValue; - Path path = new Path(); - - path.addFiles(options.get(XBOOTCLASSPATH_PREPEND)); - - if ((optionValue = options.get(ENDORSEDDIRS)) != null) - path.addDirectories(optionValue); - else - path.addDirectories(System.getProperty("java.endorsed.dirs"), false); - - if ((optionValue = options.get(BOOTCLASSPATH)) != null) { - path.addFiles(optionValue); - } 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)) - bootClassPathRtJar = file; - } - } - - path.addFiles(options.get(XBOOTCLASSPATH_APPEND)); - - // Strictly speaking, standard extensions are not bootstrap - // classes, but we treat them identically, so we'll pretend - // that they are. - if ((optionValue = options.get(EXTDIRS)) != null) - path.addDirectories(optionValue); - else - path.addDirectories(System.getProperty("java.ext.dirs"), false); - - return path; - } - - private Path computeUserClassPath() { - String cp = options.get(CLASSPATH); - - // 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 new Path() - .expandJarClassPaths(true) // Only search user jars for Class-Paths - .emptyPathDefault(new File(".")) // Empty path elt ==> current directory - .addFiles(cp); - } - - private Path computeSourcePath() { - String sourcePathArg = options.get(SOURCEPATH); - if (sourcePathArg == null) - return null; - - return new Path().addFiles(sourcePathArg); - } - - private Path computeAnnotationProcessorPath() { - String processorPathArg = options.get(PROCESSORPATH); - if (processorPathArg == null) - return null; - - return new Path().addFiles(processorPathArg); - } - - /** The actual effective locations searched for sources */ - private Path sourceSearchPath; - - public Collection<File> sourceSearchPath() { - if (sourceSearchPath == null) { - lazy(); - Path sourcePath = getPathForLocation(SOURCE_PATH); - Path userClassPath = getPathForLocation(CLASS_PATH); - sourceSearchPath = sourcePath != null ? sourcePath : userClassPath; - } - return Collections.unmodifiableCollection(sourceSearchPath); - } - - /** The actual effective locations searched for classes */ - private Path classSearchPath; - - public Collection<File> classSearchPath() { - if (classSearchPath == null) { - lazy(); - Path bootClassPath = getPathForLocation(PLATFORM_CLASS_PATH); - Path userClassPath = getPathForLocation(CLASS_PATH); - classSearchPath = new Path(); - classSearchPath.addAll(bootClassPath); - classSearchPath.addAll(userClassPath); - } - return Collections.unmodifiableCollection(classSearchPath); - } - - /** The actual effective locations for non-source, non-class files */ - private Path otherSearchPath; - - Collection<File> otherSearchPath() { - if (otherSearchPath == null) { - lazy(); - Path userClassPath = getPathForLocation(CLASS_PATH); - Path sourcePath = getPathForLocation(SOURCE_PATH); - if (sourcePath == null) - otherSearchPath = userClassPath; - else { - otherSearchPath = new Path(); - otherSearchPath.addAll(userClassPath); - otherSearchPath.addAll(sourcePath); - } - } - return Collections.unmodifiableCollection(otherSearchPath); - } - - /** Is this the name of an archive file? */ - private static boolean isArchive(File file) { - String n = file.getName().toLowerCase(); - boolean isFile = false; - if (!NON_BATCH_MODE) { - Boolean isf = isDirectory.get(file); - if (isf == null) { - isFile = file.isFile(); - isDirectory.put(file, isFile); - } - else { - isFile = isf; - } - } - else { - isFile = file.isFile(); - } - - return isFile - && (n.endsWith(".jar") || n.endsWith(".zip")); - } -}
--- a/src/share/classes/com/sun/tools/javac/zip/ZipFileIndex.java Mon Jun 21 11:43:28 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1236 +0,0 @@ -/* - * Copyright (c) 2007, 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.zip; - -import java.io.*; -import java.text.MessageFormat; -import java.util.*; -import java.util.List; -import java.util.concurrent.locks.ReentrantLock; -import java.util.zip.*; - -/** This class implements building of index of a zip archive and access to it's context. - * It also uses prebuild index if available. It supports invocations where it will - * serialize an optimized zip index file to disk. - * - * In oreder to use secondary index file make sure the option "usezipindex" is in the Options object, - * when JavacFileManager is invoked. (You can pass "-XDusezipindex" on the command line. - * - * Location where to look for/generate optimized zip index files can be provided using - * "-XDcachezipindexdir=<directory>". If this flag is not provided, the dfault location is - * the value of the "java.io.tmpdir" system property. - * - * If key "-XDwritezipindexfiles" is specified, there will be new optimized index file - * created for each archive, used by the compiler for compilation, at location, - * specified by "cachezipindexdir" option. - * - * If nonBatchMode option is specified (-XDnonBatchMode) the compiler will use timestamp - * checking to reindex the zip files if it is needed. In batch mode the timestamps are not checked - * and the compiler uses the cached indexes. - */ -public class ZipFileIndex { - private static final String MIN_CHAR = String.valueOf(Character.MIN_VALUE); - private static final String MAX_CHAR = String.valueOf(Character.MAX_VALUE); - - public final static long NOT_MODIFIED = Long.MIN_VALUE; - - private static Map<File, ZipFileIndex> zipFileIndexCache = new HashMap<File, ZipFileIndex>(); - private static ReentrantLock lock = new ReentrantLock(); - - private static boolean NON_BATCH_MODE = System.getProperty("nonBatchMode") != null;// TODO: Use -XD compiler switch for this. - - private Map<String, DirectoryEntry> directories = Collections.<String, DirectoryEntry>emptyMap(); - private Set<String> allDirs = Collections.<String>emptySet(); - - // ZipFileIndex data entries - private File zipFile; - private long zipFileLastModified = NOT_MODIFIED; - private RandomAccessFile zipRandomFile; - private ZipFileIndexEntry[] entries; - - private boolean readFromIndex = false; - private File zipIndexFile = null; - private boolean triedToReadIndex = false; - private int symbolFilePrefixLength = 0; - private boolean hasPopulatedData = false; - private long lastReferenceTimeStamp = NOT_MODIFIED; - - private boolean usePreindexedCache = false; - private String preindexedCacheLocation = null; - - private boolean writeIndex = false; - - /** - * Returns a list of all ZipFileIndex entries - * - * @return A list of ZipFileIndex entries, or an empty list - */ - public static 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 static List<ZipFileIndex> getZipFileIndexes(boolean openedOnly) { - List<ZipFileIndex> zipFileIndexes = new ArrayList<ZipFileIndex>(); - lock.lock(); - try { - zipFileIndexes.addAll(zipFileIndexCache.values()); - - if (openedOnly) { - for(ZipFileIndex elem : zipFileIndexes) { - if (!elem.isOpen()) { - zipFileIndexes.remove(elem); - } - } - } - } - finally { - lock.unlock(); - } - return zipFileIndexes; - } - - public boolean isOpen() { - lock.lock(); - try { - return zipRandomFile != null; - } - finally { - lock.unlock(); - } - } - - public static ZipFileIndex getZipFileIndex(File zipFile, int symbolFilePrefixLen, boolean useCache, String cacheLocation, boolean writeIndex) throws IOException { - ZipFileIndex zi = null; - lock.lock(); - try { - zi = getExistingZipIndex(zipFile); - - if (zi == null || (zi != null && zipFile.lastModified() != zi.zipFileLastModified)) { - zi = new ZipFileIndex(zipFile, symbolFilePrefixLen, writeIndex, - useCache, cacheLocation); - zipFileIndexCache.put(zipFile, zi); - } - } - finally { - lock.unlock(); - } - return zi; - } - - public static ZipFileIndex getExistingZipIndex(File zipFile) { - lock.lock(); - try { - return zipFileIndexCache.get(zipFile); - } - finally { - lock.unlock(); - } - } - - public static void clearCache() { - lock.lock(); - try { - zipFileIndexCache.clear(); - } - finally { - lock.unlock(); - } - } - - public static void clearCache(long timeNotUsed) { - lock.lock(); - try { - Iterator<File> cachedFileIterator = zipFileIndexCache.keySet().iterator(); - while (cachedFileIterator.hasNext()) { - File cachedFile = cachedFileIterator.next(); - ZipFileIndex cachedZipIndex = zipFileIndexCache.get(cachedFile); - if (cachedZipIndex != null) { - long timeToTest = cachedZipIndex.lastReferenceTimeStamp + timeNotUsed; - if (timeToTest < cachedZipIndex.lastReferenceTimeStamp || // Overflow... - System.currentTimeMillis() > timeToTest) { - zipFileIndexCache.remove(cachedFile); - } - } - } - } - finally { - lock.unlock(); - } - } - - public static void removeFromCache(File file) { - lock.lock(); - try { - zipFileIndexCache.remove(file); - } - finally { - lock.unlock(); - } - } - - /** 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 static void setOpenedIndexes(List<ZipFileIndex>indexes) throws IllegalStateException { - lock.lock(); - try { - if (zipFileIndexCache.isEmpty()) { - throw new IllegalStateException("Setting opened indexes should be called only when the ZipFileCache is empty. Call JavacFileManager.flush() before calling this method."); - } - - for (ZipFileIndex zfi : indexes) { - zipFileIndexCache.put(zfi.zipFile, zfi); - } - } - finally { - lock.unlock(); - } - } - - private ZipFileIndex(File zipFile, int symbolFilePrefixLen, boolean writeIndex, - boolean useCache, String cacheLocation) throws IOException { - this.zipFile = zipFile; - this.symbolFilePrefixLength = symbolFilePrefixLen; - this.writeIndex = writeIndex; - this.usePreindexedCache = useCache; - this.preindexedCacheLocation = cacheLocation; - - if (zipFile != null) { - this.zipFileLastModified = zipFile.lastModified(); - } - - // Validate integrity of the zip file - checkIndex(); - } - - public String toString() { - return "ZipFileIndex of file:(" + zipFile + ")"; - } - - // Just in case... - protected void finalize() { - closeFile(); - } - - private boolean isUpToDate() { - if (zipFile != null && - ((!NON_BATCH_MODE) || zipFileLastModified == zipFile.lastModified()) && - hasPopulatedData) { - return true; - } - - return false; - } - - /** - * Here we need to make sure that the ZipFileIndex is valid. Check the timestamp of the file and - * if its the same as the one at the time the index was build we don't need to reopen anything. - */ - private void checkIndex() throws IOException { - boolean isUpToDate = true; - if (!isUpToDate()) { - closeFile(); - isUpToDate = false; - } - - if (zipRandomFile != null || isUpToDate) { - lastReferenceTimeStamp = System.currentTimeMillis(); - return; - } - - hasPopulatedData = true; - - if (readIndex()) { - lastReferenceTimeStamp = System.currentTimeMillis(); - return; - } - - directories = Collections.<String, DirectoryEntry>emptyMap(); - allDirs = Collections.<String>emptySet(); - - try { - openFile(); - long totalLength = zipRandomFile.length(); - ZipDirectory directory = new ZipDirectory(zipRandomFile, 0L, totalLength, this); - directory.buildIndex(); - } finally { - if (zipRandomFile != null) { - closeFile(); - } - } - - lastReferenceTimeStamp = System.currentTimeMillis(); - } - - private void openFile() throws FileNotFoundException { - if (zipRandomFile == null && zipFile != null) { - zipRandomFile = new RandomAccessFile(zipFile, "r"); - } - } - - private void cleanupState() { - // Make sure there is a valid but empty index if the file doesn't exist - entries = ZipFileIndexEntry.EMPTY_ARRAY; - directories = Collections.<String, DirectoryEntry>emptyMap(); - zipFileLastModified = NOT_MODIFIED; - allDirs = Collections.<String>emptySet(); - } - - public void close() { - lock.lock(); - try { - writeIndex(); - closeFile(); - } - finally { - lock.unlock(); - } - } - - private void closeFile() { - if (zipRandomFile != null) { - try { - zipRandomFile.close(); - } catch (IOException ex) { - } - zipRandomFile = null; - } - } - - /** - * Returns the ZipFileIndexEntry for an absolute path, if there is one. - */ - public ZipFileIndexEntry getZipIndexEntry(String path) { - if (File.separatorChar != '/') { - path = path.replace('/', File.separatorChar); - } - lock.lock(); - try { - checkIndex(); - String lookFor = ""; - int lastSepIndex = path.lastIndexOf(File.separatorChar); - boolean noSeparator = false; - if (lastSepIndex == -1) { - noSeparator = true; - } - - DirectoryEntry de = directories.get(noSeparator ? "" : path.substring(0, lastSepIndex)); - - lookFor = path.substring(noSeparator ? 0 : lastSepIndex + 1); - - return de == null ? null : de.getEntry(lookFor); - } - catch (IOException e) { - return null; - } - finally { - lock.unlock(); - } - } - - /** - * Returns a javac List of filenames within an absolute path in the ZipFileIndex. - */ - public com.sun.tools.javac.util.List<String> getFiles(String path) { - if (File.separatorChar != '/') { - path = path.replace('/', File.separatorChar); - } - - lock.lock(); - try { - checkIndex(); - - DirectoryEntry de = directories.get(path); - com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getFiles(); - - if (ret == null) { - return com.sun.tools.javac.util.List.<String>nil(); - } - return ret; - } - catch (IOException e) { - return com.sun.tools.javac.util.List.<String>nil(); - } - finally { - lock.unlock(); - } - } - - public List<String> getAllDirectories(String path) { - - if (File.separatorChar != '/') { - path = path.replace('/', File.separatorChar); - } - - lock.lock(); - try { - checkIndex(); - path = path.intern(); - - DirectoryEntry de = directories.get(path); - com.sun.tools.javac.util.List<String> ret = de == null ? null : de.getDirectories(); - - if (ret == null) { - return com.sun.tools.javac.util.List.<String>nil(); - } - - return ret; - } - catch (IOException e) { - return com.sun.tools.javac.util.List.<String>nil(); - } - finally { - lock.unlock(); - } - } - - public Set<String> getAllDirectories() { - lock.lock(); - try { - checkIndex(); - if (allDirs == Collections.EMPTY_SET) { - Set<String> alldirs = new HashSet<String>(); - Iterator<String> dirsIter = directories.keySet().iterator(); - while (dirsIter.hasNext()) { - alldirs.add(new String(dirsIter.next())); - } - - allDirs = alldirs; - } - - return allDirs; - } - catch (IOException e) { - return Collections.<String>emptySet(); - } - finally { - lock.unlock(); - } - } - - /** - * Tests if a specific path exists in the zip. This method will return true - * for file entries and directories. - * - * @param path A path within the zip. - * @return True if the path is a file or dir, false otherwise. - */ - public boolean contains(String path) { - lock.lock(); - try { - checkIndex(); - return getZipIndexEntry(path) != null; - } - catch (IOException e) { - return false; - } - finally { - lock.unlock(); - } - } - - public boolean isDirectory(String path) throws IOException { - lock.lock(); - try { - // The top level in a zip file is always a directory. - if (path.length() == 0) { - lastReferenceTimeStamp = System.currentTimeMillis(); - return true; - } - - if (File.separatorChar != '/') - path = path.replace('/', File.separatorChar); - checkIndex(); - return directories.get(path) != null; - } - finally { - lock.unlock(); - } - } - - public long getLastModified(String path) throws IOException { - lock.lock(); - try { - ZipFileIndexEntry entry = getZipIndexEntry(path); - if (entry == null) - throw new FileNotFoundException(); - return entry.getLastModified(); - } - finally { - lock.unlock(); - } - } - - public int length(String path) throws IOException { - lock.lock(); - try { - ZipFileIndexEntry entry = getZipIndexEntry(path); - if (entry == null) - throw new FileNotFoundException(); - - if (entry.isDir) { - return 0; - } - - byte[] header = getHeader(entry); - // entry is not compressed? - if (get2ByteLittleEndian(header, 8) == 0) { - return entry.compressedSize; - } else { - return entry.size; - } - } - finally { - lock.unlock(); - } - } - - public byte[] read(String path) throws IOException { - lock.lock(); - try { - ZipFileIndexEntry entry = getZipIndexEntry(path); - if (entry == null) - throw new FileNotFoundException(MessageFormat.format("Path not found in ZIP: {0}", path)); - return read(entry); - } - finally { - lock.unlock(); - } - } - - public byte[] read(ZipFileIndexEntry entry) throws IOException { - lock.lock(); - try { - openFile(); - byte[] result = readBytes(entry); - closeFile(); - return result; - } - finally { - lock.unlock(); - } - } - - public int read(String path, byte[] buffer) throws IOException { - lock.lock(); - try { - ZipFileIndexEntry entry = getZipIndexEntry(path); - if (entry == null) - throw new FileNotFoundException(); - return read(entry, buffer); - } - finally { - lock.unlock(); - } - } - - public int read(ZipFileIndexEntry entry, byte[] buffer) - throws IOException { - lock.lock(); - try { - int result = readBytes(entry, buffer); - return result; - } - finally { - lock.unlock(); - } - } - - private byte[] readBytes(ZipFileIndexEntry entry) throws IOException { - byte[] header = getHeader(entry); - int csize = entry.compressedSize; - byte[] cbuf = new byte[csize]; - zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28)); - zipRandomFile.readFully(cbuf, 0, csize); - - // is this compressed - offset 8 in the ZipEntry header - if (get2ByteLittleEndian(header, 8) == 0) - return cbuf; - - int size = entry.size; - byte[] buf = new byte[size]; - if (inflate(cbuf, buf) != size) - throw new ZipException("corrupted zip file"); - - return buf; - } - - /** - * - */ - private int readBytes(ZipFileIndexEntry entry, byte[] buffer) throws IOException { - byte[] header = getHeader(entry); - - // entry is not compressed? - if (get2ByteLittleEndian(header, 8) == 0) { - zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28)); - int offset = 0; - int size = buffer.length; - while (offset < size) { - int count = zipRandomFile.read(buffer, offset, size - offset); - if (count == -1) - break; - offset += count; - } - return entry.size; - } - - int csize = entry.compressedSize; - byte[] cbuf = new byte[csize]; - zipRandomFile.skipBytes(get2ByteLittleEndian(header, 26) + get2ByteLittleEndian(header, 28)); - zipRandomFile.readFully(cbuf, 0, csize); - - int count = inflate(cbuf, buffer); - if (count == -1) - throw new ZipException("corrupted zip file"); - - return entry.size; - } - - //---------------------------------------------------------------------------- - // Zip utilities - //---------------------------------------------------------------------------- - - private byte[] getHeader(ZipFileIndexEntry entry) throws IOException { - zipRandomFile.seek(entry.offset); - byte[] header = new byte[30]; - zipRandomFile.readFully(header); - if (get4ByteLittleEndian(header, 0) != 0x04034b50) - throw new ZipException("corrupted zip file"); - if ((get2ByteLittleEndian(header, 6) & 1) != 0) - throw new ZipException("encrypted zip file"); // offset 6 in the header of the ZipFileEntry - return header; - } - - /* - * Inflate using the java.util.zip.Inflater class - */ - private static Inflater inflater; - private int inflate(byte[] src, byte[] dest) { - - // construct the inflater object or reuse an existing one - if (inflater == null) - inflater = new Inflater(true); - - synchronized (inflater) { - inflater.reset(); - inflater.setInput(src); - try { - return inflater.inflate(dest); - } catch (DataFormatException ex) { - return -1; - } - } - } - - /** - * return the two bytes buf[pos], buf[pos+1] as an unsigned integer in little - * endian format. - */ - private static int get2ByteLittleEndian(byte[] buf, int pos) { - return (buf[pos] & 0xFF) + ((buf[pos+1] & 0xFF) << 8); - } - - /** - * return the 4 bytes buf[i..i+3] as an integer in little endian format. - */ - private static int get4ByteLittleEndian(byte[] buf, int pos) { - return (buf[pos] & 0xFF) + ((buf[pos + 1] & 0xFF) << 8) + - ((buf[pos + 2] & 0xFF) << 16) + ((buf[pos + 3] & 0xFF) << 24); - } - - /* ---------------------------------------------------------------------------- - * ZipDirectory - * ----------------------------------------------------------------------------*/ - - private class ZipDirectory { - private String lastDir; - private int lastStart; - private int lastLen; - - byte[] zipDir; - RandomAccessFile zipRandomFile = null; - ZipFileIndex zipFileIndex = null; - - public ZipDirectory(RandomAccessFile zipRandomFile, long start, long end, ZipFileIndex index) throws IOException { - this.zipRandomFile = zipRandomFile; - this.zipFileIndex = index; - - findCENRecord(start, end); - } - - /* - * Reads zip file central directory. - * For more details see readCEN in zip_util.c from the JDK sources. - * This is a Java port of that function. - */ - private void findCENRecord(long start, long end) throws IOException { - long totalLength = end - start; - int endbuflen = 1024; - byte[] endbuf = new byte[endbuflen]; - long endbufend = end - start; - - // There is a variable-length field after the dir offset record. We need to do consequential search. - while (endbufend >= 22) { - if (endbufend < endbuflen) - endbuflen = (int)endbufend; - long endbufpos = endbufend - endbuflen; - zipRandomFile.seek(start + endbufpos); - zipRandomFile.readFully(endbuf, 0, endbuflen); - int i = endbuflen - 22; - while (i >= 0 && - !(endbuf[i] == 0x50 && - endbuf[i + 1] == 0x4b && - endbuf[i + 2] == 0x05 && - endbuf[i + 3] == 0x06 && - endbufpos + i + 22 + - get2ByteLittleEndian(endbuf, i + 20) == totalLength)) { - i--; - } - - if (i >= 0) { - zipDir = new byte[get4ByteLittleEndian(endbuf, i + 12) + 2]; - zipDir[0] = endbuf[i + 10]; - zipDir[1] = endbuf[i + 11]; - zipRandomFile.seek(start + get4ByteLittleEndian(endbuf, i + 16)); - zipRandomFile.readFully(zipDir, 2, zipDir.length - 2); - return; - } else { - endbufend = endbufpos + 21; - } - } - throw new ZipException("cannot read zip file"); - } - private void buildIndex() throws IOException { - int entryCount = get2ByteLittleEndian(zipDir, 0); - - entries = new ZipFileIndexEntry[entryCount]; - // Add each of the files - if (entryCount > 0) { - directories = new HashMap<String, DirectoryEntry>(); - ArrayList<ZipFileIndexEntry> entryList = new ArrayList<ZipFileIndexEntry>(); - int pos = 2; - for (int i = 0; i < entryCount; i++) { - pos = readEntry(pos, entryList, directories); - } - - // Add the accumulated dirs into the same list - Iterator i = directories.keySet().iterator(); - while (i.hasNext()) { - ZipFileIndexEntry zipFileIndexEntry = new ZipFileIndexEntry( (String) i.next()); - zipFileIndexEntry.isDir = true; - entryList.add(zipFileIndexEntry); - } - - entries = entryList.toArray(new ZipFileIndexEntry[entryList.size()]); - Arrays.sort(entries); - } else { - cleanupState(); - } - } - - private int readEntry(int pos, List<ZipFileIndexEntry> entryList, - Map<String, DirectoryEntry> directories) throws IOException { - if (get4ByteLittleEndian(zipDir, pos) != 0x02014b50) { - throw new ZipException("cannot read zip file entry"); - } - - int dirStart = pos + 46; - int fileStart = dirStart; - int fileEnd = fileStart + get2ByteLittleEndian(zipDir, pos + 28); - - if (zipFileIndex.symbolFilePrefixLength != 0 && - ((fileEnd - fileStart) >= symbolFilePrefixLength)) { - dirStart += zipFileIndex.symbolFilePrefixLength; - fileStart += zipFileIndex.symbolFilePrefixLength; - } - - // Use the OS's path separator. Keep the position of the last one. - for (int index = fileStart; index < fileEnd; index++) { - byte nextByte = zipDir[index]; - if (nextByte == (byte)'\\' || nextByte == (byte)'/') { - zipDir[index] = (byte)File.separatorChar; - fileStart = index + 1; - } - } - - String directory = null; - if (fileStart == dirStart) - directory = ""; - else if (lastDir != null && lastLen == fileStart - dirStart - 1) { - int index = lastLen - 1; - while (zipDir[lastStart + index] == zipDir[dirStart + index]) { - if (index == 0) { - directory = lastDir; - break; - } - index--; - } - } - - // Sub directories - if (directory == null) { - lastStart = dirStart; - lastLen = fileStart - dirStart - 1; - - directory = new String(zipDir, dirStart, lastLen, "UTF-8").intern(); - lastDir = directory; - - // Enter also all the parent directories - String tempDirectory = directory; - - while (directories.get(tempDirectory) == null) { - directories.put(tempDirectory, new DirectoryEntry(tempDirectory, zipFileIndex)); - int separator = tempDirectory.lastIndexOf(File.separatorChar); - if (separator == -1) - break; - tempDirectory = tempDirectory.substring(0, separator); - } - } - else { - directory = directory.intern(); - if (directories.get(directory) == null) { - directories.put(directory, new DirectoryEntry(directory, zipFileIndex)); - } - } - - // For each dir create also a file - if (fileStart != fileEnd) { - ZipFileIndexEntry entry = new ZipFileIndexEntry(directory, - new String(zipDir, fileStart, fileEnd - fileStart, "UTF-8")); - - entry.setNativeTime(get4ByteLittleEndian(zipDir, pos + 12)); - entry.compressedSize = get4ByteLittleEndian(zipDir, pos + 20); - entry.size = get4ByteLittleEndian(zipDir, pos + 24); - entry.offset = get4ByteLittleEndian(zipDir, pos + 42); - entryList.add(entry); - } - - return pos + 46 + - get2ByteLittleEndian(zipDir, pos + 28) + - get2ByteLittleEndian(zipDir, pos + 30) + - get2ByteLittleEndian(zipDir, pos + 32); - } - } - - /** - * Returns the last modified timestamp of a zip file. - * @return long - */ - public long getZipFileLastModified() throws IOException { - lock.lock(); - try { - checkIndex(); - return zipFileLastModified; - } - finally { - lock.unlock(); - } - } - - /** ------------------------------------------------------------------------ - * DirectoryEntry class - * -------------------------------------------------------------------------*/ - static class DirectoryEntry { - private boolean filesInited; - private boolean directoriesInited; - private boolean zipFileEntriesInited; - private boolean entriesInited; - - private long writtenOffsetOffset = 0; - - private String dirName; - - private com.sun.tools.javac.util.List<String> zipFileEntriesFiles = com.sun.tools.javac.util.List.<String>nil(); - private com.sun.tools.javac.util.List<String> zipFileEntriesDirectories = com.sun.tools.javac.util.List.<String>nil(); - private com.sun.tools.javac.util.List<ZipFileIndexEntry> zipFileEntries = com.sun.tools.javac.util.List.<ZipFileIndexEntry>nil(); - - private List<ZipFileIndexEntry> entries = new ArrayList<ZipFileIndexEntry>(); - - private ZipFileIndex zipFileIndex; - - private int numEntries; - - DirectoryEntry(String dirName, ZipFileIndex index) { - filesInited = false; - directoriesInited = false; - entriesInited = false; - - if (File.separatorChar == '/') { - dirName.replace('\\', '/'); - } - else { - dirName.replace('/', '\\'); - } - - this.dirName = dirName.intern(); - this.zipFileIndex = index; - } - - private com.sun.tools.javac.util.List<String> getFiles() { - if (filesInited) { - return zipFileEntriesFiles; - } - - initEntries(); - - for (ZipFileIndexEntry e : entries) { - if (!e.isDir) { - zipFileEntriesFiles = zipFileEntriesFiles.append(e.name); - } - } - filesInited = true; - return zipFileEntriesFiles; - } - - private com.sun.tools.javac.util.List<String> getDirectories() { - if (directoriesInited) { - return zipFileEntriesFiles; - } - - initEntries(); - - for (ZipFileIndexEntry e : entries) { - if (e.isDir) { - zipFileEntriesDirectories = zipFileEntriesDirectories.append(e.name); - } - } - - directoriesInited = true; - - return zipFileEntriesDirectories; - } - - private com.sun.tools.javac.util.List<ZipFileIndexEntry> getEntries() { - if (zipFileEntriesInited) { - return zipFileEntries; - } - - initEntries(); - - zipFileEntries = com.sun.tools.javac.util.List.nil(); - for (ZipFileIndexEntry zfie : entries) { - zipFileEntries = zipFileEntries.append(zfie); - } - - zipFileEntriesInited = true; - - return zipFileEntries; - } - - private ZipFileIndexEntry getEntry(String rootName) { - initEntries(); - int index = Collections.binarySearch(entries, new ZipFileIndexEntry(dirName, rootName)); - if (index < 0) { - return null; - } - - return entries.get(index); - } - - private void initEntries() { - if (entriesInited) { - return; - } - - if (!zipFileIndex.readFromIndex) { - int from = -Arrays.binarySearch(zipFileIndex.entries, - new ZipFileIndexEntry(dirName, ZipFileIndex.MIN_CHAR)) - 1; - int to = -Arrays.binarySearch(zipFileIndex.entries, - new ZipFileIndexEntry(dirName, MAX_CHAR)) - 1; - - boolean emptyList = false; - - for (int i = from; i < to; i++) { - entries.add(zipFileIndex.entries[i]); - } - } else { - File indexFile = zipFileIndex.getIndexFile(); - if (indexFile != null) { - RandomAccessFile raf = null; - try { - raf = new RandomAccessFile(indexFile, "r"); - raf.seek(writtenOffsetOffset); - - for (int nFiles = 0; nFiles < numEntries; nFiles++) { - // Read the name bytes - int zfieNameBytesLen = raf.readInt(); - byte [] zfieNameBytes = new byte[zfieNameBytesLen]; - raf.read(zfieNameBytes); - String eName = new String(zfieNameBytes, "UTF-8"); - - // Read isDir - boolean eIsDir = raf.readByte() == (byte)0 ? false : true; - - // Read offset of bytes in the real Jar/Zip file - int eOffset = raf.readInt(); - - // Read size of the file in the real Jar/Zip file - int eSize = raf.readInt(); - - // Read compressed size of the file in the real Jar/Zip file - int eCsize = raf.readInt(); - - // Read java time stamp of the file in the real Jar/Zip file - long eJavaTimestamp = raf.readLong(); - - ZipFileIndexEntry rfie = new ZipFileIndexEntry(dirName, eName); - rfie.isDir = eIsDir; - rfie.offset = eOffset; - rfie.size = eSize; - rfie.compressedSize = eCsize; - rfie.javatime = eJavaTimestamp; - entries.add(rfie); - } - } catch (Throwable t) { - // Do nothing - } finally { - try { - if (raf == null) { - raf.close(); - } - } catch (Throwable t) { - // Do nothing - } - } - } - } - - entriesInited = true; - } - - List<ZipFileIndexEntry> getEntriesAsCollection() { - initEntries(); - - return entries; - } - } - - private boolean readIndex() { - if (triedToReadIndex || !usePreindexedCache) { - return false; - } - - boolean ret = false; - lock.lock(); - try { - triedToReadIndex = true; - RandomAccessFile raf = null; - try { - File indexFileName = getIndexFile(); - raf = new RandomAccessFile(indexFileName, "r"); - - long fileStamp = raf.readLong(); - if (zipFile.lastModified() != fileStamp) { - ret = false; - } else { - directories = new HashMap<String, DirectoryEntry>(); - int numDirs = raf.readInt(); - for (int nDirs = 0; nDirs < numDirs; nDirs++) { - int dirNameBytesLen = raf.readInt(); - byte [] dirNameBytes = new byte[dirNameBytesLen]; - raf.read(dirNameBytes); - - String dirNameStr = new String(dirNameBytes, "UTF-8"); - DirectoryEntry de = new DirectoryEntry(dirNameStr, this); - de.numEntries = raf.readInt(); - de.writtenOffsetOffset = raf.readLong(); - directories.put(dirNameStr, de); - } - ret = true; - zipFileLastModified = fileStamp; - } - } catch (Throwable t) { - // Do nothing - } finally { - if (raf != null) { - try { - raf.close(); - } catch (Throwable tt) { - // Do nothing - } - } - } - if (ret == true) { - readFromIndex = true; - } - } - finally { - lock.unlock(); - } - - return ret; - } - - private boolean writeIndex() { - boolean ret = false; - if (readFromIndex || !usePreindexedCache) { - return true; - } - - if (!writeIndex) { - return true; - } - - File indexFile = getIndexFile(); - if (indexFile == null) { - return false; - } - - RandomAccessFile raf = null; - long writtenSoFar = 0; - try { - raf = new RandomAccessFile(indexFile, "rw"); - - raf.writeLong(zipFileLastModified); - writtenSoFar += 8; - - - Iterator<String> iterDirName = directories.keySet().iterator(); - List<DirectoryEntry> directoriesToWrite = new ArrayList<DirectoryEntry>(); - Map<String, Long> offsets = new HashMap<String, Long>(); - raf.writeInt(directories.keySet().size()); - writtenSoFar += 4; - - while(iterDirName.hasNext()) { - String dirName = iterDirName.next(); - DirectoryEntry dirEntry = directories.get(dirName); - - directoriesToWrite.add(dirEntry); - - // Write the dir name bytes - byte [] dirNameBytes = dirName.getBytes("UTF-8"); - int dirNameBytesLen = dirNameBytes.length; - raf.writeInt(dirNameBytesLen); - writtenSoFar += 4; - - raf.write(dirNameBytes); - writtenSoFar += dirNameBytesLen; - - // Write the number of files in the dir - List dirEntries = dirEntry.getEntriesAsCollection(); - raf.writeInt(dirEntries.size()); - writtenSoFar += 4; - - offsets.put(dirName, new Long(writtenSoFar)); - - // Write the offset of the file's data in the dir - dirEntry.writtenOffsetOffset = 0L; - raf.writeLong(0L); - writtenSoFar += 8; - } - - for (DirectoryEntry de : directoriesToWrite) { - // Fix up the offset in the directory table - long currFP = raf.getFilePointer(); - - long offsetOffset = offsets.get(de.dirName).longValue(); - raf.seek(offsetOffset); - raf.writeLong(writtenSoFar); - - raf.seek(currFP); - - // Now write each of the files in the DirectoryEntry - List<ZipFileIndexEntry> entries = de.getEntriesAsCollection(); - for (ZipFileIndexEntry zfie : entries) { - // Write the name bytes - byte [] zfieNameBytes = zfie.name.getBytes("UTF-8"); - int zfieNameBytesLen = zfieNameBytes.length; - raf.writeInt(zfieNameBytesLen); - writtenSoFar += 4; - raf.write(zfieNameBytes); - writtenSoFar += zfieNameBytesLen; - - // Write isDir - raf.writeByte(zfie.isDir ? (byte)1 : (byte)0); - writtenSoFar += 1; - - // Write offset of bytes in the real Jar/Zip file - raf.writeInt(zfie.offset); - writtenSoFar += 4; - - // Write size of the file in the real Jar/Zip file - raf.writeInt(zfie.size); - writtenSoFar += 4; - - // Write compressed size of the file in the real Jar/Zip file - raf.writeInt(zfie.compressedSize); - writtenSoFar += 4; - - // Write java time stamp of the file in the real Jar/Zip file - raf.writeLong(zfie.getLastModified()); - writtenSoFar += 8; - } - } - } catch (Throwable t) { - // Do nothing - } finally { - try { - if (raf != null) { - raf.close(); - } - } catch(IOException ioe) { - // Do nothing - } - } - - return ret; - } - - public boolean writeZipIndex() { - lock.lock(); - try { - return writeIndex(); - } - finally { - lock.unlock(); - } - } - - private File getIndexFile() { - if (zipIndexFile == null) { - if (zipFile == null) { - return null; - } - - zipIndexFile = new File((preindexedCacheLocation == null ? "" : preindexedCacheLocation) + - zipFile.getName() + ".index"); - } - - return zipIndexFile; - } - - public File getZipFile() { - return zipFile; - } -}
--- a/src/share/classes/com/sun/tools/javac/zip/ZipFileIndexEntry.java Mon Jun 21 11:43:28 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2007, 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.zip; - -import java.io.File; -import java.util.Calendar; - -public final class ZipFileIndexEntry implements Comparable<ZipFileIndexEntry> { - public static final ZipFileIndexEntry[] EMPTY_ARRAY = {}; - - // Directory related - String dir; - boolean isDir; - - // File related - String name; - - int offset; - int size; - int compressedSize; - long javatime; - - private int nativetime; - - public ZipFileIndexEntry(String path) { - int separator = path.lastIndexOf(File.separatorChar); - if (separator == -1) { - dir = "".intern(); - name = path; - } else { - dir = path.substring(0, separator).intern(); - name = path.substring(separator + 1); - } - } - - public ZipFileIndexEntry(String directory, String name) { - this.dir = directory.intern(); - this.name = name; - } - - public String getName() { - if (dir == null || dir.length() == 0) { - return name; - } - - StringBuilder sb = new StringBuilder(); - sb.append(dir); - sb.append(File.separatorChar); - sb.append(name); - return sb.toString(); - } - - public String getFileName() { - return name; - } - - public long getLastModified() { - if (javatime == 0) { - javatime = dosToJavaTime(nativetime); - } - return javatime; - } - - // based on dosToJavaTime in java.util.Zip, but avoiding the - // use of deprecated Date constructor - private static long dosToJavaTime(int dtime) { - Calendar c = Calendar.getInstance(); - c.set(Calendar.YEAR, ((dtime >> 25) & 0x7f) + 1980); - c.set(Calendar.MONTH, ((dtime >> 21) & 0x0f) - 1); - c.set(Calendar.DATE, ((dtime >> 16) & 0x1f)); - c.set(Calendar.HOUR_OF_DAY, ((dtime >> 11) & 0x1f)); - c.set(Calendar.MINUTE, ((dtime >> 5) & 0x3f)); - c.set(Calendar.SECOND, ((dtime << 1) & 0x3e)); - c.set(Calendar.MILLISECOND, 0); - return c.getTimeInMillis(); - } - - void setNativeTime(int natTime) { - nativetime = natTime; - } - - public boolean isDirectory() { - return isDir; - } - - public int compareTo(ZipFileIndexEntry other) { - String otherD = other.dir; - if (dir != otherD) { - int c = dir.compareTo(otherD); - if (c != 0) - return c; - } - return name.compareTo(other.name); - } - - - public String toString() { - return isDir ? ("Dir:" + dir + " : " + name) : - (dir + ":" + name); - } -}
--- a/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java Tue Jun 22 18:30:16 2010 -0700 @@ -25,44 +25,46 @@ package com.sun.tools.javadoc; -import java.util.*; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.net.URI; +import java.util.HashSet; +import java.util.Set; +import javax.tools.FileObject; +import javax.tools.JavaFileManager.Location; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; import com.sun.javadoc.*; import static com.sun.javadoc.LanguageVersion.*; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.code.Kinds; +import com.sun.tools.javac.code.Scope; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Type.ClassType; +import com.sun.tools.javac.code.TypeTags; + +import com.sun.tools.javac.comp.AttrContext; +import com.sun.tools.javac.comp.Env; + +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; +import com.sun.tools.javac.tree.JCTree.JCImport; +import com.sun.tools.javac.tree.TreeInfo; + import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Position; -import com.sun.tools.javac.code.Flags; -import com.sun.tools.javac.code.Kinds; -import com.sun.tools.javac.code.TypeTags; -import com.sun.tools.javac.code.Type; -import com.sun.tools.javac.code.Types; -import com.sun.tools.javac.code.Type.ClassType; -import com.sun.tools.javac.code.Scope; -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.Symbol.*; - -import com.sun.tools.javac.comp.AttrContext; -import com.sun.tools.javac.comp.Env; - -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.JCFieldAccess; -import com.sun.tools.javac.tree.JCTree.JCImport; -import com.sun.tools.javac.tree.JCTree.JCClassDecl; -import com.sun.tools.javac.tree.TreeInfo; - import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.*; -import static com.sun.tools.javac.code.TypeTags.*; - -import java.io.File; -import java.util.Set; -import java.util.HashSet; -import java.lang.reflect.Modifier; /** * Represents a java class and provides access to information @@ -274,16 +276,41 @@ */ public PackageDoc containingPackage() { PackageDocImpl p = env.getPackageDoc(tsym.packge()); - SourcePosition po = position(); - if (po != null && p.setDocPath == false && p.zipDocPath == null) { - //Set the package path if possible - File packageDir = po.file().getParentFile(); - if (packageDir != null - && (new File(packageDir, "package.html")).exists()) { - p.setDocPath(packageDir.getPath()); - } else { - p.setDocPath(null); + if (p.setDocPath == false) { + FileObject docPath; + try { + Location location = env.fileManager.hasLocation(StandardLocation.SOURCE_PATH) + ? StandardLocation.SOURCE_PATH : StandardLocation.CLASS_PATH; + + docPath = env.fileManager.getFileForInput( + location, p.qualifiedName(), "package.html"); + } catch (IOException e) { + docPath = null; } + + if (docPath == null) { + // fall back on older semantics of looking in same directory as + // source file for this class + SourcePosition po = position(); + if (env.fileManager instanceof StandardJavaFileManager && + po instanceof SourcePositionImpl) { + URI uri = ((SourcePositionImpl) po).filename.toUri(); + if ("file".equals(uri.getScheme())) { + File f = new File(uri); + File dir = f.getParentFile(); + if (dir != null) { + File pf = new File(dir, "package.html"); + if (pf.exists()) { + StandardJavaFileManager sfm = (StandardJavaFileManager) env.fileManager; + docPath = sfm.getJavaFileObjects(pf).iterator().next(); + } + } + + } + } + } + + p.setDocPath(docPath); } return p; } @@ -1254,7 +1281,7 @@ */ public SourcePosition position() { if (tsym.sourcefile == null) return null; - return SourcePositionImpl.make(tsym.sourcefile.toString(), + return SourcePositionImpl.make(tsym.sourcefile, (tree==null) ? Position.NOPOS : tree.pos, lineMap); }
--- a/src/share/classes/com/sun/tools/javadoc/DocEnv.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javadoc/DocEnv.java Tue Jun 22 18:30:16 2010 -0700 @@ -25,24 +25,21 @@ package com.sun.tools.javadoc; +import java.lang.reflect.Modifier; import java.util.*; -import java.lang.reflect.Modifier; +import javax.tools.JavaFileManager; import com.sun.javadoc.*; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Type.ClassType; -import com.sun.tools.javac.code.Type.TypeVar; -import com.sun.tools.javac.comp.Attr; import com.sun.tools.javac.comp.Check; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Position; - /** * Holds the environment for a run of javadoc. * Holds only the information needed throughout the @@ -75,10 +72,6 @@ /** Referenced directly in RootDocImpl. */ JavadocClassReader reader; - /** The compiler's attribution phase (needed to evaluate - * constant initializers). */ - Attr attr; - /** Javadoc's own version of the compiler's enter phase. */ JavadocEnter enter; @@ -93,8 +86,6 @@ /** Access filter (public, protected, ...). */ ModifierFilter showAccess; - private ClassDocImpl runtimeException; - /** True if we are using a sentence BreakIterator. */ boolean breakiterator; @@ -105,6 +96,7 @@ Check chk; Types types; + JavaFileManager fileManager; /** Allow documenting from class files? */ boolean docClasses = false; @@ -130,11 +122,11 @@ syms = Symtab.instance(context); reader = JavadocClassReader.instance0(context); enter = JavadocEnter.instance0(context); - attr = Attr.instance(context); names = Name.Table.instance(context); externalizableSym = reader.enterClass(names.fromString("java.io.Externalizable")); chk = Check.instance(context); types = Types.instance(context); + fileManager = context.get(JavaFileManager.class); // Default. Should normally be reset with setLocale. this.doclocale = new DocLocale(this, "", breakiterator);
--- a/src/share/classes/com/sun/tools/javadoc/DocImpl.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javadoc/DocImpl.java Tue Jun 22 18:30:16 2010 -0700 @@ -25,11 +25,13 @@ package com.sun.tools.javadoc; -import com.sun.javadoc.*; - import java.io.InputStream; import java.io.IOException; import java.text.CollationKey; +import javax.tools.FileObject; + +import com.sun.javadoc.*; + import com.sun.tools.javac.util.Position; /** @@ -43,7 +45,7 @@ * @author Atul M Dambalkar * @author Neal Gafter (rewrite) */ -abstract class DocImpl implements Doc, Comparable<Object> { +public abstract class DocImpl implements Doc, Comparable<Object> { /** * Doc environment @@ -163,7 +165,7 @@ /** * Utility for subclasses which read HTML documentation files. */ - String readHTMLDocumentation(InputStream input, String filename) throws IOException { + String readHTMLDocumentation(InputStream input, FileObject filename) throws IOException { int filesize = input.available(); byte[] filecontents = new byte[filesize]; input.read(filecontents, 0, filesize);
--- a/src/share/classes/com/sun/tools/javadoc/ExecutableMemberDocImpl.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javadoc/ExecutableMemberDocImpl.java Tue Jun 22 18:30:16 2010 -0700 @@ -267,7 +267,7 @@ */ public SourcePosition position() { if (sym.enclClass().sourcefile == null) return null; - return SourcePositionImpl.make(sym.enclClass().sourcefile.toString(), + return SourcePositionImpl.make(sym.enclClass().sourcefile, (tree==null) ? 0 : tree.pos, lineMap); }
--- a/src/share/classes/com/sun/tools/javadoc/FieldDocImpl.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javadoc/FieldDocImpl.java Tue Jun 22 18:30:16 2010 -0700 @@ -260,7 +260,7 @@ */ public SourcePosition position() { if (sym.enclClass().sourcefile == null) return null; - return SourcePositionImpl.make(sym.enclClass().sourcefile.toString(), + return SourcePositionImpl.make(sym.enclClass().sourcefile, (tree==null) ? 0 : tree.pos, lineMap); }
--- a/src/share/classes/com/sun/tools/javadoc/JavadocClassReader.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javadoc/JavadocClassReader.java Tue Jun 22 18:30:16 2010 -0700 @@ -25,15 +25,13 @@ package com.sun.tools.javadoc; +import java.util.EnumSet; +import javax.tools.JavaFileObject; + import com.sun.tools.javac.code.Symbol.PackageSymbol; import com.sun.tools.javac.jvm.ClassReader; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.JavacFileManager; -import com.sun.tools.javac.util.Old199; -import java.io.File; -import java.util.EnumSet; -import javax.tools.JavaFileObject; /** Javadoc uses an extended class reader that records package.html entries * @author Neal Gafter @@ -80,32 +78,7 @@ */ @Override protected void extraFileActions(PackageSymbol pack, JavaFileObject fo) { - CharSequence fileName = Old199.getName(fo); - if (docenv != null && fileName.equals("package.html")) { - if (fo instanceof JavacFileManager.ZipFileObject) { - JavacFileManager.ZipFileObject zfo = (JavacFileManager.ZipFileObject) fo; - String zipName = zfo.getZipName(); - String entryName = zfo.getZipEntryName(); - int lastSep = entryName.lastIndexOf("/"); - String classPathName = entryName.substring(0, lastSep + 1); - docenv.getPackageDoc(pack).setDocPath(zipName, classPathName); - } - else if (fo instanceof JavacFileManager.ZipFileIndexFileObject) { - JavacFileManager.ZipFileIndexFileObject zfo = (JavacFileManager.ZipFileIndexFileObject) fo; - String zipName = zfo.getZipName(); - String entryName = zfo.getZipEntryName(); - if (File.separatorChar != '/') { - entryName = entryName.replace(File.separatorChar, '/'); - } - - int lastSep = entryName.lastIndexOf("/"); - String classPathName = entryName.substring(0, lastSep + 1); - docenv.getPackageDoc(pack).setDocPath(zipName, classPathName); - } - else { - File fileDir = new File(Old199.getPath(fo)).getParentFile(); - docenv.getPackageDoc(pack).setDocPath(fileDir.getAbsolutePath()); - } - } + if (fo.isNameCompatible("package", JavaFileObject.Kind.HTML)) + docenv.getPackageDoc(pack).setDocPath(fo); } }
--- a/src/share/classes/com/sun/tools/javadoc/JavadocTool.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javadoc/JavadocTool.java Tue Jun 22 18:30:16 2010 -0700 @@ -25,23 +25,30 @@ package com.sun.tools.javadoc; -import java.io.*; - +import java.io.File; +import java.io.IOException; import java.util.Collection; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import javax.tools.JavaFileManager.Location; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; -import com.sun.tools.javac.code.*; -import com.sun.tools.javac.code.Symbol.*; -import com.sun.tools.javac.comp.*; -import com.sun.tools.javac.jvm.ClassReader; -import com.sun.tools.javac.jvm.ClassWriter; +import com.sun.tools.javac.code.Symbol.CompletionFailure; +import com.sun.tools.javac.comp.Annotate; import com.sun.tools.javac.parser.DocCommentScanner; -import com.sun.tools.javac.util.Paths; -import com.sun.tools.javac.tree.*; -import com.sun.tools.javac.tree.JCTree.*; -import com.sun.tools.javac.util.*; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.util.Abort; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Position; -import com.sun.javadoc.LanguageVersion; -import static com.sun.javadoc.LanguageVersion.*; /** * This class could be the main entry point for Javadoc when Javadoc is used as a @@ -58,7 +65,6 @@ final JavadocClassReader reader; final JavadocEnter enter; final Annotate annotate; - private final Paths paths; /** * Construct a new JavaCompiler processor, using appropriately @@ -71,7 +77,6 @@ reader = JavadocClassReader.instance0(context); enter = JavadocEnter.instance0(context); annotate = Annotate.instance(context); - paths = Paths.instance(context); } /** @@ -125,7 +130,7 @@ boolean quiet) throws IOException { docenv = DocEnv.instance(context); docenv.showAccess = filter; - docenv.quiet = quiet; + docenv.quiet = quiet; docenv.breakiterator = breakiterator; docenv.setLocale(doclocale); docenv.setEncoding(encoding); @@ -138,16 +143,18 @@ ListBuffer<JCCompilationUnit> packTrees = new ListBuffer<JCCompilationUnit>(); try { + StandardJavaFileManager fm = (StandardJavaFileManager) docenv.fileManager; for (List<String> it = javaNames; it.nonEmpty(); it = it.tail) { String name = it.head; if (!docClasses && name.endsWith(".java") && new File(name).exists()) { + JavaFileObject fo = fm.getJavaFileObjects(name).iterator().next(); docenv.notice("main.Loading_source_file", name); - JCCompilationUnit tree = parse(name); - classTrees.append(tree); + JCCompilationUnit tree = parse(fo); + classTrees.append(tree); } else if (isValidPackageName(name)) { names = names.append(name); } else if (name.endsWith(".java")) { - docenv.error(null, "main.file_not_found", name);; + docenv.error(null, "main.file_not_found", name); } else { docenv.error(null, "main.illegal_package_name", name); } @@ -156,12 +163,14 @@ if (!docClasses) { // Recursively search given subpackages. If any packages //are found, add them to the list. - searchSubPackages(subPackages, names, excludedPackages); + Map<String,List<JavaFileObject>> packageFiles = + searchSubPackages(subPackages, names, excludedPackages); // Parse the packages for (List<String> packs = names.toList(); packs.nonEmpty(); packs = packs.tail) { // Parse sources ostensibly belonging to package. - parsePackageClasses(packs.head, packTrees, excludedPackages); + String packageName = packs.head; + parsePackageClasses(packageName, packageFiles.get(packageName), packTrees, excludedPackages); } if (messager.nerrors() != 0) return null; @@ -172,7 +181,8 @@ } } catch (Abort ex) {} - if (messager.nerrors() != 0) return null; + if (messager.nerrors() != 0) + return null; if (docClasses) return new RootDocImpl(docenv, javaNames, options); @@ -190,66 +200,129 @@ return isValidClassName(s); } - - private final static char pathSep = File.pathSeparatorChar; - /** * search all directories in path for subdirectory name. Add all * .java files found in such a directory to args. */ private void parsePackageClasses(String name, - ListBuffer<JCCompilationUnit> trees, - List<String> excludedPackages) - throws IOException { + Iterable<JavaFileObject> files, + ListBuffer<JCCompilationUnit> trees, + List<String> excludedPackages) + throws IOException { if (excludedPackages.contains(name)) { return; } + boolean hasFiles = false; docenv.notice("main.Loading_source_files_for_package", name); - name = name.replace('.', File.separatorChar); - for (File pathname : paths.sourceSearchPath()) { - File f = new File(pathname, name); - String names[] = f.list(); - // if names not null, then found directory with source files - if (names != null) { - String dir = f.getAbsolutePath(); - if (!dir.endsWith(File.separator)) - dir = dir + File.separator; - for (int j = 0; j < names.length; j++) { - if (isValidJavaSourceFile(names[j])) { - String fn = dir + names[j]; - // messager.notice("main.Loading_source_file", fn); - trees.append(parse(fn)); - hasFiles = true; - } + + if (files == null) { + Location location = docenv.fileManager.hasLocation(StandardLocation.SOURCE_PATH) + ? StandardLocation.SOURCE_PATH : StandardLocation.CLASS_PATH; + ListBuffer<JavaFileObject> lb = new ListBuffer<JavaFileObject>(); + for (JavaFileObject fo: docenv.fileManager.list( + location, name, EnumSet.of(JavaFileObject.Kind.SOURCE), false)) { + String binaryName = docenv.fileManager.inferBinaryName(location, fo); + String simpleName = getSimpleName(binaryName); + if (isValidClassName(simpleName)) { + lb.append(fo); } } + files = lb.toList(); } - if (!hasFiles) + + for (JavaFileObject fo : files) { + // messager.notice("main.Loading_source_file", fn); + trees.append(parse(fo)); + hasFiles = true; + } + + if (!hasFiles) { messager.warning(null, "main.no_source_files_for_package", - name.replace(File.separatorChar, '.')); + name.replace(File.separatorChar, '.')); + } } /** * Recursively search all directories in path for subdirectory name. * Add all packages found in such a directory to packages list. */ + private Map<String,List<JavaFileObject>> searchSubPackages( + List<String> subPackages, + ListBuffer<String> packages, + List<String> excludedPackages) + throws IOException { + Map<String,List<JavaFileObject>> packageFiles = + new HashMap<String,List<JavaFileObject>>(); + + Map<String,Boolean> includedPackages = new HashMap<String,Boolean>(); + includedPackages.put("", true); + for (String p: excludedPackages) + includedPackages.put(p, false); + + if (docenv.fileManager.hasLocation(StandardLocation.SOURCE_PATH)) { + searchSubPackages(subPackages, + includedPackages, + packages, packageFiles, + StandardLocation.SOURCE_PATH, + EnumSet.of(JavaFileObject.Kind.SOURCE)); + searchSubPackages(subPackages, + includedPackages, + packages, packageFiles, + StandardLocation.CLASS_PATH, + EnumSet.of(JavaFileObject.Kind.CLASS)); + } else { + searchSubPackages(subPackages, + includedPackages, + packages, packageFiles, + StandardLocation.CLASS_PATH, + EnumSet.of(JavaFileObject.Kind.SOURCE, JavaFileObject.Kind.CLASS)); + } + return packageFiles; + } + private void searchSubPackages(List<String> subPackages, - ListBuffer<String> packages, - List<String> excludedPackages) { - // FIXME: This search path is bogus. - // Only the effective source path should be searched for sources. - // Only the effective class path should be searched for classes. - // Should the bootclasspath/extdirs also be searched for classes? - java.util.List<File> pathnames = new java.util.ArrayList<File>(); - if (paths.sourcePath() != null) - for (File elt : paths.sourcePath()) - pathnames.add(elt); - for (File elt : paths.userClassPath()) - pathnames.add(elt); + Map<String,Boolean> includedPackages, + ListBuffer<String> packages, + Map<String, List<JavaFileObject>> packageFiles, + StandardLocation location, Set<JavaFileObject.Kind> kinds) + throws IOException { + for (String subPackage: subPackages) { + if (!isIncluded(subPackage, includedPackages)) + continue; - for (String subPackage : subPackages) - searchSubPackage(subPackage, packages, excludedPackages, pathnames); + for (JavaFileObject fo: docenv.fileManager.list(location, subPackage, kinds, true)) { + String binaryName = docenv.fileManager.inferBinaryName(location, fo); + String packageName = getPackageName(binaryName); + String simpleName = getSimpleName(binaryName); + if (isIncluded(packageName, includedPackages) && isValidClassName(simpleName)) { + List<JavaFileObject> list = packageFiles.get(packageName); + list = (list == null ? List.of(fo) : list.prepend(fo)); + packageFiles.put(packageName, list); + if (!packages.contains(packageName)) + packages.add(packageName); + } + } + } + } + + private String getPackageName(String name) { + int lastDot = name.lastIndexOf("."); + return (lastDot == -1 ? "" : name.substring(0, lastDot)); + } + + private String getSimpleName(String name) { + int lastDot = name.lastIndexOf("."); + return (lastDot == -1 ? name : name.substring(lastDot + 1)); + } + + private boolean isIncluded(String packageName, Map<String,Boolean> includedPackages) { + Boolean b = includedPackages.get(packageName); + if (b == null) { + b = isIncluded(getPackageName(packageName), includedPackages); + includedPackages.put(packageName, b); + } + return b; } /**
--- a/src/share/classes/com/sun/tools/javadoc/PackageDocImpl.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javadoc/PackageDocImpl.java Tue Jun 22 18:30:16 2010 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -25,30 +25,23 @@ package com.sun.tools.javadoc; -import com.sun.javadoc.*; +import java.io.InputStream; +import java.io.IOException; +import javax.tools.FileObject; -import java.io.File; -import java.io.InputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.zip.ZipFile; -import java.util.zip.ZipEntry; +import com.sun.javadoc.*; import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Scope; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.PackageSymbol; -import com.sun.tools.javac.comp.AttrContext; -import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Position; -import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; - - /** * Represents a java package. Provides access to information * about the package, the package's comment and tags, and the @@ -63,14 +56,10 @@ public class PackageDocImpl extends DocImpl implements PackageDoc { - private static final String PACKAGE_HTML_FILE_NAME = "package.html"; - protected PackageSymbol sym; private JCCompilationUnit tree = null; // for source position - public String docPath = null; - public String zipDocPath = null; - public String zipDocEntry = null; + public FileObject docPath = null; private boolean foundDoc; // found a doc comment in either // package.html or package-info.java @@ -108,30 +97,16 @@ * Do lazy initialization of "documentation" string. */ String documentation() { - if (documentation != null) return documentation; - if (zipDocPath != null) { - try { - ZipFile f = new ZipFile(zipDocPath); - ZipEntry entry = f.getEntry(zipDocEntry); - if (entry != null) { - InputStream s = f.getInputStream(entry); - return (documentation = readHTMLDocumentation(s, - zipDocPath + File.separatorChar + zipDocEntry)); - } - } catch (IOException exc) { - documentation = ""; - env.error(null, "javadoc.File_Read_Error", - zipDocPath + File.separatorChar + zipDocEntry); - } - } + if (documentation != null) + return documentation; if (docPath != null) { // read from file try { - InputStream s = new FileInputStream(docPath); + InputStream s = docPath.openInputStream(); documentation = readHTMLDocumentation(s, docPath); } catch (IOException exc) { documentation = ""; - env.error(null, "javadoc.File_Read_Error", docPath); + env.error(null, "javadoc.File_Read_Error", docPath.getName()); } } else { // no doc file to be had @@ -363,24 +338,12 @@ /** * set doc path for an unzipped directory */ - public void setDocPath(String path) { + public void setDocPath(FileObject path) { setDocPath = true; if (path == null) return; - String newDocPath = path + File.separatorChar + PACKAGE_HTML_FILE_NAME; - if (!newDocPath.equals(docPath)) { - docPath = newDocPath; - checkDoc(); - } - } - - /** - * set the doc path for zipped directory - */ - public void setDocPath(String path, String entry) { - if (!path.equals(zipDocPath)) { - zipDocPath = path; - zipDocEntry = entry + PACKAGE_HTML_FILE_NAME; + if (!path.equals(docPath)) { + docPath = path; checkDoc(); } } @@ -409,7 +372,7 @@ */ public SourcePosition position() { return (tree != null) - ? SourcePositionImpl.make(tree.sourcefile + "", tree.pos, tree.lineMap) + ? SourcePositionImpl.make(tree.sourcefile, tree.pos, tree.lineMap) : SourcePositionImpl.make(docPath, Position.NOPOS, null); } }
--- a/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javadoc/RootDocImpl.java Tue Jun 22 18:30:16 2010 -0700 @@ -26,13 +26,13 @@ package com.sun.tools.javadoc; import java.io.IOException; -import java.io.FileInputStream; -import java.io.File; +import java.util.Locale; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; import com.sun.javadoc.*; import com.sun.tools.javac.tree.JCTree.JCClassDecl; -import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Position; @@ -307,10 +307,13 @@ * Return the path of the overview file and null if it does not exist. * @return the path of the overview file and null if it does not exist. */ - private String getOverviewPath() { + private JavaFileObject getOverviewPath() { for (String[] opt : options) { if (opt[0].equals("-overview")) { - return opt[1]; + if (env.fileManager instanceof StandardJavaFileManager) { + StandardJavaFileManager fm = (StandardJavaFileManager) env.fileManager; + return fm.getJavaFileObjects(opt[1]).iterator().next(); + } } } return null; @@ -322,7 +325,7 @@ protected String documentation() { if (documentation == null) { int cnt = options.length(); - String overviewPath = getOverviewPath(); + JavaFileObject overviewPath = getOverviewPath(); if (overviewPath == null) { // no doc file to be had documentation = ""; @@ -330,11 +333,11 @@ // read from file try { documentation = readHTMLDocumentation( - new FileInputStream(overviewPath), + overviewPath.openInputStream(), overviewPath); } catch (IOException exc) { documentation = ""; - env.error(null, "javadoc.File_Read_Error", overviewPath); + env.error(null, "javadoc.File_Read_Error", overviewPath.getName()); } } } @@ -346,9 +349,16 @@ * no position is available. */ public SourcePosition position() { - String path; + JavaFileObject path; return ((path = getOverviewPath()) == null) ? null : SourcePositionImpl.make(path, Position.NOPOS, null); } + + /** + * Return the locale provided by the user or the default locale value. + */ + public Locale getLocale() { + return env.doclocale.locale; + } }
--- a/src/share/classes/com/sun/tools/javadoc/SourcePositionImpl.java Mon Jun 21 11:43:28 2010 -0700 +++ b/src/share/classes/com/sun/tools/javadoc/SourcePositionImpl.java Tue Jun 22 18:30:16 2010 -0700 @@ -25,11 +25,12 @@ package com.sun.tools.javadoc; +import java.io.File; +import javax.tools.FileObject; + import com.sun.javadoc.SourcePosition; import com.sun.tools.javac.util.Position; -import java.io.File; - /** * A source position: filename, line number, and column number. * @@ -37,15 +38,21 @@ * @author Neal M Gafter * @author Michael Van De Vanter (position representation changed to char offsets) */ -class SourcePositionImpl implements SourcePosition { - String filename; +public class SourcePositionImpl implements SourcePosition { + FileObject filename; int position; Position.LineMap lineMap; /** The source file. Returns null if no file information is * available. */ public File file() { - return (filename == null) ? null : new File(filename); + return (filename == null) ? null : new File(filename.getName()); + } + + /** The source file. Returns null if no file information is + * available. */ + public FileObject fileObject() { + return filename; } /** The line in the source file. The first line is numbered 1; @@ -71,7 +78,7 @@ } } - private SourcePositionImpl(String file, int position, + private SourcePositionImpl(FileObject file, int position, Position.LineMap lineMap) { super(); this.filename = file; @@ -79,16 +86,27 @@ this.lineMap = lineMap; } - public static SourcePosition make(String file, int pos, + public static SourcePosition make(FileObject file, int pos, Position.LineMap lineMap) { if (file == null) return null; return new SourcePositionImpl(file, pos, lineMap); } public String toString() { + // Backwards compatibility hack. ZipFileObjects use the format + // zipfile(zipentry) but javadoc has been using zipfile/zipentry + String fn = filename.getName(); + if (fn.endsWith(")")) { + int paren = fn.lastIndexOf("("); + if (paren != -1) + fn = fn.substring(0, paren) + + File.separatorChar + + fn.substring(paren + 1, fn.length() - 1); + } + if (position == Position.NOPOS) - return filename; + return fn; else - return filename + ":" + line(); + return fn + ":" + line(); } }
--- a/test/tools/javac/6304921/TestLog.java Mon Jun 21 11:43:28 2010 -0700 +++ b/test/tools/javac/6304921/TestLog.java Tue Jun 22 18:30:16 2010 -0700 @@ -32,12 +32,12 @@ import java.net.URI; import javax.tools.JavaFileObject; import javax.tools.SimpleJavaFileObject; +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.parser.Parser; import com.sun.tools.javac.parser.Scanner; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.JavacFileManager; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.JCDiagnostic; import com.sun.tools.javac.util.Options;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/6508981/TestInferBinaryName.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,177 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6508981 + * @summary cleanup file separator handling in JavacFileManager + * (This test is specifically to test the new impl of inferBinaryName) + * @build p.A + * @run main TestInferBinaryName + */ + +import java.io.*; +import java.util.*; +import javax.tools.*; + +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Options; + +import static javax.tools.JavaFileObject.Kind.*; +import static javax.tools.StandardLocation.*; + + +/** + * Verify the various implementations of inferBinaryName, but configuring + * different instances of a file manager, getting a file object, and checking + * the impl of inferBinaryName for that file object. + */ +public class TestInferBinaryName { + static final boolean IGNORE_SYMBOL_FILE = false; + static final boolean USE_SYMBOL_FILE = true; + static final boolean DONT_USE_ZIP_FILE_INDEX = false; + static final boolean USE_ZIP_FILE_INDEX = true; + + public static void main(String... args) throws Exception { + new TestInferBinaryName().run(); + } + + void run() throws Exception { + //System.err.println(System.getProperties()); + testDirectory(); + testSymbolArchive(); + testZipArchive(); + testZipFileIndexArchive(); + testZipFileIndexArchive2(); + if (errors > 0) + throw new Exception(errors + " error found"); + } + + void testDirectory() throws IOException { + String testClassName = "p.A"; + JavaFileManager fm = + getFileManager("test.classes", USE_SYMBOL_FILE, USE_ZIP_FILE_INDEX); + test("testDirectory", + fm, testClassName, "com.sun.tools.javac.file.RegularFileObject"); + } + + void testSymbolArchive() throws IOException { + String testClassName = "java.lang.String"; + JavaFileManager fm = + getFileManager("sun.boot.class.path", USE_SYMBOL_FILE, DONT_USE_ZIP_FILE_INDEX); + test("testSymbolArchive", + fm, testClassName, "com.sun.tools.javac.file.SymbolArchive$SymbolFileObject"); + } + + void testZipArchive() throws IOException { + String testClassName = "java.lang.String"; + JavaFileManager fm = + getFileManager("sun.boot.class.path", IGNORE_SYMBOL_FILE, DONT_USE_ZIP_FILE_INDEX); + test("testZipArchive", + fm, testClassName, "com.sun.tools.javac.file.ZipArchive$ZipFileObject"); + } + + void testZipFileIndexArchive() throws IOException { + String testClassName = "java.lang.String"; + JavaFileManager fm = + getFileManager("sun.boot.class.path", USE_SYMBOL_FILE, USE_ZIP_FILE_INDEX); + test("testZipFileIndexArchive", + fm, testClassName, "com.sun.tools.javac.file.ZipFileIndexArchive$ZipFileIndexFileObject"); + } + + void testZipFileIndexArchive2() throws IOException { + String testClassName = "java.lang.String"; + JavaFileManager fm = + getFileManager("sun.boot.class.path", IGNORE_SYMBOL_FILE, USE_ZIP_FILE_INDEX); + test("testZipFileIndexArchive2", + fm, testClassName, "com.sun.tools.javac.file.ZipFileIndexArchive$ZipFileIndexFileObject"); + } + + /** + * @param testName for debugging + * @param fm suitably configured file manager + * @param testClassName the classname to test + * @param implClassName the expected classname of the JavaFileObject impl, + * used for checking that we are checking the expected impl of + * inferBinaryName + */ + void test(String testName, + JavaFileManager fm, String testClassName, String implClassName) throws IOException { + JavaFileObject fo = fm.getJavaFileForInput(CLASS_PATH, testClassName, CLASS); + if (fo == null) { + System.err.println("Can't find " + testClassName); + errors++; + return; + } + + String cn = fo.getClass().getName(); + String bn = fm.inferBinaryName(CLASS_PATH, fo); + System.err.println(testName + " " + cn + " " + bn); + check(cn, implClassName); + check(bn, testClassName); + System.err.println("OK"); + } + + JavaFileManager getFileManager(String classpathProperty, + boolean symFileKind, + boolean zipFileIndexKind) + throws IOException { + Context ctx = new Context(); + // uugh, ugly back door, should be cleaned up, someday + if (zipFileIndexKind == USE_ZIP_FILE_INDEX) + System.clearProperty("useJavaUtilZip"); + else + System.setProperty("useJavaUtilZip", "true"); + Options options = Options.instance(ctx); + if (symFileKind == IGNORE_SYMBOL_FILE) + options.put("ignore.symbol.file", "true"); + JavacFileManager fm = new JavacFileManager(ctx, false, null); + List<File> path = getPath(System.getProperty(classpathProperty)); + fm.setLocation(CLASS_PATH, path); + return fm; + } + + List<File> getPath(String s) { + List<File> path = new ArrayList<File>(); + for (String f: s.split(File.pathSeparator)) { + if (f.length() > 0) + path.add(new File(f)); + } + //System.err.println("path: " + path); + return path; + } + + void check(String found, String expect) { + if (!found.equals(expect)) { + System.err.println("Expected: " + expect); + System.err.println(" Found: " + found); + errors++; + } + } + + private int errors; +} + +class A { } +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/6508981/p/A.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,24 @@ +/* + * 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. + * + * 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 p; +class A { }
--- a/test/tools/javac/6589361/T6589361.java Mon Jun 21 11:43:28 2010 -0700 +++ b/test/tools/javac/6589361/T6589361.java Tue Jun 22 18:30:16 2010 -0700 @@ -1,11 +1,11 @@ /** - * @test @(#)T6589361.java 1.1 07/07/18 + * @test * @bug 6589361 * @summary 6589361:Failing building ct.sym file as part of the control build */ +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.JavacFileManager; import java.io.File; import javax.tools.FileObject; import javax.tools.JavaFileObject; @@ -23,8 +23,9 @@ set.add(JavaFileObject.Kind.CLASS); Iterable<JavaFileObject> files = fm.list(StandardLocation.PLATFORM_CLASS_PATH, "java.lang", set, false); for (JavaFileObject file : files) { - - if (file.toString().startsWith("java" + File.separator + "lang" + File.separator + "Object.class")) { + // Note: Zip/Jar entry names use '/', not File.separator, but just to be sure, + // we normalize the filename as well. + if (file.getName().replace(File.separatorChar, '/').contains("java/lang/Object.class")) { String str = fm.inferBinaryName(StandardLocation.CLASS_PATH, file); if (!str.equals("java.lang.Object")) { throw new AssertionError("Error in JavacFileManager.inferBinaryName method!");
--- a/test/tools/javac/T6358024.java Mon Jun 21 11:43:28 2010 -0700 +++ b/test/tools/javac/T6358024.java Tue Jun 22 18:30:16 2010 -0700 @@ -35,6 +35,8 @@ import javax.tools.*; import com.sun.source.util.*; import com.sun.tools.javac.api.*; +import com.sun.tools.javac.file.*; +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.*; import com.sun.tools.javac.util.*;
--- a/test/tools/javac/T6358166.java Mon Jun 21 11:43:28 2010 -0700 +++ b/test/tools/javac/T6358166.java Tue Jun 22 18:30:16 2010 -0700 @@ -32,6 +32,8 @@ import javax.annotation.processing.*; import javax.lang.model.element.*; import javax.tools.*; +import com.sun.tools.javac.file.*; +import com.sun.tools.javac.file.JavacFileManager; // disambiguate import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.main.*; import com.sun.tools.javac.util.*;
--- a/test/tools/javac/T6358168.java Mon Jun 21 11:43:28 2010 -0700 +++ b/test/tools/javac/T6358168.java Tue Jun 22 18:30:16 2010 -0700 @@ -33,6 +33,8 @@ import javax.annotation.processing.*; import javax.lang.model.element.*; import javax.tools.*; +import com.sun.tools.javac.file.*; +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.main.*; import com.sun.tools.javac.util.*;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/T6625520.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,55 @@ +/* + * 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. + * + * 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. + */ + +import java.io.*; +import java.util.*; +import javax.tools.*; +import com.sun.tools.javac.file.*; +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.util.*; + +/* + * @test + * @bug 6625520 + * @summary javac handles missing entries on classpath badly + */ +public class T6625520 { + public static void main(String[] args) throws Exception { + new T6625520().run(); + } + + void run() throws Exception { + Context c = new Context(); + DiagnosticCollector<JavaFileObject> dc = + new DiagnosticCollector<JavaFileObject>(); + c.put(DiagnosticListener.class, dc); + StandardJavaFileManager fm = new JavacFileManager(c, false, null); + fm.setLocation(StandardLocation.CLASS_PATH, + Arrays.asList(new File("DOES_NOT_EXIST.jar"))); + FileObject fo = fm.getFileForInput(StandardLocation.CLASS_PATH, + "p", "C.java"); + System.err.println(fo + "\n" + dc.getDiagnostics()); + if (dc.getDiagnostics().size() > 0) + throw new Exception("unexpected diagnostics found"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/T6705935.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,65 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6705935 + * @summary javac reports path name of entry in ZipFileIndex incorectly + */ + +import java.io.*; +import java.util.*; +import javax.tools.*; +import com.sun.tools.javac.file.*; + +public class T6705935 { + public static void main(String... args) throws Exception { + new T6705935().run(); + } + + public void run() throws Exception { + File java_home = new File(System.getProperty("java.home")); + if (java_home.getName().equals("jre")) + java_home = java_home.getParentFile(); + + JavaCompiler c = ToolProvider.getSystemJavaCompiler(); + JavaFileManager fm = c.getStandardFileManager(null, null, null); + for (JavaFileObject fo: fm.list(StandardLocation.PLATFORM_CLASS_PATH, + "java.lang", + Collections.singleton(JavaFileObject.Kind.CLASS), + false)) { + String p = fo.getName(); + int bra = p.indexOf("("); + int ket = p.indexOf(")"); + //System.err.println(bra + "," + ket + "," + p.length()); + if (bra == -1 || ket != p.length() -1) + throw new Exception("unexpected path: " + p + "[" + bra + "," + ket + "," + p.length()); + String part1 = p.substring(0, bra); + String part2 = p.substring(bra + 1, ket); + //System.err.println("[" + part1 + "|" + part2 + "]" + " " + java_home); + if (part1.equals(part2) || !part1.startsWith(java_home.getPath())) + throw new Exception("bad path: " + p); + + } + } +}
--- a/test/tools/javac/T6725036.java Mon Jun 21 11:43:28 2010 -0700 +++ b/test/tools/javac/T6725036.java Tue Jun 22 18:30:16 2010 -0700 @@ -34,10 +34,10 @@ import java.util.jar.JarFile; import javax.tools.JavaFileObject; -import com.sun.tools.javac.util.JavacFileManager; -import com.sun.tools.javac.zip.ZipFileIndex; -import com.sun.tools.javac.zip.ZipFileIndexEntry; -import com.sun.tools.javac.util.JavacFileManager.ZipFileIndexArchive; +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.file.RelativePath.RelativeFile; +import com.sun.tools.javac.file.ZipFileIndex; +import com.sun.tools.javac.file.ZipFileIndexArchive; import com.sun.tools.javac.util.Context; public class T6725036 { @@ -46,7 +46,7 @@ } void run() throws Exception { - String TEST_ENTRY_NAME = "java/lang/String.class"; + RelativeFile TEST_ENTRY_NAME = new RelativeFile("java/lang/String.class"); File f = new File(System.getProperty("java.home")); if (!f.getName().equals("jre")) @@ -54,23 +54,21 @@ File rt_jar = new File(new File(f, "lib"), "rt.jar"); JarFile j = new JarFile(rt_jar); - JarEntry je = j.getJarEntry(TEST_ENTRY_NAME); + JarEntry je = j.getJarEntry(TEST_ENTRY_NAME.getPath()); long jarEntryTime = je.getTime(); ZipFileIndex zfi = - ZipFileIndex.getZipFileIndex(rt_jar, 0, false, null, false); + ZipFileIndex.getZipFileIndex(rt_jar, null, false, null, false); long zfiTime = zfi.getLastModified(TEST_ENTRY_NAME); - check(je, jarEntryTime, zfi + ":" + TEST_ENTRY_NAME, zfiTime); + check(je, jarEntryTime, zfi + ":" + TEST_ENTRY_NAME.getPath(), zfiTime); Context context = new Context(); JavacFileManager fm = new JavacFileManager(context, false, null); - ZipFileIndexArchive zfia = - fm.new ZipFileIndexArchive(fm, zfi); - int sep = TEST_ENTRY_NAME.lastIndexOf("/"); + ZipFileIndexArchive zfia = new ZipFileIndexArchive(fm, zfi); JavaFileObject jfo = - zfia.getFileObject(TEST_ENTRY_NAME.substring(0, sep + 1), - TEST_ENTRY_NAME.substring(sep + 1)); + zfia.getFileObject(TEST_ENTRY_NAME.dirname(), + TEST_ENTRY_NAME.basename()); long jfoTime = jfo.getLastModified(); check(je, jarEntryTime, jfo, jfoTime);
--- a/test/tools/javac/api/6411310/T6411310.java Mon Jun 21 11:43:28 2010 -0700 +++ b/test/tools/javac/api/6411310/T6411310.java Tue Jun 22 18:30:16 2010 -0700 @@ -37,7 +37,7 @@ import static javax.tools.StandardLocation.CLASS_PATH; import static javax.tools.JavaFileObject.Kind.CLASS; -// Limited test while we wait for 6419926 +// Limited test while we wait for 6419926: 6419926 is now closed public class T6411310 extends ToolTester { @@ -45,8 +45,11 @@ JavaFileObject file = fm.getJavaFileForInput(PLATFORM_CLASS_PATH, "java.lang.Object", CLASS); - if (!file.getName().equals("Object.class")) + String fileName = file.getName(); + if (!fileName.matches(".*java/lang/Object.class\\)?")) { + System.err.println(fileName); throw new AssertionError(file); + } } public static void main(String... args) throws IOException {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/api/6411310/Test.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,254 @@ +/* + * Copyright (c) 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. + * + * 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. + */ + +/* + * @test + * @bug 6410367 6411310 + * @summary FileObject should support user-friendly names via getName() + */ + +import java.io.*; +import java.util.*; +import java.util.jar.*; +import java.util.zip.*; +import javax.tools.*; + +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Options; + +// Test FileObject.getName returned from JavacFileManager and its support classes. + +public class Test { + public static void main(String... args) throws Exception { + new Test().run(); + } + + Set<String> foundClasses = new TreeSet<String>(); + Set<String> foundJars = new TreeSet<String>(); + + void run() throws Exception { + File rt_jar = findRtJar(); + + // names for entries to be created in directories and jar files + String[] entries = { "p/A.java", "p/A.class", "p/resources/A-1.html" }; + + // test various combinations of directories and jar files, intended to + // cover all sources of file objects within JavacFileManager's support classes + + test(createFileManager(), createDir("dir", entries), "p", entries); + test(createFileManager(), createDir("a b/dir", entries), "p", entries); + + for (boolean useJavaUtilZip: new boolean[] { false, true }) { + test(createFileManager(useJavaUtilZip), createJar("jar", entries), "p", entries); + test(createFileManager(useJavaUtilZip), createJar("jar jar", entries), "p", entries); + + for (boolean useSymbolFile: new boolean[] { false, true }) { + test(createFileManager(useJavaUtilZip, useSymbolFile), rt_jar, "java.lang.ref", null); + } + } + + if (errors > 0) + throw new Exception(errors + " errors found"); + + // Verify that we hit all the impl classes we intended + checkCoverage("classes", foundClasses, + "RegularFileObject", "SymbolFileObject", "ZipFileIndexFileObject", "ZipFileObject"); + + // Verify that we hit the jar files we intended, specifically ct.sym as well as rt.jar + checkCoverage("jar files", foundJars, + "ct.sym", "jar", "jar jar", "rt.jar"); + } + + // use a new file manager for each test + void test(StandardJavaFileManager fm, File f, String pkg, String[] entries) throws Exception { + System.err.println("Test " + f); + try { + if (f.isDirectory()) { + for (File dir: new File[] { f, f.getAbsoluteFile() }) { + for (String e: entries) { + JavaFileObject fo = fm.getJavaFileObjects(new File(dir, e)).iterator().next(); + test(fo, dir, e); + } + } + } + + fm.setLocation(StandardLocation.CLASS_PATH, Collections.singleton(f)); + fm.setLocation(StandardLocation.SOURCE_PATH, Collections.singleton(f.getAbsoluteFile())); + for (StandardLocation l: EnumSet.of(StandardLocation.CLASS_PATH, StandardLocation.SOURCE_PATH)) { + for (JavaFileObject fo: fm.list(l, pkg, EnumSet.allOf(JavaFileObject.Kind.class), true)) { + // we could use fm.getLocation but the following guarantees we preserve the original filename + File dir = (l == StandardLocation.CLASS_PATH ? f : f.getAbsoluteFile()); + char sep = (dir.isDirectory() ? File.separatorChar : '/'); + String b = fm.inferBinaryName(l, fo); + String e = fo.getKind().extension; + test(fo, dir, b.replace('.', sep) + e); + } + } + } finally { + fm.close(); + } + } + + void test(JavaFileObject fo, File dir, String p) { + System.err.println("Test: " + fo); + String expect = dir.isDirectory() ? new File(dir, p).getPath() : (dir.getPath() + "(" + p + ")"); + String found = fo.getName(); + // if ct.sym is found, replace it with the equivalent rt.jar + String found2 = found.replaceAll("lib([\\\\/])ct.sym\\(META-INF/sym/rt.jar/", "jre$1lib$1rt.jar("); + if (!expect.equals(found2)) { + System.err.println("expected: " + expect); + System.err.println(" found: " + found); + if (!found.equals(found2)) + System.err.println(" found2: " + found2); + error("Failed: " + fo); + } + + // record the file object class name for coverage checks later + foundClasses.add(fo.getClass().getSimpleName()); + + if (found.contains("(")) { + // record access to the jar file for coverage checks later + foundJars.add(new File(found.substring(0, found.indexOf("("))).getName()); + } + } + + void checkCoverage(String label, Set<String> found, String... expect) throws Exception { + Set<String> e = new TreeSet<String>(Arrays.asList(expect)); + if (!found.equals(e)) { + e.removeAll(found); + throw new Exception("expected " + label + " not used: " + e); + } + } + + JavacFileManager createFileManager() { + return createFileManager(false, false); + } + + JavacFileManager createFileManager(boolean useJavaUtilZip) { + return createFileManager(useJavaUtilZip, false); + } + + JavacFileManager createFileManager(boolean useJavaUtilZip, boolean useSymbolFile) { + // javac should really not be using system properties like this + // -- it should really be using (hidden) options -- but until then + // take care to leave system properties as we find them, so as not + // to adversely affect other tests that might follow. + String prev = System.getProperty("useJavaUtilZip"); + boolean resetProperties = false; + try { + if (useJavaUtilZip) { + System.setProperty("useJavaUtilZip", "true"); + resetProperties = true; + } else if (System.getProperty("useJavaUtilZip") != null) { + System.getProperties().remove("useJavaUtilZip"); + resetProperties = true; + } + + Context c = new Context(); + if (!useSymbolFile) { + Options options = Options.instance(c); + options.put("ignore.symbol.file", "true"); + } + + return new JavacFileManager(c, false, null); + } finally { + if (resetProperties) { + if (prev == null) { + System.getProperties().remove("useJavaUtilZip"); + } else { + System.setProperty("useJavaUtilZip", prev); + } + } + } + } + + File createDir(String name, String... entries) throws Exception { + File dir = new File(name); + if (!dir.mkdirs()) + throw new Exception("cannot create directories " + dir); + for (String e: entries) { + writeFile(new File(dir, e), e); + } + return dir; + } + + File createJar(String name, String... entries) throws IOException { + File jar = new File(name); + OutputStream out = new FileOutputStream(jar); + try { + JarOutputStream jos = new JarOutputStream(out); + for (String e: entries) { + jos.putNextEntry(new ZipEntry(e)); + jos.write(e.getBytes()); + } + jos.close(); + } finally { + out.close(); + } + return jar; + } + + File findRtJar() throws Exception { + File java_home = new File(System.getProperty("java.home")); + if (java_home.getName().equals("jre")) + java_home = java_home.getParentFile(); + File rt_jar = new File(new File(new File(java_home, "jre"), "lib"), "rt.jar"); + if (!rt_jar.exists()) + throw new Exception("can't find rt.jar"); + return rt_jar; + } + + byte[] read(InputStream in) throws IOException { + byte[] data = new byte[1024]; + int offset = 0; + try { + int n; + while ((n = in.read(data, offset, data.length - offset)) != -1) { + offset += n; + if (offset == data.length) + data = Arrays.copyOf(data, 2 * data.length); + } + } finally { + in.close(); + } + return Arrays.copyOf(data, offset); + } + + void writeFile(File f, String s) throws IOException { + f.getParentFile().mkdirs(); + FileWriter out = new FileWriter(f); + try { + out.write(s); + } finally { + out.close(); + } + } + + void error(String msg) { + System.err.println(msg); + errors++; + } + + int errors; +}
--- a/test/tools/javac/api/6440333/T6440333.java Mon Jun 21 11:43:28 2010 -0700 +++ b/test/tools/javac/api/6440333/T6440333.java Tue Jun 22 18:30:16 2010 -0700 @@ -26,7 +26,6 @@ * @bug 6440333 * @summary SimpleJavaFileObject.toString() generates URI with some extra message * @author Peter von der Ah\u00e9 - * @ignore 6877223 test ignored because of issues with File.toUri on Windows (6877206) * @library ../lib * @compile T6440333.java * @run main T6440333 @@ -34,6 +33,7 @@ import java.io.File; import java.io.IOException; +import java.net.URI; import javax.tools.JavaFileObject; public class T6440333 extends ToolTester { @@ -41,14 +41,10 @@ File path = test_src.getCanonicalFile(); File src = new File(new File(path, "."), "T6440333.java"); JavaFileObject fo = fm.getJavaFileObjects(src).iterator().next(); - String expect = src.getCanonicalFile().getPath().replace(File.separatorChar, '/'); + URI expect = src.getCanonicalFile().toURI(); System.err.println("Expect " + expect); - // CURRENTLY, the following line fails on Windows because a file C:/w/jjg/... - // returns a URI file://C/w/jjg... which incorrectly encodes the drive letter - // in the URI authority. This is against the spec that the authority is - // undefined and breaks the contract that new File(f.toURI()).equals(f.getAbsoluteFile()) - System.err.println("Got: " + fo.toUri().getPath()); - if (!expect.equals(fo.toUri().getPath())) { + System.err.println("Found " + fo.toUri()); + if (!expect.equals(fo.toUri())) { throw new AssertionError(); } }
--- a/test/tools/javac/api/6440528/T6440528.java Mon Jun 21 11:43:28 2010 -0700 +++ b/test/tools/javac/api/6440528/T6440528.java Tue Jun 22 18:30:16 2010 -0700 @@ -59,9 +59,9 @@ } private File getUnderlyingFile(Object o) throws Exception { - Field f = o.getClass().getDeclaredField("f"); - f.setAccessible(true); - return (File)f.get(o); + Field file = o.getClass().getDeclaredField("file"); + file.setAccessible(true); + return (File)file.get(o); } public static void main(String... args) throws Exception {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/api/6733837/T6733837.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,68 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6733837 + * @summary Compiler API ignores locale settings + * @author Maurizio Cimadamore + * @library ../lib + */ + +import java.io.StringWriter; +import java.io.PrintWriter; +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import static javax.tools.JavaFileObject.Kind; +import com.sun.source.util.JavacTask; + +public class T6733837 extends ToolTester { + + public static void main(String... args) { + new T6733837().exec(); + } + + public void exec() { + JavaFileObject sfo = new SimpleJavaFileObject(URI.create("myfo:/Test.java"),Kind.SOURCE) { + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return "\tclass ErroneousWithTab"; + } + }; + StringWriter sw = new StringWriter(); + PrintWriter out = new PrintWriter(sw); + List<? extends JavaFileObject> files = Arrays.asList(sfo); + task = tool.getTask(sw, fm, null, null, null, files); + try { + ((JavacTask)task).analyze(); + } + catch (Throwable t) { + throw new Error("Compiler threw an exception"); + } + System.err.println(sw.toString()); + if (!sw.toString().contains("/Test.java")) + throw new Error("Bad source name in diagnostic"); + } +}
--- a/test/tools/javac/api/Sibling.java Mon Jun 21 11:43:28 2010 -0700 +++ b/test/tools/javac/api/Sibling.java Tue Jun 22 18:30:16 2010 -0700 @@ -26,7 +26,6 @@ * @bug 6399602 * @summary Verify that files are created relative to sibling * @author Peter von der Ah\u00e9 - * @ignore 6877223 test ignored because of issues with File.toUri on Windows (6877206) */ import java.io.File; @@ -48,10 +47,9 @@ "foo.bar.baz.Test", CLASS, sibling); - String name = - new File("Test.class").getAbsolutePath().replace(File.separatorChar, '/'); - if (!classFile.toUri().getPath().equals(name)) - throw new AssertionError("Expected " + name + ", got " + - classFile.toUri().getPath()); + File file = new File("Test.class").getAbsoluteFile(); + if (!classFile.toUri().equals(file.toURI())) + throw new AssertionError("Expected " + file.toURI() + ", got " + + classFile.toUri()); } }
--- a/test/tools/javac/api/T6358786.java Mon Jun 21 11:43:28 2010 -0700 +++ b/test/tools/javac/api/T6358786.java Tue Jun 22 18:30:16 2010 -0700 @@ -30,7 +30,7 @@ */ import com.sun.tools.javac.api.JavacTaskImpl; -import com.sun.tools.javac.util.JavacFileManager; +import com.sun.tools.javac.file.JavacFileManager; import java.util.Arrays; import javax.lang.model.util.Elements;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/api/T6483788.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 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. + * + * 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. + */ + +/* + * @test + * @bug 6483788 + * @summary DefaultFileManager.ZipFileObject.toUri() fails to escape space characters + */ + +import java.io.*; +import java.net.*; +import java.util.Collections; +import java.util.jar.*; +import java.util.zip.*; +import javax.tools.*; + +public class T6483788 { + public static void main(String[] args) throws Exception { + new T6483788().run(); + } + + void run() throws Exception { + File jar = createJar(); + JavaCompiler c = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fm = c.getStandardFileManager(null, null, null); + fm.setLocation(StandardLocation.CLASS_PATH, Collections.singleton(jar)); + JavaFileObject fo = fm.getJavaFileForInput(StandardLocation.CLASS_PATH, "dummy", JavaFileObject.Kind.CLASS); + System.err.println("file: " + fo); + URI uri = fo.toUri(); + System.err.println("uri: " + uri); + if (uri.toString().contains(" ")) + throw new Exception("unexpected space character found"); + } + + File createJar() throws IOException { + byte[] dummy_data = new byte[10]; + File f = new File("a b.jar"); + OutputStream out = new FileOutputStream(f); + try { + JarOutputStream jar = new JarOutputStream(out); + jar.putNextEntry(new ZipEntry("dummy.class")); + jar.write(dummy_data); + jar.close(); + } finally { + out.close(); + } + return f; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/api/T6501502.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 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. + * + * 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. + */ + +/* + * @test + * @bug 6501502 6877206 6483788 + * @summary JSR 199: FileObject.toUri should return file:///c:/ or file:/c:/ not file://c:/ + */ + +import java.io.*; +import java.net.URI; +import javax.tools.*; + +public class T6501502 { + public static void main(String... args) throws Exception { + new T6501502().run(); + } + + // The spec for java.io.File includes the following: + // For a given abstract pathname f it is guaranteed that + // new File( f.toURI()).equals( f.getAbsoluteFile()) + // For JavaFileObject we test as follows: + // new File( CONVERT_TO_FILEOBJECT(f).toURI()).equals( f.getAbsoluteFile()) + // to verify that we get reasonable URIs returned from toURI. + // To make this a general test, and not just a Windows test, + // we test a number of platform-independent paths. + void run() throws Exception { + JavaCompiler c = ToolProvider.getSystemJavaCompiler(); + fm = c.getStandardFileManager(null, null, null); + System.err.println(System.getProperties()); + File tmpDir = new File(System.getProperty("java.io.tmpdir")); + File testSrcDir = new File(System.getProperty("test.src")); + File testClassesDir = new File(System.getProperty("test.classes")); + test(new File("abc.tmp")); + test(new File(tmpDir, "bad.file")); + test(new File(testSrcDir, "T6501501.java")); + test(new File(testClassesDir, "T6501501.class")); + test(new File("a b")); + } + + void test(File f) throws Exception { + System.err.println("test " + f); + FileObject fo = fm.getJavaFileObjects(f).iterator().next(); + URI uri = fo.toUri(); + System.err.println("FileObject uri: " + uri); + if (!new File(uri).equals(f.getAbsoluteFile())) + throw new Exception("unexpected URI returned"); + } + + StandardJavaFileManager fm; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/api/T6838467.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,249 @@ +/* + * Copyright (c) 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. + * + * 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. + */ + +/* + * @test + * @bug 6838467 + * @summary JSR199 FileObjects don't obey general contract of equals. + */ + +import java.io.*; +import java.util.*; +import java.util.zip.*; +import javax.tools.*; +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.util.Context; + +public class T6838467 { + boolean fileSystemIsCaseSignificant = !new File("a").equals(new File("A")); + + enum FileKind { + DIR("dir"), + ZIP("zip"), + ZIPFILEINDEX("zip"); + FileKind(String path) { + file = new File(path); + } + final File file; + }; + + enum CompareKind { + SAME { + File other(File f) { return f; } + }, + ABSOLUTE { + File other(File f) { return f.getAbsoluteFile(); } + }, + DIFFERENT { + File other(File f) { return new File("not_" + f.getPath()); } + }, + CASEEQUIV { + File other(File f) { return new File(f.getPath().toUpperCase()); } + }; + abstract File other(File f); + }; + + String[] paths = { "p/A.java", "p/B.java", "p/C.java" }; + + public static void main(String... args) throws Exception { + new T6838467().run(); + } + + void run() throws Exception { + // on Windows, verify file system is not case significant + if (System.getProperty("os.name").toLowerCase().startsWith("windows") + && fileSystemIsCaseSignificant) { + error("fileSystemIsCaseSignificant is set on Windows."); + } + + // create a set of directories and zip files to compare + createTestDir(new File("dir"), paths); + createTestDir(new File("not_dir"), paths); + createTestZip(new File("zip"), paths); + createTestZip(new File("not_zip"), paths); + if (fileSystemIsCaseSignificant) { + createTestDir(new File("DIR"), paths); + createTestZip(new File("ZIP"), paths); + } + + // test the various sorts of file objects that can be obtained from + // the file manager, and for various values that may or may not match. + for (FileKind fk: FileKind.values()) { + for (CompareKind ck: CompareKind.values()) { + test(fk, ck); + } + } + + // verify that the various different types of file object were all + // tested + Set<String> expectClasses = new HashSet<String>(Arrays.asList( + "RegularFileObject", "ZipFileObject", "ZipFileIndexFileObject" )); + if (!foundClasses.equals(expectClasses)) { + error("expected fileobject classes not found\n" + + "expected: " + expectClasses + "\n" + + "found: " + foundClasses); + } + + if (errors > 0) + throw new Exception(errors + " errors"); + } + + void test(FileKind fk, CompareKind ck) throws IOException { + File f1 = fk.file; + JavaFileManager fm1 = createFileManager(fk, f1); + + File f2 = ck.other(fk.file); + JavaFileManager fm2 = createFileManager(fk, f2); + + try { + // If the directories or zip files match, we expect "n" matches in + // the "n-squared" comparisons to come, where "n" is the number of + // entries in the the directories or zip files. + // If the directories or zip files don't themselves match, + // we obviously don't expect any of their contents to match either. + int expect = (f1.getAbsoluteFile().equals(f2.getAbsoluteFile()) ? paths.length : 0); + + System.err.println("test " + (++count) + " " + fk + " " + ck + " " + f1 + " " + f2); + test(fm1, fm2, expect); + + } finally { + fm1.close(); + fm2.close(); + } + } + + // For a pair of file managers that may or may not have similar entries + // on the classpath, compare all files returned from one against all files + // returned from the other. For each pair of files, verify that if they + // are equal, the hashcode is equal as well, and finally verify that the + // expected number of matches was found. + void test(JavaFileManager fm1, JavaFileManager fm2, int expectEqualCount) throws IOException { + boolean foundFiles1 = false; + boolean foundFiles2 = false; + int foundEqualCount = 0; + Set<JavaFileObject.Kind> kinds = EnumSet.allOf(JavaFileObject.Kind.class); + for (FileObject fo1: fm1.list(StandardLocation.CLASS_PATH, "p", kinds, false)) { + foundFiles1 = true; + foundClasses.add(fo1.getClass().getSimpleName()); + for (FileObject fo2: fm2.list(StandardLocation.CLASS_PATH, "p", kinds, false)) { + foundFiles2 = true; + foundClasses.add(fo1.getClass().getSimpleName()); + System.err.println("compare " + fo1 + " " + fo2); + if (fo1.equals(fo2)) { + foundEqualCount++; + int hash1 = fo1.hashCode(); + int hash2 = fo2.hashCode(); + if (hash1 != hash2) + error("hashCode error: " + fo1 + " [" + hash1 + "] " + + fo2 + " [" + hash2 + "]"); + } + } + } + if (!foundFiles1) + error("no files found for file manager 1"); + if (!foundFiles2) + error("no files found for file manager 2"); + // verify the expected number of matches were found + if (foundEqualCount != expectEqualCount) + error("expected matches not found: expected " + expectEqualCount + ", found " + foundEqualCount); + } + + // create a file manager to test a FileKind, with a given directory + // or zip file placed on the classpath + JavaFileManager createFileManager(FileKind fk, File classpath) throws IOException { + StandardJavaFileManager fm = createFileManager(fk == FileKind.ZIP); + fm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(classpath)); + return fm; + } + + JavacFileManager createFileManager(boolean useJavaUtilZip) { + // javac should really not be using system properties like this + // -- it should really be using (hidden) options -- but until then + // take care to leave system properties as we find them, so as not + // to adversely affect other tests that might follow. + String prev = System.getProperty("useJavaUtilZip"); + boolean resetProperties = false; + try { + if (useJavaUtilZip) { + System.setProperty("useJavaUtilZip", "true"); + resetProperties = true; + } else if (System.getProperty("useJavaUtilZip") != null) { + System.getProperties().remove("useJavaUtilZip"); + resetProperties = true; + } + + Context c = new Context(); + return new JavacFileManager(c, false, null); + } finally { + if (resetProperties) { + if (prev == null) { + System.getProperties().remove("useJavaUtilZip"); + } else { + System.setProperty("useJavaUtilZip", prev); + } + } + } + } + + // create a directory containing a given set of paths + void createTestDir(File dir, String[] paths) throws IOException { + for (String p: paths) { + File file = new File(dir, p); + file.getParentFile().mkdirs(); + FileWriter out = new FileWriter(file); + try { + out.write(p); + } finally { + out.close(); + } + } + } + + // create a sip file containing a given set of entries + void createTestZip(File zip, String[] paths) throws IOException { + if (zip.getParentFile() != null) + zip.getParentFile().mkdirs(); + ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zip)); + try { + for (String p: paths) { + ZipEntry ze = new ZipEntry(p); + zos.putNextEntry(ze); + byte[] bytes = p.getBytes(); + zos.write(bytes, 0, bytes.length); + zos.closeEntry(); + } + } finally { + zos.close(); + } + } + + void error(String msg) { + System.err.println("Error: " + msg); + errors++; + } + + int count; + int errors; + Set<String> foundClasses = new HashSet<String>(); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/api/T6877206.java Tue Jun 22 18:30:16 2010 -0700 @@ -0,0 +1,263 @@ +/* + * Copyright (c) 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. + * + * 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. + */ + +/* + * @test + * @bug 6877206 + * @summary JavaFileObject.toUri returns bogus URI (win) + */ + +import java.io.*; +import java.net.*; +import java.util.*; +import java.util.jar.*; +import java.util.zip.*; +import javax.tools.*; + +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Options; + +// Test URIs returned from JavacFileManager and its support classes. +// For a variety of file objects, verify the validity of FileObject.toUri() +// by verifying the URI exists and points to the same contents as the file +// object itself + +public class T6877206 { + public static void main(String... args) throws Exception { + new T6877206().run(); + } + + Set<String> foundClasses = new TreeSet<String>(); + Set<String> foundJars = new TreeSet<String>(); + + void run() throws Exception { + File rt_jar = findRtJar(); + + // names for entries to be created in directories and jar files + String[] entries = { "p/A.class", "p/resources/A-1.jpg" }; + + // test various combinations of directories and jar files, intended to + // cover all sources of URIs within JavacFileManager's support classes + + test(createFileManager(), createDir("dir", entries), "p", entries.length); + test(createFileManager(), createDir("a b/dir", entries), "p", entries.length); + + for (boolean useJavaUtilZip: new boolean[] { false, true }) { + test(createFileManager(useJavaUtilZip), createJar("jar", entries), "p", entries.length); + test(createFileManager(useJavaUtilZip), createJar("jar jar", entries), "p", entries.length); + + for (boolean useSymbolFile: new boolean[] { false, true }) { + test(createFileManager(useJavaUtilZip, useSymbolFile), rt_jar, "java.lang.ref", -1); + } + } + + // Verify that we hit all the impl classes we intended + checkCoverage("classes", foundClasses, + "RegularFileObject", "SymbolFileObject", "ZipFileIndexFileObject", "ZipFileObject"); + + // Verify that we hit the jar files we intended, specifically ct.sym as well as rt.jar + checkCoverage("jar files", foundJars, + "ct.sym", "jar", "jar jar", "rt.jar"); + } + + // use a new file manager for each test + void test(StandardJavaFileManager fm, File f, String pkg, int expect) throws Exception { + JarURLConnection c; + System.err.println("Test " + f); + try { + fm.setLocation(StandardLocation.CLASS_PATH, Collections.singleton(f)); + + int count = 0; + for (JavaFileObject fo: fm.list(StandardLocation.CLASS_PATH, + pkg, EnumSet.allOf(JavaFileObject.Kind.class), true)) { + System.err.println("checking " + fo); + // record the file object class name for coverage checks later + foundClasses.add(fo.getClass().getSimpleName()); + testFileObject(fo); + count++; + } + + if (expect > 0 && count != expect) + throw new Exception("wrong number of entries found: " + + count + ", expected " + expect); + } finally { + fm.close(); + } + } + + void testFileObject(JavaFileObject fo) throws Exception { + // test the validity of the result of toUri() by using URLConnection + // and comparing the results of reading from the connection with the + // result of reading from the file object directly. + URI uri = fo.toUri(); + System.err.println("uri: " + uri); + + URLConnection urlconn = uri.toURL().openConnection(); + if (urlconn instanceof JarURLConnection) { + JarURLConnection jarconn = (JarURLConnection) urlconn; + File f = new File(jarconn.getJarFile().getName()); + // record access to the jar file for coverage checks later + foundJars.add(f.getName()); + } + + try { + byte[] uriData = read(urlconn.getInputStream()); + byte[] foData = read(fo.openInputStream()); + if (!Arrays.equals(uriData, foData)) { + if (uriData.length != foData.length) + throw new Exception("data size differs: uri data " + + uriData.length + " bytes, fo data " + foData.length+ " bytes"); + for (int i = 0; i < uriData.length; i++) { + if (uriData[i] != foData[i]) + throw new Exception("unexpected data returned at offset " + i + + ", uri data " + uriData[i] + ", fo data " + foData[i]); + } + throw new AssertionError("cannot find difference"); + } + } finally { + // In principle, simply closing the result of urlconn.getInputStream() + // should have been sufficient. But the internal JarURLConnection + // does not close the JarFile in an expeditious manner, thus preventing + // jtreg from deleting the jar file before starting the next test. + // Therefore we force access to the JarURLConnection to close the + // JarFile when necessary. + if (urlconn instanceof JarURLConnection) { + JarURLConnection jarconn = (JarURLConnection) urlconn; + jarconn.getJarFile().close(); + } + } + } + + void checkCoverage(String label, Set<String> found, String... expect) throws Exception { + Set<String> e = new TreeSet<String>(Arrays.asList(expect)); + if (!found.equals(e)) { + e.removeAll(found); + throw new Exception("expected " + label + " not used: " + e); + } + } + + JavacFileManager createFileManager() { + return createFileManager(false, false); + } + + JavacFileManager createFileManager(boolean useJavaUtilZip) { + return createFileManager(useJavaUtilZip, false); + } + + JavacFileManager createFileManager(boolean useJavaUtilZip, boolean useSymbolFile) { + // javac should really not be using system properties like this + // -- it should really be using (hidden) options -- but until then + // take care to leave system properties as we find them, so as not + // to adversely affect other tests that might follow. + String prev = System.getProperty("useJavaUtilZip"); + boolean resetProperties = false; + try { + if (useJavaUtilZip) { + System.setProperty("useJavaUtilZip", "true"); + resetProperties = true; + } else if (System.getProperty("useJavaUtilZip") != null) { + System.getProperties().remove("useJavaUtilZip"); + resetProperties = true; + } + + Context c = new Context(); + if (!useSymbolFile) { + Options options = Options.instance(c); + options.put("ignore.symbol.file", "true"); + } + + return new JavacFileManager(c, false, null); + } finally { + if (resetProperties) { + if (prev == null) { + System.getProperties().remove("useJavaUtilZip"); + } else { + System.setProperty("useJavaUtilZip", prev); + } + } + } + } + + File createDir(String name, String... entries) throws Exception { + File dir = new File(name); + if (!dir.mkdirs()) + throw new Exception("cannot create directories " + dir); + for (String e: entries) { + writeFile(new File(dir, e), e); + } + return dir; + } + + File createJar(String name, String... entries) throws IOException { + File jar = new File(name); + OutputStream out = new FileOutputStream(jar); + try { + JarOutputStream jos = new JarOutputStream(out); + for (String e: entries) { + jos.putNextEntry(new ZipEntry(e)); + jos.write(e.getBytes()); + } + jos.close(); + } finally { + out.close(); + } + return jar; + } + + File findRtJar() throws Exception { + File java_home = new File(System.getProperty("java.home")); + if (java_home.getName().equals("jre")) + java_home = java_home.getParentFile(); + File rt_jar = new File(new File(new File(java_home, "jre"), "lib"), "rt.jar"); + if (!rt_jar.exists()) + throw new Exception("can't find rt.jar"); + return rt_jar; + } + + byte[] read(InputStream in) throws IOException { + byte[] data = new byte[1024]; + int offset = 0; + try { + int n; + while ((n = in.read(data, offset, data.length - offset)) != -1) { + offset += n; + if (offset == data.length) + data = Arrays.copyOf(data, 2 * data.length); + } + } finally { + in.close(); + } + return Arrays.copyOf(data, offset); + } + + void writeFile(File f, String s) throws IOException { + f.getParentFile().mkdirs(); + FileWriter out = new FileWriter(f); + try { + out.write(s); + } finally { + out.close(); + } + } +}
--- a/test/tools/javac/api/TestResolveIdent.java Mon Jun 21 11:43:28 2010 -0700 +++ b/test/tools/javac/api/TestResolveIdent.java Tue Jun 22 18:30:16 2010 -0700 @@ -30,8 +30,8 @@ */ import com.sun.tools.javac.api.JavacTaskImpl; +import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.JavaCompiler; -import com.sun.tools.javac.util.JavacFileManager; import java.io.File; import java.io.IOException; import javax.lang.model.element.TypeElement;
--- a/test/tools/javac/util/filemanager/TestName.java Mon Jun 21 11:43:28 2010 -0700 +++ b/test/tools/javac/util/filemanager/TestName.java Tue Jun 22 18:30:16 2010 -0700 @@ -29,7 +29,7 @@ * @author Peter von der Ah\u00e9 */ -import com.sun.tools.javac.util.JavacFileManager; +import com.sun.tools.javac.file.JavacFileManager; public class TestName { public static void main(String... args) {