langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java
changeset 43026 8e8b50c7491d
parent 42840 dfe1a03d4db4
child 43873 705d732d3715
equal deleted inserted replaced
43025:b6e87a8600a4 43026:8e8b50c7491d
    36 import java.nio.file.Files;
    36 import java.nio.file.Files;
    37 import java.nio.file.Path;
    37 import java.nio.file.Path;
    38 import java.nio.file.Paths;
    38 import java.nio.file.Paths;
    39 import java.text.MessageFormat;
    39 import java.text.MessageFormat;
    40 import java.util.*;
    40 import java.util.*;
       
    41 import java.util.function.Function;
       
    42 import java.util.function.ToIntFunction;
    41 import java.util.jar.JarFile;
    43 import java.util.jar.JarFile;
    42 import java.util.regex.Pattern;
    44 import java.util.regex.Pattern;
    43 import java.util.stream.Collectors;
       
    44 import java.util.stream.Stream;
       
    45 
    45 
    46 /**
    46 /**
    47  * Implementation for the jdeps tool for static class dependency analysis.
    47  * Implementation for the jdeps tool for static class dependency analysis.
    48  */
    48  */
    49 class JdepsTask {
    49 class JdepsTask {
   312                 task.options.addmods.addAll(mods);
   312                 task.options.addmods.addAll(mods);
   313             }
   313             }
   314         },
   314         },
   315         new Option(true, "-m", "--module") {
   315         new Option(true, "-m", "--module") {
   316             void process(JdepsTask task, String opt, String arg) throws BadArgs {
   316             void process(JdepsTask task, String opt, String arg) throws BadArgs {
   317                 task.options.rootModule = arg;
   317                 if (!task.options.rootModules.isEmpty()) {
       
   318                     throw new BadArgs("err.option.already.specified", opt);
       
   319                 }
       
   320                 task.options.rootModules.add(arg);
   318                 task.options.addmods.add(arg);
   321                 task.options.addmods.add(arg);
   319             }
   322             }
   320         },
   323         },
   321         new Option(true, "--multi-release") {
   324         new Option(true, "--multi-release") {
   322             void process(JdepsTask task, String opt, String arg) throws BadArgs {
   325             void process(JdepsTask task, String opt, String arg) throws BadArgs {
   348             }
   351             }
   349         },
   352         },
   350         new Option(true, "--require") {
   353         new Option(true, "--require") {
   351             void process(JdepsTask task, String opt, String arg) {
   354             void process(JdepsTask task, String opt, String arg) {
   352                 task.options.requires.add(arg);
   355                 task.options.requires.add(arg);
       
   356                 task.options.addmods.add(arg);
   353             }
   357             }
   354         },
   358         },
   355         new Option(true, "-f", "-filter") {
   359         new Option(true, "-f", "-filter") {
   356             void process(JdepsTask task, String opt, String arg) {
   360             void process(JdepsTask task, String opt, String arg) {
   357                 task.options.filterRegex = Pattern.compile(arg);
   361                 task.options.filterRegex = Pattern.compile(arg);
   489                 showVersion(options.fullVersion);
   493                 showVersion(options.fullVersion);
   490             }
   494             }
   491             if (options.help || options.version || options.fullVersion) {
   495             if (options.help || options.version || options.fullVersion) {
   492                 return EXIT_OK;
   496                 return EXIT_OK;
   493             }
   497             }
   494 
       
   495             if (!inputArgs.isEmpty() && options.rootModule != null) {
       
   496                 reportError("err.invalid.arg.for.option", "-m");
       
   497             }
       
   498 
       
   499             if (options.numFilters() > 1) {
   498             if (options.numFilters() > 1) {
   500                 reportError("err.invalid.filters");
   499                 reportError("err.invalid.filters");
   501                 return EXIT_CMDERR;
   500                 return EXIT_CMDERR;
   502             }
   501             }
   503 
   502 
   541                 .sorted(Map.Entry.comparingByKey())
   540                 .sorted(Map.Entry.comparingByKey())
   542                 .forEach(e -> log.println(getMessage("split.package",
   541                 .forEach(e -> log.println(getMessage("split.package",
   543                                                      e.getKey(),
   542                                                      e.getKey(),
   544                                                      e.getValue().toString())));
   543                                                      e.getValue().toString())));
   545 
   544 
   546             // check if any module specified in --require is missing
   545             // check if any module specified in --add-modules, --require, and -m is missing
   547             Stream.concat(options.addmods.stream(), options.requires.stream())
   546             options.addmods.stream()
   548                 .filter(mn -> !config.isValidToken(mn))
   547                 .filter(mn -> !config.isValidToken(mn))
   549                 .forEach(mn -> config.findModule(mn).orElseThrow(() ->
   548                 .forEach(mn -> config.findModule(mn).orElseThrow(() ->
   550                     new UncheckedBadArgs(new BadArgs("err.module.not.found", mn))));
   549                     new UncheckedBadArgs(new BadArgs("err.module.not.found", mn))));
   551 
   550 
   552             return command.run(config);
   551             return command.run(config);
   618     abstract class Command {
   617     abstract class Command {
   619         final CommandOption option;
   618         final CommandOption option;
   620         protected Command(CommandOption option) {
   619         protected Command(CommandOption option) {
   621             this.option = option;
   620             this.option = option;
   622         }
   621         }
       
   622 
   623         /**
   623         /**
   624          * Returns true if the command-line options are all valid;
   624          * Returns true if the command-line options are all valid;
   625          * otherwise, returns false.
   625          * otherwise, returns false.
   626          */
   626          */
   627         abstract boolean checkOptions();
   627         abstract boolean checkOptions();
   631          */
   631          */
   632         abstract boolean run(JdepsConfiguration config) throws IOException;
   632         abstract boolean run(JdepsConfiguration config) throws IOException;
   633 
   633 
   634         /**
   634         /**
   635          * Includes all modules on system module path and application module path
   635          * Includes all modules on system module path and application module path
       
   636          *
       
   637          * When a named module is analyzed, it will analyze the dependences
       
   638          * only.  The method should be overridden when this command should
       
   639          * analyze all modules instead.
   636          */
   640          */
   637         boolean allModules() {
   641         boolean allModules() {
   638             return false;
   642             return false;
   639         }
   643         }
   640 
   644 
   677                 // -summary cannot use with -verbose option
   681                 // -summary cannot use with -verbose option
   678                 if (options.verbose != null) {
   682                 if (options.verbose != null) {
   679                     reportError("err.invalid.options", "-v, -verbose", "-s, -summary");
   683                     reportError("err.invalid.options", "-v, -verbose", "-s, -summary");
   680                     return false;
   684                     return false;
   681                 }
   685                 }
       
   686             }
       
   687 
       
   688             if (!inputArgs.isEmpty() && !options.rootModules.isEmpty()) {
       
   689                 reportError("err.invalid.arg.for.option", "-m");
   682             }
   690             }
   683             if (inputArgs.isEmpty() && !options.hasSourcePath()) {
   691             if (inputArgs.isEmpty() && !options.hasSourcePath()) {
   684                 showHelp();
   692                 showHelp();
   685                 return false;
   693                 return false;
   686             }
   694             }
   806             boolean ok = analyzer.run();
   814             boolean ok = analyzer.run();
   807 
   815 
   808             log.println();
   816             log.println();
   809             if (!options.requires.isEmpty())
   817             if (!options.requires.isEmpty())
   810                 log.println(getMessage("inverse.transitive.dependencies.on",
   818                 log.println(getMessage("inverse.transitive.dependencies.on",
   811                     options.requires));
   819                                        options.requires));
   812             else
   820             else
   813                 log.println(getMessage("inverse.transitive.dependencies.matching",
   821                 log.println(getMessage("inverse.transitive.dependencies.matching",
   814                     options.regex != null
   822                                        options.regex != null
   815                         ? options.regex.toString()
   823                                            ? options.regex.toString()
   816                         : "packages " + options.packageNames));
   824                                            : "packages " + options.packageNames));
   817 
   825 
   818             analyzer.inverseDependences().stream()
   826             analyzer.inverseDependences()
   819                 .sorted(Comparator.comparing(this::sortPath))
   827                     .stream()
   820                 .forEach(path -> log.println(path.stream()
   828                     .sorted(comparator())
   821                     .map(Archive::getName)
   829                     .map(this::toInversePath)
   822                     .collect(joining(" <- "))));
   830                     .forEach(log::println);
   823             return ok;
   831             return ok;
   824         }
   832         }
   825 
   833 
   826         private String sortPath(Deque<Archive> path) {
   834         private String toInversePath(Deque<Archive> path) {
   827             return path.peekFirst().getName();
   835             return path.stream()
       
   836                        .map(Archive::getName)
       
   837                        .collect(joining(" <- "));
       
   838         }
       
   839 
       
   840         /*
       
   841          * Returns a comparator for sorting the inversed path, grouped by
       
   842          * the first module name, then the shortest path and then sort by
       
   843          * the module names of each path
       
   844          */
       
   845         private Comparator<Deque<Archive>> comparator() {
       
   846             return Comparator.<Deque<Archive>, String>
       
   847                 comparing(deque -> deque.peekFirst().getName())
       
   848                     .thenComparingInt(Deque::size)
       
   849                     .thenComparing(this::toInversePath);
       
   850         }
       
   851 
       
   852         /*
       
   853          * Returns true if --require is specified so that all modules are
       
   854          * analyzed to find all modules that depend on the modules specified in the
       
   855          * --require option directly and indirectly
       
   856          */
       
   857         public boolean allModules() {
       
   858             return options.requires.size() > 0;
   828         }
   859         }
   829     }
   860     }
   830 
   861 
   831 
   862 
   832     class GenModuleInfo extends Command {
   863     class GenModuleInfo extends Command {
   922                                                        list, "--check"));
   953                                                        list, "--check"));
   923             }
   954             }
   924             return new ModuleAnalyzer(config, log, modules).run();
   955             return new ModuleAnalyzer(config, log, modules).run();
   925         }
   956         }
   926 
   957 
       
   958         /*
       
   959          * Returns true to analyze all modules
       
   960          */
   927         public boolean allModules() {
   961         public boolean allModules() {
   928             return true;
   962             return true;
   929         }
   963         }
   930     }
   964     }
   931 
   965 
   955             if (options.findJDKInternals) {
   989             if (options.findJDKInternals) {
   956                 reportError("err.invalid.options", "-jdkinternals",
   990                 reportError("err.invalid.options", "-jdkinternals",
   957                             option);
   991                             option);
   958                 return false;
   992                 return false;
   959             }
   993             }
       
   994 
       
   995             if (!inputArgs.isEmpty() && !options.rootModules.isEmpty()) {
       
   996                 reportError("err.invalid.arg.for.option", "-m");
       
   997             }
   960             if (inputArgs.isEmpty() && !options.hasSourcePath()) {
   998             if (inputArgs.isEmpty() && !options.hasSourcePath()) {
   961                 showHelp();
   999                 showHelp();
   962                 return false;
  1000                 return false;
   963             }
  1001             }
   964             return true;
  1002             return true;
   968         boolean run(JdepsConfiguration config) throws IOException {
  1006         boolean run(JdepsConfiguration config) throws IOException {
   969             return new ModuleExportsAnalyzer(config,
  1007             return new ModuleExportsAnalyzer(config,
   970                                              dependencyFilter(config),
  1008                                              dependencyFilter(config),
   971                                              reduced,
  1009                                              reduced,
   972                                              log).run();
  1010                                              log).run();
   973         }
       
   974 
       
   975         @Override
       
   976         boolean allModules() {
       
   977             return true;
       
   978         }
  1011         }
   979     }
  1012     }
   980 
  1013 
   981 
  1014 
   982     class GenDotFile extends AnalyzeDeps {
  1015     class GenDotFile extends AnalyzeDeps {
  1153         boolean inverse = false;
  1186         boolean inverse = false;
  1154         boolean compileTimeView = false;
  1187         boolean compileTimeView = false;
  1155         String systemModulePath = System.getProperty("java.home");
  1188         String systemModulePath = System.getProperty("java.home");
  1156         String upgradeModulePath;
  1189         String upgradeModulePath;
  1157         String modulePath;
  1190         String modulePath;
  1158         String rootModule;
  1191         Set<String> rootModules = new HashSet<>();
  1159         Set<String> addmods = new HashSet<>();
  1192         Set<String> addmods = new HashSet<>();
  1160         Runtime.Version multiRelease;
  1193         Runtime.Version multiRelease;
  1161 
  1194 
  1162         boolean hasSourcePath() {
  1195         boolean hasSourcePath() {
  1163             return !addmods.isEmpty() || includePattern != null;
  1196             return !addmods.isEmpty() || includePattern != null;