src/share/classes/com/sun/tools/javac/file/JavacFileManager.java

Thu, 24 Nov 2011 13:36:20 +0000

author
mcimadamore
date
Thu, 24 Nov 2011 13:36:20 +0000
changeset 1142
c896d95e7469
parent 1116
d830d28fc72e
child 1358
fc123bdeddb8
permissions
-rw-r--r--

7115046: Add AST node for lambda expressions
Summary: Add tree nodes for representing lambda expressions and update relevant visitors interfaces
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javac.file;
    28 import java.io.ByteArrayOutputStream;
    29 import java.io.File;
    30 import java.io.FileNotFoundException;
    31 import java.io.IOException;
    32 import java.io.OutputStreamWriter;
    33 import java.net.MalformedURLException;
    34 import java.net.URI;
    35 import java.net.URISyntaxException;
    36 import java.net.URL;
    37 import java.nio.CharBuffer;
    38 import java.nio.charset.Charset;
    39 import java.util.ArrayList;
    40 import java.util.Arrays;
    41 import java.util.Collection;
    42 import java.util.Collections;
    43 import java.util.Comparator;
    44 import java.util.EnumSet;
    45 import java.util.HashMap;
    46 import java.util.Iterator;
    47 import java.util.Map;
    48 import java.util.Set;
    49 import java.util.zip.ZipFile;
    51 import javax.lang.model.SourceVersion;
    52 import javax.tools.FileObject;
    53 import javax.tools.JavaFileManager;
    54 import javax.tools.JavaFileObject;
    55 import javax.tools.StandardJavaFileManager;
    57 import com.sun.tools.javac.file.RelativePath.RelativeFile;
    58 import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
    59 import com.sun.tools.javac.util.BaseFileManager;
    60 import com.sun.tools.javac.util.Context;
    61 import com.sun.tools.javac.util.List;
    62 import com.sun.tools.javac.util.ListBuffer;
    64 import static javax.tools.StandardLocation.*;
    66 /**
    67  * This class provides access to the source, class and other files
    68  * used by the compiler and related tools.
    69  *
    70  * <p><b>This is NOT part of any supported API.
    71  * If you write code that depends on this, you do so at your own risk.
    72  * This code and its internal interfaces are subject to change or
    73  * deletion without notice.</b>
    74  */
    75 public class JavacFileManager extends BaseFileManager implements StandardJavaFileManager {
    77     public static char[] toArray(CharBuffer buffer) {
    78         if (buffer.hasArray())
    79             return ((CharBuffer)buffer.compact().flip()).array();
    80         else
    81             return buffer.toString().toCharArray();
    82     }
    84     private FSInfo fsInfo;
    86     private boolean contextUseOptimizedZip;
    87     private ZipFileIndexCache zipFileIndexCache;
    89     private final Set<JavaFileObject.Kind> sourceOrClass =
    90         EnumSet.of(JavaFileObject.Kind.SOURCE, JavaFileObject.Kind.CLASS);
    92     protected boolean mmappedIO;
    93     protected boolean ignoreSymbolFile;
    95     protected enum SortFiles implements Comparator<File> {
    96         FORWARD {
    97             public int compare(File f1, File f2) {
    98                 return f1.getName().compareTo(f2.getName());
    99             }
   100         },
   101         REVERSE {
   102             public int compare(File f1, File f2) {
   103                 return -f1.getName().compareTo(f2.getName());
   104             }
   105         };
   106     };
   107     protected SortFiles sortFiles;
   109     /**
   110      * Register a Context.Factory to create a JavacFileManager.
   111      */
   112     public static void preRegister(Context context) {
   113         context.put(JavaFileManager.class, new Context.Factory<JavaFileManager>() {
   114             public JavaFileManager make(Context c) {
   115                 return new JavacFileManager(c, true, null);
   116             }
   117         });
   118     }
   120     /**
   121      * Create a JavacFileManager using a given context, optionally registering
   122      * it as the JavaFileManager for that context.
   123      */
   124     public JavacFileManager(Context context, boolean register, Charset charset) {
   125         super(charset);
   126         if (register)
   127             context.put(JavaFileManager.class, this);
   128         setContext(context);
   129     }
   131     /**
   132      * Set the context for JavacFileManager.
   133      */
   134     @Override
   135     public void setContext(Context context) {
   136         super.setContext(context);
   138         fsInfo = FSInfo.instance(context);
   140         contextUseOptimizedZip = options.getBoolean("useOptimizedZip", true);
   141         if (contextUseOptimizedZip)
   142             zipFileIndexCache = ZipFileIndexCache.getSharedInstance();
   144         mmappedIO = options.isSet("mmappedIO");
   145         ignoreSymbolFile = options.isSet("ignore.symbol.file");
   147         String sf = options.get("sortFiles");
   148         if (sf != null) {
   149             sortFiles = (sf.equals("reverse") ? SortFiles.REVERSE : SortFiles.FORWARD);
   150         }
   151     }
   153     @Override
   154     public boolean isDefaultBootClassPath() {
   155         return locations.isDefaultBootClassPath();
   156     }
   158     public JavaFileObject getFileForInput(String name) {
   159         return getRegularFile(new File(name));
   160     }
   162     public JavaFileObject getRegularFile(File file) {
   163         return new RegularFileObject(this, file);
   164     }
   166     public JavaFileObject getFileForOutput(String classname,
   167                                            JavaFileObject.Kind kind,
   168                                            JavaFileObject sibling)
   169         throws IOException
   170     {
   171         return getJavaFileForOutput(CLASS_OUTPUT, classname, kind, sibling);
   172     }
   174     public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) {
   175         ListBuffer<File> files = new ListBuffer<File>();
   176         for (String name : names)
   177             files.append(new File(nullCheck(name)));
   178         return getJavaFileObjectsFromFiles(files.toList());
   179     }
   181     public Iterable<? extends JavaFileObject> getJavaFileObjects(String... names) {
   182         return getJavaFileObjectsFromStrings(Arrays.asList(nullCheck(names)));
   183     }
   185     private static boolean isValidName(String name) {
   186         // Arguably, isValidName should reject keywords (such as in SourceVersion.isName() ),
   187         // but the set of keywords depends on the source level, and we don't want
   188         // impls of JavaFileManager to have to be dependent on the source level.
   189         // Therefore we simply check that the argument is a sequence of identifiers
   190         // separated by ".".
   191         for (String s : name.split("\\.", -1)) {
   192             if (!SourceVersion.isIdentifier(s))
   193                 return false;
   194         }
   195         return true;
   196     }
   198     private static void validateClassName(String className) {
   199         if (!isValidName(className))
   200             throw new IllegalArgumentException("Invalid class name: " + className);
   201     }
   203     private static void validatePackageName(String packageName) {
   204         if (packageName.length() > 0 && !isValidName(packageName))
   205             throw new IllegalArgumentException("Invalid packageName name: " + packageName);
   206     }
   208     public static void testName(String name,
   209                                 boolean isValidPackageName,
   210                                 boolean isValidClassName)
   211     {
   212         try {
   213             validatePackageName(name);
   214             if (!isValidPackageName)
   215                 throw new AssertionError("Invalid package name accepted: " + name);
   216             printAscii("Valid package name: \"%s\"", name);
   217         } catch (IllegalArgumentException e) {
   218             if (isValidPackageName)
   219                 throw new AssertionError("Valid package name rejected: " + name);
   220             printAscii("Invalid package name: \"%s\"", name);
   221         }
   222         try {
   223             validateClassName(name);
   224             if (!isValidClassName)
   225                 throw new AssertionError("Invalid class name accepted: " + name);
   226             printAscii("Valid class name: \"%s\"", name);
   227         } catch (IllegalArgumentException e) {
   228             if (isValidClassName)
   229                 throw new AssertionError("Valid class name rejected: " + name);
   230             printAscii("Invalid class name: \"%s\"", name);
   231         }
   232     }
   234     private static void printAscii(String format, Object... args) {
   235         String message;
   236         try {
   237             final String ascii = "US-ASCII";
   238             message = new String(String.format(null, format, args).getBytes(ascii), ascii);
   239         } catch (java.io.UnsupportedEncodingException ex) {
   240             throw new AssertionError(ex);
   241         }
   242         System.out.println(message);
   243     }
   246     /**
   247      * Insert all files in subdirectory subdirectory of directory directory
   248      * which match fileKinds into resultList
   249      */
   250     private void listDirectory(File directory,
   251                                RelativeDirectory subdirectory,
   252                                Set<JavaFileObject.Kind> fileKinds,
   253                                boolean recurse,
   254                                ListBuffer<JavaFileObject> resultList) {
   255         File d = subdirectory.getFile(directory);
   256         if (!caseMapCheck(d, subdirectory))
   257             return;
   259         File[] files = d.listFiles();
   260         if (files == null)
   261             return;
   263         if (sortFiles != null)
   264             Arrays.sort(files, sortFiles);
   266         for (File f: files) {
   267             String fname = f.getName();
   268             if (f.isDirectory()) {
   269                 if (recurse && SourceVersion.isIdentifier(fname)) {
   270                     listDirectory(directory,
   271                                   new RelativeDirectory(subdirectory, fname),
   272                                   fileKinds,
   273                                   recurse,
   274                                   resultList);
   275                 }
   276             } else {
   277                 if (isValidFile(fname, fileKinds)) {
   278                     JavaFileObject fe =
   279                         new RegularFileObject(this, fname, new File(d, fname));
   280                     resultList.append(fe);
   281                 }
   282             }
   283         }
   284     }
   286     /**
   287      * Insert all files in subdirectory subdirectory of archive archive
   288      * which match fileKinds into resultList
   289      */
   290     private void listArchive(Archive archive,
   291                                RelativeDirectory subdirectory,
   292                                Set<JavaFileObject.Kind> fileKinds,
   293                                boolean recurse,
   294                                ListBuffer<JavaFileObject> resultList) {
   295         // Get the files directly in the subdir
   296         List<String> files = archive.getFiles(subdirectory);
   297         if (files != null) {
   298             for (; !files.isEmpty(); files = files.tail) {
   299                 String file = files.head;
   300                 if (isValidFile(file, fileKinds)) {
   301                     resultList.append(archive.getFileObject(subdirectory, file));
   302                 }
   303             }
   304         }
   305         if (recurse) {
   306             for (RelativeDirectory s: archive.getSubdirectories()) {
   307                 if (subdirectory.contains(s)) {
   308                     // Because the archive map is a flat list of directories,
   309                     // the enclosing loop will pick up all child subdirectories.
   310                     // Therefore, there is no need to recurse deeper.
   311                     listArchive(archive, s, fileKinds, false, resultList);
   312                 }
   313             }
   314         }
   315     }
   317     /**
   318      * container is a directory, a zip file, or a non-existant path.
   319      * Insert all files in subdirectory subdirectory of container which
   320      * match fileKinds into resultList
   321      */
   322     private void listContainer(File container,
   323                                RelativeDirectory subdirectory,
   324                                Set<JavaFileObject.Kind> fileKinds,
   325                                boolean recurse,
   326                                ListBuffer<JavaFileObject> resultList) {
   327         Archive archive = archives.get(container);
   328         if (archive == null) {
   329             // archives are not created for directories.
   330             if  (fsInfo.isDirectory(container)) {
   331                 listDirectory(container,
   332                               subdirectory,
   333                               fileKinds,
   334                               recurse,
   335                               resultList);
   336                 return;
   337             }
   339             // Not a directory; either a file or non-existant, create the archive
   340             try {
   341                 archive = openArchive(container);
   342             } catch (IOException ex) {
   343                 log.error("error.reading.file",
   344                           container, getMessage(ex));
   345                 return;
   346             }
   347         }
   348         listArchive(archive,
   349                     subdirectory,
   350                     fileKinds,
   351                     recurse,
   352                     resultList);
   353     }
   355     private boolean isValidFile(String s, Set<JavaFileObject.Kind> fileKinds) {
   356         JavaFileObject.Kind kind = getKind(s);
   357         return fileKinds.contains(kind);
   358     }
   360     private static final boolean fileSystemIsCaseSensitive =
   361         File.separatorChar == '/';
   363     /** Hack to make Windows case sensitive. Test whether given path
   364      *  ends in a string of characters with the same case as given name.
   365      *  Ignore file separators in both path and name.
   366      */
   367     private boolean caseMapCheck(File f, RelativePath name) {
   368         if (fileSystemIsCaseSensitive) return true;
   369         // Note that getCanonicalPath() returns the case-sensitive
   370         // spelled file name.
   371         String path;
   372         try {
   373             path = f.getCanonicalPath();
   374         } catch (IOException ex) {
   375             return false;
   376         }
   377         char[] pcs = path.toCharArray();
   378         char[] ncs = name.path.toCharArray();
   379         int i = pcs.length - 1;
   380         int j = ncs.length - 1;
   381         while (i >= 0 && j >= 0) {
   382             while (i >= 0 && pcs[i] == File.separatorChar) i--;
   383             while (j >= 0 && ncs[j] == '/') j--;
   384             if (i >= 0 && j >= 0) {
   385                 if (pcs[i] != ncs[j]) return false;
   386                 i--;
   387                 j--;
   388             }
   389         }
   390         return j < 0;
   391     }
   393     /**
   394      * An archive provides a flat directory structure of a ZipFile by
   395      * mapping directory names to lists of files (basenames).
   396      */
   397     public interface Archive {
   398         void close() throws IOException;
   400         boolean contains(RelativePath name);
   402         JavaFileObject getFileObject(RelativeDirectory subdirectory, String file);
   404         List<String> getFiles(RelativeDirectory subdirectory);
   406         Set<RelativeDirectory> getSubdirectories();
   407     }
   409     public class MissingArchive implements Archive {
   410         final File zipFileName;
   411         public MissingArchive(File name) {
   412             zipFileName = name;
   413         }
   414         public boolean contains(RelativePath name) {
   415             return false;
   416         }
   418         public void close() {
   419         }
   421         public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
   422             return null;
   423         }
   425         public List<String> getFiles(RelativeDirectory subdirectory) {
   426             return List.nil();
   427         }
   429         public Set<RelativeDirectory> getSubdirectories() {
   430             return Collections.emptySet();
   431         }
   433         @Override
   434         public String toString() {
   435             return "MissingArchive[" + zipFileName + "]";
   436         }
   437     }
   439     /** A directory of zip files already opened.
   440      */
   441     Map<File, Archive> archives = new HashMap<File,Archive>();
   443     private static final String[] symbolFileLocation = { "lib", "ct.sym" };
   444     private static final RelativeDirectory symbolFilePrefix
   445             = new RelativeDirectory("META-INF/sym/rt.jar/");
   447     /*
   448      * This method looks for a ZipFormatException and takes appropriate
   449      * evasive action. If there is a failure in the fast mode then we
   450      * fail over to the platform zip, and allow it to deal with a potentially
   451      * non compliant zip file.
   452      */
   453     protected Archive openArchive(File zipFilename) throws IOException {
   454         try {
   455             return openArchive(zipFilename, contextUseOptimizedZip);
   456         } catch (IOException ioe) {
   457             if (ioe instanceof ZipFileIndex.ZipFormatException) {
   458                 return openArchive(zipFilename, false);
   459             } else {
   460                 throw ioe;
   461             }
   462         }
   463     }
   465     /** Open a new zip file directory, and cache it.
   466      */
   467     private Archive openArchive(File zipFileName, boolean useOptimizedZip) throws IOException {
   468         File origZipFileName = zipFileName;
   469         if (!ignoreSymbolFile && locations.isDefaultBootClassPathRtJar(zipFileName)) {
   470             File file = zipFileName.getParentFile().getParentFile(); // ${java.home}
   471             if (new File(file.getName()).equals(new File("jre")))
   472                 file = file.getParentFile();
   473             // file == ${jdk.home}
   474             for (String name : symbolFileLocation)
   475                 file = new File(file, name);
   476             // file == ${jdk.home}/lib/ct.sym
   477             if (file.exists())
   478                 zipFileName = file;
   479         }
   481         Archive archive;
   482         try {
   484             ZipFile zdir = null;
   486             boolean usePreindexedCache = false;
   487             String preindexCacheLocation = null;
   489             if (!useOptimizedZip) {
   490                 zdir = new ZipFile(zipFileName);
   491             } else {
   492                 usePreindexedCache = options.isSet("usezipindex");
   493                 preindexCacheLocation = options.get("java.io.tmpdir");
   494                 String optCacheLoc = options.get("cachezipindexdir");
   496                 if (optCacheLoc != null && optCacheLoc.length() != 0) {
   497                     if (optCacheLoc.startsWith("\"")) {
   498                         if (optCacheLoc.endsWith("\"")) {
   499                             optCacheLoc = optCacheLoc.substring(1, optCacheLoc.length() - 1);
   500                         }
   501                         else {
   502                             optCacheLoc = optCacheLoc.substring(1);
   503                         }
   504                     }
   506                     File cacheDir = new File(optCacheLoc);
   507                     if (cacheDir.exists() && cacheDir.canWrite()) {
   508                         preindexCacheLocation = optCacheLoc;
   509                         if (!preindexCacheLocation.endsWith("/") &&
   510                             !preindexCacheLocation.endsWith(File.separator)) {
   511                             preindexCacheLocation += File.separator;
   512                         }
   513                     }
   514                 }
   515             }
   517             if (origZipFileName == zipFileName) {
   518                 if (!useOptimizedZip) {
   519                     archive = new ZipArchive(this, zdir);
   520                 } else {
   521                     archive = new ZipFileIndexArchive(this,
   522                                     zipFileIndexCache.getZipFileIndex(zipFileName,
   523                                     null,
   524                                     usePreindexedCache,
   525                                     preindexCacheLocation,
   526                                     options.isSet("writezipindexfiles")));
   527                 }
   528             } else {
   529                 if (!useOptimizedZip) {
   530                     archive = new SymbolArchive(this, origZipFileName, zdir, symbolFilePrefix);
   531                 } else {
   532                     archive = new ZipFileIndexArchive(this,
   533                                     zipFileIndexCache.getZipFileIndex(zipFileName,
   534                                     symbolFilePrefix,
   535                                     usePreindexedCache,
   536                                     preindexCacheLocation,
   537                                     options.isSet("writezipindexfiles")));
   538                 }
   539             }
   540         } catch (FileNotFoundException ex) {
   541             archive = new MissingArchive(zipFileName);
   542         } catch (ZipFileIndex.ZipFormatException zfe) {
   543             throw zfe;
   544         } catch (IOException ex) {
   545             if (zipFileName.exists())
   546                 log.error("error.reading.file", zipFileName, getMessage(ex));
   547             archive = new MissingArchive(zipFileName);
   548         }
   550         archives.put(origZipFileName, archive);
   551         return archive;
   552     }
   554     /** Flush any output resources.
   555      */
   556     public void flush() {
   557         contentCache.clear();
   558     }
   560     /**
   561      * Close the JavaFileManager, releasing resources.
   562      */
   563     public void close() {
   564         for (Iterator<Archive> i = archives.values().iterator(); i.hasNext(); ) {
   565             Archive a = i.next();
   566             i.remove();
   567             try {
   568                 a.close();
   569             } catch (IOException e) {
   570             }
   571         }
   572     }
   574     private String defaultEncodingName;
   575     private String getDefaultEncodingName() {
   576         if (defaultEncodingName == null) {
   577             defaultEncodingName =
   578                 new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding();
   579         }
   580         return defaultEncodingName;
   581     }
   583     public ClassLoader getClassLoader(Location location) {
   584         nullCheck(location);
   585         Iterable<? extends File> path = getLocation(location);
   586         if (path == null)
   587             return null;
   588         ListBuffer<URL> lb = new ListBuffer<URL>();
   589         for (File f: path) {
   590             try {
   591                 lb.append(f.toURI().toURL());
   592             } catch (MalformedURLException e) {
   593                 throw new AssertionError(e);
   594             }
   595         }
   597         return getClassLoader(lb.toArray(new URL[lb.size()]));
   598     }
   600     public Iterable<JavaFileObject> list(Location location,
   601                                          String packageName,
   602                                          Set<JavaFileObject.Kind> kinds,
   603                                          boolean recurse)
   604         throws IOException
   605     {
   606         // validatePackageName(packageName);
   607         nullCheck(packageName);
   608         nullCheck(kinds);
   610         Iterable<? extends File> path = getLocation(location);
   611         if (path == null)
   612             return List.nil();
   613         RelativeDirectory subdirectory = RelativeDirectory.forPackage(packageName);
   614         ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
   616         for (File directory : path)
   617             listContainer(directory, subdirectory, kinds, recurse, results);
   618         return results.toList();
   619     }
   621     public String inferBinaryName(Location location, JavaFileObject file) {
   622         file.getClass(); // null check
   623         location.getClass(); // null check
   624         // Need to match the path semantics of list(location, ...)
   625         Iterable<? extends File> path = getLocation(location);
   626         if (path == null) {
   627             return null;
   628         }
   630         if (file instanceof BaseFileObject) {
   631             return ((BaseFileObject) file).inferBinaryName(path);
   632         } else
   633             throw new IllegalArgumentException(file.getClass().getName());
   634     }
   636     public boolean isSameFile(FileObject a, FileObject b) {
   637         nullCheck(a);
   638         nullCheck(b);
   639         if (!(a instanceof BaseFileObject))
   640             throw new IllegalArgumentException("Not supported: " + a);
   641         if (!(b instanceof BaseFileObject))
   642             throw new IllegalArgumentException("Not supported: " + b);
   643         return a.equals(b);
   644     }
   646     public boolean hasLocation(Location location) {
   647         return getLocation(location) != null;
   648     }
   650     public JavaFileObject getJavaFileForInput(Location location,
   651                                               String className,
   652                                               JavaFileObject.Kind kind)
   653         throws IOException
   654     {
   655         nullCheck(location);
   656         // validateClassName(className);
   657         nullCheck(className);
   658         nullCheck(kind);
   659         if (!sourceOrClass.contains(kind))
   660             throw new IllegalArgumentException("Invalid kind: " + kind);
   661         return getFileForInput(location, RelativeFile.forClass(className, kind));
   662     }
   664     public FileObject getFileForInput(Location location,
   665                                       String packageName,
   666                                       String relativeName)
   667         throws IOException
   668     {
   669         nullCheck(location);
   670         // validatePackageName(packageName);
   671         nullCheck(packageName);
   672         if (!isRelativeUri(relativeName))
   673             throw new IllegalArgumentException("Invalid relative name: " + relativeName);
   674         RelativeFile name = packageName.length() == 0
   675             ? new RelativeFile(relativeName)
   676             : new RelativeFile(RelativeDirectory.forPackage(packageName), relativeName);
   677         return getFileForInput(location, name);
   678     }
   680     private JavaFileObject getFileForInput(Location location, RelativeFile name) throws IOException {
   681         Iterable<? extends File> path = getLocation(location);
   682         if (path == null)
   683             return null;
   685         for (File dir: path) {
   686             Archive a = archives.get(dir);
   687             if (a == null) {
   688                 if (fsInfo.isDirectory(dir)) {
   689                     File f = name.getFile(dir);
   690                     if (f.exists())
   691                         return new RegularFileObject(this, f);
   692                     continue;
   693                 }
   694                 // Not a directory, create the archive
   695                 a = openArchive(dir);
   696             }
   697             // Process the archive
   698             if (a.contains(name)) {
   699                 return a.getFileObject(name.dirname(), name.basename());
   700             }
   701         }
   702         return null;
   703     }
   705     public JavaFileObject getJavaFileForOutput(Location location,
   706                                                String className,
   707                                                JavaFileObject.Kind kind,
   708                                                FileObject sibling)
   709         throws IOException
   710     {
   711         nullCheck(location);
   712         // validateClassName(className);
   713         nullCheck(className);
   714         nullCheck(kind);
   715         if (!sourceOrClass.contains(kind))
   716             throw new IllegalArgumentException("Invalid kind: " + kind);
   717         return getFileForOutput(location, RelativeFile.forClass(className, kind), sibling);
   718     }
   720     public FileObject getFileForOutput(Location location,
   721                                        String packageName,
   722                                        String relativeName,
   723                                        FileObject sibling)
   724         throws IOException
   725     {
   726         nullCheck(location);
   727         // validatePackageName(packageName);
   728         nullCheck(packageName);
   729         if (!isRelativeUri(relativeName))
   730             throw new IllegalArgumentException("Invalid relative name: " + relativeName);
   731         RelativeFile name = packageName.length() == 0
   732             ? new RelativeFile(relativeName)
   733             : new RelativeFile(RelativeDirectory.forPackage(packageName), relativeName);
   734         return getFileForOutput(location, name, sibling);
   735     }
   737     private JavaFileObject getFileForOutput(Location location,
   738                                             RelativeFile fileName,
   739                                             FileObject sibling)
   740         throws IOException
   741     {
   742         File dir;
   743         if (location == CLASS_OUTPUT) {
   744             if (getClassOutDir() != null) {
   745                 dir = getClassOutDir();
   746             } else {
   747                 File siblingDir = null;
   748                 if (sibling != null && sibling instanceof RegularFileObject) {
   749                     siblingDir = ((RegularFileObject)sibling).file.getParentFile();
   750                 }
   751                 return new RegularFileObject(this, new File(siblingDir, fileName.basename()));
   752             }
   753         } else if (location == SOURCE_OUTPUT) {
   754             dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir());
   755         } else {
   756             Iterable<? extends File> path = locations.getLocation(location);
   757             dir = null;
   758             for (File f: path) {
   759                 dir = f;
   760                 break;
   761             }
   762         }
   764         File file = fileName.getFile(dir); // null-safe
   765         return new RegularFileObject(this, file);
   767     }
   769     public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(
   770         Iterable<? extends File> files)
   771     {
   772         ArrayList<RegularFileObject> result;
   773         if (files instanceof Collection<?>)
   774             result = new ArrayList<RegularFileObject>(((Collection<?>)files).size());
   775         else
   776             result = new ArrayList<RegularFileObject>();
   777         for (File f: files)
   778             result.add(new RegularFileObject(this, nullCheck(f)));
   779         return result;
   780     }
   782     public Iterable<? extends JavaFileObject> getJavaFileObjects(File... files) {
   783         return getJavaFileObjectsFromFiles(Arrays.asList(nullCheck(files)));
   784     }
   786     public void setLocation(Location location,
   787                             Iterable<? extends File> path)
   788         throws IOException
   789     {
   790         nullCheck(location);
   791         locations.setLocation(location, path);
   792     }
   794     public Iterable<? extends File> getLocation(Location location) {
   795         nullCheck(location);
   796         return locations.getLocation(location);
   797     }
   799     private File getClassOutDir() {
   800         return locations.getOutputLocation(CLASS_OUTPUT);
   801     }
   803     private File getSourceOutDir() {
   804         return locations.getOutputLocation(SOURCE_OUTPUT);
   805     }
   807     /**
   808      * Enforces the specification of a "relative" URI as used in
   809      * {@linkplain #getFileForInput(Location,String,URI)
   810      * getFileForInput}.  This method must follow the rules defined in
   811      * that method, do not make any changes without consulting the
   812      * specification.
   813      */
   814     protected static boolean isRelativeUri(URI uri) {
   815         if (uri.isAbsolute())
   816             return false;
   817         String path = uri.normalize().getPath();
   818         if (path.length() == 0 /* isEmpty() is mustang API */)
   819             return false;
   820         if (!path.equals(uri.getPath())) // implicitly checks for embedded . and ..
   821             return false;
   822         if (path.startsWith("/") || path.startsWith("./") || path.startsWith("../"))
   823             return false;
   824         return true;
   825     }
   827     // Convenience method
   828     protected static boolean isRelativeUri(String u) {
   829         try {
   830             return isRelativeUri(new URI(u));
   831         } catch (URISyntaxException e) {
   832             return false;
   833         }
   834     }
   836     /**
   837      * Converts a relative file name to a relative URI.  This is
   838      * different from File.toURI as this method does not canonicalize
   839      * the file before creating the URI.  Furthermore, no schema is
   840      * used.
   841      * @param file a relative file name
   842      * @return a relative URI
   843      * @throws IllegalArgumentException if the file name is not
   844      * relative according to the definition given in {@link
   845      * javax.tools.JavaFileManager#getFileForInput}
   846      */
   847     public static String getRelativeName(File file) {
   848         if (!file.isAbsolute()) {
   849             String result = file.getPath().replace(File.separatorChar, '/');
   850             if (isRelativeUri(result))
   851                 return result;
   852         }
   853         throw new IllegalArgumentException("Invalid relative path: " + file);
   854     }
   856     /**
   857      * Get a detail message from an IOException.
   858      * Most, but not all, instances of IOException provide a non-null result
   859      * for getLocalizedMessage().  But some instances return null: in these
   860      * cases, fallover to getMessage(), and if even that is null, return the
   861      * name of the exception itself.
   862      * @param e an IOException
   863      * @return a string to include in a compiler diagnostic
   864      */
   865     public static String getMessage(IOException e) {
   866         String s = e.getLocalizedMessage();
   867         if (s != null)
   868             return s;
   869         s = e.getMessage();
   870         if (s != null)
   871             return s;
   872         return e.toString();
   873     }
   874 }

mercurial