114 // add the overlapped edges from this graph and the given g |
114 // add the overlapped edges from this graph and the given g |
115 g.edges().keySet().stream() |
115 g.edges().keySet().stream() |
116 .forEach(u -> g.adjacentNodes(u).stream() |
116 .forEach(u -> g.adjacentNodes(u).stream() |
117 .filter(v -> isAdjacent(u, v)) |
117 .filter(v -> isAdjacent(u, v)) |
118 .forEach(v -> builder.addEdge(u, v))); |
118 .forEach(v -> builder.addEdge(u, v))); |
119 return builder.build(); |
119 return builder.build().reduce(); |
120 } |
120 } |
121 |
121 |
122 /** |
122 /** |
123 * Returns nodes sorted in topological order. |
123 * Returns nodes sorted in topological order. |
124 */ |
124 */ |
333 .forEach(x -> visit(x, visited, done)); |
333 .forEach(x -> visit(x, visited, done)); |
334 done.add(node); |
334 done.add(node); |
335 result.addLast(node); |
335 result.addLast(node); |
336 } |
336 } |
337 } |
337 } |
338 |
|
339 public static class DotGraph { |
|
340 static final String ORANGE = "#e76f00"; |
|
341 static final String BLUE = "#437291"; |
|
342 static final String GRAY = "#dddddd"; |
|
343 |
|
344 static final String REEXPORTS = ""; |
|
345 static final String REQUIRES = "style=\"dashed\""; |
|
346 static final String REQUIRES_BASE = "color=\"" + GRAY + "\""; |
|
347 |
|
348 static final Set<String> javaModules = modules(name -> |
|
349 (name.startsWith("java.") && !name.equals("java.smartcardio"))); |
|
350 static final Set<String> jdkModules = modules(name -> |
|
351 (name.startsWith("java.") || |
|
352 name.startsWith("jdk.") || |
|
353 name.startsWith("javafx.")) && !javaModules.contains(name)); |
|
354 |
|
355 private static Set<String> modules(Predicate<String> predicate) { |
|
356 return ModuleFinder.ofSystem().findAll() |
|
357 .stream() |
|
358 .map(ModuleReference::descriptor) |
|
359 .map(ModuleDescriptor::name) |
|
360 .filter(predicate) |
|
361 .collect(Collectors.toSet()); |
|
362 } |
|
363 |
|
364 static void printAttributes(PrintWriter out) { |
|
365 out.format(" size=\"25,25\";%n"); |
|
366 out.format(" nodesep=.5;%n"); |
|
367 out.format(" ranksep=1.5;%n"); |
|
368 out.format(" pencolor=transparent;%n"); |
|
369 out.format(" node [shape=plaintext, fontname=\"DejaVuSans\", fontsize=36, margin=\".2,.2\"];%n"); |
|
370 out.format(" edge [penwidth=4, color=\"#999999\", arrowhead=open, arrowsize=2];%n"); |
|
371 } |
|
372 |
|
373 static void printNodes(PrintWriter out, Graph<String> graph) { |
|
374 out.format(" subgraph se {%n"); |
|
375 graph.nodes().stream() |
|
376 .filter(javaModules::contains) |
|
377 .forEach(mn -> out.format(" \"%s\" [fontcolor=\"%s\", group=%s];%n", |
|
378 mn, ORANGE, "java")); |
|
379 out.format(" }%n"); |
|
380 graph.nodes().stream() |
|
381 .filter(jdkModules::contains) |
|
382 .forEach(mn -> out.format(" \"%s\" [fontcolor=\"%s\", group=%s];%n", |
|
383 mn, BLUE, "jdk")); |
|
384 |
|
385 graph.nodes().stream() |
|
386 .filter(mn -> !javaModules.contains(mn) && !jdkModules.contains(mn)) |
|
387 .forEach(mn -> out.format(" \"%s\";%n", mn)); |
|
388 } |
|
389 |
|
390 static void printEdges(PrintWriter out, Graph<String> graph, |
|
391 String node, Set<String> requiresTransitive) { |
|
392 graph.adjacentNodes(node).forEach(dn -> { |
|
393 String attr = dn.equals("java.base") ? REQUIRES_BASE |
|
394 : (requiresTransitive.contains(dn) ? REEXPORTS : REQUIRES); |
|
395 out.format(" \"%s\" -> \"%s\" [%s];%n", node, dn, attr); |
|
396 }); |
|
397 } |
|
398 } |
|
399 |
|
400 |
|
401 } |
338 } |