Tue, 25 Sep 2012 13:11:05 -0700
7196464: upgrade JavaCompiler.shouldStopPolicy to accomodate policies in face of error and no error
Reviewed-by: mcimadamore
jjg@450 | 1 | /* |
ohair@962 | 2 | * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. |
jjg@450 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
jjg@450 | 4 | * |
jjg@450 | 5 | * This code is free software; you can redistribute it and/or modify it |
jjg@450 | 6 | * under the terms of the GNU General Public License version 2 only, as |
ohair@554 | 7 | * published by the Free Software Foundation. Oracle designates this |
jjg@450 | 8 | * particular file as subject to the "Classpath" exception as provided |
ohair@554 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
jjg@450 | 10 | * |
jjg@450 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
jjg@450 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
jjg@450 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
jjg@450 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
jjg@450 | 15 | * accompanied this code). |
jjg@450 | 16 | * |
jjg@450 | 17 | * You should have received a copy of the GNU General Public License version |
jjg@450 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
jjg@450 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
jjg@450 | 20 | * |
ohair@554 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
ohair@554 | 22 | * or visit www.oracle.com if you need additional information or have any |
ohair@554 | 23 | * questions. |
jjg@450 | 24 | */ |
jjg@450 | 25 | |
jjg@450 | 26 | package com.sun.tools.javac.nio; |
jjg@450 | 27 | |
jjg@450 | 28 | import java.io.IOException; |
jjg@450 | 29 | import java.io.InputStream; |
jjg@450 | 30 | import java.io.InputStreamReader; |
jjg@450 | 31 | import java.io.OutputStream; |
jjg@450 | 32 | import java.io.OutputStreamWriter; |
jjg@450 | 33 | import java.io.Reader; |
jjg@450 | 34 | import java.io.Writer; |
jjg@450 | 35 | import java.net.URI; |
jjg@450 | 36 | import java.nio.ByteBuffer; |
jjg@450 | 37 | import java.nio.CharBuffer; |
jjg@450 | 38 | import java.nio.charset.CharsetDecoder; |
jjg@450 | 39 | import java.nio.file.Files; |
alanb@959 | 40 | import java.nio.file.LinkOption; |
jjg@450 | 41 | import java.nio.file.Path; |
jjg@450 | 42 | import java.nio.file.attribute.BasicFileAttributes; |
jjg@450 | 43 | import javax.lang.model.element.Modifier; |
jjg@450 | 44 | import javax.lang.model.element.NestingKind; |
jjg@450 | 45 | import javax.tools.JavaFileObject; |
jjg@450 | 46 | |
jjg@450 | 47 | import com.sun.tools.javac.util.BaseFileManager; |
jjg@450 | 48 | |
jjg@450 | 49 | |
jjg@450 | 50 | /** |
jjg@450 | 51 | * Implementation of JavaFileObject using java.nio.file API. |
jjg@450 | 52 | * |
jjg@450 | 53 | * <p>PathFileObjects are, for the most part, straightforward wrappers around |
jjg@450 | 54 | * Path objects. The primary complexity is the support for "inferBinaryName". |
jjg@450 | 55 | * This is left as an abstract method, implemented by each of a number of |
jjg@450 | 56 | * different factory methods, which compute the binary name based on |
jjg@450 | 57 | * information available at the time the file object is created. |
jjg@450 | 58 | * |
jjg@581 | 59 | * <p><b>This is NOT part of any supported API. |
jjg@581 | 60 | * If you write code that depends on this, you do so at your own risk. |
jjg@450 | 61 | * This code and its internal interfaces are subject to change or |
jjg@450 | 62 | * deletion without notice.</b> |
jjg@450 | 63 | */ |
jjg@450 | 64 | abstract class PathFileObject implements JavaFileObject { |
jjg@450 | 65 | private JavacPathFileManager fileManager; |
jjg@450 | 66 | private Path path; |
jjg@450 | 67 | |
jjg@450 | 68 | /** |
jjg@450 | 69 | * Create a PathFileObject within a directory, such that the binary name |
jjg@450 | 70 | * can be inferred from the relationship to the parent directory. |
jjg@450 | 71 | */ |
jjg@450 | 72 | static PathFileObject createDirectoryPathFileObject(JavacPathFileManager fileManager, |
jjg@450 | 73 | final Path path, final Path dir) { |
jjg@450 | 74 | return new PathFileObject(fileManager, path) { |
jjg@450 | 75 | @Override |
jjg@450 | 76 | String inferBinaryName(Iterable<? extends Path> paths) { |
jjg@450 | 77 | return toBinaryName(dir.relativize(path)); |
jjg@450 | 78 | } |
jjg@450 | 79 | }; |
jjg@450 | 80 | } |
jjg@450 | 81 | |
jjg@450 | 82 | /** |
jjg@450 | 83 | * Create a PathFileObject in a file system such as a jar file, such that |
jjg@450 | 84 | * the binary name can be inferred from its position within the filesystem. |
jjg@450 | 85 | */ |
jjg@450 | 86 | static PathFileObject createJarPathFileObject(JavacPathFileManager fileManager, |
jjg@450 | 87 | final Path path) { |
jjg@450 | 88 | return new PathFileObject(fileManager, path) { |
jjg@450 | 89 | @Override |
jjg@450 | 90 | String inferBinaryName(Iterable<? extends Path> paths) { |
jjg@450 | 91 | return toBinaryName(path); |
jjg@450 | 92 | } |
jjg@450 | 93 | }; |
jjg@450 | 94 | } |
jjg@450 | 95 | |
jjg@450 | 96 | /** |
jjg@450 | 97 | * Create a PathFileObject whose binary name can be inferred from the |
jjg@450 | 98 | * relative path to a sibling. |
jjg@450 | 99 | */ |
jjg@450 | 100 | static PathFileObject createSiblingPathFileObject(JavacPathFileManager fileManager, |
jjg@450 | 101 | final Path path, final String relativePath) { |
jjg@450 | 102 | return new PathFileObject(fileManager, path) { |
jjg@450 | 103 | @Override |
jjg@450 | 104 | String inferBinaryName(Iterable<? extends Path> paths) { |
jjg@450 | 105 | return toBinaryName(relativePath, "/"); |
jjg@450 | 106 | } |
jjg@450 | 107 | }; |
jjg@450 | 108 | } |
jjg@450 | 109 | |
jjg@450 | 110 | /** |
jjg@450 | 111 | * Create a PathFileObject whose binary name might be inferred from its |
jjg@450 | 112 | * position on a search path. |
jjg@450 | 113 | */ |
jjg@450 | 114 | static PathFileObject createSimplePathFileObject(JavacPathFileManager fileManager, |
jjg@450 | 115 | final Path path) { |
jjg@450 | 116 | return new PathFileObject(fileManager, path) { |
jjg@450 | 117 | @Override |
jjg@450 | 118 | String inferBinaryName(Iterable<? extends Path> paths) { |
jjg@450 | 119 | Path absPath = path.toAbsolutePath(); |
jjg@450 | 120 | for (Path p: paths) { |
jjg@450 | 121 | Path ap = p.toAbsolutePath(); |
jjg@450 | 122 | if (absPath.startsWith(ap)) { |
jjg@450 | 123 | try { |
jjg@450 | 124 | Path rp = ap.relativize(absPath); |
jjg@450 | 125 | if (rp != null) // maybe null if absPath same as ap |
jjg@450 | 126 | return toBinaryName(rp); |
jjg@450 | 127 | } catch (IllegalArgumentException e) { |
jjg@450 | 128 | // ignore this p if cannot relativize path to p |
jjg@450 | 129 | } |
jjg@450 | 130 | } |
jjg@450 | 131 | } |
jjg@450 | 132 | return null; |
jjg@450 | 133 | } |
jjg@450 | 134 | }; |
jjg@450 | 135 | } |
jjg@450 | 136 | |
jjg@450 | 137 | protected PathFileObject(JavacPathFileManager fileManager, Path path) { |
jjg@450 | 138 | fileManager.getClass(); // null check |
jjg@450 | 139 | path.getClass(); // null check |
jjg@450 | 140 | this.fileManager = fileManager; |
jjg@450 | 141 | this.path = path; |
jjg@450 | 142 | } |
jjg@450 | 143 | |
jjg@450 | 144 | abstract String inferBinaryName(Iterable<? extends Path> paths); |
jjg@450 | 145 | |
jjg@450 | 146 | /** |
jjg@450 | 147 | * Return the Path for this object. |
jjg@450 | 148 | * @return the Path for this object. |
jjg@450 | 149 | */ |
jjg@450 | 150 | Path getPath() { |
jjg@450 | 151 | return path; |
jjg@450 | 152 | } |
jjg@450 | 153 | |
jjg@450 | 154 | @Override |
jjg@450 | 155 | public Kind getKind() { |
alanb@847 | 156 | return BaseFileManager.getKind(path.getFileName().toString()); |
jjg@450 | 157 | } |
jjg@450 | 158 | |
jjg@450 | 159 | @Override |
jjg@450 | 160 | public boolean isNameCompatible(String simpleName, Kind kind) { |
jjg@450 | 161 | simpleName.getClass(); |
jjg@450 | 162 | // null check |
jjg@450 | 163 | if (kind == Kind.OTHER && getKind() != kind) { |
jjg@450 | 164 | return false; |
jjg@450 | 165 | } |
jjg@450 | 166 | String sn = simpleName + kind.extension; |
alanb@847 | 167 | String pn = path.getFileName().toString(); |
jjg@450 | 168 | if (pn.equals(sn)) { |
jjg@450 | 169 | return true; |
jjg@450 | 170 | } |
jjg@450 | 171 | if (pn.equalsIgnoreCase(sn)) { |
jjg@450 | 172 | try { |
jjg@450 | 173 | // allow for Windows |
alanb@959 | 174 | return path.toRealPath(LinkOption.NOFOLLOW_LINKS).getFileName().toString().equals(sn); |
jjg@450 | 175 | } catch (IOException e) { |
jjg@450 | 176 | } |
jjg@450 | 177 | } |
jjg@450 | 178 | return false; |
jjg@450 | 179 | } |
jjg@450 | 180 | |
jjg@450 | 181 | @Override |
jjg@450 | 182 | public NestingKind getNestingKind() { |
jjg@450 | 183 | return null; |
jjg@450 | 184 | } |
jjg@450 | 185 | |
jjg@450 | 186 | @Override |
jjg@450 | 187 | public Modifier getAccessLevel() { |
jjg@450 | 188 | return null; |
jjg@450 | 189 | } |
jjg@450 | 190 | |
jjg@450 | 191 | @Override |
jjg@450 | 192 | public URI toUri() { |
jjg@450 | 193 | return path.toUri(); |
jjg@450 | 194 | } |
jjg@450 | 195 | |
jjg@450 | 196 | @Override |
jjg@450 | 197 | public String getName() { |
jjg@450 | 198 | return path.toString(); |
jjg@450 | 199 | } |
jjg@450 | 200 | |
jjg@450 | 201 | @Override |
jjg@450 | 202 | public InputStream openInputStream() throws IOException { |
alanb@847 | 203 | return Files.newInputStream(path); |
jjg@450 | 204 | } |
jjg@450 | 205 | |
jjg@450 | 206 | @Override |
jjg@450 | 207 | public OutputStream openOutputStream() throws IOException { |
jjg@1080 | 208 | fileManager.flushCache(this); |
jjg@450 | 209 | ensureParentDirectoriesExist(); |
alanb@847 | 210 | return Files.newOutputStream(path); |
jjg@450 | 211 | } |
jjg@450 | 212 | |
jjg@450 | 213 | @Override |
jjg@450 | 214 | public Reader openReader(boolean ignoreEncodingErrors) throws IOException { |
jjg@450 | 215 | CharsetDecoder decoder = fileManager.getDecoder(fileManager.getEncodingName(), ignoreEncodingErrors); |
jjg@450 | 216 | return new InputStreamReader(openInputStream(), decoder); |
jjg@450 | 217 | } |
jjg@450 | 218 | |
jjg@450 | 219 | @Override |
jjg@450 | 220 | public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { |
jjg@450 | 221 | CharBuffer cb = fileManager.getCachedContent(this); |
jjg@450 | 222 | if (cb == null) { |
jjg@450 | 223 | InputStream in = openInputStream(); |
jjg@450 | 224 | try { |
jjg@450 | 225 | ByteBuffer bb = fileManager.makeByteBuffer(in); |
jjg@450 | 226 | JavaFileObject prev = fileManager.log.useSource(this); |
jjg@450 | 227 | try { |
jjg@450 | 228 | cb = fileManager.decode(bb, ignoreEncodingErrors); |
jjg@450 | 229 | } finally { |
jjg@450 | 230 | fileManager.log.useSource(prev); |
jjg@450 | 231 | } |
jjg@450 | 232 | fileManager.recycleByteBuffer(bb); |
jjg@450 | 233 | if (!ignoreEncodingErrors) { |
jjg@450 | 234 | fileManager.cache(this, cb); |
jjg@450 | 235 | } |
jjg@450 | 236 | } finally { |
jjg@450 | 237 | in.close(); |
jjg@450 | 238 | } |
jjg@450 | 239 | } |
jjg@450 | 240 | return cb; |
jjg@450 | 241 | } |
jjg@450 | 242 | |
jjg@450 | 243 | @Override |
jjg@450 | 244 | public Writer openWriter() throws IOException { |
jjg@1080 | 245 | fileManager.flushCache(this); |
jjg@450 | 246 | ensureParentDirectoriesExist(); |
alanb@847 | 247 | return new OutputStreamWriter(Files.newOutputStream(path), fileManager.getEncodingName()); |
jjg@450 | 248 | } |
jjg@450 | 249 | |
jjg@450 | 250 | @Override |
jjg@450 | 251 | public long getLastModified() { |
jjg@450 | 252 | try { |
alanb@847 | 253 | return Files.getLastModifiedTime(path).toMillis(); |
jjg@450 | 254 | } catch (IOException e) { |
jjg@450 | 255 | return -1; |
jjg@450 | 256 | } |
jjg@450 | 257 | } |
jjg@450 | 258 | |
jjg@450 | 259 | @Override |
jjg@450 | 260 | public boolean delete() { |
jjg@450 | 261 | try { |
alanb@847 | 262 | Files.delete(path); |
jjg@450 | 263 | return true; |
jjg@450 | 264 | } catch (IOException e) { |
jjg@450 | 265 | return false; |
jjg@450 | 266 | } |
jjg@450 | 267 | } |
jjg@450 | 268 | |
jjg@450 | 269 | public boolean isSameFile(PathFileObject other) { |
jjg@450 | 270 | try { |
alanb@847 | 271 | return Files.isSameFile(path, other.path); |
jjg@450 | 272 | } catch (IOException e) { |
jjg@450 | 273 | return false; |
jjg@450 | 274 | } |
jjg@450 | 275 | } |
jjg@450 | 276 | |
jjg@450 | 277 | @Override |
jjg@450 | 278 | public boolean equals(Object other) { |
jjg@450 | 279 | return (other instanceof PathFileObject && path.equals(((PathFileObject) other).path)); |
jjg@450 | 280 | } |
jjg@450 | 281 | |
jjg@450 | 282 | @Override |
jjg@450 | 283 | public int hashCode() { |
jjg@450 | 284 | return path.hashCode(); |
jjg@450 | 285 | } |
jjg@450 | 286 | |
jjg@450 | 287 | @Override |
jjg@450 | 288 | public String toString() { |
jjg@450 | 289 | return getClass().getSimpleName() + "[" + path + "]"; |
jjg@450 | 290 | } |
jjg@450 | 291 | |
jjg@450 | 292 | private void ensureParentDirectoriesExist() throws IOException { |
jjg@450 | 293 | Path parent = path.getParent(); |
jjg@450 | 294 | if (parent != null) |
jjg@450 | 295 | Files.createDirectories(parent); |
jjg@450 | 296 | } |
jjg@450 | 297 | |
jjg@450 | 298 | private long size() { |
jjg@450 | 299 | try { |
alanb@847 | 300 | return Files.size(path); |
jjg@450 | 301 | } catch (IOException e) { |
jjg@450 | 302 | return -1; |
jjg@450 | 303 | } |
jjg@450 | 304 | } |
jjg@450 | 305 | |
jjg@450 | 306 | protected static String toBinaryName(Path relativePath) { |
jjg@450 | 307 | return toBinaryName(relativePath.toString(), |
jjg@450 | 308 | relativePath.getFileSystem().getSeparator()); |
jjg@450 | 309 | } |
jjg@450 | 310 | |
jjg@450 | 311 | protected static String toBinaryName(String relativePath, String sep) { |
jjg@466 | 312 | return removeExtension(relativePath).replace(sep, "."); |
jjg@450 | 313 | } |
jjg@450 | 314 | |
jjg@450 | 315 | protected static String removeExtension(String fileName) { |
jjg@450 | 316 | int lastDot = fileName.lastIndexOf("."); |
jjg@450 | 317 | return (lastDot == -1 ? fileName : fileName.substring(0, lastDot)); |
jjg@450 | 318 | } |
jjg@450 | 319 | } |