src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java

Thu, 15 Nov 2012 23:07:24 -0800

author
jjg
date
Thu, 15 Nov 2012 23:07:24 -0800
changeset 1413
bdcef2ef52d2
parent 1157
3809292620c9
child 2525
2eb010b6cb22
permissions
-rw-r--r--

6493690: javadoc should have a javax.tools.Tool service provider installed in tools.jar
Reviewed-by: darcy

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

mercurial