src/share/classes/com/sun/tools/javac/file/Locations.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) 2003, 2013, 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.FileNotFoundException;
aoqi@0 29 import java.util.Iterator;
aoqi@0 30 import java.io.File;
aoqi@0 31 import java.io.IOException;
aoqi@0 32 import java.net.MalformedURLException;
aoqi@0 33 import java.net.URL;
aoqi@0 34 import java.util.Arrays;
aoqi@0 35 import java.util.Collection;
aoqi@0 36 import java.util.Collections;
aoqi@0 37 import java.util.EnumMap;
aoqi@0 38 import java.util.EnumSet;
aoqi@0 39 import java.util.HashMap;
aoqi@0 40 import java.util.HashSet;
aoqi@0 41 import java.util.LinkedHashSet;
aoqi@0 42 import java.util.Map;
aoqi@0 43 import java.util.Set;
aoqi@0 44 import java.util.StringTokenizer;
aoqi@0 45 import java.util.zip.ZipFile;
aoqi@0 46 import javax.tools.JavaFileManager.Location;
aoqi@0 47 import javax.tools.StandardLocation;
aoqi@0 48
aoqi@0 49 import com.sun.tools.javac.code.Lint;
aoqi@0 50 import com.sun.tools.javac.main.Option;
aoqi@0 51 import com.sun.tools.javac.util.ListBuffer;
aoqi@0 52 import com.sun.tools.javac.util.Log;
aoqi@0 53 import com.sun.tools.javac.util.Options;
aoqi@0 54 import com.sun.tools.javac.util.StringUtils;
aoqi@0 55
aoqi@0 56 import javax.tools.JavaFileManager;
aoqi@0 57 import javax.tools.StandardJavaFileManager;
aoqi@0 58 import static javax.tools.StandardLocation.*;
aoqi@0 59 import static com.sun.tools.javac.main.Option.*;
aoqi@0 60
aoqi@0 61 /** This class converts command line arguments, environment variables
aoqi@0 62 * and system properties (in File.pathSeparator-separated String form)
aoqi@0 63 * into a boot class path, user class path, and source path (in
aoqi@0 64 * {@code Collection<String>} form).
aoqi@0 65 *
aoqi@0 66 * <p><b>This is NOT part of any supported API.
aoqi@0 67 * If you write code that depends on this, you do so at your own risk.
aoqi@0 68 * This code and its internal interfaces are subject to change or
aoqi@0 69 * deletion without notice.</b>
aoqi@0 70 */
aoqi@0 71 public class Locations {
aoqi@0 72
aoqi@0 73 /** The log to use for warning output */
aoqi@0 74 private Log log;
aoqi@0 75
aoqi@0 76 /** Collection of command-line options */
aoqi@0 77 private Options options;
aoqi@0 78
aoqi@0 79 /** Handler for -Xlint options */
aoqi@0 80 private Lint lint;
aoqi@0 81
aoqi@0 82 /** Access to (possibly cached) file info */
aoqi@0 83 private FSInfo fsInfo;
aoqi@0 84
aoqi@0 85 /** Whether to warn about non-existent path elements */
aoqi@0 86 private boolean warn;
aoqi@0 87
aoqi@0 88 // TODO: remove need for this
aoqi@0 89 private boolean inited = false; // TODO? caching bad?
aoqi@0 90
aoqi@0 91 public Locations() {
aoqi@0 92 initHandlers();
aoqi@0 93 }
aoqi@0 94
aoqi@0 95 public void update(Log log, Options options, Lint lint, FSInfo fsInfo) {
aoqi@0 96 this.log = log;
aoqi@0 97 this.options = options;
aoqi@0 98 this.lint = lint;
aoqi@0 99 this.fsInfo = fsInfo;
aoqi@0 100 }
aoqi@0 101
aoqi@0 102 public Collection<File> bootClassPath() {
aoqi@0 103 return getLocation(PLATFORM_CLASS_PATH);
aoqi@0 104 }
aoqi@0 105
aoqi@0 106 public boolean isDefaultBootClassPath() {
aoqi@0 107 BootClassPathLocationHandler h =
aoqi@0 108 (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH);
aoqi@0 109 return h.isDefault();
aoqi@0 110 }
aoqi@0 111
aoqi@0 112 boolean isDefaultBootClassPathRtJar(File file) {
aoqi@0 113 BootClassPathLocationHandler h =
aoqi@0 114 (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH);
aoqi@0 115 return h.isDefaultRtJar(file);
aoqi@0 116 }
aoqi@0 117
aoqi@0 118 public Collection<File> userClassPath() {
aoqi@0 119 return getLocation(CLASS_PATH);
aoqi@0 120 }
aoqi@0 121
aoqi@0 122 public Collection<File> sourcePath() {
aoqi@0 123 Collection<File> p = getLocation(SOURCE_PATH);
aoqi@0 124 // TODO: this should be handled by the LocationHandler
aoqi@0 125 return p == null || p.isEmpty() ? null : p;
aoqi@0 126 }
aoqi@0 127
aoqi@0 128 /**
aoqi@0 129 * Split a path into its elements. Empty path elements will be ignored.
aoqi@0 130 * @param path The path to be split
aoqi@0 131 * @return The elements of the path
aoqi@0 132 */
aoqi@0 133 private static Iterable<File> getPathEntries(String path) {
aoqi@0 134 return getPathEntries(path, null);
aoqi@0 135 }
aoqi@0 136
aoqi@0 137 /**
aoqi@0 138 * Split a path into its elements. If emptyPathDefault is not null, all
aoqi@0 139 * empty elements in the path, including empty elements at either end of
aoqi@0 140 * the path, will be replaced with the value of emptyPathDefault.
aoqi@0 141 * @param path The path to be split
aoqi@0 142 * @param emptyPathDefault The value to substitute for empty path elements,
aoqi@0 143 * or null, to ignore empty path elements
aoqi@0 144 * @return The elements of the path
aoqi@0 145 */
aoqi@0 146 private static Iterable<File> getPathEntries(String path, File emptyPathDefault) {
aoqi@0 147 ListBuffer<File> entries = new ListBuffer<File>();
aoqi@0 148 int start = 0;
aoqi@0 149 while (start <= path.length()) {
aoqi@0 150 int sep = path.indexOf(File.pathSeparatorChar, start);
aoqi@0 151 if (sep == -1)
aoqi@0 152 sep = path.length();
aoqi@0 153 if (start < sep)
aoqi@0 154 entries.add(new File(path.substring(start, sep)));
aoqi@0 155 else if (emptyPathDefault != null)
aoqi@0 156 entries.add(emptyPathDefault);
aoqi@0 157 start = sep + 1;
aoqi@0 158 }
aoqi@0 159 return entries;
aoqi@0 160 }
aoqi@0 161
aoqi@0 162 /**
aoqi@0 163 * Utility class to help evaluate a path option.
aoqi@0 164 * Duplicate entries are ignored, jar class paths can be expanded.
aoqi@0 165 */
aoqi@0 166 private class Path extends LinkedHashSet<File> {
aoqi@0 167 private static final long serialVersionUID = 0;
aoqi@0 168
aoqi@0 169 private boolean expandJarClassPaths = false;
aoqi@0 170 private Set<File> canonicalValues = new HashSet<File>();
aoqi@0 171
aoqi@0 172 public Path expandJarClassPaths(boolean x) {
aoqi@0 173 expandJarClassPaths = x;
aoqi@0 174 return this;
aoqi@0 175 }
aoqi@0 176
aoqi@0 177 /** What to use when path element is the empty string */
aoqi@0 178 private File emptyPathDefault = null;
aoqi@0 179
aoqi@0 180 public Path emptyPathDefault(File x) {
aoqi@0 181 emptyPathDefault = x;
aoqi@0 182 return this;
aoqi@0 183 }
aoqi@0 184
aoqi@0 185 public Path() { super(); }
aoqi@0 186
aoqi@0 187 public Path addDirectories(String dirs, boolean warn) {
aoqi@0 188 boolean prev = expandJarClassPaths;
aoqi@0 189 expandJarClassPaths = true;
aoqi@0 190 try {
aoqi@0 191 if (dirs != null)
aoqi@0 192 for (File dir : getPathEntries(dirs))
aoqi@0 193 addDirectory(dir, warn);
aoqi@0 194 return this;
aoqi@0 195 } finally {
aoqi@0 196 expandJarClassPaths = prev;
aoqi@0 197 }
aoqi@0 198 }
aoqi@0 199
aoqi@0 200 public Path addDirectories(String dirs) {
aoqi@0 201 return addDirectories(dirs, warn);
aoqi@0 202 }
aoqi@0 203
aoqi@0 204 private void addDirectory(File dir, boolean warn) {
aoqi@0 205 if (!dir.isDirectory()) {
aoqi@0 206 if (warn)
aoqi@0 207 log.warning(Lint.LintCategory.PATH,
aoqi@0 208 "dir.path.element.not.found", dir);
aoqi@0 209 return;
aoqi@0 210 }
aoqi@0 211
aoqi@0 212 File[] files = dir.listFiles();
aoqi@0 213 if (files == null)
aoqi@0 214 return;
aoqi@0 215
aoqi@0 216 for (File direntry : files) {
aoqi@0 217 if (isArchive(direntry))
aoqi@0 218 addFile(direntry, warn);
aoqi@0 219 }
aoqi@0 220 }
aoqi@0 221
aoqi@0 222 public Path addFiles(String files, boolean warn) {
aoqi@0 223 if (files != null) {
aoqi@0 224 addFiles(getPathEntries(files, emptyPathDefault), warn);
aoqi@0 225 }
aoqi@0 226 return this;
aoqi@0 227 }
aoqi@0 228
aoqi@0 229 public Path addFiles(String files) {
aoqi@0 230 return addFiles(files, warn);
aoqi@0 231 }
aoqi@0 232
aoqi@0 233 public Path addFiles(Iterable<? extends File> files, boolean warn) {
aoqi@0 234 if (files != null) {
aoqi@0 235 for (File file: files)
aoqi@0 236 addFile(file, warn);
aoqi@0 237 }
aoqi@0 238 return this;
aoqi@0 239 }
aoqi@0 240
aoqi@0 241 public Path addFiles(Iterable<? extends File> files) {
aoqi@0 242 return addFiles(files, warn);
aoqi@0 243 }
aoqi@0 244
aoqi@0 245 public void addFile(File file, boolean warn) {
aoqi@0 246 if (contains(file)) {
aoqi@0 247 // discard duplicates
aoqi@0 248 return;
aoqi@0 249 }
aoqi@0 250
aoqi@0 251 if (! fsInfo.exists(file)) {
aoqi@0 252 /* No such file or directory exists */
aoqi@0 253 if (warn) {
aoqi@0 254 log.warning(Lint.LintCategory.PATH,
aoqi@0 255 "path.element.not.found", file);
aoqi@0 256 }
aoqi@0 257 super.add(file);
aoqi@0 258 return;
aoqi@0 259 }
aoqi@0 260
aoqi@0 261 File canonFile = fsInfo.getCanonicalFile(file);
aoqi@0 262 if (canonicalValues.contains(canonFile)) {
aoqi@0 263 /* Discard duplicates and avoid infinite recursion */
aoqi@0 264 return;
aoqi@0 265 }
aoqi@0 266
aoqi@0 267 if (fsInfo.isFile(file)) {
aoqi@0 268 /* File is an ordinary file. */
aoqi@0 269 if (!isArchive(file)) {
aoqi@0 270 /* Not a recognized extension; open it to see if
aoqi@0 271 it looks like a valid zip file. */
aoqi@0 272 try {
aoqi@0 273 ZipFile z = new ZipFile(file);
aoqi@0 274 z.close();
aoqi@0 275 if (warn) {
aoqi@0 276 log.warning(Lint.LintCategory.PATH,
aoqi@0 277 "unexpected.archive.file", file);
aoqi@0 278 }
aoqi@0 279 } catch (IOException e) {
aoqi@0 280 // FIXME: include e.getLocalizedMessage in warning
aoqi@0 281 if (warn) {
aoqi@0 282 log.warning(Lint.LintCategory.PATH,
aoqi@0 283 "invalid.archive.file", file);
aoqi@0 284 }
aoqi@0 285 return;
aoqi@0 286 }
aoqi@0 287 }
aoqi@0 288 }
aoqi@0 289
aoqi@0 290 /* Now what we have left is either a directory or a file name
aoqi@0 291 conforming to archive naming convention */
aoqi@0 292 super.add(file);
aoqi@0 293 canonicalValues.add(canonFile);
aoqi@0 294
aoqi@0 295 if (expandJarClassPaths && fsInfo.isFile(file))
aoqi@0 296 addJarClassPath(file, warn);
aoqi@0 297 }
aoqi@0 298
aoqi@0 299 // Adds referenced classpath elements from a jar's Class-Path
aoqi@0 300 // Manifest entry. In some future release, we may want to
aoqi@0 301 // update this code to recognize URLs rather than simple
aoqi@0 302 // filenames, but if we do, we should redo all path-related code.
aoqi@0 303 private void addJarClassPath(File jarFile, boolean warn) {
aoqi@0 304 try {
aoqi@0 305 for (File f: fsInfo.getJarClassPath(jarFile)) {
aoqi@0 306 addFile(f, warn);
aoqi@0 307 }
aoqi@0 308 } catch (IOException e) {
aoqi@0 309 log.error("error.reading.file", jarFile, JavacFileManager.getMessage(e));
aoqi@0 310 }
aoqi@0 311 }
aoqi@0 312 }
aoqi@0 313
aoqi@0 314 /**
aoqi@0 315 * Base class for handling support for the representation of Locations.
aoqi@0 316 * Implementations are responsible for handling the interactions between
aoqi@0 317 * the command line options for a location, and API access via setLocation.
aoqi@0 318 * @see #initHandlers
aoqi@0 319 * @see #getHandler
aoqi@0 320 */
aoqi@0 321 protected abstract class LocationHandler {
aoqi@0 322 final Location location;
aoqi@0 323 final Set<Option> options;
aoqi@0 324
aoqi@0 325 /**
aoqi@0 326 * Create a handler. The location and options provide a way to map
aoqi@0 327 * from a location or an option to the corresponding handler.
aoqi@0 328 * @see #initHandlers
aoqi@0 329 */
aoqi@0 330 protected LocationHandler(Location location, Option... options) {
aoqi@0 331 this.location = location;
aoqi@0 332 this.options = options.length == 0 ?
aoqi@0 333 EnumSet.noneOf(Option.class):
aoqi@0 334 EnumSet.copyOf(Arrays.asList(options));
aoqi@0 335 }
aoqi@0 336
aoqi@0 337 // TODO: TEMPORARY, while Options still used for command line options
aoqi@0 338 void update(Options optionTable) {
aoqi@0 339 for (Option o: options) {
aoqi@0 340 String v = optionTable.get(o);
aoqi@0 341 if (v != null) {
aoqi@0 342 handleOption(o, v);
aoqi@0 343 }
aoqi@0 344 }
aoqi@0 345 }
aoqi@0 346
aoqi@0 347 /** @see JavaFileManager#handleOption */
aoqi@0 348 abstract boolean handleOption(Option option, String value);
aoqi@0 349 /** @see StandardJavaFileManager#getLocation */
aoqi@0 350 abstract Collection<File> getLocation();
aoqi@0 351 /** @see StandardJavaFileManager#setLocation */
aoqi@0 352 abstract void setLocation(Iterable<? extends File> files) throws IOException;
aoqi@0 353 }
aoqi@0 354
aoqi@0 355 /**
aoqi@0 356 * General purpose implementation for output locations,
aoqi@0 357 * such as -d/CLASS_OUTPUT and -s/SOURCE_OUTPUT.
aoqi@0 358 * All options are treated as equivalent (i.e. aliases.)
aoqi@0 359 * The value is a single file, possibly null.
aoqi@0 360 */
aoqi@0 361 private class OutputLocationHandler extends LocationHandler {
aoqi@0 362 private File outputDir;
aoqi@0 363
aoqi@0 364 OutputLocationHandler(Location location, Option... options) {
aoqi@0 365 super(location, options);
aoqi@0 366 }
aoqi@0 367
aoqi@0 368 @Override
aoqi@0 369 boolean handleOption(Option option, String value) {
aoqi@0 370 if (!options.contains(option))
aoqi@0 371 return false;
aoqi@0 372
aoqi@0 373 // TODO: could/should validate outputDir exists and is a directory
aoqi@0 374 // need to decide how best to report issue for benefit of
aoqi@0 375 // direct API call on JavaFileManager.handleOption(specifies IAE)
aoqi@0 376 // vs. command line decoding.
aoqi@0 377 outputDir = new File(value);
aoqi@0 378 return true;
aoqi@0 379 }
aoqi@0 380
aoqi@0 381 @Override
aoqi@0 382 Collection<File> getLocation() {
aoqi@0 383 return (outputDir == null) ? null : Collections.singleton(outputDir);
aoqi@0 384 }
aoqi@0 385
aoqi@0 386 @Override
aoqi@0 387 void setLocation(Iterable<? extends File> files) throws IOException {
aoqi@0 388 if (files == null) {
aoqi@0 389 outputDir = null;
aoqi@0 390 } else {
aoqi@0 391 Iterator<? extends File> pathIter = files.iterator();
aoqi@0 392 if (!pathIter.hasNext())
aoqi@0 393 throw new IllegalArgumentException("empty path for directory");
aoqi@0 394 File dir = pathIter.next();
aoqi@0 395 if (pathIter.hasNext())
aoqi@0 396 throw new IllegalArgumentException("path too long for directory");
aoqi@0 397 if (!dir.exists())
aoqi@0 398 throw new FileNotFoundException(dir + ": does not exist");
aoqi@0 399 else if (!dir.isDirectory())
aoqi@0 400 throw new IOException(dir + ": not a directory");
aoqi@0 401 outputDir = dir;
aoqi@0 402 }
aoqi@0 403 }
aoqi@0 404 }
aoqi@0 405
aoqi@0 406 /**
aoqi@0 407 * General purpose implementation for search path locations,
aoqi@0 408 * such as -sourcepath/SOURCE_PATH and -processorPath/ANNOTATION_PROCESS_PATH.
aoqi@0 409 * All options are treated as equivalent (i.e. aliases.)
aoqi@0 410 * The value is an ordered set of files and/or directories.
aoqi@0 411 */
aoqi@0 412 private class SimpleLocationHandler extends LocationHandler {
aoqi@0 413 protected Collection<File> searchPath;
aoqi@0 414
aoqi@0 415 SimpleLocationHandler(Location location, Option... options) {
aoqi@0 416 super(location, options);
aoqi@0 417 }
aoqi@0 418
aoqi@0 419 @Override
aoqi@0 420 boolean handleOption(Option option, String value) {
aoqi@0 421 if (!options.contains(option))
aoqi@0 422 return false;
aoqi@0 423 searchPath = value == null ? null :
aoqi@0 424 Collections.unmodifiableCollection(createPath().addFiles(value));
aoqi@0 425 return true;
aoqi@0 426 }
aoqi@0 427
aoqi@0 428 @Override
aoqi@0 429 Collection<File> getLocation() {
aoqi@0 430 return searchPath;
aoqi@0 431 }
aoqi@0 432
aoqi@0 433 @Override
aoqi@0 434 void setLocation(Iterable<? extends File> files) {
aoqi@0 435 Path p;
aoqi@0 436 if (files == null) {
aoqi@0 437 p = computePath(null);
aoqi@0 438 } else {
aoqi@0 439 p = createPath().addFiles(files);
aoqi@0 440 }
aoqi@0 441 searchPath = Collections.unmodifiableCollection(p);
aoqi@0 442 }
aoqi@0 443
aoqi@0 444 protected Path computePath(String value) {
aoqi@0 445 return createPath().addFiles(value);
aoqi@0 446 }
aoqi@0 447
aoqi@0 448 protected Path createPath() {
aoqi@0 449 return new Path();
aoqi@0 450 }
aoqi@0 451 }
aoqi@0 452
aoqi@0 453 /**
aoqi@0 454 * Subtype of SimpleLocationHandler for -classpath/CLASS_PATH.
aoqi@0 455 * If no value is given, a default is provided, based on system properties
aoqi@0 456 * and other values.
aoqi@0 457 */
aoqi@0 458 private class ClassPathLocationHandler extends SimpleLocationHandler {
aoqi@0 459 ClassPathLocationHandler() {
aoqi@0 460 super(StandardLocation.CLASS_PATH,
aoqi@0 461 Option.CLASSPATH, Option.CP);
aoqi@0 462 }
aoqi@0 463
aoqi@0 464 @Override
aoqi@0 465 Collection<File> getLocation() {
aoqi@0 466 lazy();
aoqi@0 467 return searchPath;
aoqi@0 468 }
aoqi@0 469
aoqi@0 470 @Override
aoqi@0 471 protected Path computePath(String value) {
aoqi@0 472 String cp = value;
aoqi@0 473
aoqi@0 474 // CLASSPATH environment variable when run from `javac'.
aoqi@0 475 if (cp == null) cp = System.getProperty("env.class.path");
aoqi@0 476
aoqi@0 477 // If invoked via a java VM (not the javac launcher), use the
aoqi@0 478 // platform class path
aoqi@0 479 if (cp == null && System.getProperty("application.home") == null)
aoqi@0 480 cp = System.getProperty("java.class.path");
aoqi@0 481
aoqi@0 482 // Default to current working directory.
aoqi@0 483 if (cp == null) cp = ".";
aoqi@0 484
aoqi@0 485 return createPath().addFiles(cp);
aoqi@0 486 }
aoqi@0 487
aoqi@0 488 @Override
aoqi@0 489 protected Path createPath() {
aoqi@0 490 return new Path()
aoqi@0 491 .expandJarClassPaths(true) // Only search user jars for Class-Paths
aoqi@0 492 .emptyPathDefault(new File(".")); // Empty path elt ==> current directory
aoqi@0 493 }
aoqi@0 494
aoqi@0 495 private void lazy() {
aoqi@0 496 if (searchPath == null)
aoqi@0 497 setLocation(null);
aoqi@0 498 }
aoqi@0 499 }
aoqi@0 500
aoqi@0 501 /**
aoqi@0 502 * Custom subtype of LocationHandler for PLATFORM_CLASS_PATH.
aoqi@0 503 * Various options are supported for different components of the
aoqi@0 504 * platform class path.
aoqi@0 505 * Setting a value with setLocation overrides all existing option values.
aoqi@0 506 * Setting any option overrides any value set with setLocation, and reverts
aoqi@0 507 * to using default values for options that have not been set.
aoqi@0 508 * Setting -bootclasspath or -Xbootclasspath overrides any existing
aoqi@0 509 * value for -Xbootclasspath/p: and -Xbootclasspath/a:.
aoqi@0 510 */
aoqi@0 511 private class BootClassPathLocationHandler extends LocationHandler {
aoqi@0 512 private Collection<File> searchPath;
aoqi@0 513 final Map<Option, String> optionValues = new EnumMap<Option,String>(Option.class);
aoqi@0 514
aoqi@0 515 /**
aoqi@0 516 * rt.jar as found on the default bootclasspath.
aoqi@0 517 * If the user specified a bootclasspath, null is used.
aoqi@0 518 */
aoqi@0 519 private File defaultBootClassPathRtJar = null;
aoqi@0 520
aoqi@0 521 /**
aoqi@0 522 * Is bootclasspath the default?
aoqi@0 523 */
aoqi@0 524 private boolean isDefaultBootClassPath;
aoqi@0 525
aoqi@0 526 BootClassPathLocationHandler() {
aoqi@0 527 super(StandardLocation.PLATFORM_CLASS_PATH,
aoqi@0 528 Option.BOOTCLASSPATH, Option.XBOOTCLASSPATH,
aoqi@0 529 Option.XBOOTCLASSPATH_PREPEND,
aoqi@0 530 Option.XBOOTCLASSPATH_APPEND,
aoqi@0 531 Option.ENDORSEDDIRS, Option.DJAVA_ENDORSED_DIRS,
aoqi@0 532 Option.EXTDIRS, Option.DJAVA_EXT_DIRS);
aoqi@0 533 }
aoqi@0 534
aoqi@0 535 boolean isDefault() {
aoqi@0 536 lazy();
aoqi@0 537 return isDefaultBootClassPath;
aoqi@0 538 }
aoqi@0 539
aoqi@0 540 boolean isDefaultRtJar(File file) {
aoqi@0 541 lazy();
aoqi@0 542 return file.equals(defaultBootClassPathRtJar);
aoqi@0 543 }
aoqi@0 544
aoqi@0 545 @Override
aoqi@0 546 boolean handleOption(Option option, String value) {
aoqi@0 547 if (!options.contains(option))
aoqi@0 548 return false;
aoqi@0 549
aoqi@0 550 option = canonicalize(option);
aoqi@0 551 optionValues.put(option, value);
aoqi@0 552 if (option == BOOTCLASSPATH) {
aoqi@0 553 optionValues.remove(XBOOTCLASSPATH_PREPEND);
aoqi@0 554 optionValues.remove(XBOOTCLASSPATH_APPEND);
aoqi@0 555 }
aoqi@0 556 searchPath = null; // reset to "uninitialized"
aoqi@0 557 return true;
aoqi@0 558 }
aoqi@0 559 // where
aoqi@0 560 // TODO: would be better if option aliasing was handled at a higher
aoqi@0 561 // level
aoqi@0 562 private Option canonicalize(Option option) {
aoqi@0 563 switch (option) {
aoqi@0 564 case XBOOTCLASSPATH:
aoqi@0 565 return Option.BOOTCLASSPATH;
aoqi@0 566 case DJAVA_ENDORSED_DIRS:
aoqi@0 567 return Option.ENDORSEDDIRS;
aoqi@0 568 case DJAVA_EXT_DIRS:
aoqi@0 569 return Option.EXTDIRS;
aoqi@0 570 default:
aoqi@0 571 return option;
aoqi@0 572 }
aoqi@0 573 }
aoqi@0 574
aoqi@0 575 @Override
aoqi@0 576 Collection<File> getLocation() {
aoqi@0 577 lazy();
aoqi@0 578 return searchPath;
aoqi@0 579 }
aoqi@0 580
aoqi@0 581 @Override
aoqi@0 582 void setLocation(Iterable<? extends File> files) {
aoqi@0 583 if (files == null) {
aoqi@0 584 searchPath = null; // reset to "uninitialized"
aoqi@0 585 } else {
aoqi@0 586 defaultBootClassPathRtJar = null;
aoqi@0 587 isDefaultBootClassPath = false;
aoqi@0 588 Path p = new Path().addFiles(files, false);
aoqi@0 589 searchPath = Collections.unmodifiableCollection(p);
aoqi@0 590 optionValues.clear();
aoqi@0 591 }
aoqi@0 592 }
aoqi@0 593
aoqi@0 594 Path computePath() {
aoqi@0 595 defaultBootClassPathRtJar = null;
aoqi@0 596 Path path = new Path();
aoqi@0 597
aoqi@0 598 String bootclasspathOpt = optionValues.get(BOOTCLASSPATH);
aoqi@0 599 String endorseddirsOpt = optionValues.get(ENDORSEDDIRS);
aoqi@0 600 String extdirsOpt = optionValues.get(EXTDIRS);
aoqi@0 601 String xbootclasspathPrependOpt = optionValues.get(XBOOTCLASSPATH_PREPEND);
aoqi@0 602 String xbootclasspathAppendOpt = optionValues.get(XBOOTCLASSPATH_APPEND);
aoqi@0 603 path.addFiles(xbootclasspathPrependOpt);
aoqi@0 604
aoqi@0 605 if (endorseddirsOpt != null)
aoqi@0 606 path.addDirectories(endorseddirsOpt);
aoqi@0 607 else
aoqi@0 608 path.addDirectories(System.getProperty("java.endorsed.dirs"), false);
aoqi@0 609
aoqi@0 610 if (bootclasspathOpt != null) {
aoqi@0 611 path.addFiles(bootclasspathOpt);
aoqi@0 612 } else {
aoqi@0 613 // Standard system classes for this compiler's release.
aoqi@0 614 String files = System.getProperty("sun.boot.class.path");
aoqi@0 615 path.addFiles(files, false);
aoqi@0 616 File rt_jar = new File("rt.jar");
aoqi@0 617 for (File file : getPathEntries(files)) {
aoqi@0 618 if (new File(file.getName()).equals(rt_jar))
aoqi@0 619 defaultBootClassPathRtJar = file;
aoqi@0 620 }
aoqi@0 621 }
aoqi@0 622
aoqi@0 623 path.addFiles(xbootclasspathAppendOpt);
aoqi@0 624
aoqi@0 625 // Strictly speaking, standard extensions are not bootstrap
aoqi@0 626 // classes, but we treat them identically, so we'll pretend
aoqi@0 627 // that they are.
aoqi@0 628 if (extdirsOpt != null)
aoqi@0 629 path.addDirectories(extdirsOpt);
aoqi@0 630 else
aoqi@0 631 path.addDirectories(System.getProperty("java.ext.dirs"), false);
aoqi@0 632
aoqi@0 633 isDefaultBootClassPath =
aoqi@0 634 (xbootclasspathPrependOpt == null) &&
aoqi@0 635 (bootclasspathOpt == null) &&
aoqi@0 636 (xbootclasspathAppendOpt == null);
aoqi@0 637
aoqi@0 638 return path;
aoqi@0 639 }
aoqi@0 640
aoqi@0 641 private void lazy() {
aoqi@0 642 if (searchPath == null)
aoqi@0 643 searchPath = Collections.unmodifiableCollection(computePath());
aoqi@0 644 }
aoqi@0 645 }
aoqi@0 646
aoqi@0 647 Map<Location, LocationHandler> handlersForLocation;
aoqi@0 648 Map<Option, LocationHandler> handlersForOption;
aoqi@0 649
aoqi@0 650 void initHandlers() {
aoqi@0 651 handlersForLocation = new HashMap<Location, LocationHandler>();
aoqi@0 652 handlersForOption = new EnumMap<Option, LocationHandler>(Option.class);
aoqi@0 653
aoqi@0 654 LocationHandler[] handlers = {
aoqi@0 655 new BootClassPathLocationHandler(),
aoqi@0 656 new ClassPathLocationHandler(),
aoqi@0 657 new SimpleLocationHandler(StandardLocation.SOURCE_PATH, Option.SOURCEPATH),
aoqi@0 658 new SimpleLocationHandler(StandardLocation.ANNOTATION_PROCESSOR_PATH, Option.PROCESSORPATH),
aoqi@0 659 new OutputLocationHandler((StandardLocation.CLASS_OUTPUT), Option.D),
aoqi@0 660 new OutputLocationHandler((StandardLocation.SOURCE_OUTPUT), Option.S),
aoqi@0 661 new OutputLocationHandler((StandardLocation.NATIVE_HEADER_OUTPUT), Option.H)
aoqi@0 662 };
aoqi@0 663
aoqi@0 664 for (LocationHandler h: handlers) {
aoqi@0 665 handlersForLocation.put(h.location, h);
aoqi@0 666 for (Option o: h.options)
aoqi@0 667 handlersForOption.put(o, h);
aoqi@0 668 }
aoqi@0 669 }
aoqi@0 670
aoqi@0 671 boolean handleOption(Option option, String value) {
aoqi@0 672 LocationHandler h = handlersForOption.get(option);
aoqi@0 673 return (h == null ? false : h.handleOption(option, value));
aoqi@0 674 }
aoqi@0 675
aoqi@0 676 Collection<File> getLocation(Location location) {
aoqi@0 677 LocationHandler h = getHandler(location);
aoqi@0 678 return (h == null ? null : h.getLocation());
aoqi@0 679 }
aoqi@0 680
aoqi@0 681 File getOutputLocation(Location location) {
aoqi@0 682 if (!location.isOutputLocation())
aoqi@0 683 throw new IllegalArgumentException();
aoqi@0 684 LocationHandler h = getHandler(location);
aoqi@0 685 return ((OutputLocationHandler) h).outputDir;
aoqi@0 686 }
aoqi@0 687
aoqi@0 688 void setLocation(Location location, Iterable<? extends File> files) throws IOException {
aoqi@0 689 LocationHandler h = getHandler(location);
aoqi@0 690 if (h == null) {
aoqi@0 691 if (location.isOutputLocation())
aoqi@0 692 h = new OutputLocationHandler(location);
aoqi@0 693 else
aoqi@0 694 h = new SimpleLocationHandler(location);
aoqi@0 695 handlersForLocation.put(location, h);
aoqi@0 696 }
aoqi@0 697 h.setLocation(files);
aoqi@0 698 }
aoqi@0 699
aoqi@0 700 protected LocationHandler getHandler(Location location) {
aoqi@0 701 location.getClass(); // null check
aoqi@0 702 lazy();
aoqi@0 703 return handlersForLocation.get(location);
aoqi@0 704 }
aoqi@0 705
aoqi@0 706 // TOGO
aoqi@0 707 protected void lazy() {
aoqi@0 708 if (!inited) {
aoqi@0 709 warn = lint.isEnabled(Lint.LintCategory.PATH);
aoqi@0 710
aoqi@0 711 for (LocationHandler h: handlersForLocation.values()) {
aoqi@0 712 h.update(options);
aoqi@0 713 }
aoqi@0 714
aoqi@0 715 inited = true;
aoqi@0 716 }
aoqi@0 717 }
aoqi@0 718
aoqi@0 719 /** Is this the name of an archive file? */
aoqi@0 720 private boolean isArchive(File file) {
aoqi@0 721 String n = StringUtils.toLowerCase(file.getName());
aoqi@0 722 return fsInfo.isFile(file)
aoqi@0 723 && (n.endsWith(".jar") || n.endsWith(".zip"));
aoqi@0 724 }
aoqi@0 725
aoqi@0 726 /**
aoqi@0 727 * Utility method for converting a search path string to an array
aoqi@0 728 * of directory and JAR file URLs.
aoqi@0 729 *
aoqi@0 730 * Note that this method is called by apt and the DocletInvoker.
aoqi@0 731 *
aoqi@0 732 * @param path the search path string
aoqi@0 733 * @return the resulting array of directory and JAR file URLs
aoqi@0 734 */
aoqi@0 735 public static URL[] pathToURLs(String path) {
aoqi@0 736 StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
aoqi@0 737 URL[] urls = new URL[st.countTokens()];
aoqi@0 738 int count = 0;
aoqi@0 739 while (st.hasMoreTokens()) {
aoqi@0 740 URL url = fileToURL(new File(st.nextToken()));
aoqi@0 741 if (url != null) {
aoqi@0 742 urls[count++] = url;
aoqi@0 743 }
aoqi@0 744 }
aoqi@0 745 urls = Arrays.copyOf(urls, count);
aoqi@0 746 return urls;
aoqi@0 747 }
aoqi@0 748
aoqi@0 749 /**
aoqi@0 750 * Returns the directory or JAR file URL corresponding to the specified
aoqi@0 751 * local file name.
aoqi@0 752 *
aoqi@0 753 * @param file the File object
aoqi@0 754 * @return the resulting directory or JAR file URL, or null if unknown
aoqi@0 755 */
aoqi@0 756 private static URL fileToURL(File file) {
aoqi@0 757 String name;
aoqi@0 758 try {
aoqi@0 759 name = file.getCanonicalPath();
aoqi@0 760 } catch (IOException e) {
aoqi@0 761 name = file.getAbsolutePath();
aoqi@0 762 }
aoqi@0 763 name = name.replace(File.separatorChar, '/');
aoqi@0 764 if (!name.startsWith("/")) {
aoqi@0 765 name = "/" + name;
aoqi@0 766 }
aoqi@0 767 // If the file does not exist, then assume that it's a directory
aoqi@0 768 if (!file.isFile()) {
aoqi@0 769 name = name + "/";
aoqi@0 770 }
aoqi@0 771 try {
aoqi@0 772 return new URL("file", "", name);
aoqi@0 773 } catch (MalformedURLException e) {
aoqi@0 774 throw new IllegalArgumentException(file.toString());
aoqi@0 775 }
aoqi@0 776 }
aoqi@0 777 }

mercurial