All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tinkerpop.blueprints.impls.dex.DexGraph Maven / Gradle / Ivy

package com.tinkerpop.blueprints.impls.dex;

import com.sparsity.dex.gdb.AttributeKind;
import com.sparsity.dex.gdb.ObjectType;
import com.tinkerpop.blueprints.CloseableIterable;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Element;
import com.tinkerpop.blueprints.Features;
import com.tinkerpop.blueprints.KeyIndexableGraph;
import com.tinkerpop.blueprints.MetaGraph;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.blueprints.util.ExceptionFactory;
import com.tinkerpop.blueprints.util.MultiIterable;
import com.tinkerpop.blueprints.util.PropertyFilteredIterable;
import com.tinkerpop.blueprints.util.StringFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Dex is a graph database developed by Sparsity Technologies.
 * 

* Dex natively supports the property graph data model defined by Blueprints. * However, there are a few peculiarities. No user defined element identifiers: * Dex is the gatekeeper and creator of vertex and edge identifiers. Thus, when * creating a new vertex or edge instance, the provided object identifier is * ignored. *

* Vertices are labeled too: When adding vertices, the user can set * {@link DexGraph#label} to be used as the label of the vertex to be created. * Also, the label of a vertex (or even an element) can be retrieved through the * {@link StringFactory#LABEL} property. *

* DexGraph implements {@link KeyIndexableGraph} with some particularities on * the way it can be used. As both vertices and edges are labeled when working * with Dex, the use of some APIs may require previously setting the label (by * means of {@link DexGraph#label}). Those APIs are: * {@link #getVertices(String, Object)}, {@link #getEdges(String, Object)}, and * {@link #createKeyIndex(String, Class)}. *

* When working with DexGraph, all methods having as a result a collection * actually return a {@link CloseableIterable} collection. Thus users can * {@link CloseableIterable#close()} the collection to free resources. * Otherwise, all those collections will automatically be closed when the * database is stopped ( {@link #shutdown()}). * * @author Sparsity * Technologies */ public class DexGraph implements MetaGraph, KeyIndexableGraph { /** * Default Vertex label. */ public static final String DEFAULT_DEX_VERTEX_LABEL = "VERTEX_LABEL"; /** * This is a "bypass" to set the Dex vertex label (node type). *

* Dex vertices belong to a vertex/node type (thus all of them have a label). * By default, all vertices will have the {@link #DEFAULT_DEX_VERTEX_LABEL} label. * The user may set a different vertex label by setting this property when calling * {@link #addVertex(Object)}. *

* Moreover, this value will also be used for the KeyIndex-related methods. * * @see #addVertex(Object) * @see #createKeyIndex(String, Class) * @see #getVertices(String, Object) * @see #getEdges(String, Object) */ public ThreadLocal label = new ThreadLocal() { @Override protected String initialValue() { return null; } }; /** * Database persistent file. */ private File db = null; private com.sparsity.dex.gdb.Dex dex = null; private com.sparsity.dex.gdb.Database gpool = null; private com.sparsity.dex.gdb.Session session = null; private com.sparsity.dex.gdb.Graph rawGraph = null; private static final Features FEATURES = new Features(); static { FEATURES.supportsDuplicateEdges = true; FEATURES.supportsSelfLoops = true; FEATURES.isPersistent = true; FEATURES.isRDFModel = false; FEATURES.supportsVertexIteration = true; FEATURES.supportsEdgeIteration = true; FEATURES.supportsVertexIndex = false; FEATURES.supportsEdgeIndex = false; FEATURES.ignoresSuppliedIds = true; FEATURES.supportsEdgeRetrieval = true; FEATURES.supportsVertexProperties = true; FEATURES.supportsEdgeProperties = true; FEATURES.supportsTransactions = false; FEATURES.supportsIndices = false; FEATURES.supportsSerializableObjectProperty = false; FEATURES.supportsBooleanProperty = true; FEATURES.supportsDoubleProperty = true; FEATURES.supportsFloatProperty = true; FEATURES.supportsIntegerProperty = true; FEATURES.supportsPrimitiveArrayProperty = false; FEATURES.supportsUniformListProperty = false; FEATURES.supportsMixedListProperty = false; FEATURES.supportsLongProperty = false; FEATURES.supportsMapProperty = false; FEATURES.supportsStringProperty = true; FEATURES.isWrapper = false; FEATURES.supportsKeyIndices = true; FEATURES.supportsVertexKeyIndex = true; FEATURES.supportsEdgeKeyIndex = true; FEATURES.supportsThreadedTransactions = false; } /** * Gets the Dex raw graph. * * @return Dex raw graph. */ public com.sparsity.dex.gdb.Graph getRawGraph() { return rawGraph; } /** * Gets the Dex * * @return The Dex */ com.sparsity.dex.gdb.Session getRawSession() { return session; } /** * All iterables are registered here to be automatically closed when the * database is stopped (at {@link #shutdown()}). */ private List> iterables = new ArrayList>(); /** * Registers a collection. * * @param col Collection to be registered. */ protected void register(final DexIterable col) { iterables.add(col); } /** * Unregisters a collection. * * @param col Collection to be unregistered */ protected void unregister(final DexIterable col) { iterables.remove(col); } /** * Creates a new instance. * * @param fileName Database persistent file. */ public DexGraph(final String fileName) { try { final File db = new File(fileName); final File dbPath = db.getParentFile(); if (!dbPath.exists()) { if (!dbPath.mkdirs()) { throw new RuntimeException("Could not create directory"); } } final boolean create = !db.exists(); this.db = db; dex = new com.sparsity.dex.gdb.Dex(new com.sparsity.dex.gdb.DexConfig()); gpool = (create ? dex.create(db.getPath(), db.getName()) : dex.open(db.getPath(), false)); session = gpool.newSession(); rawGraph = session.getGraph(); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } } /** * Creates a new Vertex. *

* Given identifier is ignored. *

* Use {@link #label} to specify the label for the new Vertex. * If no label is given, {@value #DEFAULT_DEX_VERTEX_LABEL} will be used. * * @param id It is ignored. * @return Added Vertex. * @see com.tinkerpop.blueprints.Graph#addVertex(java.lang.Object) * @see #label */ @Override public Vertex addVertex(final Object id) { String label = this.label.get() == null ? DEFAULT_DEX_VERTEX_LABEL : this.label.get(); int type = this.getRawGraph().findType(label); if (type == com.sparsity.dex.gdb.Type.InvalidType) { // First instance of this type, let's create it type = rawGraph.newNodeType(label); } assert type != com.sparsity.dex.gdb.Type.InvalidType; // create object instance long oid = rawGraph.newNode(type); return new DexVertex(this, oid); } /* * (non-Javadoc) * * @see com.tinkerpop.blueprints.Graph#getVertex(java.lang.Object) */ @Override public Vertex getVertex(final Object id) { if (null == id) throw ExceptionFactory.vertexIdCanNotBeNull(); try { final Long longId = Double.valueOf(id.toString()).longValue(); final int type = rawGraph.getObjectType(longId); if (type != com.sparsity.dex.gdb.Type.InvalidType) return new DexVertex(this, longId); else return null; } catch (NumberFormatException e) { return null; } catch (RuntimeException re) { // dex throws a runtime exception => [DEX: 12] Invalid object identifier. return null; } } /* * (non-Javadoc) * * @see * com.tinkerpop.blueprints.Graph#removeVertex(com.tinkerpop.blueprints * .pgm.Vertex) */ @Override public void removeVertex(final Vertex vertex) { assert vertex instanceof DexVertex; rawGraph.drop((Long) vertex.getId()); } /* * (non-Javadoc) * * @see com.tinkerpop.blueprints.Graph#getVertices() */ @Override public CloseableIterable getVertices() { com.sparsity.dex.gdb.TypeList tlist = rawGraph.findNodeTypes(); List> vertices = new ArrayList>(); for (Integer type : tlist) { com.sparsity.dex.gdb.Objects objs = rawGraph.select(type); vertices.add(new DexIterable(this, objs, Vertex.class)); } tlist.delete(); tlist = null; return new MultiIterable(vertices); } /** * Returns an iterable to all the vertices in the graph that have a particular key/value property. *

* In case key is {@link StringFactory#LABEL}, it returns an iterable of all the vertices having * the given value as the label (therefore, belonging to the given type). *

* In case {@link #label} is null, it will return all vertices having a particular * key/value no matters the type. * In case {@link #label} is not null, it will return all vertices having a particular * key/value belonging to the given type. * * @see com.tinkerpop.blueprints.Graph#getVertices(String, Object) * @see #label */ @Override public CloseableIterable getVertices(final String key, final Object value) { if (key.compareTo(StringFactory.LABEL) == 0) { // label is "indexed" int type = this.getRawGraph().findType(value.toString()); if (type != com.sparsity.dex.gdb.Type.InvalidType) { com.sparsity.dex.gdb.Type tdata = this.getRawGraph().getType(type); if (tdata.getObjectType() == ObjectType.Node) { com.sparsity.dex.gdb.Objects objs = this.getRawGraph().select(type); return new DexIterable(this, objs, Vertex.class); } } return null; } String label = this.label.get(); if (label == null) { // all vertex types com.sparsity.dex.gdb.TypeList tlist = this.getRawGraph().findNodeTypes(); List> vertices = new ArrayList>(); for (Integer type : tlist) { int attr = this.getRawGraph().findAttribute(type, key); if (com.sparsity.dex.gdb.Attribute.InvalidAttribute != attr) { com.sparsity.dex.gdb.Attribute adata = this.getRawGraph().getAttribute(attr); if (adata.getKind() == AttributeKind.Basic) { // "table" scan com.sparsity.dex.gdb.Objects objs = this.getRawGraph().select(type); vertices.add(new PropertyFilteredIterable(key, value, new DexIterable(this, objs, Vertex.class))); } else { // use the index vertices.add(new DexIterable(this, this.rawGet(adata, value), Vertex.class)); } } } tlist.delete(); tlist = null; if (vertices.size() > 0) return new MultiIterable(vertices); else throw new IllegalArgumentException("The given attribute '" + key + "' does not exist"); } else { // restricted to a type int type = this.getRawGraph().findType(label); if (type == com.sparsity.dex.gdb.Type.InvalidType) { throw new IllegalArgumentException("Unnexisting vertex label: " + label); } com.sparsity.dex.gdb.Type tdata = this.getRawGraph().getType(type); if (tdata.getObjectType() != com.sparsity.dex.gdb.ObjectType.Node) { throw new IllegalArgumentException("Given label is not a vertex label: " + label); } int attr = this.getRawGraph().findAttribute(type, key); if (com.sparsity.dex.gdb.Attribute.InvalidAttribute == attr) { throw new IllegalArgumentException("The given attribute '" + key + "' does not exist for the given node label '" + label + "'"); } com.sparsity.dex.gdb.Attribute adata = this.getRawGraph().getAttribute(attr); if (adata.getKind() == AttributeKind.Basic) { // "table" scan com.sparsity.dex.gdb.Objects objs = this.getRawGraph().select(type); return new PropertyFilteredIterable(key, value, new DexIterable(this, objs, Vertex.class)); } else { // use the index return new DexIterable(this, this.rawGet(adata, value), Vertex.class); } } } /* * (non-Javadoc) * * @see com.tinkerpop.blueprints.Graph#addEdge(java.lang.Object, * com.tinkerpop.blueprints.Vertex, com.tinkerpop.blueprints.Vertex, * java.lang.String) */ @Override public Edge addEdge(final Object id, final Vertex outVertex, final Vertex inVertex, final String label) { int type = this.getRawGraph().findType(label); if (type == com.sparsity.dex.gdb.Type.InvalidType) { // First instance of this type, let's create it type = rawGraph.newEdgeType(label, true, true); } assert type != com.sparsity.dex.gdb.Type.InvalidType; // create object instance assert outVertex instanceof DexVertex && inVertex instanceof DexVertex; long oid = rawGraph.newEdge(type, (Long) outVertex.getId(), (Long) inVertex.getId()); return new DexEdge(this, oid); } /* * (non-Javadoc) * * @see com.tinkerpop.blueprints.Graph#getEdge(java.lang.Object) */ @Override public Edge getEdge(final Object id) { if (null == id) throw ExceptionFactory.edgeIdCanNotBeNull(); try { Long longId = Double.valueOf(id.toString()).longValue(); int type = rawGraph.getObjectType(longId); if (type != com.sparsity.dex.gdb.Type.InvalidType) return new DexEdge(this, longId); else return null; } catch (NumberFormatException e) { return null; } catch (RuntimeException re) { // dex throws an runtime exception => [DEX: 12] Invalid object identifier. return null; } } /* * (non-Javadoc) * * @see * com.tinkerpop.blueprints.Graph#removeEdge(com.tinkerpop.blueprints * .pgm.Edge) */ @Override public void removeEdge(final Edge edge) { assert edge instanceof DexEdge; rawGraph.drop((Long) edge.getId()); } /* * (non-Javadoc) * * @see com.tinkerpop.blueprints.Graph#getEdges() */ @Override public CloseableIterable getEdges() { com.sparsity.dex.gdb.TypeList tlist = rawGraph.findEdgeTypes(); List> edges = new ArrayList>(); for (Integer type : tlist) { com.sparsity.dex.gdb.Objects objs = rawGraph.select(type); edges.add(new DexIterable(this, objs, Edge.class)); } tlist.delete(); tlist = null; return new MultiIterable(edges); } /** * Returns an iterable to all the edges in the graph that have a particular key/value property. *

* In case key is {@link StringFactory#LABEL}, it returns an iterable of all the edges having * the given value as the label (therefore, belonging to the given type). *

* In case {@link #label} is null, it will return all edges having a particular * key/value no matters the type. * In case {@link #label} is not null, it will return all edges having a particular * key/value belonging to the given type. * * @see com.tinkerpop.blueprints.Graph#getEdges(String, Object) * @see #label */ @Override public CloseableIterable getEdges(final String key, final Object value) { if (key.compareTo(StringFactory.LABEL) == 0) { // label is "indexed" int type = this.getRawGraph().findType(value.toString()); if (type != com.sparsity.dex.gdb.Type.InvalidType) { com.sparsity.dex.gdb.Type tdata = this.getRawGraph().getType(type); if (tdata.getObjectType() == ObjectType.Edge) { com.sparsity.dex.gdb.Objects objs = this.getRawGraph().select(type); return new DexIterable(this, objs, Edge.class); } } return null; } String label = this.label.get(); if (label == null) { // all vertex types com.sparsity.dex.gdb.TypeList tlist = this.getRawGraph().findEdgeTypes(); List> edges = new ArrayList>(); for (Integer type : tlist) { int attr = this.getRawGraph().findAttribute(type, key); if (com.sparsity.dex.gdb.Attribute.InvalidAttribute != attr) { com.sparsity.dex.gdb.Attribute adata = this.getRawGraph().getAttribute(attr); if (adata.getKind() == AttributeKind.Basic) { // "table" scan com.sparsity.dex.gdb.Objects objs = this.getRawGraph().select(type); edges.add(new PropertyFilteredIterable(key, value, new DexIterable(this, objs, Edge.class))); } else { // use the index edges.add(new DexIterable(this, this.rawGet(adata, value), Edge.class)); } } } tlist.delete(); tlist = null; if (edges.size() > 0) return new MultiIterable(edges); else throw new IllegalArgumentException("The given attribute '" + key + "' does not exist"); } else { // restricted to a type int type = this.getRawGraph().findType(label); if (type == com.sparsity.dex.gdb.Type.InvalidType) { throw new IllegalArgumentException("Unnexisting edge label: " + label); } com.sparsity.dex.gdb.Type tdata = this.getRawGraph().getType(type); if (tdata.getObjectType() != com.sparsity.dex.gdb.ObjectType.Edge) { throw new IllegalArgumentException("Given label is not a edge label: " + label); } int attr = this.getRawGraph().findAttribute(type, key); if (com.sparsity.dex.gdb.Attribute.InvalidAttribute == attr) { throw new IllegalArgumentException("The given attribute '" + key + "' does not exist for the given edge label '" + label + "'"); } com.sparsity.dex.gdb.Attribute adata = this.getRawGraph().getAttribute(attr); if (adata.getKind() == AttributeKind.Basic) { // "table" scan com.sparsity.dex.gdb.Objects objs = this.getRawGraph().select(type); return new PropertyFilteredIterable(key, value, new DexIterable(this, objs, Edge.class)); } else { // use the index return new DexIterable(this, this.rawGet(adata, value), Edge.class); } } } /** * Closes all non-closed iterables. */ protected void closeAllCollections() { while (!iterables.isEmpty()) { iterables.remove(iterables.size() - 1).close(); } } /* * (non-Javadoc) * * @see com.tinkerpop.blueprints.Graph#shutdown() */ @Override public void shutdown() { closeAllCollections(); rawGraph = null; session.close(); gpool.close(); dex.close(); } @Override public String toString() { return StringFactory.graphString(this, db.getPath()); } public Features getFeatures() { return FEATURES; } private com.sparsity.dex.gdb.Objects rawGet(final com.sparsity.dex.gdb.Attribute adata, final Object value) { com.sparsity.dex.gdb.Value v = new com.sparsity.dex.gdb.Value(); switch (adata.getDataType()) { case Boolean: v.setBooleanVoid((Boolean) value); break; case Integer: v.setIntegerVoid((Integer) value); break; case Long: v.setLongVoid((Long) value); break; case String: v.setStringVoid((String) value); break; case Double: if (value instanceof Double) { v.setDoubleVoid((Double) value); } else if (value instanceof Float) { v.setDoubleVoid(((Float) value).doubleValue()); } break; default: throw new UnsupportedOperationException(); } return this.getRawGraph().select(adata.getId(), com.sparsity.dex.gdb.Condition.Equal, v); } @Override public void dropKeyIndex(String key, Class elementClass) { throw new UnsupportedOperationException(); } /** * Create an automatic indexing structure for indexing provided key for element class. *

* Dex attributes are restricted to an specific vertex/edge type. The property * {@link #label} must be used to specify the vertex/edge label. *

* The index could be created even before the vertex/edge label * had been created (that is, there are no instances for the given vertex/edge label). * If so, this will create the vertex/edge type automatically. * The same way, if necessary the attribute will be created automatically. *

* FIXME: In case the attribute is created, this always creates an String * attribute, could this be set somehow? * * @see com.tinkerpop.blueprints.KeyIndexableGraph#createKeyIndex(String, Class) * @see #label */ @Override public void createKeyIndex(String key, Class elementClass) { String label = this.label.get(); if (label == null) { throw new IllegalArgumentException("Label must be given"); } int type = this.getRawGraph().findType(label); if (type == com.sparsity.dex.gdb.Type.InvalidType) { // create the node/edge type if (Vertex.class.isAssignableFrom(elementClass)) { type = this.getRawGraph().newNodeType(label); } else if (Edge.class.isAssignableFrom(elementClass)) { type = this.getRawGraph().newEdgeType(label, true, true); } else { throw ExceptionFactory.classIsNotIndexable(elementClass); } } else { // validate the node/edge type com.sparsity.dex.gdb.Type tdata = this.getRawGraph().getType(type); if (tdata.getObjectType() == ObjectType.Node) { if (!Vertex.class.isAssignableFrom(elementClass)) { throw new IllegalArgumentException("Given element class '" + elementClass.getName() + "' is not valid for the given node type '" + label + "'"); } } else if (tdata.getObjectType() == ObjectType.Edge) { if (!Edge.class.isAssignableFrom(elementClass)) { throw new IllegalArgumentException("Given element class '" + elementClass.getName() + "' is not valid for the given edge type '" + label + "'"); } } } int attr = this.getRawGraph().findAttribute(type, key); if (com.sparsity.dex.gdb.Attribute.InvalidAttribute == attr) { // create the attribute (indexed) attr = this.getRawGraph().newAttribute(type, key, com.sparsity.dex.gdb.DataType.String, com.sparsity.dex.gdb.AttributeKind.Indexed); } else { // it already exists, let's indexe it if necessary com.sparsity.dex.gdb.Attribute adata = this.getRawGraph().getAttribute(attr); if (adata.getKind() == AttributeKind.Indexed || adata.getKind() == AttributeKind.Unique) { throw ExceptionFactory.indexAlreadyExists(label + " " + key); } this.getRawGraph().indexAttribute(attr, com.sparsity.dex.gdb.AttributeKind.Indexed); } } @Override public Set getIndexedKeys(Class elementClass) { com.sparsity.dex.gdb.TypeList tlist = null; if (Vertex.class.isAssignableFrom(elementClass)) { tlist = this.getRawGraph().findNodeTypes(); } else if (Edge.class.isAssignableFrom(elementClass)) { tlist = this.getRawGraph().findEdgeTypes(); } else { throw ExceptionFactory.classIsNotIndexable(elementClass); } boolean found = false; Set ret = new HashSet(); for (Integer type : tlist) { com.sparsity.dex.gdb.AttributeList alist = this.getRawGraph().findAttributes(type); for (Integer attr : alist) { com.sparsity.dex.gdb.Attribute adata = this.getRawGraph().getAttribute(attr); if (adata.getKind() == AttributeKind.Indexed || adata.getKind() == AttributeKind.Unique) { ret.add(adata.getName()); } } alist.delete(); alist = null; } tlist.delete(); tlist = null; return ret; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy