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

Tue, 28 Dec 2010 15:54:52 -0800

author
ohair
date
Tue, 28 Dec 2010 15:54:52 -0800
changeset 798
4868a36f6fd8
parent 757
c44234f680da
child 809
e63b1f8341ce
permissions
-rw-r--r--

6962318: Update copyright year
Reviewed-by: xdono

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

mercurial