Created
May 10, 2017 17:20
-
-
Save pvlasov/88b7f66d372bb553cfba415afaab1e9c to your computer and use it in GitHub Desktop.
Call graph visualization with Gephi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Dependencies: | |
- Java Call Graph - https://github.com/gousiosg/java-callgraph. | |
- Gexf4j - https://github.com/francesco-ficarola/gexf4j (download all dependencies with mvn dependency:copy-dependencies) | |
*/ | |
import java.io.BufferedReader; | |
import java.io.File; | |
import java.io.FileReader; | |
import java.io.FileWriter; | |
import java.io.Writer; | |
import java.util.Calendar; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.Map; | |
import java.util.Set; | |
import it.uniroma1.dis.wsngroup.gexf4j.core.EdgeType; | |
import it.uniroma1.dis.wsngroup.gexf4j.core.Gexf; | |
import it.uniroma1.dis.wsngroup.gexf4j.core.Graph; | |
import it.uniroma1.dis.wsngroup.gexf4j.core.Mode; | |
import it.uniroma1.dis.wsngroup.gexf4j.core.Node; | |
import it.uniroma1.dis.wsngroup.gexf4j.core.data.Attribute; | |
import it.uniroma1.dis.wsngroup.gexf4j.core.data.AttributeClass; | |
import it.uniroma1.dis.wsngroup.gexf4j.core.data.AttributeList; | |
import it.uniroma1.dis.wsngroup.gexf4j.core.data.AttributeType; | |
import it.uniroma1.dis.wsngroup.gexf4j.core.impl.GexfImpl; | |
import it.uniroma1.dis.wsngroup.gexf4j.core.impl.StaxGraphWriter; | |
import it.uniroma1.dis.wsngroup.gexf4j.core.impl.data.AttributeListImpl; | |
import it.uniroma1.dis.wsngroup.gexf4j.core.impl.viz.ColorImpl; | |
import it.uniroma1.dis.wsngroup.gexf4j.core.viz.Color; | |
public class CallGraphScanner { | |
public static void main(String[] args) throws Exception { | |
for (String callGraph: args) { | |
Gexf gexf = new GexfImpl(); | |
Calendar date = Calendar.getInstance(); | |
gexf.getMetadata() | |
.setLastModified(date.getTime()) | |
.setCreator("Nasdanika.org") | |
.setDescription("Route and Renderer call graph"); | |
gexf.setVisualization(true); | |
Graph graph = gexf.getGraph(); | |
graph.setDefaultEdgeType(EdgeType.DIRECTED).setMode(Mode.DYNAMIC); | |
AttributeList attrList = new AttributeListImpl(AttributeClass.NODE); | |
Attribute attFullName = attrList.createAttribute("0", AttributeType.STRING, "fullName"); | |
graph.getAttributeLists().add(attrList); | |
Map<String, Node> methodNodes = new HashMap<>(); | |
Set<String> idSet = new HashSet<>(); | |
try (BufferedReader br = new BufferedReader(new FileReader(callGraph))) { | |
String line; | |
while ((line = br.readLine()) != null) { | |
String[] dep = line.split(" "); | |
String source = dep[0]; | |
if (source.startsWith("M:org.nasdanika.cdo.web.routes.app.Renderer:") || source.startsWith("M:org.nasdanika.cdo.web.routes.app.Route:") || source.startsWith("M:org.nasdanika.cdo.web.routes.app.EOperationTarget:")) { | |
int lpidx = source.indexOf("("); | |
if (lpidx != -1) { | |
source = source.substring(0, lpidx); | |
source = source.substring(source.lastIndexOf('.')+1); | |
if (!source.endsWith(":<clinit>")) { | |
String target = dep[1].substring(3); | |
if (target.startsWith("org.nasdanika.cdo.web.routes.app.Renderer:") || target.startsWith("org.nasdanika.cdo.web.routes.app.Route:") || source.startsWith("M:org.nasdanika.cdo.web.routes.app.EOperationTarget:")) { | |
int tlpidx = target.indexOf("("); | |
if (tlpidx != -1) { | |
target = target.substring(0, tlpidx); | |
target = target.substring(target.lastIndexOf('.')+1); | |
if (!source.equals(target)) { | |
Node sourceNode = getMethodNode(graph, source, methodNodes, attFullName); | |
Node targetNode = getMethodNode(graph, target, methodNodes, attFullName); | |
if (idSet.add(sourceNode.getId()+":"+targetNode.getId())) { | |
sourceNode.connectTo(String.valueOf(idSet.size()), targetNode).setEdgeType(EdgeType.DIRECTED); | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
StaxGraphWriter graphWriter = new StaxGraphWriter(); | |
File f = new File(callGraph+".gexf"); | |
try (Writer out = new FileWriter(f, false)) { | |
graphWriter.writeToStream(gexf, out, "UTF-8"); | |
System.out.println(f.getAbsolutePath()); | |
} | |
} | |
} | |
private static Node getMethodNode(Graph graph, String method, Map<String, Node> methodNodes, Attribute attFullName) { | |
int colonIdx = method.indexOf(":"); | |
String methodName = method.substring(colonIdx+1); | |
Node methodNode = methodNodes.get(methodName); | |
if (methodNode == null) { | |
methodNode = graph.createNode(String.valueOf(methodNodes.size())); | |
Color color = new ColorImpl(127, 127, 127); | |
if (method.startsWith("Renderer")) { | |
color.setG(255); | |
} else if (method.startsWith("Route")) { | |
color.setB(255); | |
} else { | |
color.setR(255); | |
} | |
methodNode.setLabel(methodName).setColor(color); | |
methodNode.getAttributeValues().addValue(attFullName, method); | |
methodNodes.put(methodName, methodNode); | |
} | |
return methodNode; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment