/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.graphdht.hashgraph;
import java.io.Serializable;
import java.util.*;
import org.graphdht.hashcontainer.HTServiceFactory;
import org.graphdht.hashcontainer.SimpleHT;
import org.graphdht.hashcontainer.SimpleHTServiceFactory;
import org.graphdht.openchord.OpenChordHTServiceFactory;
import org.neo4j.graphdb.*;
import org.neo4j.kernel.impl.transaction.TransactionFailureException;
import javax.transaction.TransactionManager;
import org.graphdht.dht.HTService;
/**
* @author alex
*/
public class SimpleNodeManager {
HTServiceFactory fact = null;
HTService<Long, SimplePrimitive> nodeAndRelMap;
//SimpleHT<Node> nodeMap;
//SimpleHT<Relationship> relationshipMap;
SimpleNodeManager() {
nodeAndRelMap = new SimpleHT<Long, SimplePrimitive>();
//nodeMap = new SimpleHT<Node>();
//relationshipMap = new SimpleHT<Relationship>();
//create reference node
Node referenceNode = new SimpleNode(0L, this);
//nodeMap.put(referenceNode.getId(), referenceNode );
nodeAndRelMap.put(referenceNode.getId(), (SimplePrimitive) referenceNode);
}
public SimpleNodeManager(String config) {
if ("simple".equals(config)) {
fact = new SimpleHTServiceFactory<PropertyContainer>();
} else if ("openchord".equals(config)) {
fact = new OpenChordHTServiceFactory<SimplePropertyContainer>();
} else {
throw new RuntimeException("Option for HTService not avilable");
}
nodeAndRelMap = fact.createHTService();
//nodeMap = new SimpleHT<Node>();
//relationshipMap = new SimpleHT<Relationship>();
//create reference node
Node referenceNode = new SimpleNode(0L, this);
//nodeMap.put(referenceNode.getId(), referenceNode );
nodeAndRelMap.put(referenceNode.getId(), (SimplePrimitive) referenceNode);
}
public Node createNode() {
Node node = null;
node = new SimpleNode(generateNextId(), this);
//this.nodeMap.put(node.getId(), node);
this.nodeAndRelMap.put(node.getId(), (SimplePrimitive) node);
return node;
}
public Node getNodeById(long id) {
//return this.nodeMap.get(id);
SimpleNode node = (SimpleNode) this.nodeAndRelMap.get(id);
node.setSimpleNodeManager(this);
return node;
}
public Relationship getRelationshipById(long id) {
//return this.relationshipMap.get(id);
SimpleRelationship rel = (SimpleRelationship) this.nodeAndRelMap.get(id);
rel.setSimpleNodeManager(this);
return rel;
}
public Node getReferenceNode() {
//return this.nodeMap.get(new Long(0));
SimpleNode node = (SimpleNode) this.nodeAndRelMap.get(new Long(0));
node.setSimpleNodeManager(this);
return node;
}
/**
* Lists all the nodes that belong to the graph.
* This method should be avoided at all costs since it may cause OutOfMemoryError
* @return
*/
public Iterable<Node> getAllNodes() {
//return this.nodeMap.getAllValues();
Collection<Node> nodes = new ArrayList<Node>();
for (SimplePrimitive node : this.nodeAndRelMap.getAllValues()) {
node.setSimpleNodeManager(this);
if (node.getClass().equals(SimpleNode.class)) {
nodes.add((Node) node);
}
}
return nodes;
}
public Iterable<RelationshipType> getRelationshipTypes() {
/*Map<RelationshipType, Integer> m = new HashMap<RelationshipType, Integer>();
for (Relationship e : this.relationshipMap.getAllValues()) {
if (!m.containsKey(e.getType())) {
m.put(e.getType(), 0);
}
}
return m.keySet();*/
Map<RelationshipType, Integer> m = new HashMap<RelationshipType, Integer>();
for (SimplePrimitive e : this.nodeAndRelMap.getAllValues()) {
e.setSimpleNodeManager(this);
//FIXME this comparison might cause problem
if (e.getClass() == SimpleRelationship.class) {
if (!m.containsKey(((Relationship) e).getType())) {
m.put(((Relationship) e).getType(), 0);
}
}
}
return m.keySet();
}
public void shutdown() {
//TODO Does it make sense to shutdown Chord here?
return;
}
//methods that should not be implemented for remote DBs
public boolean enableRemoteShell() {
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean enableRemoteShell(Map<String, Serializable> initialProperties) {
throw new UnsupportedOperationException("Not supported yet.");
}
public Transaction beginTx() {
System.out.println("Stub transaction started!!");
return new PlaceboTransaction(null);
}
//methods that should not be implemented for remote DBs
//private methods that need to be changed or put alsewhere
//-1 is used by Neo4J Embedded to represent an id of something that does not exist
static long nextId = 1;
static boolean thereIsNextId = true;
private static long generateNextId() {
if (thereIsNextId == false) {
throw new OverFlowException();
}
if (nextId == Long.MAX_VALUE) {
thereIsNextId = false; //last value guaranteed to be unique
}
return nextId++;
}
public void deleteRelationship(Long aLong) {
//isolated nodes should also be deleted
//Relationship rel = this.relationshipMap.get(aLong);
SimplePrimitive rel = this.nodeAndRelMap.get(aLong);
rel.setSimpleNodeManager(this);
SimpleNode startNode = (SimpleNode) this.getNodeById(
((SimpleRelationship) rel).getStartNode().getId());
SimpleNode endNode = (SimpleNode) this.getNodeById(
((SimpleRelationship) rel).getEndNode().getId());
startNode.deleteRelationship(aLong);
endNode.deleteRelationship(aLong);
//this.relationshipMap.remove(aLong);
this.nodeAndRelMap.remove(aLong);
}
public Relationship createRelationship(long simpleNodeId, long otherNodeId, RelationshipType type) {
//SimpleNode otherNode = (SimpleNode)this.nodeMap.get(otherNodeId);
SimpleNode otherNode = (SimpleNode) this.nodeAndRelMap.get(otherNodeId);
otherNode.setSimpleNodeManager(this);
if (otherNode != null) {
Relationship rel = new SimpleRelationship(generateNextId(), simpleNodeId, otherNodeId, type, true, this);
//this.relationshipMap.put(rel.getId(), rel);
this.nodeAndRelMap.put(rel.getId(), (SimplePrimitive) rel);
otherNode.addRelationship(rel);
return rel;
} else {
throw new org.neo4j.graphdb.NotFoundException("The destiny node of this relationship does not exist in the graph");
}
}
public void deleteNode(Long aLong) {
//return this.nodeMap.remove(aLong);
//Node node = (Node) this.nodeAndRelMap.get(aLong); //confirms if this is really a node
this.nodeAndRelMap.remove(aLong);
}
/**
* This class should be kept like this
* Since this is an implementation of Neo4J over Chord two different aspects must be balanced
* - Neo4J transaction tests must pass
* - Chord is non transactional so real transactions should not occur
*/
private static class PlaceboTransaction implements Transaction {
private final TransactionManager transactionManager;
PlaceboTransaction(TransactionManager transactionManager) {
// we should override all so null is ok
this.transactionManager = transactionManager;
}
public void failure() {
try {
transactionManager.getTransaction().setRollbackOnly();
} catch (Exception e) {
throw new TransactionFailureException(
"Failed to mark transaction as rollback only.", e);
}
}
public void success() {
}
public void finish() {
}
}
}