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

    1   /*
    2    * Copyright (c) 2009, 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.nio;
   27   
   28   
   29   import java.io.File;
   30   import java.io.FileNotFoundException;
   31   import java.io.IOException;
   32   import java.net.MalformedURLException;
   33   import java.net.URL;
   34   import java.nio.charset.Charset;
   35   import java.nio.file.Files;
   36   import java.nio.file.FileSystem;
   37   import java.nio.file.FileSystems;
   38   import java.nio.file.FileVisitOption;
   39   import java.nio.file.FileVisitResult;
   40   import java.nio.file.Path;
   41   import java.nio.file.SimpleFileVisitor;
   42   import java.nio.file.attribute.BasicFileAttributes;
   43   import java.util.ArrayList;
   44   import java.util.Arrays;
   45   import java.util.Collection;
   46   import java.util.Collections;
   47   import java.util.EnumSet;
   48   import java.util.HashMap;
   49   import java.util.Iterator;
   50   import java.util.LinkedHashSet;
   51   import java.util.Map;
   52   import java.util.Set;
   53   import javax.lang.model.SourceVersion;
   54   import javax.tools.FileObject;
   55   import javax.tools.JavaFileManager;
   56   import javax.tools.JavaFileObject;
   57   import javax.tools.JavaFileObject.Kind;
   58   import javax.tools.StandardLocation;
   59   
   60   import static java.nio.file.FileVisitOption.*;
   61   import static javax.tools.StandardLocation.*;
   62   
   63   import com.sun.tools.javac.file.Paths;
   64   import com.sun.tools.javac.util.BaseFileManager;
   65   import com.sun.tools.javac.util.Context;
   66   import com.sun.tools.javac.util.List;
   67   import com.sun.tools.javac.util.ListBuffer;
   68   
   69   import static com.sun.tools.javac.main.OptionName.*;
   70   
   71   
   72   // NOTE the imports carefully for this compilation unit.
   73   //
   74   // Path:  java.nio.file.Path -- the new NIO type for which this file manager exists
   75   //
   76   // Paths: com.sun.tools.javac.file.Paths -- legacy javac type for handling path options
   77   //      The other Paths (java.nio.file.Paths) is not used
   78   
   79   // NOTE this and related classes depend on new API in JDK 7.
   80   // This requires special handling while bootstrapping the JDK build,
   81   // when these classes might not yet have been compiled. To workaround
   82   // this, the build arranges to make stubs of these classes available
   83   // when compiling this and related classes. The set of stub files
   84   // is specified in make/build.properties.
   85   
   86   /**
   87    *  Implementation of PathFileManager: a JavaFileManager based on the use
   88    *  of java.nio.file.Path.
   89    *
   90    *  <p>Just as a Path is somewhat analagous to a File, so too is this
   91    *  JavacPathFileManager analogous to JavacFileManager, as it relates to the
   92    *  support of FileObjects based on File objects (i.e. just RegularFileObject,
   93    *  not ZipFileObject and its variants.)
   94    *
   95    *  <p>The default values for the standard locations supported by this file
   96    *  manager are the same as the default values provided by JavacFileManager --
   97    *  i.e. as determined by the javac.file.Paths class. To override these values,
   98    *  call {@link #setLocation}.
   99    *
  100    *  <p>To reduce confusion with Path objects, the locations such as "class path",
  101    *  "source path", etc, are generically referred to here as "search paths".
  102    *
  103    *  <p><b>This is NOT part of any supported API.
  104    *  If you write code that depends on this, you do so at your own risk.
  105    *  This code and its internal interfaces are subject to change or
  106    *  deletion without notice.</b>
  107    */
  108   public class JavacPathFileManager extends BaseFileManager implements PathFileManager {
  109       protected FileSystem defaultFileSystem;
  110   
  111       /**
  112        * Create a JavacPathFileManager using a given context, optionally registering
  113        * it as the JavaFileManager for that context.
  114        */
  115       public JavacPathFileManager(Context context, boolean register, Charset charset) {
  116           super(charset);
  117           if (register)
  118               context.put(JavaFileManager.class, this);
  119           pathsForLocation = new HashMap<Location, PathsForLocation>();
  120           fileSystems = new HashMap<Path,FileSystem>();
  121           setContext(context);
  122       }
  123   
  124       /**
  125        * Set the context for JavacPathFileManager.
  126        */
  127       @Override
  128       protected void setContext(Context context) {
  129           super.setContext(context);
  130           searchPaths = Paths.instance(context);
  131       }
  132   
  133       @Override
  134       public FileSystem getDefaultFileSystem() {
  135           if (defaultFileSystem == null)
  136               defaultFileSystem = FileSystems.getDefault();
  137           return defaultFileSystem;
  138       }
  139   
  140       @Override
  141       public void setDefaultFileSystem(FileSystem fs) {
  142           defaultFileSystem = fs;
  143       }
  144   
  145       @Override
  146       public void flush() throws IOException {
  147           contentCache.clear();
  148       }
  149   
  150       @Override
  151       public void close() throws IOException {
  152           for (FileSystem fs: fileSystems.values())
  153               fs.close();
  154       }
  155   
  156       @Override
  157       public ClassLoader getClassLoader(Location location) {
  158           nullCheck(location);
  159           Iterable<? extends Path> path = getLocation(location);
  160           if (path == null)
  161               return null;
  162           ListBuffer<URL> lb = new ListBuffer<URL>();
  163           for (Path p: path) {
  164               try {
  165                   lb.append(p.toUri().toURL());
  166               } catch (MalformedURLException e) {
  167                   throw new AssertionError(e);
  168               }
  169           }
  170   
  171           return getClassLoader(lb.toArray(new URL[lb.size()]));
  172       }
  173   
  174       @Override
  175       public boolean isDefaultBootClassPath() {
  176           return searchPaths.isDefaultBootClassPath();
  177       }
  178   
  179       // <editor-fold defaultstate="collapsed" desc="Location handling">
  180   
  181       public boolean hasLocation(Location location) {
  182           return (getLocation(location) != null);
  183       }
  184   
  185       public Iterable<? extends Path> getLocation(Location location) {
  186           nullCheck(location);
  187           lazyInitSearchPaths();
  188           PathsForLocation path = pathsForLocation.get(location);
  189           if (path == null && !pathsForLocation.containsKey(location)) {
  190               setDefaultForLocation(location);
  191               path = pathsForLocation.get(location);
  192           }
  193           return path;
  194       }
  195   
  196       private Path getOutputLocation(Location location) {
  197           Iterable<? extends Path> paths = getLocation(location);
  198           return (paths == null ? null : paths.iterator().next());
  199       }
  200   
  201       public void setLocation(Location location, Iterable<? extends Path> searchPath)
  202               throws IOException
  203       {
  204           nullCheck(location);
  205           lazyInitSearchPaths();
  206           if (searchPath == null) {
  207               setDefaultForLocation(location);
  208           } else {
  209               if (location.isOutputLocation())
  210                   checkOutputPath(searchPath);
  211               PathsForLocation pl = new PathsForLocation();
  212               for (Path p: searchPath)
  213                   pl.add(p);  // TODO -Xlint:path warn if path not found
  214               pathsForLocation.put(location, pl);
  215           }
  216       }
  217   
  218       private void checkOutputPath(Iterable<? extends Path> searchPath) throws IOException {
  219           Iterator<? extends Path> pathIter = searchPath.iterator();
  220           if (!pathIter.hasNext())
  221               throw new IllegalArgumentException("empty path for directory");
  222           Path path = pathIter.next();
  223           if (pathIter.hasNext())
  224               throw new IllegalArgumentException("path too long for directory");
  225           if (!isDirectory(path))
  226               throw new IOException(path + ": not a directory");
  227       }
  228   
  229       private void setDefaultForLocation(Location locn) {
  230           Collection<File> files = null;
  231           if (locn instanceof StandardLocation) {
  232               switch ((StandardLocation) locn) {
  233                   case CLASS_PATH:
  234                       files = searchPaths.userClassPath();
  235                       break;
  236                   case PLATFORM_CLASS_PATH:
  237                       files = searchPaths.bootClassPath();
  238                       break;
  239                   case SOURCE_PATH:
  240                       files = searchPaths.sourcePath();
  241                       break;
  242                   case CLASS_OUTPUT: {
  243                       String arg = options.get(D);
  244                       files = (arg == null ? null : Collections.singleton(new File(arg)));
  245                       break;
  246                   }
  247                   case SOURCE_OUTPUT: {
  248                       String arg = options.get(S);
  249                       files = (arg == null ? null : Collections.singleton(new File(arg)));
  250                       break;
  251                   }
  252               }
  253           }
  254   
  255           PathsForLocation pl = new PathsForLocation();
  256           if (files != null) {
  257               for (File f: files)
  258                   pl.add(f.toPath());
  259           }
  260           pathsForLocation.put(locn, pl);
  261       }
  262   
  263       private void lazyInitSearchPaths() {
  264           if (!inited) {
  265               setDefaultForLocation(PLATFORM_CLASS_PATH);
  266               setDefaultForLocation(CLASS_PATH);
  267               setDefaultForLocation(SOURCE_PATH);
  268               inited = true;
  269           }
  270       }
  271       // where
  272           private boolean inited = false;
  273   
  274       private Map<Location, PathsForLocation> pathsForLocation;
  275       private Paths searchPaths;
  276   
  277       private static class PathsForLocation extends LinkedHashSet<Path> {
  278           private static final long serialVersionUID = 6788510222394486733L;
  279       }
  280   
  281       // </editor-fold>
  282   
  283       // <editor-fold defaultstate="collapsed" desc="FileObject handling">
  284   
  285       @Override
  286       public Path getPath(FileObject fo) {
  287           nullCheck(fo);
  288           if (!(fo instanceof PathFileObject))
  289               throw new IllegalArgumentException();
  290           return ((PathFileObject) fo).getPath();
  291       }
  292   
  293       @Override
  294       public boolean isSameFile(FileObject a, FileObject b) {
  295           nullCheck(a);
  296           nullCheck(b);
  297           if (!(a instanceof PathFileObject))
  298               throw new IllegalArgumentException("Not supported: " + a);
  299           if (!(b instanceof PathFileObject))
  300               throw new IllegalArgumentException("Not supported: " + b);
  301           return ((PathFileObject) a).isSameFile((PathFileObject) b);
  302       }
  303   
  304       @Override
  305       public Iterable<JavaFileObject> list(Location location,
  306               String packageName, Set<Kind> kinds, boolean recurse)
  307               throws IOException {
  308           // validatePackageName(packageName);
  309           nullCheck(packageName);
  310           nullCheck(kinds);
  311   
  312           Iterable<? extends Path> paths = getLocation(location);
  313           if (paths == null)
  314               return List.nil();
  315           ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
  316   
  317           for (Path path : paths)
  318               list(path, packageName, kinds, recurse, results);
  319   
  320           return results.toList();
  321       }
  322   
  323       private void list(Path path, String packageName, final Set<Kind> kinds,
  324               boolean recurse, final ListBuffer<JavaFileObject> results)
  325               throws IOException {
  326           if (!Files.exists(path))
  327               return;
  328   
  329           final Path pathDir;
  330           if (isDirectory(path))
  331               pathDir = path;
  332           else {
  333               FileSystem fs = getFileSystem(path);
  334               if (fs == null)
  335                   return;
  336               pathDir = fs.getRootDirectories().iterator().next();
  337           }
  338           String sep = path.getFileSystem().getSeparator();
  339           Path packageDir = packageName.isEmpty() ? pathDir
  340                   : pathDir.resolve(packageName.replace(".", sep));
  341           if (!Files.exists(packageDir))
  342               return;
  343   
  344   /* Alternate impl of list, superceded by use of Files.walkFileTree */
  345   //        Deque<Path> queue = new LinkedList<Path>();
  346   //        queue.add(packageDir);
  347   //
  348   //        Path dir;
  349   //        while ((dir = queue.poll()) != null) {
  350   //            DirectoryStream<Path> ds = dir.newDirectoryStream();
  351   //            try {
  352   //                for (Path p: ds) {
  353   //                    String name = p.getFileName().toString();
  354   //                    if (isDirectory(p)) {
  355   //                        if (recurse && SourceVersion.isIdentifier(name)) {
  356   //                            queue.add(p);
  357   //                        }
  358   //                    } else {
  359   //                        if (kinds.contains(getKind(name))) {
  360   //                            JavaFileObject fe =
  361   //                                PathFileObject.createDirectoryPathFileObject(this, p, pathDir);
  362   //                            results.append(fe);
  363   //                        }
  364   //                    }
  365   //                }
  366   //            } finally {
  367   //                ds.close();
  368   //            }
  369   //        }
  370           int maxDepth = (recurse ? Integer.MAX_VALUE : 1);
  371           Set<FileVisitOption> opts = EnumSet.of(FOLLOW_LINKS);
  372           Files.walkFileTree(packageDir, opts, maxDepth,
  373                   new SimpleFileVisitor<Path>() {
  374               @Override
  375               public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
  376                   Path name = dir.getFileName();
  377                   if (name == null || SourceVersion.isIdentifier(name.toString())) // JSR 292?
  378                       return FileVisitResult.CONTINUE;
  379                   else
  380                       return FileVisitResult.SKIP_SUBTREE;
  381               }
  382   
  383               @Override
  384               public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
  385                   if (attrs.isRegularFile() && kinds.contains(getKind(file.getFileName().toString()))) {
  386                       JavaFileObject fe =
  387                           PathFileObject.createDirectoryPathFileObject(
  388                               JavacPathFileManager.this, file, pathDir);
  389                       results.append(fe);
  390                   }
  391                   return FileVisitResult.CONTINUE;
  392               }
  393           });
  394       }
  395   
  396       @Override
  397       public Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths(
  398           Iterable<? extends Path> paths) {
  399           ArrayList<PathFileObject> result;
  400           if (paths instanceof Collection<?>)
  401               result = new ArrayList<PathFileObject>(((Collection<?>)paths).size());
  402           else
  403               result = new ArrayList<PathFileObject>();
  404           for (Path p: paths)
  405               result.add(PathFileObject.createSimplePathFileObject(this, nullCheck(p)));
  406           return result;
  407       }
  408   
  409       @Override
  410       public Iterable<? extends JavaFileObject> getJavaFileObjects(Path... paths) {
  411           return getJavaFileObjectsFromPaths(Arrays.asList(nullCheck(paths)));
  412       }
  413   
  414       @Override
  415       public JavaFileObject getJavaFileForInput(Location location,
  416               String className, Kind kind) throws IOException {
  417           return getFileForInput(location, getRelativePath(className, kind));
  418       }
  419   
  420       @Override
  421       public FileObject getFileForInput(Location location,
  422               String packageName, String relativeName) throws IOException {
  423           return getFileForInput(location, getRelativePath(packageName, relativeName));
  424       }
  425   
  426       private JavaFileObject getFileForInput(Location location, String relativePath)
  427               throws IOException {
  428           for (Path p: getLocation(location)) {
  429               if (isDirectory(p)) {
  430                   Path f = resolve(p, relativePath);
  431                   if (Files.exists(f))
  432                       return PathFileObject.createDirectoryPathFileObject(this, f, p);
  433               } else {
  434                   FileSystem fs = getFileSystem(p);
  435                   if (fs != null) {
  436                       Path file = getPath(fs, relativePath);
  437                       if (Files.exists(file))
  438                           return PathFileObject.createJarPathFileObject(this, file);
  439                   }
  440               }
  441           }
  442           return null;
  443       }
  444   
  445       @Override
  446       public JavaFileObject getJavaFileForOutput(Location location,
  447               String className, Kind kind, FileObject sibling) throws IOException {
  448           return getFileForOutput(location, getRelativePath(className, kind), sibling);
  449       }
  450   
  451       @Override
  452       public FileObject getFileForOutput(Location location, String packageName,
  453               String relativeName, FileObject sibling)
  454               throws IOException {
  455           return getFileForOutput(location, getRelativePath(packageName, relativeName), sibling);
  456       }
  457   
  458       private JavaFileObject getFileForOutput(Location location,
  459               String relativePath, FileObject sibling) {
  460           Path dir = getOutputLocation(location);
  461           if (dir == null) {
  462               if (location == CLASS_OUTPUT) {
  463                   Path siblingDir = null;
  464                   if (sibling != null && sibling instanceof PathFileObject) {
  465                       siblingDir = ((PathFileObject) sibling).getPath().getParent();
  466                   }
  467                   return PathFileObject.createSiblingPathFileObject(this,
  468                           siblingDir.resolve(getBaseName(relativePath)),
  469                           relativePath);
  470               } else if (location == SOURCE_OUTPUT) {
  471                   dir = getOutputLocation(CLASS_OUTPUT);
  472               }
  473           }
  474   
  475           Path file;
  476           if (dir != null) {
  477               file = resolve(dir, relativePath);
  478               return PathFileObject.createDirectoryPathFileObject(this, file, dir);
  479           } else {
  480               file = getPath(getDefaultFileSystem(), relativePath);
  481               return PathFileObject.createSimplePathFileObject(this, file);
  482           }
  483   
  484       }
  485   
  486       @Override
  487       public String inferBinaryName(Location location, JavaFileObject fo) {
  488           nullCheck(fo);
  489           // Need to match the path semantics of list(location, ...)
  490           Iterable<? extends Path> paths = getLocation(location);
  491           if (paths == null) {
  492               return null;
  493           }
  494   
  495           if (!(fo instanceof PathFileObject))
  496               throw new IllegalArgumentException(fo.getClass().getName());
  497   
  498           return ((PathFileObject) fo).inferBinaryName(paths);
  499       }
  500   
  501       private FileSystem getFileSystem(Path p) throws IOException {
  502           FileSystem fs = fileSystems.get(p);
  503           if (fs == null) {
  504               fs = FileSystems.newFileSystem(p, null);
  505               fileSystems.put(p, fs);
  506           }
  507           return fs;
  508       }
  509   
  510       private Map<Path,FileSystem> fileSystems;
  511   
  512       // </editor-fold>
  513   
  514       // <editor-fold defaultstate="collapsed" desc="Utility methods">
  515   
  516       private static String getRelativePath(String className, Kind kind) {
  517           return className.replace(".", "/") + kind.extension;
  518       }
  519   
  520       private static String getRelativePath(String packageName, String relativeName) {
  521           return packageName.replace(".", "/") + relativeName;
  522       }
  523   
  524       private static String getBaseName(String relativePath) {
  525           int lastSep = relativePath.lastIndexOf("/");
  526           return relativePath.substring(lastSep + 1); // safe if "/" not found
  527       }
  528   
  529       private static boolean isDirectory(Path path) throws IOException {
  530           BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
  531           return attrs.isDirectory();
  532       }
  533   
  534       private static Path getPath(FileSystem fs, String relativePath) {
  535           return fs.getPath(relativePath.replace("/", fs.getSeparator()));
  536       }
  537   
  538       private static Path resolve(Path base, String relativePath) {
  539           FileSystem fs = base.getFileSystem();
  540           Path rp = fs.getPath(relativePath.replace("/", fs.getSeparator()));
  541           return base.resolve(rp);
  542       }
  543   
  544       // </editor-fold>
  545   
  546   }

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