EMMA Coverage Report (generated Thu Dec 06 15:24:05 GMT 2007)
[all classes][com.sun.tools.javac.util]

COVERAGE SUMMARY FOR SOURCE FILE [Paths.java]

nameclass, %method, %block, %line, %
Paths.java100% (5/5)78%  (39/50)67%  (766/1141)69%  (178/257)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Paths100% (1/1)70%  (19/27)65%  (368/568)64%  (82.2/128)
access$400 (Paths): Log 0%   (0/1)0%   (0/3)0%   (0/1)
bootClassPath (): Collection 0%   (0/1)0%   (0/7)0%   (0/2)
classSearchPath (): Collection 0%   (0/1)0%   (0/33)0%   (0/8)
clearPathExistanceCache (): void 0%   (0/1)0%   (0/3)0%   (0/2)
otherSearchPath (): Collection 0%   (0/1)0%   (0/39)0%   (0/10)
sourcePath (): Collection 0%   (0/1)0%   (0/16)0%   (0/3)
sourceSearchPath (): Collection 0%   (0/1)0%   (0/24)0%   (0/6)
userClassPath (): Collection 0%   (0/1)0%   (0/7)0%   (0/2)
setPathForLocation (JavaFileManager$Location, Iterable): void 100% (1/1)48%  (29/61)60%  (9/15)
computeAnnotationProcessorPath (): Paths$Path 100% (1/1)56%  (9/16)75%  (3/4)
computeSourcePath (): Paths$Path 100% (1/1)56%  (9/16)75%  (3/4)
computeBootClassPath (): Paths$Path 100% (1/1)87%  (101/116)86%  (18/21)
<static initializer> 100% (1/1)93%  (26/28)99%  (5.9/6)
isArchive (File): boolean 100% (1/1)93%  (43/46)91%  (10/11)
computeUserClassPath (): Paths$Path 100% (1/1)94%  (31/33)92%  (5.5/6)
Paths (Context): void 100% (1/1)100% (22/22)100% (7/7)
access$300 (Paths): boolean 100% (1/1)100% (3/3)100% (1/1)
access$500 (File): boolean 100% (1/1)100% (3/3)100% (1/1)
access$600 (): boolean 100% (1/1)100% (2/2)100% (1/1)
access$700 (): Map 100% (1/1)100% (2/2)100% (1/1)
access$800 (): Map 100% (1/1)100% (2/2)100% (1/1)
access$900 (): Lock 100% (1/1)100% (2/2)100% (1/1)
getPathForLocation (JavaFileManager$Location): Paths$Path 100% (1/1)100% (18/18)100% (4/4)
instance (Context): Paths 100% (1/1)100% (14/14)100% (4/4)
isBootClassPathRtJar (File): boolean 100% (1/1)100% (5/5)100% (1/1)
lazy (): void 100% (1/1)100% (34/34)100% (7/7)
setContext (Context): void 100% (1/1)100% (13/13)100% (4/4)
     
class Paths$Path100% (1/1)91%  (10/11)65%  (299/459)71%  (76.2/107)
addDirectories (String): Paths$Path 0%   (0/1)0%   (0/7)0%   (0/1)
addJarClassPath (File, boolean): void 100% (1/1)47%  (74/156)62%  (22.2/36)
addFile (File, boolean): void 100% (1/1)61%  (94/153)65%  (26/40)
addDirectory (String, boolean): void 100% (1/1)77%  (41/53)82%  (9/11)
Paths$Path (Paths): void 100% (1/1)100% (17/17)100% (4/4)
addDirectories (String, boolean): Paths$Path 100% (1/1)100% (22/22)100% (4/4)
addFile (String, boolean): Paths$Path 100% (1/1)100% (9/9)100% (2/2)
addFiles (String): Paths$Path 100% (1/1)100% (7/7)100% (1/1)
addFiles (String, boolean): Paths$Path 100% (1/1)100% (25/25)100% (4/4)
emptyPathDefault (String): Paths$Path 100% (1/1)100% (5/5)100% (2/2)
expandJarClassPaths (boolean): Paths$Path 100% (1/1)100% (5/5)100% (2/2)
     
class Paths$PathIterator$1100% (1/1)75%  (3/4)82%  (54/66)79%  (8.7/11)
remove (): void 0%   (0/1)0%   (0/4)0%   (0/1)
next (): String 100% (1/1)82%  (36/44)84%  (6.7/8)
Paths$PathIterator$1 (Paths$PathIterator): void 100% (1/1)100% (6/6)100% (1/1)
hasNext (): boolean 100% (1/1)100% (12/12)100% (1/1)
     
class Paths$PathIterator100% (1/1)86%  (6/7)92%  (33/36)97%  (7.8/8)
access$200 (Paths$PathIterator): String 0%   (0/1)0%   (0/3)0%   (0/1)
Paths$PathIterator (String): void 100% (1/1)100% (5/5)100% (1/1)
Paths$PathIterator (String, String): void 100% (1/1)100% (12/12)100% (5/5)
access$000 (Paths$PathIterator): int 100% (1/1)100% (3/3)100% (1/1)
access$002 (Paths$PathIterator, int): int 100% (1/1)100% (5/5)100% (1/1)
access$100 (Paths$PathIterator): String 100% (1/1)100% (3/3)100% (1/1)
iterator (): Iterator 100% (1/1)100% (5/5)100% (1/1)
     
class Paths$PathEntry100% (1/1)100% (1/1)100% (12/12)100% (4/4)
Paths$PathEntry (): void 100% (1/1)100% (12/12)100% (4/4)

1/*
2 * Copyright 2003-2006 Sun Microsystems, Inc.  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.  Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25 
26package com.sun.tools.javac.util;
27import java.io.File;
28import java.io.IOException;
29import java.util.HashMap;
30import java.util.HashSet;
31import java.util.Map;
32import java.util.Set;
33import java.util.jar.JarFile;
34import java.util.jar.Manifest;
35import java.util.jar.Attributes;
36import java.util.Collection;
37import java.util.Collections;
38import java.util.LinkedHashSet;
39import java.util.Iterator;
40import java.util.StringTokenizer;
41import java.util.zip.ZipException;
42import java.util.zip.ZipFile;
43import com.sun.tools.javac.code.Lint;
44import com.sun.tools.javac.util.Context;
45import com.sun.tools.javac.util.Log;
46import com.sun.tools.javac.util.Options;
47import com.sun.tools.javac.util.Position;
48import java.util.ArrayList;
49import java.util.concurrent.ConcurrentHashMap;
50import java.util.concurrent.locks.Lock;
51import java.util.concurrent.locks.ReentrantLock;
52import javax.tools.JavaFileManager.Location;
53 
54import static com.sun.tools.javac.main.OptionName.*;
55import static javax.tools.StandardLocation.*;
56 
57/** This class converts command line arguments, environment variables
58 *  and system properties (in File.pathSeparator-separated String form)
59 *  into a boot class path, user class path, and source path (in
60 *  Collection<String> form).
61 *
62 *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
63 *  you write code that depends on this, you do so at your own risk.
64 *  This code and its internal interfaces are subject to change or
65 *  deletion without notice.</b>
66 */
67public class Paths {
68 
69    /** The context key for the todo list */
70    protected static final Context.Key<Paths> pathsKey =
71        new Context.Key<Paths>();
72 
73    /** Get the Paths instance for this context. */
74    public static Paths instance(Context context) {
75        Paths instance = context.get(pathsKey);
76        if (instance == null)
77            instance = new Paths(context);
78        return instance;
79    }
80 
81    /** The log to use for warning output */
82    private Log log;
83 
84    /** Collection of command-line options */
85    private Options options;
86 
87    /** Handler for -Xlint options */
88    private Lint lint;
89 
90    private static boolean NON_BATCH_MODE = System.getProperty("nonBatchMode") != null;// TODO: Use -XD compiler switch for this.
91    private static Map<File, PathEntry> pathExistanceCache = new ConcurrentHashMap<File, PathEntry>();
92    private static Map<File, java.util.List<String>> manifestEntries = new ConcurrentHashMap<File, java.util.List<String>>();
93    private static Map<File, Boolean> isDirectory = new ConcurrentHashMap<File, Boolean>();
94    private static Lock lock = new ReentrantLock();
95 
96    public static void clearPathExistanceCache() {
97            pathExistanceCache.clear();
98    }
99 
100    static class PathEntry {
101        boolean exists = false;
102        boolean isFile = false;
103        File cannonicalPath = null;
104    }
105 
106    protected Paths(Context context) {
107        context.put(pathsKey, this);
108        pathsForLocation = new HashMap<Location,Path>(16);
109        setContext(context);
110    }
111 
112    void setContext(Context context) {
113        log = Log.instance(context);
114        options = Options.instance(context);
115        lint = Lint.instance(context);
116    }
117 
118    /** Whether to warn about non-existent path elements */
119    private boolean warn;
120 
121    private Map<Location, Path> pathsForLocation;
122 
123    private boolean inited = false; // TODO? caching bad?
124 
125    /**
126     * rt.jar as found on the default bootclass path.  If the user specified a
127     * bootclasspath, null is used.
128     */
129    private File bootClassPathRtJar = null;
130 
131    Path getPathForLocation(Location location) {
132        Path path = pathsForLocation.get(location);
133        if (path == null)
134            setPathForLocation(location, null);
135        return pathsForLocation.get(location);
136    }
137 
138    void setPathForLocation(Location location, Iterable<? extends File> path) {
139        // TODO? if (inited) throw new IllegalStateException
140        // TODO: otherwise reset sourceSearchPath, classSearchPath as needed
141        Path p;
142        if (path == null) {
143            if (location == CLASS_PATH)
144                p = computeUserClassPath();
145            else if (location == PLATFORM_CLASS_PATH)
146                p = computeBootClassPath();
147            else if (location == ANNOTATION_PROCESSOR_PATH)
148                p = computeAnnotationProcessorPath();
149            else if (location == SOURCE_PATH)
150                p = computeSourcePath();
151            else
152                // no defaults for other paths
153                p = null;
154        } else {
155            p = new Path();
156            for (File f: path)
157                p.addFile(f, warn); // TODO: is use of warn appropriate?
158        }
159        pathsForLocation.put(location, p);
160    }
161 
162    protected void lazy() {
163        if (!inited) {
164            warn = lint.isEnabled(Lint.LintCategory.PATH);
165 
166            pathsForLocation.put(PLATFORM_CLASS_PATH, computeBootClassPath());
167            pathsForLocation.put(CLASS_PATH, computeUserClassPath());
168            pathsForLocation.put(SOURCE_PATH, computeSourcePath());
169 
170            inited = true;
171        }
172    }
173 
174    public Collection<File> bootClassPath() {
175        lazy();
176        return Collections.unmodifiableCollection(getPathForLocation(PLATFORM_CLASS_PATH));
177    }
178    public Collection<File> userClassPath() {
179        lazy();
180        return Collections.unmodifiableCollection(getPathForLocation(CLASS_PATH));
181    }
182    public Collection<File> sourcePath() {
183        lazy();
184        Path p = getPathForLocation(SOURCE_PATH);
185        return p == null || p.size() == 0
186            ? null
187            : Collections.unmodifiableCollection(p);
188    }
189 
190    boolean isBootClassPathRtJar(File file) {
191        return file.equals(bootClassPathRtJar);
192    }
193 
194    private static class PathIterator implements Iterable<String> {
195        private int pos = 0;
196        private final String path;
197        private final String emptyPathDefault;
198 
199        public PathIterator(String path, String emptyPathDefault) {
200            this.path = path;
201            this.emptyPathDefault = emptyPathDefault;
202        }
203        public PathIterator(String path) { this(path, null); }
204        public Iterator<String> iterator() {
205            return new Iterator<String>() {
206                public boolean hasNext() {
207                    return pos <= path.length();
208                }
209                public String next() {
210                    int beg = pos;
211                    int end = path.indexOf(File.pathSeparator, beg);
212                    if (end == -1)
213                        end = path.length();
214                    pos = end + 1;
215 
216                    if (beg == end && emptyPathDefault != null)
217                        return emptyPathDefault;
218                    else
219                        return path.substring(beg, end);
220                }
221                public void remove() {
222                    throw new UnsupportedOperationException();
223                }
224            };
225        }
226    }
227 
228    private class Path extends LinkedHashSet<File> {
229        private static final long serialVersionUID = 0;
230 
231        private boolean expandJarClassPaths = false;
232        private Set<File> canonicalValues = new HashSet<File>();
233 
234        public Path expandJarClassPaths(boolean x) {
235            expandJarClassPaths = x;
236            return this;
237        }
238 
239        /** What to use when path element is the empty string */
240        private String emptyPathDefault = null;
241 
242        public Path emptyPathDefault(String x) {
243            emptyPathDefault = x;
244            return this;
245        }
246 
247        public Path() { super(); }
248 
249        public Path addDirectories(String dirs, boolean warn) {
250            if (dirs != null)
251                for (String dir : new PathIterator(dirs))
252                    addDirectory(dir, warn);
253            return this;
254        }
255 
256        public Path addDirectories(String dirs) {
257            return addDirectories(dirs, warn);
258        }
259 
260        private void addDirectory(String dir, boolean warn) {
261            if (! new File(dir).isDirectory()) {
262                if (warn)
263                    log.warning("dir.path.element.not.found", dir);
264                return;
265            }
266 
267            File[] files = new File(dir).listFiles();
268            if (files == null)
269                return;
270 
271            for (File direntry : files) {
272                if (isArchive(direntry))
273                    addFile(direntry, warn);
274            }
275        }
276 
277        public Path addFiles(String files, boolean warn) {
278            if (files != null)
279                for (String file : new PathIterator(files, emptyPathDefault))
280                    addFile(file, warn);
281            return this;
282        }
283 
284        public Path addFiles(String files) {
285            return addFiles(files, warn);
286        }
287 
288        public Path addFile(String file, boolean warn) {
289            addFile(new File(file), warn);
290            return this;
291        }
292 
293        public void addFile(File file, boolean warn) {
294            boolean foundInCache = false;
295            PathEntry pe = null;
296            if (!NON_BATCH_MODE) {
297                    pe = pathExistanceCache.get(file);
298                    if (pe != null) {
299                        foundInCache = true;
300                    }
301                    else {
302                        pe = new PathEntry();
303                    }
304            }
305            else {
306                pe = new PathEntry();
307            }
308 
309            File canonFile;
310            try {
311                if (!foundInCache) {
312                    pe.cannonicalPath = file.getCanonicalFile();
313                }
314                else {
315                   canonFile = pe.cannonicalPath;
316                }
317            } catch (IOException e) {
318                pe.cannonicalPath = canonFile = file;
319            }
320 
321            if (contains(file) || canonicalValues.contains(pe.cannonicalPath)) {
322                /* Discard duplicates and avoid infinite recursion */
323                return;
324            }
325 
326            if (!foundInCache) {
327                pe.exists = file.exists();
328                pe.isFile = file.isFile();
329                if (!NON_BATCH_MODE) {
330                    pathExistanceCache.put(file, pe);
331                }
332            }
333 
334            if (! pe.exists) {
335                /* No such file or directory exists */
336                if (warn)
337                    log.warning("path.element.not.found", file);
338            } else if (pe.isFile) {
339                /* File is an ordinary file. */
340                if (!isArchive(file)) {
341                    /* Not a recognized extension; open it to see if
342                     it looks like a valid zip file. */
343                    try {
344                        ZipFile z = new ZipFile(file);
345                        z.close();
346                        if (warn)
347                            log.warning("unexpected.archive.file", file);
348                    } catch (IOException e) {
349                        // FIXME: include e.getLocalizedMessage in warning
350                        if (warn)
351                            log.warning("invalid.archive.file", file);
352                        return;
353                    }
354                }
355            }
356 
357            /* Now what we have left is either a directory or a file name
358               confirming to archive naming convention */
359            super.add(file);
360            canonicalValues.add(pe.cannonicalPath);
361 
362            if (expandJarClassPaths && file.exists() && file.isFile())
363                addJarClassPath(file, warn);
364        }
365 
366        // Adds referenced classpath elements from a jar's Class-Path
367        // Manifest entry.  In some future release, we may want to
368        // update this code to recognize URLs rather than simple
369        // filenames, but if we do, we should redo all path-related code.
370        private void addJarClassPath(File jarFile, boolean warn) {
371            try {
372                java.util.List<String> manifestsList = manifestEntries.get(jarFile);
373                if (!NON_BATCH_MODE) {
374                    lock.lock();
375                    try {
376                        if (manifestsList != null) {
377                            for (String entr : manifestsList) {
378                                addFile(new File(entr), warn);
379                            }
380                            return;
381                        }
382                    }
383                    finally {
384                        lock.unlock();
385                    }
386                }
387 
388                if (!NON_BATCH_MODE) {
389                    manifestsList = new ArrayList<String>();
390                    manifestEntries.put(jarFile, manifestsList);
391                }
392 
393                String jarParent = jarFile.getParent();
394                JarFile jar = new JarFile(jarFile);
395 
396                try {
397                    Manifest man = jar.getManifest();
398                    if (man == null) return;
399 
400                    Attributes attr = man.getMainAttributes();
401                    if (attr == null) return;
402 
403                    String path = attr.getValue(Attributes.Name.CLASS_PATH);
404                    if (path == null) return;
405 
406                    for (StringTokenizer st = new StringTokenizer(path);
407                         st.hasMoreTokens();) {
408                        String elt = st.nextToken();
409                        File f = (jarParent == null ? new File(elt) : new File(jarParent, elt));
410                        addFile(f, warn);
411 
412                        if (!NON_BATCH_MODE) {
413                            lock.lock();
414                            try {
415                                manifestsList.add(elt);
416                            }
417                            finally {
418                                lock.unlock();
419                            }
420                        }
421                    }
422                } finally {
423                    jar.close();
424                }
425            } catch (IOException e) {
426                log.error("error.reading.file", jarFile, e.getLocalizedMessage());
427            }
428        }
429    }
430 
431    private Path computeBootClassPath() {
432        bootClassPathRtJar = null;
433        String optionValue;
434        Path path = new Path();
435 
436        path.addFiles(options.get(XBOOTCLASSPATH_PREPEND));
437 
438        if ((optionValue = options.get(ENDORSEDDIRS)) != null)
439            path.addDirectories(optionValue);
440        else
441            path.addDirectories(System.getProperty("java.endorsed.dirs"), false);
442 
443        if ((optionValue = options.get(BOOTCLASSPATH)) != null) {
444            path.addFiles(optionValue);
445        } else {
446            // Standard system classes for this compiler's release.
447            String files = System.getProperty("sun.boot.class.path");
448            path.addFiles(files, false);
449            File rt_jar = new File("rt.jar");
450            for (String file : new PathIterator(files, null)) {
451                File f = new File(file);
452                if (new File(f.getName()).equals(rt_jar))
453                    bootClassPathRtJar = f;
454            }
455        }
456 
457        path.addFiles(options.get(XBOOTCLASSPATH_APPEND));
458 
459        // Strictly speaking, standard extensions are not bootstrap
460        // classes, but we treat them identically, so we'll pretend
461        // that they are.
462        if ((optionValue = options.get(EXTDIRS)) != null)
463            path.addDirectories(optionValue);
464        else
465            path.addDirectories(System.getProperty("java.ext.dirs"), false);
466 
467        return path;
468    }
469 
470    private Path computeUserClassPath() {
471        String cp = options.get(CLASSPATH);
472 
473        // CLASSPATH environment variable when run from `javac'.
474        if (cp == null) cp = System.getProperty("env.class.path");
475 
476        // If invoked via a java VM (not the javac launcher), use the
477        // platform class path
478        if (cp == null && System.getProperty("application.home") == null)
479            cp = System.getProperty("java.class.path");
480 
481        // Default to current working directory.
482        if (cp == null) cp = ".";
483 
484        return new Path()
485            .expandJarClassPaths(true) // Only search user jars for Class-Paths
486            .emptyPathDefault(".")     // Empty path elt ==> current directory
487            .addFiles(cp);
488    }
489 
490    private Path computeSourcePath() {
491        String sourcePathArg = options.get(SOURCEPATH);
492        if (sourcePathArg == null)
493            return null;
494 
495        return new Path().addFiles(sourcePathArg);
496    }
497 
498    private Path computeAnnotationProcessorPath() {
499        String processorPathArg = options.get(PROCESSORPATH);
500        if (processorPathArg == null)
501            return null;
502 
503        return new Path().addFiles(processorPathArg);
504    }
505 
506    /** The actual effective locations searched for sources */
507    private Path sourceSearchPath;
508 
509    public Collection<File> sourceSearchPath() {
510        if (sourceSearchPath == null) {
511            lazy();
512            Path sourcePath = getPathForLocation(SOURCE_PATH);
513            Path userClassPath = getPathForLocation(CLASS_PATH);
514            sourceSearchPath = sourcePath != null ? sourcePath : userClassPath;
515        }
516        return Collections.unmodifiableCollection(sourceSearchPath);
517    }
518 
519    /** The actual effective locations searched for classes */
520    private Path classSearchPath;
521 
522    public Collection<File> classSearchPath() {
523        if (classSearchPath == null) {
524            lazy();
525            Path bootClassPath = getPathForLocation(PLATFORM_CLASS_PATH);
526            Path userClassPath = getPathForLocation(CLASS_PATH);
527            classSearchPath = new Path();
528            classSearchPath.addAll(bootClassPath);
529            classSearchPath.addAll(userClassPath);
530        }
531        return Collections.unmodifiableCollection(classSearchPath);
532    }
533 
534    /** The actual effective locations for non-source, non-class files */
535    private Path otherSearchPath;
536 
537    Collection<File> otherSearchPath() {
538        if (otherSearchPath == null) {
539            lazy();
540            Path userClassPath = getPathForLocation(CLASS_PATH);
541            Path sourcePath = getPathForLocation(SOURCE_PATH);
542            if (sourcePath == null)
543                otherSearchPath = userClassPath;
544            else {
545                otherSearchPath = new Path();
546                otherSearchPath.addAll(userClassPath);
547                otherSearchPath.addAll(sourcePath);
548            }
549        }
550        return Collections.unmodifiableCollection(otherSearchPath);
551    }
552 
553    /** Is this the name of an archive file? */
554    private static boolean isArchive(File file) {
555        String n = file.getName().toLowerCase();
556        boolean isFile = false;
557        if (!NON_BATCH_MODE) {
558            Boolean isf = isDirectory.get(file);
559            if (isf == null) {
560                isFile = file.isFile();
561                isDirectory.put(file, isFile);
562            }
563            else {
564                isFile = isf;
565            }
566        }
567        else {
568            isFile = file.isFile();
569        }
570 
571        return isFile
572            && (n.endsWith(".jar") || n.endsWith(".zip"));
573    }
574}

[all classes][com.sun.tools.javac.util]
EMMA 2.0.5312 (C) Vladimir Roubtsov