8015912: jdeps support to output in dot file format
authormchung
Thu, 17 Oct 2013 13:19:48 -0700
changeset 21046 ebf16a1a6328
parent 21045 a7a1562c97be
child 21047 37288695878a
8015912: jdeps support to output in dot file format 8026255: Switch jdeps to follow traditional Java option style Reviewed-by: alanb
langtools/src/share/classes/com/sun/tools/jdeps/Analyzer.java
langtools/src/share/classes/com/sun/tools/jdeps/Archive.java
langtools/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java
langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java
langtools/src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java
langtools/src/share/classes/com/sun/tools/jdeps/Profile.java
langtools/src/share/classes/com/sun/tools/jdeps/Profiles.java
langtools/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties
langtools/test/tools/jdeps/APIDeps.java
langtools/test/tools/jdeps/Basic.java
langtools/test/tools/jdeps/Test.java
langtools/test/tools/jdeps/b/B.java
langtools/test/tools/jdeps/c/C.java
langtools/test/tools/jdeps/c/I.java
langtools/test/tools/jdeps/d/D.java
langtools/test/tools/jdeps/e/E.java
langtools/test/tools/jdeps/f/F.java
langtools/test/tools/jdeps/g/G.java
langtools/test/tools/jdeps/m/Bar.java
langtools/test/tools/jdeps/m/Foo.java
langtools/test/tools/jdeps/m/Gee.java
--- a/langtools/src/share/classes/com/sun/tools/jdeps/Analyzer.java	Thu Oct 17 13:50:00 2013 +0200
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/Analyzer.java	Thu Oct 17 13:19:48 2013 -0700
@@ -25,9 +25,8 @@
 package com.sun.tools.jdeps;
 
 import com.sun.tools.classfile.Dependency.Location;
-import java.util.ArrayList;
+import com.sun.tools.jdeps.PlatformClassPath.JDKArchive;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -52,8 +51,8 @@
     };
 
     private final Type type;
-    private final List<ArchiveDeps> results = new ArrayList<ArchiveDeps>();
-    private final Map<String, Archive> map = new HashMap<String, Archive>();
+    private final Map<Archive, ArchiveDeps> results = new HashMap<>();
+    private final Map<String, Archive> map = new HashMap<>();
     private final Archive NOT_FOUND
         = new Archive(JdepsTask.getMessage("artifact.not.found"));
 
@@ -78,27 +77,27 @@
                 deps = new PackageVisitor(archive);
             }
             archive.visit(deps);
-            results.add(deps);
+            results.put(archive, deps);
         }
 
         // set the required dependencies
-        for (ArchiveDeps result: results) {
+        for (ArchiveDeps result: results.values()) {
             for (Set<String> set : result.deps.values()) {
                 for (String target : set) {
                     Archive source = getArchive(target);
                     if (result.archive != source) {
-                        if (!result.requiredArchives.contains(source)) {
-                            result.requiredArchives.add(source);
+                        String profile = "";
+                        if (source instanceof JDKArchive) {
+                            profile = result.profile != null ? result.profile.toString() : "";
+                            if (result.getTargetProfile(target) == null) {
+                                profile += ", JDK internal API";
+                                // override the value if it accesses any JDK internal
+                                result.requireArchives.put(source, profile);
+                                continue;
+                            }
                         }
-                        // either a profile name or the archive name
-                        String tname = result.getTargetProfile(target);
-                        if (tname.isEmpty()) {
-                            tname = PlatformClassPath.contains(source)
-                                        ? "JDK internal API (" + source.getFileName() + ")"
-                                        : source.toString();
-                        }
-                        if (!result.targetNames.contains(tname)) {
-                            result.targetNames.add(tname);
+                        if (!result.requireArchives.containsKey(source)) {
+                            result.requireArchives.put(source, profile);
                         }
                     }
                 }
@@ -106,42 +105,46 @@
         }
     }
 
+    public boolean hasDependences(Archive archive) {
+        if (results.containsKey(archive)) {
+            return results.get(archive).deps.size() > 0;
+        }
+        return false;
+    }
+
     public interface Visitor {
         /**
+         * Visits the source archive to its destination archive of
+         * a recorded dependency.
+         */
+        void visitArchiveDependence(Archive origin, Archive target, String profile);
+        /**
          * Visits a recorded dependency from origin to target which can be
          * a fully-qualified classname, a package name, a profile or
          * archive name depending on the Analyzer's type.
          */
-        void visit(String origin, String target, String profile);
-        /**
-         * Visits the source archive to its destination archive of
-         * a recorded dependency.
-         */
-        void visit(Archive source, Archive dest);
+        void visitDependence(String origin, Archive source, String target, Archive archive, String profile);
     }
 
-    public void visitSummary(Visitor v) {
-        for (ArchiveDeps r : results) {
-            for (Archive a : r.requiredArchives) {
-                v.visit(r.archive, a);
-            }
-            for (String name : r.targetNames) {
-                v.visit(r.archive.getFileName(), name, name);
-            }
+    public void visitArchiveDependences(Archive source, Visitor v) {
+        ArchiveDeps r = results.get(source);
+        for (Map.Entry<Archive,String> e : r.requireArchives.entrySet()) {
+            v.visitArchiveDependence(r.archive, e.getKey(), e.getValue());
         }
     }
 
-    public void visit(Visitor v) {
-        for (ArchiveDeps r: results) {
-            for (Archive a : r.requiredArchives) {
-                v.visit(r.archive, a);
-            }
-            for (String origin : r.deps.keySet()) {
-                for (String target : r.deps.get(origin)) {
-                    // filter intra-dependency unless in verbose mode
-                    if (type == Type.VERBOSE || getArchive(origin) != getArchive(target)) {
-                        v.visit(origin, target, r.getTargetProfile(target));
-                    }
+    public void visitDependences(Archive source, Visitor v) {
+        ArchiveDeps r = results.get(source);
+        for (String origin : r.deps.keySet()) {
+            for (String target : r.deps.get(origin)) {
+                Archive archive = getArchive(target);
+                assert source == getArchive(origin);
+                Profile profile = r.getTargetProfile(target);
+
+                // filter intra-dependency unless in verbose mode
+                if (type == Type.VERBOSE || archive != source) {
+                    v.visitDependence(origin, source, target, archive,
+                                      profile != null ? profile.toString() : "");
                 }
             }
         }
@@ -151,29 +154,15 @@
         return map.containsKey(name) ? map.get(name) : NOT_FOUND;
     }
 
-    /**
-     * Returns the file name of the archive for non-JRE class or
-     * internal JRE classes.  It returns empty string for SE API.
-     */
-    public String getArchiveName(String target, String profile) {
-        Archive source = getArchive(target);
-        String name = source.getFileName();
-        if (PlatformClassPath.contains(source))
-            return profile.isEmpty() ? "JDK internal API (" + name + ")" : "";
-        return name;
-    }
-
     private abstract class ArchiveDeps implements Archive.Visitor {
         final Archive archive;
-        final Set<Archive> requiredArchives;
-        final SortedSet<String> targetNames;
+        final Map<Archive,String> requireArchives;
         final SortedMap<String, SortedSet<String>> deps;
-
+        Profile profile = null;
         ArchiveDeps(Archive archive) {
             this.archive = archive;
-            this.requiredArchives = new HashSet<Archive>();
-            this.targetNames = new TreeSet<String>();
-            this.deps = new TreeMap<String, SortedSet<String>>();
+            this.requireArchives = new HashMap<>();
+            this.deps = new TreeMap<>();
         }
 
         void add(String loc) {
@@ -188,17 +177,19 @@
         void add(String origin, String target) {
             SortedSet<String> set = deps.get(origin);
             if (set == null) {
-                set = new TreeSet<String>();
-                deps.put(origin, set);
+                deps.put(origin, set = new TreeSet<>());
             }
             if (!set.contains(target)) {
                 set.add(target);
+                // find the corresponding profile
+                Profile p = getTargetProfile(target);
+                if (profile == null || (p != null && profile.profile < p.profile)) {
+                     profile = p;
+                }
             }
         }
-
         public abstract void visit(Location o, Location t);
-        public abstract String getTargetProfile(String target);
-
+        public abstract Profile getTargetProfile(String target);
     }
 
     private class ClassVisitor extends ArchiveDeps {
@@ -211,9 +202,9 @@
         public void visit(Location o, Location t) {
             add(o.getClassName(), t.getClassName());
         }
-        public String getTargetProfile(String target) {
+        public Profile getTargetProfile(String target) {
             int i = target.lastIndexOf('.');
-            return (i > 0) ? Profiles.getProfileName(target.substring(0, i)) : "";
+            return (i > 0) ? Profile.getProfile(target.substring(0, i)) : null;
         }
     }
 
@@ -231,8 +222,8 @@
             String pkg = loc.getPackageName();
             return pkg.isEmpty() ? "<unnamed>" : pkg;
         }
-        public String getTargetProfile(String target) {
-            return Profiles.getProfileName(target);
+        public Profile getTargetProfile(String target) {
+            return Profile.getProfile(target);
         }
     }
 }
--- a/langtools/src/share/classes/com/sun/tools/jdeps/Archive.java	Thu Oct 17 13:50:00 2013 +0200
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/Archive.java	Thu Oct 17 13:19:48 2013 -0700
@@ -25,7 +25,7 @@
 package com.sun.tools.jdeps;
 
 import com.sun.tools.classfile.Dependency.Location;
-import java.io.File;
+import java.nio.file.Path;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -35,21 +35,20 @@
  * Represents the source of the class files.
  */
 public class Archive {
-    private final File file;
+    private final Path path;
     private final String filename;
     private final ClassFileReader reader;
-    private final Map<Location, Set<Location>> deps
-        = new HashMap<Location, Set<Location>>();
+    private final Map<Location, Set<Location>> deps = new HashMap<>();
 
     public Archive(String name) {
-        this.file = null;
+        this.path = null;
         this.filename = name;
         this.reader = null;
     }
 
-    public Archive(File f, ClassFileReader reader) {
-        this.file = f;
-        this.filename = f.getName();
+    public Archive(Path p, ClassFileReader reader) {
+        this.path = p;
+        this.filename = path.getFileName().toString();
         this.reader = reader;
     }
 
@@ -64,14 +63,14 @@
     public void addClass(Location origin) {
         Set<Location> set = deps.get(origin);
         if (set == null) {
-            set = new HashSet<Location>();
+            set = new HashSet<>();
             deps.put(origin, set);
         }
     }
     public void addClass(Location origin, Location target) {
         Set<Location> set = deps.get(origin);
         if (set == null) {
-            set = new HashSet<Location>();
+            set = new HashSet<>();
             deps.put(origin, set);
         }
         set.add(target);
@@ -87,7 +86,7 @@
     }
 
     public String toString() {
-        return file != null ? file.getPath() : filename;
+        return path != null ? path.toString() : filename;
     }
 
     interface Visitor {
--- a/langtools/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Thu Oct 17 13:50:00 2013 +0200
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/ClassFileReader.java	Thu Oct 17 13:19:48 2013 -0700
@@ -45,17 +45,17 @@
     /**
      * Returns a ClassFileReader instance of a given path.
      */
-    public static ClassFileReader newInstance(File path) throws IOException {
-        if (!path.exists()) {
-            throw new FileNotFoundException(path.getAbsolutePath());
+    public static ClassFileReader newInstance(Path path) throws IOException {
+        if (!Files.exists(path)) {
+            throw new FileNotFoundException(path.toString());
         }
 
-        if (path.isDirectory()) {
-            return new DirectoryReader(path.toPath());
-        } else if (path.getName().endsWith(".jar")) {
-            return new JarFileReader(path.toPath());
+        if (Files.isDirectory(path)) {
+            return new DirectoryReader(path);
+        } else if (path.getFileName().toString().endsWith(".jar")) {
+            return new JarFileReader(path);
         } else {
-            return new ClassFileReader(path.toPath());
+            return new ClassFileReader(path);
         }
     }
 
@@ -163,16 +163,16 @@
                 int i = name.lastIndexOf('.');
                 String pathname = name.replace('.', File.separatorChar) + ".class";
                 Path p = path.resolve(pathname);
-                if (!p.toFile().exists()) {
+                if (!Files.exists(p)) {
                     p = path.resolve(pathname.substring(0, i) + "$" +
                                      pathname.substring(i+1, pathname.length()));
                 }
-                if (p.toFile().exists()) {
+                if (Files.exists(p)) {
                     return readClassFile(p);
                 }
             } else {
                 Path p = path.resolve(name + ".class");
-                if (p.toFile().exists()) {
+                if (Files.exists(p)) {
                     return readClassFile(p);
                 }
             }
@@ -193,7 +193,7 @@
             Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
                 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                         throws IOException {
-                    if (file.toFile().getName().endsWith(".class")) {
+                    if (file.getFileName().toString().endsWith(".class")) {
                         files.add(file);
                     }
                     return FileVisitResult.CONTINUE;
--- a/langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java	Thu Oct 17 13:50:00 2013 +0200
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java	Thu Oct 17 13:19:48 2013 -0700
@@ -24,12 +24,18 @@
  */
 package com.sun.tools.jdeps;
 
+import com.sun.tools.classfile.AccessFlags;
 import com.sun.tools.classfile.ClassFile;
 import com.sun.tools.classfile.ConstantPoolException;
 import com.sun.tools.classfile.Dependencies;
 import com.sun.tools.classfile.Dependencies.ClassFileError;
 import com.sun.tools.classfile.Dependency;
+import com.sun.tools.jdeps.PlatformClassPath.JDKArchive;
 import java.io.*;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.text.MessageFormat;
 import java.util.*;
 import java.util.regex.Pattern;
@@ -67,11 +73,10 @@
 
         boolean matches(String opt) {
             for (String a : aliases) {
-                if (a.equals(opt)) {
+                if (a.equals(opt))
                     return true;
-                } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) {
+                if (hasArg && opt.startsWith(a + "="))
                     return true;
-                }
             }
             return false;
         }
@@ -96,62 +101,96 @@
     }
 
     static Option[] recognizedOptions = {
-        new Option(false, "-h", "-?", "--help") {
+        new Option(false, "-h", "-?", "-help") {
             void process(JdepsTask task, String opt, String arg) {
                 task.options.help = true;
             }
         },
-        new Option(false, "-s", "--summary") {
+        new Option(true, "-dotoutput") {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                Path p = Paths.get(arg);
+                if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
+                    throw new BadArgs("err.dot.output.path", arg);
+                }
+                task.options.dotOutputDir = arg;
+            }
+        },
+        new Option(false, "-s", "-summary") {
             void process(JdepsTask task, String opt, String arg) {
                 task.options.showSummary = true;
                 task.options.verbose = Analyzer.Type.SUMMARY;
             }
         },
-        new Option(false, "-v", "--verbose") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.verbose = Analyzer.Type.VERBOSE;
-            }
-        },
-        new Option(true, "-V", "--verbose-level") {
+        new Option(false, "-v", "-verbose",
+                          "-verbose:package",
+                          "-verbose:class")
+        {
             void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                if ("package".equals(arg)) {
-                    task.options.verbose = Analyzer.Type.PACKAGE;
-                } else if ("class".equals(arg)) {
-                    task.options.verbose = Analyzer.Type.CLASS;
-                } else {
-                    throw new BadArgs("err.invalid.arg.for.option", opt);
+                switch (opt) {
+                    case "-v":
+                    case "-verbose":
+                        task.options.verbose = Analyzer.Type.VERBOSE;
+                        break;
+                    case "-verbose:package":
+                            task.options.verbose = Analyzer.Type.PACKAGE;
+                            break;
+                    case "-verbose:class":
+                            task.options.verbose = Analyzer.Type.CLASS;
+                            break;
+                    default:
+                        throw new BadArgs("err.invalid.arg.for.option", opt);
                 }
             }
         },
-        new Option(true, "-c", "--classpath") {
+        new Option(true, "-cp", "-classpath") {
             void process(JdepsTask task, String opt, String arg) {
                 task.options.classpath = arg;
             }
         },
-        new Option(true, "-p", "--package") {
+        new Option(true, "-p", "-package") {
             void process(JdepsTask task, String opt, String arg) {
                 task.options.packageNames.add(arg);
             }
         },
-        new Option(true, "-e", "--regex") {
+        new Option(true, "-e", "-regex") {
             void process(JdepsTask task, String opt, String arg) {
                 task.options.regex = arg;
             }
         },
-        new Option(false, "-P", "--profile") {
+        new Option(true, "-include") {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                task.options.includePattern = Pattern.compile(arg);
+            }
+        },
+        new Option(false, "-P", "-profile") {
             void process(JdepsTask task, String opt, String arg) throws BadArgs {
                 task.options.showProfile = true;
-                if (Profiles.getProfileCount() == 0) {
+                if (Profile.getProfileCount() == 0) {
                     throw new BadArgs("err.option.unsupported", opt, getMessage("err.profiles.msg"));
                 }
             }
         },
-        new Option(false, "-R", "--recursive") {
+        new Option(false, "-apionly") {
+            void process(JdepsTask task, String opt, String arg) {
+                task.options.apiOnly = true;
+            }
+        },
+        new Option(false, "-R", "-recursive") {
             void process(JdepsTask task, String opt, String arg) {
                 task.options.depth = 0;
             }
         },
-        new HiddenOption(true, "-d", "--depth") {
+        new Option(false, "-version") {
+            void process(JdepsTask task, String opt, String arg) {
+                task.options.version = true;
+            }
+        },
+        new HiddenOption(false, "-fullversion") {
+            void process(JdepsTask task, String opt, String arg) {
+                task.options.fullVersion = true;
+            }
+        },
+        new HiddenOption(true, "-depth") {
             void process(JdepsTask task, String opt, String arg) throws BadArgs {
                 try {
                     task.options.depth = Integer.parseInt(arg);
@@ -160,16 +199,6 @@
                 }
             }
         },
-        new Option(false, "--version") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.version = true;
-            }
-        },
-        new HiddenOption(false, "--fullversion") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.fullVersion = true;
-            }
-        },
     };
 
     private static final String PROGNAME = "jdeps";
@@ -202,7 +231,7 @@
             if (options.version || options.fullVersion) {
                 showVersion(options.fullVersion);
             }
-            if (classes.isEmpty() && !options.wildcard) {
+            if (classes.isEmpty() && options.includePattern == null) {
                 if (options.help || options.version || options.fullVersion) {
                     return EXIT_OK;
                 } else {
@@ -233,19 +262,51 @@
         }
     }
 
-    private final List<Archive> sourceLocations = new ArrayList<Archive>();
+    private final List<Archive> sourceLocations = new ArrayList<>();
     private boolean run() throws IOException {
         findDependencies();
         Analyzer analyzer = new Analyzer(options.verbose);
         analyzer.run(sourceLocations);
-        if (options.verbose == Analyzer.Type.SUMMARY) {
-            printSummary(log, analyzer);
+        if (options.dotOutputDir != null) {
+            Path dir = Paths.get(options.dotOutputDir);
+            Files.createDirectories(dir);
+            generateDotFiles(dir, analyzer);
         } else {
-            printDependencies(log, analyzer);
+            printRawOutput(log, analyzer);
         }
         return true;
     }
 
+    private void generateDotFiles(Path dir, Analyzer analyzer) throws IOException {
+        Path summary = dir.resolve("summary.dot");
+        try (PrintWriter sw = new PrintWriter(Files.newOutputStream(summary));
+             DotFileFormatter formatter = new DotFileFormatter(sw, "summary")) {
+            for (Archive archive : sourceLocations) {
+                 analyzer.visitArchiveDependences(archive, formatter);
+            }
+        }
+        if (options.verbose != Analyzer.Type.SUMMARY) {
+            for (Archive archive : sourceLocations) {
+                if (analyzer.hasDependences(archive)) {
+                    Path dotfile = dir.resolve(archive.getFileName() + ".dot");
+                    try (PrintWriter pw = new PrintWriter(Files.newOutputStream(dotfile));
+                         DotFileFormatter formatter = new DotFileFormatter(pw, archive)) {
+                        analyzer.visitDependences(archive, formatter);
+                    }
+                }
+            }
+        }
+    }
+
+    private void printRawOutput(PrintWriter writer, Analyzer analyzer) {
+        for (Archive archive : sourceLocations) {
+            RawOutputFormatter formatter = new RawOutputFormatter(writer);
+            analyzer.visitArchiveDependences(archive, formatter);
+            if (options.verbose != Analyzer.Type.SUMMARY) {
+                analyzer.visitDependences(archive, formatter);
+            }
+        }
+    }
     private boolean isValidClassName(String name) {
         if (!Character.isJavaIdentifierStart(name.charAt(0))) {
             return false;
@@ -259,27 +320,43 @@
         return true;
     }
 
-    private void findDependencies() throws IOException {
-        Dependency.Finder finder = Dependencies.getClassDependencyFinder();
-        Dependency.Filter filter;
-        if (options.regex != null) {
-            filter = Dependencies.getRegexFilter(Pattern.compile(options.regex));
+    private Dependency.Filter getDependencyFilter() {
+         if (options.regex != null) {
+            return Dependencies.getRegexFilter(Pattern.compile(options.regex));
         } else if (options.packageNames.size() > 0) {
-            filter = Dependencies.getPackageFilter(options.packageNames, false);
+            return Dependencies.getPackageFilter(options.packageNames, false);
         } else {
-            filter = new Dependency.Filter() {
+            return new Dependency.Filter() {
+                @Override
                 public boolean accepts(Dependency dependency) {
                     return !dependency.getOrigin().equals(dependency.getTarget());
                 }
             };
         }
+    }
 
-        List<Archive> archives = new ArrayList<Archive>();
-        Deque<String> roots = new LinkedList<String>();
+    private boolean matches(String classname, AccessFlags flags) {
+        if (options.apiOnly && !flags.is(AccessFlags.ACC_PUBLIC)) {
+            return false;
+        } else if (options.includePattern != null) {
+            return options.includePattern.matcher(classname.replace('/', '.')).matches();
+        } else {
+            return true;
+        }
+    }
+
+    private void findDependencies() throws IOException {
+        Dependency.Finder finder =
+            options.apiOnly ? Dependencies.getAPIFinder(AccessFlags.ACC_PROTECTED)
+                            : Dependencies.getClassDependencyFinder();
+        Dependency.Filter filter = getDependencyFilter();
+
+        List<Archive> archives = new ArrayList<>();
+        Deque<String> roots = new LinkedList<>();
         for (String s : classes) {
-            File f = new File(s);
-            if (f.exists()) {
-                archives.add(new Archive(f, ClassFileReader.newInstance(f)));
+            Path p = Paths.get(s);
+            if (Files.exists(p)) {
+                archives.add(new Archive(p, ClassFileReader.newInstance(p)));
             } else {
                 if (isValidClassName(s)) {
                     roots.add(s);
@@ -289,9 +366,8 @@
             }
         }
 
-        List<Archive> classpaths = new ArrayList<Archive>(); // for class file lookup
-        if (options.wildcard) {
-            // include all archives from classpath to the initial list
+        List<Archive> classpaths = new ArrayList<>(); // for class file lookup
+        if (options.includePattern != null) {
             archives.addAll(getClassPathArchives(options.classpath));
         } else {
             classpaths.addAll(getClassPathArchives(options.classpath));
@@ -305,8 +381,8 @@
         // Work queue of names of classfiles to be searched.
         // Entries will be unique, and for classes that do not yet have
         // dependencies in the results map.
-        Deque<String> deque = new LinkedList<String>();
-        Set<String> doneClasses = new HashSet<String>();
+        Deque<String> deque = new LinkedList<>();
+        Set<String> doneClasses = new HashSet<>();
 
         // get the immediate dependencies of the input files
         for (Archive a : archives) {
@@ -318,16 +394,18 @@
                     throw new ClassFileError(e);
                 }
 
-                if (!doneClasses.contains(classFileName)) {
-                    doneClasses.add(classFileName);
-                }
-                for (Dependency d : finder.findDependencies(cf)) {
-                    if (filter.accepts(d)) {
-                        String cn = d.getTarget().getName();
-                        if (!doneClasses.contains(cn) && !deque.contains(cn)) {
-                            deque.add(cn);
+                if (matches(classFileName, cf.access_flags)) {
+                    if (!doneClasses.contains(classFileName)) {
+                        doneClasses.add(classFileName);
+                    }
+                    for (Dependency d : finder.findDependencies(cf)) {
+                        if (filter.accepts(d)) {
+                            String cn = d.getTarget().getName();
+                            if (!doneClasses.contains(cn) && !deque.contains(cn)) {
+                                deque.add(cn);
+                            }
+                            a.addClass(d.getOrigin(), d.getTarget());
                         }
-                        a.addClass(d.getOrigin(), d.getTarget());
                     }
                 }
             }
@@ -379,46 +457,10 @@
                 }
             }
             unresolved = deque;
-            deque = new LinkedList<String>();
+            deque = new LinkedList<>();
         } while (!unresolved.isEmpty() && depth-- > 0);
     }
 
-    private void printSummary(final PrintWriter out, final Analyzer analyzer) {
-        Analyzer.Visitor visitor = new Analyzer.Visitor() {
-            public void visit(String origin, String target, String profile) {
-                if (options.showProfile) {
-                    out.format("%-30s -> %s%n", origin, target);
-                }
-            }
-            public void visit(Archive origin, Archive target) {
-                if (!options.showProfile) {
-                    out.format("%-30s -> %s%n", origin, target);
-                }
-            }
-        };
-        analyzer.visitSummary(visitor);
-    }
-
-    private void printDependencies(final PrintWriter out, final Analyzer analyzer) {
-        Analyzer.Visitor visitor = new Analyzer.Visitor() {
-            private String pkg = "";
-            public void visit(String origin, String target, String profile) {
-                if (!origin.equals(pkg)) {
-                    pkg = origin;
-                    out.format("   %s (%s)%n", origin, analyzer.getArchive(origin).getFileName());
-                }
-                out.format("      -> %-50s %s%n", target,
-                           (options.showProfile && !profile.isEmpty())
-                               ? profile
-                               : analyzer.getArchiveName(target, profile));
-            }
-            public void visit(Archive origin, Archive target) {
-                out.format("%s -> %s%n", origin, target);
-            }
-        };
-        analyzer.visit(visitor);
-    }
-
     public void handleOptions(String[] args) throws BadArgs {
         // process options
         for (int i=0; i < args.length; i++) {
@@ -427,7 +469,7 @@
                 Option option = getOption(name);
                 String param = null;
                 if (option.hasArg) {
-                    if (name.startsWith("--") && name.indexOf('=') > 0) {
+                    if (name.startsWith("-") && name.indexOf('=') > 0) {
                         param = name.substring(name.indexOf('=') + 1, name.length());
                     } else if (i + 1 < args.length) {
                         param = args[++i];
@@ -447,11 +489,7 @@
                     if (name.charAt(0) == '-') {
                         throw new BadArgs("err.option.after.class", name).showUsage(true);
                     }
-                    if (name.equals("*") || name.equals("\"*\"")) {
-                        options.wildcard = true;
-                    } else {
-                        classes.add(name);
-                    }
+                    classes.add(name);
                 }
             }
         }
@@ -518,13 +556,15 @@
         boolean showProfile;
         boolean showSummary;
         boolean wildcard;
-        String regex;
+        boolean apiOnly;
+        String dotOutputDir;
         String classpath = "";
         int depth = 1;
         Analyzer.Type verbose = Analyzer.Type.PACKAGE;
-        Set<String> packageNames = new HashSet<String>();
+        Set<String> packageNames = new HashSet<>();
+        String regex;             // apply to the dependences
+        Pattern includePattern;   // apply to classes
     }
-
     private static class ResourceBundleHelper {
         static final ResourceBundle versionRB;
         static final ResourceBundle bundle;
@@ -547,9 +587,9 @@
     private List<Archive> getArchives(List<String> filenames) throws IOException {
         List<Archive> result = new ArrayList<Archive>();
         for (String s : filenames) {
-            File f = new File(s);
-            if (f.exists()) {
-                result.add(new Archive(f, ClassFileReader.newInstance(f)));
+            Path p = Paths.get(s);
+            if (Files.exists(p)) {
+                result.add(new Archive(p, ClassFileReader.newInstance(p)));
             } else {
                 warning("warn.file.not.exist", s);
             }
@@ -558,18 +598,131 @@
     }
 
     private List<Archive> getClassPathArchives(String paths) throws IOException {
-        List<Archive> result = new ArrayList<Archive>();
+        List<Archive> result = new ArrayList<>();
         if (paths.isEmpty()) {
             return result;
         }
         for (String p : paths.split(File.pathSeparator)) {
             if (p.length() > 0) {
-                File f = new File(p);
-                if (f.exists()) {
-                    result.add(new Archive(f, ClassFileReader.newInstance(f)));
+                List<Path> files = new ArrayList<>();
+                // wildcard to parse all JAR files e.g. -classpath dir/*
+                int i = p.lastIndexOf(".*");
+                if (i > 0) {
+                    Path dir = Paths.get(p.substring(0, i));
+                    try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.jar")) {
+                        for (Path entry : stream) {
+                            files.add(entry);
+                        }
+                    }
+                } else {
+                    files.add(Paths.get(p));
+                }
+                for (Path f : files) {
+                    if (Files.exists(f)) {
+                        result.add(new Archive(f, ClassFileReader.newInstance(f)));
+                    }
                 }
             }
         }
         return result;
     }
+
+
+    /**
+     * Returns the file name of the archive for non-JRE class or
+     * internal JRE classes.  It returns empty string for SE API.
+     */
+    private static String getArchiveName(Archive source, String profile) {
+        String name = source.getFileName();
+        if (source instanceof JDKArchive)
+            return profile.isEmpty() ? "JDK internal API (" + name + ")" : "";
+        return name;
+    }
+
+    class RawOutputFormatter implements Analyzer.Visitor {
+        private final PrintWriter writer;
+        RawOutputFormatter(PrintWriter writer) {
+            this.writer = writer;
+        }
+
+        private String pkg = "";
+        @Override
+        public void visitDependence(String origin, Archive source,
+                                    String target, Archive archive, String profile) {
+            if (!origin.equals(pkg)) {
+                pkg = origin;
+                writer.format("   %s (%s)%n", origin, source.getFileName());
+            }
+            String name = (options.showProfile && !profile.isEmpty())
+                                ? profile
+                                : getArchiveName(archive, profile);
+            writer.format("      -> %-50s %s%n", target, name);
+        }
+
+        @Override
+        public void visitArchiveDependence(Archive origin, Archive target, String profile) {
+            writer.format("%s -> %s", origin, target);
+            if (options.showProfile && !profile.isEmpty()) {
+                writer.format(" (%s)%n", profile);
+            } else {
+                writer.format("%n");
+            }
+        }
+    }
+
+    class DotFileFormatter implements Analyzer.Visitor, AutoCloseable {
+        private final PrintWriter writer;
+        private final String name;
+        DotFileFormatter(PrintWriter writer, String name) {
+            this.writer = writer;
+            this.name = name;
+            writer.format("digraph \"%s\" {%n", name);
+        }
+        DotFileFormatter(PrintWriter writer, Archive archive) {
+            this.writer = writer;
+            this.name = archive.getFileName();
+            writer.format("digraph \"%s\" {%n", name);
+            writer.format("    // Path: %s%n", archive.toString());
+        }
+
+        @Override
+        public void close() {
+            writer.println("}");
+        }
+
+        private final Set<String> edges = new HashSet<>();
+        private String node = "";
+        @Override
+        public void visitDependence(String origin, Archive source,
+                                    String target, Archive archive, String profile) {
+            if (!node.equals(origin)) {
+                edges.clear();
+                node = origin;
+            }
+            // if -P option is specified, package name -> profile will
+            // be shown and filter out multiple same edges.
+            if (!edges.contains(target)) {
+                StringBuilder sb = new StringBuilder();
+                String name = options.showProfile && !profile.isEmpty()
+                                  ? profile
+                                  : getArchiveName(archive, profile);
+                writer.format("   %-50s -> %s;%n",
+                                 String.format("\"%s\"", origin),
+                                 name.isEmpty() ? String.format("\"%s\"", target)
+                                                :  String.format("\"%s (%s)\"", target, name));
+                edges.add(target);
+            }
+        }
+
+        @Override
+        public void visitArchiveDependence(Archive origin, Archive target, String profile) {
+             String name = options.showProfile && !profile.isEmpty()
+                                ? profile : "";
+             writer.format("   %-30s -> \"%s\";%n",
+                           String.format("\"%s\"", origin.getFileName()),
+                           name.isEmpty()
+                               ? target.getFileName()
+                               : String.format("%s (%s)", target.getFileName(), name));
+        }
+    }
 }
--- a/langtools/src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java	Thu Oct 17 13:50:00 2013 +0200
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/PlatformClassPath.java	Thu Oct 17 13:19:48 2013 -0700
@@ -24,11 +24,11 @@
  */
 package com.sun.tools.jdeps;
 
-import java.io.File;
 import java.io.IOException;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.*;
@@ -38,45 +38,38 @@
  */
 class PlatformClassPath {
     private final static List<Archive> javaHomeArchives = init();
+
     static List<Archive> getArchives() {
         return javaHomeArchives;
     }
 
-    static boolean contains(Archive archive) {
-        return javaHomeArchives.contains(archive);
+    private static List<Archive> init() {
+        List<Archive> result = new ArrayList<>();
+        Path home = Paths.get(System.getProperty("java.home"));
+        try {
+            if (home.endsWith("jre")) {
+                // jar files in <javahome>/jre/lib
+                result.addAll(addJarFiles(home.resolve("lib")));
+            } else if (Files.exists(home.resolve("lib"))) {
+                // either a JRE or a jdk build image
+                Path classes = home.resolve("classes");
+                if (Files.isDirectory(classes)) {
+                    // jdk build outputdir
+                    result.add(new JDKArchive(classes, ClassFileReader.newInstance(classes)));
+                }
+                // add other JAR files
+                result.addAll(addJarFiles(home.resolve("lib")));
+            } else {
+                throw new RuntimeException("\"" + home + "\" not a JDK home");
+            }
+            return result;
+        } catch (IOException e) {
+            throw new Error(e);
+        }
     }
 
-    private static List<Archive> init() {
-        List<Archive> result = new ArrayList<Archive>();
-        String javaHome = System.getProperty("java.home");
-        File jre = new File(javaHome, "jre");
-        File lib = new File(javaHome, "lib");
-
-        try {
-            if (jre.exists() && jre.isDirectory()) {
-                result.addAll(addJarFiles(new File(jre, "lib")));
-                result.addAll(addJarFiles(lib));
-            } else if (lib.exists() && lib.isDirectory()) {
-                // either a JRE or a jdk build image
-                File classes = new File(javaHome, "classes");
-                if (classes.exists() && classes.isDirectory()) {
-                    // jdk build outputdir
-                    result.add(new Archive(classes, ClassFileReader.newInstance(classes)));
-                }
-                // add other JAR files
-                result.addAll(addJarFiles(lib));
-            } else {
-                throw new RuntimeException("\"" + javaHome + "\" not a JDK home");
-            }
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-        return result;
-    }
-
-    private static List<Archive> addJarFiles(File f) throws IOException {
-        final List<Archive> result = new ArrayList<Archive>();
-        final Path root = f.toPath();
+    private static List<Archive> addJarFiles(final Path root) throws IOException {
+        final List<Archive> result = new ArrayList<>();
         final Path ext = root.resolve("ext");
         Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
             @Override
@@ -91,17 +84,30 @@
                 }
             }
             @Override
-            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+            public FileVisitResult visitFile(Path p, BasicFileAttributes attrs)
                 throws IOException
             {
-                File f = file.toFile();
-                String fn = f.getName();
-                if (fn.endsWith(".jar") && !fn.equals("alt-rt.jar")) {
-                    result.add(new Archive(f, ClassFileReader.newInstance(f)));
+                String fn = p.getFileName().toString();
+                if (fn.endsWith(".jar")) {
+                    // JDK may cobundle with JavaFX that doesn't belong to any profile
+                    // Treat jfxrt.jar as regular Archive
+                    result.add(fn.equals("jfxrt.jar")
+                        ? new Archive(p, ClassFileReader.newInstance(p))
+                        : new JDKArchive(p, ClassFileReader.newInstance(p)));
                 }
                 return FileVisitResult.CONTINUE;
             }
         });
         return result;
     }
+
+    /**
+     * A JDK archive is part of the JDK containing the Java SE API
+     * or implementation classes (i.e. JDK internal API)
+     */
+    static class JDKArchive extends Archive {
+        JDKArchive(Path p, ClassFileReader reader) {
+            super(p, reader);
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/Profile.java	Thu Oct 17 13:19:48 2013 -0700
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.tools.jdeps;
+
+import com.sun.tools.classfile.Annotation;
+import com.sun.tools.classfile.Annotation.*;
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPool.*;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.RuntimeAnnotations_attribute;
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.jar.JarFile;
+
+/**
+ * Build the profile information from ct.sym if exists.
+ */
+enum Profile {
+
+    COMPACT1("compact1", 1),
+    COMPACT2("compact2", 2),
+    COMPACT3("compact3", 3),
+    FULL_JRE("Full JRE", 4);
+
+    final String name;
+    final int profile;
+    final Set<String> packages;
+    final Set<String> proprietaryPkgs;
+
+    Profile(String name, int profile) {
+        this.name = name;
+        this.profile = profile;
+        this.packages = new HashSet<>();
+        this.proprietaryPkgs = new HashSet<>();
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    public static int getProfileCount() {
+        return PackageToProfile.map.values().size();
+    }
+
+    /**
+     * Returns the Profile for the given package name. It returns an empty
+     * string if the given package is not in any profile.
+     */
+    public static Profile getProfile(String pn) {
+        Profile profile = PackageToProfile.map.get(pn);
+        return (profile != null && profile.packages.contains(pn))
+                ? profile : null;
+    }
+
+    static class PackageToProfile {
+        static Map<String, Profile> map = initProfiles();
+
+        private static Map<String, Profile> initProfiles() {
+            try {
+                String profilesProps = System.getProperty("jdeps.profiles");
+                if (profilesProps != null) {
+                    // for testing for JDK development build where ct.sym doesn't exist
+                    initProfilesFromProperties(profilesProps);
+                } else {
+                    Path home = Paths.get(System.getProperty("java.home"));
+                    if (home.endsWith("jre")) {
+                        home = home.getParent();
+                    }
+                    Path ctsym = home.resolve("lib").resolve("ct.sym");
+                    if (Files.exists(ctsym)) {
+                        // parse ct.sym and load information about profiles
+                        try (JarFile jf = new JarFile(ctsym.toFile())) {
+                            ClassFileReader reader = ClassFileReader.newInstance(ctsym, jf);
+                            for (ClassFile cf : reader.getClassFiles()) {
+                                findProfile(cf);
+                            }
+                        }
+                    }
+                }
+            } catch (IOException | ConstantPoolException e) {
+                throw new Error(e);
+            }
+            HashMap<String,Profile> map = new HashMap<>();
+            for (Profile profile : Profile.values()) {
+                for (String pn : profile.packages) {
+                    if (!map.containsKey(pn)) {
+                        // split packages in the JRE: use the smaller compact
+                        map.put(pn, profile);
+                    }
+                }
+                for (String pn : profile.proprietaryPkgs) {
+                    if (!map.containsKey(pn)) {
+                        map.put(pn, profile);
+                    }
+                }
+            }
+            return map;
+        }
+        private static final String PROFILE_ANNOTATION = "Ljdk/Profile+Annotation;";
+        private static final String PROPRIETARY_ANNOTATION = "Lsun/Proprietary+Annotation;";
+        private static Profile findProfile(ClassFile cf) throws ConstantPoolException {
+            RuntimeAnnotations_attribute attr = (RuntimeAnnotations_attribute)
+                cf.attributes.get(Attribute.RuntimeInvisibleAnnotations);
+            int index = 0;
+            boolean proprietary = false;
+            if (attr != null) {
+                for (int i = 0; i < attr.annotations.length; i++) {
+                    Annotation ann = attr.annotations[i];
+                    String annType = cf.constant_pool.getUTF8Value(ann.type_index);
+                    if (PROFILE_ANNOTATION.equals(annType)) {
+                        for (int j = 0; j < ann.num_element_value_pairs; j++) {
+                            Annotation.element_value_pair pair = ann.element_value_pairs[j];
+                            Primitive_element_value ev = (Primitive_element_value) pair.value;
+                            CONSTANT_Integer_info info = (CONSTANT_Integer_info)
+                                cf.constant_pool.get(ev.const_value_index);
+                            index = info.value;
+                            break;
+                        }
+                    } else if (PROPRIETARY_ANNOTATION.equals(annType)) {
+                        proprietary = true;
+                    }
+                }
+            }
+
+            Profile p = null;  // default
+            switch (index) {
+                case 1:
+                    p = Profile.COMPACT1; break;
+                case 2:
+                    p = Profile.COMPACT2; break;
+                case 3:
+                    p = Profile.COMPACT3; break;
+                case 4:
+                    p = Profile.FULL_JRE; break;
+                default:
+                    // skip classes with profile=0
+                    // Inner classes are not annotated with the profile annotation
+                    return null;
+            }
+
+            String name = cf.getName();
+            int i = name.lastIndexOf('/');
+            name = (i > 0) ? name.substring(0, i).replace('/', '.') : "";
+            if (proprietary) {
+                p.proprietaryPkgs.add(name);
+            } else {
+                p.packages.add(name);
+            }
+            return p;
+        }
+
+        private static void initProfilesFromProperties(String path) throws IOException {
+            Properties props = new Properties();
+            try (FileReader reader = new FileReader(path)) {
+                props.load(reader);
+            }
+            for (Profile prof : Profile.values()) {
+                int i = prof.profile;
+                String key = props.getProperty("profile." + i + ".name");
+                if (key == null) {
+                    throw new RuntimeException(key + " missing in " + path);
+                }
+                String n = props.getProperty("profile." + i + ".packages");
+                String[] pkgs = n.split("\\s+");
+                for (String p : pkgs) {
+                    if (p.isEmpty()) continue;
+                    prof.packages.add(p);
+                }
+            }
+        }
+    }
+
+    // for debugging
+    public static void main(String[] args) {
+        if (args.length == 0) {
+            if (Profile.getProfileCount() == 0) {
+                System.err.println("No profile is present in this JDK");
+            }
+            for (Profile p : Profile.values()) {
+                String profileName = p.name;
+                SortedSet<String> set = new TreeSet<>(p.packages);
+                for (String s : set) {
+                    // filter out the inner classes that are not annotated with
+                    // the profile annotation
+                    if (PackageToProfile.map.get(s) == p) {
+                        System.out.format("%2d: %-10s  %s%n", p.profile, profileName, s);
+                        profileName = "";
+                    } else {
+                        System.err.format("Split package: %s in %s and %s %n",
+                            s, PackageToProfile.map.get(s).name, p.name);
+                    }
+                }
+            }
+        }
+        for (String pn : args) {
+            System.out.format("%s in %s%n", pn, getProfile(pn));
+        }
+    }
+}
--- a/langtools/src/share/classes/com/sun/tools/jdeps/Profiles.java	Thu Oct 17 13:50:00 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,241 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.sun.tools.jdeps;
-
-import com.sun.tools.classfile.Annotation;
-import com.sun.tools.classfile.Annotation.*;
-import com.sun.tools.classfile.Attribute;
-import com.sun.tools.classfile.ClassFile;
-import com.sun.tools.classfile.ConstantPool;
-import com.sun.tools.classfile.ConstantPool.*;
-import com.sun.tools.classfile.ConstantPoolException;
-import com.sun.tools.classfile.RuntimeAnnotations_attribute;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.*;
-import java.util.jar.JarFile;
-
-/**
- * Build the profile information from ct.sym if exists.
- */
-class Profiles {
-    private static final Map<String,Profile> map = initProfiles();
-    /**
-     * Returns the name of the profile for the given package name.
-     * It returns an empty string if the given package is not in any profile.
-     */
-    public static String getProfileName(String pn) {
-        Profile profile = map.get(pn);
-        return (profile != null && profile.packages.contains(pn))
-                    ? profile.name : "";
-    }
-
-    public static int getProfileCount() {
-        return new HashSet<Profile>(map.values()).size();
-    }
-
-    private static Map<String,Profile> initProfiles() {
-        List<Profile> profiles = new ArrayList<Profile>();
-        try {
-            String profilesProps = System.getProperty("jdeps.profiles");
-            if (profilesProps != null) {
-                // for testing for JDK development build where ct.sym doesn't exist
-                initProfilesFromProperties(profiles, profilesProps);
-            } else {
-                Path home = Paths.get(System.getProperty("java.home"));
-                if (home.endsWith("jre")) {
-                    home = home.getParent();
-                }
-                Path ctsym = home.resolve("lib").resolve("ct.sym");
-                if (ctsym.toFile().exists()) {
-                    // add a default Full JRE
-                    profiles.add(0, new Profile("Full JRE", 0));
-                    // parse ct.sym and load information about profiles
-                    try (JarFile jf = new JarFile(ctsym.toFile())) {
-                        ClassFileReader reader = ClassFileReader.newInstance(ctsym, jf);
-                        for (ClassFile cf : reader.getClassFiles()) {
-                            findProfile(profiles, cf);
-                        }
-                    }
-
-                    // merge the last Profile with the "Full JRE"
-                    if (profiles.size() > 1) {
-                        Profile fullJRE = profiles.get(0);
-                        Profile p = profiles.remove(profiles.size() - 1);
-                        for (String pn : fullJRE.packages) {
-                            // The last profile contains the packages determined from ct.sym.
-                            // Move classes annotated profile==0 or no attribute that are
-                            // added in the fullJRE profile to either supported or proprietary
-                            // packages appropriately
-                            if (p.proprietaryPkgs.contains(pn)) {
-                                p.proprietaryPkgs.add(pn);
-                            } else {
-                                p.packages.add(pn);
-                            }
-                        }
-                        fullJRE.packages.clear();
-                        fullJRE.proprietaryPkgs.clear();
-                        fullJRE.packages.addAll(p.packages);
-                        fullJRE.proprietaryPkgs.addAll(p.proprietaryPkgs);
-                    }
-                }
-            }
-        } catch (IOException | ConstantPoolException e) {
-            throw new Error(e);
-        }
-        HashMap<String,Profile> map = new HashMap<String,Profile>();
-        for (Profile profile : profiles) {
-            // Inner classes are not annotated with the profile annotation
-            // packages may be in one profile but also appear in the Full JRE
-            // Full JRE is always the first element in profiles list and
-            // so the map will contain the appropriate Profile
-            for (String pn : profile.packages) {
-                map.put(pn, profile);
-            }
-            for (String pn : profile.proprietaryPkgs) {
-                map.put(pn, profile);
-            }
-        }
-        return map;
-    }
-
-    private static final String PROFILE_ANNOTATION = "Ljdk/Profile+Annotation;";
-    private static final String PROPRIETARY_ANNOTATION = "Lsun/Proprietary+Annotation;";
-    private static Profile findProfile(List<Profile> profiles, ClassFile cf)
-            throws ConstantPoolException
-    {
-        RuntimeAnnotations_attribute attr = (RuntimeAnnotations_attribute)
-            cf.attributes.get(Attribute.RuntimeInvisibleAnnotations);
-        int index = 0;
-        boolean proprietary = false;
-        if (attr != null) {
-            for (int i = 0; i < attr.annotations.length; i++) {
-                Annotation ann = attr.annotations[i];
-                String annType = cf.constant_pool.getUTF8Value(ann.type_index);
-                if (PROFILE_ANNOTATION.equals(annType)) {
-                    for (int j = 0; j < ann.num_element_value_pairs; j++) {
-                        Annotation.element_value_pair pair = ann.element_value_pairs[j];
-                        Primitive_element_value ev = (Primitive_element_value)pair.value;
-                        CONSTANT_Integer_info info = (CONSTANT_Integer_info)
-                             cf.constant_pool.get(ev.const_value_index);
-                        index = info.value;
-                        break;
-                    }
-                } else if (PROPRIETARY_ANNOTATION.equals(annType)) {
-                    proprietary = true;
-                }
-            }
-            if (index >= profiles.size()) {
-                Profile p = null;
-                for (int i = profiles.size(); i <= index; i++) {
-                    p = new Profile(i);
-                    profiles.add(p);
-                }
-            }
-        }
-
-        Profile p = profiles.get(index);
-        String name = cf.getName();
-        int i = name.lastIndexOf('/');
-        name = (i > 0) ? name.substring(0, i).replace('/','.') : "";
-        if (proprietary) {
-            p.proprietaryPkgs.add(name);
-        } else {
-            p.packages.add(name);
-        }
-        return p;
-    }
-
-    private static void initProfilesFromProperties(List<Profile> profiles, String path)
-            throws IOException
-    {
-        Properties props = new Properties();
-        try (FileReader reader = new FileReader(path)) {
-            props.load(reader);
-        }
-        int i=1;
-        String key;
-        while (props.containsKey((key = "profile." + i + ".name"))) {
-            Profile profile = new Profile(props.getProperty(key), i);
-            profiles.add(profile);
-            String n = props.getProperty("profile." + i + ".packages");
-            String[] pkgs = n.split("\\s+");
-            for (String p : pkgs) {
-                if (p.isEmpty()) continue;
-                profile.packages.add(p);
-            }
-            i++;
-        }
-    }
-
-    private static class Profile {
-        final String name;
-        final int profile;
-        final Set<String> packages;
-        final Set<String> proprietaryPkgs;
-        Profile(int profile) {
-            this("compact" + profile, profile);
-        }
-        Profile(String name, int profile) {
-            this.name = name;
-            this.profile = profile;
-            this.packages = new HashSet<String>();
-            this.proprietaryPkgs = new HashSet<String>();
-        }
-        public String toString() {
-            return name;
-        }
-    }
-
-    // for debugging
-    public static void main(String[] args) {
-        if (args.length == 0) {
-            Profile[] profiles = new Profile[getProfileCount()];
-            for (Profile p : map.values()) {
-                // move the zeroth profile to the last
-                int index = p.profile == 0 ? profiles.length-1 : p.profile-1;
-                profiles[index] = p;
-            }
-            for (Profile p : profiles) {
-                String profileName = p.name;
-                SortedSet<String> set = new TreeSet<String>(p.packages);
-                for (String s : set) {
-                    // filter out the inner classes that are not annotated with
-                    // the profile annotation
-                    if (map.get(s) == p) {
-                        System.out.format("%-10s  %s%n", profileName, s);
-                        profileName = "";
-                    }
-                }
-            }
-        }
-        for (String pn : args) {
-            System.out.format("%s in %s%n", pn, getProfileName(pn));
-        }
-    }
-}
--- a/langtools/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Thu Oct 17 13:50:00 2013 +0200
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Thu Oct 17 13:19:48 2013 -0700
@@ -5,46 +5,63 @@
 main.usage=\
 Usage: {0} <options> <classes...>\n\
 where <classes> can be a pathname to a .class file, a directory, a JAR file,\n\
-or a fully-qualified classname or wildcard "*".  Possible options include:
+or a fully-qualified class name.  Possible options include:
 
 error.prefix=Error:
 warn.prefix=Warning:
 
 main.opt.h=\
-\  -h -?      --help                    Print this usage message
+\  -h -?        -help                 Print this usage message
 
 main.opt.version=\
-\             --version                 Version information
-
-main.opt.V=\
-\  -V <level> --verbose-level=<level>   Print package-level or class-level dependencies\n\
-\                                       Valid levels are: "package" and "class"
+\  -version                           Version information
 
 main.opt.v=\
-\  -v         --verbose                 Print additional information
+\  -v           -verbose              Print all class level dependencies\n\
+\  -verbose:package                   Print package-level dependencies excluding\n\
+\                                     dependencies within the same archive\n\
+\  -verbose:class                     Print class-level dependencies excluding\n\
+\                                     dependencies within the same archive
 
 main.opt.s=\
-\  -s         --summary                 Print dependency summary only
+\  -s           -summary              Print dependency summary only
 
 main.opt.p=\
-\  -p <pkg name> --package=<pkg name>   Restrict analysis to classes in this package\n\
-\                                       (may be given multiple times)
+\  -p <pkgname> -package <pkgname>    Finds dependences in the given package\n\
+\                                     (may be given multiple times)
 
 main.opt.e=\
-\  -e <regex> --regex=<regex>           Restrict analysis to packages matching pattern\n\
-\                                       (-p and -e are exclusive)
+\  -e <regex>   -regex <regex>        Finds dependences in packages matching pattern\n\
+\                                     (-p and -e are exclusive)
+
+main.opt.include=\
+\  -include <regex>                   Restrict analysis to classes matching pattern\n\
+\                                     This option filters the list of classes to\n\
+\                                     be analyzed.  It can be used together with\n\
+\                                     -p and -e which apply pattern to the dependences
 
 main.opt.P=\
-\  -P         --profile                 Show profile or the file containing a package
+\  -P           -profile              Show profile or the file containing a package
 
-main.opt.c=\
-\  -c <path>  --classpath=<path>        Specify where to find class files
+main.opt.cp=\
+\  -cp <path>   -classpath <path>     Specify where to find class files
 
 main.opt.R=\
-\  -R         --recursive               Recursively traverse all dependencies
+\  -R           -recursive            Recursively traverse all dependencies
 
-main.opt.d=\
-\  -d <depth> --depth=<depth>           Specify the depth of the transitive dependency analysis
+main.opt.apionly=\
+\  -apionly                           Restrict analysis to APIs i.e. dependences\n\
+\                                     from the signature of public and protected\n\
+\                                     members of public classes including field\n\
+\                                     type, method parameter types, returned type,\n\
+\                                     checked exception types etc
+
+main.opt.dotoutput=\
+\  -dotoutput <dir>                   Destination directory for DOT file output
+
+main.opt.depth=\
+\  -depth=<depth>                     Specify the depth of the transitive\n\
+\                                     dependency analysis
 
 err.unknown.option=unknown option: {0}
 err.missing.arg=no value given for {0}
@@ -53,6 +70,7 @@
 err.option.after.class=option must be specified before classes: {0}
 err.option.unsupported={0} not supported: {1}
 err.profiles.msg=No profile information
+err.dot.output.path=invalid path: {0}
 warn.invalid.arg=Invalid classname or pathname not exist: {0}
 warn.split.package=package {0} defined in {1} {2}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/APIDeps.java	Thu Oct 17 13:19:48 2013 -0700
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8015912
+ * @summary find API dependencies
+ * @build m.Bar m.Foo m.Gee b.B c.C c.I d.D e.E f.F g.G
+ * @run main APIDeps
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.regex.*;
+
+public class APIDeps {
+    private static boolean symbolFileExist = initProfiles();
+    private static boolean initProfiles() {
+        // check if ct.sym exists; if not use the profiles.properties file
+        Path home = Paths.get(System.getProperty("java.home"));
+        if (home.endsWith("jre")) {
+            home = home.getParent();
+        }
+        Path ctsym = home.resolve("lib").resolve("ct.sym");
+        boolean symbolExists = ctsym.toFile().exists();
+        if (!symbolExists) {
+            Path testSrcProfiles =
+                Paths.get(System.getProperty("test.src", "."), "profiles.properties");
+            if (!testSrcProfiles.toFile().exists())
+                throw new Error(testSrcProfiles + " does not exist");
+            System.out.format("%s doesn't exist.%nUse %s to initialize profiles info%n",
+                ctsym, testSrcProfiles);
+            System.setProperty("jdeps.profiles", testSrcProfiles.toString());
+        }
+        return symbolExists;
+    }
+
+    public static void main(String... args) throws Exception {
+        int errors = 0;
+        errors += new APIDeps().run();
+        if (errors > 0)
+            throw new Exception(errors + " errors found");
+    }
+
+    int run() throws IOException {
+        File testDir = new File(System.getProperty("test.classes", "."));
+        String testDirBasename = testDir.toPath().getFileName().toString();
+        File mDir = new File(testDir, "m");
+        // all dependencies
+        test(new File(mDir, "Bar.class"),
+             new String[] {"java.lang.Object", "java.lang.String",
+                           "java.util.Set", "java.util.HashSet",
+                           "java.lang.management.ManagementFactory",
+                           "java.lang.management.RuntimeMXBean",
+                           "b.B", "c.C", "d.D", "f.F", "g.G"},
+             new String[] {"compact1", "compact3", testDirBasename},
+             new String[] {"-classpath", testDir.getPath(), "-verbose", "-P"});
+        test(new File(mDir, "Foo.class"),
+             new String[] {"c.I", "e.E", "f.F", "m.Bar"},
+             new String[] {testDirBasename},
+             new String[] {"-classpath", testDir.getPath(), "-verbose", "-P"});
+        test(new File(mDir, "Gee.class"),
+             new String[] {"g.G", "sun.misc.Lock"},
+             new String[] {testDirBasename, "JDK internal API"},
+             new String[] {"-classpath", testDir.getPath(), "-verbose"});
+        // parse only APIs
+        test(mDir,
+             new String[] {"java.lang.Object", "java.lang.String",
+                           "java.util.Set",
+                           "c.C", "d.D", "c.I", "e.E", "m.Bar"},
+             new String[] {"compact1", testDirBasename, mDir.getName()},
+             new String[] {"-classpath", testDir.getPath(), "-verbose", "-P", "-apionly"});
+        return errors;
+    }
+
+    void test(File file, String[] expect, String[] profiles) {
+        test(file, expect, profiles, new String[0]);
+    }
+
+    void test(File file, String[] expect, String[] profiles, String[] options) {
+        List<String> args = new ArrayList<>(Arrays.asList(options));
+        if (file != null) {
+            args.add(file.getPath());
+        }
+        checkResult("api-dependencies", expect, profiles,
+                    jdeps(args.toArray(new String[0])));
+    }
+
+    Map<String,String> jdeps(String... args) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        System.err.println("jdeps " + Arrays.toString(args));
+        int rc = com.sun.tools.jdeps.Main.run(args, pw);
+        pw.close();
+        String out = sw.toString();
+        if (!out.isEmpty())
+            System.err.println(out);
+        if (rc != 0)
+            throw new Error("jdeps failed: rc=" + rc);
+        return findDeps(out);
+    }
+
+    // Pattern used to parse lines
+    private static Pattern linePattern = Pattern.compile(".*\r?\n");
+    private static Pattern pattern = Pattern.compile("\\s+ -> (\\S+) +(.*)");
+
+    // Use the linePattern to break the given String into lines, applying
+    // the pattern to each line to see if we have a match
+    private static Map<String,String> findDeps(String out) {
+        Map<String,String> result = new HashMap<>();
+        Matcher lm = linePattern.matcher(out);  // Line matcher
+        Matcher pm = null;                      // Pattern matcher
+        int lines = 0;
+        while (lm.find()) {
+            lines++;
+            CharSequence cs = lm.group();       // The current line
+            if (pm == null)
+                pm = pattern.matcher(cs);
+            else
+                pm.reset(cs);
+            if (pm.find())
+                result.put(pm.group(1), pm.group(2).trim());
+            if (lm.end() == out.length())
+                break;
+        }
+        return result;
+    }
+
+    void checkResult(String label, String[] expect, Collection<String> found) {
+        List<String> list = Arrays.asList(expect);
+        if (!isEqual(list, found))
+            error("Unexpected " + label + " found: '" + found + "', expected: '" + list + "'");
+    }
+
+    void checkResult(String label, String[] expect, String[] profiles, Map<String,String> result) {
+        // check the dependencies
+        checkResult(label, expect, result.keySet());
+        // check profile information
+        Set<String> values = new TreeSet<>();
+        String internal = "JDK internal API";
+        for (String s: result.values()) {
+            if (s.startsWith(internal)){
+                values.add(internal);
+            } else {
+                values.add(s);
+            }
+        }
+        checkResult(label, profiles, values);
+    }
+
+    boolean isEqual(List<String> expected, Collection<String> found) {
+        if (expected.size() != found.size())
+            return false;
+
+        List<String> list = new ArrayList<>(found);
+        list.removeAll(expected);
+        return list.isEmpty();
+    }
+
+    void error(String msg) {
+        System.err.println("Error: " + msg);
+        errors++;
+    }
+
+    int errors;
+}
--- a/langtools/test/tools/jdeps/Basic.java	Thu Oct 17 13:50:00 2013 +0200
+++ b/langtools/test/tools/jdeps/Basic.java	Thu Oct 17 13:19:48 2013 -0700
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8003562 8005428
+ * @bug 8003562 8005428 8015912
  * @summary Basic tests for jdeps tool
  * @build Test p.Foo
  * @run main Basic
@@ -79,40 +79,33 @@
              new String[] {"compact1", "compact1", "compact3"});
         // test class-level dependency output
         test(new File(testDir, "Test.class"),
-             new String[] {"java.lang.Object", "p.Foo"},
-             new String[] {"compact1", "not found"},
-             new String[] {"-V", "class"});
+             new String[] {"java.lang.Object", "java.lang.String", "p.Foo"},
+             new String[] {"compact1", "compact1", "not found"},
+             new String[] {"-verbose:class"});
         // test -p option
         test(new File(testDir, "Test.class"),
              new String[] {"p.Foo"},
              new String[] {"not found"},
-             new String[] {"--verbose-level=class", "-p", "p"});
+             new String[] {"-verbose:class", "-p", "p"});
         // test -e option
         test(new File(testDir, "Test.class"),
              new String[] {"p.Foo"},
              new String[] {"not found"},
-             new String[] {"-V", "class", "-e", "p\\..*"});
+             new String[] {"-verbose:class", "-e", "p\\..*"});
         test(new File(testDir, "Test.class"),
              new String[] {"java.lang"},
              new String[] {"compact1"},
-             new String[] {"-V", "package", "-e", "java\\.lang\\..*"});
-        // test -classpath and wildcard options
+             new String[] {"-verbose:package", "-e", "java\\.lang\\..*"});
+        // test -classpath and -include options
         test(null,
-             new String[] {"com.sun.tools.jdeps", "java.lang", "java.util",
-                           "java.util.regex", "java.io", "java.nio.file",
+             new String[] {"java.lang", "java.util",
                            "java.lang.management"},
-             new String[] {(symbolFileExist? "not found" : "JDK internal API (classes)"),
-                           "compact1", "compact1", "compact1",
-                           "compact1", "compact1", "compact3"},
-             new String[] {"--classpath", testDir.getPath(), "*"});
-        /* Temporary disable this test case.  Test.class has a dependency
-         * on java.lang.String on certain windows machine (8008479).
-         // -v shows intra-dependency
-         test(new File(testDir, "Test.class"),
-              new String[] {"java.lang.Object", "p.Foo"},
-              new String[] {"compact1", testDir.getName()},
-              new String[] {"-v", "--classpath", testDir.getPath(), "Test.class"});
-        */
+             new String[] {"compact1", "compact1", "compact3"},
+             new String[] {"-classpath", testDir.getPath(), "-include", "p.+|Test.class"});
+        test(new File(testDir, "Test.class"),
+             new String[] {"java.lang.Object", "java.lang.String", "p.Foo"},
+             new String[] {"compact1", "compact1", testDir.getName()},
+             new String[] {"-v", "-classpath", testDir.getPath(), "Test.class"});
         return errors;
     }
 
--- a/langtools/test/tools/jdeps/Test.java	Thu Oct 17 13:50:00 2013 +0200
+++ b/langtools/test/tools/jdeps/Test.java	Thu Oct 17 13:19:48 2013 -0700
@@ -25,4 +25,7 @@
     public void test() {
         p.Foo f = new p.Foo();
     }
+    private String name() {
+        return "this test";
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/b/B.java	Thu Oct 17 13:19:48 2013 -0700
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package b;
+
+import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({TYPE, METHOD, FIELD})
+public @interface B {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/c/C.java	Thu Oct 17 13:19:48 2013 -0700
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package c;
+
+public class C {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/c/I.java	Thu Oct 17 13:19:48 2013 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package c;
+
+public interface I {
+    void run();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/d/D.java	Thu Oct 17 13:19:48 2013 -0700
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package d;
+
+public class D {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/e/E.java	Thu Oct 17 13:19:48 2013 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package e;
+
+// use compact2
+public class E extends java.rmi.RemoteException {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/f/F.java	Thu Oct 17 13:19:48 2013 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package f;
+
+public class F {
+    public F() {
+        // jdk internal API
+        sun.misc.Unsafe.getUnsafe();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/g/G.java	Thu Oct 17 13:19:48 2013 -0700
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package g;
+
+public class G {
+    // Full JRE
+    private static final boolean gui = java.beans.Beans.isGuiAvailable();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/m/Bar.java	Thu Oct 17 13:19:48 2013 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package m;
+
+import java.util.*;
+
+@b.B
+public class Bar {
+    public final Set<String> set = new HashSet<>();
+    protected d.D d;
+    private f.F f;
+
+    public Bar() {
+        // compact3
+        java.lang.management.ManagementFactory.getRuntimeMXBean();
+    }
+
+    protected c.C c() {
+        return new c.C();
+    }
+
+    /* package private */ void setF(f.F o) {
+        f = o;
+    }
+
+    private g.G g() {
+        return new g.G();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/m/Foo.java	Thu Oct 17 13:19:48 2013 -0700
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package m;
+
+public class Foo extends Bar implements c.I {
+   public void foo() throws e.E {
+   }
+   public void run() {
+      setF(new f.F());
+   }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/m/Gee.java	Thu Oct 17 13:19:48 2013 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package m;
+
+
+class Gee extends g.G {
+    public sun.misc.Lock lock;
+}
+