--- a/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/JdepsTask.java Thu May 28 16:13:55 2015 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1099 +0,0 @@
-/*
- * Copyright (c) 2012, 2014, 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.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.classfile.Dependency.Location;
-import static com.sun.tools.jdeps.Analyzer.Type.*;
-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;
-
-/**
- * Implementation for the jdeps tool for static class dependency analysis.
- */
-class JdepsTask {
- static class BadArgs extends Exception {
- static final long serialVersionUID = 8765093759964640721L;
- BadArgs(String key, Object... args) {
- super(JdepsTask.getMessage(key, args));
- this.key = key;
- this.args = args;
- }
-
- BadArgs showUsage(boolean b) {
- showUsage = b;
- return this;
- }
- final String key;
- final Object[] args;
- boolean showUsage;
- }
-
- static abstract class Option {
- Option(boolean hasArg, String... aliases) {
- this.hasArg = hasArg;
- this.aliases = aliases;
- }
-
- boolean isHidden() {
- return false;
- }
-
- boolean matches(String opt) {
- for (String a : aliases) {
- if (a.equals(opt))
- return true;
- if (hasArg && opt.startsWith(a + "="))
- return true;
- }
- return false;
- }
-
- boolean ignoreRest() {
- return false;
- }
-
- abstract void process(JdepsTask task, String opt, String arg) throws BadArgs;
- final boolean hasArg;
- final String[] aliases;
- }
-
- static abstract class HiddenOption extends Option {
- HiddenOption(boolean hasArg, String... aliases) {
- super(hasArg, aliases);
- }
-
- boolean isHidden() {
- return true;
- }
- }
-
- static Option[] recognizedOptions = {
- new Option(false, "-h", "-?", "-help") {
- void process(JdepsTask task, String opt, String arg) {
- task.options.help = true;
- }
- },
- 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.invalid.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 = SUMMARY;
- }
- },
- new Option(false, "-v", "-verbose",
- "-verbose:package",
- "-verbose:class") {
- void process(JdepsTask task, String opt, String arg) throws BadArgs {
- switch (opt) {
- case "-v":
- case "-verbose":
- task.options.verbose = VERBOSE;
- task.options.filterSameArchive = false;
- task.options.filterSamePackage = false;
- break;
- case "-verbose:package":
- task.options.verbose = PACKAGE;
- break;
- case "-verbose:class":
- task.options.verbose = CLASS;
- break;
- default:
- throw new BadArgs("err.invalid.arg.for.option", opt);
- }
- }
- },
- new Option(true, "-cp", "-classpath") {
- void process(JdepsTask task, String opt, String arg) {
- task.options.classpath = arg;
- }
- },
- new Option(true, "-p", "-package") {
- void process(JdepsTask task, String opt, String arg) {
- task.options.packageNames.add(arg);
- }
- },
- new Option(true, "-e", "-regex") {
- void process(JdepsTask task, String opt, String arg) {
- task.options.regex = arg;
- }
- },
-
- new Option(true, "-f", "-filter") {
- void process(JdepsTask task, String opt, String arg) {
- task.options.filterRegex = arg;
- }
- },
- new Option(false, "-filter:package",
- "-filter:archive",
- "-filter:none") {
- void process(JdepsTask task, String opt, String arg) {
- switch (opt) {
- case "-filter:package":
- task.options.filterSamePackage = true;
- task.options.filterSameArchive = false;
- break;
- case "-filter:archive":
- task.options.filterSameArchive = true;
- task.options.filterSamePackage = false;
- break;
- case "-filter:none":
- task.options.filterSameArchive = false;
- task.options.filterSamePackage = false;
- break;
- }
- }
- },
- 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;
- task.options.showModule = false;
- }
- },
- new Option(false, "-M", "-module") {
- void process(JdepsTask task, String opt, String arg) throws BadArgs {
- task.options.showModule = true;
- task.options.showProfile = false;
- }
- },
- 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;
- // turn off filtering
- task.options.filterSameArchive = false;
- task.options.filterSamePackage = false;
- }
- },
- new Option(false, "-jdkinternals") {
- void process(JdepsTask task, String opt, String arg) {
- task.options.findJDKInternals = true;
- task.options.verbose = CLASS;
- if (task.options.includePattern == null) {
- task.options.includePattern = Pattern.compile(".*");
- }
- }
- },
- new HiddenOption(false, "-verify:access") {
- void process(JdepsTask task, String opt, String arg) {
- task.options.verifyAccess = true;
- task.options.verbose = VERBOSE;
- task.options.filterSameArchive = false;
- task.options.filterSamePackage = false;
- }
- },
- new HiddenOption(true, "-mp") {
- void process(JdepsTask task, String opt, String arg) throws BadArgs {
- task.options.mpath = Paths.get(arg);
- if (!Files.isDirectory(task.options.mpath)) {
- throw new BadArgs("err.invalid.path", arg);
- }
- if (task.options.includePattern == null) {
- task.options.includePattern = Pattern.compile(".*");
- }
- }
- },
- 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(false, "-showlabel") {
- void process(JdepsTask task, String opt, String arg) {
- task.options.showLabel = true;
- }
- },
- new HiddenOption(false, "-q", "-quiet") {
- void process(JdepsTask task, String opt, String arg) {
- task.options.nowarning = true;
- }
- },
- new HiddenOption(true, "-depth") {
- void process(JdepsTask task, String opt, String arg) throws BadArgs {
- try {
- task.options.depth = Integer.parseInt(arg);
- } catch (NumberFormatException e) {
- throw new BadArgs("err.invalid.arg.for.option", opt);
- }
- }
- },
- };
-
- private static final String PROGNAME = "jdeps";
- private final Options options = new Options();
- private final List<String> classes = new ArrayList<>();
-
- private PrintWriter log;
- void setLog(PrintWriter out) {
- log = out;
- }
-
- /**
- * Result codes.
- */
- static final int EXIT_OK = 0, // Completed with no errors.
- EXIT_ERROR = 1, // Completed but reported errors.
- EXIT_CMDERR = 2, // Bad command-line arguments
- EXIT_SYSERR = 3, // System error or resource exhaustion.
- EXIT_ABNORMAL = 4;// terminated abnormally
-
- int run(String[] args) {
- if (log == null) {
- log = new PrintWriter(System.out);
- }
- try {
- handleOptions(args);
- if (options.help) {
- showHelp();
- }
- if (options.version || options.fullVersion) {
- showVersion(options.fullVersion);
- }
- if (classes.isEmpty() && options.includePattern == null) {
- if (options.help || options.version || options.fullVersion) {
- return EXIT_OK;
- } else {
- showHelp();
- return EXIT_CMDERR;
- }
- }
- if (options.regex != null && options.packageNames.size() > 0) {
- showHelp();
- return EXIT_CMDERR;
- }
- if ((options.findJDKInternals || options.verifyAccess) &&
- (options.regex != null || options.packageNames.size() > 0 || options.showSummary)) {
- showHelp();
- return EXIT_CMDERR;
- }
- if (options.showSummary && options.verbose != SUMMARY) {
- showHelp();
- return EXIT_CMDERR;
- }
-
- boolean ok = run();
- return ok ? EXIT_OK : EXIT_ERROR;
- } catch (BadArgs e) {
- reportError(e.key, e.args);
- if (e.showUsage) {
- log.println(getMessage("main.usage.summary", PROGNAME));
- }
- return EXIT_CMDERR;
- } catch (IOException e) {
- return EXIT_ABNORMAL;
- } finally {
- log.flush();
- }
- }
-
- private final List<Archive> sourceLocations = new ArrayList<>();
- private final List<Archive> classpaths = new ArrayList<>();
- private final List<Archive> initialArchives = new ArrayList<>();
- private boolean run() throws IOException {
- buildArchives();
-
- if (options.verifyAccess) {
- return verifyModuleAccess();
- } else {
- return analyzeDeps();
- }
- }
-
- private boolean analyzeDeps() throws IOException {
- Analyzer analyzer = new Analyzer(options.verbose, new Analyzer.Filter() {
- @Override
- public boolean accepts(Location origin, Archive originArchive,
- Location target, Archive targetArchive)
- {
- if (options.findJDKInternals) {
- // accepts target that is JDK class but not exported
- return isJDKModule(targetArchive) &&
- !((Module) targetArchive).isExported(target.getClassName());
- } else if (options.filterSameArchive) {
- // accepts origin and target that from different archive
- return originArchive != targetArchive;
- }
- return true;
- }
- });
-
- // parse classfiles and find all dependencies
- findDependencies(options.apiOnly);
-
- // analyze the dependencies
- analyzer.run(sourceLocations);
-
- // output result
- if (options.dotOutputDir != null) {
- Path dir = Paths.get(options.dotOutputDir);
- Files.createDirectories(dir);
- generateDotFiles(dir, analyzer);
- } else {
- printRawOutput(log, analyzer);
- }
-
- if (options.findJDKInternals && !options.nowarning) {
- showReplacements(analyzer);
- }
- return true;
- }
-
- private boolean verifyModuleAccess() throws IOException {
- // two passes
- // 1. check API dependences where the types of dependences must be re-exported
- // 2. check all dependences where types must be accessible
-
- // pass 1
- findDependencies(true /* api only */);
- Analyzer analyzer = Analyzer.getExportedAPIsAnalyzer();
- boolean pass1 = analyzer.run(sourceLocations);
- if (!pass1) {
- System.out.println("ERROR: Failed API access verification");
- }
- // pass 2
- findDependencies(false);
- analyzer = Analyzer.getModuleAccessAnalyzer();
- boolean pass2 = analyzer.run(sourceLocations);
- if (!pass2) {
- System.out.println("ERROR: Failed module access verification");
- }
- if (pass1 & pass2) {
- System.out.println("Access verification succeeded.");
- }
- return pass1 & pass2;
- }
-
- private void generateSummaryDotFile(Path dir, Analyzer analyzer) throws IOException {
- // If verbose mode (-v or -verbose option),
- // the summary.dot file shows package-level dependencies.
- Analyzer.Type summaryType =
- (options.verbose == PACKAGE || options.verbose == SUMMARY) ? SUMMARY : PACKAGE;
- Path summary = dir.resolve("summary.dot");
- try (PrintWriter sw = new PrintWriter(Files.newOutputStream(summary));
- SummaryDotFile dotfile = new SummaryDotFile(sw, summaryType)) {
- for (Archive archive : sourceLocations) {
- if (!archive.isEmpty()) {
- if (options.verbose == PACKAGE || options.verbose == SUMMARY) {
- if (options.showLabel) {
- // build labels listing package-level dependencies
- analyzer.visitDependences(archive, dotfile.labelBuilder(), PACKAGE);
- }
- }
- analyzer.visitDependences(archive, dotfile, summaryType);
- }
- }
- }
- }
-
- private void generateDotFiles(Path dir, Analyzer analyzer) throws IOException {
- // output individual .dot file for each archive
- if (options.verbose != SUMMARY) {
- for (Archive archive : sourceLocations) {
- if (analyzer.hasDependences(archive)) {
- Path dotfile = dir.resolve(archive.getName() + ".dot");
- try (PrintWriter pw = new PrintWriter(Files.newOutputStream(dotfile));
- DotFileFormatter formatter = new DotFileFormatter(pw, archive)) {
- analyzer.visitDependences(archive, formatter);
- }
- }
- }
- }
- // generate summary dot file
- generateSummaryDotFile(dir, analyzer);
- }
-
- private void printRawOutput(PrintWriter writer, Analyzer analyzer) {
- RawOutputFormatter depFormatter = new RawOutputFormatter(writer);
- RawSummaryFormatter summaryFormatter = new RawSummaryFormatter(writer);
- for (Archive archive : sourceLocations) {
- if (!archive.isEmpty()) {
- analyzer.visitDependences(archive, summaryFormatter, SUMMARY);
- if (analyzer.hasDependences(archive) && options.verbose != SUMMARY) {
- analyzer.visitDependences(archive, depFormatter);
- }
- }
- }
- }
-
- private boolean isValidClassName(String name) {
- if (!Character.isJavaIdentifierStart(name.charAt(0))) {
- return false;
- }
- for (int i=1; i < name.length(); i++) {
- char c = name.charAt(i);
- if (c != '.' && !Character.isJavaIdentifierPart(c)) {
- return false;
- }
- }
- return true;
- }
-
- /*
- * Dep Filter configured based on the input jdeps option
- * 1. -p and -regex to match target dependencies
- * 2. -filter:package to filter out same-package dependencies
- *
- * This filter is applied when jdeps parses the class files
- * and filtered dependencies are not stored in the Analyzer.
- *
- * -filter:archive is applied later in the Analyzer as the
- * containing archive of a target class may not be known until
- * the entire archive
- */
- class DependencyFilter implements Dependency.Filter {
- final Dependency.Filter filter;
- final Pattern filterPattern;
- DependencyFilter() {
- if (options.regex != null) {
- this.filter = Dependencies.getRegexFilter(Pattern.compile(options.regex));
- } else if (options.packageNames.size() > 0) {
- this.filter = Dependencies.getPackageFilter(options.packageNames, false);
- } else {
- this.filter = null;
- }
-
- this.filterPattern =
- options.filterRegex != null ? Pattern.compile(options.filterRegex) : null;
- }
- @Override
- public boolean accepts(Dependency d) {
- if (d.getOrigin().equals(d.getTarget())) {
- return false;
- }
- String pn = d.getTarget().getPackageName();
- if (options.filterSamePackage && d.getOrigin().getPackageName().equals(pn)) {
- return false;
- }
-
- if (filterPattern != null && filterPattern.matcher(pn).matches()) {
- return false;
- }
- return filter != null ? filter.accepts(d) : true;
- }
- }
-
- /**
- * Tests if the given class matches the pattern given in the -include option
- */
- private boolean matches(String classname) {
- if (options.includePattern != null) {
- return options.includePattern.matcher(classname.replace('/', '.')).matches();
- } else {
- return true;
- }
- }
-
- private void buildArchives() throws IOException {
- for (String s : classes) {
- Path p = Paths.get(s);
- if (Files.exists(p)) {
- initialArchives.add(Archive.getInstance(p));
- }
- }
- sourceLocations.addAll(initialArchives);
-
- classpaths.addAll(getClassPathArchives(options.classpath));
- if (options.includePattern != null) {
- initialArchives.addAll(classpaths);
- }
- classpaths.addAll(PlatformClassPath.getModules(options.mpath));
- if (options.mpath != null) {
- initialArchives.addAll(PlatformClassPath.getModules(options.mpath));
- } else {
- classpaths.addAll(PlatformClassPath.getJarFiles());
- }
- // add all classpath archives to the source locations for reporting
- sourceLocations.addAll(classpaths);
- }
-
- private void findDependencies(boolean apiOnly) throws IOException {
- Dependency.Finder finder =
- apiOnly ? Dependencies.getAPIFinder(AccessFlags.ACC_PROTECTED)
- : Dependencies.getClassDependencyFinder();
- Dependency.Filter filter = new DependencyFilter();
-
- Deque<String> roots = new LinkedList<>();
- for (String s : classes) {
- Path p = Paths.get(s);
- if (!Files.exists(p)) {
- if (isValidClassName(s)) {
- roots.add(s);
- } else {
- warning("warn.invalid.arg", s);
- }
- }
- }
-
- // 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<>();
- Set<String> doneClasses = new HashSet<>();
-
- // get the immediate dependencies of the input files
- for (Archive a : initialArchives) {
- for (ClassFile cf : a.reader().getClassFiles()) {
- String classFileName;
- try {
- classFileName = cf.getName();
- } catch (ConstantPoolException e) {
- throw new ClassFileError(e);
- }
-
- // tests if this class matches the -include or -apiOnly option if specified
- if (!matches(classFileName) || (apiOnly && !cf.access_flags.is(AccessFlags.ACC_PUBLIC))) {
- continue;
- }
-
- 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());
- } else {
- // ensure that the parsed class is added the archive
- a.addClass(d.getOrigin());
- }
- }
- for (String name : a.reader().skippedEntries()) {
- warning("warn.skipped.entry", name, a.getPathName());
- }
- }
- }
-
- // add Archive for looking up classes from the classpath
- // for transitive dependency analysis
- Deque<String> unresolved = roots;
- int depth = options.depth > 0 ? options.depth : Integer.MAX_VALUE;
- do {
- String name;
- while ((name = unresolved.poll()) != null) {
- if (doneClasses.contains(name)) {
- continue;
- }
- ClassFile cf = null;
- for (Archive a : classpaths) {
- cf = a.reader().getClassFile(name);
- if (cf != null) {
- String classFileName;
- try {
- classFileName = cf.getName();
- } catch (ConstantPoolException e) {
- throw new ClassFileError(e);
- }
- if (!doneClasses.contains(classFileName)) {
- // if name is a fully-qualified class name specified
- // from command-line, this class might already be parsed
- doneClasses.add(classFileName);
-
- for (Dependency d : finder.findDependencies(cf)) {
- if (depth == 0) {
- // ignore the dependency
- a.addClass(d.getOrigin());
- break;
- } else if (filter.accepts(d)) {
- a.addClass(d.getOrigin(), d.getTarget());
- String cn = d.getTarget().getName();
- if (!doneClasses.contains(cn) && !deque.contains(cn)) {
- deque.add(cn);
- }
- } else {
- // ensure that the parsed class is added the archive
- a.addClass(d.getOrigin());
- }
- }
- }
- break;
- }
- }
- if (cf == null) {
- doneClasses.add(name);
- }
- }
- unresolved = deque;
- deque = new LinkedList<>();
- } while (!unresolved.isEmpty() && depth-- > 0);
- }
-
- public void handleOptions(String[] args) throws BadArgs {
- // process options
- for (int i=0; i < args.length; i++) {
- if (args[i].charAt(0) == '-') {
- String name = args[i];
- Option option = getOption(name);
- String param = null;
- if (option.hasArg) {
- if (name.startsWith("-") && name.indexOf('=') > 0) {
- param = name.substring(name.indexOf('=') + 1, name.length());
- } else if (i + 1 < args.length) {
- param = args[++i];
- }
- if (param == null || param.isEmpty() || param.charAt(0) == '-') {
- throw new BadArgs("err.missing.arg", name).showUsage(true);
- }
- }
- option.process(this, name, param);
- if (option.ignoreRest()) {
- i = args.length;
- }
- } else {
- // process rest of the input arguments
- for (; i < args.length; i++) {
- String name = args[i];
- if (name.charAt(0) == '-') {
- throw new BadArgs("err.option.after.class", name).showUsage(true);
- }
- classes.add(name);
- }
- }
- }
- }
-
- private Option getOption(String name) throws BadArgs {
- for (Option o : recognizedOptions) {
- if (o.matches(name)) {
- return o;
- }
- }
- throw new BadArgs("err.unknown.option", name).showUsage(true);
- }
-
- private void reportError(String key, Object... args) {
- log.println(getMessage("error.prefix") + " " + getMessage(key, args));
- }
-
- private void warning(String key, Object... args) {
- log.println(getMessage("warn.prefix") + " " + getMessage(key, args));
- }
-
- private void showHelp() {
- log.println(getMessage("main.usage", PROGNAME));
- for (Option o : recognizedOptions) {
- String name = o.aliases[0].substring(1); // there must always be at least one name
- name = name.charAt(0) == '-' ? name.substring(1) : name;
- if (o.isHidden() || name.equals("h") || name.startsWith("filter:")) {
- continue;
- }
- log.println(getMessage("main.opt." + name));
- }
- }
-
- private void showVersion(boolean full) {
- log.println(version(full ? "full" : "release"));
- }
-
- private String version(String key) {
- // key=version: mm.nn.oo[-milestone]
- // key=full: mm.mm.oo[-milestone]-build
- if (ResourceBundleHelper.versionRB == null) {
- return System.getProperty("java.version");
- }
- try {
- return ResourceBundleHelper.versionRB.getString(key);
- } catch (MissingResourceException e) {
- return getMessage("version.unknown", System.getProperty("java.version"));
- }
- }
-
- static String getMessage(String key, Object... args) {
- try {
- return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args);
- } catch (MissingResourceException e) {
- throw new InternalError("Missing message: " + key);
- }
- }
-
- private static class Options {
- boolean help;
- boolean version;
- boolean fullVersion;
- boolean showProfile;
- boolean showModule;
- boolean showSummary;
- boolean apiOnly;
- boolean showLabel;
- boolean findJDKInternals;
- boolean nowarning;
- // default is to show package-level dependencies
- // and filter references from same package
- Analyzer.Type verbose = PACKAGE;
- boolean filterSamePackage = true;
- boolean filterSameArchive = false;
- String filterRegex;
- String dotOutputDir;
- String classpath = "";
- int depth = 1;
- Set<String> packageNames = new HashSet<>();
- String regex; // apply to the dependences
- Pattern includePattern; // apply to classes
- // module boundary access check
- boolean verifyAccess;
- Path mpath;
- }
- private static class ResourceBundleHelper {
- static final ResourceBundle versionRB;
- static final ResourceBundle bundle;
- static final ResourceBundle jdkinternals;
-
- static {
- Locale locale = Locale.getDefault();
- try {
- bundle = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdeps", locale);
- } catch (MissingResourceException e) {
- throw new InternalError("Cannot find jdeps resource bundle for locale " + locale);
- }
- try {
- versionRB = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.version");
- } catch (MissingResourceException e) {
- throw new InternalError("version.resource.missing");
- }
- try {
- jdkinternals = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdkinternals");
- } catch (MissingResourceException e) {
- throw new InternalError("Cannot find jdkinternals resource bundle");
- }
- }
- }
-
- /*
- * Returns the list of Archive specified in cpaths and not included
- * initialArchives
- */
- private List<Archive> getClassPathArchives(String cpaths)
- throws IOException
- {
- List<Archive> result = new ArrayList<>();
- if (cpaths.isEmpty()) {
- return result;
- }
- List<Path> paths = new ArrayList<>();
- for (String p : cpaths.split(File.pathSeparator)) {
- if (p.length() > 0) {
- // 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) {
- paths.add(entry);
- }
- }
- } else {
- paths.add(Paths.get(p));
- }
- }
- }
- for (Path path : paths) {
- boolean found = initialArchives.stream()
- .map(Archive::path)
- .anyMatch(p -> isSameFile(path, p));
- if (!found && Files.exists(path)) {
- result.add(Archive.getInstance(path));
- }
- }
- return result;
- }
-
- private boolean isSameFile(Path p1, Path p2) {
- try {
- return Files.isSameFile(p1, p2);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
- class RawOutputFormatter implements Analyzer.Visitor {
- private final PrintWriter writer;
- private String pkg = "";
- RawOutputFormatter(PrintWriter writer) {
- this.writer = writer;
- }
- @Override
- public void visitDependence(String origin, Archive originArchive,
- String target, Archive targetArchive) {
- String tag = toTag(target, targetArchive);
- if (options.verbose == VERBOSE) {
- writer.format(" %-50s -> %-50s %s%n", origin, target, tag);
- } else {
- if (!origin.equals(pkg)) {
- pkg = origin;
- writer.format(" %s (%s)%n", origin, originArchive.getName());
- }
- writer.format(" -> %-50s %s%n", target, tag);
- }
- }
- }
-
- class RawSummaryFormatter implements Analyzer.Visitor {
- private final PrintWriter writer;
- RawSummaryFormatter(PrintWriter writer) {
- this.writer = writer;
- }
- @Override
- public void visitDependence(String origin, Archive originArchive,
- String target, Archive targetArchive) {
- String targetName = targetArchive.getPathName();
- if (options.showModule && isJDKModule(targetArchive)) {
- targetName = ((Module)targetArchive).name();
- }
- writer.format("%s -> %s", originArchive.getName(), targetName);
- if (options.showProfile && isJDKModule(targetArchive)) {
- writer.format(" (%s)", target);
- }
- writer.format("%n");
- }
- }
-
- class DotFileFormatter implements Analyzer.Visitor, AutoCloseable {
- private final PrintWriter writer;
- private final String name;
- DotFileFormatter(PrintWriter writer, Archive archive) {
- this.writer = writer;
- this.name = archive.getName();
- writer.format("digraph \"%s\" {%n", name);
- writer.format(" // Path: %s%n", archive.getPathName());
- }
-
- @Override
- public void close() {
- writer.println("}");
- }
-
- @Override
- public void visitDependence(String origin, Archive originArchive,
- String target, Archive targetArchive) {
- String tag = toTag(target, targetArchive);
- writer.format(" %-50s -> \"%s\";%n",
- String.format("\"%s\"", origin),
- tag.isEmpty() ? target
- : String.format("%s (%s)", target, tag));
- }
- }
-
- class SummaryDotFile implements Analyzer.Visitor, AutoCloseable {
- private final PrintWriter writer;
- private final Analyzer.Type type;
- private final Map<Archive, Map<Archive,StringBuilder>> edges = new HashMap<>();
- SummaryDotFile(PrintWriter writer, Analyzer.Type type) {
- this.writer = writer;
- this.type = type;
- writer.format("digraph \"summary\" {%n");
- }
-
- @Override
- public void close() {
- writer.println("}");
- }
-
- @Override
- public void visitDependence(String origin, Archive originArchive,
- String target, Archive targetArchive) {
- String targetName = type == PACKAGE ? target : targetArchive.getName();
- if (isJDKModule(targetArchive)) {
- Module m = (Module)targetArchive;
- String n = showProfileOrModule(m);
- if (!n.isEmpty()) {
- targetName += " (" + n + ")";
- }
- } else if (type == PACKAGE) {
- targetName += " (" + targetArchive.getName() + ")";
- }
- String label = getLabel(originArchive, targetArchive);
- writer.format(" %-50s -> \"%s\"%s;%n",
- String.format("\"%s\"", origin), targetName, label);
- }
-
- String getLabel(Archive origin, Archive target) {
- if (edges.isEmpty())
- return "";
-
- StringBuilder label = edges.get(origin).get(target);
- return label == null ? "" : String.format(" [label=\"%s\",fontsize=9]", label.toString());
- }
-
- Analyzer.Visitor labelBuilder() {
- // show the package-level dependencies as labels in the dot graph
- return new Analyzer.Visitor() {
- @Override
- public void visitDependence(String origin, Archive originArchive, String target, Archive targetArchive) {
- edges.putIfAbsent(originArchive, new HashMap<>());
- edges.get(originArchive).putIfAbsent(targetArchive, new StringBuilder());
- StringBuilder sb = edges.get(originArchive).get(targetArchive);
- String tag = toTag(target, targetArchive);
- addLabel(sb, origin, target, tag);
- }
-
- void addLabel(StringBuilder label, String origin, String target, String tag) {
- label.append(origin).append(" -> ").append(target);
- if (!tag.isEmpty()) {
- label.append(" (" + tag + ")");
- }
- label.append("\\n");
- }
- };
- }
- }
-
- /**
- * Test if the given archive is part of the JDK
- */
- private boolean isJDKModule(Archive archive) {
- return Module.class.isInstance(archive);
- }
-
- /**
- * If the given archive is JDK archive, this method returns the profile name
- * only if -profile option is specified; it accesses a private JDK API and
- * the returned value will have "JDK internal API" prefix
- *
- * For non-JDK archives, this method returns the file name of the archive.
- */
- private String toTag(String name, Archive source) {
- if (!isJDKModule(source)) {
- return source.getName();
- }
-
- Module module = (Module)source;
- boolean isExported = false;
- if (options.verbose == CLASS || options.verbose == VERBOSE) {
- isExported = module.isExported(name);
- } else {
- isExported = module.isExportedPackage(name);
- }
- if (isExported) {
- // exported API
- return showProfileOrModule(module);
- } else {
- return "JDK internal API (" + source.getName() + ")";
- }
- }
-
- private String showProfileOrModule(Module m) {
- String tag = "";
- if (options.showProfile) {
- Profile p = Profile.getProfile(m);
- if (p != null) {
- tag = p.profileName();
- }
- } else if (options.showModule) {
- tag = m.name();
- }
- return tag;
- }
-
- private Profile getProfile(String name) {
- String pn = name;
- if (options.verbose == CLASS || options.verbose == VERBOSE) {
- int i = name.lastIndexOf('.');
- pn = i > 0 ? name.substring(0, i) : "";
- }
- return Profile.getProfile(pn);
- }
-
- /**
- * Returns the recommended replacement API for the given classname;
- * or return null if replacement API is not known.
- */
- private String replacementFor(String cn) {
- String name = cn;
- String value = null;
- while (value == null && name != null) {
- try {
- value = ResourceBundleHelper.jdkinternals.getString(name);
- } catch (MissingResourceException e) {
- // go up one subpackage level
- int i = name.lastIndexOf('.');
- name = i > 0 ? name.substring(0, i) : null;
- }
- }
- return value;
- };
-
- private void showReplacements(Analyzer analyzer) {
- Map<String,String> jdkinternals = new TreeMap<>();
- boolean useInternals = false;
- for (Archive source : sourceLocations) {
- useInternals = useInternals || analyzer.hasDependences(source);
- for (String cn : analyzer.dependences(source)) {
- String repl = replacementFor(cn);
- if (repl != null) {
- jdkinternals.putIfAbsent(cn, repl);
- }
- }
- }
- if (useInternals) {
- log.println();
- warning("warn.replace.useJDKInternals", getMessage("jdeps.wiki.url"));
- }
- if (!jdkinternals.isEmpty()) {
- log.println();
- log.format("%-40s %s%n", "JDK Internal API", "Suggested Replacement");
- log.format("%-40s %s%n", "----------------", "---------------------");
- for (Map.Entry<String,String> e : jdkinternals.entrySet()) {
- log.format("%-40s %s%n", e.getKey(), e.getValue());
- }
- }
-
- }
-}