package org.lrg.outcode.builder.db;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.JavaModelException;
import org.lrg.outcode.IHindsight;
import org.lrg.outcode.activator.GraphDB;
import org.lrg.outcode.builder.RelTypes;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Label;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.ResourceIterator;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.index.Index;
public class GraphDatasource {
public static GraphDatasource INSTANCE = new GraphDatasource();
public Map<String, Index<Node>> elementsIndex = new HashMap<String, Index<Node>>();
private GraphDatasource() {
};
public Node addNodeToDB(IJavaElement parent, IJavaElement element, String version, String commitID, int added, int removed) {
Node parentNode = findLatestNodeForElementID(parent);
if (parentNode == null)
parentNode = createIJavaElementNode(parent, version, commitID, added, removed);
Node n = createIJavaElementNode(element, version, commitID, added, removed);
parentNode.createRelationshipTo(n, RelTypes.CONTAINS);
n.createRelationshipTo(parentNode, RelTypes.PARENT);
return n;
}
public Node createIJavaElementNode(IJavaElement element, String version, String commitID, int added, int removed) {
String handleIdentifier = element.getHandleIdentifier();
String elementName = element.getElementName();
String label = computeLabel(element);
Node n = createEntityNode(handleIdentifier, elementName, label, element, version, commitID, added, removed);
return n;
}
private String computeLabel(IJavaElement element) {
String label = element.getClass().getSimpleName();
label = label.replace("Resolved", "");
label = label.replace("Source", "");
return label;
}
public Node createEntityNode(String handleIdentifier, String elementName, String stringLabel, IJavaElement element, String version, String commitID, int added, int removed) {
GraphDatabaseService graphDb = GraphDB.instance.getDB();
String vidToFind = element.getHandleIdentifier() + "_" + version;
Label label = Label.label(stringLabel);
Node n = graphDb.findNode(label, IHindsight.VID, vidToFind);
if (n == null) {
Node createNode = graphDb.createNode();
createNode.addLabel(label);
createNode.setProperty(IHindsight.ID, handleIdentifier);
createNode.setProperty(IHindsight.VID, vidToFind);
if (element.getElementType() == IJavaElement.PACKAGE_FRAGMENT)
createNode.setProperty(IHindsight.NAME, element.getPath().makeRelativeTo(element.getJavaProject().getPath()).toPortableString().replaceAll("/", "."));
else
createNode.setProperty(IHindsight.NAME, elementName);
if (element instanceof IMethod) {
IMethod method = (IMethod) element;
try {
createNode.setProperty("code", method.getSource() != null ? method.getSource() : "");
} catch (JavaModelException e) {
e.printStackTrace();
}
}
n = createNode;
n.setProperty(IHindsight.COMMIT, version);
n.setProperty(IHindsight.COMMITID, commitID);
n.setProperty("addedLOC", added);
n.setProperty("removedLOC", removed);
}
return findLatestVersion(n);
}
public Node findFirsNodeForElementID(IJavaElement member) {
Node result = null;
GraphDatabaseService db = GraphDB.instance.getDB();
Label label = Label.label(computeLabel(member));
ResourceIterator<Node> nodes = db.findNodes(label, IHindsight.ID, member.getHandleIdentifier());
if (nodes.hasNext())
result = nodes.next();
nodes.close();
if (result != null)
result = findFirstVersion(result);
return result;
}
public Node findFirstVersion(Node n) {
Node result = n;
Iterable<Relationship> toBefore = n.getRelationships(RelTypes.NEXT, Direction.INCOMING);
while (toBefore != null && toBefore.iterator().hasNext()) {
Relationship next = toBefore.iterator().next();
Node end = next.getEndNode();
Node start = next.getStartNode();
if (end.equals(start)) {// safety check, this should not happen
System.out.println("found NEXT relation to the same node " + start);
break;
}
result = end;
toBefore = result.getRelationships(RelTypes.NEXT, Direction.INCOMING);
}
return result;
}
public Node findLatestNodeForElementID(IJavaElement member) {
Node result = null;
GraphDatabaseService db = GraphDB.instance.getDB();
Label label = Label.label(computeLabel(member));
ResourceIterator<Node> nodes = db.findNodes(label, IHindsight.ID, member.getHandleIdentifier());
if (nodes.hasNext())
result = nodes.next();
nodes.close();
if (result != null)
result = findLatestVersion(result);
return result;
}
public Node findLatestVersion(Node n) {
Node result = n;
Iterable<Relationship> toNext = n.getRelationships(RelTypes.NEXT, Direction.OUTGOING);
while (toNext != null && toNext.iterator().hasNext()) {
Relationship next = toNext.iterator().next();
Node end = next.getEndNode();
Node start = next.getStartNode();
if (end.equals(start))
break;
result = end;
toNext = result.getRelationships(RelTypes.NEXT, Direction.OUTGOING);
}
return result;
}
public Index<Node> getElementTypeIndex(IJavaElement element, String version) {
String key = element.getElementType() + version;
if (elementsIndex.containsKey(key))
return elementsIndex.get(key);
Transaction tx = GraphDB.instance.getDB().beginTx();
try {
elementsIndex.put(key, GraphDB.instance.getDB().index().forNodes(key));
tx.success();
} catch (Exception e) {
e.printStackTrace();
} finally {
tx.close();
}
return elementsIndex.get(key);
}
public Node addProjectToDb(IJavaProject javaProject, String commit, String commitID) {
Node n = createIJavaElementNode(javaProject, commit, commitID, 0, 0);
n.setProperty(IHindsight.COMMIT, Long.parseLong(commit));
n.setProperty(IHindsight.COMMITID, commitID);
return n;
}
public Node addModifiedVersion(ICompilationUnit iCompilationUnit, String version) {
String handleIdentifier = iCompilationUnit.getHandleIdentifier();
GraphDatabaseService db = GraphDB.instance.getDB();
Node n = null;
Label label = Label.label(computeLabel(iCompilationUnit));
String computeVersionWhenIntroduced = computeVersionWhenIntroduced(iCompilationUnit);
if (computeVersionWhenIntroduced.length() > 0) {
String vidToFind = handleIdentifier + "_" + computeVersionWhenIntroduced;
try {
n = db.findNode(label, IHindsight.VID, vidToFind);
if (n != null) {
n = findLatestVersion(n);// this should not be necessary if
// @computeVersionWhenIntroduced
// actually returned the latest
// version
Node createNode = db.createNode();
createNode.addLabel(Label.label(computeLabel(iCompilationUnit)));
createNode.setProperty(IHindsight.NAME, iCompilationUnit.getElementName());
createNode.setProperty(IHindsight.ID, handleIdentifier);
createNode.setProperty(IHindsight.VID, version);
n.createRelationshipTo(createNode, RelTypes.NEXT);
return createNode;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
/* TODO refactor so that it returns latest version */
private String computeVersionWhenIntroduced(IJavaElement member) {
String result = "";
GraphDatabaseService db = GraphDB.instance.getDB();
Label label = Label.label(computeLabel(member));
ResourceIterator<Node> nodes = db.findNodes(label, IHindsight.ID, member.getHandleIdentifier());
if (nodes.hasNext())
result = nodes.next().getProperty(IHindsight.COMMIT).toString();
nodes.close();
return result;
}
public Node addNextVersionNodeToDB(IJavaElement parent, IJavaElement element, String version, String commitID, int added, int removed) {
String handleIdentifier = element.getHandleIdentifier();
GraphDatabaseService graphDb = GraphDB.instance.getDB();
Label label = Label.label(computeLabel(element));
String computeVersionWhenIntroduced = computeVersionWhenIntroduced(element);
Node n = null;
if (computeVersionWhenIntroduced.length() > 0) {
String vidToFind = handleIdentifier + "_" + computeVersionWhenIntroduced;
try {
n = graphDb.findNode(label, IHindsight.VID, vidToFind);
if (n != null) {
Node createIJavaElementNode = createIJavaElementNode(element, version, commitID, added, removed);
n = findLatestVersion(n);
if (!n.getProperty(IHindsight.VID).equals(createIJavaElementNode.getProperty(IHindsight.VID)))
n.createRelationshipTo(createIJavaElementNode, RelTypes.NEXT);
n = createIJavaElementNode;
} else
n = addNodeToDB(parent, element, version, commitID, added, removed);
} catch (Exception e) {
e.printStackTrace();
}
} else
n = addNodeToDB(parent, element, version, commitID, added, removed);
return n;
}
public boolean createdNewCommitNode(String commitID) {
GraphDatabaseService db = GraphDB.instance.getDB();
Label label = Label.label("CommitLabel");
GraphDatabaseService dbService = GraphDB.instance.getDB();
Transaction tx = dbService.beginTx();
try {
Node findNode = db.findNode(label, IHindsight.COMMITID, commitID);
if (findNode != null)
return false;
Node createNode = db.createNode();
createNode.addLabel(label);
createNode.setProperty(IHindsight.COMMITID, commitID);
tx.success();
} catch (Exception e) {
e.printStackTrace();
} finally {
tx.close();
}
return true;
}
}