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

Wed, 27 Apr 2016 01:34:52 +0800

author
aoqi
date
Wed, 27 Apr 2016 01:34:52 +0800
changeset 0
959103a6100f
child 2525
2eb010b6cb22
permissions
-rw-r--r--

Initial load
http://hg.openjdk.java.net/jdk8u/jdk8u/langtools/
changeset: 2573:53ca196be1ae
tag: jdk8u25-b17

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation. Oracle designates this
aoqi@0 8 * particular file as subject to the "Classpath" exception as provided
aoqi@0 9 * by Oracle in the LICENSE file that accompanied this code.
aoqi@0 10 *
aoqi@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 14 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 15 * accompanied this code).
aoqi@0 16 *
aoqi@0 17 * You should have received a copy of the GNU General Public License version
aoqi@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 20 *
aoqi@0 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 22 * or visit www.oracle.com if you need additional information or have any
aoqi@0 23 * questions.
aoqi@0 24 */
aoqi@0 25
aoqi@0 26 package com.sun.tools.javac.file;
aoqi@0 27
aoqi@0 28 import java.io.ByteArrayOutputStream;
aoqi@0 29 import java.io.File;
aoqi@0 30 import java.io.FileNotFoundException;
aoqi@0 31 import java.io.IOException;
aoqi@0 32 import java.io.OutputStreamWriter;
aoqi@0 33 import java.net.MalformedURLException;
aoqi@0 34 import java.net.URI;
aoqi@0 35 import java.net.URISyntaxException;
aoqi@0 36 import java.net.URL;
aoqi@0 37 import java.nio.CharBuffer;
aoqi@0 38 import java.nio.charset.Charset;
aoqi@0 39 import java.util.ArrayList;
aoqi@0 40 import java.util.Arrays;
aoqi@0 41 import java.util.Collection;
aoqi@0 42 import java.util.Collections;
aoqi@0 43 import java.util.Comparator;
aoqi@0 44 import java.util.EnumSet;
aoqi@0 45 import java.util.HashMap;
aoqi@0 46 import java.util.Iterator;
aoqi@0 47 import java.util.Map;
aoqi@0 48 import java.util.Set;
aoqi@0 49 import java.util.zip.ZipFile;
aoqi@0 50
aoqi@0 51 import javax.lang.model.SourceVersion;
aoqi@0 52 import javax.tools.FileObject;
aoqi@0 53 import javax.tools.JavaFileManager;
aoqi@0 54 import javax.tools.JavaFileObject;
aoqi@0 55 import javax.tools.StandardJavaFileManager;
aoqi@0 56
aoqi@0 57 import com.sun.tools.javac.file.RelativePath.RelativeFile;
aoqi@0 58 import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
aoqi@0 59 import com.sun.tools.javac.util.BaseFileManager;
aoqi@0 60 import com.sun.tools.javac.util.Context;
aoqi@0 61 import com.sun.tools.javac.util.List;
aoqi@0 62 import com.sun.tools.javac.util.ListBuffer;
aoqi@0 63
aoqi@0 64 import static javax.tools.StandardLocation.*;
aoqi@0 65
aoqi@0 66 /**
aoqi@0 67 * This class provides access to the source, class and other files
aoqi@0 68 * used by the compiler and related tools.
aoqi@0 69 *
aoqi@0 70 * <p><b>This is NOT part of any supported API.
aoqi@0 71 * If you write code that depends on this, you do so at your own risk.
aoqi@0 72 * This code and its internal interfaces are subject to change or
aoqi@0 73 * deletion without notice.</b>
aoqi@0 74 */
aoqi@0 75 public class JavacFileManager extends BaseFileManager implements StandardJavaFileManager {
aoqi@0 76
aoqi@0 77 public static char[] toArray(CharBuffer buffer) {
aoqi@0 78 if (buffer.hasArray())
aoqi@0 79 return ((CharBuffer)buffer.compact().flip()).array();
aoqi@0 80 else
aoqi@0 81 return buffer.toString().toCharArray();
aoqi@0 82 }
aoqi@0 83
aoqi@0 84 private FSInfo fsInfo;
aoqi@0 85
aoqi@0 86 private boolean contextUseOptimizedZip;
aoqi@0 87 private ZipFileIndexCache zipFileIndexCache;
aoqi@0 88
aoqi@0 89 private final Set<JavaFileObject.Kind> sourceOrClass =
aoqi@0 90 EnumSet.of(JavaFileObject.Kind.SOURCE, JavaFileObject.Kind.CLASS);
aoqi@0 91
aoqi@0 92 protected boolean mmappedIO;
aoqi@0 93 protected boolean symbolFileEnabled;
aoqi@0 94
aoqi@0 95 protected enum SortFiles implements Comparator<File> {
aoqi@0 96 FORWARD {
aoqi@0 97 public int compare(File f1, File f2) {
aoqi@0 98 return f1.getName().compareTo(f2.getName());
aoqi@0 99 }
aoqi@0 100 },
aoqi@0 101 REVERSE {
aoqi@0 102 public int compare(File f1, File f2) {
aoqi@0 103 return -f1.getName().compareTo(f2.getName());
aoqi@0 104 }
aoqi@0 105 };
aoqi@0 106 };
aoqi@0 107 protected SortFiles sortFiles;
aoqi@0 108
aoqi@0 109 /**
aoqi@0 110 * Register a Context.Factory to create a JavacFileManager.
aoqi@0 111 */
aoqi@0 112 public static void preRegister(Context context) {
aoqi@0 113 context.put(JavaFileManager.class, new Context.Factory<JavaFileManager>() {
aoqi@0 114 public JavaFileManager make(Context c) {
aoqi@0 115 return new JavacFileManager(c, true, null);
aoqi@0 116 }
aoqi@0 117 });
aoqi@0 118 }
aoqi@0 119
aoqi@0 120 /**
aoqi@0 121 * Create a JavacFileManager using a given context, optionally registering
aoqi@0 122 * it as the JavaFileManager for that context.
aoqi@0 123 */
aoqi@0 124 public JavacFileManager(Context context, boolean register, Charset charset) {
aoqi@0 125 super(charset);
aoqi@0 126 if (register)
aoqi@0 127 context.put(JavaFileManager.class, this);
aoqi@0 128 setContext(context);
aoqi@0 129 }
aoqi@0 130
aoqi@0 131 /**
aoqi@0 132 * Set the context for JavacFileManager.
aoqi@0 133 */
aoqi@0 134 @Override
aoqi@0 135 public void setContext(Context context) {
aoqi@0 136 super.setContext(context);
aoqi@0 137
aoqi@0 138 fsInfo = FSInfo.instance(context);
aoqi@0 139
aoqi@0 140 contextUseOptimizedZip = options.getBoolean("useOptimizedZip", true);
aoqi@0 141 if (contextUseOptimizedZip)
aoqi@0 142 zipFileIndexCache = ZipFileIndexCache.getSharedInstance();
aoqi@0 143
aoqi@0 144 mmappedIO = options.isSet("mmappedIO");
aoqi@0 145 symbolFileEnabled = !options.isSet("ignore.symbol.file");
aoqi@0 146
aoqi@0 147 String sf = options.get("sortFiles");
aoqi@0 148 if (sf != null) {
aoqi@0 149 sortFiles = (sf.equals("reverse") ? SortFiles.REVERSE : SortFiles.FORWARD);
aoqi@0 150 }
aoqi@0 151 }
aoqi@0 152
aoqi@0 153 /**
aoqi@0 154 * Set whether or not to use ct.sym as an alternate to rt.jar.
aoqi@0 155 */
aoqi@0 156 public void setSymbolFileEnabled(boolean b) {
aoqi@0 157 symbolFileEnabled = b;
aoqi@0 158 }
aoqi@0 159
aoqi@0 160 @Override
aoqi@0 161 public boolean isDefaultBootClassPath() {
aoqi@0 162 return locations.isDefaultBootClassPath();
aoqi@0 163 }
aoqi@0 164
aoqi@0 165 public JavaFileObject getFileForInput(String name) {
aoqi@0 166 return getRegularFile(new File(name));
aoqi@0 167 }
aoqi@0 168
aoqi@0 169 public JavaFileObject getRegularFile(File file) {
aoqi@0 170 return new RegularFileObject(this, file);
aoqi@0 171 }
aoqi@0 172
aoqi@0 173 public JavaFileObject getFileForOutput(String classname,
aoqi@0 174 JavaFileObject.Kind kind,
aoqi@0 175 JavaFileObject sibling)
aoqi@0 176 throws IOException
aoqi@0 177 {
aoqi@0 178 return getJavaFileForOutput(CLASS_OUTPUT, classname, kind, sibling);
aoqi@0 179 }
aoqi@0 180
aoqi@0 181 public Iterable<? extends JavaFileObject> getJavaFileObjectsFromStrings(Iterable<String> names) {
aoqi@0 182 ListBuffer<File> files = new ListBuffer<File>();
aoqi@0 183 for (String name : names)
aoqi@0 184 files.append(new File(nullCheck(name)));
aoqi@0 185 return getJavaFileObjectsFromFiles(files.toList());
aoqi@0 186 }
aoqi@0 187
aoqi@0 188 public Iterable<? extends JavaFileObject> getJavaFileObjects(String... names) {
aoqi@0 189 return getJavaFileObjectsFromStrings(Arrays.asList(nullCheck(names)));
aoqi@0 190 }
aoqi@0 191
aoqi@0 192 private static boolean isValidName(String name) {
aoqi@0 193 // Arguably, isValidName should reject keywords (such as in SourceVersion.isName() ),
aoqi@0 194 // but the set of keywords depends on the source level, and we don't want
aoqi@0 195 // impls of JavaFileManager to have to be dependent on the source level.
aoqi@0 196 // Therefore we simply check that the argument is a sequence of identifiers
aoqi@0 197 // separated by ".".
aoqi@0 198 for (String s : name.split("\\.", -1)) {
aoqi@0 199 if (!SourceVersion.isIdentifier(s))
aoqi@0 200 return false;
aoqi@0 201 }
aoqi@0 202 return true;
aoqi@0 203 }
aoqi@0 204
aoqi@0 205 private static void validateClassName(String className) {
aoqi@0 206 if (!isValidName(className))
aoqi@0 207 throw new IllegalArgumentException("Invalid class name: " + className);
aoqi@0 208 }
aoqi@0 209
aoqi@0 210 private static void validatePackageName(String packageName) {
aoqi@0 211 if (packageName.length() > 0 && !isValidName(packageName))
aoqi@0 212 throw new IllegalArgumentException("Invalid packageName name: " + packageName);
aoqi@0 213 }
aoqi@0 214
aoqi@0 215 public static void testName(String name,
aoqi@0 216 boolean isValidPackageName,
aoqi@0 217 boolean isValidClassName)
aoqi@0 218 {
aoqi@0 219 try {
aoqi@0 220 validatePackageName(name);
aoqi@0 221 if (!isValidPackageName)
aoqi@0 222 throw new AssertionError("Invalid package name accepted: " + name);
aoqi@0 223 printAscii("Valid package name: \"%s\"", name);
aoqi@0 224 } catch (IllegalArgumentException e) {
aoqi@0 225 if (isValidPackageName)
aoqi@0 226 throw new AssertionError("Valid package name rejected: " + name);
aoqi@0 227 printAscii("Invalid package name: \"%s\"", name);
aoqi@0 228 }
aoqi@0 229 try {
aoqi@0 230 validateClassName(name);
aoqi@0 231 if (!isValidClassName)
aoqi@0 232 throw new AssertionError("Invalid class name accepted: " + name);
aoqi@0 233 printAscii("Valid class name: \"%s\"", name);
aoqi@0 234 } catch (IllegalArgumentException e) {
aoqi@0 235 if (isValidClassName)
aoqi@0 236 throw new AssertionError("Valid class name rejected: " + name);
aoqi@0 237 printAscii("Invalid class name: \"%s\"", name);
aoqi@0 238 }
aoqi@0 239 }
aoqi@0 240
aoqi@0 241 private static void printAscii(String format, Object... args) {
aoqi@0 242 String message;
aoqi@0 243 try {
aoqi@0 244 final String ascii = "US-ASCII";
aoqi@0 245 message = new String(String.format(null, format, args).getBytes(ascii), ascii);
aoqi@0 246 } catch (java.io.UnsupportedEncodingException ex) {
aoqi@0 247 throw new AssertionError(ex);
aoqi@0 248 }
aoqi@0 249 System.out.println(message);
aoqi@0 250 }
aoqi@0 251
aoqi@0 252
aoqi@0 253 /**
aoqi@0 254 * Insert all files in subdirectory subdirectory of directory directory
aoqi@0 255 * which match fileKinds into resultList
aoqi@0 256 */
aoqi@0 257 private void listDirectory(File directory,
aoqi@0 258 RelativeDirectory subdirectory,
aoqi@0 259 Set<JavaFileObject.Kind> fileKinds,
aoqi@0 260 boolean recurse,
aoqi@0 261 ListBuffer<JavaFileObject> resultList) {
aoqi@0 262 File d = subdirectory.getFile(directory);
aoqi@0 263 if (!caseMapCheck(d, subdirectory))
aoqi@0 264 return;
aoqi@0 265
aoqi@0 266 File[] files = d.listFiles();
aoqi@0 267 if (files == null)
aoqi@0 268 return;
aoqi@0 269
aoqi@0 270 if (sortFiles != null)
aoqi@0 271 Arrays.sort(files, sortFiles);
aoqi@0 272
aoqi@0 273 for (File f: files) {
aoqi@0 274 String fname = f.getName();
aoqi@0 275 if (f.isDirectory()) {
aoqi@0 276 if (recurse && SourceVersion.isIdentifier(fname)) {
aoqi@0 277 listDirectory(directory,
aoqi@0 278 new RelativeDirectory(subdirectory, fname),
aoqi@0 279 fileKinds,
aoqi@0 280 recurse,
aoqi@0 281 resultList);
aoqi@0 282 }
aoqi@0 283 } else {
aoqi@0 284 if (isValidFile(fname, fileKinds)) {
aoqi@0 285 JavaFileObject fe =
aoqi@0 286 new RegularFileObject(this, fname, new File(d, fname));
aoqi@0 287 resultList.append(fe);
aoqi@0 288 }
aoqi@0 289 }
aoqi@0 290 }
aoqi@0 291 }
aoqi@0 292
aoqi@0 293 /**
aoqi@0 294 * Insert all files in subdirectory subdirectory of archive archive
aoqi@0 295 * which match fileKinds into resultList
aoqi@0 296 */
aoqi@0 297 private void listArchive(Archive archive,
aoqi@0 298 RelativeDirectory subdirectory,
aoqi@0 299 Set<JavaFileObject.Kind> fileKinds,
aoqi@0 300 boolean recurse,
aoqi@0 301 ListBuffer<JavaFileObject> resultList) {
aoqi@0 302 // Get the files directly in the subdir
aoqi@0 303 List<String> files = archive.getFiles(subdirectory);
aoqi@0 304 if (files != null) {
aoqi@0 305 for (; !files.isEmpty(); files = files.tail) {
aoqi@0 306 String file = files.head;
aoqi@0 307 if (isValidFile(file, fileKinds)) {
aoqi@0 308 resultList.append(archive.getFileObject(subdirectory, file));
aoqi@0 309 }
aoqi@0 310 }
aoqi@0 311 }
aoqi@0 312 if (recurse) {
aoqi@0 313 for (RelativeDirectory s: archive.getSubdirectories()) {
aoqi@0 314 if (subdirectory.contains(s)) {
aoqi@0 315 // Because the archive map is a flat list of directories,
aoqi@0 316 // the enclosing loop will pick up all child subdirectories.
aoqi@0 317 // Therefore, there is no need to recurse deeper.
aoqi@0 318 listArchive(archive, s, fileKinds, false, resultList);
aoqi@0 319 }
aoqi@0 320 }
aoqi@0 321 }
aoqi@0 322 }
aoqi@0 323
aoqi@0 324 /**
aoqi@0 325 * container is a directory, a zip file, or a non-existant path.
aoqi@0 326 * Insert all files in subdirectory subdirectory of container which
aoqi@0 327 * match fileKinds into resultList
aoqi@0 328 */
aoqi@0 329 private void listContainer(File container,
aoqi@0 330 RelativeDirectory subdirectory,
aoqi@0 331 Set<JavaFileObject.Kind> fileKinds,
aoqi@0 332 boolean recurse,
aoqi@0 333 ListBuffer<JavaFileObject> resultList) {
aoqi@0 334 Archive archive = archives.get(container);
aoqi@0 335 if (archive == null) {
aoqi@0 336 // archives are not created for directories.
aoqi@0 337 if (fsInfo.isDirectory(container)) {
aoqi@0 338 listDirectory(container,
aoqi@0 339 subdirectory,
aoqi@0 340 fileKinds,
aoqi@0 341 recurse,
aoqi@0 342 resultList);
aoqi@0 343 return;
aoqi@0 344 }
aoqi@0 345
aoqi@0 346 // Not a directory; either a file or non-existant, create the archive
aoqi@0 347 try {
aoqi@0 348 archive = openArchive(container);
aoqi@0 349 } catch (IOException ex) {
aoqi@0 350 log.error("error.reading.file",
aoqi@0 351 container, getMessage(ex));
aoqi@0 352 return;
aoqi@0 353 }
aoqi@0 354 }
aoqi@0 355 listArchive(archive,
aoqi@0 356 subdirectory,
aoqi@0 357 fileKinds,
aoqi@0 358 recurse,
aoqi@0 359 resultList);
aoqi@0 360 }
aoqi@0 361
aoqi@0 362 private boolean isValidFile(String s, Set<JavaFileObject.Kind> fileKinds) {
aoqi@0 363 JavaFileObject.Kind kind = getKind(s);
aoqi@0 364 return fileKinds.contains(kind);
aoqi@0 365 }
aoqi@0 366
aoqi@0 367 private static final boolean fileSystemIsCaseSensitive =
aoqi@0 368 File.separatorChar == '/';
aoqi@0 369
aoqi@0 370 /** Hack to make Windows case sensitive. Test whether given path
aoqi@0 371 * ends in a string of characters with the same case as given name.
aoqi@0 372 * Ignore file separators in both path and name.
aoqi@0 373 */
aoqi@0 374 private boolean caseMapCheck(File f, RelativePath name) {
aoqi@0 375 if (fileSystemIsCaseSensitive) return true;
aoqi@0 376 // Note that getCanonicalPath() returns the case-sensitive
aoqi@0 377 // spelled file name.
aoqi@0 378 String path;
aoqi@0 379 try {
aoqi@0 380 path = f.getCanonicalPath();
aoqi@0 381 } catch (IOException ex) {
aoqi@0 382 return false;
aoqi@0 383 }
aoqi@0 384 char[] pcs = path.toCharArray();
aoqi@0 385 char[] ncs = name.path.toCharArray();
aoqi@0 386 int i = pcs.length - 1;
aoqi@0 387 int j = ncs.length - 1;
aoqi@0 388 while (i >= 0 && j >= 0) {
aoqi@0 389 while (i >= 0 && pcs[i] == File.separatorChar) i--;
aoqi@0 390 while (j >= 0 && ncs[j] == '/') j--;
aoqi@0 391 if (i >= 0 && j >= 0) {
aoqi@0 392 if (pcs[i] != ncs[j]) return false;
aoqi@0 393 i--;
aoqi@0 394 j--;
aoqi@0 395 }
aoqi@0 396 }
aoqi@0 397 return j < 0;
aoqi@0 398 }
aoqi@0 399
aoqi@0 400 /**
aoqi@0 401 * An archive provides a flat directory structure of a ZipFile by
aoqi@0 402 * mapping directory names to lists of files (basenames).
aoqi@0 403 */
aoqi@0 404 public interface Archive {
aoqi@0 405 void close() throws IOException;
aoqi@0 406
aoqi@0 407 boolean contains(RelativePath name);
aoqi@0 408
aoqi@0 409 JavaFileObject getFileObject(RelativeDirectory subdirectory, String file);
aoqi@0 410
aoqi@0 411 List<String> getFiles(RelativeDirectory subdirectory);
aoqi@0 412
aoqi@0 413 Set<RelativeDirectory> getSubdirectories();
aoqi@0 414 }
aoqi@0 415
aoqi@0 416 public class MissingArchive implements Archive {
aoqi@0 417 final File zipFileName;
aoqi@0 418 public MissingArchive(File name) {
aoqi@0 419 zipFileName = name;
aoqi@0 420 }
aoqi@0 421 public boolean contains(RelativePath name) {
aoqi@0 422 return false;
aoqi@0 423 }
aoqi@0 424
aoqi@0 425 public void close() {
aoqi@0 426 }
aoqi@0 427
aoqi@0 428 public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
aoqi@0 429 return null;
aoqi@0 430 }
aoqi@0 431
aoqi@0 432 public List<String> getFiles(RelativeDirectory subdirectory) {
aoqi@0 433 return List.nil();
aoqi@0 434 }
aoqi@0 435
aoqi@0 436 public Set<RelativeDirectory> getSubdirectories() {
aoqi@0 437 return Collections.emptySet();
aoqi@0 438 }
aoqi@0 439
aoqi@0 440 @Override
aoqi@0 441 public String toString() {
aoqi@0 442 return "MissingArchive[" + zipFileName + "]";
aoqi@0 443 }
aoqi@0 444 }
aoqi@0 445
aoqi@0 446 /** A directory of zip files already opened.
aoqi@0 447 */
aoqi@0 448 Map<File, Archive> archives = new HashMap<File,Archive>();
aoqi@0 449
aoqi@0 450 private static final String[] symbolFileLocation = { "lib", "ct.sym" };
aoqi@0 451 private static final RelativeDirectory symbolFilePrefix
aoqi@0 452 = new RelativeDirectory("META-INF/sym/rt.jar/");
aoqi@0 453
aoqi@0 454 /*
aoqi@0 455 * This method looks for a ZipFormatException and takes appropriate
aoqi@0 456 * evasive action. If there is a failure in the fast mode then we
aoqi@0 457 * fail over to the platform zip, and allow it to deal with a potentially
aoqi@0 458 * non compliant zip file.
aoqi@0 459 */
aoqi@0 460 protected Archive openArchive(File zipFilename) throws IOException {
aoqi@0 461 try {
aoqi@0 462 return openArchive(zipFilename, contextUseOptimizedZip);
aoqi@0 463 } catch (IOException ioe) {
aoqi@0 464 if (ioe instanceof ZipFileIndex.ZipFormatException) {
aoqi@0 465 return openArchive(zipFilename, false);
aoqi@0 466 } else {
aoqi@0 467 throw ioe;
aoqi@0 468 }
aoqi@0 469 }
aoqi@0 470 }
aoqi@0 471
aoqi@0 472 /** Open a new zip file directory, and cache it.
aoqi@0 473 */
aoqi@0 474 private Archive openArchive(File zipFileName, boolean useOptimizedZip) throws IOException {
aoqi@0 475 File origZipFileName = zipFileName;
aoqi@0 476 if (symbolFileEnabled && locations.isDefaultBootClassPathRtJar(zipFileName)) {
aoqi@0 477 File file = zipFileName.getParentFile().getParentFile(); // ${java.home}
aoqi@0 478 if (new File(file.getName()).equals(new File("jre")))
aoqi@0 479 file = file.getParentFile();
aoqi@0 480 // file == ${jdk.home}
aoqi@0 481 for (String name : symbolFileLocation)
aoqi@0 482 file = new File(file, name);
aoqi@0 483 // file == ${jdk.home}/lib/ct.sym
aoqi@0 484 if (file.exists())
aoqi@0 485 zipFileName = file;
aoqi@0 486 }
aoqi@0 487
aoqi@0 488 Archive archive;
aoqi@0 489 try {
aoqi@0 490
aoqi@0 491 ZipFile zdir = null;
aoqi@0 492
aoqi@0 493 boolean usePreindexedCache = false;
aoqi@0 494 String preindexCacheLocation = null;
aoqi@0 495
aoqi@0 496 if (!useOptimizedZip) {
aoqi@0 497 zdir = new ZipFile(zipFileName);
aoqi@0 498 } else {
aoqi@0 499 usePreindexedCache = options.isSet("usezipindex");
aoqi@0 500 preindexCacheLocation = options.get("java.io.tmpdir");
aoqi@0 501 String optCacheLoc = options.get("cachezipindexdir");
aoqi@0 502
aoqi@0 503 if (optCacheLoc != null && optCacheLoc.length() != 0) {
aoqi@0 504 if (optCacheLoc.startsWith("\"")) {
aoqi@0 505 if (optCacheLoc.endsWith("\"")) {
aoqi@0 506 optCacheLoc = optCacheLoc.substring(1, optCacheLoc.length() - 1);
aoqi@0 507 }
aoqi@0 508 else {
aoqi@0 509 optCacheLoc = optCacheLoc.substring(1);
aoqi@0 510 }
aoqi@0 511 }
aoqi@0 512
aoqi@0 513 File cacheDir = new File(optCacheLoc);
aoqi@0 514 if (cacheDir.exists() && cacheDir.canWrite()) {
aoqi@0 515 preindexCacheLocation = optCacheLoc;
aoqi@0 516 if (!preindexCacheLocation.endsWith("/") &&
aoqi@0 517 !preindexCacheLocation.endsWith(File.separator)) {
aoqi@0 518 preindexCacheLocation += File.separator;
aoqi@0 519 }
aoqi@0 520 }
aoqi@0 521 }
aoqi@0 522 }
aoqi@0 523
aoqi@0 524 if (origZipFileName == zipFileName) {
aoqi@0 525 if (!useOptimizedZip) {
aoqi@0 526 archive = new ZipArchive(this, zdir);
aoqi@0 527 } else {
aoqi@0 528 archive = new ZipFileIndexArchive(this,
aoqi@0 529 zipFileIndexCache.getZipFileIndex(zipFileName,
aoqi@0 530 null,
aoqi@0 531 usePreindexedCache,
aoqi@0 532 preindexCacheLocation,
aoqi@0 533 options.isSet("writezipindexfiles")));
aoqi@0 534 }
aoqi@0 535 } else {
aoqi@0 536 if (!useOptimizedZip) {
aoqi@0 537 archive = new SymbolArchive(this, origZipFileName, zdir, symbolFilePrefix);
aoqi@0 538 } else {
aoqi@0 539 archive = new ZipFileIndexArchive(this,
aoqi@0 540 zipFileIndexCache.getZipFileIndex(zipFileName,
aoqi@0 541 symbolFilePrefix,
aoqi@0 542 usePreindexedCache,
aoqi@0 543 preindexCacheLocation,
aoqi@0 544 options.isSet("writezipindexfiles")));
aoqi@0 545 }
aoqi@0 546 }
aoqi@0 547 } catch (FileNotFoundException ex) {
aoqi@0 548 archive = new MissingArchive(zipFileName);
aoqi@0 549 } catch (ZipFileIndex.ZipFormatException zfe) {
aoqi@0 550 throw zfe;
aoqi@0 551 } catch (IOException ex) {
aoqi@0 552 if (zipFileName.exists())
aoqi@0 553 log.error("error.reading.file", zipFileName, getMessage(ex));
aoqi@0 554 archive = new MissingArchive(zipFileName);
aoqi@0 555 }
aoqi@0 556
aoqi@0 557 archives.put(origZipFileName, archive);
aoqi@0 558 return archive;
aoqi@0 559 }
aoqi@0 560
aoqi@0 561 /** Flush any output resources.
aoqi@0 562 */
aoqi@0 563 public void flush() {
aoqi@0 564 contentCache.clear();
aoqi@0 565 }
aoqi@0 566
aoqi@0 567 /**
aoqi@0 568 * Close the JavaFileManager, releasing resources.
aoqi@0 569 */
aoqi@0 570 public void close() {
aoqi@0 571 for (Iterator<Archive> i = archives.values().iterator(); i.hasNext(); ) {
aoqi@0 572 Archive a = i.next();
aoqi@0 573 i.remove();
aoqi@0 574 try {
aoqi@0 575 a.close();
aoqi@0 576 } catch (IOException e) {
aoqi@0 577 }
aoqi@0 578 }
aoqi@0 579 }
aoqi@0 580
aoqi@0 581 private String defaultEncodingName;
aoqi@0 582 private String getDefaultEncodingName() {
aoqi@0 583 if (defaultEncodingName == null) {
aoqi@0 584 defaultEncodingName =
aoqi@0 585 new OutputStreamWriter(new ByteArrayOutputStream()).getEncoding();
aoqi@0 586 }
aoqi@0 587 return defaultEncodingName;
aoqi@0 588 }
aoqi@0 589
aoqi@0 590 public ClassLoader getClassLoader(Location location) {
aoqi@0 591 nullCheck(location);
aoqi@0 592 Iterable<? extends File> path = getLocation(location);
aoqi@0 593 if (path == null)
aoqi@0 594 return null;
aoqi@0 595 ListBuffer<URL> lb = new ListBuffer<URL>();
aoqi@0 596 for (File f: path) {
aoqi@0 597 try {
aoqi@0 598 lb.append(f.toURI().toURL());
aoqi@0 599 } catch (MalformedURLException e) {
aoqi@0 600 throw new AssertionError(e);
aoqi@0 601 }
aoqi@0 602 }
aoqi@0 603
aoqi@0 604 return getClassLoader(lb.toArray(new URL[lb.size()]));
aoqi@0 605 }
aoqi@0 606
aoqi@0 607 public Iterable<JavaFileObject> list(Location location,
aoqi@0 608 String packageName,
aoqi@0 609 Set<JavaFileObject.Kind> kinds,
aoqi@0 610 boolean recurse)
aoqi@0 611 throws IOException
aoqi@0 612 {
aoqi@0 613 // validatePackageName(packageName);
aoqi@0 614 nullCheck(packageName);
aoqi@0 615 nullCheck(kinds);
aoqi@0 616
aoqi@0 617 Iterable<? extends File> path = getLocation(location);
aoqi@0 618 if (path == null)
aoqi@0 619 return List.nil();
aoqi@0 620 RelativeDirectory subdirectory = RelativeDirectory.forPackage(packageName);
aoqi@0 621 ListBuffer<JavaFileObject> results = new ListBuffer<JavaFileObject>();
aoqi@0 622
aoqi@0 623 for (File directory : path)
aoqi@0 624 listContainer(directory, subdirectory, kinds, recurse, results);
aoqi@0 625 return results.toList();
aoqi@0 626 }
aoqi@0 627
aoqi@0 628 public String inferBinaryName(Location location, JavaFileObject file) {
aoqi@0 629 file.getClass(); // null check
aoqi@0 630 location.getClass(); // null check
aoqi@0 631 // Need to match the path semantics of list(location, ...)
aoqi@0 632 Iterable<? extends File> path = getLocation(location);
aoqi@0 633 if (path == null) {
aoqi@0 634 return null;
aoqi@0 635 }
aoqi@0 636
aoqi@0 637 if (file instanceof BaseFileObject) {
aoqi@0 638 return ((BaseFileObject) file).inferBinaryName(path);
aoqi@0 639 } else
aoqi@0 640 throw new IllegalArgumentException(file.getClass().getName());
aoqi@0 641 }
aoqi@0 642
aoqi@0 643 public boolean isSameFile(FileObject a, FileObject b) {
aoqi@0 644 nullCheck(a);
aoqi@0 645 nullCheck(b);
aoqi@0 646 if (!(a instanceof BaseFileObject))
aoqi@0 647 throw new IllegalArgumentException("Not supported: " + a);
aoqi@0 648 if (!(b instanceof BaseFileObject))
aoqi@0 649 throw new IllegalArgumentException("Not supported: " + b);
aoqi@0 650 return a.equals(b);
aoqi@0 651 }
aoqi@0 652
aoqi@0 653 public boolean hasLocation(Location location) {
aoqi@0 654 return getLocation(location) != null;
aoqi@0 655 }
aoqi@0 656
aoqi@0 657 public JavaFileObject getJavaFileForInput(Location location,
aoqi@0 658 String className,
aoqi@0 659 JavaFileObject.Kind kind)
aoqi@0 660 throws IOException
aoqi@0 661 {
aoqi@0 662 nullCheck(location);
aoqi@0 663 // validateClassName(className);
aoqi@0 664 nullCheck(className);
aoqi@0 665 nullCheck(kind);
aoqi@0 666 if (!sourceOrClass.contains(kind))
aoqi@0 667 throw new IllegalArgumentException("Invalid kind: " + kind);
aoqi@0 668 return getFileForInput(location, RelativeFile.forClass(className, kind));
aoqi@0 669 }
aoqi@0 670
aoqi@0 671 public FileObject getFileForInput(Location location,
aoqi@0 672 String packageName,
aoqi@0 673 String relativeName)
aoqi@0 674 throws IOException
aoqi@0 675 {
aoqi@0 676 nullCheck(location);
aoqi@0 677 // validatePackageName(packageName);
aoqi@0 678 nullCheck(packageName);
aoqi@0 679 if (!isRelativeUri(relativeName))
aoqi@0 680 throw new IllegalArgumentException("Invalid relative name: " + relativeName);
aoqi@0 681 RelativeFile name = packageName.length() == 0
aoqi@0 682 ? new RelativeFile(relativeName)
aoqi@0 683 : new RelativeFile(RelativeDirectory.forPackage(packageName), relativeName);
aoqi@0 684 return getFileForInput(location, name);
aoqi@0 685 }
aoqi@0 686
aoqi@0 687 private JavaFileObject getFileForInput(Location location, RelativeFile name) throws IOException {
aoqi@0 688 Iterable<? extends File> path = getLocation(location);
aoqi@0 689 if (path == null)
aoqi@0 690 return null;
aoqi@0 691
aoqi@0 692 for (File dir: path) {
aoqi@0 693 Archive a = archives.get(dir);
aoqi@0 694 if (a == null) {
aoqi@0 695 if (fsInfo.isDirectory(dir)) {
aoqi@0 696 File f = name.getFile(dir);
aoqi@0 697 if (f.exists())
aoqi@0 698 return new RegularFileObject(this, f);
aoqi@0 699 continue;
aoqi@0 700 }
aoqi@0 701 // Not a directory, create the archive
aoqi@0 702 a = openArchive(dir);
aoqi@0 703 }
aoqi@0 704 // Process the archive
aoqi@0 705 if (a.contains(name)) {
aoqi@0 706 return a.getFileObject(name.dirname(), name.basename());
aoqi@0 707 }
aoqi@0 708 }
aoqi@0 709 return null;
aoqi@0 710 }
aoqi@0 711
aoqi@0 712 public JavaFileObject getJavaFileForOutput(Location location,
aoqi@0 713 String className,
aoqi@0 714 JavaFileObject.Kind kind,
aoqi@0 715 FileObject sibling)
aoqi@0 716 throws IOException
aoqi@0 717 {
aoqi@0 718 nullCheck(location);
aoqi@0 719 // validateClassName(className);
aoqi@0 720 nullCheck(className);
aoqi@0 721 nullCheck(kind);
aoqi@0 722 if (!sourceOrClass.contains(kind))
aoqi@0 723 throw new IllegalArgumentException("Invalid kind: " + kind);
aoqi@0 724 return getFileForOutput(location, RelativeFile.forClass(className, kind), sibling);
aoqi@0 725 }
aoqi@0 726
aoqi@0 727 public FileObject getFileForOutput(Location location,
aoqi@0 728 String packageName,
aoqi@0 729 String relativeName,
aoqi@0 730 FileObject sibling)
aoqi@0 731 throws IOException
aoqi@0 732 {
aoqi@0 733 nullCheck(location);
aoqi@0 734 // validatePackageName(packageName);
aoqi@0 735 nullCheck(packageName);
aoqi@0 736 if (!isRelativeUri(relativeName))
aoqi@0 737 throw new IllegalArgumentException("Invalid relative name: " + relativeName);
aoqi@0 738 RelativeFile name = packageName.length() == 0
aoqi@0 739 ? new RelativeFile(relativeName)
aoqi@0 740 : new RelativeFile(RelativeDirectory.forPackage(packageName), relativeName);
aoqi@0 741 return getFileForOutput(location, name, sibling);
aoqi@0 742 }
aoqi@0 743
aoqi@0 744 private JavaFileObject getFileForOutput(Location location,
aoqi@0 745 RelativeFile fileName,
aoqi@0 746 FileObject sibling)
aoqi@0 747 throws IOException
aoqi@0 748 {
aoqi@0 749 File dir;
aoqi@0 750 if (location == CLASS_OUTPUT) {
aoqi@0 751 if (getClassOutDir() != null) {
aoqi@0 752 dir = getClassOutDir();
aoqi@0 753 } else {
aoqi@0 754 File siblingDir = null;
aoqi@0 755 if (sibling != null && sibling instanceof RegularFileObject) {
aoqi@0 756 siblingDir = ((RegularFileObject)sibling).file.getParentFile();
aoqi@0 757 }
aoqi@0 758 return new RegularFileObject(this, new File(siblingDir, fileName.basename()));
aoqi@0 759 }
aoqi@0 760 } else if (location == SOURCE_OUTPUT) {
aoqi@0 761 dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir());
aoqi@0 762 } else {
aoqi@0 763 Iterable<? extends File> path = locations.getLocation(location);
aoqi@0 764 dir = null;
aoqi@0 765 for (File f: path) {
aoqi@0 766 dir = f;
aoqi@0 767 break;
aoqi@0 768 }
aoqi@0 769 }
aoqi@0 770
aoqi@0 771 File file = fileName.getFile(dir); // null-safe
aoqi@0 772 return new RegularFileObject(this, file);
aoqi@0 773
aoqi@0 774 }
aoqi@0 775
aoqi@0 776 public Iterable<? extends JavaFileObject> getJavaFileObjectsFromFiles(
aoqi@0 777 Iterable<? extends File> files)
aoqi@0 778 {
aoqi@0 779 ArrayList<RegularFileObject> result;
aoqi@0 780 if (files instanceof Collection<?>)
aoqi@0 781 result = new ArrayList<RegularFileObject>(((Collection<?>)files).size());
aoqi@0 782 else
aoqi@0 783 result = new ArrayList<RegularFileObject>();
aoqi@0 784 for (File f: files)
aoqi@0 785 result.add(new RegularFileObject(this, nullCheck(f)));
aoqi@0 786 return result;
aoqi@0 787 }
aoqi@0 788
aoqi@0 789 public Iterable<? extends JavaFileObject> getJavaFileObjects(File... files) {
aoqi@0 790 return getJavaFileObjectsFromFiles(Arrays.asList(nullCheck(files)));
aoqi@0 791 }
aoqi@0 792
aoqi@0 793 public void setLocation(Location location,
aoqi@0 794 Iterable<? extends File> path)
aoqi@0 795 throws IOException
aoqi@0 796 {
aoqi@0 797 nullCheck(location);
aoqi@0 798 locations.setLocation(location, path);
aoqi@0 799 }
aoqi@0 800
aoqi@0 801 public Iterable<? extends File> getLocation(Location location) {
aoqi@0 802 nullCheck(location);
aoqi@0 803 return locations.getLocation(location);
aoqi@0 804 }
aoqi@0 805
aoqi@0 806 private File getClassOutDir() {
aoqi@0 807 return locations.getOutputLocation(CLASS_OUTPUT);
aoqi@0 808 }
aoqi@0 809
aoqi@0 810 private File getSourceOutDir() {
aoqi@0 811 return locations.getOutputLocation(SOURCE_OUTPUT);
aoqi@0 812 }
aoqi@0 813
aoqi@0 814 /**
aoqi@0 815 * Enforces the specification of a "relative" name as used in
aoqi@0 816 * {@linkplain #getFileForInput(Location,String,String)
aoqi@0 817 * getFileForInput}. This method must follow the rules defined in
aoqi@0 818 * that method, do not make any changes without consulting the
aoqi@0 819 * specification.
aoqi@0 820 */
aoqi@0 821 protected static boolean isRelativeUri(URI uri) {
aoqi@0 822 if (uri.isAbsolute())
aoqi@0 823 return false;
aoqi@0 824 String path = uri.normalize().getPath();
aoqi@0 825 if (path.length() == 0 /* isEmpty() is mustang API */)
aoqi@0 826 return false;
aoqi@0 827 if (!path.equals(uri.getPath())) // implicitly checks for embedded . and ..
aoqi@0 828 return false;
aoqi@0 829 if (path.startsWith("/") || path.startsWith("./") || path.startsWith("../"))
aoqi@0 830 return false;
aoqi@0 831 return true;
aoqi@0 832 }
aoqi@0 833
aoqi@0 834 // Convenience method
aoqi@0 835 protected static boolean isRelativeUri(String u) {
aoqi@0 836 try {
aoqi@0 837 return isRelativeUri(new URI(u));
aoqi@0 838 } catch (URISyntaxException e) {
aoqi@0 839 return false;
aoqi@0 840 }
aoqi@0 841 }
aoqi@0 842
aoqi@0 843 /**
aoqi@0 844 * Converts a relative file name to a relative URI. This is
aoqi@0 845 * different from File.toURI as this method does not canonicalize
aoqi@0 846 * the file before creating the URI. Furthermore, no schema is
aoqi@0 847 * used.
aoqi@0 848 * @param file a relative file name
aoqi@0 849 * @return a relative URI
aoqi@0 850 * @throws IllegalArgumentException if the file name is not
aoqi@0 851 * relative according to the definition given in {@link
aoqi@0 852 * javax.tools.JavaFileManager#getFileForInput}
aoqi@0 853 */
aoqi@0 854 public static String getRelativeName(File file) {
aoqi@0 855 if (!file.isAbsolute()) {
aoqi@0 856 String result = file.getPath().replace(File.separatorChar, '/');
aoqi@0 857 if (isRelativeUri(result))
aoqi@0 858 return result;
aoqi@0 859 }
aoqi@0 860 throw new IllegalArgumentException("Invalid relative path: " + file);
aoqi@0 861 }
aoqi@0 862
aoqi@0 863 /**
aoqi@0 864 * Get a detail message from an IOException.
aoqi@0 865 * Most, but not all, instances of IOException provide a non-null result
aoqi@0 866 * for getLocalizedMessage(). But some instances return null: in these
aoqi@0 867 * cases, fallover to getMessage(), and if even that is null, return the
aoqi@0 868 * name of the exception itself.
aoqi@0 869 * @param e an IOException
aoqi@0 870 * @return a string to include in a compiler diagnostic
aoqi@0 871 */
aoqi@0 872 public static String getMessage(IOException e) {
aoqi@0 873 String s = e.getLocalizedMessage();
aoqi@0 874 if (s != null)
aoqi@0 875 return s;
aoqi@0 876 s = e.getMessage();
aoqi@0 877 if (s != null)
aoqi@0 878 return s;
aoqi@0 879 return e.toString();
aoqi@0 880 }
aoqi@0 881 }

mercurial