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

Fri, 09 May 2014 20:33:21 -0700

author
mfang
date
Fri, 09 May 2014 20:33:21 -0700
changeset 2388
0add97444be9
parent 1375
ea2616a6bd01
child 2413
fe033d997ddf
permissions
-rw-r--r--

8041424: 8u20 l10n resource file translation update 1
Reviewed-by: naoto, yhuang

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

mercurial