package org.ntlab.traceDebugger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.ntlab.traceAnalysisPlatform.tracer.trace.MethodInvocation;
import org.ntlab.traceAnalysisPlatform.tracer.trace.Statement;
import org.ntlab.traceAnalysisPlatform.tracer.trace.Trace;
import org.ntlab.traceAnalysisPlatform.tracer.trace.TracePoint;
public class TraceBreakPoints {
private Trace trace;
private Map<String, Map<Integer, TraceBreakPoint>> traceBreakPoints = new HashMap<>();
private List<TracePoint> histories = new LinkedList<>();
private ListIterator<TracePoint> historyIt = histories.listIterator();
private TracePoint curHistPoint;
private int curIdx = -1;
public TraceBreakPoints(Trace trace) {
this.trace = trace;
}
public List<TraceBreakPoint> getAllTraceBreakPoints() {
List<TraceBreakPoint> list = new ArrayList<>();
for (Map<Integer, TraceBreakPoint> innerMap : traceBreakPoints.values()) {
list.addAll(innerMap.values());
}
Collections.sort(list, new Comparator<TraceBreakPoint>() {
@Override
public int compare(TraceBreakPoint arg0, TraceBreakPoint arg1) {
if (arg0.getMethodSignature().equals(arg1.getMethodSignature())) {
return (arg0.getLineNo() < arg1.getLineNo()) ? -1 : 1;
}
return arg0.getMethodSignature().compareTo(arg1.getMethodSignature());
}
});
return list;
}
public boolean addTraceBreakPoint(String inputSignature, int lineNo, long currentTime) {
String methodSignature = findMethodSignaureOnTrace(inputSignature);
if (methodSignature == null) return false;
Map<Integer, TraceBreakPoint> innerMap = traceBreakPoints.get(methodSignature);
if (innerMap == null) {
innerMap = new HashMap<>();
traceBreakPoints.put(methodSignature, innerMap);
}
TraceBreakPoint tbp = new TraceBreakPoint(methodSignature, lineNo, currentTime);
if (!tbp.isAvailable()) return false;
innerMap.put(lineNo, tbp);
addHistories(tbp);
return true;
}
public boolean addTraceBreakPoint(String methodSignature, int lineNo) {
return addTraceBreakPoint(methodSignature, lineNo, 0L);
}
private void removeTraceBreakPoint(String methodSignature, int lineNo) {
Map<Integer, TraceBreakPoint> innerMap = traceBreakPoints.get(methodSignature);
if (innerMap == null) return;
TraceBreakPoint tbp = innerMap.remove(lineNo);
if (tbp != null) removeHistories(tbp);
if (innerMap.isEmpty()) traceBreakPoints.remove(methodSignature);
}
public void removeTraceBreakPoint(TraceBreakPoint traceBreakPoint) {
String methodSignature = traceBreakPoint.getMethodSignature();
int lineNo = traceBreakPoint.getLineNo();
removeTraceBreakPoint(methodSignature, lineNo);
}
private String findMethodSignaureOnTrace(String inputSignature) {
HashSet<String> methodSignatures = trace.getAllMethodSignatures();
for (String signature : methodSignatures) {
String signatureFront = signature.substring(0, signature.indexOf("(") + 1);
String inputSignatureFront = inputSignature.substring(0, inputSignature.indexOf("(") + 1);
if (!(signatureFront.endsWith(inputSignatureFront))) continue;
String signatureBack = signature.substring(signature.indexOf("(") + 1);
String[] signatureArgs = signatureBack.split(",");
String inputSignatureBack = inputSignature.substring(inputSignature.indexOf("(") + 1);
String[] inputSignatureArgs = inputSignatureBack.split(",");
if (signatureArgs.length != inputSignatureArgs.length) continue;
boolean isMatch = true;
for (int i = 0; i < signatureArgs.length; i++) {
if (!(signatureArgs[i].endsWith(inputSignatureArgs[i]))) {
isMatch = false;
break;
}
}
if (isMatch) return signature;
}
return null;
}
private void addHistories(TraceBreakPoint tbp) {
ListIterator<TracePoint> it = histories.listIterator();
Iterator<TracePoint> tbpIt = tbp.getTracePoints().iterator();
if (!(tbpIt.hasNext())) return;
TracePoint addedTp = tbpIt.next();
int idx = 0;
while (it.hasNext()) {
TracePoint tp = it.next();
if (getTime(addedTp) < getTime(tp)) {
it.previous();
it.add(addedTp);
if (idx <= curIdx) {
curIdx++;
}
addedTp = null;
if (!(tbpIt.hasNext())) break;
addedTp = tbpIt.next();
}
idx++;
}
if (addedTp != null) {
it.add(addedTp);
while (tbpIt.hasNext()) {
it.add(tbpIt.next());
}
}
historyIt = histories.listIterator(curIdx + 1); // 次に取得するインデックスに合わせたイテレータを再取得
confirm();
}
private void removeHistories(TraceBreakPoint tbp) {
ListIterator<TracePoint> it = histories.listIterator();
Iterator<TracePoint> tbpIt = tbp.getTracePoints().iterator();
if (!(tbpIt.hasNext())) return;
TracePoint removedTp = tbpIt.next();
int idx = 0;
while (it.hasNext()) {
TracePoint tp = it.next();
if (tp.equals(removedTp)) {
it.remove();
if (tp.equals(curHistPoint)) {
curHistPoint = null; // 現在位置に対応するブレークポイントが削除された場合は現在位置をなしにする
curIdx = -1;
} else if (-1 < curIdx && idx <= curIdx) {
curIdx--;
}
if (!(tbpIt.hasNext())) break;
removedTp = tbpIt.next();
} else {
idx++;
}
}
if (curHistPoint == null) {
historyIt = null;
} else {
historyIt = histories.listIterator(curIdx + 1); // 次に取得するインデックスに合わせたイテレータを再取得
}
confirm();
}
public TracePoint getFirstTracePoint() {
return getNextTracePoint(0L);
}
public TracePoint getNextTracePoint(long time) {
long curHistTime;
if (curHistPoint == null) {
curHistTime = 0L;
curIdx = -1;
historyIt = histories.listIterator();
} else {
curHistTime = getTime(curHistPoint);
}
if (curHistTime <= time) {
while (historyIt.hasNext()) {
TracePoint tp = historyIt.next();
if (tp.equals(curHistPoint)) continue;
curHistPoint = tp;
curIdx++;
if (!checkAvailable(curHistPoint)) continue;
curHistTime = getTime(curHistPoint);
if (curHistTime > time) {
confirm();
return curHistPoint;
}
}
} else {
while (historyIt.hasPrevious()) {
TracePoint tp = historyIt.previous();
if (tp.equals(curHistPoint)) continue;
curIdx--;
if (!checkAvailable(tp)) continue;
curHistTime = getTime(tp);
if (curHistTime <= time) {
confirm();
return curHistPoint;
}
curHistPoint = tp;
}
confirm();
return curHistPoint;
}
confirm();
return null;
}
public TracePoint getPreviousTracePoint(long time) {
long curHistTime;
if (curHistPoint == null) {
curHistTime = Long.MAX_VALUE;
curIdx = histories.size();
historyIt = histories.listIterator(histories.size());
} else {
curHistTime = getTime(curHistPoint);
}
if (curHistTime >= time) {
while (historyIt.hasPrevious()) {
TracePoint tp = historyIt.previous();
if (tp.equals(curHistPoint)) continue;
curHistPoint = tp;
curIdx--;
if (!checkAvailable(curHistPoint)) continue;
curHistTime = getTime(curHistPoint);
if (curHistTime < time) {
confirm();
return curHistPoint;
}
}
} else {
while (historyIt.hasNext()) {
TracePoint tp = historyIt.next();
if (tp.equals(curHistPoint)) continue;
curIdx++;
if (!checkAvailable(tp)) continue;
curHistTime = getTime(tp);
if (curHistTime >= time) {
confirm();
return curHistPoint;
}
curHistPoint = tp;
}
confirm();
return curHistPoint;
}
confirm();
return null;
}
private TraceBreakPoint getTraceBreakPoint(TracePoint tp) {
String signature = tp.getMethodExecution().getSignature();
int lineNo = tp.getStatement().getLineNo();
Map<Integer, TraceBreakPoint> innerMap = traceBreakPoints.get(signature);
return (innerMap != null) ? innerMap.get(lineNo) : null;
}
private boolean checkAvailable(TracePoint tp) {
TraceBreakPoint tbp = getTraceBreakPoint(tp);
return (tbp != null) ? tbp.isAvailable() : false;
}
public void reset() {
curIdx = -1;
historyIt = histories.listIterator();
curHistPoint = null;
}
public void clear() {
traceBreakPoints.clear();
histories.clear();
curIdx = -1;
historyIt = null;
curHistPoint = null;
}
private long getTime(TracePoint tp) {
Statement statement = tp.getStatement();
if (statement instanceof MethodInvocation) {
return ((MethodInvocation)statement).getCalledMethodExecution().getEntryTime();
}
return statement.getTimeStamp();
}
private void confirm() {
System.out.println();
if (curHistPoint == null) {
System.out.println("cur: " + "Not Exist");
} else {
System.out.println("cur: " + getTime(curHistPoint));
}
int idx = 0;
for (TracePoint tp : histories) {
String signature = tp.getMethodExecution().getSignature();
int lineNo = tp.getStatement().getLineNo();
long time = getTime(tp);
String idxStr = (idx == curIdx) ? "←←←←←" : "";
System.out.println(time + " " + signature + " line: " + lineNo + " " + idxStr);
idx++;
}
System.out.println();
}
}