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

Tue, 25 Sep 2012 13:06:58 -0700

author
jjg
date
Tue, 25 Sep 2012 13:06:58 -0700
changeset 1339
0e5899f09dab
parent 1230
b14d9583ce92
child 1358
fc123bdeddb8
permissions
-rw-r--r--

7193657: provide internal ArrayUtils class to simplify common usage of arrays in javac
Reviewed-by: mcimadamore, jjg
Contributed-by: vicenterz@yahoo.es

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

mercurial