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

Fri, 31 Aug 2012 10:37:46 +0100

author
jfranck
date
Fri, 31 Aug 2012 10:37:46 +0100
changeset 1313
873ddd9f4900
parent 1230
b14d9583ce92
child 1339
0e5899f09dab
permissions
-rw-r--r--

7151010: Add compiler support for repeating annotations
Reviewed-by: jjg, mcimadamore

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

mercurial