--- old/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleDotGraph.java 2017-03-23 16:43:18.000000000 -0700 +++ new/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleDotGraph.java 2017-03-23 16:43:18.000000000 -0700 @@ -32,6 +32,7 @@ import java.io.PrintWriter; import java.lang.module.Configuration; import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.*; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; import java.lang.module.ResolvedModule; @@ -39,8 +40,8 @@ import java.nio.file.Path; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Collections; import java.util.Deque; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -76,10 +77,16 @@ * @param dir output directory */ public boolean genDotFiles(Path dir) throws IOException { + return genDotFiles(dir, DotGraphAttributes.DEFAULT); + } + + public boolean genDotFiles(Path dir, Attributes attributes) + throws IOException + { Files.createDirectories(dir); for (String mn : configurations.keySet()) { Path path = dir.resolve(mn + ".dot"); - genDotFile(path, mn, configurations.get(mn)); + genDotFile(path, mn, configurations.get(mn), attributes); } return true; } @@ -87,7 +94,9 @@ /** * Generate dotfile of the given path */ - public void genDotFile(Path path, String name, Configuration configuration) + public void genDotFile(Path path, String name, + Configuration configuration, + Attributes attributes) throws IOException { // transitive reduction @@ -95,12 +104,12 @@ ? requiresTransitiveGraph(configuration, Set.of(name)) : gengraph(configuration); - DotGraphBuilder builder = new DotGraphBuilder(name, graph); - builder.subgraph("se", "java", DotGraphBuilder.ORANGE, + DotGraphBuilder builder = new DotGraphBuilder(name, graph, attributes); + builder.subgraph("se", "java", attributes.javaSubgraphColor(), DotGraphBuilder.JAVA_SE_SUBGRAPH) - .subgraph("jdk", "jdk", DotGraphBuilder.BLUE, + .subgraph("jdk", "jdk", attributes.jdkSubgraphColor(), DotGraphBuilder.JDK_SUBGRAPH) - .descriptors(graph.nodes().stream() + .modules(graph.nodes().stream() .map(mn -> configuration.findModule(mn).get() .reference().descriptor())); // build dot file @@ -118,12 +127,12 @@ private Graph gengraph(Configuration cf) { Graph.Builder builder = new Graph.Builder<>(); cf.modules().stream() - .forEach(resolvedModule -> { - String mn = resolvedModule.reference().descriptor().name(); + .forEach(rm -> { + String mn = rm.name(); builder.addNode(mn); - resolvedModule.reads().stream() - .map(ResolvedModule::name) - .forEach(target -> builder.addEdge(mn, target)); + rm.reads().stream() + .map(ResolvedModule::name) + .forEach(target -> builder.addEdge(mn, target)); }); Graph rpg = requiresTransitiveGraph(cf, builder.nodes); @@ -149,22 +158,103 @@ visited.add(mn); builder.addNode(mn); - ModuleDescriptor descriptor = cf.findModule(mn).get() - .reference().descriptor(); - descriptor.requires().stream() - .filter(d -> d.modifiers().contains(TRANSITIVE) + cf.findModule(mn).get() + .reference().descriptor().requires().stream() + .filter(d -> d.modifiers().contains(TRANSITIVE) || d.name().equals("java.base")) - .map(d -> d.name()) - .forEach(d -> { - deque.add(d); - builder.addEdge(mn, d); - }); + .map(Requires::name) + .forEach(d -> { + deque.add(d); + builder.addEdge(mn, d); + }); } return builder.build().reduce(); } - public static class DotGraphBuilder { + public interface Attributes { + static final String ORANGE = "#e76f00"; + static final String BLUE = "#437291"; + static final String BLACK = "#000000"; + static final String DARK_GRAY = "#999999"; + static final String LIGHT_GRAY = "#dddddd"; + + int fontSize(); + String fontName(); + String fontColor(); + + int arrowSize(); + int arrowWidth(); + String arrowColor(); + + default double rankSep() { + return 1; + } + + default List> ranks() { + return Collections.emptyList(); + } + + default int weightOf(String s, String t) { + return 1; + } + + default String requiresMandatedColor() { + return LIGHT_GRAY; + } + + default String javaSubgraphColor() { + return ORANGE; + } + + default String jdkSubgraphColor() { + return BLUE; + } + } + + static class DotGraphAttributes implements Attributes { + static final DotGraphAttributes DEFAULT = new DotGraphAttributes(); + + static final String FONT_NAME = "DejaVuSans"; + static final int FONT_SIZE = 12; + static final int ARROW_SIZE = 1; + static final int ARROW_WIDTH = 2; + + @Override + public int fontSize() { + return FONT_SIZE; + } + + @Override + public String fontName() { + return FONT_NAME; + } + + @Override + public String fontColor() { + return BLACK; + } + + @Override + public int arrowSize() { + return ARROW_SIZE; + } + + @Override + public int arrowWidth() { + return ARROW_WIDTH; + } + + @Override + public String arrowColor() { + return DARK_GRAY; + } + } + + private static class DotGraphBuilder { + static final String REEXPORTS = ""; + static final String REQUIRES = "style=\"dashed\""; + static final Set JAVA_SE_SUBGRAPH = javaSE(); static final Set JDK_SUBGRAPH = jdk(); @@ -215,41 +305,20 @@ } } - static final String ORANGE = "#e76f00"; - static final String BLUE = "#437291"; - static final String GRAY = "#dddddd"; - static final String BLACK = "#000000"; - - static final String FONT_NAME = "DejaVuSans"; - static final int FONT_SIZE = 12; - static final int ARROW_SIZE = 1; - static final int ARROW_WIDTH = 2; - static final int RANK_SEP = 1; - - static final String REEXPORTS = ""; - static final String REQUIRES = "style=\"dashed\""; - static final String REQUIRES_BASE = "color=\"" + GRAY + "\""; - - // can be configured - static double rankSep = RANK_SEP; - static String fontColor = BLACK; - static String fontName = FONT_NAME; - static int fontsize = FONT_SIZE; - static int arrowWidth = ARROW_WIDTH; - static int arrowSize = ARROW_SIZE; - static final Map weights = new HashMap<>(); - static final List> ranks = new ArrayList<>(); - private final String name; private final Graph graph; private final Set descriptors = new TreeSet<>(); private final List subgraphs = new ArrayList<>(); - public DotGraphBuilder(String name, Graph graph) { + private final Attributes attributes; + public DotGraphBuilder(String name, + Graph graph, + Attributes attributes) { this.name = name; this.graph = graph; + this.attributes = attributes; } - public DotGraphBuilder descriptors(Stream descriptors) { + public DotGraphBuilder modules(Stream descriptors) { descriptors.forEach(this.descriptors::add); return this; } @@ -260,22 +329,27 @@ out.format("digraph \"%s\" {%n", name); out.format(" nodesep=.5;%n"); - out.format(" ranksep=%f;%n", rankSep); + out.format(" ranksep=%f;%n", attributes.rankSep()); out.format(" pencolor=transparent;%n"); - out.format(" node [shape=plaintext, fontname=\"%s\", fontsize=%d, margin=\".2,.2\"];%n", - fontName, fontsize); - out.format(" edge [penwidth=%d, color=\"#999999\", arrowhead=open, arrowsize=%d];%n", - arrowWidth, arrowSize); + out.format(" node [shape=plaintext, fontcolor=\"%s\", fontname=\"%s\"," + + " fontsize=%d, margin=\".2,.2\"];%n", + attributes.fontColor(), + attributes.fontName(), + attributes.fontSize()); + out.format(" edge [penwidth=%d, color=\"%s\", arrowhead=open, arrowsize=%d];%n", + attributes.arrowWidth(), + attributes.arrowColor(), + attributes.arrowSize()); // same RANKS - ranks.stream() - .map(nodes -> descriptors.stream() + attributes.ranks().stream() + .map(nodes -> descriptors.stream() .map(ModuleDescriptor::name) .filter(nodes::contains) .map(mn -> "\"" + mn + "\"") .collect(joining(","))) - .filter(group -> group.length() > 0) - .forEach(group -> out.format(" {rank=same %s}%n", group)); + .filter(group -> group.length() > 0) + .forEach(group -> out.format(" {rank=same %s}%n", group)); subgraphs.forEach(subgraph -> { out.format(" subgraph %s {%n", subgraph.name); @@ -314,10 +388,14 @@ String mn = md.name(); edges.stream().forEach(dn -> { - String attr = dn.equals("java.base") ? REQUIRES_BASE - : (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES); + String attr; + if (dn.equals("java.base")) { + attr = "color=\"" + attributes.requiresMandatedColor() + "\""; + } else { + attr = (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES); + } - int w = weightOf(mn, dn); + int w = attributes.weightOf(mn, dn); if (w > 1) { if (!attr.isEmpty()) attr += ", "; @@ -328,41 +406,5 @@ }); } - public int weightOf(String s, String t) { - int w = weights.getOrDefault(s + ":" + t, 1); - if (w != 1) - return w; - if (s.startsWith("java.") && t.startsWith("java.")) - return 10; - return 1; - } - - public static void sameRankNodes(Set nodes) { - ranks.add(nodes); - } - - public static void weight(String s, String t, int w) { - weights.put(s + ":" + t, w); - } - - public static void setRankSep(double value) { - rankSep = value; - } - - public static void setFontSize(int size) { - fontsize = size; - } - - public static void setFontColor(String color) { - fontColor = color; - } - - public static void setArrowSize(int size) { - arrowSize = size; - } - - public static void setArrowWidth(int width) { - arrowWidth = width; - } } }