--- old/src/share/classes/sun/module/tools/JRepo.java	Tue Jul  8 18:11:44 2008
+++ new/src/share/classes/sun/module/tools/JRepo.java	Tue Jul  8 18:11:44 2008
@@ -30,6 +30,7 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.io.PrintStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -36,16 +37,20 @@
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.module.*;
+import java.module.annotation.ImportPolicyClass;
 import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.text.DateFormat;
 import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import sun.module.JamUtils;
+import java.util.Set;
 import sun.module.repository.RepositoryConfig;
 import sun.security.action.GetPropertyAction;
 import sun.tools.jar.CommandLine;
@@ -77,12 +82,18 @@
     /** Usage message created from each command's usage. */
     private static String usage = null;
 
-    /** Format for module name & version. */
+    /** Format for ModuleArchiveInfo name & version. */
     private static final String MAIFormat = "%-20s %-20s";
 
-    /** Format for additional/verbose module information. */
+    /** Format for additional/verbose ModuleArchiveInfo details. */
     private static final String MAIFormatVerbose = " %-9s %-7s %-17s %s";
 
+    /** Format for ModuleDefinition name & version. */
+    private static final String MDFormat = "%s-%s";
+
+    /** Format for additional/verbose ModuleDefinition details. */
+    private static final String MDFormatVerbose = " %s";
+
     /** String containing column headings for name & version. */
     private static final String maiHeading;
 
@@ -98,6 +109,12 @@
     /** Location of repository; if not given uses system repository. */
     private static final RepositoryFlag repositoryFlag = new RepositoryFlag();
 
+    /** Indicates dependencies command should display info on core modules. */
+    private static final Flag javaseFlag = new Flag('j');
+
+    /** Provides way to specify platform binding fo dependencies command. */
+    private static final BindingFlag bindingFlag = new BindingFlag();
+
     /** Contains the flags that are common to all commands. */
     private static final HashMap<Character, Flag> commonFlags = new HashMap<Character, Flag>();
 
@@ -117,6 +134,10 @@
         maiHeadingVerbose = sw.toString();
     }
 
+    public JRepo(OutputStream out, OutputStream err, BufferedReader reader) {
+        this(new PrintStream(out), new PrintStream(err), reader);
+    }
+
     public JRepo(PrintStream out, PrintStream err, BufferedReader reader) {
         msg = new Messenger("jrepo", out, err, reader);
         synchronized(commands) {
@@ -124,6 +145,7 @@
                 new ListCommand().register(commands);
                 new InstallCommand().register(commands);
                 new UninstallCommand().register(commands);
+                new DependenciesCommand().register(commands);
             }
         }
         reset();
@@ -187,7 +209,8 @@
                         "jrepo",
                         f.getCanonicalFile());
                 } else {
-                    throw new IOException("Cannot access repository at " + repositoryLocation);
+                    throw new IOException("Cannot access repository at " // XXX i18n
+                                          + repositoryLocation); 
                 }
             }
         }
@@ -260,18 +283,18 @@
 
 
     /** Returns a user-grokkable description of the repository. */
-    private String getRepositoryText(Repository repo) {
+    private static String getRepositoryText(Repository repo) {
         String rc;
         URL u = repo.getSourceLocation();
         if (u == null) {
             rc = "Bootstrap repository";
         } else {
-            rc = "Repository " + u.toExternalForm();
+                        rc = "Repository '" + repo.getName() + "' at " + u.toExternalForm();
         }
         return rc;
     }
 
-    private String getMAIText(ModuleArchiveInfo mai) {
+    private static String getMAIText(ModuleArchiveInfo mai) {
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
         pw.printf(MAIFormat, mai.getName(), mai.getVersion());
@@ -291,6 +314,22 @@
         return sw.toString();
     }
 
+    private static String getMText(Module m) {
+        return getMDText(m.getModuleDefinition());
+    }
+    
+    private static String getMDText(ModuleDefinition md) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        pw.printf(MDFormat, md.getName(), md.getVersion());
+        if (verboseFlag.isEnabled()) {
+            URL srcLoc = md.getRepository().getSourceLocation();
+            pw.printf(MDFormatVerbose,
+                      srcLoc == null ? "bootstrap" : srcLoc.toString());
+        }
+        return sw.toString();
+    }
+
     void usageError() {
         usageError(msg);
     }
@@ -298,7 +337,7 @@
     static void usageError(Messenger msg) {
         if (usage == null) {
             StringBuilder ub = new StringBuilder(
-                "Usage: jrepo <command>\nwhere <command> includes:");
+                "Usage: jrepo <command>\nwhere <command> includes:"); // XXX i18n
             for (Command c : commands.values()) {
                 String u = c.usage();
                 if (u != null) {
@@ -313,7 +352,7 @@
     /**
      * Represents a flag given on the command line.  Flags always are 2
      * characters long, and start with a '-'.  They can have additional
-     * associated arguments (cf RepositoryFlag).
+     * associated arguments (cf {@link #RepositoryFlag}).
      */
     private static class Flag {
         private final char name;
@@ -336,7 +375,7 @@
         }
 
         /** @return the number of arguments consumed by this Flag. */
-        int set(String[] args, int pos) {
+        int set(String[] args, int pos) throws IllegalArgumentException {
             enabled = true;
             return 1;
         }
@@ -361,7 +400,8 @@
             super('r');
         }
 
-        int set(String[] args, int pos) {
+        @Override
+        int set(String[] args, int pos) throws IllegalArgumentException {
             int rc = super.set(args, pos);
             location = args[pos + 1];
             return rc + 1;
@@ -371,6 +411,7 @@
             return location;
         }
 
+        @Override
         void reset() {
             super.reset();
             location = null;
@@ -377,6 +418,43 @@
         }
     }
 
+    private static class BindingFlag extends Flag {
+        String platform;
+        String arch;
+
+        BindingFlag() {
+            super('b');
+        }
+
+        @Override
+        int set(String[] args, int pos) throws IllegalArgumentException {
+            int rc = super.set(args, pos);
+            String[] binding = args[pos + 1].split("-");
+            if (binding.length != 2) {
+                throw new IllegalArgumentException(
+                    "Must 2 and only 2 elements for platform-arch");
+            }
+            platform = binding[0];
+            arch = binding[1];
+            return rc + 1;
+        }
+
+        String getPlatform() {
+            return platform;
+        }
+
+        String getArch() {
+            return arch;
+        }
+
+        @Override
+        void reset() {
+            super.reset();
+            platform = null;
+            arch = null;
+        }
+    }
+
     /*
      * Command types: An abstract base class, plus one concrete class for
      * each Command.
@@ -424,7 +502,8 @@
                         i += numConsumed;  // Increases at each iteration.
                         rc += numConsumed; // Increases only when the arg is a flag.
                     } else {
-                        throw new IllegalArgumentException("unrecognized flag: " + args[i]);
+                        throw new IllegalArgumentException("unrecognized flag: " // XXX i18n
+                                                           + args[i]);
                     }
                 } else {
                     i++;
@@ -441,6 +520,7 @@
          */
         abstract String usage();
 
+        @Override
         public String toString() { return name; }
 
         /**
@@ -453,9 +533,9 @@
         abstract class RepositoryVisitor {
             abstract void doit(Repository repo, Messenger msg);
 
-            void doBefore(Messenger msg) { }
+            void preVisit(Messenger msg) { }
 
-            void doAfter(Messenger msg) { }
+            void postVisit(Messenger msg) { }
 
             final void run(Repository repo, Messenger msg) {
                 visit(repo, msg);
@@ -466,13 +546,179 @@
                 if (parent != null) {
                     visit(parent, msg);
                 }
-                doBefore(msg);
+                preVisit(msg);
                 doit(repo, msg);
-                doAfter(msg);
+                postVisit(msg);
             }
         }
     }
 
+
+    /** Lists dependencies of a module. */
+    private class DependenciesCommand extends Command {
+        @SuppressWarnings("unchecked")
+        private final Map<Character, Flag> myFlags = (Map<Character, Flag>) commonFlags.clone();
+
+        private String name;
+        private Version version;
+
+        // For printing module name, version.
+        private String moduleString;
+
+        DependenciesCommand() {
+            super("dependencies");
+            javaseFlag.register(myFlags);
+            bindingFlag.register(myFlags);
+        }
+
+        @Override
+        void reset() {
+            javaseFlag.reset();
+            bindingFlag.reset();
+        }
+        
+        @Override
+        int parseFlags(String[] args, Map<Character, Flag> flags) {
+            return super.parseFlags(args, myFlags);
+        }
+
+        boolean parseArgs(String[] args, Messenger msg) {
+            if (args.length > 0) {
+                name = args[0];
+            }
+            if (args.length > 1) {
+                try {
+                    version = Version.valueOf(args[1]);
+                } catch (IllegalArgumentException ex) {
+                    return false;
+                }
+            }
+            if (args.length > 2) {
+                return false;
+            }
+            
+            if (DEBUG) debug("name: " + name + " ver: " + version
+                             + " plat: " + bindingFlag.getPlatform()
+                             + " arch: " + bindingFlag.getArch());
+            return true;
+        }
+
+        boolean run(Repository repo, Messenger msg) {
+            boolean rc = true;
+            if (name != null) {
+                VersionConstraint vc = (version == null
+                                        ? VersionConstraint.DEFAULT
+                                        : version.toVersionConstraint());
+                printHeader(name, vc);
+                rc = depend(repo, name, vc,
+                            bindingFlag.getPlatform(), bindingFlag.getArch());
+                printTrailer(null);
+            } else {
+                for (ModuleArchiveInfo mai : repo.list()) {
+                    reset();
+                    String maiName = mai.getName();
+                    VersionConstraint vc = mai.getVersion().toVersionConstraint();
+                    printHeader(maiName, vc);
+                    rc &= depend(repo, maiName, vc,
+                                 mai.getPlatform(), mai.getArch());
+                    printTrailer("\n");
+                }
+            }
+            return rc;
+        }
+
+        boolean depend(Repository repo, String name, VersionConstraint constraint,
+                       String platform, String arch) {
+            ImportTraverser iv = new JRepoImportTraverser(msg);
+            try {
+                iv.visit(repo, name, constraint, platform, arch);
+                for (Module dep : iv) {
+                    // If any modules were found, traversal was successful
+                    return true;
+                }
+                if (verboseFlag.isEnabled()) {
+                    msg.error("Cannot find module " + name + " in " // XXX i18n
+                              + getRepositoryText(repo));
+                }
+                return false;
+            } catch (ModuleInitializationException ex) {
+                msg.error("Cannot instantiate module for " + name // XXX i18n
+                          + ": " + ex);
+                return false;
+            }
+        }
+
+        
+        void printHeader(String name, VersionConstraint vc) {
+            if (verboseFlag.isEnabled()) {
+                msg.println("Dependencies for " // XXXi18n
+                            + name + "-" + vc + ":");
+            }
+        }
+
+        void printTrailer(String s) {
+            if (verboseFlag.isEnabled()) {
+                msg.print(s);
+            }
+        }
+        
+        // TBD support platform binding.  Ideally, want to allow specifying
+        // version, or binding, or both.
+        String usage() {
+            return "dependencies [-v] [-r repositoryLocation] [-b platform-arch]"// XXX i18n
+                + " [moduleName [moduleVersion] ]\n"
+                + "        Lists all modules on which identified modules depend.\n"
+                + "        If no moduleName is given, lists dependencies of all"
+                + " modules in the repository.";
+        }
+    }
+            
+
+    private static class JRepoImportTraverser extends ImportTraverser {
+        private final Messenger msg;
+        
+        private String indent = "";
+
+        JRepoImportTraverser(Messenger msg) {
+            this.msg = msg;
+        }
+
+        @Override
+        protected void init(Module m) {
+            printModule(m);
+        }
+
+        @Override
+        protected boolean preVisit(Module m) {
+            if (javaseFlag.isEnabled() == false
+                && "java.se".equals(m.getModuleDefinition().getName())) {
+                return false;
+            } else {
+                indent += "    ";
+                return true;
+            }
+        }
+
+        @Override
+        protected void visit(Module m) {
+            printModule(m);
+        }
+
+        @Override
+        protected void postVisit(Module m) {
+            if (javaseFlag.isEnabled() == false
+                && "java.se".equals(m.getModuleDefinition().getName())) {
+                // empty
+            } else {
+                indent = indent.substring(4);
+            }
+        }
+
+        void printModule(Module m) {
+            msg.println(indent + getMText(m));
+        }
+    }
+
     /** Installs a JAM into a repository. */
     private class InstallCommand extends Command {
         private String jamName;
@@ -528,7 +774,7 @@
         }
 
         String usage() {
-            return "install [-v] -r repositoryLocation jamFile | jamURL\n"
+            return "install [-v] -r repositoryLocation jamFile | jamURL\n" // XXX i18n
                 +  "        installs a module into a repository";
         }
     }
@@ -554,6 +800,7 @@
             interactiveFlag.register(myFlags);
         }
 
+        @Override
         void reset() {
             version = null;
             platformBinding = null;
@@ -561,6 +808,7 @@
             interactiveFlag.reset();
         }
 
+        @Override
         int parseFlags(String[] args, Map<Character, Flag> flags) {
             return super.parseFlags(args, myFlags);
         }
@@ -647,7 +895,8 @@
         }
 
         String usage() {
-            return "uninstall [-v] [-f | -i] -r repositoryLocation moduleName [moduleVersion] [modulePlatformBinding]\n"
+            return "uninstall [-v] [-f | -i] -r repositoryLocation moduleName"// XXX i18n
+                + " [moduleVersion] [modulePlatformBinding]\n"
                 +  "        removes a module from a repository, along with associated files.";
         }
 
@@ -659,9 +908,9 @@
                 rc = repo.uninstall(mai);
                 if (verboseFlag.isEnabled()) {
                     if (rc) {
-                        msg.println("Uninstalled " + getMAIText(mai));
+                        msg.println("Uninstalled " + getMAIText(mai)); // XXX i18n
                     } else {
-                        msg.error("Failed to uninstall " + getMAIText(mai));
+                        msg.error("Failed to uninstall " + getMAIText(mai)); // XXX i18n
                     }
                 }
             } catch (Exception ex) {
@@ -769,10 +1018,12 @@
             parentFlag.register(myFlags);
         }
 
+        @Override
         void reset() {
             parentFlag.reset();
         }
 
+        @Override
         int parseFlags(String[] args, Map<Character, Flag> flags) {
             return super.parseFlags(args, myFlags);
         }
@@ -795,9 +1046,11 @@
             boolean found = visitor.wasFound();
             if (verboseFlag.isEnabled() && !found) {
                 if (moduleName != null) {
-                    msg.error("Could not find module name starting with '" + moduleName + "'");
+                    msg.error("Could not find module name starting with '"// 
+                                                                          // XXX i18n
+                              + moduleName + "'");
                 } else {
-                    msg.error("Could not find any modules");
+                    msg.error("Could not find any modules"); // XXX i18n
                 }
             }
             return found;
@@ -804,7 +1057,8 @@
         }
 
         String usage() {
-            return "list [-v] [-p] [-r repositoryLocation] moduleName\n"
+            return "list [-v] [-p] [-r repositoryLocation] moduleName\n"// 
+                                                                        // XXX i18n
                 +  "        lists the modules in the repository";
         }
 
@@ -815,15 +1069,21 @@
 
             void doit(Repository repo, Messenger msg) {
                 boolean printedHeader = false;
-                for (ModuleArchiveInfo mai : repo.list()) {
-                    if (moduleName == null || mai.getName().startsWith(moduleName)) {
-                        if (!printedHeader) {
-                            msg.println(getRepositoryText(repo));
-                            msg.println(verboseFlag.isEnabled() ? maiHeadingVerbose : maiHeading);
-                            printedHeader = true;
+                List<ModuleArchiveInfo> maiList = repo.list();
+                if (maiList.size() == 0 && verboseFlag.isEnabled()) {
+                    msg.println(getRepositoryText(repo));
+                    msg.println("   empty");
+                } else {
+                    for (ModuleArchiveInfo mai : repo.list()) {
+                        if (moduleName == null || mai.getName().startsWith(moduleName)) {
+                            if (!printedHeader) {
+                                msg.println(getRepositoryText(repo));
+                                msg.println(verboseFlag.isEnabled() ? maiHeadingVerbose : maiHeading);
+                                printedHeader = true;
+                            }
+                            msg.println(getMAIText(mai));
+                            found = true;
                         }
-                        msg.println(getMAIText(mai));
-                        found = true;
                     }
                 }
             }
