package org.ntlab.objectGraphAnalyzer;
import java.util.ArrayList;
import java.util.HashMap;
import org.ntlab.trace.FieldUpdate;
import org.ntlab.trace.IMethodExecutionVisitor;
import org.ntlab.trace.IStatementVisitor;
import org.ntlab.trace.MethodExecution;
import org.ntlab.trace.MethodInvocation;
import org.ntlab.trace.Statement;
import org.ntlab.trace.ThreadInstance;
import org.ntlab.trace.Trace;
import org.ntlab.trace.TraceJSON;
public class ObjectGraphReconstructor {
/**
* @param args
*/
public static void main(String[] args) {
final HashMap<String, Integer> callCounts = new HashMap<>();
TraceJSON trace = new TraceJSON("traces\\jEditNormal.trace");
for (ThreadInstance thread: trace.getAllThreads().values()) {
thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() {
@Override
public boolean preVisitThread(ThreadInstance thread) {
return false;
}
@Override
public boolean preVisitMethodExecution(MethodExecution methodExecution) {
String objId = methodExecution.getThisObjId();
if (!Trace.isNull(objId)) {
String key = objId;
if (callCounts.get(key) == null) {
callCounts.put(key, 1);
} else {
callCounts.put(key, callCounts.get(key) + 1);
}
} else {
String className = methodExecution.getThisClassName();
String key = className;
if (callCounts.get(key) == null) {
callCounts.put(key, 1);
} else {
callCounts.put(key, callCounts.get(key) + 1);
}
}
return false;
}
@Override
public boolean postVisitThread(ThreadInstance thread) {
return false;
}
@Override
public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList<MethodExecution> children) {
return false;
}
});
}
final HashMap<String, String> classNames = new HashMap<>();
final HashMap<String, String> links = new HashMap<>();
trace.traverseStatementsInTrace(new IStatementVisitor() {
@Override
public boolean preVisitStatement(Statement statement) {
if (statement instanceof FieldUpdate) {
FieldUpdate f = (FieldUpdate)statement;
String linkId = null;
if (!Trace.isNull(f.getContainerObjId())) {
// 通常のオブジェクト間参照の場合
if (classNames.get(f.getContainerObjId()) == null) {
classNames.put(f.getContainerObjId(), f.getContainerClassName());
}
linkId = f.getContainerObjId() + ":" + f.getFieldName();
} else {
// static フィールドによる参照の場合
if (classNames.get(f.getContainerClassName()) == null) {
classNames.put(f.getContainerClassName(), f.getContainerClassName());
}
linkId = f.getContainerClassName() + ":" + f.getFieldName();
}
if (!Trace.isNull(f.getValueObjId())) {
// null 以外への参照の場合
if (!Trace.isPrimitive(f.getValueClassName())) {
// 参照型の場合のみリンク生成
links.put(linkId, f.getValueObjId());
if (classNames.get(f.getValueObjId()) == null) {
classNames.put(f.getValueObjId(), f.getValueClassName());
}
}
} else {
// null 値の代入の場合、リンクを削除
links.remove(linkId);
}
}
return false;
}
@Override
public boolean postVisitStatement(Statement statement) {
return false;
}
});
String objectLabel;
String objectElements[];
String linkElements[];
String fieldElements[];
System.out.println("digraph jEditNormal {");
for (String objectId: classNames.keySet()) {
if (callCounts.get(objectId) != null && callCounts.get(objectId) >= 200) {
objectElements = objectId.split("\\.");
objectLabel = objectElements[objectElements.length - 1].replace("$", "_");
System.out.println(objectLabel + " [label=\"" + objectId + ":" + classNames.get(objectId)+ "\"]");
}
}
String srcObjId;
String dstObjId;
for (String linkId: links.keySet()) {
linkElements = linkId.split(":");
srcObjId = linkElements[0];
dstObjId = links.get(linkId);
if (callCounts.get(srcObjId) != null && callCounts.get(srcObjId) >= 200
&& callCounts.get(dstObjId) != null && callCounts.get(dstObjId) >= 200) {
fieldElements = linkElements[1].split("\\.");
objectElements = srcObjId.split("\\.");
objectLabel = objectElements[objectElements.length - 1].replace("$", "_");
System.out.println(objectLabel + " -> "
+ dstObjId
+ " [label=\"" + fieldElements[fieldElements.length - 1] +"\"]");
}
}
System.out.println("}");
}
}