8003562: Provide a CLI tool to analyze class dependencies

Fri, 28 Dec 2012 22:25:21 -0800

author
mchung
date
Fri, 28 Dec 2012 22:25:21 -0800
changeset 1472
0c244701188e
parent 1468
690c41cdab55
child 1473
31780dd06ec7

8003562: Provide a CLI tool to analyze class dependencies
Reviewed-by: jjg, alanb, ulfzibis, erikj

make/build.properties file | annotate | diff | comparison | revisions
makefiles/BuildLangtools.gmk file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/classfile/Dependencies.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/classfile/Dependency.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/jdeps/Archive.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/jdeps/ClassFileReader.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/jdeps/JdepsTask.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/jdeps/Main.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/jdeps/resources/jdk.properties file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/jdeps/resources/version.properties-template file | annotate | diff | comparison | revisions
test/Makefile file | annotate | diff | comparison | revisions
test/tools/jdeps/Basic.java file | annotate | diff | comparison | revisions
test/tools/jdeps/Test.java file | annotate | diff | comparison | revisions
test/tools/jdeps/p/Foo.java file | annotate | diff | comparison | revisions
     1.1 --- a/make/build.properties	Tue Dec 25 17:23:59 2012 -0800
     1.2 +++ b/make/build.properties	Fri Dec 28 22:25:21 2012 -0800
     1.3 @@ -153,6 +153,7 @@
     1.4  javap.includes = \
     1.5          com/sun/tools/classfile/ \
     1.6          com/sun/tools/javap/ \
     1.7 +        com/sun/tools/jdeps/ \
     1.8          sun/tools/javap/
     1.9  
    1.10  javap.tests = \
     2.1 --- a/makefiles/BuildLangtools.gmk	Tue Dec 25 17:23:59 2012 -0800
     2.2 +++ b/makefiles/BuildLangtools.gmk	Fri Dec 28 22:25:21 2012 -0800
     2.3 @@ -75,6 +75,7 @@
     2.4  	printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javah/resources/version.properties
     2.5  	printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javap/resources/version.properties
     2.6  	printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javac/resources/version.properties
     2.7 +	printf "jdk=$(JDK_VERSION)\nfull=$(FULL_VERSION)\nrelease=$(RELEASE)\n" > $(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/jdeps/resources/version.properties
     2.8  	echo Compiling $(words $(PROPSOURCES) v1 v2 v3) properties into resource bundles
     2.9  	$(TOOL_COMPILEPROPS_CMD) $(PROPCMDLINE) \
    2.10  		-compile 	$(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javah/resources/version.properties \
    2.11 @@ -85,6 +86,9 @@
    2.12  				java.util.ListResourceBundle \
    2.13  		-compile	$(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javac/resources/version.properties \
    2.14  				$(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/javac/resources/version.java \
    2.15 +				java.util.ListResourceBundle \
    2.16 +		-compile	$(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/jdeps/resources/version.properties \
    2.17 +				$(LANGTOOLS_OUTPUTDIR)/gensrc/com/sun/tools/jdeps/resources/version.java \
    2.18  				java.util.ListResourceBundle
    2.19  	echo PROPS_ARE_CREATED=yes > $@
    2.20  
     3.1 --- a/src/share/classes/com/sun/tools/classfile/Dependencies.java	Tue Dec 25 17:23:59 2012 -0800
     3.2 +++ b/src/share/classes/com/sun/tools/classfile/Dependencies.java	Fri Dec 28 22:25:21 2012 -0800
     3.3 @@ -142,6 +142,15 @@
     3.4      }
     3.5  
     3.6      /**
     3.7 +     * Get a finder to do class dependency analysis.
     3.8 +     *
     3.9 +     * @return a Class dependency finder
    3.10 +     */
    3.11 +    public static Finder getClassDependencyFinder() {
    3.12 +        return new ClassDependencyFinder();
    3.13 +    }
    3.14 +
    3.15 +    /**
    3.16       * Get the finder used to locate the dependencies for a class.
    3.17       * @return the finder
    3.18       */
    3.19 @@ -246,8 +255,6 @@
    3.20          return results;
    3.21      }
    3.22  
    3.23 -
    3.24 -
    3.25      /**
    3.26       * Find the dependencies of a class, using the current
    3.27       * {@link Dependencies#getFinder finder} and
    3.28 @@ -306,38 +313,44 @@
    3.29       * A location identifying a class.
    3.30       */
    3.31      static class SimpleLocation implements Location {
    3.32 -        public SimpleLocation(String className) {
    3.33 -            this.className = className;
    3.34 +        public SimpleLocation(String name) {
    3.35 +            this.name = name;
    3.36 +            this.className = name.replace('/', '.').replace('$', '.');
    3.37          }
    3.38  
    3.39 -        /**
    3.40 -         * Get the name of the class being depended on. This name will be used to
    3.41 -         * locate the class file for transitive dependency analysis.
    3.42 -         * @return the name of the class being depended on
    3.43 -         */
    3.44 +        public String getName() {
    3.45 +            return name;
    3.46 +        }
    3.47 +
    3.48          public String getClassName() {
    3.49              return className;
    3.50          }
    3.51  
    3.52 +        public String getPackageName() {
    3.53 +            int i = name.lastIndexOf('/');
    3.54 +            return (i > 0) ? name.substring(0, i).replace('/', '.') : "";
    3.55 +        }
    3.56 +
    3.57          @Override
    3.58          public boolean equals(Object other) {
    3.59              if (this == other)
    3.60                  return true;
    3.61              if (!(other instanceof SimpleLocation))
    3.62                  return false;
    3.63 -            return (className.equals(((SimpleLocation) other).className));
    3.64 +            return (name.equals(((SimpleLocation) other).name));
    3.65          }
    3.66  
    3.67          @Override
    3.68          public int hashCode() {
    3.69 -            return className.hashCode();
    3.70 +            return name.hashCode();
    3.71          }
    3.72  
    3.73          @Override
    3.74          public String toString() {
    3.75 -            return className;
    3.76 +            return name;
    3.77          }
    3.78  
    3.79 +        private String name;
    3.80          private String className;
    3.81      }
    3.82  
    3.83 @@ -431,9 +444,7 @@
    3.84          }
    3.85  
    3.86          public boolean accepts(Dependency dependency) {
    3.87 -            String cn = dependency.getTarget().getClassName();
    3.88 -            int lastSep = cn.lastIndexOf("/");
    3.89 -            String pn = (lastSep == -1 ? "" : cn.substring(0, lastSep));
    3.90 +            String pn = dependency.getTarget().getPackageName();
    3.91              if (packageNames.contains(pn))
    3.92                  return true;
    3.93  
    3.94 @@ -451,8 +462,6 @@
    3.95          private final boolean matchSubpackages;
    3.96      }
    3.97  
    3.98 -
    3.99 -
   3.100      /**
   3.101       * This class identifies class names directly or indirectly in the constant pool.
   3.102       */
   3.103 @@ -462,6 +471,26 @@
   3.104              for (CPInfo cpInfo: classfile.constant_pool.entries()) {
   3.105                  v.scan(cpInfo);
   3.106              }
   3.107 +            try {
   3.108 +                v.addClass(classfile.super_class);
   3.109 +                v.addClasses(classfile.interfaces);
   3.110 +                v.scan(classfile.attributes);
   3.111 +
   3.112 +                for (Field f : classfile.fields) {
   3.113 +                    v.scan(f.descriptor, f.attributes);
   3.114 +                }
   3.115 +                for (Method m : classfile.methods) {
   3.116 +                    v.scan(m.descriptor, m.attributes);
   3.117 +                    Exceptions_attribute e =
   3.118 +                        (Exceptions_attribute)m.attributes.get(Attribute.Exceptions);
   3.119 +                    if (e != null) {
   3.120 +                        v.addClasses(e.exception_index_table);
   3.121 +                    }
   3.122 +                }
   3.123 +            } catch (ConstantPoolException e) {
   3.124 +                throw new ClassFileError(e);
   3.125 +            }
   3.126 +
   3.127              return v.deps;
   3.128          }
   3.129      }
   3.130 @@ -558,9 +587,7 @@
   3.131              void scan(Descriptor d, Attributes attrs) {
   3.132                  try {
   3.133                      scan(new Signature(d.index).getType(constant_pool));
   3.134 -                    Signature_attribute sa = (Signature_attribute) attrs.get(Attribute.Signature);
   3.135 -                    if (sa != null)
   3.136 -                        scan(new Signature(sa.signature_index).getType(constant_pool));
   3.137 +                    scan(attrs);
   3.138                  } catch (ConstantPoolException e) {
   3.139                      throw new ClassFileError(e);
   3.140                  }
   3.141 @@ -574,6 +601,43 @@
   3.142                  t.accept(this, null);
   3.143              }
   3.144  
   3.145 +            void scan(Attributes attrs) {
   3.146 +                try {
   3.147 +                    Signature_attribute sa = (Signature_attribute)attrs.get(Attribute.Signature);
   3.148 +                    if (sa != null)
   3.149 +                        scan(sa.getParsedSignature().getType(constant_pool));
   3.150 +
   3.151 +                    scan((RuntimeVisibleAnnotations_attribute)
   3.152 +                            attrs.get(Attribute.RuntimeVisibleAnnotations));
   3.153 +                    scan((RuntimeVisibleParameterAnnotations_attribute)
   3.154 +                            attrs.get(Attribute.RuntimeVisibleParameterAnnotations));
   3.155 +                } catch (ConstantPoolException e) {
   3.156 +                    throw new ClassFileError(e);
   3.157 +                }
   3.158 +            }
   3.159 +
   3.160 +            private void scan(RuntimeAnnotations_attribute attr) throws ConstantPoolException {
   3.161 +                if (attr == null) {
   3.162 +                    return;
   3.163 +                }
   3.164 +                for (int i = 0; i < attr.annotations.length; i++) {
   3.165 +                    int index = attr.annotations[i].type_index;
   3.166 +                    scan(new Signature(index).getType(constant_pool));
   3.167 +                }
   3.168 +            }
   3.169 +
   3.170 +            private void scan(RuntimeParameterAnnotations_attribute attr) throws ConstantPoolException {
   3.171 +                if (attr == null) {
   3.172 +                    return;
   3.173 +                }
   3.174 +                for (int param = 0; param < attr.parameter_annotations.length; param++) {
   3.175 +                    for (int i = 0; i < attr.parameter_annotations[param].length; i++) {
   3.176 +                        int index = attr.parameter_annotations[param][i].type_index;
   3.177 +                        scan(new Signature(index).getType(constant_pool));
   3.178 +                    }
   3.179 +                }
   3.180 +            }
   3.181 +
   3.182              void addClass(int index) throws ConstantPoolException {
   3.183                  if (index != 0) {
   3.184                      String name = constant_pool.getClassInfo(index).getBaseName();
   3.185 @@ -698,6 +762,7 @@
   3.186                  findDependencies(type.paramTypes);
   3.187                  findDependencies(type.returnType);
   3.188                  findDependencies(type.throwsTypes);
   3.189 +                findDependencies(type.typeParamTypes);
   3.190                  return null;
   3.191              }
   3.192  
   3.193 @@ -709,7 +774,7 @@
   3.194  
   3.195              public Void visitClassType(ClassType type, Void p) {
   3.196                  findDependencies(type.outerType);
   3.197 -                addDependency(type.name);
   3.198 +                addDependency(type.getBinaryName());
   3.199                  findDependencies(type.typeArgs);
   3.200                  return null;
   3.201              }
     4.1 --- a/src/share/classes/com/sun/tools/classfile/Dependency.java	Tue Dec 25 17:23:59 2012 -0800
     4.2 +++ b/src/share/classes/com/sun/tools/classfile/Dependency.java	Fri Dec 28 22:25:21 2012 -0800
     4.3 @@ -71,7 +71,19 @@
     4.4           * dependency analysis.
     4.5           * @return the name of the class containing the location.
     4.6           */
     4.7 +        String getName();
     4.8 +
     4.9 +        /**
    4.10 +         * Get the fully-qualified name of the class containing the location.
    4.11 +         * @return the fully-qualified name of the class containing the location.
    4.12 +         */
    4.13          String getClassName();
    4.14 +
    4.15 +        /**
    4.16 +         * Get the package name of the class containing the location.
    4.17 +         * @return the package name of the class containing the location.
    4.18 +         */
    4.19 +        String getPackageName();
    4.20      }
    4.21  
    4.22  
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/share/classes/com/sun/tools/jdeps/Archive.java	Fri Dec 28 22:25:21 2012 -0800
     5.3 @@ -0,0 +1,173 @@
     5.4 +/*
     5.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
     5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 + *
     5.8 + * This code is free software; you can redistribute it and/or modify it
     5.9 + * under the terms of the GNU General Public License version 2 only, as
    5.10 + * published by the Free Software Foundation.  Oracle designates this
    5.11 + * particular file as subject to the "Classpath" exception as provided
    5.12 + * by Oracle in the LICENSE file that accompanied this code.
    5.13 + *
    5.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    5.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.17 + * version 2 for more details (a copy is included in the LICENSE file that
    5.18 + * accompanied this code).
    5.19 + *
    5.20 + * You should have received a copy of the GNU General Public License version
    5.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    5.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.23 + *
    5.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.25 + * or visit www.oracle.com if you need additional information or have any
    5.26 + * questions.
    5.27 + */
    5.28 +package com.sun.tools.jdeps;
    5.29 +
    5.30 +import com.sun.tools.classfile.Dependency;
    5.31 +import com.sun.tools.classfile.Dependency.Location;
    5.32 +import java.io.File;
    5.33 +import java.util.Comparator;
    5.34 +import java.util.HashMap;
    5.35 +import java.util.HashSet;
    5.36 +import java.util.Map;
    5.37 +import java.util.Set;
    5.38 +import java.util.SortedMap;
    5.39 +import java.util.SortedSet;
    5.40 +import java.util.TreeMap;
    5.41 +import java.util.TreeSet;
    5.42 +
    5.43 +/**
    5.44 + * Represents the source of the class files.
    5.45 + */
    5.46 +public class Archive {
    5.47 +    private static Map<String,Archive> archiveForClass = new HashMap<String,Archive>();
    5.48 +    public static Archive find(Location loc) {
    5.49 +        return archiveForClass.get(loc.getName());
    5.50 +    }
    5.51 +
    5.52 +    private final File file;
    5.53 +    private final String filename;
    5.54 +    private final DependencyRecorder recorder;
    5.55 +    private final ClassFileReader reader;
    5.56 +    public Archive(String name) {
    5.57 +        this.file = null;
    5.58 +        this.filename = name;
    5.59 +        this.recorder = new DependencyRecorder();
    5.60 +        this.reader = null;
    5.61 +    }
    5.62 +
    5.63 +    public Archive(File f, ClassFileReader reader) {
    5.64 +        this.file = f;
    5.65 +        this.filename = f.getName();
    5.66 +        this.recorder = new DependencyRecorder();
    5.67 +        this.reader = reader;
    5.68 +    }
    5.69 +
    5.70 +    public ClassFileReader reader() {
    5.71 +        return reader;
    5.72 +    }
    5.73 +
    5.74 +    public String getFileName() {
    5.75 +        return filename;
    5.76 +    }
    5.77 +
    5.78 +    public void addClass(String classFileName) {
    5.79 +        Archive a = archiveForClass.get(classFileName);
    5.80 +        assert(a == null || a == this); // ## issue warning?
    5.81 +        if (!archiveForClass.containsKey(classFileName)) {
    5.82 +            archiveForClass.put(classFileName, this);
    5.83 +        }
    5.84 +    }
    5.85 +
    5.86 +    public void addDependency(Dependency d) {
    5.87 +        recorder.addDependency(d);
    5.88 +    }
    5.89 +
    5.90 +    /**
    5.91 +     * Returns a sorted map of a class to its dependencies.
    5.92 +     */
    5.93 +    public SortedMap<Location, SortedSet<Location>> getDependencies() {
    5.94 +        DependencyRecorder.Filter filter = new DependencyRecorder.Filter() {
    5.95 +            public boolean accept(Location origin, Location target) {
    5.96 +                 return (archiveForClass.get(origin.getName()) !=
    5.97 +                            archiveForClass.get(target.getName()));
    5.98 +        }};
    5.99 +
   5.100 +        SortedMap<Location, SortedSet<Location>> result =
   5.101 +            new TreeMap<Location, SortedSet<Location>>(locationComparator);
   5.102 +        for (Map.Entry<Location, Set<Location>> e : recorder.dependencies().entrySet()) {
   5.103 +            Location o = e.getKey();
   5.104 +            for (Location t : e.getValue()) {
   5.105 +                if (filter.accept(o, t)) {
   5.106 +                    SortedSet<Location> odeps = result.get(o);
   5.107 +                    if (odeps == null) {
   5.108 +                        odeps = new TreeSet<Location>(locationComparator);
   5.109 +                        result.put(o, odeps);
   5.110 +                    }
   5.111 +                    odeps.add(t);
   5.112 +                }
   5.113 +            }
   5.114 +        }
   5.115 +        return result;
   5.116 +    }
   5.117 +
   5.118 +    /**
   5.119 +     * Returns the set of archives this archive requires.
   5.120 +     */
   5.121 +    public Set<Archive> getRequiredArchives() {
   5.122 +        SortedSet<Archive> deps = new TreeSet<Archive>(new Comparator<Archive>() {
   5.123 +            public int compare(Archive a1, Archive a2) {
   5.124 +                return a1.toString().compareTo(a2.toString());
   5.125 +            }
   5.126 +        });
   5.127 +
   5.128 +        for (Map.Entry<Location, Set<Location>> e : recorder.dependencies().entrySet()) {
   5.129 +            Location o = e.getKey();
   5.130 +            Archive origin = Archive.find(o);
   5.131 +            for (Location t : e.getValue()) {
   5.132 +                Archive target = Archive.find(t);
   5.133 +                assert(origin != null && target != null);
   5.134 +                if (origin != target) {
   5.135 +                    if (!deps.contains(target)) {
   5.136 +                        deps.add(target);
   5.137 +                    }
   5.138 +                }
   5.139 +            }
   5.140 +        }
   5.141 +        return deps;
   5.142 +    }
   5.143 +
   5.144 +    public String toString() {
   5.145 +        return file != null ? file.getPath() : filename;
   5.146 +    }
   5.147 +
   5.148 +    private static class DependencyRecorder {
   5.149 +        static interface Filter {
   5.150 +            boolean accept(Location origin, Location target);
   5.151 +        }
   5.152 +
   5.153 +        public void addDependency(Dependency d) {
   5.154 +            Set<Location> odeps = map.get(d.getOrigin());
   5.155 +            if (odeps == null) {
   5.156 +                odeps = new HashSet<Location>();
   5.157 +                map.put(d.getOrigin(), odeps);
   5.158 +            }
   5.159 +            odeps.add(d.getTarget());
   5.160 +        }
   5.161 +
   5.162 +        public Map<Location, Set<Location>> dependencies() {
   5.163 +            return map;
   5.164 +        }
   5.165 +
   5.166 +        private final Map<Location, Set<Location>> map =
   5.167 +            new HashMap<Location, Set<Location>>();
   5.168 +    }
   5.169 +
   5.170 +    private static Comparator<Location> locationComparator =
   5.171 +        new Comparator<Location>() {
   5.172 +            public int compare(Location o1, Location o2) {
   5.173 +                return o1.toString().compareTo(o2.toString());
   5.174 +            }
   5.175 +        };
   5.176 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Fri Dec 28 22:25:21 2012 -0800
     6.3 @@ -0,0 +1,326 @@
     6.4 +/*
     6.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
     6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     6.7 + *
     6.8 + * This code is free software; you can redistribute it and/or modify it
     6.9 + * under the terms of the GNU General Public License version 2 only, as
    6.10 + * published by the Free Software Foundation.  Oracle designates this
    6.11 + * particular file as subject to the "Classpath" exception as provided
    6.12 + * by Oracle in the LICENSE file that accompanied this code.
    6.13 + *
    6.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    6.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    6.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    6.17 + * version 2 for more details (a copy is included in the LICENSE file that
    6.18 + * accompanied this code).
    6.19 + *
    6.20 + * You should have received a copy of the GNU General Public License version
    6.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    6.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    6.23 + *
    6.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    6.25 + * or visit www.oracle.com if you need additional information or have any
    6.26 + * questions.
    6.27 + */
    6.28 +package com.sun.tools.jdeps;
    6.29 +
    6.30 +import com.sun.tools.classfile.ClassFile;
    6.31 +import com.sun.tools.classfile.ConstantPoolException;
    6.32 +import com.sun.tools.classfile.Dependencies.ClassFileError;
    6.33 +import java.io.*;
    6.34 +import java.nio.file.FileVisitResult;
    6.35 +import java.nio.file.Files;
    6.36 +import java.nio.file.Path;
    6.37 +import java.nio.file.SimpleFileVisitor;
    6.38 +import java.nio.file.attribute.BasicFileAttributes;
    6.39 +import java.util.*;
    6.40 +import java.util.jar.JarEntry;
    6.41 +import java.util.jar.JarFile;
    6.42 +
    6.43 +/**
    6.44 + * ClassFileReader reads ClassFile(s) of a given path that can be
    6.45 + * a .class file, a directory, or a JAR file.
    6.46 + */
    6.47 +public class ClassFileReader {
    6.48 +    /**
    6.49 +     * Returns a ClassFileReader instance of a given path.
    6.50 +     */
    6.51 +    public static ClassFileReader newInstance(File path) throws IOException {
    6.52 +        if (!path.exists()) {
    6.53 +            throw new FileNotFoundException(path.getAbsolutePath());
    6.54 +        }
    6.55 +
    6.56 +        if (path.isDirectory()) {
    6.57 +            return new DirectoryReader(path.toPath());
    6.58 +        } else if (path.getName().endsWith(".jar")) {
    6.59 +            return new JarFileReader(path.toPath());
    6.60 +        } else {
    6.61 +            return new ClassFileReader(path.toPath());
    6.62 +        }
    6.63 +    }
    6.64 +
    6.65 +    protected final Path path;
    6.66 +    protected final String baseFileName;
    6.67 +    private ClassFileReader(Path path) {
    6.68 +        this.path = path;
    6.69 +        this.baseFileName = path.getFileName() != null
    6.70 +                                ? path.getFileName().toString()
    6.71 +                                : path.toString();
    6.72 +    }
    6.73 +
    6.74 +    public String getFileName() {
    6.75 +        return baseFileName;
    6.76 +    }
    6.77 +
    6.78 +    /**
    6.79 +     * Returns the ClassFile matching the given binary name
    6.80 +     * or a fully-qualified class name.
    6.81 +     */
    6.82 +    public ClassFile getClassFile(String name) throws IOException {
    6.83 +        if (name.indexOf('.') > 0) {
    6.84 +            int i = name.lastIndexOf('.');
    6.85 +            String pathname = name.replace('.', File.separatorChar) + ".class";
    6.86 +            if (baseFileName.equals(pathname) ||
    6.87 +                    baseFileName.equals(pathname.substring(0, i) + "$" +
    6.88 +                                        pathname.substring(i+1, pathname.length()))) {
    6.89 +                return readClassFile(path);
    6.90 +            }
    6.91 +        } else {
    6.92 +            if (baseFileName.equals(name.replace('/', File.separatorChar) + ".class")) {
    6.93 +                return readClassFile(path);
    6.94 +            }
    6.95 +        }
    6.96 +        return null;
    6.97 +    }
    6.98 +
    6.99 +    public Iterable<ClassFile> getClassFiles() throws IOException {
   6.100 +        return new Iterable<ClassFile>() {
   6.101 +            public Iterator<ClassFile> iterator() {
   6.102 +                return new FileIterator();
   6.103 +            }
   6.104 +        };
   6.105 +    }
   6.106 +
   6.107 +    protected ClassFile readClassFile(Path p) throws IOException {
   6.108 +        InputStream is = null;
   6.109 +        try {
   6.110 +            is = Files.newInputStream(p);
   6.111 +            return ClassFile.read(is);
   6.112 +        } catch (ConstantPoolException e) {
   6.113 +            throw new ClassFileError(e);
   6.114 +        } finally {
   6.115 +            if (is != null) {
   6.116 +                is.close();
   6.117 +            }
   6.118 +        }
   6.119 +    }
   6.120 +
   6.121 +    class FileIterator implements Iterator<ClassFile> {
   6.122 +        int count;
   6.123 +        FileIterator() {
   6.124 +            this.count = 0;
   6.125 +        }
   6.126 +        public boolean hasNext() {
   6.127 +            return count == 0 && baseFileName.endsWith(".class");
   6.128 +        }
   6.129 +
   6.130 +        public ClassFile next() {
   6.131 +            if (!hasNext()) {
   6.132 +                throw new NoSuchElementException();
   6.133 +            }
   6.134 +            try {
   6.135 +                ClassFile cf = readClassFile(path);
   6.136 +                count++;
   6.137 +                return cf;
   6.138 +            } catch (IOException e) {
   6.139 +                throw new ClassFileError(e);
   6.140 +            }
   6.141 +        }
   6.142 +
   6.143 +        public void remove() {
   6.144 +            throw new UnsupportedOperationException("Not supported yet.");
   6.145 +        }
   6.146 +    }
   6.147 +
   6.148 +    public String toString() {
   6.149 +        return path.toString();
   6.150 +    }
   6.151 +
   6.152 +    private static class DirectoryReader extends ClassFileReader {
   6.153 +        DirectoryReader(Path path) throws IOException {
   6.154 +            super(path);
   6.155 +        }
   6.156 +
   6.157 +        public ClassFile getClassFile(String name) throws IOException {
   6.158 +            if (name.indexOf('.') > 0) {
   6.159 +                int i = name.lastIndexOf('.');
   6.160 +                String pathname = name.replace('.', File.separatorChar) + ".class";
   6.161 +                Path p = path.resolve(pathname);
   6.162 +                if (!p.toFile().exists()) {
   6.163 +                    p = path.resolve(pathname.substring(0, i) + "$" +
   6.164 +                                     pathname.substring(i+1, pathname.length()));
   6.165 +                }
   6.166 +                if (p.toFile().exists()) {
   6.167 +                    return readClassFile(p);
   6.168 +                }
   6.169 +            } else {
   6.170 +                Path p = path.resolve(name + ".class");
   6.171 +                if (p.toFile().exists()) {
   6.172 +                    return readClassFile(p);
   6.173 +                }
   6.174 +            }
   6.175 +            return null;
   6.176 +        }
   6.177 +
   6.178 +        public Iterable<ClassFile> getClassFiles() throws IOException {
   6.179 +            final Iterator<ClassFile> iter = new DirectoryIterator();
   6.180 +            return new Iterable<ClassFile>() {
   6.181 +                public Iterator<ClassFile> iterator() {
   6.182 +                    return iter;
   6.183 +                }
   6.184 +            };
   6.185 +        }
   6.186 +
   6.187 +        private List<Path> walkTree(Path dir) throws IOException {
   6.188 +            final List<Path> files = new ArrayList<Path>();
   6.189 +            Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
   6.190 +                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
   6.191 +                        throws IOException {
   6.192 +                    if (file.toFile().getName().endsWith(".class")) {
   6.193 +                        files.add(file);
   6.194 +                    }
   6.195 +                    return FileVisitResult.CONTINUE;
   6.196 +                }
   6.197 +            });
   6.198 +            return files;
   6.199 +        }
   6.200 +
   6.201 +        class DirectoryIterator implements Iterator<ClassFile> {
   6.202 +            private List<Path> entries;
   6.203 +            private int index = 0;
   6.204 +            DirectoryIterator() throws IOException {
   6.205 +                entries = walkTree(path);
   6.206 +                index = 0;
   6.207 +            }
   6.208 +
   6.209 +            public boolean hasNext() {
   6.210 +                return index != entries.size();
   6.211 +            }
   6.212 +
   6.213 +            public ClassFile next() {
   6.214 +                if (!hasNext()) {
   6.215 +                    throw new NoSuchElementException();
   6.216 +                }
   6.217 +                Path path = entries.get(index++);
   6.218 +                try {
   6.219 +                    return readClassFile(path);
   6.220 +                } catch (IOException e) {
   6.221 +                    throw new ClassFileError(e);
   6.222 +                }
   6.223 +            }
   6.224 +
   6.225 +            public void remove() {
   6.226 +                throw new UnsupportedOperationException("Not supported yet.");
   6.227 +            }
   6.228 +        }
   6.229 +    }
   6.230 +
   6.231 +    private static class JarFileReader extends ClassFileReader {
   6.232 +        final JarFile jarfile;
   6.233 +        JarFileReader(Path path) throws IOException {
   6.234 +            super(path);
   6.235 +            this.jarfile = new JarFile(path.toFile());
   6.236 +        }
   6.237 +
   6.238 +        public ClassFile getClassFile(String name) throws IOException {
   6.239 +            if (name.indexOf('.') > 0) {
   6.240 +                int i = name.lastIndexOf('.');
   6.241 +                String entryName = name.replace('.', '/') + ".class";
   6.242 +                JarEntry e = jarfile.getJarEntry(entryName);
   6.243 +                if (e == null) {
   6.244 +                    e = jarfile.getJarEntry(entryName.substring(0, i) + "$"
   6.245 +                            + entryName.substring(i + 1, entryName.length()));
   6.246 +                }
   6.247 +                if (e != null) {
   6.248 +                    return readClassFile(e);
   6.249 +                }
   6.250 +            } else {
   6.251 +                JarEntry e = jarfile.getJarEntry(name + ".class");
   6.252 +                if (e != null) {
   6.253 +                    return readClassFile(e);
   6.254 +                }
   6.255 +            }
   6.256 +            return null;
   6.257 +        }
   6.258 +
   6.259 +        private ClassFile readClassFile(JarEntry e) throws IOException {
   6.260 +            InputStream is = null;
   6.261 +            try {
   6.262 +                is = jarfile.getInputStream(e);
   6.263 +                return ClassFile.read(is);
   6.264 +            } catch (ConstantPoolException ex) {
   6.265 +                throw new ClassFileError(ex);
   6.266 +            } finally {
   6.267 +                if (is != null)
   6.268 +                    is.close();
   6.269 +            }
   6.270 +        }
   6.271 +
   6.272 +        public Iterable<ClassFile> getClassFiles() throws IOException {
   6.273 +            final Iterator<ClassFile> iter = new JarFileIterator();
   6.274 +            return new Iterable<ClassFile>() {
   6.275 +                public Iterator<ClassFile> iterator() {
   6.276 +                    return iter;
   6.277 +                }
   6.278 +            };
   6.279 +        }
   6.280 +
   6.281 +        class JarFileIterator implements Iterator<ClassFile> {
   6.282 +            private Enumeration<JarEntry> entries;
   6.283 +            private JarEntry nextEntry;
   6.284 +            JarFileIterator() {
   6.285 +                this.entries = jarfile.entries();
   6.286 +                while (entries.hasMoreElements()) {
   6.287 +                    JarEntry e = entries.nextElement();
   6.288 +                    String name = e.getName();
   6.289 +                    if (name.endsWith(".class")) {
   6.290 +                        this.nextEntry = e;
   6.291 +                        break;
   6.292 +                    }
   6.293 +                }
   6.294 +            }
   6.295 +
   6.296 +            public boolean hasNext() {
   6.297 +                return nextEntry != null;
   6.298 +            }
   6.299 +
   6.300 +            public ClassFile next() {
   6.301 +                if (!hasNext()) {
   6.302 +                    throw new NoSuchElementException();
   6.303 +                }
   6.304 +
   6.305 +                ClassFile cf;
   6.306 +                try {
   6.307 +                    cf = readClassFile(nextEntry);
   6.308 +                } catch (IOException ex) {
   6.309 +                    throw new ClassFileError(ex);
   6.310 +                }
   6.311 +                JarEntry entry = nextEntry;
   6.312 +                nextEntry = null;
   6.313 +                while (entries.hasMoreElements()) {
   6.314 +                    JarEntry e = entries.nextElement();
   6.315 +                    String name = e.getName();
   6.316 +                    if (name.endsWith(".class")) {
   6.317 +                        nextEntry = e;
   6.318 +                        break;
   6.319 +                    }
   6.320 +                }
   6.321 +                return cf;
   6.322 +            }
   6.323 +
   6.324 +            public void remove() {
   6.325 +                throw new UnsupportedOperationException("Not supported yet.");
   6.326 +            }
   6.327 +        }
   6.328 +    }
   6.329 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/share/classes/com/sun/tools/jdeps/JdepsTask.java	Fri Dec 28 22:25:21 2012 -0800
     7.3 @@ -0,0 +1,650 @@
     7.4 +/*
     7.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
     7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     7.7 + *
     7.8 + * This code is free software; you can redistribute it and/or modify it
     7.9 + * under the terms of the GNU General Public License version 2 only, as
    7.10 + * published by the Free Software Foundation.  Oracle designates this
    7.11 + * particular file as subject to the "Classpath" exception as provided
    7.12 + * by Oracle in the LICENSE file that accompanied this code.
    7.13 + *
    7.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    7.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    7.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    7.17 + * version 2 for more details (a copy is included in the LICENSE file that
    7.18 + * accompanied this code).
    7.19 + *
    7.20 + * You should have received a copy of the GNU General Public License version
    7.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    7.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    7.23 + *
    7.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    7.25 + * or visit www.oracle.com if you need additional information or have any
    7.26 + * questions.
    7.27 + */
    7.28 +package com.sun.tools.jdeps;
    7.29 +
    7.30 +import com.sun.tools.classfile.ClassFile;
    7.31 +import com.sun.tools.classfile.ConstantPoolException;
    7.32 +import com.sun.tools.classfile.Dependencies;
    7.33 +import com.sun.tools.classfile.Dependencies.ClassFileError;
    7.34 +import com.sun.tools.classfile.Dependency;
    7.35 +import com.sun.tools.classfile.Dependency.Location;
    7.36 +import java.io.*;
    7.37 +import java.text.MessageFormat;
    7.38 +import java.util.*;
    7.39 +import java.util.regex.Pattern;
    7.40 +
    7.41 +/**
    7.42 + * Implementation for the jdeps tool for static class dependency analysis.
    7.43 + */
    7.44 +class JdepsTask {
    7.45 +    class BadArgs extends Exception {
    7.46 +        static final long serialVersionUID = 8765093759964640721L;
    7.47 +        BadArgs(String key, Object... args) {
    7.48 +            super(JdepsTask.this.getMessage(key, args));
    7.49 +            this.key = key;
    7.50 +            this.args = args;
    7.51 +        }
    7.52 +
    7.53 +        BadArgs showUsage(boolean b) {
    7.54 +            showUsage = b;
    7.55 +            return this;
    7.56 +        }
    7.57 +        final String key;
    7.58 +        final Object[] args;
    7.59 +        boolean showUsage;
    7.60 +    }
    7.61 +
    7.62 +    static abstract class Option {
    7.63 +        Option(boolean hasArg, String... aliases) {
    7.64 +            this.hasArg = hasArg;
    7.65 +            this.aliases = aliases;
    7.66 +        }
    7.67 +
    7.68 +        boolean isHidden() {
    7.69 +            return false;
    7.70 +        }
    7.71 +
    7.72 +        boolean matches(String opt) {
    7.73 +            for (String a : aliases) {
    7.74 +                if (a.equals(opt)) {
    7.75 +                    return true;
    7.76 +                } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
    7.77 +                    return true;
    7.78 +                }
    7.79 +            }
    7.80 +            return false;
    7.81 +        }
    7.82 +
    7.83 +        boolean ignoreRest() {
    7.84 +            return false;
    7.85 +        }
    7.86 +
    7.87 +        abstract void process(JdepsTask task, String opt, String arg) throws BadArgs;
    7.88 +        final boolean hasArg;
    7.89 +        final String[] aliases;
    7.90 +    }
    7.91 +
    7.92 +    static abstract class HiddenOption extends Option {
    7.93 +        HiddenOption(boolean hasArg, String... aliases) {
    7.94 +            super(hasArg, aliases);
    7.95 +        }
    7.96 +
    7.97 +        boolean isHidden() {
    7.98 +            return true;
    7.99 +        }
   7.100 +    }
   7.101 +
   7.102 +    static Option[] recognizedOptions = {
   7.103 +        new Option(false, "-h", "-?", "--help") {
   7.104 +            void process(JdepsTask task, String opt, String arg) {
   7.105 +                task.options.help = true;
   7.106 +            }
   7.107 +        },
   7.108 +        new Option(false, "-s", "--summary") {
   7.109 +            void process(JdepsTask task, String opt, String arg) {
   7.110 +                task.options.showSummary = true;
   7.111 +                task.options.verbose = Options.Verbose.SUMMARY;
   7.112 +            }
   7.113 +        },
   7.114 +        new Option(false, "-v", "--verbose") {
   7.115 +            void process(JdepsTask task, String opt, String arg) {
   7.116 +                task.options.verbose = Options.Verbose.VERBOSE;
   7.117 +            }
   7.118 +        },
   7.119 +        new Option(true, "-V", "--verbose-level") {
   7.120 +            void process(JdepsTask task, String opt, String arg) throws BadArgs {
   7.121 +                switch (arg) {
   7.122 +                    case "package":
   7.123 +                        task.options.verbose = Options.Verbose.PACKAGE;
   7.124 +                        break;
   7.125 +                    case "class":
   7.126 +                        task.options.verbose = Options.Verbose.CLASS;
   7.127 +                        break;
   7.128 +                    default:
   7.129 +                        throw task.new BadArgs("err.invalid.arg.for.option", opt);
   7.130 +                }
   7.131 +            }
   7.132 +        },
   7.133 +        new Option(true, "-c", "--classpath") {
   7.134 +            void process(JdepsTask task, String opt, String arg) {
   7.135 +                task.options.classpath = arg;
   7.136 +            }
   7.137 +        },
   7.138 +        new Option(true, "-p", "--package") {
   7.139 +            void process(JdepsTask task, String opt, String arg) {
   7.140 +                task.options.packageNames.add(arg);
   7.141 +            }
   7.142 +        },
   7.143 +        new Option(true, "-e", "--regex") {
   7.144 +            void process(JdepsTask task, String opt, String arg) {
   7.145 +                task.options.regex = arg;
   7.146 +            }
   7.147 +        },
   7.148 +        new Option(false, "-P", "--profile") {
   7.149 +            void process(JdepsTask task, String opt, String arg) {
   7.150 +                task.options.showProfile = true;
   7.151 +            }
   7.152 +        },
   7.153 +        new Option(false, "-R", "--recursive") {
   7.154 +            void process(JdepsTask task, String opt, String arg) {
   7.155 +                task.options.depth = 0;
   7.156 +            }
   7.157 +        },
   7.158 +        new HiddenOption(true, "-d", "--depth") {
   7.159 +            void process(JdepsTask task, String opt, String arg) throws BadArgs {
   7.160 +                try {
   7.161 +                    task.options.depth = Integer.parseInt(arg);
   7.162 +                } catch (NumberFormatException e) {
   7.163 +                    throw task.new BadArgs("err.invalid.arg.for.option", opt);
   7.164 +                }
   7.165 +            }
   7.166 +        },
   7.167 +        new Option(false, "--version") {
   7.168 +            void process(JdepsTask task, String opt, String arg) {
   7.169 +                task.options.version = true;
   7.170 +            }
   7.171 +        },
   7.172 +        new HiddenOption(false, "--fullversion") {
   7.173 +            void process(JdepsTask task, String opt, String arg) {
   7.174 +                task.options.fullVersion = true;
   7.175 +            }
   7.176 +        },
   7.177 +
   7.178 +    };
   7.179 +
   7.180 +    private static final String PROGNAME = "jdeps";
   7.181 +    private final Options options = new Options();
   7.182 +    private final List<String> classes = new ArrayList<String>();
   7.183 +
   7.184 +    private PrintWriter log;
   7.185 +    void setLog(PrintWriter out) {
   7.186 +        log = out;
   7.187 +    }
   7.188 +
   7.189 +    /**
   7.190 +     * Result codes.
   7.191 +     */
   7.192 +    static final int EXIT_OK = 0, // Completed with no errors.
   7.193 +                     EXIT_ERROR = 1, // Completed but reported errors.
   7.194 +                     EXIT_CMDERR = 2, // Bad command-line arguments
   7.195 +                     EXIT_SYSERR = 3, // System error or resource exhaustion.
   7.196 +                     EXIT_ABNORMAL = 4;// terminated abnormally
   7.197 +
   7.198 +    int run(String[] args) {
   7.199 +        if (log == null) {
   7.200 +            log = new PrintWriter(System.out);
   7.201 +        }
   7.202 +        try {
   7.203 +            handleOptions(args);
   7.204 +            if (options.help) {
   7.205 +                showHelp();
   7.206 +            }
   7.207 +            if (options.version || options.fullVersion) {
   7.208 +                showVersion(options.fullVersion);
   7.209 +            }
   7.210 +            if (classes.isEmpty() && !options.wildcard) {
   7.211 +                if (options.help || options.version || options.fullVersion) {
   7.212 +                    return EXIT_OK;
   7.213 +                } else {
   7.214 +                    showHelp();
   7.215 +                    return EXIT_CMDERR;
   7.216 +                }
   7.217 +            }
   7.218 +            if (options.regex != null && options.packageNames.size() > 0) {
   7.219 +                showHelp();
   7.220 +                return EXIT_CMDERR;
   7.221 +            }
   7.222 +            if (options.showSummary && options.verbose != Options.Verbose.SUMMARY) {
   7.223 +                showHelp();
   7.224 +                return EXIT_CMDERR;
   7.225 +            }
   7.226 +            boolean ok = run();
   7.227 +            return ok ? EXIT_OK : EXIT_ERROR;
   7.228 +        } catch (BadArgs e) {
   7.229 +            reportError(e.key, e.args);
   7.230 +            if (e.showUsage) {
   7.231 +                log.println(getMessage("main.usage.summary", PROGNAME));
   7.232 +            }
   7.233 +            return EXIT_CMDERR;
   7.234 +        } catch (IOException e) {
   7.235 +            return EXIT_ABNORMAL;
   7.236 +        } finally {
   7.237 +            log.flush();
   7.238 +        }
   7.239 +    }
   7.240 +
   7.241 +    private final List<Archive> sourceLocations = new ArrayList<Archive>();
   7.242 +    private final Archive NOT_FOUND = new Archive(getMessage("artifact.not.found"));
   7.243 +    private boolean run() throws IOException {
   7.244 +        findDependencies();
   7.245 +        switch (options.verbose) {
   7.246 +            case VERBOSE:
   7.247 +            case CLASS:
   7.248 +                printClassDeps(log);
   7.249 +                break;
   7.250 +            case PACKAGE:
   7.251 +                printPackageDeps(log);
   7.252 +                break;
   7.253 +            case SUMMARY:
   7.254 +                for (Archive origin : sourceLocations) {
   7.255 +                    for (Archive target : origin.getRequiredArchives()) {
   7.256 +                        log.format("%-30s -> %s%n", origin, target);
   7.257 +                    }
   7.258 +                }
   7.259 +                break;
   7.260 +            default:
   7.261 +                throw new InternalError("Should not reach here");
   7.262 +        }
   7.263 +        return true;
   7.264 +    }
   7.265 +
   7.266 +    private boolean isValidClassName(String name) {
   7.267 +        if (!Character.isJavaIdentifierStart(name.charAt(0))) {
   7.268 +            return false;
   7.269 +        }
   7.270 +        for (int i=1; i < name.length(); i++) {
   7.271 +            char c = name.charAt(i);
   7.272 +            if (c != '.'  && !Character.isJavaIdentifierPart(c)) {
   7.273 +                return false;
   7.274 +            }
   7.275 +        }
   7.276 +        return true;
   7.277 +    }
   7.278 +
   7.279 +    private void findDependencies() throws IOException {
   7.280 +        Dependency.Finder finder = Dependencies.getClassDependencyFinder();
   7.281 +        Dependency.Filter filter;
   7.282 +        if (options.regex != null) {
   7.283 +            filter = Dependencies.getRegexFilter(Pattern.compile(options.regex));
   7.284 +        } else if (options.packageNames.size() > 0) {
   7.285 +            filter = Dependencies.getPackageFilter(options.packageNames, false);
   7.286 +        } else {
   7.287 +            filter = new Dependency.Filter() {
   7.288 +                public boolean accepts(Dependency dependency) {
   7.289 +                    return !dependency.getOrigin().equals(dependency.getTarget());
   7.290 +                }
   7.291 +            };
   7.292 +        }
   7.293 +
   7.294 +        List<Archive> archives = new ArrayList<Archive>();
   7.295 +        Deque<String> roots = new LinkedList<String>();
   7.296 +        for (String s : classes) {
   7.297 +            File f = new File(s);
   7.298 +            if (f.exists()) {
   7.299 +                archives.add(new Archive(f, ClassFileReader.newInstance(f)));
   7.300 +            } else {
   7.301 +                if (isValidClassName(s)) {
   7.302 +                    roots.add(s);
   7.303 +                } else {
   7.304 +                    warning("warn.invalid.arg", s);
   7.305 +                }
   7.306 +            }
   7.307 +        }
   7.308 +
   7.309 +        List<Archive> classpaths = new ArrayList<Archive>(); // for class file lookup
   7.310 +        if (options.wildcard) {
   7.311 +            // include all archives from classpath to the initial list
   7.312 +            archives.addAll(getClassPathArchives(options.classpath));
   7.313 +        } else {
   7.314 +            classpaths.addAll(getClassPathArchives(options.classpath));
   7.315 +        }
   7.316 +        classpaths.addAll(PlatformClassPath.getArchives());
   7.317 +
   7.318 +        // add all archives to the source locations for reporting
   7.319 +        sourceLocations.addAll(archives);
   7.320 +        sourceLocations.addAll(classpaths);
   7.321 +
   7.322 +        // Work queue of names of classfiles to be searched.
   7.323 +        // Entries will be unique, and for classes that do not yet have
   7.324 +        // dependencies in the results map.
   7.325 +        Deque<String> deque = new LinkedList<String>();
   7.326 +        Set<String> doneClasses = new HashSet<String>();
   7.327 +
   7.328 +        // get the immediate dependencies of the input files
   7.329 +        for (Archive a : archives) {
   7.330 +            for (ClassFile cf : a.reader().getClassFiles()) {
   7.331 +                String classFileName;
   7.332 +                try {
   7.333 +                    classFileName = cf.getName();
   7.334 +                } catch (ConstantPoolException e) {
   7.335 +                    throw new ClassFileError(e);
   7.336 +                }
   7.337 +                a.addClass(classFileName);
   7.338 +                if (!doneClasses.contains(classFileName)) {
   7.339 +                    doneClasses.add(classFileName);
   7.340 +                }
   7.341 +                for (Dependency d : finder.findDependencies(cf)) {
   7.342 +                    if (filter.accepts(d)) {
   7.343 +                        String cn = d.getTarget().getName();
   7.344 +                        if (!doneClasses.contains(cn) && !deque.contains(cn)) {
   7.345 +                            deque.add(cn);
   7.346 +                        }
   7.347 +                        a.addDependency(d);
   7.348 +                    }
   7.349 +                }
   7.350 +            }
   7.351 +        }
   7.352 +
   7.353 +        // add Archive for looking up classes from the classpath
   7.354 +        // for transitive dependency analysis
   7.355 +        Deque<String> unresolved = roots;
   7.356 +        int depth = options.depth > 0 ? options.depth : Integer.MAX_VALUE;
   7.357 +        do {
   7.358 +            String name;
   7.359 +            while ((name = unresolved.poll()) != null) {
   7.360 +                if (doneClasses.contains(name)) {
   7.361 +                    continue;
   7.362 +                }
   7.363 +                ClassFile cf = null;
   7.364 +                for (Archive a : classpaths) {
   7.365 +                    cf = a.reader().getClassFile(name);
   7.366 +                    if (cf != null) {
   7.367 +                        String classFileName;
   7.368 +                        try {
   7.369 +                            classFileName = cf.getName();
   7.370 +                        } catch (ConstantPoolException e) {
   7.371 +                            throw new ClassFileError(e);
   7.372 +                        }
   7.373 +                        a.addClass(classFileName);
   7.374 +                        if (!doneClasses.contains(classFileName)) {
   7.375 +                            // if name is a fully-qualified class name specified
   7.376 +                            // from command-line, this class might already be parsed
   7.377 +                            doneClasses.add(classFileName);
   7.378 +                            if (depth > 0) {
   7.379 +                                for (Dependency d : finder.findDependencies(cf)) {
   7.380 +                                    if (filter.accepts(d)) {
   7.381 +                                        String cn = d.getTarget().getName();
   7.382 +                                        if (!doneClasses.contains(cn) && !deque.contains(cn)) {
   7.383 +                                            deque.add(cn);
   7.384 +                                        }
   7.385 +                                        a.addDependency(d);
   7.386 +                                    }
   7.387 +                                }
   7.388 +                            }
   7.389 +                        }
   7.390 +                        break;
   7.391 +                    }
   7.392 +                }
   7.393 +                if (cf == null) {
   7.394 +                    NOT_FOUND.addClass(name);
   7.395 +                }
   7.396 +            }
   7.397 +            unresolved = deque;
   7.398 +            deque = new LinkedList<String>();
   7.399 +        } while (!unresolved.isEmpty() && depth-- > 0);
   7.400 +    }
   7.401 +
   7.402 +    private void printPackageDeps(PrintWriter out) {
   7.403 +        for (Archive source : sourceLocations) {
   7.404 +            SortedMap<Location, SortedSet<Location>> deps = source.getDependencies();
   7.405 +            if (deps.isEmpty())
   7.406 +                continue;
   7.407 +
   7.408 +            for (Archive target : source.getRequiredArchives()) {
   7.409 +                out.format("%s -> %s%n", source, target);
   7.410 +            }
   7.411 +
   7.412 +            Map<String, Archive> pkgs = new TreeMap<String, Archive>();
   7.413 +            SortedMap<String, Archive> targets = new TreeMap<String, Archive>();
   7.414 +            String pkg = "";
   7.415 +            for (Map.Entry<Location, SortedSet<Location>> e : deps.entrySet()) {
   7.416 +                String cn = e.getKey().getClassName();
   7.417 +                String p = packageOf(e.getKey());
   7.418 +                Archive origin = Archive.find(e.getKey());
   7.419 +                assert origin != null;
   7.420 +                if (!pkgs.containsKey(p)) {
   7.421 +                    pkgs.put(p, origin);
   7.422 +                } else if (pkgs.get(p) != origin) {
   7.423 +                    warning("warn.split.package", p, origin, pkgs.get(p));
   7.424 +                }
   7.425 +
   7.426 +                if (!p.equals(pkg)) {
   7.427 +                    printTargets(out, targets);
   7.428 +                    pkg = p;
   7.429 +                    targets.clear();
   7.430 +                    out.format("   %s (%s)%n", p, origin.getFileName());
   7.431 +                }
   7.432 +
   7.433 +                for (Location t : e.getValue()) {
   7.434 +                    p = packageOf(t);
   7.435 +                    Archive target = Archive.find(t);
   7.436 +                    if (!targets.containsKey(p)) {
   7.437 +                        targets.put(p, target);
   7.438 +                    }
   7.439 +                }
   7.440 +            }
   7.441 +            printTargets(out, targets);
   7.442 +            out.println();
   7.443 +        }
   7.444 +    }
   7.445 +
   7.446 +    private void printTargets(PrintWriter out, Map<String, Archive> targets) {
   7.447 +        for (Map.Entry<String, Archive> t : targets.entrySet()) {
   7.448 +            String pn = t.getKey();
   7.449 +            out.format("      -> %-40s %s%n", pn, getPackageInfo(pn, t.getValue()));
   7.450 +        }
   7.451 +    }
   7.452 +
   7.453 +    private String getPackageInfo(String pn, Archive source) {
   7.454 +        if (PlatformClassPath.contains(source)) {
   7.455 +            String name = PlatformClassPath.getProfileName(pn);
   7.456 +            if (name.isEmpty()) {
   7.457 +                return "JDK internal API (" + source.getFileName() + ")";
   7.458 +            }
   7.459 +            return options.showProfile ? name : "";
   7.460 +        }
   7.461 +        return source.getFileName();
   7.462 +    }
   7.463 +
   7.464 +    private static String packageOf(Location loc) {
   7.465 +        String pkg = loc.getPackageName();
   7.466 +        return pkg.isEmpty() ? "<unnamed>" : pkg;
   7.467 +    }
   7.468 +
   7.469 +    private void printClassDeps(PrintWriter out) {
   7.470 +        for (Archive source : sourceLocations) {
   7.471 +            SortedMap<Location, SortedSet<Location>> deps = source.getDependencies();
   7.472 +            if (deps.isEmpty())
   7.473 +                continue;
   7.474 +
   7.475 +            for (Archive target : source.getRequiredArchives()) {
   7.476 +                out.format("%s -> %s%n", source, target);
   7.477 +            }
   7.478 +            out.format("%s%n", source);
   7.479 +            for (Map.Entry<Location, SortedSet<Location>> e : deps.entrySet()) {
   7.480 +                String cn = e.getKey().getClassName();
   7.481 +                Archive origin = Archive.find(e.getKey());
   7.482 +                out.format("   %s (%s)%n", cn, origin.getFileName());
   7.483 +                for (Location t : e.getValue()) {
   7.484 +                    cn = t.getClassName();
   7.485 +                    Archive target = Archive.find(t);
   7.486 +                    out.format("      -> %-60s %s%n", cn, getPackageInfo(t.getPackageName(), target));
   7.487 +                }
   7.488 +            }
   7.489 +            out.println();
   7.490 +        }
   7.491 +    }
   7.492 +    public void handleOptions(String[] args) throws BadArgs {
   7.493 +        // process options
   7.494 +        for (int i=0; i < args.length; i++) {
   7.495 +            if (args[i].charAt(0) == '-') {
   7.496 +                String name = args[i];
   7.497 +                Option option = getOption(name);
   7.498 +                String param = null;
   7.499 +                if (option.hasArg) {
   7.500 +                    if (name.startsWith("--") && name.indexOf('=') > 0) {
   7.501 +                        param = name.substring(name.indexOf('=') + 1, name.length());
   7.502 +                    } else if (i + 1 < args.length) {
   7.503 +                        param = args[++i];
   7.504 +                    }
   7.505 +                    if (param == null || param.isEmpty() || param.charAt(0) == '-') {
   7.506 +                        throw new BadArgs("err.missing.arg", name).showUsage(true);
   7.507 +                    }
   7.508 +                }
   7.509 +                option.process(this, name, param);
   7.510 +                if (option.ignoreRest()) {
   7.511 +                    i = args.length;
   7.512 +                }
   7.513 +            } else {
   7.514 +                // process rest of the input arguments
   7.515 +                for (; i < args.length; i++) {
   7.516 +                    String name = args[i];
   7.517 +                    if (name.charAt(0) == '-') {
   7.518 +                        throw new BadArgs("err.option.after.class", name).showUsage(true);
   7.519 +                    }
   7.520 +                    if (name.equals("*") || name.equals("\"*\"")) {
   7.521 +                        options.wildcard = true;
   7.522 +                    } else {
   7.523 +                        classes.add(name);
   7.524 +                    }
   7.525 +                }
   7.526 +            }
   7.527 +        }
   7.528 +    }
   7.529 +
   7.530 +    private Option getOption(String name) throws BadArgs {
   7.531 +        for (Option o : recognizedOptions) {
   7.532 +            if (o.matches(name)) {
   7.533 +                return o;
   7.534 +            }
   7.535 +        }
   7.536 +        throw new BadArgs("err.unknown.option", name).showUsage(true);
   7.537 +    }
   7.538 +
   7.539 +    private void reportError(String key, Object... args) {
   7.540 +        log.println(getMessage("error.prefix") + " " + getMessage(key, args));
   7.541 +    }
   7.542 +
   7.543 +    private void warning(String key, Object... args) {
   7.544 +        log.println(getMessage("warn.prefix") + " " + getMessage(key, args));
   7.545 +    }
   7.546 +
   7.547 +    private void showHelp() {
   7.548 +        log.println(getMessage("main.usage", PROGNAME));
   7.549 +        for (Option o : recognizedOptions) {
   7.550 +            String name = o.aliases[0].substring(1); // there must always be at least one name
   7.551 +            name = name.charAt(0) == '-' ? name.substring(1) : name;
   7.552 +            if (o.isHidden() || name.equals("h")) {
   7.553 +                continue;
   7.554 +            }
   7.555 +            log.println(getMessage("main.opt." + name));
   7.556 +        }
   7.557 +    }
   7.558 +
   7.559 +    private void showVersion(boolean full) {
   7.560 +        log.println(version(full ? "full" : "release"));
   7.561 +    }
   7.562 +
   7.563 +    private String version(String key) {
   7.564 +        // key=version:  mm.nn.oo[-milestone]
   7.565 +        // key=full:     mm.mm.oo[-milestone]-build
   7.566 +        if (ResourceBundleHelper.versionRB == null) {
   7.567 +            return System.getProperty("java.version");
   7.568 +        }
   7.569 +        try {
   7.570 +            return ResourceBundleHelper.versionRB.getString(key);
   7.571 +        } catch (MissingResourceException e) {
   7.572 +            return getMessage("version.unknown", System.getProperty("java.version"));
   7.573 +        }
   7.574 +    }
   7.575 +
   7.576 +    public String getMessage(String key, Object... args) {
   7.577 +        try {
   7.578 +            return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args);
   7.579 +        } catch (MissingResourceException e) {
   7.580 +            throw new InternalError("Missing message: " + key);
   7.581 +        }
   7.582 +    }
   7.583 +
   7.584 +    private static class Options {
   7.585 +        enum Verbose {
   7.586 +            CLASS,
   7.587 +            PACKAGE,
   7.588 +            SUMMARY,
   7.589 +            VERBOSE
   7.590 +        };
   7.591 +
   7.592 +        boolean help;
   7.593 +        boolean version;
   7.594 +        boolean fullVersion;
   7.595 +        boolean showFlags;
   7.596 +        boolean showProfile;
   7.597 +        boolean showSummary;
   7.598 +        boolean wildcard;
   7.599 +        String regex;
   7.600 +        String classpath = "";
   7.601 +        int depth = 1;
   7.602 +        Verbose verbose = Verbose.PACKAGE;
   7.603 +        Set<String> packageNames = new HashSet<String>();
   7.604 +    }
   7.605 +
   7.606 +    private static class ResourceBundleHelper {
   7.607 +        static final ResourceBundle versionRB;
   7.608 +        static final ResourceBundle bundle;
   7.609 +
   7.610 +        static {
   7.611 +            Locale locale = Locale.getDefault();
   7.612 +            try {
   7.613 +                bundle = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdeps", locale);
   7.614 +            } catch (MissingResourceException e) {
   7.615 +                throw new InternalError("Cannot find jdeps resource bundle for locale " + locale);
   7.616 +            }
   7.617 +            try {
   7.618 +                versionRB = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.version");
   7.619 +            } catch (MissingResourceException e) {
   7.620 +                throw new InternalError("version.resource.missing");
   7.621 +            }
   7.622 +        }
   7.623 +    }
   7.624 +
   7.625 +    private List<Archive> getArchives(List<String> filenames) throws IOException {
   7.626 +        List<Archive> result = new ArrayList<Archive>();
   7.627 +        for (String s : filenames) {
   7.628 +            File f = new File(s);
   7.629 +            if (f.exists()) {
   7.630 +                result.add(new Archive(f, ClassFileReader.newInstance(f)));
   7.631 +            } else {
   7.632 +                warning("warn.file.not.exist", s);
   7.633 +            }
   7.634 +        }
   7.635 +        return result;
   7.636 +    }
   7.637 +
   7.638 +    private List<Archive> getClassPathArchives(String paths) throws IOException {
   7.639 +        List<Archive> result = new ArrayList<Archive>();
   7.640 +        if (paths.isEmpty()) {
   7.641 +            return result;
   7.642 +        }
   7.643 +        for (String p : paths.split(File.pathSeparator)) {
   7.644 +            if (p.length() > 0) {
   7.645 +                File f = new File(p);
   7.646 +                if (f.exists()) {
   7.647 +                    result.add(new Archive(f, ClassFileReader.newInstance(f)));
   7.648 +                }
   7.649 +            }
   7.650 +        }
   7.651 +        return result;
   7.652 +    }
   7.653 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/share/classes/com/sun/tools/jdeps/Main.java	Fri Dec 28 22:25:21 2012 -0800
     8.3 @@ -0,0 +1,66 @@
     8.4 +/*
     8.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
     8.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     8.7 + *
     8.8 + * This code is free software; you can redistribute it and/or modify it
     8.9 + * under the terms of the GNU General Public License version 2 only, as
    8.10 + * published by the Free Software Foundation.  Oracle designates this
    8.11 + * particular file as subject to the "Classpath" exception as provided
    8.12 + * by Oracle in the LICENSE file that accompanied this code.
    8.13 + *
    8.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    8.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    8.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    8.17 + * version 2 for more details (a copy is included in the LICENSE file that
    8.18 + * accompanied this code).
    8.19 + *
    8.20 + * You should have received a copy of the GNU General Public License version
    8.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    8.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    8.23 + *
    8.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    8.25 + * or visit www.oracle.com if you need additional information or have any
    8.26 + * questions.
    8.27 + */
    8.28 +
    8.29 +package com.sun.tools.jdeps;
    8.30 +
    8.31 +import java.io.*;
    8.32 +
    8.33 +/**
    8.34 + *
    8.35 + * Usage:
    8.36 + *    jdeps [options] files ...
    8.37 + * where options include:
    8.38 + *    -p package-name   restrict analysis to classes in this package
    8.39 + *                      (may be given multiple times)
    8.40 + *    -e regex          restrict analysis to packages matching pattern
    8.41 + *                      (-p and -e are exclusive)
    8.42 + *    -v                show class-level dependencies
    8.43 + *                      default: package-level dependencies
    8.44 + *    -r --recursive    transitive dependencies analysis
    8.45 + *    -classpath paths  Classpath to locate class files
    8.46 + *    -all              process all class files in the given classpath
    8.47 + */
    8.48 +public class Main {
    8.49 +    public static void main(String... args) throws Exception {
    8.50 +        JdepsTask t = new JdepsTask();
    8.51 +        int rc = t.run(args);
    8.52 +        System.exit(rc);
    8.53 +    }
    8.54 +
    8.55 +
    8.56 +    /**
    8.57 +     * Entry point that does <i>not</i> call System.exit.
    8.58 +     *
    8.59 +     * @param args command line arguments
    8.60 +     * @param out output stream
    8.61 +     * @return an exit code. 0 means success, non-zero means an error occurred.
    8.62 +     */
    8.63 +    public static int run(String[] args, PrintWriter out) {
    8.64 +        JdepsTask t = new JdepsTask();
    8.65 +        t.setLog(out);
    8.66 +        return t.run(args);
    8.67 +    }
    8.68 +}
    8.69 +
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java	Fri Dec 28 22:25:21 2012 -0800
     9.3 @@ -0,0 +1,169 @@
     9.4 +/*
     9.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
     9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     9.7 + *
     9.8 + * This code is free software; you can redistribute it and/or modify it
     9.9 + * under the terms of the GNU General Public License version 2 only, as
    9.10 + * published by the Free Software Foundation.  Oracle designates this
    9.11 + * particular file as subject to the "Classpath" exception as provided
    9.12 + * by Oracle in the LICENSE file that accompanied this code.
    9.13 + *
    9.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    9.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    9.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    9.17 + * version 2 for more details (a copy is included in the LICENSE file that
    9.18 + * accompanied this code).
    9.19 + *
    9.20 + * You should have received a copy of the GNU General Public License version
    9.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    9.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    9.23 + *
    9.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    9.25 + * or visit www.oracle.com if you need additional information or have any
    9.26 + * questions.
    9.27 + */
    9.28 +package com.sun.tools.jdeps;
    9.29 +
    9.30 +import java.io.File;
    9.31 +import java.io.IOException;
    9.32 +import java.nio.file.FileVisitResult;
    9.33 +import java.nio.file.Files;
    9.34 +import java.nio.file.Path;
    9.35 +import java.nio.file.SimpleFileVisitor;
    9.36 +import java.nio.file.attribute.BasicFileAttributes;
    9.37 +import java.util.*;
    9.38 +
    9.39 +/**
    9.40 + * ClassPath for Java SE and JDK
    9.41 + */
    9.42 +class PlatformClassPath {
    9.43 +    /*
    9.44 +     * Profiles for Java SE
    9.45 +     *
    9.46 +     * This is a temporary workaround until a common API is defined for langtools
    9.47 +     * to determine which profile a given classname belongs to.  The list of
    9.48 +     * packages and profile names are hardcoded in jdk.properties and
    9.49 +     * split packages are not supported.
    9.50 +     */
    9.51 +    static class Profile {
    9.52 +        final String name;
    9.53 +        final Set<String> packages;
    9.54 +
    9.55 +        Profile(String name) {
    9.56 +            this.name = name;
    9.57 +            this.packages = new HashSet<String>();
    9.58 +        }
    9.59 +    }
    9.60 +
    9.61 +    private final static String JAVAFX = "javafx";
    9.62 +    private final static Map<String,Profile> map = getProfilePackages();
    9.63 +    static String getProfileName(String packageName) {
    9.64 +        Profile profile = map.get(packageName);
    9.65 +        if (packageName.startsWith(JAVAFX + ".")) {
    9.66 +            profile = map.get(JAVAFX);
    9.67 +        }
    9.68 +        return profile != null ? profile.name : "";
    9.69 +    }
    9.70 +
    9.71 +    private final static List<Archive> javaHomeArchives = init();
    9.72 +    static List<Archive> getArchives() {
    9.73 +        return javaHomeArchives;
    9.74 +    }
    9.75 +
    9.76 +    static boolean contains(Archive archive) {
    9.77 +        return javaHomeArchives.contains(archive);
    9.78 +    }
    9.79 +
    9.80 +    private static List<Archive> init() {
    9.81 +        List<Archive> result = new ArrayList<Archive>();
    9.82 +        String javaHome = System.getProperty("java.home");
    9.83 +        List<File> files = new ArrayList<File>();
    9.84 +        File jre = new File(javaHome, "jre");
    9.85 +        File lib = new File(javaHome, "lib");
    9.86 +
    9.87 +        try {
    9.88 +            if (jre.exists() && jre.isDirectory()) {
    9.89 +                result.addAll(addJarFiles(new File(jre, "lib")));
    9.90 +                result.addAll(addJarFiles(lib));
    9.91 +            } else if (lib.exists() && lib.isDirectory()) {
    9.92 +                // either a JRE or a jdk build image
    9.93 +                File classes = new File(javaHome, "classes");
    9.94 +                if (classes.exists() && classes.isDirectory()) {
    9.95 +                    // jdk build outputdir
    9.96 +                    result.add(new Archive(classes, ClassFileReader.newInstance(classes)));
    9.97 +                }
    9.98 +                // add other JAR files
    9.99 +                result.addAll(addJarFiles(lib));
   9.100 +            } else {
   9.101 +                throw new RuntimeException("\"" + javaHome + "\" not a JDK home");
   9.102 +            }
   9.103 +        } catch (IOException e) {
   9.104 +            throw new RuntimeException(e);
   9.105 +        }
   9.106 +
   9.107 +        // add a JavaFX profile if there is jfxrt.jar
   9.108 +        for (Archive archive : result) {
   9.109 +            if (archive.getFileName().equals("jfxrt.jar")) {
   9.110 +                map.put(JAVAFX, new Profile("jfxrt.jar"));
   9.111 +            }
   9.112 +        }
   9.113 +        return result;
   9.114 +    }
   9.115 +
   9.116 +    private static List<Archive> addJarFiles(File f) throws IOException {
   9.117 +        final List<Archive> result = new ArrayList<Archive>();
   9.118 +        final Path root = f.toPath();
   9.119 +        final Path ext = root.resolve("ext");
   9.120 +        Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
   9.121 +            @Override
   9.122 +            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
   9.123 +                throws IOException
   9.124 +            {
   9.125 +                if (dir.equals(root) || dir.equals(ext)) {
   9.126 +                    return FileVisitResult.CONTINUE;
   9.127 +                } else {
   9.128 +                    // skip other cobundled JAR files
   9.129 +                    return FileVisitResult.SKIP_SUBTREE;
   9.130 +                }
   9.131 +            }
   9.132 +            @Override
   9.133 +            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
   9.134 +                throws IOException
   9.135 +            {
   9.136 +                File f = file.toFile();
   9.137 +                String fn = f.getName();
   9.138 +                if (fn.endsWith(".jar") && !fn.equals("alt-rt.jar")) {
   9.139 +                    result.add(new Archive(f, ClassFileReader.newInstance(f)));
   9.140 +                }
   9.141 +                return FileVisitResult.CONTINUE;
   9.142 +            }
   9.143 +        });
   9.144 +        return result;
   9.145 +    }
   9.146 +
   9.147 +    private static Map<String,Profile> getProfilePackages() {
   9.148 +        Map<String,Profile> map = new HashMap<String,Profile>();
   9.149 +
   9.150 +        // read the properties as a ResourceBundle as the build compiles
   9.151 +        // the properties file into Java class.  Another alternative is
   9.152 +        // to load it as Properties and fix the build to exclude this file.
   9.153 +        ResourceBundle profileBundle =
   9.154 +            ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdk");
   9.155 +
   9.156 +        int i=1;
   9.157 +        String key;
   9.158 +        while (profileBundle.containsKey((key = "profile." + i + ".name"))) {
   9.159 +            Profile profile = new Profile(profileBundle.getString(key));
   9.160 +            String n = profileBundle.getString("profile." + i + ".packages");
   9.161 +            String[] pkgs = n.split("\\s+");
   9.162 +            for (String p : pkgs) {
   9.163 +                if (p.isEmpty()) continue;
   9.164 +                assert(map.containsKey(p) == false);
   9.165 +                profile.packages.add(p);
   9.166 +                map.put(p, profile);
   9.167 +            }
   9.168 +            i++;
   9.169 +        }
   9.170 +        return map;
   9.171 +    }
   9.172 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Fri Dec 28 22:25:21 2012 -0800
    10.3 @@ -0,0 +1,57 @@
    10.4 +main.usage.summary=\
    10.5 +Usage: {0} <options> <classes...>\n\
    10.6 +use -h, -? or --help for a list of possible options
    10.7 +
    10.8 +main.usage=\
    10.9 +Usage: {0} <options> <classes...>\n\
   10.10 +where <classes> can be a pathname to a .class file, a directory, a JAR file,\n\
   10.11 +or a fully-qualified classname or wildcard "*".  Possible options include:
   10.12 +
   10.13 +error.prefix=Error:
   10.14 +warn.prefix=Warning:
   10.15 +
   10.16 +main.opt.h=\
   10.17 +\  -h -?      --help                    Print this usage message
   10.18 +
   10.19 +main.opt.version=\
   10.20 +\             --version                 Version information
   10.21 +
   10.22 +main.opt.V=\
   10.23 +\  -V <level> --verbose-level=<level>   Print package-level or class-level dependencies\n\
   10.24 +\                                       Valid levels are: "package" and "class"
   10.25 +
   10.26 +main.opt.v=\
   10.27 +\  -v         --verbose                 Print additional information
   10.28 +
   10.29 +main.opt.s=\
   10.30 +\  -s         --summary                 Print dependency summary only
   10.31 +
   10.32 +main.opt.p=\
   10.33 +\  -p <pkg name> --package=<pkg name>   Restrict analysis to classes in this package\n\
   10.34 +\                                       (may be given multiple times)
   10.35 +
   10.36 +main.opt.e=\
   10.37 +\  -e <regex> --regex=<regex>           Restrict analysis to packages matching pattern\n\
   10.38 +\                                       (-p and -e are exclusive)
   10.39 +
   10.40 +main.opt.P=\
   10.41 +\  -P         --profile                 Show profile or the file containing a package
   10.42 +
   10.43 +main.opt.c=\
   10.44 +\  -c <path>  --classpath=<path>        Specify where to find class files
   10.45 +
   10.46 +main.opt.R=\
   10.47 +\  -R         --recursive               Recursively traverse all dependencies
   10.48 +
   10.49 +main.opt.d=\
   10.50 +\  -d <depth> --depth=<depth>           Specify the depth of the transitive dependency analysis
   10.51 +
   10.52 +err.unknown.option=unknown option: {0}
   10.53 +err.missing.arg=no value given for {0}
   10.54 +err.internal.error=internal error: {0} {1} {2}
   10.55 +err.invalid.arg.for.option=invalid argument for option: {0}
   10.56 +err.option.after.class=option must be specified before classes: {0}
   10.57 +warn.invalid.arg=Invalid classname or pathname not exist: {0}
   10.58 +warn.split.package=package {0} defined in {1} {2}
   10.59 +
   10.60 +artifact.not.found=not found
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/share/classes/com/sun/tools/jdeps/resources/jdk.properties	Fri Dec 28 22:25:21 2012 -0800
    11.3 @@ -0,0 +1,262 @@
    11.4 +# This properties file does not need localization.
    11.5 +
    11.6 +profile.1.name = compact1
    11.7 +profile.1.packages = \
    11.8 +    java.io \
    11.9 +    java.lang \
   11.10 +    java.lang.annotation \
   11.11 +    java.lang.invoke \
   11.12 +    java.lang.ref \
   11.13 +    java.lang.reflect \
   11.14 +    java.math \
   11.15 +    java.net \
   11.16 +    java.nio \
   11.17 +    java.nio.channels \
   11.18 +    java.nio.channels.spi \
   11.19 +    java.nio.charset \
   11.20 +    java.nio.charset.spi \
   11.21 +    java.nio.file \
   11.22 +    java.nio.file.attribute \
   11.23 +    java.nio.file.spi \
   11.24 +    java.security \
   11.25 +    java.security.cert \
   11.26 +    java.security.interfaces \
   11.27 +    java.security.spec \
   11.28 +    java.text \
   11.29 +    java.text.spi \
   11.30 +    java.util \
   11.31 +    java.util.concurrent \
   11.32 +    java.util.concurrent.atomic \
   11.33 +    java.util.concurrent.locks \
   11.34 +    java.util.jar \
   11.35 +    java.util.logging \
   11.36 +    java.util.regex \
   11.37 +    java.util.spi \
   11.38 +    java.util.zip \
   11.39 +    javax.crypto \
   11.40 +    javax.crypto.interfaces \
   11.41 +    javax.crypto.spec \
   11.42 +    javax.security.auth \
   11.43 +    javax.security.auth.callback \
   11.44 +    javax.security.auth.login \
   11.45 +    javax.security.auth.spi \
   11.46 +    javax.security.auth.x500 \
   11.47 +    javax.net \
   11.48 +    javax.net.ssl \
   11.49 +    javax.security.cert \
   11.50 +    \
   11.51 +    com.sun.net.ssl \
   11.52 +    com.sun.nio.file \
   11.53 +    com.sun.nio.sctp \
   11.54 +    com.sun.security.auth \
   11.55 +    com.sun.security.auth.login
   11.56 +
   11.57 +profile.2.name = compact2
   11.58 +profile.2.packages = \
   11.59 +    java.sql \
   11.60 +    javax.sql \
   11.61 +    javax.xml \
   11.62 +    javax.xml.datatype \
   11.63 +    javax.xml.namespace \
   11.64 +    javax.xml.parsers \
   11.65 +    javax.xml.stream \
   11.66 +    javax.xml.stream.events \
   11.67 +    javax.xml.stream.util \
   11.68 +    javax.xml.transform \
   11.69 +    javax.xml.transform.dom \
   11.70 +    javax.xml.transform.sax \
   11.71 +    javax.xml.transform.stax \
   11.72 +    javax.xml.transform.stream \
   11.73 +    javax.xml.validation \
   11.74 +    javax.xml.xpath \
   11.75 +    org.w3c.dom \
   11.76 +    org.w3c.dom.bootstrap \
   11.77 +    org.w3c.dom.events \
   11.78 +    org.w3c.dom.ls \
   11.79 +    org.xml.sax \
   11.80 +    org.xml.sax.ext \
   11.81 +    org.xml.sax.helpers \
   11.82 +    java.rmi \
   11.83 +    java.rmi.activation \
   11.84 +    java.rmi.dgc \
   11.85 +    java.rmi.registry \
   11.86 +    java.rmi.server \
   11.87 +    javax.rmi.ssl \
   11.88 +    javax.transaction \
   11.89 +    javax.transaction.xa \
   11.90 +    \
   11.91 +    com.sun.net.httpserver \
   11.92 +    com.sun.net.httpserver.spi
   11.93 +
   11.94 +profile.3.name = compact3
   11.95 +profile.3.packages = \
   11.96 +    java.lang.instrument \
   11.97 +    java.lang.management \
   11.98 +    java.security.acl \
   11.99 +    java.util.prefs \
  11.100 +    javax.management \
  11.101 +    javax.management.loading \
  11.102 +    javax.management.modelmbean \
  11.103 +    javax.management.monitor \
  11.104 +    javax.management.openmbean \
  11.105 +    javax.management.relation \
  11.106 +    javax.management.remote \
  11.107 +    javax.management.remote.rmi \
  11.108 +    javax.management.timer \
  11.109 +    javax.naming \
  11.110 +    javax.naming.directory \
  11.111 +    javax.naming.event \
  11.112 +    javax.naming.ldap \
  11.113 +    javax.naming.spi \
  11.114 +    javax.sql.rowset \
  11.115 +    javax.sql.rowset.serial \
  11.116 +    javax.sql.rowset.spi \
  11.117 +    javax.security.auth.kerberos \
  11.118 +    javax.security.sasl \
  11.119 +    javax.script \
  11.120 +    javax.smartcardio \
  11.121 +    javax.xml.crypto \
  11.122 +    javax.xml.crypto.dom \
  11.123 +    javax.xml.crypto.dsig \
  11.124 +    javax.xml.crypto.dsig.dom \
  11.125 +    javax.xml.crypto.dsig.keyinfo \
  11.126 +    javax.xml.crypto.dsig.spec \
  11.127 +    javax.annotation.processing \
  11.128 +    javax.lang.model \
  11.129 +    javax.lang.model.element \
  11.130 +    javax.lang.model.type \
  11.131 +    javax.lang.model.util \
  11.132 +    javax.tools \
  11.133 +    javax.tools.annotation \
  11.134 +    org.ietf.jgss \
  11.135 +    \
  11.136 +    com.sun.management \
  11.137 +    com.sun.security.auth.callback \
  11.138 +    com.sun.security.auth.module \
  11.139 +    com.sun.security.jgss
  11.140 +
  11.141 +profile.4.name = Full JRE
  11.142 +profile.4.packages = \
  11.143 +    java.applet \
  11.144 +    java.awt \
  11.145 +    java.awt.color \
  11.146 +    java.awt.datatransfer \
  11.147 +    java.awt.dnd \
  11.148 +    java.awt.dnd.peer \
  11.149 +    java.awt.event \
  11.150 +    java.awt.font \
  11.151 +    java.awt.geom \
  11.152 +    java.awt.im \
  11.153 +    java.awt.im.spi \
  11.154 +    java.awt.image \
  11.155 +    java.awt.image.renderable \
  11.156 +    java.awt.peer \
  11.157 +    java.awt.print \
  11.158 +    java.beans \
  11.159 +    java.beans.beancontext \
  11.160 +    javax.accessibility \
  11.161 +    javax.imageio \
  11.162 +    javax.imageio.event \
  11.163 +    javax.imageio.metadata \
  11.164 +    javax.imageio.plugins.bmp \
  11.165 +    javax.imageio.plugins.jpeg \
  11.166 +    javax.imageio.spi \
  11.167 +    javax.imageio.stream \
  11.168 +    javax.print \
  11.169 +    javax.print.attribute \
  11.170 +    javax.print.attribute.standard \
  11.171 +    javax.print.event \
  11.172 +    javax.sound.midi \
  11.173 +    javax.sound.midi.spi \
  11.174 +    javax.sound.sampled \
  11.175 +    javax.sound.sampled.spi \
  11.176 +    javax.swing \
  11.177 +    javax.swing.border \
  11.178 +    javax.swing.colorchooser \
  11.179 +    javax.swing.event \
  11.180 +    javax.swing.filechooser \
  11.181 +    javax.swing.plaf \
  11.182 +    javax.swing.plaf.basic \
  11.183 +    javax.swing.plaf.metal \
  11.184 +    javax.swing.plaf.multi \
  11.185 +    javax.swing.plaf.nimbus \
  11.186 +    javax.swing.plaf.synth \
  11.187 +    javax.swing.table \
  11.188 +    javax.swing.text \
  11.189 +    javax.swing.text.html \
  11.190 +    javax.swing.text.html.parser \
  11.191 +    javax.swing.text.rtf \
  11.192 +    javax.swing.tree \
  11.193 +    javax.swing.undo \
  11.194 +    javax.activation \
  11.195 +    javax.jws \
  11.196 +    javax.jws.soap \
  11.197 +    javax.rmi \
  11.198 +    javax.rmi.CORBA \
  11.199 +    javax.xml.bind \
  11.200 +    javax.xml.bind.annotation \
  11.201 +    javax.xml.bind.annotation.adapters \
  11.202 +    javax.xml.bind.attachment \
  11.203 +    javax.xml.bind.helpers \
  11.204 +    javax.xml.bind.util \
  11.205 +    javax.xml.soap \
  11.206 +    javax.xml.ws \
  11.207 +    javax.xml.ws.handler \
  11.208 +    javax.xml.ws.handler.soap \
  11.209 +    javax.xml.ws.http \
  11.210 +    javax.xml.ws.soap \
  11.211 +    javax.xml.ws.spi \
  11.212 +    javax.xml.ws.spi.http \
  11.213 +    javax.xml.ws.wsaddressing \
  11.214 +    javax.annotation \
  11.215 +    org.omg.CORBA \
  11.216 +    org.omg.CORBA.DynAnyPackage \
  11.217 +    org.omg.CORBA.ORBPackage \
  11.218 +    org.omg.CORBA.TypeCodePackage \
  11.219 +    org.omg.CORBA.portable \
  11.220 +    org.omg.CORBA_2_3 \
  11.221 +    org.omg.CORBA_2_3.portable \
  11.222 +    org.omg.CosNaming \
  11.223 +    org.omg.CosNaming.NamingContextExtPackage \
  11.224 +    org.omg.CosNaming.NamingContextPackage \
  11.225 +    org.omg.Dynamic \
  11.226 +    org.omg.DynamicAny \
  11.227 +    org.omg.DynamicAny.DynAnyFactoryPackage \
  11.228 +    org.omg.DynamicAny.DynAnyPackage \
  11.229 +    org.omg.IOP \
  11.230 +    org.omg.IOP.CodecFactoryPackage \
  11.231 +    org.omg.IOP.CodecPackage \
  11.232 +    org.omg.Messaging \
  11.233 +    org.omg.PortableInterceptor \
  11.234 +    org.omg.PortableInterceptor.ORBInitInfoPackage \
  11.235 +    org.omg.PortableServer \
  11.236 +    org.omg.PortableServer.CurrentPackage \
  11.237 +    org.omg.PortableServer.POAManagerPackage \
  11.238 +    org.omg.PortableServer.POAPackage \
  11.239 +    org.omg.PortableServer.ServantLocatorPackage \
  11.240 +    org.omg.PortableServer.portable \
  11.241 +    org.omg.SendingContext \
  11.242 +    org.omg.stub.java.rmi \
  11.243 +    org.omg.stub.javax.management.remote.rmi
  11.244 +
  11.245 +# Remaining JDK supported API
  11.246 +profile.5.name = JDK tools
  11.247 +profile.5.packages = \
  11.248 +    com.sun.jdi \
  11.249 +    com.sun.jdi.connect \
  11.250 +    com.sun.jdi.connect.spi \
  11.251 +    com.sun.jdi.event \
  11.252 +    com.sun.jdi.request \
  11.253 +    com.sun.javadoc \
  11.254 +    com.sun.tools.doclets \
  11.255 +    com.sun.tools.doctree \
  11.256 +    com.sun.source.tree \
  11.257 +    com.sun.source.util \
  11.258 +    com.sun.tools.attach \
  11.259 +    com.sun.tools.attach.spi \
  11.260 +    com.sun.tools.jconsole \
  11.261 +    com.sun.tools.javac \
  11.262 +    com.sun.tools.javah \
  11.263 +    com.sun.tools.javap \
  11.264 +    com.sun.tools.javadoc \
  11.265 +    com.sun.servicetag
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/share/classes/com/sun/tools/jdeps/resources/version.properties-template	Fri Dec 28 22:25:21 2012 -0800
    12.3 @@ -0,0 +1,28 @@
    12.4 +#
    12.5 +# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
    12.6 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    12.7 +#
    12.8 +# This code is free software; you can redistribute it and/or modify it
    12.9 +# under the terms of the GNU General Public License version 2 only, as
   12.10 +# published by the Free Software Foundation.  Oracle designates this
   12.11 +# particular file as subject to the "Classpath" exception as provided
   12.12 +# by Oracle in the LICENSE file that accompanied this code.
   12.13 +#
   12.14 +# This code is distributed in the hope that it will be useful, but WITHOUT
   12.15 +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   12.16 +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   12.17 +# version 2 for more details (a copy is included in the LICENSE file that
   12.18 +# accompanied this code).
   12.19 +#
   12.20 +# You should have received a copy of the GNU General Public License version
   12.21 +# 2 along with this work; if not, write to the Free Software Foundation,
   12.22 +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   12.23 +#
   12.24 +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   12.25 +# or visit www.oracle.com if you need additional information or have any
   12.26 +# questions.
   12.27 +#
   12.28 +
   12.29 +jdk=$(JDK_VERSION)
   12.30 +full=$(FULL_VERSION)
   12.31 +release=$(RELEASE)
    13.1 --- a/test/Makefile	Tue Dec 25 17:23:59 2012 -0800
    13.2 +++ b/test/Makefile	Fri Dec 28 22:25:21 2012 -0800
    13.3 @@ -229,7 +229,7 @@
    13.4  all: $(JPRT_CLEAN) jtreg-tests jck-compiler-tests jck-runtime-tests $(JPRT_ARCHIVE_BUNDLE) all-summary
    13.5  	@echo "Testing completed successfully"
    13.6  
    13.7 -jtreg apt javac javadoc javah javap: $(JPRT_CLEAN) jtreg-tests $(JPRT_ARCHIVE_BUNDLE) jtreg-summary
    13.8 +jtreg apt javac javadoc javah javap jdeps: $(JPRT_CLEAN) jtreg-tests $(JPRT_ARCHIVE_BUNDLE) jtreg-summary
    13.9  	@echo "Testing completed successfully"
   13.10  
   13.11  jck-compiler: $(JPRT_CLEAN) jck-compiler-tests $(JPRT_ARCHIVE_BUNDLE) jck-compiler-summary
   13.12 @@ -246,6 +246,7 @@
   13.13  javadoc:	JTREG_TESTDIRS = tools/javadoc com/sun/javadoc
   13.14  javah:		JTREG_TESTDIRS = tools/javah
   13.15  javap:		JTREG_TESTDIRS = tools/javap
   13.16 +jdeps:		JTREG_TESTDIRS = tools/jdeps
   13.17  
   13.18  # Run jtreg tests
   13.19  #
   13.20 @@ -426,7 +427,7 @@
   13.21  
   13.22  # Phony targets (e.g. these are not filenames)
   13.23  .PHONY: all clean \
   13.24 -	jtreg javac javadoc javah javap jtreg-tests jtreg-summary check-jtreg \
   13.25 +	jtreg javac javadoc javah javap jdeps jtreg-tests jtreg-summary check-jtreg \
   13.26  	jck-compiler jck-compiler-tests jck-compiler-summary \
   13.27  	jck-runtime jck-runtime-tests jck-runtime-summary check-jck
   13.28  
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/test/tools/jdeps/Basic.java	Fri Dec 28 22:25:21 2012 -0800
    14.3 @@ -0,0 +1,149 @@
    14.4 +/*
    14.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
    14.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    14.7 + *
    14.8 + * This code is free software; you can redistribute it and/or modify it
    14.9 + * under the terms of the GNU General Public License version 2 only, as
   14.10 + * published by the Free Software Foundation.
   14.11 + *
   14.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   14.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   14.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14.15 + * version 2 for more details (a copy is included in the LICENSE file that
   14.16 + * accompanied this code).
   14.17 + *
   14.18 + * You should have received a copy of the GNU General Public License version
   14.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   14.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   14.21 + *
   14.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   14.23 + * or visit www.oracle.com if you need additional information or have any
   14.24 + * questions.
   14.25 + */
   14.26 +
   14.27 +/*
   14.28 + * @test
   14.29 + * @bug 8003562
   14.30 + * @summary Basic tests for jdeps tool
   14.31 + * @build Test p.Foo
   14.32 + * @run main Basic
   14.33 + */
   14.34 +
   14.35 +import java.io.File;
   14.36 +import java.io.IOException;
   14.37 +import java.io.PrintWriter;
   14.38 +import java.io.StringWriter;
   14.39 +import java.util.*;
   14.40 +import java.util.regex.*;
   14.41 +
   14.42 +public class Basic {
   14.43 +    public static void main(String... args) throws Exception {
   14.44 +        int errors = 0;
   14.45 +
   14.46 +        errors += new Basic().run();
   14.47 +        if (errors > 0)
   14.48 +            throw new Exception(errors + " errors found");
   14.49 +    }
   14.50 +
   14.51 +    int run() throws IOException {
   14.52 +        File testDir = new File(System.getProperty("test.classes", "."));
   14.53 +        // test a .class file
   14.54 +        test(new File(testDir, "Test.class"),
   14.55 +             new String[] {"java.lang", "p"});
   14.56 +        // test a directory
   14.57 +        test(new File(testDir, "p"),
   14.58 +             new String[] {"java.lang", "java.util"});
   14.59 +        // test class-level dependency output
   14.60 +        test(new File(testDir, "Test.class"),
   14.61 +             new String[] {"java.lang.Object", "p.Foo"},
   14.62 +             new String[] {"-V", "class"});
   14.63 +        // test -p option
   14.64 +        test(new File(testDir, "Test.class"),
   14.65 +             new String[] {"p.Foo"},
   14.66 +             new String[] {"--verbose-level=class", "-p", "p"});
   14.67 +        // test -e option
   14.68 +        test(new File(testDir, "Test.class"),
   14.69 +             new String[] {"p.Foo"},
   14.70 +             new String[] {"-V", "class", "-e", "p\\..*"});
   14.71 +        test(new File(testDir, "Test.class"),
   14.72 +             new String[] {"java.lang"},
   14.73 +             new String[] {"-V", "package", "-e", "java\\.lang\\..*"});
   14.74 +        // test -classpath and -all options
   14.75 +        test(null,
   14.76 +             new String[] {"com.sun.tools.jdeps", "java.lang", "java.util",
   14.77 +                           "java.util.regex", "java.io", "p"},
   14.78 +             new String[] {"--classpath", testDir.getPath(), "*"});
   14.79 +        return errors;
   14.80 +    }
   14.81 +
   14.82 +    void test(File file, String[] expect) {
   14.83 +        test(file, expect, new String[0]);
   14.84 +    }
   14.85 +
   14.86 +    void test(File file, String[] expect, String[] options) {
   14.87 +        String[] args;
   14.88 +        if (file != null) {
   14.89 +            args = Arrays.copyOf(options, options.length+1);
   14.90 +            args[options.length] = file.getPath();
   14.91 +        } else {
   14.92 +            args = options;
   14.93 +        }
   14.94 +        String[] deps = jdeps(args);
   14.95 +        checkEqual("dependencies", expect, deps);
   14.96 +    }
   14.97 +
   14.98 +    String[] jdeps(String... args) {
   14.99 +        StringWriter sw = new StringWriter();
  14.100 +        PrintWriter pw = new PrintWriter(sw);
  14.101 +        System.err.println("jdeps " + Arrays.toString(args));
  14.102 +        int rc = com.sun.tools.jdeps.Main.run(args, pw);
  14.103 +        pw.close();
  14.104 +        String out = sw.toString();
  14.105 +        if (!out.isEmpty())
  14.106 +            System.err.println(out);
  14.107 +        if (rc != 0)
  14.108 +            throw new Error("jdeps failed: rc=" + rc);
  14.109 +        return findDeps(out);
  14.110 +    }
  14.111 +
  14.112 +    // Pattern used to parse lines
  14.113 +    private static Pattern linePattern = Pattern.compile(".*\r?\n");
  14.114 +    private static Pattern pattern = Pattern.compile("\\s+ -> (\\S+) +.*");
  14.115 +
  14.116 +    // Use the linePattern to break the given String into lines, applying
  14.117 +    // the pattern to each line to see if we have a match
  14.118 +    private static String[] findDeps(String out) {
  14.119 +        List<String> result = new ArrayList<>();
  14.120 +        Matcher lm = linePattern.matcher(out);  // Line matcher
  14.121 +        Matcher pm = null;                      // Pattern matcher
  14.122 +        int lines = 0;
  14.123 +        while (lm.find()) {
  14.124 +            lines++;
  14.125 +            CharSequence cs = lm.group();       // The current line
  14.126 +            if (pm == null)
  14.127 +                pm = pattern.matcher(cs);
  14.128 +            else
  14.129 +                pm.reset(cs);
  14.130 +            if (pm.find())
  14.131 +                result.add(pm.group(1));
  14.132 +            if (lm.end() == out.length())
  14.133 +                break;
  14.134 +        }
  14.135 +        return result.toArray(new String[0]);
  14.136 +    }
  14.137 +
  14.138 +    void checkEqual(String label, String[] expect, String[] found) {
  14.139 +        Set<String> s1 = new HashSet<>(Arrays.asList(expect));
  14.140 +        Set<String> s2 = new HashSet<>(Arrays.asList(found));
  14.141 +
  14.142 +        if (!s1.equals(s2))
  14.143 +            error("Unexpected " + label + " found: '" + s2 + "', expected: '" + s1 + "'");
  14.144 +    }
  14.145 +
  14.146 +    void error(String msg) {
  14.147 +        System.err.println("Error: " + msg);
  14.148 +        errors++;
  14.149 +    }
  14.150 +
  14.151 +    int errors;
  14.152 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/test/tools/jdeps/Test.java	Fri Dec 28 22:25:21 2012 -0800
    15.3 @@ -0,0 +1,28 @@
    15.4 +/*
    15.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
    15.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    15.7 + *
    15.8 + * This code is free software; you can redistribute it and/or modify it
    15.9 + * under the terms of the GNU General Public License version 2 only, as
   15.10 + * published by the Free Software Foundation.
   15.11 + *
   15.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   15.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   15.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   15.15 + * version 2 for more details (a copy is included in the LICENSE file that
   15.16 + * accompanied this code).
   15.17 + *
   15.18 + * You should have received a copy of the GNU General Public License version
   15.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   15.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   15.21 + *
   15.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   15.23 + * or visit www.oracle.com if you need additional information or have any
   15.24 + * questions.
   15.25 + */
   15.26 +
   15.27 +public class Test {
   15.28 +    public void test() {
   15.29 +        p.Foo f = new p.Foo();
   15.30 +    }
   15.31 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/test/tools/jdeps/p/Foo.java	Fri Dec 28 22:25:21 2012 -0800
    16.3 @@ -0,0 +1,35 @@
    16.4 +/*
    16.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
    16.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    16.7 + *
    16.8 + * This code is free software; you can redistribute it and/or modify it
    16.9 + * under the terms of the GNU General Public License version 2 only, as
   16.10 + * published by the Free Software Foundation.
   16.11 + *
   16.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   16.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   16.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   16.15 + * version 2 for more details (a copy is included in the LICENSE file that
   16.16 + * accompanied this code).
   16.17 + *
   16.18 + * You should have received a copy of the GNU General Public License version
   16.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   16.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   16.21 + *
   16.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   16.23 + * or visit www.oracle.com if you need additional information or have any
   16.24 + * questions.
   16.25 + */
   16.26 +
   16.27 +package p;
   16.28 +
   16.29 +import java.util.List;
   16.30 +import java.util.Collections;
   16.31 +public class Foo {
   16.32 +    public static List foo() {
   16.33 +        return Collections.emptyList();
   16.34 +    }
   16.35 +
   16.36 +    public Foo() {
   16.37 +    }
   16.38 +}

mercurial