langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java
changeset 16290 b0b4f52de7ea
parent 15030 2d8dec41f029
child 16550 f20e2521f3df
equal deleted inserted replaced
16289:8bf9d5ba7dc6 16290:b0b4f52de7ea
    27 import com.sun.tools.classfile.ClassFile;
    27 import com.sun.tools.classfile.ClassFile;
    28 import com.sun.tools.classfile.ConstantPoolException;
    28 import com.sun.tools.classfile.ConstantPoolException;
    29 import com.sun.tools.classfile.Dependencies;
    29 import com.sun.tools.classfile.Dependencies;
    30 import com.sun.tools.classfile.Dependencies.ClassFileError;
    30 import com.sun.tools.classfile.Dependencies.ClassFileError;
    31 import com.sun.tools.classfile.Dependency;
    31 import com.sun.tools.classfile.Dependency;
    32 import com.sun.tools.classfile.Dependency.Location;
       
    33 import java.io.*;
    32 import java.io.*;
    34 import java.text.MessageFormat;
    33 import java.text.MessageFormat;
    35 import java.util.*;
    34 import java.util.*;
    36 import java.util.regex.Pattern;
    35 import java.util.regex.Pattern;
    37 
    36 
    40  */
    39  */
    41 class JdepsTask {
    40 class JdepsTask {
    42     class BadArgs extends Exception {
    41     class BadArgs extends Exception {
    43         static final long serialVersionUID = 8765093759964640721L;
    42         static final long serialVersionUID = 8765093759964640721L;
    44         BadArgs(String key, Object... args) {
    43         BadArgs(String key, Object... args) {
    45             super(JdepsTask.this.getMessage(key, args));
    44             super(JdepsTask.getMessage(key, args));
    46             this.key = key;
    45             this.key = key;
    47             this.args = args;
    46             this.args = args;
    48         }
    47         }
    49 
    48 
    50         BadArgs showUsage(boolean b) {
    49         BadArgs showUsage(boolean b) {
   103             }
   102             }
   104         },
   103         },
   105         new Option(false, "-s", "--summary") {
   104         new Option(false, "-s", "--summary") {
   106             void process(JdepsTask task, String opt, String arg) {
   105             void process(JdepsTask task, String opt, String arg) {
   107                 task.options.showSummary = true;
   106                 task.options.showSummary = true;
   108                 task.options.verbose = Options.Verbose.SUMMARY;
   107                 task.options.verbose = Analyzer.Type.SUMMARY;
   109             }
   108             }
   110         },
   109         },
   111         new Option(false, "-v", "--verbose") {
   110         new Option(false, "-v", "--verbose") {
   112             void process(JdepsTask task, String opt, String arg) {
   111             void process(JdepsTask task, String opt, String arg) {
   113                 task.options.verbose = Options.Verbose.VERBOSE;
   112                 task.options.verbose = Analyzer.Type.VERBOSE;
   114             }
   113             }
   115         },
   114         },
   116         new Option(true, "-V", "--verbose-level") {
   115         new Option(true, "-V", "--verbose-level") {
   117             void process(JdepsTask task, String opt, String arg) throws BadArgs {
   116             void process(JdepsTask task, String opt, String arg) throws BadArgs {
   118                 switch (arg) {
   117                 if ("package".equals(arg)) {
   119                     case "package":
   118                     task.options.verbose = Analyzer.Type.PACKAGE;
   120                         task.options.verbose = Options.Verbose.PACKAGE;
   119                 } else if ("class".equals(arg)) {
   121                         break;
   120                     task.options.verbose = Analyzer.Type.CLASS;
   122                     case "class":
   121                 } else {
   123                         task.options.verbose = Options.Verbose.CLASS;
   122                     throw task.new BadArgs("err.invalid.arg.for.option", opt);
   124                         break;
       
   125                     default:
       
   126                         throw task.new BadArgs("err.invalid.arg.for.option", opt);
       
   127                 }
   123                 }
   128             }
   124             }
   129         },
   125         },
   130         new Option(true, "-c", "--classpath") {
   126         new Option(true, "-c", "--classpath") {
   131             void process(JdepsTask task, String opt, String arg) {
   127             void process(JdepsTask task, String opt, String arg) {
   169         new HiddenOption(false, "--fullversion") {
   165         new HiddenOption(false, "--fullversion") {
   170             void process(JdepsTask task, String opt, String arg) {
   166             void process(JdepsTask task, String opt, String arg) {
   171                 task.options.fullVersion = true;
   167                 task.options.fullVersion = true;
   172             }
   168             }
   173         },
   169         },
   174 
       
   175     };
   170     };
   176 
   171 
   177     private static final String PROGNAME = "jdeps";
   172     private static final String PROGNAME = "jdeps";
   178     private final Options options = new Options();
   173     private final Options options = new Options();
   179     private final List<String> classes = new ArrayList<String>();
   174     private final List<String> classes = new ArrayList<String>();
   214             }
   209             }
   215             if (options.regex != null && options.packageNames.size() > 0) {
   210             if (options.regex != null && options.packageNames.size() > 0) {
   216                 showHelp();
   211                 showHelp();
   217                 return EXIT_CMDERR;
   212                 return EXIT_CMDERR;
   218             }
   213             }
   219             if (options.showSummary && options.verbose != Options.Verbose.SUMMARY) {
   214             if (options.showSummary && options.verbose != Analyzer.Type.SUMMARY) {
   220                 showHelp();
   215                 showHelp();
   221                 return EXIT_CMDERR;
   216                 return EXIT_CMDERR;
   222             }
   217             }
   223             boolean ok = run();
   218             boolean ok = run();
   224             return ok ? EXIT_OK : EXIT_ERROR;
   219             return ok ? EXIT_OK : EXIT_ERROR;
   234             log.flush();
   229             log.flush();
   235         }
   230         }
   236     }
   231     }
   237 
   232 
   238     private final List<Archive> sourceLocations = new ArrayList<Archive>();
   233     private final List<Archive> sourceLocations = new ArrayList<Archive>();
   239     private final Archive NOT_FOUND = new Archive(getMessage("artifact.not.found"));
       
   240     private boolean run() throws IOException {
   234     private boolean run() throws IOException {
   241         findDependencies();
   235         findDependencies();
   242         switch (options.verbose) {
   236         Analyzer analyzer = new Analyzer(options.verbose);
   243             case VERBOSE:
   237         analyzer.run(sourceLocations);
   244             case CLASS:
   238         if (options.verbose == Analyzer.Type.SUMMARY) {
   245                 printClassDeps(log);
   239             printSummary(log, analyzer);
   246                 break;
   240         } else {
   247             case PACKAGE:
   241             printDependencies(log, analyzer);
   248                 printPackageDeps(log);
       
   249                 break;
       
   250             case SUMMARY:
       
   251                 for (Archive origin : sourceLocations) {
       
   252                     for (Archive target : origin.getRequiredArchives()) {
       
   253                         log.format("%-30s -> %s%n", origin, target);
       
   254                     }
       
   255                 }
       
   256                 break;
       
   257             default:
       
   258                 throw new InternalError("Should not reach here");
       
   259         }
   242         }
   260         return true;
   243         return true;
   261     }
   244     }
   262 
   245 
   263     private boolean isValidClassName(String name) {
   246     private boolean isValidClassName(String name) {
   329                 try {
   312                 try {
   330                     classFileName = cf.getName();
   313                     classFileName = cf.getName();
   331                 } catch (ConstantPoolException e) {
   314                 } catch (ConstantPoolException e) {
   332                     throw new ClassFileError(e);
   315                     throw new ClassFileError(e);
   333                 }
   316                 }
   334                 a.addClass(classFileName);
   317 
   335                 if (!doneClasses.contains(classFileName)) {
   318                 if (!doneClasses.contains(classFileName)) {
   336                     doneClasses.add(classFileName);
   319                     doneClasses.add(classFileName);
   337                 }
   320                 }
   338                 for (Dependency d : finder.findDependencies(cf)) {
   321                 for (Dependency d : finder.findDependencies(cf)) {
   339                     if (filter.accepts(d)) {
   322                     if (filter.accepts(d)) {
   340                         String cn = d.getTarget().getName();
   323                         String cn = d.getTarget().getName();
   341                         if (!doneClasses.contains(cn) && !deque.contains(cn)) {
   324                         if (!doneClasses.contains(cn) && !deque.contains(cn)) {
   342                             deque.add(cn);
   325                             deque.add(cn);
   343                         }
   326                         }
   344                         a.addDependency(d);
   327                         a.addClass(d.getOrigin(), d.getTarget());
   345                     }
   328                     }
   346                 }
   329                 }
   347             }
   330             }
   348         }
   331         }
   349 
   332 
   365                         try {
   348                         try {
   366                             classFileName = cf.getName();
   349                             classFileName = cf.getName();
   367                         } catch (ConstantPoolException e) {
   350                         } catch (ConstantPoolException e) {
   368                             throw new ClassFileError(e);
   351                             throw new ClassFileError(e);
   369                         }
   352                         }
   370                         a.addClass(classFileName);
       
   371                         if (!doneClasses.contains(classFileName)) {
   353                         if (!doneClasses.contains(classFileName)) {
   372                             // if name is a fully-qualified class name specified
   354                             // if name is a fully-qualified class name specified
   373                             // from command-line, this class might already be parsed
   355                             // from command-line, this class might already be parsed
   374                             doneClasses.add(classFileName);
   356                             doneClasses.add(classFileName);
   375                             if (depth > 0) {
   357                             for (Dependency d : finder.findDependencies(cf)) {
   376                                 for (Dependency d : finder.findDependencies(cf)) {
   358                                 if (depth == 0) {
   377                                     if (filter.accepts(d)) {
   359                                     // ignore the dependency
   378                                         String cn = d.getTarget().getName();
   360                                     a.addClass(d.getOrigin());
   379                                         if (!doneClasses.contains(cn) && !deque.contains(cn)) {
   361                                     break;
   380                                             deque.add(cn);
   362                                 } else if (filter.accepts(d)) {
   381                                         }
   363                                     a.addClass(d.getOrigin(), d.getTarget());
   382                                         a.addDependency(d);
   364                                     String cn = d.getTarget().getName();
       
   365                                     if (!doneClasses.contains(cn) && !deque.contains(cn)) {
       
   366                                         deque.add(cn);
   383                                     }
   367                                     }
   384                                 }
   368                                 }
   385                             }
   369                             }
   386                         }
   370                         }
   387                         break;
   371                         break;
   388                     }
   372                     }
   389                 }
   373                 }
   390                 if (cf == null) {
   374                 if (cf == null) {
   391                     NOT_FOUND.addClass(name);
   375                     doneClasses.add(name);
   392                 }
   376                 }
   393             }
   377             }
   394             unresolved = deque;
   378             unresolved = deque;
   395             deque = new LinkedList<String>();
   379             deque = new LinkedList<String>();
   396         } while (!unresolved.isEmpty() && depth-- > 0);
   380         } while (!unresolved.isEmpty() && depth-- > 0);
   397     }
   381     }
   398 
   382 
   399     private void printPackageDeps(PrintWriter out) {
   383     private void printSummary(final PrintWriter out, final Analyzer analyzer) {
   400         for (Archive source : sourceLocations) {
   384         Analyzer.Visitor visitor = new Analyzer.Visitor() {
   401             SortedMap<Location, SortedSet<Location>> deps = source.getDependencies();
   385             public void visit(String origin, String profile) {
   402             if (deps.isEmpty())
   386                 if (options.showProfile) {
   403                 continue;
   387                     out.format("%-30s -> %s%n", origin, profile);
   404 
   388                 }
   405             for (Archive target : source.getRequiredArchives()) {
   389             }
   406                 out.format("%s -> %s%n", source, target);
   390             public void visit(Archive origin, Archive target) {
   407             }
   391                 if (!options.showProfile) {
   408 
   392                     out.format("%-30s -> %s%n", origin, target);
   409             Map<String, Archive> pkgs = new TreeMap<String, Archive>();
   393                 }
   410             SortedMap<String, Archive> targets = new TreeMap<String, Archive>();
   394             }
   411             String pkg = "";
   395         };
   412             for (Map.Entry<Location, SortedSet<Location>> e : deps.entrySet()) {
   396         analyzer.visitSummary(visitor);
   413                 String cn = e.getKey().getClassName();
   397     }
   414                 String p = packageOf(e.getKey());
   398 
   415                 Archive origin = Archive.find(e.getKey());
   399     private void printDependencies(final PrintWriter out, final Analyzer analyzer) {
   416                 assert origin != null;
   400         Analyzer.Visitor visitor = new Analyzer.Visitor() {
   417                 if (!pkgs.containsKey(p)) {
   401             private String pkg = "";
   418                     pkgs.put(p, origin);
   402             public void visit(String origin, String target) {
   419                 } else if (pkgs.get(p) != origin) {
   403                 if (!origin.equals(pkg)) {
   420                     warning("warn.split.package", p, origin, pkgs.get(p));
   404                     pkg = origin;
   421                 }
   405                     out.format("   %s (%s)%n", origin, analyzer.getArchiveName(origin));
   422 
   406                 }
   423                 if (!p.equals(pkg)) {
   407                 Archive source = analyzer.getArchive(target);
   424                     printTargets(out, targets);
   408                 String profile = options.showProfile ? analyzer.getProfile(target) : "";
   425                     pkg = p;
   409                 out.format("      -> %-50s %s%n", target,
   426                     targets.clear();
   410                            PlatformClassPath.contains(source)
   427                     out.format("   %s (%s)%n", p, origin.getFileName());
   411                                ? profile
   428                 }
   412                                : analyzer.getArchiveName(target));
   429 
   413             }
   430                 for (Location t : e.getValue()) {
   414             public void visit(Archive origin, Archive target) {
   431                     p = packageOf(t);
   415                 out.format("%s -> %s%n", origin, target);
   432                     Archive target = Archive.find(t);
   416             }
   433                     if (!targets.containsKey(p)) {
   417         };
   434                         targets.put(p, target);
   418         analyzer.visit(visitor);
   435                     }
   419     }
   436                 }
   420 
   437             }
       
   438             printTargets(out, targets);
       
   439             out.println();
       
   440         }
       
   441     }
       
   442 
       
   443     private void printTargets(PrintWriter out, Map<String, Archive> targets) {
       
   444         for (Map.Entry<String, Archive> t : targets.entrySet()) {
       
   445             String pn = t.getKey();
       
   446             out.format("      -> %-40s %s%n", pn, getPackageInfo(pn, t.getValue()));
       
   447         }
       
   448     }
       
   449 
       
   450     private String getPackageInfo(String pn, Archive source) {
       
   451         if (PlatformClassPath.contains(source)) {
       
   452             String name = PlatformClassPath.getProfileName(pn);
       
   453             if (name.isEmpty()) {
       
   454                 return "JDK internal API (" + source.getFileName() + ")";
       
   455             }
       
   456             return options.showProfile ? name : "";
       
   457         }
       
   458         return source.getFileName();
       
   459     }
       
   460 
       
   461     private static String packageOf(Location loc) {
       
   462         String pkg = loc.getPackageName();
       
   463         return pkg.isEmpty() ? "<unnamed>" : pkg;
       
   464     }
       
   465 
       
   466     private void printClassDeps(PrintWriter out) {
       
   467         for (Archive source : sourceLocations) {
       
   468             SortedMap<Location, SortedSet<Location>> deps = source.getDependencies();
       
   469             if (deps.isEmpty())
       
   470                 continue;
       
   471 
       
   472             for (Archive target : source.getRequiredArchives()) {
       
   473                 out.format("%s -> %s%n", source, target);
       
   474             }
       
   475             out.format("%s%n", source);
       
   476             for (Map.Entry<Location, SortedSet<Location>> e : deps.entrySet()) {
       
   477                 String cn = e.getKey().getClassName();
       
   478                 Archive origin = Archive.find(e.getKey());
       
   479                 out.format("   %s (%s)%n", cn, origin.getFileName());
       
   480                 for (Location t : e.getValue()) {
       
   481                     cn = t.getClassName();
       
   482                     Archive target = Archive.find(t);
       
   483                     out.format("      -> %-60s %s%n", cn, getPackageInfo(t.getPackageName(), target));
       
   484                 }
       
   485             }
       
   486             out.println();
       
   487         }
       
   488     }
       
   489     public void handleOptions(String[] args) throws BadArgs {
   421     public void handleOptions(String[] args) throws BadArgs {
   490         // process options
   422         // process options
   491         for (int i=0; i < args.length; i++) {
   423         for (int i=0; i < args.length; i++) {
   492             if (args[i].charAt(0) == '-') {
   424             if (args[i].charAt(0) == '-') {
   493                 String name = args[i];
   425                 String name = args[i];
   568         } catch (MissingResourceException e) {
   500         } catch (MissingResourceException e) {
   569             return getMessage("version.unknown", System.getProperty("java.version"));
   501             return getMessage("version.unknown", System.getProperty("java.version"));
   570         }
   502         }
   571     }
   503     }
   572 
   504 
   573     public String getMessage(String key, Object... args) {
   505     static String getMessage(String key, Object... args) {
   574         try {
   506         try {
   575             return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args);
   507             return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args);
   576         } catch (MissingResourceException e) {
   508         } catch (MissingResourceException e) {
   577             throw new InternalError("Missing message: " + key);
   509             throw new InternalError("Missing message: " + key);
   578         }
   510         }
   579     }
   511     }
   580 
   512 
   581     private static class Options {
   513     private static class Options {
   582         enum Verbose {
       
   583             CLASS,
       
   584             PACKAGE,
       
   585             SUMMARY,
       
   586             VERBOSE
       
   587         };
       
   588 
       
   589         boolean help;
   514         boolean help;
   590         boolean version;
   515         boolean version;
   591         boolean fullVersion;
   516         boolean fullVersion;
   592         boolean showFlags;
   517         boolean showFlags;
   593         boolean showProfile;
   518         boolean showProfile;
   594         boolean showSummary;
   519         boolean showSummary;
   595         boolean wildcard;
   520         boolean wildcard;
   596         String regex;
   521         String regex;
   597         String classpath = "";
   522         String classpath = "";
   598         int depth = 1;
   523         int depth = 1;
   599         Verbose verbose = Verbose.PACKAGE;
   524         Analyzer.Type verbose = Analyzer.Type.PACKAGE;
   600         Set<String> packageNames = new HashSet<String>();
   525         Set<String> packageNames = new HashSet<String>();
   601     }
   526     }
   602 
   527 
   603     private static class ResourceBundleHelper {
   528     private static class ResourceBundleHelper {
   604         static final ResourceBundle versionRB;
   529         static final ResourceBundle versionRB;