src/share/classes/com/sun/tools/javac/file/JavacFileManager.java

Fri, 04 Jul 2008 15:06:27 -0700

author
tbell
date
Fri, 04 Jul 2008 15:06:27 -0700
changeset 62
07c916ecfc71
parent 57
aa67a5da66e3
parent 54
eaf608c64fec
child 103
e571266ae14f
permissions
-rw-r--r--

Merge

duke@1 1 /*
xdono@54 2 * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
duke@1 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1 4 *
duke@1 5 * This code is free software; you can redistribute it and/or modify it
duke@1 6 * under the terms of the GNU General Public License version 2 only, as
duke@1 7 * published by the Free Software Foundation. Sun designates this
duke@1 8 * particular file as subject to the "Classpath" exception as provided
duke@1 9 * by Sun in the LICENSE file that accompanied this code.
duke@1 10 *
duke@1 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@1 15 * accompanied this code).
duke@1 16 *
duke@1 17 * You should have received a copy of the GNU General Public License version
duke@1 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@1 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1 20 *
duke@1 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@1 22 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@1 23 * have any questions.
duke@1 24 */
duke@1 25
jjg@50 26 package com.sun.tools.javac.file;
duke@1 27
duke@1 28 import java.io.ByteArrayOutputStream;
duke@1 29 import java.io.File;
duke@1 30 import java.io.FileInputStream;
duke@1 31 import java.io.FileNotFoundException;
duke@1 32 import java.io.IOException;
duke@1 33 import java.io.InputStream;
duke@1 34 import java.io.OutputStreamWriter;
duke@1 35 import java.lang.ref.SoftReference;
duke@1 36 import java.net.MalformedURLException;
duke@1 37 import java.net.URI;
duke@1 38 import java.net.URL;
duke@1 39 import java.net.URLClassLoader;
duke@1 40 import java.nio.ByteBuffer;
duke@1 41 import java.nio.CharBuffer;
duke@1 42 import java.nio.channels.FileChannel;
duke@1 43 import java.nio.charset.Charset;
duke@1 44 import java.nio.charset.CharsetDecoder;
duke@1 45 import java.nio.charset.CoderResult;
duke@1 46 import java.nio.charset.CodingErrorAction;
duke@1 47 import java.nio.charset.IllegalCharsetNameException;
duke@1 48 import java.nio.charset.UnsupportedCharsetException;
duke@1 49 import java.util.ArrayList;
duke@1 50 import java.util.Arrays;
duke@1 51 import java.util.Collection;
duke@1 52 import java.util.Collections;
duke@1 53 import java.util.EnumSet;
duke@1 54 import java.util.HashMap;
duke@1 55 import java.util.Iterator;
duke@1 56 import java.util.Map;
duke@1 57 import java.util.Set;
jjg@50 58 import java.util.concurrent.ConcurrentHashMap;
duke@1 59 import java.util.zip.ZipFile;
duke@1 60
duke@1 61 import javax.lang.model.SourceVersion;
duke@1 62 import javax.tools.FileObject;
duke@1 63 import javax.tools.JavaFileManager;
duke@1 64 import javax.tools.JavaFileObject;
jjg@50 65 import javax.tools.StandardJavaFileManager;
duke@1 66
duke@1 67 import com.sun.tools.javac.code.Source;
jjg@50 68 import com.sun.tools.javac.main.JavacOption;
jjg@50 69 import com.sun.tools.javac.main.OptionName;
jjg@50 70 import com.sun.tools.javac.main.RecognizedOptions;
jjg@50 71 import com.sun.tools.javac.util.Context;
duke@1 72 import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
jjg@50 73 import com.sun.tools.javac.util.List;
jjg@50 74 import com.sun.tools.javac.util.ListBuffer;
jjg@50 75 import com.sun.tools.javac.util.Log;
jjg@50 76 import com.sun.tools.javac.util.Options;
duke@1 77
duke@1 78 import static com.sun.tools.javac.main.OptionName.*;
duke@1 79 import static javax.tools.StandardLocation.*;
duke@1 80
duke@1 81 /**
duke@1 82 * This class provides access to the source, class and other files
duke@1 83 * used by the compiler and related tools.
duke@1 84 */
duke@1 85 public class JavacFileManager implements StandardJavaFileManager {
duke@1 86
duke@1 87 private static final String[] symbolFileLocation = { "lib", "ct.sym" };
duke@1 88 private static final String symbolFilePrefix = "META-INF/sym/rt.jar/";
duke@1 89
duke@1 90 boolean useZipFileIndex;
duke@1 91
duke@1 92 private static boolean CHECK_ZIP_TIMESTAMP = false;
duke@1 93 private static Map<File, Boolean> isDirectory = new ConcurrentHashMap<File, Boolean>();
duke@1 94
duke@1 95
duke@1 96 public static char[] toArray(CharBuffer buffer) {
duke@1 97 if (buffer.hasArray())
duke@1 98 return ((CharBuffer)buffer.compact().flip()).array();
duke@1 99 else
duke@1 100 return buffer.toString().toCharArray();
duke@1 101 }
duke@1 102
duke@1 103 /**
duke@1 104 * The log to be used for error reporting.
duke@1 105 */
duke@1 106 protected Log log;
duke@1 107
duke@1 108 /** Encapsulates knowledge of paths
duke@1 109 */
duke@1 110 private Paths paths;
duke@1 111
duke@1 112 private Options options;
duke@1 113
duke@1 114 private final File uninited = new File("U N I N I T E D");
duke@1 115
duke@1 116 private final Set<JavaFileObject.Kind> sourceOrClass =
duke@1 117 EnumSet.of(JavaFileObject.Kind.SOURCE, JavaFileObject.Kind.CLASS);
duke@1 118
duke@1 119 /** The standard output directory, primarily used for classes.
duke@1 120 * Initialized by the "-d" option.
duke@1 121 * If classOutDir = null, files are written into same directory as the sources
duke@1 122 * they were generated from.
duke@1 123 */
duke@1 124 private File classOutDir = uninited;
duke@1 125
duke@1 126 /** The output directory, used when generating sources while processing annotations.
duke@1 127 * Initialized by the "-s" option.
duke@1 128 */
duke@1 129 private File sourceOutDir = uninited;
duke@1 130
duke@1 131 protected boolean mmappedIO;
duke@1 132 protected boolean ignoreSymbolFile;
duke@1 133
duke@1 134 /**
duke@1 135 * User provided charset (through javax.tools).
duke@1 136 */
duke@1 137 protected Charset charset;
duke@1 138
duke@1 139 /**
duke@1 140 * Register a Context.Factory to create a JavacFileManager.
duke@1 141 */
duke@1 142 public static void preRegister(final Context context) {
duke@1 143 context.put(JavaFileManager.class, new Context.Factory<JavaFileManager>() {
duke@1 144 public JavaFileManager make() {
duke@1 145 return new JavacFileManager(context, true, null);
duke@1 146 }
duke@1 147 });
duke@1 148 }
duke@1 149
duke@1 150 /**
duke@1 151 * Create a JavacFileManager using a given context, optionally registering
duke@1 152 * it as the JavaFileManager for that context.
duke@1 153 */
duke@1 154 public JavacFileManager(Context context, boolean register, Charset charset) {
duke@1 155 if (register)
duke@1 156 context.put(JavaFileManager.class, this);
duke@1 157 byteBufferCache = new ByteBufferCache();
duke@1 158 this.charset = charset;
duke@1 159 setContext(context);
duke@1 160 }
duke@1 161
duke@1 162 /**
duke@1 163 * Set the context for JavacFileManager.
duke@1 164 */
duke@1 165 public void setContext(Context context) {
duke@1 166 log = Log.instance(context);
duke@1 167 if (paths == null) {
duke@1 168 paths = Paths.instance(context);
duke@1 169 } else {
duke@1 170 // Reuse the Paths object as it stores the locations that
duke@1 171 // have been set with setLocation, etc.
duke@1 172 paths.setContext(context);
duke@1 173 }
duke@1 174
duke@1 175 options = Options.instance(context);
duke@1 176
duke@1 177 useZipFileIndex = System.getProperty("useJavaUtilZip") == null;// TODO: options.get("useJavaUtilZip") == null;
duke@1 178 CHECK_ZIP_TIMESTAMP = System.getProperty("checkZipIndexTimestamp") != null;// TODO: options.get("checkZipIndexTimestamp") != null;
duke@1 179
duke@1 180 mmappedIO = options.get("mmappedIO") != null;
duke@1 181 ignoreSymbolFile = options.get("ignore.symbol.file") != null;
duke@1 182 }
duke@1 183
duke@1 184 public JavaFileObject getFileForInput(String name) {
duke@1 185 return getRegularFile(new File(name));
duke@1 186 }
duke@1 187
duke@1 188 public JavaFileObject getRegularFile(File file) {
jjg@57 189 return new RegularFileObject(this, file);
duke@1 190 }
duke@1 191
duke@1 192 public JavaFileObject getFileForOutput(String classname,
duke@1 193 JavaFileObject.Kind kind,
duke@1 194 JavaFileObject sibling)
duke@1 195 throws IOException
duke@1 196 {
duke@1 197 return getJavaFileForOutput(CLASS_OUTPUT, classname, kind, sibling);
duke@1 198 }
duke@1 199
duke@1 200 public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) {
duke@1 201 ListBuffer<File> files = new ListBuffer<File>();
duke@1 202 for (String name : names)
duke@1 203 files.append(new File(nullCheck(name)));
duke@1 204 return getJavaFileObjectsFromFiles(files.toList());
duke@1 205 }
duke@1 206
duke@1 207 public Iterable<? extends JavaFileObject> getJavaFileObjects(String... names) {
duke@1 208 return getJavaFileObjectsFromStrings(Arrays.asList(nullCheck(names)));
duke@1 209 }
duke@1 210
duke@1 211 protected JavaFileObject.Kind getKind(String extension) {
duke@1 212 if (extension.equals(JavaFileObject.Kind.CLASS.extension))
duke@1 213 return JavaFileObject.Kind.CLASS;
duke@1 214 else if (extension.equals(JavaFileObject.Kind.SOURCE.extension))
duke@1 215 return JavaFileObject.Kind.SOURCE;
duke@1 216 else if (extension.equals(JavaFileObject.Kind.HTML.extension))
duke@1 217 return JavaFileObject.Kind.HTML;
duke@1 218 else
duke@1 219 return JavaFileObject.Kind.OTHER;
duke@1 220 }
duke@1 221
duke@1 222 private static boolean isValidName(String name) {
duke@1 223 // Arguably, isValidName should reject keywords (such as in SourceVersion.isName() ),
duke@1 224 // but the set of keywords depends on the source level, and we don't want
duke@1 225 // impls of JavaFileManager to have to be dependent on the source level.
duke@1 226 // Therefore we simply check that the argument is a sequence of identifiers
duke@1 227 // separated by ".".
duke@1 228 for (String s : name.split("\\.", -1)) {
duke@1 229 if (!SourceVersion.isIdentifier(s))
duke@1 230 return false;
duke@1 231 }
duke@1 232 return true;
duke@1 233 }
duke@1 234
duke@1 235 private static void validateClassName(String className) {
duke@1 236 if (!isValidName(className))
duke@1 237 throw new IllegalArgumentException("Invalid class name: " + className);
duke@1 238 }
duke@1 239
duke@1 240 private static void validatePackageName(String packageName) {
duke@1 241 if (packageName.length() > 0 && !isValidName(packageName))
duke@1 242 throw new IllegalArgumentException("Invalid packageName name: " + packageName);
duke@1 243 }
duke@1 244
duke@1 245 public static void testName(String name,
duke@1 246 boolean isValidPackageName,
duke@1 247 boolean isValidClassName)
duke@1 248 {
duke@1 249 try {
duke@1 250 validatePackageName(name);
duke@1 251 if (!isValidPackageName)
duke@1 252 throw new AssertionError("Invalid package name accepted: " + name);
duke@1 253 printAscii("Valid package name: \"%s\"", name);
duke@1 254 } catch (IllegalArgumentException e) {
duke@1 255 if (isValidPackageName)
duke@1 256 throw new AssertionError("Valid package name rejected: " + name);
duke@1 257 printAscii("Invalid package name: \"%s\"", name);
duke@1 258 }
duke@1 259 try {
duke@1 260 validateClassName(name);
duke@1 261 if (!isValidClassName)
duke@1 262 throw new AssertionError("Invalid class name accepted: " + name);
duke@1 263 printAscii("Valid class name: \"%s\"", name);
duke@1 264 } catch (IllegalArgumentException e) {
duke@1 265 if (isValidClassName)
duke@1 266 throw new AssertionError("Valid class name rejected: " + name);
duke@1 267 printAscii("Invalid class name: \"%s\"", name);
duke@1 268 }
duke@1 269 }
duke@1 270 private static void printAscii(String format, Object... args) {
duke@1 271 String message;
duke@1 272 try {
duke@1 273 final String ascii = "US-ASCII";
duke@1 274 message = new String(String.format(null, format, args).getBytes(ascii), ascii);
duke@1 275 } catch (java.io.UnsupportedEncodingException ex) {
duke@1 276 throw new AssertionError(ex);
duke@1 277 }
duke@1 278 System.out.println(message);
duke@1 279 }
duke@1 280
duke@1 281 /** Return external representation of name,
duke@1 282 * converting '.' to File.separatorChar.
duke@1 283 */
duke@1 284 private static String externalizeFileName(CharSequence name) {
duke@1 285 return name.toString().replace('.', File.separatorChar);
duke@1 286 }
duke@1 287
duke@1 288 private static String externalizeFileName(CharSequence n, JavaFileObject.Kind kind) {
duke@1 289 return externalizeFileName(n) + kind.extension;
duke@1 290 }
duke@1 291
duke@1 292 private static String baseName(String fileName) {
duke@1 293 return fileName.substring(fileName.lastIndexOf(File.separatorChar) + 1);
duke@1 294 }
duke@1 295
duke@1 296 /**
duke@1 297 * Insert all files in subdirectory `subdirectory' of `directory' which end
duke@1 298 * in one of the extensions in `extensions' into packageSym.
duke@1 299 */
duke@1 300 private void listDirectory(File directory,
duke@1 301 String subdirectory,
duke@1 302 Set<JavaFileObject.Kind> fileKinds,
duke@1 303 boolean recurse,
duke@1 304 ListBuffer<JavaFileObject> l) {
duke@1 305 Archive archive = archives.get(directory);
duke@1 306
duke@1 307 boolean isFile = false;
duke@1 308 if (CHECK_ZIP_TIMESTAMP) {
duke@1 309 Boolean isf = isDirectory.get(directory);
duke@1 310 if (isf == null) {
duke@1 311 isFile = directory.isFile();
duke@1 312 isDirectory.put(directory, isFile);
duke@1 313 }
duke@1 314 else {
duke@1 315 isFile = directory.isFile();
duke@1 316 }
duke@1 317 }
duke@1 318 else {
duke@1 319 isFile = directory.isFile();
duke@1 320 }
duke@1 321
duke@1 322 if (archive != null || isFile) {
duke@1 323 if (archive == null) {
duke@1 324 try {
duke@1 325 archive = openArchive(directory);
duke@1 326 } catch (IOException ex) {
duke@1 327 log.error("error.reading.file",
duke@1 328 directory, ex.getLocalizedMessage());
duke@1 329 return;
duke@1 330 }
duke@1 331 }
duke@1 332 if (subdirectory.length() != 0) {
duke@1 333 if (!useZipFileIndex) {
duke@1 334 subdirectory = subdirectory.replace('\\', '/');
duke@1 335 if (!subdirectory.endsWith("/")) subdirectory = subdirectory + "/";
duke@1 336 }
duke@1 337 else {
duke@1 338 if (File.separatorChar == '/') {
duke@1 339 subdirectory = subdirectory.replace('\\', '/');
duke@1 340 }
duke@1 341 else {
duke@1 342 subdirectory = subdirectory.replace('/', '\\');
duke@1 343 }
duke@1 344
duke@1 345 if (!subdirectory.endsWith(File.separator)) subdirectory = subdirectory + File.separator;
duke@1 346 }
duke@1 347 }
duke@1 348
duke@1 349 List<String> files = archive.getFiles(subdirectory);
duke@1 350 if (files != null) {
duke@1 351 for (String file; !files.isEmpty(); files = files.tail) {
duke@1 352 file = files.head;
duke@1 353 if (isValidFile(file, fileKinds)) {
duke@1 354 l.append(archive.getFileObject(subdirectory, file));
duke@1 355 }
duke@1 356 }
duke@1 357 }
duke@1 358 if (recurse) {
duke@1 359 for (String s: archive.getSubdirectories()) {
duke@1 360 if (s.startsWith(subdirectory) && !s.equals(subdirectory)) {
duke@1 361 // Because the archive map is a flat list of directories,
duke@1 362 // the enclosing loop will pick up all child subdirectories.
duke@1 363 // Therefore, there is no need to recurse deeper.
duke@1 364 listDirectory(directory, s, fileKinds, false, l);
duke@1 365 }
duke@1 366 }
duke@1 367 }
duke@1 368 } else {
duke@1 369 File d = subdirectory.length() != 0
duke@1 370 ? new File(directory, subdirectory)
duke@1 371 : directory;
duke@1 372 if (!caseMapCheck(d, subdirectory))
duke@1 373 return;
duke@1 374
duke@1 375 File[] files = d.listFiles();
duke@1 376 if (files == null)
duke@1 377 return;
duke@1 378
duke@1 379 for (File f: files) {
duke@1 380 String fname = f.getName();
duke@1 381 if (f.isDirectory()) {
duke@1 382 if (recurse && SourceVersion.isIdentifier(fname)) {
duke@1 383 listDirectory(directory,
duke@1 384 subdirectory + File.separator + fname,
duke@1 385 fileKinds,
duke@1 386 recurse,
duke@1 387 l);
duke@1 388 }
duke@1 389 } else {
duke@1 390 if (isValidFile(fname, fileKinds)) {
duke@1 391 JavaFileObject fe =
jjg@57 392 new RegularFileObject(this, fname, new File(d, fname));
duke@1 393 l.append(fe);
duke@1 394 }
duke@1 395 }
duke@1 396 }
duke@1 397 }
duke@1 398 }
duke@1 399
duke@1 400 private boolean isValidFile(String s, Set<JavaFileObject.Kind> fileKinds) {
duke@1 401 int lastDot = s.lastIndexOf(".");
duke@1 402 String extn = (lastDot == -1 ? s : s.substring(lastDot));
duke@1 403 JavaFileObject.Kind kind = getKind(extn);
duke@1 404 return fileKinds.contains(kind);
duke@1 405 }
duke@1 406
duke@1 407 private static final boolean fileSystemIsCaseSensitive =
duke@1 408 File.separatorChar == '/';
duke@1 409
duke@1 410 /** Hack to make Windows case sensitive. Test whether given path
duke@1 411 * ends in a string of characters with the same case as given name.
duke@1 412 * Ignore file separators in both path and name.
duke@1 413 */
duke@1 414 private boolean caseMapCheck(File f, String name) {
duke@1 415 if (fileSystemIsCaseSensitive) return true;
duke@1 416 // Note that getCanonicalPath() returns the case-sensitive
duke@1 417 // spelled file name.
duke@1 418 String path;
duke@1 419 try {
duke@1 420 path = f.getCanonicalPath();
duke@1 421 } catch (IOException ex) {
duke@1 422 return false;
duke@1 423 }
duke@1 424 char[] pcs = path.toCharArray();
duke@1 425 char[] ncs = name.toCharArray();
duke@1 426 int i = pcs.length - 1;
duke@1 427 int j = ncs.length - 1;
duke@1 428 while (i >= 0 && j >= 0) {
duke@1 429 while (i >= 0 && pcs[i] == File.separatorChar) i--;
duke@1 430 while (j >= 0 && ncs[j] == File.separatorChar) j--;
duke@1 431 if (i >= 0 && j >= 0) {
duke@1 432 if (pcs[i] != ncs[j]) return false;
duke@1 433 i--;
duke@1 434 j--;
duke@1 435 }
duke@1 436 }
duke@1 437 return j < 0;
duke@1 438 }
duke@1 439
duke@1 440 /**
duke@1 441 * An archive provides a flat directory structure of a ZipFile by
duke@1 442 * mapping directory names to lists of files (basenames).
duke@1 443 */
duke@1 444 public interface Archive {
duke@1 445 void close() throws IOException;
duke@1 446
duke@1 447 boolean contains(String name);
duke@1 448
duke@1 449 JavaFileObject getFileObject(String subdirectory, String file);
duke@1 450
duke@1 451 List<String> getFiles(String subdirectory);
duke@1 452
duke@1 453 Set<String> getSubdirectories();
duke@1 454 }
duke@1 455
duke@1 456 public class MissingArchive implements Archive {
duke@1 457 final File zipFileName;
duke@1 458 public MissingArchive(File name) {
duke@1 459 zipFileName = name;
duke@1 460 }
duke@1 461 public boolean contains(String name) {
jjg@57 462 return false;
duke@1 463 }
duke@1 464
duke@1 465 public void close() {
duke@1 466 }
duke@1 467
duke@1 468 public JavaFileObject getFileObject(String subdirectory, String file) {
duke@1 469 return null;
duke@1 470 }
duke@1 471
duke@1 472 public List<String> getFiles(String subdirectory) {
duke@1 473 return List.nil();
duke@1 474 }
duke@1 475
duke@1 476 public Set<String> getSubdirectories() {
duke@1 477 return Collections.emptySet();
duke@1 478 }
duke@1 479 }
duke@1 480
duke@1 481 /** A directory of zip files already opened.
duke@1 482 */
duke@1 483 Map<File, Archive> archives = new HashMap<File,Archive>();
duke@1 484
duke@1 485 /** Open a new zip file directory.
duke@1 486 */
duke@1 487 protected Archive openArchive(File zipFileName) throws IOException {
duke@1 488 Archive archive = archives.get(zipFileName);
duke@1 489 if (archive == null) {
duke@1 490 File origZipFileName = zipFileName;
duke@1 491 if (!ignoreSymbolFile && paths.isBootClassPathRtJar(zipFileName)) {
duke@1 492 File file = zipFileName.getParentFile().getParentFile(); // ${java.home}
duke@1 493 if (new File(file.getName()).equals(new File("jre")))
duke@1 494 file = file.getParentFile();
duke@1 495 // file == ${jdk.home}
duke@1 496 for (String name : symbolFileLocation)
duke@1 497 file = new File(file, name);
duke@1 498 // file == ${jdk.home}/lib/ct.sym
duke@1 499 if (file.exists())
duke@1 500 zipFileName = file;
duke@1 501 }
duke@1 502
duke@1 503 try {
duke@1 504
duke@1 505 ZipFile zdir = null;
duke@1 506
duke@1 507 boolean usePreindexedCache = false;
duke@1 508 String preindexCacheLocation = null;
duke@1 509
duke@1 510 if (!useZipFileIndex) {
duke@1 511 zdir = new ZipFile(zipFileName);
duke@1 512 }
duke@1 513 else {
duke@1 514 usePreindexedCache = options.get("usezipindex") != null;
duke@1 515 preindexCacheLocation = options.get("java.io.tmpdir");
duke@1 516 String optCacheLoc = options.get("cachezipindexdir");
duke@1 517
duke@1 518 if (optCacheLoc != null && optCacheLoc.length() != 0) {
duke@1 519 if (optCacheLoc.startsWith("\"")) {
duke@1 520 if (optCacheLoc.endsWith("\"")) {
duke@1 521 optCacheLoc = optCacheLoc.substring(1, optCacheLoc.length() - 1);
duke@1 522 }
duke@1 523 else {
duke@1 524 optCacheLoc = optCacheLoc.substring(1);
duke@1 525 }
duke@1 526 }
duke@1 527
duke@1 528 File cacheDir = new File(optCacheLoc);
duke@1 529 if (cacheDir.exists() && cacheDir.canWrite()) {
duke@1 530 preindexCacheLocation = optCacheLoc;
duke@1 531 if (!preindexCacheLocation.endsWith("/") &&
duke@1 532 !preindexCacheLocation.endsWith(File.separator)) {
duke@1 533 preindexCacheLocation += File.separator;
duke@1 534 }
duke@1 535 }
duke@1 536 }
duke@1 537 }
duke@1 538
duke@1 539 if (origZipFileName == zipFileName) {
duke@1 540 if (!useZipFileIndex) {
jjg@57 541 archive = new ZipArchive(this, zdir);
duke@1 542 } else {
jjg@57 543 archive = new ZipFileIndexArchive(this, ZipFileIndex.getZipFileIndex(zipFileName, null,
duke@1 544 usePreindexedCache, preindexCacheLocation, options.get("writezipindexfiles") != null));
duke@1 545 }
duke@1 546 }
duke@1 547 else {
duke@1 548 if (!useZipFileIndex) {
jjg@57 549 archive = new SymbolArchive(this, origZipFileName, zdir, symbolFilePrefix);
duke@1 550 }
duke@1 551 else {
jjg@57 552 archive = new ZipFileIndexArchive(this,
jjg@57 553 ZipFileIndex.getZipFileIndex(zipFileName,
jjg@57 554 symbolFilePrefix,
jjg@57 555 usePreindexedCache,
jjg@57 556 preindexCacheLocation,
jjg@57 557 options.get("writezipindexfiles") != null));
duke@1 558 }
duke@1 559 }
duke@1 560 } catch (FileNotFoundException ex) {
duke@1 561 archive = new MissingArchive(zipFileName);
duke@1 562 } catch (IOException ex) {
jjg@56 563 if (zipFileName.exists())
jjg@56 564 log.error("error.reading.file", zipFileName, ex.getLocalizedMessage());
duke@1 565 archive = new MissingArchive(zipFileName);
duke@1 566 }
duke@1 567
duke@1 568 archives.put(origZipFileName, archive);
duke@1 569 }
duke@1 570 return archive;
duke@1 571 }
duke@1 572
duke@1 573 /** Flush any output resources.
duke@1 574 */
duke@1 575 public void flush() {
duke@1 576 contentCache.clear();
duke@1 577 }
duke@1 578
duke@1 579 /**
duke@1 580 * Close the JavaFileManager, releasing resources.
duke@1 581 */
duke@1 582 public void close() {
duke@1 583 for (Iterator<Archive> i = archives.values().iterator(); i.hasNext(); ) {
duke@1 584 Archive a = i.next();
duke@1 585 i.remove();
duke@1 586 try {
duke@1 587 a.close();
duke@1 588 } catch (IOException e) {
duke@1 589 }
duke@1 590 }
duke@1 591 }
duke@1 592
jjg@57 593 CharBuffer getCachedContent(JavaFileObject file) {
jjg@57 594 SoftReference<CharBuffer> r = contentCache.get(file);
jjg@57 595 return (r == null ? null : r.get());
jjg@57 596 }
jjg@57 597
jjg@57 598 void cache(JavaFileObject file, CharBuffer cb) {
jjg@57 599 contentCache.put(file, new SoftReference<CharBuffer>(cb));
jjg@57 600 }
jjg@57 601
jjg@57 602 private final Map<JavaFileObject, SoftReference<CharBuffer>> contentCache
jjg@57 603 = new HashMap<JavaFileObject, SoftReference<CharBuffer>>();
duke@1 604
duke@1 605 private String defaultEncodingName;
duke@1 606 private String getDefaultEncodingName() {
duke@1 607 if (defaultEncodingName == null) {
duke@1 608 defaultEncodingName =
duke@1 609 new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding();
duke@1 610 }
duke@1 611 return defaultEncodingName;
duke@1 612 }
duke@1 613
duke@1 614 protected String getEncodingName() {
duke@1 615 String encName = options.get(OptionName.ENCODING);
duke@1 616 if (encName == null)
duke@1 617 return getDefaultEncodingName();
duke@1 618 else
duke@1 619 return encName;
duke@1 620 }
duke@1 621
duke@1 622 protected Source getSource() {
duke@1 623 String sourceName = options.get(OptionName.SOURCE);
duke@1 624 Source source = null;
duke@1 625 if (sourceName != null)
duke@1 626 source = Source.lookup(sourceName);
duke@1 627 return (source != null ? source : Source.DEFAULT);
duke@1 628 }
duke@1 629
duke@1 630 /**
duke@1 631 * Make a byte buffer from an input stream.
duke@1 632 */
jjg@57 633 ByteBuffer makeByteBuffer(InputStream in)
duke@1 634 throws IOException {
duke@1 635 int limit = in.available();
duke@1 636 if (mmappedIO && in instanceof FileInputStream) {
duke@1 637 // Experimental memory mapped I/O
duke@1 638 FileInputStream fin = (FileInputStream)in;
duke@1 639 return fin.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, limit);
duke@1 640 }
duke@1 641 if (limit < 1024) limit = 1024;
duke@1 642 ByteBuffer result = byteBufferCache.get(limit);
duke@1 643 int position = 0;
duke@1 644 while (in.available() != 0) {
duke@1 645 if (position >= limit)
duke@1 646 // expand buffer
duke@1 647 result = ByteBuffer.
duke@1 648 allocate(limit <<= 1).
duke@1 649 put((ByteBuffer)result.flip());
duke@1 650 int count = in.read(result.array(),
duke@1 651 position,
duke@1 652 limit - position);
duke@1 653 if (count < 0) break;
duke@1 654 result.position(position += count);
duke@1 655 }
duke@1 656 return (ByteBuffer)result.flip();
duke@1 657 }
duke@1 658
jjg@57 659 void recycleByteBuffer(ByteBuffer bb) {
jjg@57 660 byteBufferCache.put(bb);
jjg@57 661 }
jjg@57 662
duke@1 663 /**
duke@1 664 * A single-element cache of direct byte buffers.
duke@1 665 */
duke@1 666 private static class ByteBufferCache {
duke@1 667 private ByteBuffer cached;
duke@1 668 ByteBuffer get(int capacity) {
duke@1 669 if (capacity < 20480) capacity = 20480;
duke@1 670 ByteBuffer result =
duke@1 671 (cached != null && cached.capacity() >= capacity)
duke@1 672 ? (ByteBuffer)cached.clear()
duke@1 673 : ByteBuffer.allocate(capacity + capacity>>1);
duke@1 674 cached = null;
duke@1 675 return result;
duke@1 676 }
duke@1 677 void put(ByteBuffer x) {
duke@1 678 cached = x;
duke@1 679 }
duke@1 680 }
jjg@57 681
duke@1 682 private final ByteBufferCache byteBufferCache;
duke@1 683
jjg@57 684 CharsetDecoder getDecoder(String encodingName, boolean ignoreEncodingErrors) {
duke@1 685 Charset charset = (this.charset == null)
duke@1 686 ? Charset.forName(encodingName)
duke@1 687 : this.charset;
duke@1 688 CharsetDecoder decoder = charset.newDecoder();
duke@1 689
duke@1 690 CodingErrorAction action;
duke@1 691 if (ignoreEncodingErrors)
duke@1 692 action = CodingErrorAction.REPLACE;
duke@1 693 else
duke@1 694 action = CodingErrorAction.REPORT;
duke@1 695
duke@1 696 return decoder
duke@1 697 .onMalformedInput(action)
duke@1 698 .onUnmappableCharacter(action);
duke@1 699 }
duke@1 700
duke@1 701 /**
duke@1 702 * Decode a ByteBuffer into a CharBuffer.
duke@1 703 */
jjg@57 704 CharBuffer decode(ByteBuffer inbuf, boolean ignoreEncodingErrors) {
duke@1 705 String encodingName = getEncodingName();
duke@1 706 CharsetDecoder decoder;
duke@1 707 try {
duke@1 708 decoder = getDecoder(encodingName, ignoreEncodingErrors);
duke@1 709 } catch (IllegalCharsetNameException e) {
duke@1 710 log.error("unsupported.encoding", encodingName);
duke@1 711 return (CharBuffer)CharBuffer.allocate(1).flip();
duke@1 712 } catch (UnsupportedCharsetException e) {
duke@1 713 log.error("unsupported.encoding", encodingName);
duke@1 714 return (CharBuffer)CharBuffer.allocate(1).flip();
duke@1 715 }
duke@1 716
duke@1 717 // slightly overestimate the buffer size to avoid reallocation.
duke@1 718 float factor =
duke@1 719 decoder.averageCharsPerByte() * 0.8f +
duke@1 720 decoder.maxCharsPerByte() * 0.2f;
duke@1 721 CharBuffer dest = CharBuffer.
duke@1 722 allocate(10 + (int)(inbuf.remaining()*factor));
duke@1 723
duke@1 724 while (true) {
duke@1 725 CoderResult result = decoder.decode(inbuf, dest, true);
duke@1 726 dest.flip();
duke@1 727
duke@1 728 if (result.isUnderflow()) { // done reading
duke@1 729 // make sure there is at least one extra character
duke@1 730 if (dest.limit() == dest.capacity()) {
duke@1 731 dest = CharBuffer.allocate(dest.capacity()+1).put(dest);
duke@1 732 dest.flip();
duke@1 733 }
duke@1 734 return dest;
duke@1 735 } else if (result.isOverflow()) { // buffer too small; expand
duke@1 736 int newCapacity =
duke@1 737 10 + dest.capacity() +
duke@1 738 (int)(inbuf.remaining()*decoder.maxCharsPerByte());
duke@1 739 dest = CharBuffer.allocate(newCapacity).put(dest);
duke@1 740 } else if (result.isMalformed() || result.isUnmappable()) {
duke@1 741 // bad character in input
duke@1 742
duke@1 743 // report coding error (warn only pre 1.5)
duke@1 744 if (!getSource().allowEncodingErrors()) {
duke@1 745 log.error(new SimpleDiagnosticPosition(dest.limit()),
duke@1 746 "illegal.char.for.encoding",
duke@1 747 charset == null ? encodingName : charset.name());
duke@1 748 } else {
duke@1 749 log.warning(new SimpleDiagnosticPosition(dest.limit()),
duke@1 750 "illegal.char.for.encoding",
duke@1 751 charset == null ? encodingName : charset.name());
duke@1 752 }
duke@1 753
duke@1 754 // skip past the coding error
duke@1 755 inbuf.position(inbuf.position() + result.length());
duke@1 756
duke@1 757 // undo the flip() to prepare the output buffer
duke@1 758 // for more translation
duke@1 759 dest.position(dest.limit());
duke@1 760 dest.limit(dest.capacity());
duke@1 761 dest.put((char)0xfffd); // backward compatible
duke@1 762 } else {
duke@1 763 throw new AssertionError(result);
duke@1 764 }
duke@1 765 }
duke@1 766 // unreached
duke@1 767 }
duke@1 768
duke@1 769 public ClassLoader getClassLoader(Location location) {
duke@1 770 nullCheck(location);
duke@1 771 Iterable<? extends File> path = getLocation(location);
duke@1 772 if (path == null)
duke@1 773 return null;
duke@1 774 ListBuffer<URL> lb = new ListBuffer<URL>();
duke@1 775 for (File f: path) {
duke@1 776 try {
duke@1 777 lb.append(f.toURI().toURL());
duke@1 778 } catch (MalformedURLException e) {
duke@1 779 throw new AssertionError(e);
duke@1 780 }
duke@1 781 }
duke@1 782 return new URLClassLoader(lb.toArray(new URL[lb.size()]),
duke@1 783 getClass().getClassLoader());
duke@1 784 }
duke@1 785
duke@1 786 public Iterable<JavaFileObject> list(Location location,
duke@1 787 String packageName,
duke@1 788 Set<JavaFileObject.Kind> kinds,
duke@1 789 boolean recurse)
duke@1 790 throws IOException
duke@1 791 {
duke@1 792 // validatePackageName(packageName);
duke@1 793 nullCheck(packageName);
duke@1 794 nullCheck(kinds);
duke@1 795
duke@1 796 Iterable<? extends File> path = getLocation(location);
duke@1 797 if (path == null)
duke@1 798 return List.nil();
duke@1 799 String subdirectory = externalizeFileName(packageName);
duke@1 800 ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
duke@1 801
duke@1 802 for (File directory : path)
duke@1 803 listDirectory(directory, subdirectory, kinds, recurse, results);
duke@1 804
duke@1 805 return results.toList();
duke@1 806 }
duke@1 807
duke@1 808 public String inferBinaryName(Location location, JavaFileObject file) {
duke@1 809 file.getClass(); // null check
duke@1 810 location.getClass(); // null check
duke@1 811 // Need to match the path semantics of list(location, ...)
duke@1 812 Iterable<? extends File> path = getLocation(location);
duke@1 813 if (path == null) {
duke@1 814 return null;
duke@1 815 }
duke@1 816
jjg@57 817 if (file instanceof BaseFileObject) {
jjg@57 818 return ((BaseFileObject) file).inferBinaryName(path);
duke@1 819 } else
duke@1 820 throw new IllegalArgumentException(file.getClass().getName());
duke@1 821 }
duke@1 822
duke@1 823 public boolean isSameFile(FileObject a, FileObject b) {
duke@1 824 nullCheck(a);
duke@1 825 nullCheck(b);
duke@1 826 if (!(a instanceof BaseFileObject))
duke@1 827 throw new IllegalArgumentException("Not supported: " + a);
duke@1 828 if (!(b instanceof BaseFileObject))
duke@1 829 throw new IllegalArgumentException("Not supported: " + b);
duke@1 830 return a.equals(b);
duke@1 831 }
duke@1 832
duke@1 833 public boolean handleOption(String current, Iterator<String> remaining) {
duke@1 834 for (JavacOption o: javacFileManagerOptions) {
duke@1 835 if (o.matches(current)) {
duke@1 836 if (o.hasArg()) {
duke@1 837 if (remaining.hasNext()) {
duke@1 838 if (!o.process(options, current, remaining.next()))
duke@1 839 return true;
duke@1 840 }
duke@1 841 } else {
duke@1 842 if (!o.process(options, current))
duke@1 843 return true;
duke@1 844 }
duke@1 845 // operand missing, or process returned false
duke@1 846 throw new IllegalArgumentException(current);
duke@1 847 }
duke@1 848 }
duke@1 849
duke@1 850 return false;
duke@1 851 }
duke@1 852 // where
duke@1 853 private static JavacOption[] javacFileManagerOptions =
duke@1 854 RecognizedOptions.getJavacFileManagerOptions(
duke@1 855 new RecognizedOptions.GrumpyHelper());
duke@1 856
duke@1 857 public int isSupportedOption(String option) {
duke@1 858 for (JavacOption o : javacFileManagerOptions) {
duke@1 859 if (o.matches(option))
duke@1 860 return o.hasArg() ? 1 : 0;
duke@1 861 }
duke@1 862 return -1;
duke@1 863 }
duke@1 864
duke@1 865 public boolean hasLocation(Location location) {
duke@1 866 return getLocation(location) != null;
duke@1 867 }
duke@1 868
duke@1 869 public JavaFileObject getJavaFileForInput(Location location,
duke@1 870 String className,
duke@1 871 JavaFileObject.Kind kind)
duke@1 872 throws IOException
duke@1 873 {
duke@1 874 nullCheck(location);
duke@1 875 // validateClassName(className);
duke@1 876 nullCheck(className);
duke@1 877 nullCheck(kind);
duke@1 878 if (!sourceOrClass.contains(kind))
duke@1 879 throw new IllegalArgumentException("Invalid kind " + kind);
duke@1 880 return getFileForInput(location, externalizeFileName(className, kind));
duke@1 881 }
duke@1 882
duke@1 883 public FileObject getFileForInput(Location location,
duke@1 884 String packageName,
duke@1 885 String relativeName)
duke@1 886 throws IOException
duke@1 887 {
duke@1 888 nullCheck(location);
duke@1 889 // validatePackageName(packageName);
duke@1 890 nullCheck(packageName);
duke@1 891 if (!isRelativeUri(URI.create(relativeName))) // FIXME 6419701
duke@1 892 throw new IllegalArgumentException("Invalid relative name: " + relativeName);
duke@1 893 String name = packageName.length() == 0
duke@1 894 ? relativeName
duke@1 895 : new File(externalizeFileName(packageName), relativeName).getPath();
duke@1 896 return getFileForInput(location, name);
duke@1 897 }
duke@1 898
duke@1 899 private JavaFileObject getFileForInput(Location location, String name) throws IOException {
duke@1 900 Iterable<? extends File> path = getLocation(location);
duke@1 901 if (path == null)
duke@1 902 return null;
duke@1 903
duke@1 904 for (File dir: path) {
duke@1 905 if (dir.isDirectory()) {
duke@1 906 File f = new File(dir, name.replace('/', File.separatorChar));
duke@1 907 if (f.exists())
jjg@57 908 return new RegularFileObject(this, f);
duke@1 909 } else {
duke@1 910 Archive a = openArchive(dir);
duke@1 911 if (a.contains(name)) {
duke@1 912 int i = name.lastIndexOf('/');
duke@1 913 String dirname = name.substring(0, i+1);
duke@1 914 String basename = name.substring(i+1);
duke@1 915 return a.getFileObject(dirname, basename);
duke@1 916 }
duke@1 917
duke@1 918 }
duke@1 919 }
duke@1 920 return null;
duke@1 921
duke@1 922 }
duke@1 923
duke@1 924 public JavaFileObject getJavaFileForOutput(Location location,
duke@1 925 String className,
duke@1 926 JavaFileObject.Kind kind,
duke@1 927 FileObject sibling)
duke@1 928 throws IOException
duke@1 929 {
duke@1 930 nullCheck(location);
duke@1 931 // validateClassName(className);
duke@1 932 nullCheck(className);
duke@1 933 nullCheck(kind);
duke@1 934 if (!sourceOrClass.contains(kind))
duke@1 935 throw new IllegalArgumentException("Invalid kind " + kind);
duke@1 936 return getFileForOutput(location, externalizeFileName(className, kind), sibling);
duke@1 937 }
duke@1 938
duke@1 939 public FileObject getFileForOutput(Location location,
duke@1 940 String packageName,
duke@1 941 String relativeName,
duke@1 942 FileObject sibling)
duke@1 943 throws IOException
duke@1 944 {
duke@1 945 nullCheck(location);
duke@1 946 // validatePackageName(packageName);
duke@1 947 nullCheck(packageName);
duke@1 948 if (!isRelativeUri(URI.create(relativeName))) // FIXME 6419701
duke@1 949 throw new IllegalArgumentException("relativeName is invalid");
duke@1 950 String name = packageName.length() == 0
duke@1 951 ? relativeName
duke@1 952 : new File(externalizeFileName(packageName), relativeName).getPath();
duke@1 953 return getFileForOutput(location, name, sibling);
duke@1 954 }
duke@1 955
duke@1 956 private JavaFileObject getFileForOutput(Location location,
duke@1 957 String fileName,
duke@1 958 FileObject sibling)
duke@1 959 throws IOException
duke@1 960 {
duke@1 961 File dir;
duke@1 962 if (location == CLASS_OUTPUT) {
duke@1 963 if (getClassOutDir() != null) {
duke@1 964 dir = getClassOutDir();
duke@1 965 } else {
duke@1 966 File siblingDir = null;
duke@1 967 if (sibling != null && sibling instanceof RegularFileObject) {
duke@1 968 siblingDir = ((RegularFileObject)sibling).f.getParentFile();
duke@1 969 }
jjg@57 970 return new RegularFileObject(this, new File(siblingDir, baseName(fileName)));
duke@1 971 }
duke@1 972 } else if (location == SOURCE_OUTPUT) {
duke@1 973 dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir());
duke@1 974 } else {
duke@1 975 Iterable<? extends File> path = paths.getPathForLocation(location);
duke@1 976 dir = null;
duke@1 977 for (File f: path) {
duke@1 978 dir = f;
duke@1 979 break;
duke@1 980 }
duke@1 981 }
duke@1 982
duke@1 983 File file = (dir == null ? new File(fileName) : new File(dir, fileName));
jjg@57 984 return new RegularFileObject(this, file);
duke@1 985
duke@1 986 }
duke@1 987
duke@1 988 public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(
duke@1 989 Iterable<? extends File> files)
duke@1 990 {
duke@1 991 ArrayList<RegularFileObject> result;
duke@1 992 if (files instanceof Collection)
duke@1 993 result = new ArrayList<RegularFileObject>(((Collection)files).size());
duke@1 994 else
duke@1 995 result = new ArrayList<RegularFileObject>();
duke@1 996 for (File f: files)
jjg@57 997 result.add(new RegularFileObject(this, nullCheck(f)));
duke@1 998 return result;
duke@1 999 }
duke@1 1000
duke@1 1001 public Iterable<? extends JavaFileObject> getJavaFileObjects(File... files) {
duke@1 1002 return getJavaFileObjectsFromFiles(Arrays.asList(nullCheck(files)));
duke@1 1003 }
duke@1 1004
duke@1 1005 public void setLocation(Location location,
duke@1 1006 Iterable<? extends File> path)
duke@1 1007 throws IOException
duke@1 1008 {
duke@1 1009 nullCheck(location);
duke@1 1010 paths.lazy();
duke@1 1011
duke@1 1012 final File dir = location.isOutputLocation() ? getOutputDirectory(path) : null;
duke@1 1013
duke@1 1014 if (location == CLASS_OUTPUT)
duke@1 1015 classOutDir = getOutputLocation(dir, D);
duke@1 1016 else if (location == SOURCE_OUTPUT)
duke@1 1017 sourceOutDir = getOutputLocation(dir, S);
duke@1 1018 else
duke@1 1019 paths.setPathForLocation(location, path);
duke@1 1020 }
duke@1 1021 // where
duke@1 1022 private File getOutputDirectory(Iterable<? extends File> path) throws IOException {
duke@1 1023 if (path == null)
duke@1 1024 return null;
duke@1 1025 Iterator<? extends File> pathIter = path.iterator();
duke@1 1026 if (!pathIter.hasNext())
duke@1 1027 throw new IllegalArgumentException("empty path for directory");
duke@1 1028 File dir = pathIter.next();
duke@1 1029 if (pathIter.hasNext())
duke@1 1030 throw new IllegalArgumentException("path too long for directory");
duke@1 1031 if (!dir.exists())
duke@1 1032 throw new FileNotFoundException(dir + ": does not exist");
duke@1 1033 else if (!dir.isDirectory())
duke@1 1034 throw new IOException(dir + ": not a directory");
duke@1 1035 return dir;
duke@1 1036 }
duke@1 1037
duke@1 1038 private File getOutputLocation(File dir, OptionName defaultOptionName) {
duke@1 1039 if (dir != null)
duke@1 1040 return dir;
duke@1 1041 String arg = options.get(defaultOptionName);
duke@1 1042 if (arg == null)
duke@1 1043 return null;
duke@1 1044 return new File(arg);
duke@1 1045 }
duke@1 1046
duke@1 1047 public Iterable<? extends File> getLocation(Location location) {
duke@1 1048 nullCheck(location);
duke@1 1049 paths.lazy();
duke@1 1050 if (location == CLASS_OUTPUT) {
duke@1 1051 return (getClassOutDir() == null ? null : List.of(getClassOutDir()));
duke@1 1052 } else if (location == SOURCE_OUTPUT) {
duke@1 1053 return (getSourceOutDir() == null ? null : List.of(getSourceOutDir()));
duke@1 1054 } else
duke@1 1055 return paths.getPathForLocation(location);
duke@1 1056 }
duke@1 1057
duke@1 1058 private File getClassOutDir() {
duke@1 1059 if (classOutDir == uninited)
duke@1 1060 classOutDir = getOutputLocation(null, D);
duke@1 1061 return classOutDir;
duke@1 1062 }
duke@1 1063
duke@1 1064 private File getSourceOutDir() {
duke@1 1065 if (sourceOutDir == uninited)
duke@1 1066 sourceOutDir = getOutputLocation(null, S);
duke@1 1067 return sourceOutDir;
duke@1 1068 }
duke@1 1069
duke@1 1070 /**
duke@1 1071 * Enforces the specification of a "relative" URI as used in
duke@1 1072 * {@linkplain #getFileForInput(Location,String,URI)
duke@1 1073 * getFileForInput}. This method must follow the rules defined in
duke@1 1074 * that method, do not make any changes without consulting the
duke@1 1075 * specification.
duke@1 1076 */
duke@1 1077 protected static boolean isRelativeUri(URI uri) {
duke@1 1078 if (uri.isAbsolute())
duke@1 1079 return false;
duke@1 1080 String path = uri.normalize().getPath();
duke@1 1081 if (path.length() == 0 /* isEmpty() is mustang API */)
duke@1 1082 return false;
duke@1 1083 char first = path.charAt(0);
duke@1 1084 return first != '.' && first != '/';
duke@1 1085 }
duke@1 1086
duke@1 1087 /**
duke@1 1088 * Converts a relative file name to a relative URI. This is
duke@1 1089 * different from File.toURI as this method does not canonicalize
duke@1 1090 * the file before creating the URI. Furthermore, no schema is
duke@1 1091 * used.
duke@1 1092 * @param file a relative file name
duke@1 1093 * @return a relative URI
duke@1 1094 * @throws IllegalArgumentException if the file name is not
duke@1 1095 * relative according to the definition given in {@link
duke@1 1096 * javax.tools.JavaFileManager#getFileForInput}
duke@1 1097 */
duke@1 1098 public static String getRelativeName(File file) {
duke@1 1099 if (!file.isAbsolute()) {
duke@1 1100 String result = file.getPath().replace(File.separatorChar, '/');
duke@1 1101 if (JavacFileManager.isRelativeUri(URI.create(result))) // FIXME 6419701
duke@1 1102 return result;
duke@1 1103 }
duke@1 1104 throw new IllegalArgumentException("Invalid relative path: " + file);
duke@1 1105 }
duke@1 1106
duke@1 1107 @SuppressWarnings("deprecation") // bug 6410637
jjg@50 1108 public static String getJavacFileName(FileObject file) {
duke@1 1109 if (file instanceof BaseFileObject)
duke@1 1110 return ((BaseFileObject)file).getPath();
duke@1 1111 URI uri = file.toUri();
duke@1 1112 String scheme = uri.getScheme();
duke@1 1113 if (scheme == null || scheme.equals("file") || scheme.equals("jar"))
duke@1 1114 return uri.getPath();
duke@1 1115 else
duke@1 1116 return uri.toString();
duke@1 1117 }
duke@1 1118
duke@1 1119 @SuppressWarnings("deprecation") // bug 6410637
jjg@50 1120 public static String getJavacBaseFileName(FileObject file) {
duke@1 1121 if (file instanceof BaseFileObject)
duke@1 1122 return ((BaseFileObject)file).getName();
duke@1 1123 URI uri = file.toUri();
duke@1 1124 String scheme = uri.getScheme();
duke@1 1125 if (scheme == null || scheme.equals("file") || scheme.equals("jar")) {
duke@1 1126 String path = uri.getPath();
duke@1 1127 if (path == null)
duke@1 1128 return null;
duke@1 1129 if (scheme != null && scheme.equals("jar"))
duke@1 1130 path = path.substring(path.lastIndexOf('!') + 1);
duke@1 1131 return path.substring(path.lastIndexOf('/') + 1);
duke@1 1132 } else {
duke@1 1133 return uri.toString();
duke@1 1134 }
duke@1 1135 }
duke@1 1136
duke@1 1137 private static <T> T nullCheck(T o) {
duke@1 1138 o.getClass(); // null check
duke@1 1139 return o;
duke@1 1140 }
duke@1 1141
duke@1 1142 private static <T> Iterable<T> nullCheck(Iterable<T> it) {
duke@1 1143 for (T t : it)
duke@1 1144 t.getClass(); // null check
duke@1 1145 return it;
duke@1 1146 }
duke@1 1147 }

mercurial