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

Tue, 09 Oct 2012 19:31:58 -0700

author
jjg
date
Tue, 09 Oct 2012 19:31:58 -0700
changeset 1358
fc123bdeddb8
parent 1339
0e5899f09dab
child 1375
ea2616a6bd01
permissions
-rw-r--r--

8000208: fix langtools javadoc comment issues
Reviewed-by: bpatel, mcimadamore

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@1116 423 Collections.unmodifiableCollection(computePath(value));
jjg@1116 424 return true;
jjg@1116 425 }
jjg@1116 426
jjg@1116 427 protected Path computePath(String value) {
jjg@1116 428 return new Path().addFiles(value);
jjg@1116 429 }
jjg@1116 430
jjg@1116 431 @Override
jjg@1116 432 Collection<File> getLocation() {
jjg@1116 433 return searchPath;
jjg@1116 434 }
jjg@1116 435
jjg@1116 436 @Override
jjg@1116 437 void setLocation(Iterable<? extends File> files) {
jjg@1116 438 Path p;
jjg@1116 439 if (files == null) {
jjg@1116 440 p = computePath(null);
jjg@1116 441 } else {
jjg@1116 442 p = new Path().addFiles(files);
jjg@1116 443 }
jjg@1116 444 searchPath = Collections.unmodifiableCollection(p);
jjg@1116 445 }
duke@1 446 }
duke@1 447
jjg@1116 448 /**
jjg@1116 449 * Subtype of SimpleLocationHandler for -classpath/CLASS_PATH.
jjg@1116 450 * If no value is given, a default is provided, based on system properties
jjg@1116 451 * and other values.
jjg@1116 452 */
jjg@1116 453 private class ClassPathLocationHandler extends SimpleLocationHandler {
jjg@1116 454 ClassPathLocationHandler() {
jjg@1116 455 super(StandardLocation.CLASS_PATH,
jjg@1157 456 Option.CLASSPATH, Option.CP);
jjg@1116 457 }
duke@1 458
jjg@1116 459 @Override
jjg@1116 460 Collection<File> getLocation() {
jjg@1116 461 lazy();
jjg@1116 462 return searchPath;
jjg@1116 463 }
jjg@1116 464
jjg@1116 465 @Override
jjg@1116 466 protected Path computePath(String value) {
jjg@1116 467 String cp = value;
jjg@1116 468
jjg@1116 469 // CLASSPATH environment variable when run from `javac'.
jjg@1116 470 if (cp == null) cp = System.getProperty("env.class.path");
jjg@1116 471
jjg@1116 472 // If invoked via a java VM (not the javac launcher), use the
jjg@1116 473 // platform class path
jjg@1116 474 if (cp == null && System.getProperty("application.home") == null)
jjg@1116 475 cp = System.getProperty("java.class.path");
jjg@1116 476
jjg@1116 477 // Default to current working directory.
jjg@1116 478 if (cp == null) cp = ".";
jjg@1116 479
jjg@1116 480 return new Path()
jjg@1116 481 .expandJarClassPaths(true) // Only search user jars for Class-Paths
jjg@1116 482 .emptyPathDefault(new File(".")) // Empty path elt ==> current directory
jjg@1116 483 .addFiles(cp);
jjg@1116 484 }
jjg@1116 485
jjg@1116 486 private void lazy() {
jjg@1116 487 if (searchPath == null)
jjg@1116 488 setLocation(null);
jjg@1116 489 }
duke@1 490 }
duke@1 491
jjg@1116 492 /**
jjg@1116 493 * Custom subtype of LocationHandler for PLATFORM_CLASS_PATH.
jjg@1116 494 * Various options are supported for different components of the
jjg@1116 495 * platform class path.
jjg@1116 496 * Setting a value with setLocation overrides all existing option values.
jjg@1116 497 * Setting any option overrides any value set with setLocation, and reverts
jjg@1116 498 * to using default values for options that have not been set.
jjg@1116 499 * Setting -bootclasspath or -Xbootclasspath overrides any existing
jjg@1116 500 * value for -Xbootclasspath/p: and -Xbootclasspath/a:.
jjg@1116 501 */
jjg@1116 502 private class BootClassPathLocationHandler extends LocationHandler {
jjg@1116 503 private Collection<File> searchPath;
jjg@1157 504 final Map<Option, String> optionValues = new EnumMap<Option,String>(Option.class);
duke@1 505
jjg@1116 506 /**
jjg@1116 507 * rt.jar as found on the default bootclasspath.
jjg@1116 508 * If the user specified a bootclasspath, null is used.
jjg@1116 509 */
jjg@1116 510 private File defaultBootClassPathRtJar = null;
jjg@1116 511
jjg@1116 512 /**
jjg@1116 513 * Is bootclasspath the default?
jjg@1116 514 */
jjg@1116 515 private boolean isDefaultBootClassPath;
jjg@1116 516
jjg@1116 517 BootClassPathLocationHandler() {
jjg@1116 518 super(StandardLocation.PLATFORM_CLASS_PATH,
jjg@1157 519 Option.BOOTCLASSPATH, Option.XBOOTCLASSPATH,
jjg@1157 520 Option.XBOOTCLASSPATH_PREPEND,
jjg@1157 521 Option.XBOOTCLASSPATH_APPEND,
jjg@1157 522 Option.ENDORSEDDIRS, Option.DJAVA_ENDORSED_DIRS,
jjg@1157 523 Option.EXTDIRS, Option.DJAVA_EXT_DIRS);
jjg@1116 524 }
jjg@1116 525
jjg@1116 526 boolean isDefault() {
duke@1 527 lazy();
jjg@1116 528 return isDefaultBootClassPath;
duke@1 529 }
jjg@1116 530
jjg@1116 531 boolean isDefaultRtJar(File file) {
jjg@1116 532 lazy();
jjg@1116 533 return file.equals(defaultBootClassPathRtJar);
jjg@1116 534 }
jjg@1116 535
jjg@1116 536 @Override
jjg@1157 537 boolean handleOption(Option option, String value) {
jjg@1116 538 if (!options.contains(option))
jjg@1116 539 return false;
jjg@1116 540
jjg@1116 541 option = canonicalize(option);
jjg@1116 542 optionValues.put(option, value);
jjg@1116 543 if (option == BOOTCLASSPATH) {
jjg@1116 544 optionValues.remove(XBOOTCLASSPATH_PREPEND);
jjg@1116 545 optionValues.remove(XBOOTCLASSPATH_APPEND);
jjg@1116 546 }
jjg@1116 547 searchPath = null; // reset to "uninitialized"
jjg@1116 548 return true;
jjg@1116 549 }
jjg@1116 550 // where
jjg@1116 551 // TODO: would be better if option aliasing was handled at a higher
jjg@1116 552 // level
jjg@1157 553 private Option canonicalize(Option option) {
jjg@1116 554 switch (option) {
jjg@1116 555 case XBOOTCLASSPATH:
jjg@1157 556 return Option.BOOTCLASSPATH;
jjg@1116 557 case DJAVA_ENDORSED_DIRS:
jjg@1157 558 return Option.ENDORSEDDIRS;
jjg@1116 559 case DJAVA_EXT_DIRS:
jjg@1157 560 return Option.EXTDIRS;
jjg@1116 561 default:
jjg@1116 562 return option;
jjg@1116 563 }
jjg@1116 564 }
jjg@1116 565
jjg@1116 566 @Override
jjg@1116 567 Collection<File> getLocation() {
jjg@1116 568 lazy();
jjg@1116 569 return searchPath;
jjg@1116 570 }
jjg@1116 571
jjg@1116 572 @Override
jjg@1116 573 void setLocation(Iterable<? extends File> files) {
jjg@1116 574 if (files == null) {
jjg@1116 575 searchPath = null; // reset to "uninitialized"
jjg@1116 576 } else {
jjg@1116 577 defaultBootClassPathRtJar = null;
jjg@1116 578 isDefaultBootClassPath = false;
jjg@1116 579 Path p = new Path().addFiles(files, false);
jjg@1116 580 searchPath = Collections.unmodifiableCollection(p);
jjg@1116 581 optionValues.clear();
jjg@1116 582 }
jjg@1116 583 }
jjg@1116 584
jjg@1116 585 Path computePath() {
jjg@1116 586 defaultBootClassPathRtJar = null;
jjg@1116 587 Path path = new Path();
jjg@1116 588
jjg@1116 589 String bootclasspathOpt = optionValues.get(BOOTCLASSPATH);
jjg@1116 590 String endorseddirsOpt = optionValues.get(ENDORSEDDIRS);
jjg@1116 591 String extdirsOpt = optionValues.get(EXTDIRS);
jjg@1116 592 String xbootclasspathPrependOpt = optionValues.get(XBOOTCLASSPATH_PREPEND);
jjg@1116 593 String xbootclasspathAppendOpt = optionValues.get(XBOOTCLASSPATH_APPEND);
jjg@1116 594
jjg@1116 595 path.addFiles(xbootclasspathPrependOpt);
jjg@1116 596
jjg@1116 597 if (endorseddirsOpt != null)
jjg@1116 598 path.addDirectories(endorseddirsOpt);
jjg@1116 599 else
jjg@1116 600 path.addDirectories(System.getProperty("java.endorsed.dirs"), false);
jjg@1116 601
jjg@1116 602 if (bootclasspathOpt != null) {
jjg@1116 603 path.addFiles(bootclasspathOpt);
jjg@1116 604 } else {
jjg@1116 605 // Standard system classes for this compiler's release.
jjg@1116 606 String files = System.getProperty("sun.boot.class.path");
jjg@1116 607 path.addFiles(files, false);
jjg@1116 608 File rt_jar = new File("rt.jar");
jjg@1116 609 for (File file : getPathEntries(files)) {
jjg@1116 610 if (new File(file.getName()).equals(rt_jar))
jjg@1116 611 defaultBootClassPathRtJar = file;
jjg@1116 612 }
jjg@1116 613 }
jjg@1116 614
jjg@1116 615 path.addFiles(xbootclasspathAppendOpt);
jjg@1116 616
jjg@1116 617 // Strictly speaking, standard extensions are not bootstrap
jjg@1116 618 // classes, but we treat them identically, so we'll pretend
jjg@1116 619 // that they are.
jjg@1116 620 if (extdirsOpt != null)
jjg@1116 621 path.addDirectories(extdirsOpt);
jjg@1116 622 else
jjg@1116 623 path.addDirectories(System.getProperty("java.ext.dirs"), false);
jjg@1116 624
jjg@1116 625 isDefaultBootClassPath =
jjg@1116 626 (xbootclasspathPrependOpt == null) &&
jjg@1116 627 (bootclasspathOpt == null) &&
jjg@1116 628 (xbootclasspathAppendOpt == null);
jjg@1116 629
jjg@1116 630 return path;
jjg@1116 631 }
jjg@1116 632
jjg@1116 633 private void lazy() {
jjg@1116 634 if (searchPath == null)
jjg@1116 635 searchPath = Collections.unmodifiableCollection(computePath());
jjg@1116 636 }
duke@1 637 }
duke@1 638
jjg@1116 639 Map<Location, LocationHandler> handlersForLocation;
jjg@1157 640 Map<Option, LocationHandler> handlersForOption;
duke@1 641
jjg@1116 642 void initHandlers() {
jjg@1116 643 handlersForLocation = new HashMap<Location, LocationHandler>();
jjg@1157 644 handlersForOption = new EnumMap<Option, LocationHandler>(Option.class);
jjg@1116 645
jjg@1116 646 LocationHandler[] handlers = {
jjg@1116 647 new BootClassPathLocationHandler(),
jjg@1116 648 new ClassPathLocationHandler(),
jjg@1157 649 new SimpleLocationHandler(StandardLocation.SOURCE_PATH, Option.SOURCEPATH),
jjg@1157 650 new SimpleLocationHandler(StandardLocation.ANNOTATION_PROCESSOR_PATH, Option.PROCESSORPATH),
jjg@1157 651 new OutputLocationHandler((StandardLocation.CLASS_OUTPUT), Option.D),
jjg@1230 652 new OutputLocationHandler((StandardLocation.SOURCE_OUTPUT), Option.S),
jjg@1230 653 new OutputLocationHandler((StandardLocation.NATIVE_HEADER_OUTPUT), Option.H)
jjg@1116 654 };
jjg@1116 655
jjg@1116 656 for (LocationHandler h: handlers) {
jjg@1116 657 handlersForLocation.put(h.location, h);
jjg@1157 658 for (Option o: h.options)
jjg@1116 659 handlersForOption.put(o, h);
duke@1 660 }
duke@1 661 }
duke@1 662
jjg@1157 663 boolean handleOption(Option option, String value) {
jjg@1116 664 LocationHandler h = handlersForOption.get(option);
jjg@1116 665 return (h == null ? false : h.handleOption(option, value));
jjg@1116 666 }
duke@1 667
jjg@1116 668 Collection<File> getLocation(Location location) {
jjg@1116 669 LocationHandler h = getHandler(location);
jjg@1116 670 return (h == null ? null : h.getLocation());
jjg@1116 671 }
jjg@1116 672
jjg@1116 673 File getOutputLocation(Location location) {
jjg@1116 674 if (!location.isOutputLocation())
jjg@1116 675 throw new IllegalArgumentException();
jjg@1116 676 LocationHandler h = getHandler(location);
jjg@1116 677 return ((OutputLocationHandler) h).outputDir;
jjg@1116 678 }
jjg@1116 679
jjg@1116 680 void setLocation(Location location, Iterable<? extends File> files) throws IOException {
jjg@1116 681 LocationHandler h = getHandler(location);
jjg@1116 682 if (h == null) {
jjg@1116 683 if (location.isOutputLocation())
jjg@1116 684 h = new OutputLocationHandler(location);
jjg@1116 685 else
jjg@1116 686 h = new SimpleLocationHandler(location);
jjg@1116 687 handlersForLocation.put(location, h);
jjg@1116 688 }
jjg@1116 689 h.setLocation(files);
jjg@1116 690 }
jjg@1116 691
jjg@1116 692 protected LocationHandler getHandler(Location location) {
jjg@1116 693 location.getClass(); // null check
jjg@1116 694 lazy();
jjg@1116 695 return handlersForLocation.get(location);
jjg@1116 696 }
jjg@1116 697
jjg@1116 698 // TOGO
jjg@1116 699 protected void lazy() {
jjg@1116 700 if (!inited) {
jjg@1116 701 warn = lint.isEnabled(Lint.LintCategory.PATH);
jjg@1116 702
jjg@1116 703 for (LocationHandler h: handlersForLocation.values()) {
jjg@1116 704 h.update(options);
duke@1 705 }
jjg@1116 706
jjg@1116 707 inited = true;
duke@1 708 }
duke@1 709 }
duke@1 710
duke@1 711 /** Is this the name of an archive file? */
jjg@106 712 private boolean isArchive(File file) {
duke@1 713 String n = file.getName().toLowerCase();
jjg@106 714 return fsInfo.isFile(file)
duke@1 715 && (n.endsWith(".jar") || n.endsWith(".zip"));
duke@1 716 }
darcy@497 717
darcy@497 718 /**
darcy@497 719 * Utility method for converting a search path string to an array
darcy@497 720 * of directory and JAR file URLs.
darcy@497 721 *
darcy@497 722 * Note that this method is called by apt and the DocletInvoker.
darcy@497 723 *
darcy@497 724 * @param path the search path string
darcy@497 725 * @return the resulting array of directory and JAR file URLs
darcy@497 726 */
darcy@497 727 public static URL[] pathToURLs(String path) {
darcy@497 728 StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
darcy@497 729 URL[] urls = new URL[st.countTokens()];
darcy@497 730 int count = 0;
darcy@497 731 while (st.hasMoreTokens()) {
darcy@497 732 URL url = fileToURL(new File(st.nextToken()));
darcy@497 733 if (url != null) {
darcy@497 734 urls[count++] = url;
darcy@497 735 }
darcy@497 736 }
jjg@1339 737 urls = Arrays.copyOf(urls, count);
darcy@497 738 return urls;
darcy@497 739 }
darcy@497 740
darcy@497 741 /**
darcy@497 742 * Returns the directory or JAR file URL corresponding to the specified
darcy@497 743 * local file name.
darcy@497 744 *
darcy@497 745 * @param file the File object
darcy@497 746 * @return the resulting directory or JAR file URL, or null if unknown
darcy@497 747 */
darcy@497 748 private static URL fileToURL(File file) {
darcy@497 749 String name;
darcy@497 750 try {
darcy@497 751 name = file.getCanonicalPath();
darcy@497 752 } catch (IOException e) {
darcy@497 753 name = file.getAbsolutePath();
darcy@497 754 }
darcy@497 755 name = name.replace(File.separatorChar, '/');
darcy@497 756 if (!name.startsWith("/")) {
darcy@497 757 name = "/" + name;
darcy@497 758 }
darcy@497 759 // If the file does not exist, then assume that it's a directory
darcy@497 760 if (!file.isFile()) {
darcy@497 761 name = name + "/";
darcy@497 762 }
darcy@497 763 try {
darcy@497 764 return new URL("file", "", name);
darcy@497 765 } catch (MalformedURLException e) {
darcy@497 766 throw new IllegalArgumentException(file.toString());
darcy@497 767 }
darcy@497 768 }
duke@1 769 }

mercurial