Newer
Older
MagnetRON / src / org / ntlab / deltaViewer / CollaborationObjectCallGraph.java
package org.ntlab.deltaViewer;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.ntlab.deltaExtractor.ExtractedStructure;
import org.ntlab.trace.MethodExecution;
import org.ntlab.trace.Reference;
import org.ntlab.trace.TracePoint;

/**
 * CollaborationObjectCallGraph is IObjectCallGraph implementation class to merge ExtractedStructure.
 * 
 * @author Nitta Lab.
 */
public class CollaborationObjectCallGraph implements IObjectCallGraph {
	private Set<Reference> references = new HashSet<>();
	private List<MethodExecution> startPoints = new ArrayList<>(); // Common ancestor point
	private List<TracePoint> relatedPoints = new ArrayList<>();

	public CollaborationObjectCallGraph(ExtractedStructure e) {
		references.addAll(e.getDelta().getSrcSide());
		references.addAll(e.getDelta().getDstSide());
		startPoints.add(e.getCoordinator());
		relatedPoints.add(e.getRelatedTracePoint().duplicate());
	}

	@Override
	public List<Reference> getReferences() {
		return new ArrayList<Reference>(references); // Convert to List from Set.
	}

	@Override
	public List<MethodExecution> getStartPoints() {
		return startPoints;
	}

	@Override
	public List<TracePoint> getRelatedPoints() {
		return relatedPoints;
	}

	@Override
	public Map<MethodExecution, List<MethodExecution>> getCallTree() {
		return null;
	}

	/**
	 * Merge ExtractedStructure not to overlap reference.
	 * @param e ExtractedStructure to be merged into the field.
	 */
	public void merge(ExtractedStructure e) {
		references.addAll(e.getDelta().getSrcSide());
		references.addAll(e.getDelta().getDstSide());

		// There may be bug. (Two object has each coordinator like JHotDraw Transform)
		MethodExecution thisStartPoint = startPoints.get(0);
		MethodExecution tmp = thisStartPoint;
		MethodExecution thisRoot = thisStartPoint.getParent();
		MethodExecution otherStartPoint = e.getCoordinator();
		while(thisRoot != null) { // Get Root of thisStartPoint.
			tmp = tmp.getParent();
			thisRoot = tmp.getParent();
		}
		thisRoot = tmp;
		/* lowest common ancestor algorithm */
		MethodExecution lca = lowestCommonAncestor(thisRoot, thisStartPoint, otherStartPoint);
		startPoints.clear();
		startPoints.add(lca);

		// Is it in time stamp order?
		TracePoint otherRelatedTp = e.getRelatedTracePoint().duplicate();
		relatedPoints.add(otherRelatedTp);
		relatedPoints = sortTracePointByTimeStamp(relatedPoints);
	}

	/**
	 * Search lowest common ancestor(lca) of p and q.
	 * @param root
	 * @param p
	 * @param q
	 * @return Lca methodExecution.
	 */
	public MethodExecution lowestCommonAncestor(MethodExecution root, MethodExecution p, MethodExecution q) {
		if(root == null || root == p || root == q)  return root;
		Set<MethodExecution> pRoots = new HashSet<>();
		MethodExecution pTmp = p;
		while (!root.equals(pTmp) && pTmp != null) {
			pRoots.add(pTmp);
			pTmp = pTmp.getParent();
		}
		pRoots.add(root);
		MethodExecution qTmp = q;
		while (!root.equals(qTmp) && qTmp != null) {
			if (pRoots.contains(qTmp)) return qTmp;
			qTmp = qTmp.getParent();
		}
		return root;
	}

	/**
	 * Sort tracePoint in time stamp order.
	 * @param tpList TracePoint List to sort.
	 * @return Sorted TracePoint List.
	 */
	private List<TracePoint> sortTracePointByTimeStamp(List<TracePoint> tpList) {
		List<TracePoint> cloneTpList = new ArrayList<>(tpList);
		List<TracePoint> sortedTpList = cloneTpList.stream().sorted(new Comparator<TracePoint>() {
			@Override
			public int compare(TracePoint tp1, TracePoint tp2) {
				long tp1TimeStamp = tp1.getStatement().getTimeStamp();
				long tp2TimeStamp = tp2.getStatement().getTimeStamp();
				if (tp1TimeStamp > tp2TimeStamp) return 1;
				else if (tp1TimeStamp < tp2TimeStamp) return -1;
				return 0;
			}
		}).collect(Collectors.toList());
		return sortedTpList;
	}
}