in src/graph/ReactorGraph.java [57:169]
public static void main(String[] args) {
try {
// Parse DOT file
MutableGraph originalGraph = new Parser().read(new File("target/graph/reactor-graph.dot"));
// Create final graph
MutableGraph clusteredGraph = mutGraph("G").setDirected(true);
clusteredGraph.graphAttrs().add(GraphAttr.COMPOUND);
clusteredGraph.graphAttrs().add(Label.of("Reactor Graph"));
// Create clusters
Map<String, MutableGraph> clusters = new HashMap<>();
for (String clusterName : CLUSTER_PATTERNS.keySet()) {
String key = "cluster_" + clusterName.replaceAll("\\s+", "");
MutableGraph cluster = mutGraph(key).setDirected(true);
cluster.graphAttrs().add(Label.of(clusterName));
clusters.put(clusterName, cluster);
clusteredGraph.add(cluster);
}
// Map to store new nodes by node name
Map<String, MutableNode> nodeMap = new HashMap<>();
Map<String, String> nodeToCluster = new HashMap<>();
Map<String, String> newNames = new HashMap<>();
// First pass: Create nodes and organize them into clusters
for (MutableNode originalNode : originalGraph.nodes()) {
String oldNodeName = originalNode.name().toString();
if (HIDDEN_NODES.matcher(oldNodeName).matches()) {
continue;
}
String nodeName = oldNodeName;
if (originalNode.get("label") instanceof Label l) {
nodeName = l.value();
}
MutableNode newNode = mutNode(nodeName);
nodeMap.put(nodeName, newNode);
newNames.put(oldNodeName, nodeName);
boolean added = false;
for (Map.Entry<String, Pattern> entry : CLUSTER_PATTERNS.entrySet()) {
if (entry.getValue().matcher(oldNodeName).matches()) {
clusters.get(entry.getKey()).add(newNode);
nodeToCluster.put(nodeName, entry.getKey());
added = true;
break;
}
}
if (!added) {
clusteredGraph.add(newNode);
}
}
// Second pass: Add links to the clustered graph
Map<String, MutableNode> substitutes = new HashMap<>();
Set<Pair> existingLinks = new HashSet<>();
for (MutableNode node : originalGraph.nodes()) {
for (Link link : node.links()) {
String sourceName = newNames.get(link.from().name().toString());
String targetName = newNames.get(link.to().name().toString());
String sourceCluster = nodeToCluster.get(sourceName);
String targetCluster = nodeToCluster.get(targetName);
MutableNode sourceNode = nodeMap.get(sourceName);
MutableNode targetNode = nodeMap.get(targetName);
if (sourceNode != null && targetNode != null ) {
if (!Objects.equals(sourceCluster, targetCluster)) {
// Inter-cluster link
if (sourceCluster != null) {
sourceName = "cluster_" + sourceCluster.replaceAll("\\s+", "");
}
if (targetCluster != null) {
targetName = "cluster_" + targetCluster.replaceAll("\\s+", "");
}
sourceNode = substitutes.computeIfAbsent(sourceName, n -> createNode(n, clusteredGraph));
targetNode = substitutes.computeIfAbsent(targetName, n -> createNode(n, clusteredGraph));
}
if (existingLinks.add(new Pair(sourceName, targetName))) {
sourceNode.addLink(targetNode);
}
}
}
}
// Write intermediary graph to DOT file
String dotContent = Graphviz.fromGraph(clusteredGraph).render(Format.DOT).toString();
Files.write(Paths.get("target/graph/intermediary_graph.dot"), dotContent.getBytes());
System.out.println("Intermediary graph written to intermediary_graph.dot");
// Render graph to SVF
Graphviz.fromGraph(clusteredGraph)
.engine(Engine.FDP)
.render(Format.SVG).toFile(new File("target/graph/intermediary_graph.svg"));
System.out.println("Final graph rendered to intermediary_graph.svg");
// Generate and render the high-level graph
MutableGraph highLevelGraph = generateHighLevelGraph(clusteredGraph, clusters, nodeToCluster, nodeMap);
// Write high-level graph to DOT file
String highLevelDotContent = Graphviz.fromGraph(highLevelGraph).render(Format.DOT).toString();
Files.write(Paths.get("target/graph/high_level_graph.dot"), highLevelDotContent.getBytes());
System.out.println("High-level graph written to high_level_graph.dot");
// Render high-level graph to SVG
Graphviz.fromGraph(highLevelGraph)
.engine(Engine.DOT)
.render(Format.SVG).toFile(new File("target/site/images/maven-deps.svg"));
System.out.println("High-level graph rendered to high_level_graph.svg");
} catch (IOException e) {
e.printStackTrace();
}
}