langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RegularFileObject.java
changeset 34560 b6a567b677f7
parent 34481 e0ff9821f1e8
child 34561 79c436257611
equal deleted inserted replaced
34481:e0ff9821f1e8 34560:b6a567b677f7
     1 /*
       
     2  * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package com.sun.tools.javac.file;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.io.InputStream;
       
    30 import java.io.OutputStream;
       
    31 import java.io.OutputStreamWriter;
       
    32 import java.io.Writer;
       
    33 import java.lang.ref.Reference;
       
    34 import java.lang.ref.SoftReference;
       
    35 import java.net.URI;
       
    36 import java.nio.ByteBuffer;
       
    37 import java.nio.CharBuffer;
       
    38 import java.nio.charset.CharsetDecoder;
       
    39 import java.nio.file.Files;
       
    40 import java.nio.file.Path;
       
    41 import java.nio.file.Paths;
       
    42 import java.text.Normalizer;
       
    43 import java.util.Objects;
       
    44 
       
    45 import javax.tools.JavaFileObject;
       
    46 
       
    47 import com.sun.tools.javac.util.DefinedBy;
       
    48 import com.sun.tools.javac.util.DefinedBy.Api;
       
    49 
       
    50 /**
       
    51  * A subclass of JavaFileObject representing regular files.
       
    52  *
       
    53  * <p><b>This is NOT part of any supported API.
       
    54  * If you write code that depends on this, you do so at your own risk.
       
    55  * This code and its internal interfaces are subject to change or
       
    56  * deletion without notice.</b>
       
    57  */
       
    58 class RegularFileObject extends BaseFileObject {
       
    59 
       
    60     /** Have the parent directories been created?
       
    61      */
       
    62     private boolean hasParents = false;
       
    63     private String name;
       
    64     final Path file;
       
    65     private Reference<Path> absFileRef;
       
    66     final static boolean isMacOS = System.getProperty("os.name", "").contains("OS X");
       
    67 
       
    68     public RegularFileObject(JavacFileManager fileManager, Path f) {
       
    69         this(fileManager, f.getFileName().toString(), f);
       
    70     }
       
    71 
       
    72     public RegularFileObject(JavacFileManager fileManager, String name, Path f) {
       
    73         super(fileManager);
       
    74         if (Files.isDirectory(f)) {
       
    75             throw new IllegalArgumentException("directories not supported");
       
    76         }
       
    77         this.name = name;
       
    78         this.file = f;
       
    79         if (getLastModified() > System.currentTimeMillis())
       
    80             fileManager.log.warning("file.from.future", f);
       
    81     }
       
    82 
       
    83     @Override @DefinedBy(Api.COMPILER)
       
    84     public URI toUri() {
       
    85         return file.toUri().normalize();
       
    86     }
       
    87 
       
    88     @Override @DefinedBy(Api.COMPILER)
       
    89     public String getName() {
       
    90         return file.toString();
       
    91     }
       
    92 
       
    93     @Override
       
    94     public String getShortName() {
       
    95         return name;
       
    96     }
       
    97 
       
    98     @Override @DefinedBy(Api.COMPILER)
       
    99     public JavaFileObject.Kind getKind() {
       
   100         return getKind(name);
       
   101     }
       
   102 
       
   103     @Override @DefinedBy(Api.COMPILER)
       
   104     public InputStream openInputStream() throws IOException {
       
   105         return Files.newInputStream(file);
       
   106     }
       
   107 
       
   108     @Override @DefinedBy(Api.COMPILER)
       
   109     public OutputStream openOutputStream() throws IOException {
       
   110         fileManager.flushCache(this);
       
   111         ensureParentDirectoriesExist();
       
   112         return Files.newOutputStream(file);
       
   113     }
       
   114 
       
   115     @Override @DefinedBy(Api.COMPILER)
       
   116     public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException {
       
   117         CharBuffer cb = fileManager.getCachedContent(this);
       
   118         if (cb == null) {
       
   119             try (InputStream in = Files.newInputStream(file)) {
       
   120                 ByteBuffer bb = fileManager.makeByteBuffer(in);
       
   121                 JavaFileObject prev = fileManager.log.useSource(this);
       
   122                 try {
       
   123                     cb = fileManager.decode(bb, ignoreEncodingErrors);
       
   124                 } finally {
       
   125                     fileManager.log.useSource(prev);
       
   126                 }
       
   127                 fileManager.recycleByteBuffer(bb);
       
   128                 if (!ignoreEncodingErrors) {
       
   129                     fileManager.cache(this, cb);
       
   130                 }
       
   131             }
       
   132         }
       
   133         return cb;
       
   134     }
       
   135 
       
   136     @Override @DefinedBy(Api.COMPILER)
       
   137     public Writer openWriter() throws IOException {
       
   138         fileManager.flushCache(this);
       
   139         ensureParentDirectoriesExist();
       
   140         return new OutputStreamWriter(Files.newOutputStream(file), fileManager.getEncodingName());
       
   141     }
       
   142 
       
   143     @Override @DefinedBy(Api.COMPILER)
       
   144     public long getLastModified() {
       
   145         try {
       
   146             return Files.getLastModifiedTime(file).toMillis();
       
   147         } catch (IOException e) {
       
   148             return 0;
       
   149         }
       
   150     }
       
   151 
       
   152     @Override @DefinedBy(Api.COMPILER)
       
   153     public boolean delete() {
       
   154         try {
       
   155             Files.delete(file);
       
   156             return true;
       
   157         } catch (IOException e) {
       
   158             return false;
       
   159         }
       
   160     }
       
   161 
       
   162     @Override
       
   163     protected CharsetDecoder getDecoder(boolean ignoreEncodingErrors) {
       
   164         return fileManager.getDecoder(fileManager.getEncodingName(), ignoreEncodingErrors);
       
   165     }
       
   166 
       
   167     @Override
       
   168     protected String inferBinaryName(Iterable<? extends Path> path) {
       
   169         String fPath = file.toString();
       
   170         //System.err.println("RegularFileObject " + file + " " +r.getPath());
       
   171         for (Path dir: path) {
       
   172             //System.err.println("dir: " + dir);
       
   173             String sep = dir.getFileSystem().getSeparator();
       
   174             String dPath = dir.toString();
       
   175             if (dPath.length() == 0)
       
   176                 dPath = System.getProperty("user.dir");
       
   177             if (!dPath.endsWith(sep))
       
   178                 dPath += sep;
       
   179             if (fPath.regionMatches(true, 0, dPath, 0, dPath.length())
       
   180                 && Paths.get(fPath.substring(0, dPath.length())).equals(Paths.get(dPath))) {
       
   181                 String relativeName = fPath.substring(dPath.length());
       
   182                 return removeExtension(relativeName).replace(sep, ".");
       
   183             }
       
   184         }
       
   185         return null;
       
   186     }
       
   187 
       
   188     @Override @DefinedBy(Api.COMPILER)
       
   189     public boolean isNameCompatible(String cn, JavaFileObject.Kind kind) {
       
   190         Objects.requireNonNull(cn);
       
   191         // null check
       
   192         if (kind == Kind.OTHER && getKind() != kind) {
       
   193             return false;
       
   194         }
       
   195         String n = cn + kind.extension;
       
   196         if (name.equals(n)) {
       
   197             return true;
       
   198         }
       
   199         if (isMacOS && Normalizer.isNormalized(name, Normalizer.Form.NFD)
       
   200             && Normalizer.isNormalized(n, Normalizer.Form.NFC)) {
       
   201             // On Mac OS X it is quite possible to file name and class
       
   202             // name normalized in a different way - in that case we have to normalize file name
       
   203             // to the Normal Form Compised (NFC)
       
   204             String normName = Normalizer.normalize(name, Normalizer.Form.NFC);
       
   205             if (normName.equals(n)) {
       
   206                 this.name = normName;
       
   207                 return true;
       
   208             }
       
   209         }
       
   210 
       
   211             if (name.equalsIgnoreCase(n)) {
       
   212             try {
       
   213                 // allow for Windows
       
   214                 return file.toRealPath().getFileName().toString().equals(n);
       
   215             } catch (IOException e) {
       
   216             }
       
   217         }
       
   218         return false;
       
   219     }
       
   220 
       
   221     private void ensureParentDirectoriesExist() throws IOException {
       
   222         if (!hasParents) {
       
   223             Path parent = file.getParent();
       
   224             if (parent != null && !Files.isDirectory(parent)) {
       
   225                 try {
       
   226                     Files.createDirectories(parent);
       
   227                 } catch (IOException e) {
       
   228                     throw new IOException("could not create parent directories", e);
       
   229                 }
       
   230             }
       
   231             hasParents = true;
       
   232         }
       
   233     }
       
   234 
       
   235     /**
       
   236      * Check if two file objects are equal.
       
   237      * Two RegularFileObjects are equal if the absolute paths of the underlying
       
   238      * files are equal.
       
   239      */
       
   240     @Override
       
   241     public boolean equals(Object other) {
       
   242         if (this == other)
       
   243             return true;
       
   244 
       
   245         if (!(other instanceof RegularFileObject))
       
   246             return false;
       
   247 
       
   248         RegularFileObject o = (RegularFileObject) other;
       
   249         return getAbsoluteFile().equals(o.getAbsoluteFile());
       
   250     }
       
   251 
       
   252     @Override
       
   253     public int hashCode() {
       
   254         return getAbsoluteFile().hashCode();
       
   255     }
       
   256 
       
   257     private Path getAbsoluteFile() {
       
   258         Path absFile = (absFileRef == null ? null : absFileRef.get());
       
   259         if (absFile == null) {
       
   260             absFile = file.toAbsolutePath();
       
   261             absFileRef = new SoftReference<>(absFile);
       
   262         }
       
   263         return absFile;
       
   264     }
       
   265 }