Home » openjdk-7 » com.sun.tools » javac » file » [javadoc | source]

    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    */
   25   
   26   package com.sun.tools.javac.file;
   27   
   28   import java.util.Comparator;
   29   import java.io.ByteArrayOutputStream;
   30   import java.io.File;
   31   import java.io.FileNotFoundException;
   32   import java.io.IOException;
   33   import java.io.OutputStreamWriter;
   34   import java.net.MalformedURLException;
   35   import java.net.URI;
   36   import java.net.URISyntaxException;
   37   import java.net.URL;
   38   import java.nio.CharBuffer;
   39   import java.nio.charset.Charset;
   40   import java.util.ArrayList;
   41   import java.util.Arrays;
   42   import java.util.Collection;
   43   import java.util.Collections;
   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;
   50   
   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;
   56   
   57   import com.sun.tools.javac.file.RelativePath.RelativeFile;
   58   import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
   59   import com.sun.tools.javac.main.OptionName;
   60   import com.sun.tools.javac.util.BaseFileManager;
   61   import com.sun.tools.javac.util.Context;
   62   import com.sun.tools.javac.util.List;
   63   import com.sun.tools.javac.util.ListBuffer;
   64   
   65   import static javax.tools.StandardLocation.*;
   66   import static com.sun.tools.javac.main.OptionName.*;
   67   
   68   /**
   69    * This class provides access to the source, class and other files
   70    * used by the compiler and related tools.
   71    *
   72    * <p><b>This is NOT part of any supported API.
   73    * If you write code that depends on this, you do so at your own risk.
   74    * This code and its internal interfaces are subject to change or
   75    * deletion without notice.</b>
   76    */
   77   public class JavacFileManager extends BaseFileManager implements StandardJavaFileManager {
   78   
   79       public static char[] toArray(CharBuffer buffer) {
   80           if (buffer.hasArray())
   81               return ((CharBuffer)buffer.compact().flip()).array();
   82           else
   83               return buffer.toString().toCharArray();
   84       }
   85   
   86       /** Encapsulates knowledge of paths
   87        */
   88       private Paths paths;
   89   
   90       private FSInfo fsInfo;
   91   
   92       private boolean contextUseOptimizedZip;
   93       private ZipFileIndexCache zipFileIndexCache;
   94   
   95       private final File uninited = new File("U N I N I T E D");
   96   
   97       private final Set<JavaFileObject.Kind> sourceOrClass =
   98           EnumSet.of(JavaFileObject.Kind.SOURCE, JavaFileObject.Kind.CLASS);
   99   
  100       /** The standard output directory, primarily used for classes.
  101        *  Initialized by the "-d" option.
  102        *  If classOutDir = null, files are written into same directory as the sources
  103        *  they were generated from.
  104        */
  105       private File classOutDir = uninited;
  106   
  107       /** The output directory, used when generating sources while processing annotations.
  108        *  Initialized by the "-s" option.
  109        */
  110       private File sourceOutDir = uninited;
  111   
  112       protected boolean mmappedIO;
  113       protected boolean ignoreSymbolFile;
  114   
  115       protected enum SortFiles implements Comparator<File> {
  116           FORWARD {
  117               public int compare(File f1, File f2) {
  118                   return f1.getName().compareTo(f2.getName());
  119               }
  120           },
  121           REVERSE {
  122               public int compare(File f1, File f2) {
  123                   return -f1.getName().compareTo(f2.getName());
  124               }
  125           };
  126       };
  127       protected SortFiles sortFiles;
  128   
  129       /**
  130        * Register a Context.Factory to create a JavacFileManager.
  131        */
  132       public static void preRegister(Context context) {
  133           context.put(JavaFileManager.class, new Context.Factory<JavaFileManager>() {
  134               public JavaFileManager make(Context c) {
  135                   return new JavacFileManager(c, true, null);
  136               }
  137           });
  138       }
  139   
  140       /**
  141        * Create a JavacFileManager using a given context, optionally registering
  142        * it as the JavaFileManager for that context.
  143        */
  144       public JavacFileManager(Context context, boolean register, Charset charset) {
  145           super(charset);
  146           if (register)
  147               context.put(JavaFileManager.class, this);
  148           setContext(context);
  149       }
  150   
  151       /**
  152        * Set the context for JavacFileManager.
  153        */
  154       @Override
  155       public void setContext(Context context) {
  156           super.setContext(context);
  157           if (paths == null) {
  158               paths = Paths.instance(context);
  159           } else {
  160               // Reuse the Paths object as it stores the locations that
  161               // have been set with setLocation, etc.
  162               paths.setContext(context);
  163           }
  164   
  165           fsInfo = FSInfo.instance(context);
  166   
  167           contextUseOptimizedZip = options.getBoolean("useOptimizedZip", true);
  168           if (contextUseOptimizedZip)
  169               zipFileIndexCache = ZipFileIndexCache.getSharedInstance();
  170   
  171           mmappedIO = options.isSet("mmappedIO");
  172           ignoreSymbolFile = options.isSet("ignore.symbol.file");
  173   
  174           String sf = options.get("sortFiles");
  175           if (sf != null) {
  176               sortFiles = (sf.equals("reverse") ? SortFiles.REVERSE : SortFiles.FORWARD);
  177           }
  178       }
  179   
  180       @Override
  181       public boolean isDefaultBootClassPath() {
  182           return paths.isDefaultBootClassPath();
  183       }
  184   
  185       public JavaFileObject getFileForInput(String name) {
  186           return getRegularFile(new File(name));
  187       }
  188   
  189       public JavaFileObject getRegularFile(File file) {
  190           return new RegularFileObject(this, file);
  191       }
  192   
  193       public JavaFileObject getFileForOutput(String classname,
  194                                              JavaFileObject.Kind kind,
  195                                              JavaFileObject sibling)
  196           throws IOException
  197       {
  198           return getJavaFileForOutput(CLASS_OUTPUT, classname, kind, sibling);
  199       }
  200   
  201       public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) {
  202           ListBuffer<File> files = new ListBuffer<File>();
  203           for (String name : names)
  204               files.append(new File(nullCheck(name)));
  205           return getJavaFileObjectsFromFiles(files.toList());
  206       }
  207   
  208       public Iterable<? extends JavaFileObject> getJavaFileObjects(String... names) {
  209           return getJavaFileObjectsFromStrings(Arrays.asList(nullCheck(names)));
  210       }
  211   
  212       private static boolean isValidName(String name) {
  213           // Arguably, isValidName should reject keywords (such as in SourceVersion.isName() ),
  214           // but the set of keywords depends on the source level, and we don't want
  215           // impls of JavaFileManager to have to be dependent on the source level.
  216           // Therefore we simply check that the argument is a sequence of identifiers
  217           // separated by ".".
  218           for (String s : name.split("\\.", -1)) {
  219               if (!SourceVersion.isIdentifier(s))
  220                   return false;
  221           }
  222           return true;
  223       }
  224   
  225       private static void validateClassName(String className) {
  226           if (!isValidName(className))
  227               throw new IllegalArgumentException("Invalid class name: " + className);
  228       }
  229   
  230       private static void validatePackageName(String packageName) {
  231           if (packageName.length() > 0 && !isValidName(packageName))
  232               throw new IllegalArgumentException("Invalid packageName name: " + packageName);
  233       }
  234   
  235       public static void testName(String name,
  236                                   boolean isValidPackageName,
  237                                   boolean isValidClassName)
  238       {
  239           try {
  240               validatePackageName(name);
  241               if (!isValidPackageName)
  242                   throw new AssertionError("Invalid package name accepted: " + name);
  243               printAscii("Valid package name: \"%s\"", name);
  244           } catch (IllegalArgumentException e) {
  245               if (isValidPackageName)
  246                   throw new AssertionError("Valid package name rejected: " + name);
  247               printAscii("Invalid package name: \"%s\"", name);
  248           }
  249           try {
  250               validateClassName(name);
  251               if (!isValidClassName)
  252                   throw new AssertionError("Invalid class name accepted: " + name);
  253               printAscii("Valid class name: \"%s\"", name);
  254           } catch (IllegalArgumentException e) {
  255               if (isValidClassName)
  256                   throw new AssertionError("Valid class name rejected: " + name);
  257               printAscii("Invalid class name: \"%s\"", name);
  258           }
  259       }
  260   
  261       private static void printAscii(String format, Object... args) {
  262           String message;
  263           try {
  264               final String ascii = "US-ASCII";
  265               message = new String(String.format(null, format, args).getBytes(ascii), ascii);
  266           } catch (java.io.UnsupportedEncodingException ex) {
  267               throw new AssertionError(ex);
  268           }
  269           System.out.println(message);
  270       }
  271   
  272   
  273       /**
  274        * Insert all files in subdirectory subdirectory of directory directory
  275        * which match fileKinds into resultList
  276        */
  277       private void listDirectory(File directory,
  278                                  RelativeDirectory subdirectory,
  279                                  Set<JavaFileObject.Kind> fileKinds,
  280                                  boolean recurse,
  281                                  ListBuffer<JavaFileObject> resultList) {
  282           File d = subdirectory.getFile(directory);
  283           if (!caseMapCheck(d, subdirectory))
  284               return;
  285   
  286           File[] files = d.listFiles();
  287           if (files == null)
  288               return;
  289   
  290           if (sortFiles != null)
  291               Arrays.sort(files, sortFiles);
  292   
  293           for (File f: files) {
  294               String fname = f.getName();
  295               if (f.isDirectory()) {
  296                   if (recurse && SourceVersion.isIdentifier(fname)) {
  297                       listDirectory(directory,
  298                                     new RelativeDirectory(subdirectory, fname),
  299                                     fileKinds,
  300                                     recurse,
  301                                     resultList);
  302                   }
  303               } else {
  304                   if (isValidFile(fname, fileKinds)) {
  305                       JavaFileObject fe =
  306                           new RegularFileObject(this, fname, new File(d, fname));
  307                       resultList.append(fe);
  308                   }
  309               }
  310           }
  311       }
  312   
  313       /**
  314        * Insert all files in subdirectory subdirectory of archive archive
  315        * which match fileKinds into resultList
  316        */
  317       private void listArchive(Archive archive,
  318                                  RelativeDirectory subdirectory,
  319                                  Set<JavaFileObject.Kind> fileKinds,
  320                                  boolean recurse,
  321                                  ListBuffer<JavaFileObject> resultList) {
  322           // Get the files directly in the subdir
  323           List<String> files = archive.getFiles(subdirectory);
  324           if (files != null) {
  325               for (; !files.isEmpty(); files = files.tail) {
  326                   String file = files.head;
  327                   if (isValidFile(file, fileKinds)) {
  328                       resultList.append(archive.getFileObject(subdirectory, file));
  329                   }
  330               }
  331           }
  332           if (recurse) {
  333               for (RelativeDirectory s: archive.getSubdirectories()) {
  334                   if (subdirectory.contains(s)) {
  335                       // Because the archive map is a flat list of directories,
  336                       // the enclosing loop will pick up all child subdirectories.
  337                       // Therefore, there is no need to recurse deeper.
  338                       listArchive(archive, s, fileKinds, false, resultList);
  339                   }
  340               }
  341           }
  342       }
  343   
  344       /**
  345        * container is a directory, a zip file, or a non-existant path.
  346        * Insert all files in subdirectory subdirectory of container which
  347        * match fileKinds into resultList
  348        */
  349       private void listContainer(File container,
  350                                  RelativeDirectory subdirectory,
  351                                  Set<JavaFileObject.Kind> fileKinds,
  352                                  boolean recurse,
  353                                  ListBuffer<JavaFileObject> resultList) {
  354           Archive archive = archives.get(container);
  355           if (archive == null) {
  356               // archives are not created for directories.
  357               if  (fsInfo.isDirectory(container)) {
  358                   listDirectory(container,
  359                                 subdirectory,
  360                                 fileKinds,
  361                                 recurse,
  362                                 resultList);
  363                   return;
  364               }
  365   
  366               // Not a directory; either a file or non-existant, create the archive
  367               try {
  368                   archive = openArchive(container);
  369               } catch (IOException ex) {
  370                   log.error("error.reading.file",
  371                             container, getMessage(ex));
  372                   return;
  373               }
  374           }
  375           listArchive(archive,
  376                       subdirectory,
  377                       fileKinds,
  378                       recurse,
  379                       resultList);
  380       }
  381   
  382       private boolean isValidFile(String s, Set<JavaFileObject.Kind> fileKinds) {
  383           JavaFileObject.Kind kind = getKind(s);
  384           return fileKinds.contains(kind);
  385       }
  386   
  387       private static final boolean fileSystemIsCaseSensitive =
  388           File.separatorChar == '/';
  389   
  390       /** Hack to make Windows case sensitive. Test whether given path
  391        *  ends in a string of characters with the same case as given name.
  392        *  Ignore file separators in both path and name.
  393        */
  394       private boolean caseMapCheck(File f, RelativePath name) {
  395           if (fileSystemIsCaseSensitive) return true;
  396           // Note that getCanonicalPath() returns the case-sensitive
  397           // spelled file name.
  398           String path;
  399           try {
  400               path = f.getCanonicalPath();
  401           } catch (IOException ex) {
  402               return false;
  403           }
  404           char[] pcs = path.toCharArray();
  405           char[] ncs = name.path.toCharArray();
  406           int i = pcs.length - 1;
  407           int j = ncs.length - 1;
  408           while (i >= 0 && j >= 0) {
  409               while (i >= 0 && pcs[i] == File.separatorChar) i--;
  410               while (j >= 0 && ncs[j] == '/') j--;
  411               if (i >= 0 && j >= 0) {
  412                   if (pcs[i] != ncs[j]) return false;
  413                   i--;
  414                   j--;
  415               }
  416           }
  417           return j < 0;
  418       }
  419   
  420       /**
  421        * An archive provides a flat directory structure of a ZipFile by
  422        * mapping directory names to lists of files (basenames).
  423        */
  424       public interface Archive {
  425           void close() throws IOException;
  426   
  427           boolean contains(RelativePath name);
  428   
  429           JavaFileObject getFileObject(RelativeDirectory subdirectory, String file);
  430   
  431           List<String> getFiles(RelativeDirectory subdirectory);
  432   
  433           Set<RelativeDirectory> getSubdirectories();
  434       }
  435   
  436       public class MissingArchive implements Archive {
  437           final File zipFileName;
  438           public MissingArchive(File name) {
  439               zipFileName = name;
  440           }
  441           public boolean contains(RelativePath name) {
  442               return false;
  443           }
  444   
  445           public void close() {
  446           }
  447   
  448           public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
  449               return null;
  450           }
  451   
  452           public List<String> getFiles(RelativeDirectory subdirectory) {
  453               return List.nil();
  454           }
  455   
  456           public Set<RelativeDirectory> getSubdirectories() {
  457               return Collections.emptySet();
  458           }
  459   
  460           @Override
  461           public String toString() {
  462               return "MissingArchive[" + zipFileName + "]";
  463           }
  464       }
  465   
  466       /** A directory of zip files already opened.
  467        */
  468       Map<File, Archive> archives = new HashMap<File,Archive>();
  469   
  470       private static final String[] symbolFileLocation = { "lib", "ct.sym" };
  471       private static final RelativeDirectory symbolFilePrefix
  472               = new RelativeDirectory("META-INF/sym/rt.jar/");
  473   
  474       /*
  475        * This method looks for a ZipFormatException and takes appropriate
  476        * evasive action. If there is a failure in the fast mode then we
  477        * fail over to the platform zip, and allow it to deal with a potentially
  478        * non compliant zip file.
  479        */
  480       protected Archive openArchive(File zipFilename) throws IOException {
  481           try {
  482               return openArchive(zipFilename, contextUseOptimizedZip);
  483           } catch (IOException ioe) {
  484               if (ioe instanceof ZipFileIndex.ZipFormatException) {
  485                   return openArchive(zipFilename, false);
  486               } else {
  487                   throw ioe;
  488               }
  489           }
  490       }
  491   
  492       /** Open a new zip file directory, and cache it.
  493        */
  494       private Archive openArchive(File zipFileName, boolean useOptimizedZip) throws IOException {
  495           File origZipFileName = zipFileName;
  496           if (!ignoreSymbolFile && paths.isDefaultBootClassPathRtJar(zipFileName)) {
  497               File file = zipFileName.getParentFile().getParentFile(); // ${java.home}
  498               if (new File(file.getName()).equals(new File("jre")))
  499                   file = file.getParentFile();
  500               // file == ${jdk.home}
  501               for (String name : symbolFileLocation)
  502                   file = new File(file, name);
  503               // file == ${jdk.home}/lib/ct.sym
  504               if (file.exists())
  505                   zipFileName = file;
  506           }
  507   
  508           Archive archive;
  509           try {
  510   
  511               ZipFile zdir = null;
  512   
  513               boolean usePreindexedCache = false;
  514               String preindexCacheLocation = null;
  515   
  516               if (!useOptimizedZip) {
  517                   zdir = new ZipFile(zipFileName);
  518               } else {
  519                   usePreindexedCache = options.isSet("usezipindex");
  520                   preindexCacheLocation = options.get("java.io.tmpdir");
  521                   String optCacheLoc = options.get("cachezipindexdir");
  522   
  523                   if (optCacheLoc != null && optCacheLoc.length() != 0) {
  524                       if (optCacheLoc.startsWith("\"")) {
  525                           if (optCacheLoc.endsWith("\"")) {
  526                               optCacheLoc = optCacheLoc.substring(1, optCacheLoc.length() - 1);
  527                           }
  528                           else {
  529                               optCacheLoc = optCacheLoc.substring(1);
  530                           }
  531                       }
  532   
  533                       File cacheDir = new File(optCacheLoc);
  534                       if (cacheDir.exists() && cacheDir.canWrite()) {
  535                           preindexCacheLocation = optCacheLoc;
  536                           if (!preindexCacheLocation.endsWith("/") &&
  537                               !preindexCacheLocation.endsWith(File.separator)) {
  538                               preindexCacheLocation += File.separator;
  539                           }
  540                       }
  541                   }
  542               }
  543   
  544               if (origZipFileName == zipFileName) {
  545                   if (!useOptimizedZip) {
  546                       archive = new ZipArchive(this, zdir);
  547                   } else {
  548                       archive = new ZipFileIndexArchive(this,
  549                                       zipFileIndexCache.getZipFileIndex(zipFileName,
  550                                       null,
  551                                       usePreindexedCache,
  552                                       preindexCacheLocation,
  553                                       options.isSet("writezipindexfiles")));
  554                   }
  555               } else {
  556                   if (!useOptimizedZip) {
  557                       archive = new SymbolArchive(this, origZipFileName, zdir, symbolFilePrefix);
  558                   } else {
  559                       archive = new ZipFileIndexArchive(this,
  560                                       zipFileIndexCache.getZipFileIndex(zipFileName,
  561                                       symbolFilePrefix,
  562                                       usePreindexedCache,
  563                                       preindexCacheLocation,
  564                                       options.isSet("writezipindexfiles")));
  565                   }
  566               }
  567           } catch (FileNotFoundException ex) {
  568               archive = new MissingArchive(zipFileName);
  569           } catch (ZipFileIndex.ZipFormatException zfe) {
  570               throw zfe;
  571           } catch (IOException ex) {
  572               if (zipFileName.exists())
  573                   log.error("error.reading.file", zipFileName, getMessage(ex));
  574               archive = new MissingArchive(zipFileName);
  575           }
  576   
  577           archives.put(origZipFileName, archive);
  578           return archive;
  579       }
  580   
  581       /** Flush any output resources.
  582        */
  583       public void flush() {
  584           contentCache.clear();
  585       }
  586   
  587       /**
  588        * Close the JavaFileManager, releasing resources.
  589        */
  590       public void close() {
  591           for (Iterator<Archive> i = archives.values().iterator(); i.hasNext(); ) {
  592               Archive a = i.next();
  593               i.remove();
  594               try {
  595                   a.close();
  596               } catch (IOException e) {
  597               }
  598           }
  599       }
  600   
  601       private String defaultEncodingName;
  602       private String getDefaultEncodingName() {
  603           if (defaultEncodingName == null) {
  604               defaultEncodingName =
  605                   new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding();
  606           }
  607           return defaultEncodingName;
  608       }
  609   
  610       public ClassLoader getClassLoader(Location location) {
  611           nullCheck(location);
  612           Iterable<? extends File> path = getLocation(location);
  613           if (path == null)
  614               return null;
  615           ListBuffer<URL> lb = new ListBuffer<URL>();
  616           for (File f: path) {
  617               try {
  618                   lb.append(f.toURI().toURL());
  619               } catch (MalformedURLException e) {
  620                   throw new AssertionError(e);
  621               }
  622           }
  623   
  624           return getClassLoader(lb.toArray(new URL[lb.size()]));
  625       }
  626   
  627       public Iterable<JavaFileObject> list(Location location,
  628                                            String packageName,
  629                                            Set<JavaFileObject.Kind> kinds,
  630                                            boolean recurse)
  631           throws IOException
  632       {
  633           // validatePackageName(packageName);
  634           nullCheck(packageName);
  635           nullCheck(kinds);
  636   
  637           Iterable<? extends File> path = getLocation(location);
  638           if (path == null)
  639               return List.nil();
  640           RelativeDirectory subdirectory = RelativeDirectory.forPackage(packageName);
  641           ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
  642   
  643           for (File directory : path)
  644               listContainer(directory, subdirectory, kinds, recurse, results);
  645           return results.toList();
  646       }
  647   
  648       public String inferBinaryName(Location location, JavaFileObject file) {
  649           file.getClass(); // null check
  650           location.getClass(); // null check
  651           // Need to match the path semantics of list(location, ...)
  652           Iterable<? extends File> path = getLocation(location);
  653           if (path == null) {
  654               return null;
  655           }
  656   
  657           if (file instanceof BaseFileObject) {
  658               return ((BaseFileObject) file).inferBinaryName(path);
  659           } else
  660               throw new IllegalArgumentException(file.getClass().getName());
  661       }
  662   
  663       public boolean isSameFile(FileObject a, FileObject b) {
  664           nullCheck(a);
  665           nullCheck(b);
  666           if (!(a instanceof BaseFileObject))
  667               throw new IllegalArgumentException("Not supported: " + a);
  668           if (!(b instanceof BaseFileObject))
  669               throw new IllegalArgumentException("Not supported: " + b);
  670           return a.equals(b);
  671       }
  672   
  673       public boolean hasLocation(Location location) {
  674           return getLocation(location) != null;
  675       }
  676   
  677       public JavaFileObject getJavaFileForInput(Location location,
  678                                                 String className,
  679                                                 JavaFileObject.Kind kind)
  680           throws IOException
  681       {
  682           nullCheck(location);
  683           // validateClassName(className);
  684           nullCheck(className);
  685           nullCheck(kind);
  686           if (!sourceOrClass.contains(kind))
  687               throw new IllegalArgumentException("Invalid kind: " + kind);
  688           return getFileForInput(location, RelativeFile.forClass(className, kind));
  689       }
  690   
  691       public FileObject getFileForInput(Location location,
  692                                         String packageName,
  693                                         String relativeName)
  694           throws IOException
  695       {
  696           nullCheck(location);
  697           // validatePackageName(packageName);
  698           nullCheck(packageName);
  699           if (!isRelativeUri(relativeName))
  700               throw new IllegalArgumentException("Invalid relative name: " + relativeName);
  701           RelativeFile name = packageName.length() == 0
  702               ? new RelativeFile(relativeName)
  703               : new RelativeFile(RelativeDirectory.forPackage(packageName), relativeName);
  704           return getFileForInput(location, name);
  705       }
  706   
  707       private JavaFileObject getFileForInput(Location location, RelativeFile name) throws IOException {
  708           Iterable<? extends File> path = getLocation(location);
  709           if (path == null)
  710               return null;
  711   
  712           for (File dir: path) {
  713               Archive a = archives.get(dir);
  714               if (a == null) {
  715                   if (fsInfo.isDirectory(dir)) {
  716                       File f = name.getFile(dir);
  717                       if (f.exists())
  718                           return new RegularFileObject(this, f);
  719                       continue;
  720                   }
  721                   // Not a directory, create the archive
  722                   a = openArchive(dir);
  723               }
  724               // Process the archive
  725               if (a.contains(name)) {
  726                   return a.getFileObject(name.dirname(), name.basename());
  727               }
  728           }
  729           return null;
  730       }
  731   
  732       public JavaFileObject getJavaFileForOutput(Location location,
  733                                                  String className,
  734                                                  JavaFileObject.Kind kind,
  735                                                  FileObject sibling)
  736           throws IOException
  737       {
  738           nullCheck(location);
  739           // validateClassName(className);
  740           nullCheck(className);
  741           nullCheck(kind);
  742           if (!sourceOrClass.contains(kind))
  743               throw new IllegalArgumentException("Invalid kind: " + kind);
  744           return getFileForOutput(location, RelativeFile.forClass(className, kind), sibling);
  745       }
  746   
  747       public FileObject getFileForOutput(Location location,
  748                                          String packageName,
  749                                          String relativeName,
  750                                          FileObject sibling)
  751           throws IOException
  752       {
  753           nullCheck(location);
  754           // validatePackageName(packageName);
  755           nullCheck(packageName);
  756           if (!isRelativeUri(relativeName))
  757               throw new IllegalArgumentException("Invalid relative name: " + relativeName);
  758           RelativeFile name = packageName.length() == 0
  759               ? new RelativeFile(relativeName)
  760               : new RelativeFile(RelativeDirectory.forPackage(packageName), relativeName);
  761           return getFileForOutput(location, name, sibling);
  762       }
  763   
  764       private JavaFileObject getFileForOutput(Location location,
  765                                               RelativeFile fileName,
  766                                               FileObject sibling)
  767           throws IOException
  768       {
  769           File dir;
  770           if (location == CLASS_OUTPUT) {
  771               if (getClassOutDir() != null) {
  772                   dir = getClassOutDir();
  773               } else {
  774                   File siblingDir = null;
  775                   if (sibling != null && sibling instanceof RegularFileObject) {
  776                       siblingDir = ((RegularFileObject)sibling).file.getParentFile();
  777                   }
  778                   return new RegularFileObject(this, new File(siblingDir, fileName.basename()));
  779               }
  780           } else if (location == SOURCE_OUTPUT) {
  781               dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir());
  782           } else {
  783               Iterable<? extends File> path = paths.getPathForLocation(location);
  784               dir = null;
  785               for (File f: path) {
  786                   dir = f;
  787                   break;
  788               }
  789           }
  790   
  791           File file = fileName.getFile(dir); // null-safe
  792           return new RegularFileObject(this, file);
  793   
  794       }
  795   
  796       public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(
  797           Iterable<? extends File> files)
  798       {
  799           ArrayList<RegularFileObject> result;
  800           if (files instanceof Collection<?>)
  801               result = new ArrayList<RegularFileObject>(((Collection<?>)files).size());
  802           else
  803               result = new ArrayList<RegularFileObject>();
  804           for (File f: files)
  805               result.add(new RegularFileObject(this, nullCheck(f)));
  806           return result;
  807       }
  808   
  809       public Iterable<? extends JavaFileObject> getJavaFileObjects(File... files) {
  810           return getJavaFileObjectsFromFiles(Arrays.asList(nullCheck(files)));
  811       }
  812   
  813       public void setLocation(Location location,
  814                               Iterable<? extends File> path)
  815           throws IOException
  816       {
  817           nullCheck(location);
  818           paths.lazy();
  819   
  820           final File dir = location.isOutputLocation() ? getOutputDirectory(path) : null;
  821   
  822           if (location == CLASS_OUTPUT)
  823               classOutDir = getOutputLocation(dir, D);
  824           else if (location == SOURCE_OUTPUT)
  825               sourceOutDir = getOutputLocation(dir, S);
  826           else
  827               paths.setPathForLocation(location, path);
  828       }
  829       // where
  830           private File getOutputDirectory(Iterable<? extends File> path) throws IOException {
  831               if (path == null)
  832                   return null;
  833               Iterator<? extends File> pathIter = path.iterator();
  834               if (!pathIter.hasNext())
  835                   throw new IllegalArgumentException("empty path for directory");
  836               File dir = pathIter.next();
  837               if (pathIter.hasNext())
  838                   throw new IllegalArgumentException("path too long for directory");
  839               if (!dir.exists())
  840                   throw new FileNotFoundException(dir + ": does not exist");
  841               else if (!dir.isDirectory())
  842                   throw new IOException(dir + ": not a directory");
  843               return dir;
  844           }
  845   
  846       private File getOutputLocation(File dir, OptionName defaultOptionName) {
  847           if (dir != null)
  848               return dir;
  849           String arg = options.get(defaultOptionName);
  850           if (arg == null)
  851               return null;
  852           return new File(arg);
  853       }
  854   
  855       public Iterable<? extends File> getLocation(Location location) {
  856           nullCheck(location);
  857           paths.lazy();
  858           if (location == CLASS_OUTPUT) {
  859               return (getClassOutDir() == null ? null : List.of(getClassOutDir()));
  860           } else if (location == SOURCE_OUTPUT) {
  861               return (getSourceOutDir() == null ? null : List.of(getSourceOutDir()));
  862           } else
  863               return paths.getPathForLocation(location);
  864       }
  865   
  866       private File getClassOutDir() {
  867           if (classOutDir == uninited)
  868               classOutDir = getOutputLocation(null, D);
  869           return classOutDir;
  870       }
  871   
  872       private File getSourceOutDir() {
  873           if (sourceOutDir == uninited)
  874               sourceOutDir = getOutputLocation(null, S);
  875           return sourceOutDir;
  876       }
  877   
  878       /**
  879        * Enforces the specification of a "relative" URI as used in
  880        * {@linkplain #getFileForInput(Location,String,URI)
  881        * getFileForInput}.  This method must follow the rules defined in
  882        * that method, do not make any changes without consulting the
  883        * specification.
  884        */
  885       protected static boolean isRelativeUri(URI uri) {
  886           if (uri.isAbsolute())
  887               return false;
  888           String path = uri.normalize().getPath();
  889           if (path.length() == 0 /* isEmpty() is mustang API */)
  890               return false;
  891           if (!path.equals(uri.getPath())) // implicitly checks for embedded . and ..
  892               return false;
  893           if (path.startsWith("/") || path.startsWith("./") || path.startsWith("../"))
  894               return false;
  895           return true;
  896       }
  897   
  898       // Convenience method
  899       protected static boolean isRelativeUri(String u) {
  900           try {
  901               return isRelativeUri(new URI(u));
  902           } catch (URISyntaxException e) {
  903               return false;
  904           }
  905       }
  906   
  907       /**
  908        * Converts a relative file name to a relative URI.  This is
  909        * different from File.toURI as this method does not canonicalize
  910        * the file before creating the URI.  Furthermore, no schema is
  911        * used.
  912        * @param file a relative file name
  913        * @return a relative URI
  914        * @throws IllegalArgumentException if the file name is not
  915        * relative according to the definition given in {@link
  916        * javax.tools.JavaFileManager#getFileForInput}
  917        */
  918       public static String getRelativeName(File file) {
  919           if (!file.isAbsolute()) {
  920               String result = file.getPath().replace(File.separatorChar, '/');
  921               if (isRelativeUri(result))
  922                   return result;
  923           }
  924           throw new IllegalArgumentException("Invalid relative path: " + file);
  925       }
  926   
  927       /**
  928        * Get a detail message from an IOException.
  929        * Most, but not all, instances of IOException provide a non-null result
  930        * for getLocalizedMessage().  But some instances return null: in these
  931        * cases, fallover to getMessage(), and if even that is null, return the
  932        * name of the exception itself.
  933        * @param e an IOException
  934        * @return a string to include in a compiler diagnostic
  935        */
  936       public static String getMessage(IOException e) {
  937           String s = e.getLocalizedMessage();
  938           if (s != null)
  939               return s;
  940           s = e.getMessage();
  941           if (s != null)
  942               return s;
  943           return e.toString();
  944       }
  945   }

Home » openjdk-7 » com.sun.tools » javac » file » [javadoc | source]