src/share/classes/sun/module/tools/JRepo.java

Print this page

        

@@ -43,18 +43,19 @@
 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.Comparator;
 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 java.util.Set;
+import java.util.TreeSet;
 import sun.module.repository.RepositoryConfig;
 import sun.security.action.GetPropertyAction;
 import sun.tools.jar.CommandLine;
 
 /**

@@ -112,19 +113,20 @@
     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();
+    /** Causes an individual command to print help and exit. */
+    private static final Flag helpFlag = new Flag('h');
 
     /** Contains the flags that are common to all commands. */
     private static final HashMap<Character, Flag> commonFlags = new HashMap<Character, Flag>();
 
     static {
         repositoryFlag.register(commonFlags);
         verboseFlag.register(commonFlags);
+        helpFlag.register(commonFlags);
 
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
         pw.printf(MAIFormat, "Name", "Version"); // XXX i18n
         maiHeading = sw.toString();

@@ -142,14 +144,16 @@
 
     public JRepo(PrintStream out, PrintStream err, BufferedReader reader) {
         msg = new Messenger("jrepo", out, err, reader);
         synchronized(commands) {
             if (commands.isEmpty()) {
-                new ListCommand().register(commands);
+                new DependenciesCommand().register(commands);
                 new InstallCommand().register(commands);
+                new HelpCommand().register(commands);
+                new ListCommand().register(commands);
                 new UninstallCommand().register(commands);
-                new DependenciesCommand().register(commands);
+                new ValidateCommand().register(commands);
             }
         }
         reset();
     }
 

@@ -168,10 +172,15 @@
         if (DEBUG && cmd != null) debug("running " + cmd);
         if (cmd == null) {
             return false;
         }
 
+        if (helpFlag.isEnabled()) {
+            cmd.usageError(msg);
+            return true;
+        }
+
         Repository repo = null;
         try {
              repo = getRepository();
              repo.shutdownOnExit(true);
         } catch (IOException ex) {

@@ -223,10 +232,11 @@
     private void reset() {
         moduleName = null;
         parentFlag.reset();
         repositoryFlag.reset();
         verboseFlag.reset();
+        helpFlag.reset();
         for (Command cmd : commands.values()) {
             cmd.reset();
         }
     }
 

@@ -262,44 +272,37 @@
             return null;
         }
 
         try {
             int numFlags = cmd.parseFlags(args, commonFlags);
+            if (helpFlag.isEnabled()) {
+                return cmd;
+            }
+            
             args = Arrays.copyOfRange(args, numFlags + 1, args.length);
             try {
                 if (cmd.parseArgs(args, msg)) {
                     return cmd;
                 } else {
-                    usageError();
+                    cmd.usageError(msg);
                     return null;
                 }
             } catch (ArrayIndexOutOfBoundsException e) {
                 usageError();
             }
         } catch (IllegalArgumentException ex) {
             msg.error(ex.getMessage());
-            usageError();
+            cmd.usageError(msg);
             return null;
         }
         return cmd;
     }
 
 
     /** Returns a user-grokkable description of the repository. */
     private static String getRepositoryText(Repository repo) {
         String rc;
-/*        URI u = repo.getSourceLocation();
-        if (u == null) {
-            rc = "Bootstrap repository";
-        } else {
-            try {
-                rc = "Repository " + u.toURL().toExternalForm();
-            } catch (MalformedURLException ex) {
-                rc = "Repository unknown";
-            }
-        }
- */
         rc = "[" + repo.toString() + "]";
 
         return rc;
     }
 

@@ -331,13 +334,10 @@
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
         pw.printf(MDFormat, md.getName(), md.getVersion());
         if (verboseFlag.isEnabled()) {
             pw.printf(MDFormatVerbose,
-//                      md.getRepository() == Repository.getBootstrapRepository()
-//                      ? "bootstrap"
-//                      : md.getRepository().getSourceLocation().toString());
                      md.getRepository().getName());
         }
         return sw.toString();
     }
 

@@ -430,47 +430,10 @@
             super.reset();
             location = null;
         }
     }
 
-    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.
      */
 

@@ -502,11 +465,11 @@
         /**
          * Parse the Flags for this command.
          * @return number of flags found.
          * @throws IllegalArgumentException if an invalid flag is given.
          */
-        int parseFlags(String[] args, Map<Character, Flag> flags) {
+/*        int parseFlags(String[] args, Map<Character, Flag> flags) {
             int rc = 0;
             int i = 0;
             while (i < args.length) {
                 String s = args[i];
                 if (s.length() == 2 && s.charAt(0) == '-') {

@@ -517,21 +480,57 @@
                         rc += numConsumed; // Increases only when the arg is a flag.
                     } else {
                         throw new IllegalArgumentException("unrecognized flag: " // XXX i18n
                                                            + args[i]);
                     }
+                } if (s.charAt(0) == '-') {
+                    throw new IllegalArgumentException("invalid flag: " // XXX i18n
+                                                       + args[i]);
                 } else {
                     i++;
                 }
             }
             return rc;
         }
+*/
+        int parseFlags(String[] args, Map<Character, Flag> flags) {
+            int rc = 0;
+            int i = 0;
+            while (i < args.length) {
+                String s = args[i];
+                if (s.charAt(0) == '-') {
+                    if (s.length() == 2) {
+                        Flag f = flags.get(s.charAt(1));
+                        if (f != null) {
+                            int numConsumed = f.set(args, i);
+                            i += numConsumed;  // Increases at each iteration.
+                            rc += numConsumed; // Increases only when the arg is a flag.
+                        } else {
+                            throw new IllegalArgumentException("unrecognized flag: " // XXX i18n
+                                                               + args[i]);
+                        }
+                    } else {
+                        throw new IllegalArgumentException("invalid flag: " // XXX i18n
+                                                           + args[i]);
+                    }
+                } else {
+                    i++;
+                }
+            }
+            return rc;
+        }
 
         /** Represents the actual behavior of the command. */
         abstract boolean run(Repository repo, Messenger msg);
 
-        /** Returns a usage string describing this command, or null if the
+        /** Prints command-specific usage message. */
+        void usageError(Messenger msg) {
+            msg.error("Synopsis for " + name + ": \n" + usage());
+        }
+
+        /**
+         *Returns a usage string describing this command, or null if the
          * command is a synonym for another command.
          */
         abstract String usage();
 
         @Override

@@ -580,17 +579,15 @@
         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);

@@ -609,13 +606,11 @@
             }
             if (args.length > 2) {
                 return false;
             }
 
-            if (DEBUG) debug("name: " + name + " ver: " + version
-                             + " plat: " + bindingFlag.getPlatform()
-                             + " arch: " + bindingFlag.getArch());
+            if (DEBUG) debug("name: " + name + " ver: " + version);
             return true;
         }
 
         boolean run(Repository repo, Messenger msg) {
             boolean rc = true;

@@ -622,33 +617,30 @@
             if (name != null) {
                 VersionConstraint vc = (version == null
                                         ? VersionConstraint.DEFAULT
                                         : version.toVersionConstraint());
                 printHeader(name, vc);
-                rc = depend(repo, name, vc,
-                            bindingFlag.getPlatform(), bindingFlag.getArch());
+                rc = depend(repo, name, vc);
                 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());
+                    rc &= depend(repo, maiName, vc);
                     printTrailer("\n");
                 }
             }
             return rc;
         }
 
-        boolean depend(Repository repo, String name, VersionConstraint constraint,
-                       String platform, String arch) {
+        boolean depend(Repository repo, String name, VersionConstraint constraint) {
             ImportTraverser traverser = new ImportTraverser();
             ImportTraverser.Visitor visitor = new ImportVisitor(traverser, msg);
             try {
-                traverser.traverse(visitor, repo, name, constraint, platform, arch);
+                traverser.traverse(visitor, repo, name, constraint);
                 if (traverser.traversedAny()) {
                     return true;
                 }
                 if (verboseFlag.isEnabled()) {
                     msg.error("Cannot find module " + name + " in " // XXX i18n

@@ -675,12 +667,12 @@
                 msg.print(s);
             }
         }
 
         String usage() {
-            return "dependencies [-v] [-r repositoryLocation] [-b platform-arch]"// XXX i18n
-                + " [moduleName [moduleVersion] ]\n"
+            // XXX i18n
+            return "dependencies [-v] [-r repositoryLocation] [moduleName [moduleVersion] ]\n"
                 + "        Lists all modules on which identified modules depend.\n"
                 + "        If no moduleName is given, lists dependencies of all"
                 + " module archives in the repository\n"
                 + "        which are instantiable on the current platform.";
         }

@@ -734,18 +726,59 @@
         void printModule(Module m) {
             msg.println(indent + getMText(m));
         }
     }
 
+    
+    /** Prints help. */
+    private class HelpCommand extends Command {
+        HelpCommand() {
+            super("help");
+        }
+        
+        boolean parseArgs(String[] args, Messenger msg) {
+            return true;
+        }
+        
+        boolean run(Repository repo, Messenger msg) {
+            JRepo.this.usageError(msg);
+            return true;
+        }
+        
+        String usage() {
+            return "help\n        Prints brief help text for all commands.\n"
+                +  "        Each command allows a -h option which gives help for that command.";
+        }
+    }
+    
+
     /** Installs a JAM into a repository. */
     private class InstallCommand extends Command {
+        @SuppressWarnings("unchecked")
+        private final Map<Character, Flag> myFlags = (Map<Character, Flag>) commonFlags.clone();
+
+        /** When used, prevents checking of installed module's dependencies. */
+        private Flag quickInstallFlag = new Flag('q');
+
         private String jamName;
 
         InstallCommand() {
             super("install");
+            quickInstallFlag.register(myFlags);
         }
 
+        @Override
+        void reset() {
+            jamName = null;
+            quickInstallFlag.reset();
+        }
+
+        @Override
+        int parseFlags(String[] args, Map<Character, Flag> flags) {
+            return super.parseFlags(args, myFlags);
+        }
+
         boolean parseArgs(String[] args, Messenger msg) {
             boolean rc = false;
             if (!parentFlag.isEnabled()
                     && repositoryFlag.getLocation() != null
                     && args.length == 1) {

@@ -778,11 +811,31 @@
                 try {
                     ModuleArchiveInfo mai = repo.install(new URL(jamURL).toURI());
                     if (verboseFlag.isEnabled()) {
                         msg.println("Installed " + jamName + ": " + getMAIText(mai));
                     }
+                    if (!quickInstallFlag.isEnabled()) {
+                        ModuleDefinition md = repo.find(
+                            mai.getName(), mai.getVersion().toVersionConstraint());
+                        if (md == null) {
+                            msg.error("Warning: " + jamName
+                                      + " was installed but cannot be found");
+                        } else {
+                            try {
+                                Module m = md.getModuleInstance();
+                            } catch (ModuleInitializationException ex) {
+                                msg.error("Cannot install " + ex.getMessage());
+                                if (!repo.uninstall(mai)) {
+                                    msg.error("Could not uninstall " + mai);
+                                }
+                                return false;
+                            }
+                        }
+                    }
                     return true;
+                } catch (IllegalStateException ex) {
+                    msg.error("Cannot install " + jamName + ": " + ex.getMessage());
                 } catch (URISyntaxException ex) {
                     msg.error("Cannot install " + jamName + ": no such file, or malformed URI");
                 } catch (MalformedURLException ex) {
                     msg.error("Cannot install " + jamName + ": no such file, or malformed URL");
                 } catch (IOException ex) {

@@ -791,12 +844,12 @@
             }
             return false;
         }
 
         String usage() {
-            return "install [-v] -r repositoryLocation jamFile | jamURL\n" // XXX i18n
-                +  "        installs a module into a repository";
+            return "install [-v] [-q] -r repositoryLocation jamFile | jamURL\n" // XXX i18n
+                +  "        Installs a module into a repository.";
         }
     }
 
     /** Uninstalls a module from a repository. */
     private class UninstallCommand extends Command {

@@ -914,11 +967,11 @@
         }
 
         String usage() {
             return "uninstall [-v] [-f | -i] -r repositoryLocation moduleName"// XXX i18n
                 + " [moduleVersion] [modulePlatformBinding]\n"
-                +  "        removes a module from a repository, along with associated files.";
+                +  "        Removes a module from a repository, along with associated files.";
         }
 
         /** Uninstall the ModuleArchiveInfo from the Repository. */
         private boolean uninstall(Repository repo, ModuleArchiveInfo mai, Messenger msg) {
             boolean rc = false;

@@ -1025,10 +1078,64 @@
             }
             return s;
         }
     }
 
+    /** Provides a way to sort ModuleArchiveInfo instances. */
+    static class MAIComparator implements Comparator<ModuleArchiveInfo> {
+        private static final MAIComparator instance = new MAIComparator();
+
+        private MAIComparator() { }
+
+        static MAIComparator getInstance() {
+            return instance;
+        }
+
+        public int compare(ModuleArchiveInfo o1, ModuleArchiveInfo o2) {
+            int rc = o1.getName().compareTo(o2.getName());
+            if (rc != 0) {
+                return rc;
+            }
+
+            rc = o1.getVersion().compareTo(o2.getVersion());
+            if (rc != 0) {
+                return rc;
+            }
+
+            rc = compareStrings(o1.getPlatform(), o2.getPlatform());
+            if (rc != 0) {
+                return rc;
+            }
+
+            return compareStrings(o1.getArch(), o2.getArch());
+        }
+
+        // Compare two Strings.  If neither is null, compare them
+        // lexicographically.  If both are null, return 0.  If the first is
+        // null, return -1; else 1.
+        private int compareStrings(String s1, String s2) {
+            int rc = 0;
+            if (s2 != null && s2 != null) {
+                rc = s1.compareTo(s2);
+                if (rc != 0) {
+                    return rc;
+                }
+            }
+            if (s1 == null) {
+                return -1;
+            } else if (s2 == null) {
+                return 1;
+            }
+            return 0;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            return this == o;
+        }
+    }
+
     /** Prints information about modules found in repositories. */
     private class ListCommand extends Command {
         @SuppressWarnings("unchecked")
         private final Map<Character, Flag> myFlags = (Map<Character, Flag>) commonFlags.clone();
 

@@ -1073,12 +1180,13 @@
             }
             return found;
         }
 
         String usage() {
-            return "list [-v] [-p] [-r repositoryLocation] moduleName\n"// XXX i18n
-                +  "        lists the modules in the repository";
+            return "list [-v] [-p] [-r repositoryLocation] [moduleName]\n"// XXX i18n
+                +  "        Lists the modules in the repository that match the given name.\n"
+                +  "        If no moduleName is given, lists all modules in the repository.";
         }
 
         class ListRepositoryVisitor extends RepositoryVisitor {
             private boolean found = false;
 

@@ -1089,11 +1197,14 @@
                 List<ModuleArchiveInfo> maiList = repo.list();
                 if (maiList.size() == 0 && verboseFlag.isEnabled()) {
                     msg.println(getRepositoryText(repo));
                     msg.println("   empty");
                 } else {
-                    for (ModuleArchiveInfo mai : repo.list()) {
+                    TreeSet<ModuleArchiveInfo> sorted =
+                        new TreeSet<ModuleArchiveInfo>(MAIComparator.getInstance());
+                    sorted.addAll(repo.list());
+                    for (ModuleArchiveInfo mai : sorted) {
                         if (moduleName == null || mai.getName().startsWith(moduleName)) {
                             if (!printedHeader) {
                                 msg.println(getRepositoryText(repo));
                                 msg.println(verboseFlag.isEnabled() ? maiHeadingVerbose : maiHeading);
                                 printedHeader = true;

@@ -1104,6 +1215,117 @@
                     }
                 }
             }
         }
     }
+
+    /** Runs shallow and/or deep validation on one or more modules. */
+    class ValidateCommand extends Command {
+        @SuppressWarnings("unchecked")
+        private final Map<Character, Flag> myFlags = (Map<Character, Flag>) commonFlags.clone();
+
+        /** Indicates that deep validation should be run. */
+        private Flag deepValidateFlag = new Flag('d');
+
+        private String name;
+        private Version version;
+
+        ValidateCommand() {
+            super("validate");
+            deepValidateFlag.register(myFlags);
+        }
+
+        @Override
+        void reset() {
+            deepValidateFlag.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);
+            return true;
+        }
+
+        boolean run(Repository repo, Messenger msg) {
+            boolean rc = true;
+            if (name != null) {
+                VersionConstraint vc = (version == null
+                                        ? VersionConstraint.DEFAULT
+                                        : version.toVersionConstraint());
+
+                List<ModuleDefinition> mdList = repo.find(Query.module(name, vc));
+                if (mdList.size() == 1) {
+                    rc = validate(mdList.get(0), msg);
+                } else {
+                    throw new IllegalArgumentException(
+                        "more than one matching module found for name=" + name
+                        + " version=" + vc);
+                }
+            } else {
+                for (ModuleDefinition md : repo.findAll()) {
+                    rc &= validate(md, msg);
+                }
+            }
+            return rc;
+        }
+
+        /** @return true if the module passes validation validation. */
+        boolean validate(ModuleDefinition md, Messenger msg) {
+            boolean rc = false;
+            try {
+                Module m = md.getModuleInstance();
+                if (deepValidateFlag.isEnabled()) {
+                    if (m.supportsDeepValidation()) {
+                        try {
+                            m.deepValidate();
+                            if (verboseFlag.isEnabled()) {
+                                msg.println(
+                                    "Module " + m + " passed deep validation"); // XXX i18n
+                            }
+                            rc = true;
+                        } catch (ModuleInitializationException ex) {
+                            msg.error(
+                                "Module " + m + " failed deep validation"); // XXX i18n
+                        }
+                    }
+                } else {
+                    // Module was instantiated => passed shallow validation
+                    if (verboseFlag.isEnabled()) {
+                        msg.println(
+                            "Module " + m + " passed shallow validation"); // XXX i18n
+                    }
+                    rc = true;
+                }
+            } catch (ModuleInitializationException ex) {
+                msg.error("Could not initialize module for " + md // XXX i18n
+                          + ": " + ex.getMessage());
+            }
+            return rc;
+        }
+        
+        String usage() {
+             // XXX i18n
+            return "validate [-v] [-d] [-r repositoryLocation] [moduleName [moduleVersion] ]\n"
+                + "        Runs deep validation on the identified modules.\n"
+                + "        If no moduleName is given, validates all module"
+                + " archives in the repository.\n";
+        }
+    }
 }