langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/PathFileObject.java
changeset 34560 b6a567b677f7
parent 31753 72417309a675
child 35807 2eb1d877da0f
equal deleted inserted replaced
34481:e0ff9821f1e8 34560:b6a567b677f7
    31 import java.io.OutputStream;
    31 import java.io.OutputStream;
    32 import java.io.OutputStreamWriter;
    32 import java.io.OutputStreamWriter;
    33 import java.io.Reader;
    33 import java.io.Reader;
    34 import java.io.Writer;
    34 import java.io.Writer;
    35 import java.net.URI;
    35 import java.net.URI;
       
    36 import java.net.URISyntaxException;
    36 import java.nio.ByteBuffer;
    37 import java.nio.ByteBuffer;
    37 import java.nio.CharBuffer;
    38 import java.nio.CharBuffer;
    38 import java.nio.charset.CharsetDecoder;
    39 import java.nio.charset.CharsetDecoder;
       
    40 import java.nio.file.FileSystem;
       
    41 import java.nio.file.FileSystems;
    39 import java.nio.file.Files;
    42 import java.nio.file.Files;
    40 import java.nio.file.LinkOption;
    43 import java.nio.file.LinkOption;
    41 import java.nio.file.Path;
    44 import java.nio.file.Path;
       
    45 import java.text.Normalizer;
    42 import java.util.Objects;
    46 import java.util.Objects;
    43 
    47 
    44 import javax.lang.model.element.Modifier;
    48 import javax.lang.model.element.Modifier;
    45 import javax.lang.model.element.NestingKind;
    49 import javax.lang.model.element.NestingKind;
       
    50 import javax.tools.FileObject;
    46 import javax.tools.JavaFileObject;
    51 import javax.tools.JavaFileObject;
    47 
    52 
       
    53 import com.sun.tools.javac.file.RelativePath.RelativeFile;
    48 import com.sun.tools.javac.util.DefinedBy;
    54 import com.sun.tools.javac.util.DefinedBy;
    49 import com.sun.tools.javac.util.DefinedBy.Api;
    55 import com.sun.tools.javac.util.DefinedBy.Api;
    50 
    56 
    51 
    57 
    52 /**
    58 /**
    53  *  Implementation of JavaFileObject using java.nio.file API.
    59  *  Implementation of JavaFileObject using java.nio.file API.
    54  *
    60  *
    55  *  <p>PathFileObjects are, for the most part, straightforward wrappers around
    61  *  <p>PathFileObjects are, for the most part, straightforward wrappers around
    56  *  Path objects. The primary complexity is the support for "inferBinaryName".
    62  *  immutable absolute Path objects. Different subtypes are used to provide
    57  *  This is left as an abstract method, implemented by each of a number of
    63  *  specialized implementations of "inferBinaryName" and "getName" that capture
    58  *  different factory methods, which compute the binary name based on
    64  *  additional information available at the time the object is created.
    59  *  information available at the time the file object is created.
    65  *
       
    66  *  <p>In general, {@link JavaFileManager#isSameFile} should be used to
       
    67  *  determine whether two file objects refer to the same file on disk.
       
    68  *  PathFileObject also supports the standard {@code equals} and {@code hashCode}
       
    69  *  methods, primarily for convenience when working with collections.
       
    70  *  All of these operations delegate to the equivalent operations on the
       
    71  *  underlying Path object.
    60  *
    72  *
    61  *  <p><b>This is NOT part of any supported API.
    73  *  <p><b>This is NOT part of any supported API.
    62  *  If you write code that depends on this, you do so at your own risk.
    74  *  If you write code that depends on this, you do so at your own risk.
    63  *  This code and its internal interfaces are subject to change or
    75  *  This code and its internal interfaces are subject to change or
    64  *  deletion without notice.</b>
    76  *  deletion without notice.</b>
    65  */
    77  */
    66 public abstract class PathFileObject implements JavaFileObject {
    78 public abstract class PathFileObject implements JavaFileObject {
    67     private final BaseFileManager fileManager;
    79     private static final FileSystem defaultFileSystem = FileSystems.getDefault();
    68     private final Path path;
    80     private static final boolean isMacOS = System.getProperty("os.name", "").contains("OS X");
    69 
    81 
    70     /**
    82     protected final BaseFileManager fileManager;
    71      * Create a PathFileObject within a directory, such that the binary name
    83     protected final Path path;
    72      * can be inferred from the relationship to the parent directory.
    84     private boolean hasParents;
    73      */
    85 
    74     static PathFileObject createDirectoryPathFileObject(BaseFileManager fileManager,
    86     /**
    75             final Path path, final Path dir) {
    87      * Create a PathFileObject for a file within a directory, such that the
    76         return new PathFileObject(fileManager, path) {
    88      * binary name can be inferred from the relationship to an enclosing directory.
    77             @Override
    89      *
    78             public String inferBinaryName(Iterable<? extends Path> paths) {
    90      * The binary name is derived from {@code relativePath}.
    79                 return toBinaryName(dir.relativize(path));
    91      * The name is derived from the composition of {@code userPackageRootDir}
       
    92      * and {@code relativePath}.
       
    93      *
       
    94      * @param fileManager the file manager creating this file object
       
    95      * @param path the absolute path referred to by this file object
       
    96      * @param userPackageRootDir the path of the directory containing the
       
    97      *          root of the package hierarchy
       
    98      * @param relativePath the path of this file relative to {@code userPackageRootDir}
       
    99      */
       
   100     static PathFileObject forDirectoryPath(BaseFileManager fileManager, Path path,
       
   101             Path userPackageRootDir, RelativePath relativePath) {
       
   102         return new DirectoryFileObject(fileManager, path, userPackageRootDir, relativePath);
       
   103     }
       
   104 
       
   105     private static class DirectoryFileObject extends PathFileObject {
       
   106         private final Path userPackageRootDir;
       
   107         private final RelativePath relativePath;
       
   108 
       
   109         private DirectoryFileObject(BaseFileManager fileManager, Path path,
       
   110                 Path userPackageRootDir, RelativePath relativePath) {
       
   111             super(fileManager, path);
       
   112             this.userPackageRootDir = userPackageRootDir;
       
   113             this.relativePath = relativePath;
       
   114         }
       
   115 
       
   116         @Override @DefinedBy(Api.COMPILER)
       
   117         public String getName() {
       
   118             return relativePath.resolveAgainst(userPackageRootDir).toString();
       
   119         }
       
   120 
       
   121         @Override
       
   122         public String inferBinaryName(Iterable<? extends Path> paths) {
       
   123             return toBinaryName(relativePath);
       
   124         }
       
   125 
       
   126         @Override
       
   127         public String toString() {
       
   128             return "DirectoryFileObject[" + userPackageRootDir + ":" + relativePath.path + "]";
       
   129         }
       
   130 
       
   131         @Override
       
   132         PathFileObject getSibling(String baseName) {
       
   133             return new DirectoryFileObject(fileManager,
       
   134                     path.resolveSibling(baseName),
       
   135                     userPackageRootDir,
       
   136                     new RelativeFile(relativePath.dirname(), baseName)
       
   137             );
       
   138         }
       
   139     }
       
   140 
       
   141     /**
       
   142      * Create a PathFileObject for a file in a file system such as a jar file,
       
   143      * such that the binary name can be inferred from its position within the
       
   144      * file system.
       
   145      *
       
   146      * The binary name is derived from {@code path}.
       
   147      * The name is derived from the composition of {@code userJarPath}
       
   148      * and {@code path}.
       
   149      *
       
   150      * @param fileManager the file manager creating this file object
       
   151      * @param path the path referred to by this file object
       
   152      * @param userJarPath the path of the jar file containing the file system.
       
   153      */
       
   154     public static PathFileObject forJarPath(BaseFileManager fileManager,
       
   155             Path path, Path userJarPath) {
       
   156         return new JarFileObject(fileManager, path, userJarPath);
       
   157     }
       
   158 
       
   159     private static class JarFileObject extends PathFileObject {
       
   160         private final Path userJarPath;
       
   161 
       
   162         private JarFileObject(BaseFileManager fileManager, Path path, Path userJarPath) {
       
   163             super(fileManager, path);
       
   164             this.userJarPath = userJarPath;
       
   165         }
       
   166 
       
   167         @Override @DefinedBy(Api.COMPILER)
       
   168         public String getName() {
       
   169             // The use of ( ) to delimit the entry name is not ideal
       
   170             // but it does match earlier behavior
       
   171             return userJarPath + "(" + path + ")";
       
   172         }
       
   173 
       
   174         @Override
       
   175         public String inferBinaryName(Iterable<? extends Path> paths) {
       
   176             Path root = path.getFileSystem().getRootDirectories().iterator().next();
       
   177             return toBinaryName(root.relativize(path));
       
   178         }
       
   179 
       
   180         @Override @DefinedBy(Api.COMPILER)
       
   181         public URI toUri() {
       
   182             // Work around bug JDK-8134451:
       
   183             // path.toUri() returns double-encoded URIs, that cannot be opened by URLConnection
       
   184             return createJarUri(userJarPath, path.toString());
       
   185         }
       
   186 
       
   187         @Override
       
   188         public String toString() {
       
   189             return "JarFileObject[" + userJarPath + ":" + path + "]";
       
   190         }
       
   191 
       
   192         @Override
       
   193         PathFileObject getSibling(String baseName) {
       
   194             return new JarFileObject(fileManager,
       
   195                     path.resolveSibling(baseName),
       
   196                     userJarPath
       
   197             );
       
   198         }
       
   199 
       
   200         private static URI createJarUri(Path jarFile, String entryName) {
       
   201             URI jarURI = jarFile.toUri().normalize();
       
   202             String separator = entryName.startsWith("/") ? "!" : "!/";
       
   203             try {
       
   204                 // The jar URI convention appears to be not to re-encode the jarURI
       
   205                 return new URI("jar:" + jarURI + separator + entryName);
       
   206             } catch (URISyntaxException e) {
       
   207                 throw new CannotCreateUriError(jarURI + separator + entryName, e);
    80             }
   208             }
    81         };
   209         }
    82     }
   210     }
    83 
   211 
    84     /**
   212     /**
    85      * Create a PathFileObject in a file system such as a jar file, such that
   213      * Create a PathFileObject for a file in a modular file system, such as jrt:,
    86      * the binary name can be inferred from its position within the filesystem.
   214      * such that the binary name can be inferred from its position within the
    87      */
   215      * filesystem.
    88     public static PathFileObject createJarPathFileObject(BaseFileManager fileManager,
   216      *
       
   217      * The binary name is derived from {@code path}, ignoring the first two
       
   218      * elements of the name (which are "modules" and a module name).
       
   219      * The name is derived from {@code path}.
       
   220      *
       
   221      * @param fileManager the file manager creating this file object
       
   222      * @param path the path referred to by this file object
       
   223      */
       
   224     public static PathFileObject forJRTPath(BaseFileManager fileManager,
    89             final Path path) {
   225             final Path path) {
    90         return new PathFileObject(fileManager, path) {
   226         return new JRTFileObject(fileManager, path);
    91             @Override
   227     }
    92             public String inferBinaryName(Iterable<? extends Path> paths) {
   228 
    93                 return toBinaryName(path);
   229     private static class JRTFileObject extends PathFileObject {
    94             }
   230         // private final Path javaHome;
    95         };
   231         private JRTFileObject(BaseFileManager fileManager, Path path) {
    96     }
   232             super(fileManager, path);
    97 
   233         }
    98     /**
   234 
    99      * Create a PathFileObject in a modular file system, such as jrt:, such that
   235         @Override @DefinedBy(Api.COMPILER)
   100      * the binary name can be inferred from its position within the filesystem.
   236         public String getName() {
   101      */
   237             return path.toString();
   102     public static PathFileObject createJRTPathFileObject(BaseFileManager fileManager,
   238         }
   103             final Path path) {
   239 
   104         return new PathFileObject(fileManager, path) {
   240         @Override
   105             @Override
   241         public String inferBinaryName(Iterable<? extends Path> paths) {
   106             public String inferBinaryName(Iterable<? extends Path> paths) {
   242             // use subpath to ignore the leading /modules/MODULE-NAME
   107                 // use subpath to ignore the leading /modules/MODULE-NAME
   243             return toBinaryName(path.subpath(2, path.getNameCount()));
   108                 return toBinaryName(path.subpath(2, path.getNameCount()));
   244         }
   109             }
   245 
   110         };
   246         @Override
   111     }
   247         public String toString() {
   112 
   248             return "JRTFileObject[" + path + "]";
   113     /**
   249         }
   114      * Create a PathFileObject whose binary name can be inferred from the
   250 
   115      * relative path to a sibling.
   251         @Override
   116      */
   252         PathFileObject getSibling(String baseName) {
   117     static PathFileObject createSiblingPathFileObject(BaseFileManager fileManager,
   253             return new JRTFileObject(fileManager,
   118             final Path path, final String relativePath) {
   254                     path.resolveSibling(baseName)
   119         return new PathFileObject(fileManager, path) {
   255             );
   120             @Override
   256         }
   121             public String inferBinaryName(Iterable<? extends Path> paths) {
   257     }
   122                 return toBinaryName(relativePath, "/");
   258 
   123             }
   259     /**
   124         };
   260      * Create a PathFileObject for a file whose binary name must be inferred
   125     }
   261      * from its position on a search path.
   126 
   262      *
   127     /**
   263      * The binary name is inferred by finding an enclosing directory in
   128      * Create a PathFileObject whose binary name might be inferred from its
   264      * the sequence of paths associated with the location given to
   129      * position on a search path.
   265      * {@link JavaFileManager#inferBinaryName).
   130      */
   266      * The name is derived from {@code userPath}.
   131     static PathFileObject createSimplePathFileObject(BaseFileManager fileManager,
   267      *
   132             final Path path) {
   268      * @param fileManager the file manager creating this file object
   133         return new PathFileObject(fileManager, path) {
   269      * @param path the path referred to by this file object
   134             @Override
   270      * @param userPath the "user-friendly" name for this path.
   135             public String inferBinaryName(Iterable<? extends Path> paths) {
   271      */
   136                 Path absPath = path.toAbsolutePath();
   272     static PathFileObject forSimplePath(BaseFileManager fileManager,
   137                 for (Path p: paths) {
   273             Path path, Path userPath) {
   138                     Path ap = p.toAbsolutePath();
   274         return new SimpleFileObject(fileManager, path, userPath);
   139                     if (absPath.startsWith(ap)) {
   275     }
   140                         try {
   276 
   141                             Path rp = ap.relativize(absPath);
   277     private static class SimpleFileObject extends PathFileObject {
   142                             if (rp != null) // maybe null if absPath same as ap
   278         private final Path userPath;
   143                                 return toBinaryName(rp);
   279         private SimpleFileObject(BaseFileManager fileManager, Path path, Path userPath) {
   144                         } catch (IllegalArgumentException e) {
   280             super(fileManager, path);
   145                             // ignore this p if cannot relativize path to p
   281             this.userPath = userPath;
   146                         }
   282         }
       
   283 
       
   284         @Override @DefinedBy(Api.COMPILER)
       
   285         public String getName() {
       
   286             return userPath.toString();
       
   287         }
       
   288 
       
   289         @Override
       
   290         public String inferBinaryName(Iterable<? extends Path> paths) {
       
   291             Path absPath = path.toAbsolutePath();
       
   292             for (Path p: paths) {
       
   293                 Path ap = p.toAbsolutePath();
       
   294                 if (absPath.startsWith(ap)) {
       
   295                     try {
       
   296                         Path rp = ap.relativize(absPath);
       
   297                         if (rp != null) // maybe null if absPath same as ap
       
   298                             return toBinaryName(rp);
       
   299                     } catch (IllegalArgumentException e) {
       
   300                         // ignore this p if cannot relativize path to p
   147                     }
   301                     }
   148                 }
   302                 }
   149                 return null;
       
   150             }
   303             }
   151         };
   304             return null;
   152     }
   305         }
   153 
   306 
       
   307         @Override
       
   308         PathFileObject getSibling(String baseName) {
       
   309             return new SimpleFileObject(fileManager,
       
   310                     path.resolveSibling(baseName),
       
   311                     userPath.resolveSibling(baseName)
       
   312             );
       
   313         }
       
   314     }
       
   315 
       
   316     /**
       
   317      * Create a PathFileObject, for a specified path, in the context of
       
   318      * a given file manager.
       
   319      *
       
   320      * In general, this path should be an
       
   321      * {@link Path#toAbsolutePath absolute path}, if not a
       
   322      * {@link Path#toRealPath} real path.
       
   323      * It will be used as the basis of {@code equals}, {@code hashCode}
       
   324      * and {@code isSameFile} methods on this file object.
       
   325      *
       
   326      * A PathFileObject should also have a "friendly name" per the
       
   327      * specification for {@link FileObject#getName}. The friendly name
       
   328      * is provided by the various subtypes of {@code PathFileObject}.
       
   329      *
       
   330      * @param fileManager the file manager creating this file object
       
   331      * @param path the path contained in this file object.
       
   332      */
   154     protected PathFileObject(BaseFileManager fileManager, Path path) {
   333     protected PathFileObject(BaseFileManager fileManager, Path path) {
   155         this.fileManager = Objects.requireNonNull(fileManager);
   334         this.fileManager = Objects.requireNonNull(fileManager);
   156         this.path = Objects.requireNonNull(path);
   335         if (Files.isDirectory(path)) {
   157     }
   336             throw new IllegalArgumentException("directories not supported");
   158 
   337         }
   159     public abstract String inferBinaryName(Iterable<? extends Path> paths);
   338         this.path = path;
       
   339     }
       
   340 
       
   341     /**
       
   342      * See {@link JavacFileManager#inferBinaryName}.
       
   343      */
       
   344     abstract String inferBinaryName(Iterable<? extends Path> paths);
       
   345 
       
   346     /**
       
   347      * Return the file object for a sibling file with a given file name.
       
   348      * See {@link JavacFileManager#getFileForOutput} and
       
   349      * {@link JavacFileManager#getJavaFileForOutput}.
       
   350      */
       
   351     abstract PathFileObject getSibling(String basename);
   160 
   352 
   161     /**
   353     /**
   162      * Return the Path for this object.
   354      * Return the Path for this object.
   163      * @return the Path for this object.
   355      * @return the Path for this object.
       
   356      * @see StandardJavaFileManager#asPath
   164      */
   357      */
   165     public Path getPath() {
   358     public Path getPath() {
   166         return path;
   359         return path;
   167     }
   360     }
   168 
   361 
       
   362     /**
       
   363      * The short name is used when generating raw diagnostics.
       
   364      * @return the last component of the path
       
   365      */
       
   366     public String getShortName() {
       
   367         return path.getFileName().toString();
       
   368     }
       
   369 
   169     @Override @DefinedBy(Api.COMPILER)
   370     @Override @DefinedBy(Api.COMPILER)
   170     public Kind getKind() {
   371     public Kind getKind() {
   171         return BaseFileManager.getKind(path.getFileName().toString());
   372         return BaseFileManager.getKind(path.getFileName().toString());
   172     }
   373     }
   173 
   374 
   174     @Override @DefinedBy(Api.COMPILER)
   375     @Override @DefinedBy(Api.COMPILER)
   175     public boolean isNameCompatible(String simpleName, Kind kind) {
   376     public boolean isNameCompatible(String simpleName, Kind kind) {
   176         Objects.requireNonNull(simpleName);
   377         Objects.requireNonNull(simpleName);
   177         // null check
   378         Objects.requireNonNull(kind);
       
   379 
   178         if (kind == Kind.OTHER && getKind() != kind) {
   380         if (kind == Kind.OTHER && getKind() != kind) {
   179             return false;
   381             return false;
   180         }
   382         }
       
   383 
   181         String sn = simpleName + kind.extension;
   384         String sn = simpleName + kind.extension;
   182         String pn = path.getFileName().toString();
   385         String pn = path.getFileName().toString();
   183         if (pn.equals(sn)) {
   386         if (pn.equals(sn)) {
   184             return true;
   387             return true;
   185         }
   388         }
   186         if (pn.equalsIgnoreCase(sn)) {
   389 
   187             try {
   390         if (path.getFileSystem() == defaultFileSystem) {
   188                 // allow for Windows
   391             if (isMacOS) {
   189                 return path.toRealPath(LinkOption.NOFOLLOW_LINKS).getFileName().toString().equals(sn);
   392                 String name = path.getFileName().toString();
   190             } catch (IOException e) {
   393                 if (Normalizer.isNormalized(name, Normalizer.Form.NFD)
       
   394                         && Normalizer.isNormalized(sn, Normalizer.Form.NFC)) {
       
   395                     // On Mac OS X it is quite possible to have the file name and the
       
   396                     // given simple name normalized in different ways.
       
   397                     // In that case we have to normalize file name to the
       
   398                     // Normal Form Composed (NFC).
       
   399                     String normName = Normalizer.normalize(name, Normalizer.Form.NFC);
       
   400                     if (normName.equals(sn)) {
       
   401                         return true;
       
   402                     }
       
   403                 }
   191             }
   404             }
   192         }
   405 
       
   406             if (pn.equalsIgnoreCase(sn)) {
       
   407                 try {
       
   408                     // allow for Windows
       
   409                     return path.toRealPath(LinkOption.NOFOLLOW_LINKS).getFileName().toString().equals(sn);
       
   410                 } catch (IOException e) {
       
   411                 }
       
   412             }
       
   413         }
       
   414 
   193         return false;
   415         return false;
   194     }
   416     }
   195 
   417 
   196     @Override @DefinedBy(Api.COMPILER)
   418     @Override @DefinedBy(Api.COMPILER)
   197     public NestingKind getNestingKind() {
   419     public NestingKind getNestingKind() {
   204     }
   426     }
   205 
   427 
   206     @Override @DefinedBy(Api.COMPILER)
   428     @Override @DefinedBy(Api.COMPILER)
   207     public URI toUri() {
   429     public URI toUri() {
   208         return path.toUri();
   430         return path.toUri();
   209     }
       
   210 
       
   211     @Override @DefinedBy(Api.COMPILER)
       
   212     public String getName() {
       
   213         return path.toString();
       
   214     }
   431     }
   215 
   432 
   216     @Override @DefinedBy(Api.COMPILER)
   433     @Override @DefinedBy(Api.COMPILER)
   217     public InputStream openInputStream() throws IOException {
   434     public InputStream openInputStream() throws IOException {
   218         return Files.newInputStream(path);
   435         return Files.newInputStream(path);
   262     @Override @DefinedBy(Api.COMPILER)
   479     @Override @DefinedBy(Api.COMPILER)
   263     public long getLastModified() {
   480     public long getLastModified() {
   264         try {
   481         try {
   265             return Files.getLastModifiedTime(path).toMillis();
   482             return Files.getLastModifiedTime(path).toMillis();
   266         } catch (IOException e) {
   483         } catch (IOException e) {
   267             return -1;
   484             return 0;
   268         }
   485         }
   269     }
   486     }
   270 
   487 
   271     @Override @DefinedBy(Api.COMPILER)
   488     @Override @DefinedBy(Api.COMPILER)
   272     public boolean delete() {
   489     public boolean delete() {
   276         } catch (IOException e) {
   493         } catch (IOException e) {
   277             return false;
   494             return false;
   278         }
   495         }
   279     }
   496     }
   280 
   497 
   281     public boolean isSameFile(PathFileObject other) {
   498     boolean isSameFile(PathFileObject other) {
   282         try {
   499         try {
   283             return Files.isSameFile(path, other.path);
   500             return Files.isSameFile(path, other.path);
   284         } catch (IOException e) {
   501         } catch (IOException e) {
   285             return false;
   502             return false;
   286         }
   503         }
   300     public String toString() {
   517     public String toString() {
   301         return getClass().getSimpleName() + "[" + path + "]";
   518         return getClass().getSimpleName() + "[" + path + "]";
   302     }
   519     }
   303 
   520 
   304     private void ensureParentDirectoriesExist() throws IOException {
   521     private void ensureParentDirectoriesExist() throws IOException {
   305         Path parent = path.getParent();
   522         if (!hasParents) {
   306         if (parent != null)
   523             Path parent = path.getParent();
   307             Files.createDirectories(parent);
   524             if (parent != null && !Files.isDirectory(parent)) {
   308     }
   525                 try {
   309 
   526                     Files.createDirectories(parent);
   310     private long size() {
   527                 } catch (IOException e) {
   311         try {
   528                     throw new IOException("could not create parent directories", e);
   312             return Files.size(path);
   529                 }
   313         } catch (IOException e) {
   530             }
   314             return -1;
   531             hasParents = true;
   315         }
   532         }
       
   533     }
       
   534 
       
   535     protected static String toBinaryName(RelativePath relativePath) {
       
   536         return toBinaryName(relativePath.path, "/");
   316     }
   537     }
   317 
   538 
   318     protected static String toBinaryName(Path relativePath) {
   539     protected static String toBinaryName(Path relativePath) {
   319         return toBinaryName(relativePath.toString(),
   540         return toBinaryName(relativePath.toString(),
   320                 relativePath.getFileSystem().getSeparator());
   541                 relativePath.getFileSystem().getSeparator());
   321     }
   542     }
   322 
   543 
   323     protected static String toBinaryName(String relativePath, String sep) {
   544     private static String toBinaryName(String relativePath, String sep) {
   324         return removeExtension(relativePath).replace(sep, ".");
   545         return removeExtension(relativePath).replace(sep, ".");
   325     }
   546     }
   326 
   547 
   327     protected static String removeExtension(String fileName) {
   548     private static String removeExtension(String fileName) {
   328         int lastDot = fileName.lastIndexOf(".");
   549         int lastDot = fileName.lastIndexOf(".");
   329         return (lastDot == -1 ? fileName : fileName.substring(0, lastDot));
   550         return (lastDot == -1 ? fileName : fileName.substring(0, lastDot));
   330     }
   551     }
       
   552 
       
   553     /** Return the last component of a presumed hierarchical URI.
       
   554      *  From the scheme specific part of the URI, it returns the substring
       
   555      *  after the last "/" if any, or everything if no "/" is found.
       
   556      */
       
   557     public static String getSimpleName(FileObject fo) {
       
   558         URI uri = fo.toUri();
       
   559         String s = uri.getSchemeSpecificPart();
       
   560         return s.substring(s.lastIndexOf("/") + 1); // safe when / not found
       
   561 
       
   562     }
       
   563 
       
   564     /** Used when URLSyntaxException is thrown unexpectedly during
       
   565      *  implementations of FileObject.toURI(). */
       
   566     public static class CannotCreateUriError extends Error {
       
   567         private static final long serialVersionUID = 9101708840997613546L;
       
   568         public CannotCreateUriError(String value, Throwable cause) {
       
   569             super(value, cause);
       
   570         }
       
   571     }
   331 }
   572 }