package org.openntf.domino.graph2.impl; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Logger; import javolution.util.FastTable; import org.openntf.domino.Database; import org.openntf.domino.DbDirectory; import org.openntf.domino.Session; import org.openntf.domino.big.NoteCoordinate; import org.openntf.domino.big.NoteList; //import org.openntf.domino.big.impl.DbCache; import org.openntf.domino.graph2.DConfiguration; import org.openntf.domino.graph2.DElementStore; import org.openntf.domino.graph2.DKeyResolver; import org.openntf.domino.graph2.exception.ElementKeyException; import org.openntf.domino.utils.DominoUtils; import org.openntf.domino.utils.Factory; import org.openntf.domino.utils.Factory.SessionType; import com.tinkerpop.blueprints.Edge; import com.tinkerpop.blueprints.Element; import com.tinkerpop.blueprints.Features; import com.tinkerpop.blueprints.Graph; import com.tinkerpop.blueprints.GraphQuery; import com.tinkerpop.blueprints.Vertex; import com.tinkerpop.blueprints.util.MultiIterable; public class DGraph implements org.openntf.domino.graph2.DGraph { @SuppressWarnings("unused") private static final Logger log_ = Logger.getLogger(DGraph.class.getName()); public static final Set<String> EMPTY_IDS = Collections.emptySet(); private DConfiguration configuration_; protected Graph extendedGraph_; @SuppressWarnings("unused") // private DbCache dbCache_; public static class GraphTransaction extends FastTable<Element> { private static final long serialVersionUID = 1L; } public static ThreadLocal<GraphTransaction> localTxn = new ThreadLocal<GraphTransaction>() { @Override public GraphTransaction get() { if (super.get() == null) { super.set(new GraphTransaction()); } return super.get(); } }; public DGraph(final DConfiguration config) { configuration_ = config; config.setGraph(this); } protected Map<Class<?>, Long> getTypeMap() { return configuration_.getTypeMap(); } public DConfiguration getConfiguration() { return configuration_; } public void setConfiguration(final DConfiguration configuration) { configuration_ = configuration; } @Override public Features getFeatures() { // TODO Implement this return null; } @Override public Element getElement(final Object id) { if (id instanceof NoteCoordinate) { } DElementStore store = findElementStore(id); Element result = store.getElement(id); return result; } @Override public Vertex addVertex(final Object id) { return findElementStore(id).addVertex(id); } @Override public Vertex getVertex(final Object id) { return findElementStore(id).getVertex(id); } @Override public void removeVertex(final Vertex vertex) { findElementStore(vertex).removeVertex(vertex); } @Override public Iterable<Vertex> getVertices() { List<Iterable<Vertex>> storeList = new ArrayList<Iterable<Vertex>>(); for (DElementStore store : getElementStores().values()) { storeList.add(store.getVertices()); } return new MultiIterable<Vertex>(storeList); } @Override public Iterable<Vertex> getVertices(final String key, final Object value) { List<Iterable<Vertex>> storeList = new ArrayList<Iterable<Vertex>>(); for (DElementStore store : getElementStores().values()) { storeList.add(store.getVertices(key, value)); } return new MultiIterable<Vertex>(storeList); } @Override public Edge addEdge(final Object id, final Vertex outVertex, final Vertex inVertex, final String label) { DEdge result = null; // if (id != null) { // System.out.println("TEMP DEBUG: Adding " + label + " edge with id " + String.valueOf(id)); result = (DEdge) findElementStore(id).addEdge(id); result.setLabel(label); result.setInVertex(inVertex); result.setOutVertex(outVertex); // } else { // //TODO NTF implementation // System.out.println("TEMP DEBUG: id is null so we don't have an implementation yet."); // } return result; } @Override public Edge getEdge(final Object id) { if (id instanceof NoteCoordinate) { } return findElementStore(id).getEdge(id); } @Override public void removeEdge(final Edge edge) { findElementStore(edge).removeEdge(edge); } public void removeEdge(final Edge edge, final Vertex removingVertex) { findElementStore(edge).removeEdge(edge, removingVertex); } @Override public Iterable<Edge> getEdges() { List<Iterable<Edge>> storeList = new ArrayList<Iterable<Edge>>(); for (DElementStore store : getElementStores().values()) { storeList.add(store.getEdges()); } return new MultiIterable<Edge>(storeList); } @Override public Iterable<Edge> getEdges(final String key, final Object value) { List<Iterable<Edge>> storeList = new ArrayList<Iterable<Edge>>(); for (DElementStore store : getElementStores().values()) { storeList.add(store.getEdges(key, value)); } return new MultiIterable<Edge>(storeList); } @Override public GraphQuery query() { // TODO Implement this or remove comment return null; } @Override public void shutdown() { } @Override public Object getRawGraph() { // TODO Implement this or remove comment return null; } @SuppressWarnings("deprecation") @Override public void stopTransaction(final Conclusion conclusion) { // TODO Implement this or remove comment } @Override public void commit() { GraphTransaction txn = localTxn.get(); Iterator<Element> it = txn.iterator(); while (it.hasNext()) { Element elem = it.next(); if (elem instanceof DElement) { DElement delem = (DElement) elem; delem.applyChanges(); DElementStore store = findElementStore(elem.getId()); // store.uncache(delem); } it.remove(); } } @Override public void rollback() { localTxn.set(null); } @Override public void startTransaction(final Element elem) { GraphTransaction txn = localTxn.get(); txn.add(elem); } @Override public Object findDelegate(final Object delegateKey) { DElementStore store = findElementStore(delegateKey); return store.findElementDelegate(delegateKey, Element.class); } @Override public void removeDelegate(final Element element) { DElementStore store = findElementStore(element); store.removeElementDelegate(element); } @Override public Map<Long, DElementStore> getElementStores() { return configuration_.getElementStores(); } @Override public DElementStore findElementStore(final Element element) { DElementStore result = null; Class<?> type = element.getClass(); Long key = getTypeMap().get(type); if (key != null) { result = findElementStore(key); } else { //TODO NTF Keep?? result = findElementStore(element.getId()); } if (result == null) { result = getDefaultElementStore(); } return result; } @Override public DElementStore findElementStore(final Class<?> type) { DElementStore result = getDefaultElementStore(); Long key = getTypeMap().get(type); if (key != null) { DElementStore chk = getElementStores().get(key); if (chk != null) { result = chk; } } return result; } @Override public DElementStore findElementStore(final Object delegateKey) { DElementStore result = null; if (delegateKey == null) { // System.out.println("delegateKey is null"); return getDefaultElementStore(); } if (delegateKey instanceof CharSequence) { CharSequence skey = (CharSequence) delegateKey; // System.out.println("delegateKey is CharSequence " + skey.length()); if (skey.length() == 16) { if (DominoUtils.isReplicaId(skey)) { Long rid = NoteCoordinate.Utils.getLongFromReplid(skey); result = getElementStores().get(rid); if (result == null) { DElementStore newStore = new org.openntf.domino.graph2.impl.DElementStore(); newStore.setStoreKey(rid); newStore.setConfiguration(this.getConfiguration()); getElementStores().put(rid, newStore); // System.out.println("TEMP DEBUG Added new dynamic element store " + String.valueOf(rid)); result = newStore; } } else { throw new ElementKeyException("Cannot resolve a key of " + skey.toString()); } } else if (skey.length() == 32) { result = getDefaultElementStore(); } else if (skey.length() > 50) { String prefix = skey.subSequence(0, 2).toString(); if (prefix.equals("EC") || prefix.equals("ED") || prefix.equals("ET") || prefix.equals("EU")) { CharSequence mid = skey.subSequence(2, 50); if (DominoUtils.isMetaversalId(mid)) { CharSequence ridStr = skey.subSequence(2, 18); Long rid = NoteCoordinate.Utils.getLongFromReplid(ridStr); result = getElementStores().get(rid); if (result == null) { DElementStore newStore = new org.openntf.domino.graph2.impl.DElementStore(); newStore.setStoreKey(rid); newStore.setConfiguration(this.getConfiguration()); getElementStores().put(rid, newStore); // System.out.println("TEMP DEBUG Added new dynamic element store " + String.valueOf(rid)); result = newStore; } } } else if (prefix.equals("VC") || prefix.equals("VD") || prefix.equals("VT") || prefix.equals("VU")) { CharSequence mid = skey.subSequence(2, 50); if (DominoUtils.isMetaversalId(mid)) { CharSequence ridStr = skey.subSequence(2, 18); Long rid = NoteCoordinate.Utils.getLongFromReplid(ridStr); result = getElementStores().get(rid); if (result == null) { DElementStore newStore = new org.openntf.domino.graph2.impl.DElementStore(); newStore.setStoreKey(rid); newStore.setConfiguration(this.getConfiguration()); getElementStores().put(rid, newStore); // System.out.println("TEMP DEBUG Added new dynamic element store " + String.valueOf(rid)); result = newStore; } } } if (result == null) { throw new ElementKeyException("Cannot resolve a key of " + skey.toString()); } } else if (skey.length() > 16) { CharSequence prefix = skey.subSequence(0, 16); if (DominoUtils.isReplicaId(prefix)) { // System.out.println("TEMP DEBUG Attempting to resolve replica id " + prefix + " to an element store"); Long rid = NoteCoordinate.Utils.getLongFromReplid(prefix); result = getElementStores().get(rid); if (result == null) { DElementStore newStore = new org.openntf.domino.graph2.impl.DElementStore(); newStore.setStoreKey(rid); newStore.setConfiguration(this.getConfiguration()); getElementStores().put(rid, newStore); // System.out.println("TEMP DEBUG Added new dynamic element store " + String.valueOf(rid)); result = newStore; } } else { throw new ElementKeyException("Cannot resolve a key of " + skey.toString()); } } else { throw new ElementKeyException("Cannot resolve a key of " + skey.toString()); } } else if (delegateKey instanceof NoteCoordinate) { // System.out.println("delegateKey is a NoteCoordinate"); long key = ((NoteCoordinate) delegateKey).getReplicaLong(); result = getElementStores().get(key); if (result == null) { DElementStore newStore = new org.openntf.domino.graph2.impl.DElementStore(); newStore.setStoreKey(key); newStore.setConfiguration(this.getConfiguration()); getElementStores().put(key, newStore); // System.out.println("TEMP DEBUG Added new dynamic element store " + String.valueOf(key)); result = newStore; } // System.out.println("TEMP DEBUG returning an element store for key " + NoteCoordinate.Utils.getReplidFromLong(key) // + " and isProxied is " + result.isProxied()); } else { System.err.println("delegateKey is a " + delegateKey.getClass().getName()); } if (result == null) { result = getDefaultElementStore(); // System.out.println("Returning default element store"); } return result; } @Override public DElementStore getDefaultElementStore() { return getConfiguration().getDefaultElementStore(); } public org.openntf.domino.graph2.DEdgeList getEdgesFromIds(final Vertex source, final NoteList list) { org.openntf.domino.graph2.DEdgeList result = new DFastEdgeList((DVertex) source, this, list); return result; } @Override public DEdgeList getEdgesFromIds(final Vertex source, final Set<String> set) { DEdgeList result = new DEdgeList((DVertex) source); for (String id : set) { Edge edge = getEdge(id); if (edge != null) { result.add(edge); } } return result; } @Override public DEdgeList getEdgesFromIds(final Vertex source, final Set<String> set, final String... labels) { DEdgeList result = new DEdgeList((DVertex) source); for (String id : set) { Edge edge = getEdge(id); if (edge != null) { for (String label : labels) { if (label.equals(edge.getLabel())) { result.add(edge); break; } } } } return result; } @Override public Object getStoreDelegate(final DElementStore store) { //FIXME NTF probably need to farm this out to some kind of Factory... Object result = null; Long key = store.getStoreKey(); String keyStr = NoteCoordinate.Utils.getReplidFromLong(key); // System.out.println("Attempting to find database with replica id " + keyStr); Session session = Factory.getSession(SessionType.CURRENT); // DbDirectory dir = session.getDbDirectory(""); // result = dir.openDatabaseByReplicaID(keyStr); // if (result == null) { // System.err.println("Unable to open database by replica id " + keyStr); // } result = session.getDatabase(keyStr); //TODO NTF sort out server? return result; } @Override public Object getStoreDelegate(final DElementStore store, final Object provisionalKey) { Object result = null; Session session = Factory.getSession(SessionType.CURRENT); if (provisionalKey instanceof CharSequence) { String key = provisionalKey.toString(); String server = ""; if (key.contains("!!")) { server = ""; //TODO NTF parse key string to find server name in form of 'Server!!path.nsf' //key = key; //TODO NTF parse again } DbDirectory dir = session.getDbDirectory(server); result = dir.openDatabase(key); if (result == null) { Session localSession = Factory.getSession(SessionType.NATIVE); DbDirectory localDir = localSession.getDbDirectory(server); Database newDb = localDir.createDatabase(key); newDb.setCategories("graph2"); // newDb.setFolderReferencesEnabled(false); newDb.setTitle("Auto-generated graph2 element store"); for (org.openntf.domino.View v : newDb.getViews()) { v.setName("NONE"); v.setSelectionFormula("SELECT @False"); } result = newDb; } store.setStoreKey(((Database) result).getReplicaID()); } else { //TODO NTF Unimplemented } return result; } @Override public Object getProxyStoreDelegate(final DElementStore store) { //FIXME NTF probably need to farm this out to some kind of Factory... Object result = null; Long key = store.getProxyStoreKey(); Session session = Factory.getSession(SessionType.CURRENT); String keyStr = NoteCoordinate.Utils.getReplidFromLong(key); result = session.getDatabase(keyStr); //TODO NTF sort out server? return result; } @Override public Object getProxyStoreDelegate(final DElementStore store, final Object provisionalKey) { Object result = null; Session session = Factory.getSession(SessionType.CURRENT); if (provisionalKey instanceof CharSequence) { String key = provisionalKey.toString(); String server = ""; if (key.contains("!!")) { server = ""; //TODO NTF parse key string to find server name in form of 'Server!!path.nsf' //key = key; //TODO NTF parse again } DbDirectory dir = session.getDbDirectory(server); result = dir.openDatabase(key); if (result == null) { Session localSession = Factory.getSession(SessionType.NATIVE); DbDirectory localDir = localSession.getDbDirectory(server); Database newDb = localDir.createDatabase(key); newDb.setCategories("graph2"); newDb.setFolderReferencesEnabled(false); newDb.setTitle("Auto-generated graph2 element store"); for (org.openntf.domino.View v : newDb.getViews()) { v.setName("NONE"); v.setSelectionFormula("SELECT @False"); } result = newDb; } store.setProxyStoreKey(((Database) result).getReplicaID()); } else { //TODO NTF Unimplemented } return result; } @Override public void addKeyResolver(final DKeyResolver resolver) { getConfiguration().addKeyResolver(resolver); } @Override public DKeyResolver getKeyResolver(final Class<?> type) { return getConfiguration().getKeyResolver(type); } @Override public void setExtendedGraph(final Graph graph) { extendedGraph_ = graph; } @Override public Graph getExtendedGraph() { return extendedGraph_; } @Override public void flushCache() { for (Long key : getElementStores().keySet()) { DElementStore elemStore = getElementStores().get(key); elemStore.flushCache(); } } }