Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Generalized IdGraph to selectively enable custom vertex or edge IDs, …

…accommodating base graphs which do not support either edge or vertex indexing
  • Loading branch information...
commit ca64cf8c68286e15f3c389a4c08485e5dccb35e6 1 parent 0c3a854
@joshsh joshsh authored
View
1  CHANGELOG.textile
@@ -15,6 +15,7 @@ h3. Version 2.3.0 (NOT OFFICIALLY RELEASED YET)
</dependency>
```
+* Generalized @IdGraph@ to selectively enable custom vertex or edge IDs
* Stricter testing of property keys/value to ensure legal Blueprints values (no id, label, empty string, null)
* @Element.getProperty()@ API signature changed to support automatic typing to declared variable type
* Moved @PropertyGraphSail@, which provides a dynamic RDF view of any Blueprints graph, from Tinkubator into @blueprints-graph-sail@
View
2  blueprints-core/src/main/java/com/tinkerpop/blueprints/util/wrappers/id/IdEdge.java
@@ -11,7 +11,7 @@
public class IdEdge extends IdElement implements Edge {
protected IdEdge(final Edge base, final IdGraph idGraph) {
- super(base, idGraph);
+ super(base, idGraph, idGraph.getSupportEdgeIds());
}
public Edge getBaseEdge() {
View
39 blueprints-core/src/main/java/com/tinkerpop/blueprints/util/wrappers/id/IdElement.java
@@ -16,13 +16,18 @@
protected final IdGraph idGraph;
- protected IdElement(final Element baseElement, final IdGraph idGraph) {
+ protected final boolean propertyBased;
+
+ protected IdElement(final Element baseElement,
+ final IdGraph idGraph,
+ final boolean propertyBased) {
this.baseElement = baseElement;
this.idGraph = idGraph;
+ this.propertyBased = propertyBased;
}
public <T> T getProperty(final String key) {
- if (key.equals(IdGraph.ID)) {
+ if (propertyBased && key.equals(IdGraph.ID)) {
return null;
}
@@ -30,31 +35,41 @@ protected IdElement(final Element baseElement, final IdGraph idGraph) {
}
public Set<String> getPropertyKeys() {
- final Set<String> keys = baseElement.getPropertyKeys();
- final Set<String> s = new HashSet<String>();
- s.addAll(keys);
- s.remove(IdGraph.ID);
- return s;
+ if (propertyBased) {
+ final Set<String> keys = baseElement.getPropertyKeys();
+ final Set<String> s = new HashSet<String>();
+ s.addAll(keys);
+ s.remove(IdGraph.ID);
+ return s;
+ } else {
+ return baseElement.getPropertyKeys();
+ }
}
public void setProperty(final String key, final Object value) {
- if (key.equals(IdGraph.ID)) {
- throw new IllegalArgumentException("Unable to set value for reserved property " + IdGraph.ID);
+ if (propertyBased) {
+ if (key.equals(IdGraph.ID)) {
+ throw new IllegalArgumentException("Unable to set value for reserved property " + IdGraph.ID);
+ }
}
baseElement.setProperty(key, value);
}
public <T> T removeProperty(final String key) {
- if (key.equals(IdGraph.ID)) {
- throw new IllegalArgumentException("Unable to remove value for reserved property " + IdGraph.ID);
+ if (propertyBased) {
+ if (key.equals(IdGraph.ID)) {
+ throw new IllegalArgumentException("Unable to remove value for reserved property " + IdGraph.ID);
+ }
}
return baseElement.removeProperty(key);
}
public Object getId() {
- return baseElement.getProperty(IdGraph.ID);
+ return propertyBased
+ ? baseElement.getProperty(IdGraph.ID)
+ : baseElement.getId();
}
public int hashCode() {
View
217 blueprints-core/src/main/java/com/tinkerpop/blueprints/util/wrappers/id/IdGraph.java
@@ -25,6 +25,8 @@
* <p/>
* The base Graph must be an instance of KeyIndexableGraph.
* It *may* be an instance of IndexableGraph, in which case its indices will be wrapped appropriately.
+ * For those graphs which support vertex indices but not edge indices (or vice versa),
+ * you may configure IdGraph to use custom IDs only for vertices or only for edges.
*
* @author Joshua Shinavier (http://fortytwo.net)
*/
@@ -35,70 +37,85 @@
private final T baseGraph;
- private final IdFactory vertexIdFactory;
- private final IdFactory edgeIdFactory;
+ private IdFactory vertexIdFactory;
+ private IdFactory edgeIdFactory;
private final Features features;
+ private final boolean supportVertexIds, supportEdgeIds;
+
private boolean uniqueIds = true;
/**
- * Adds custom ID functionality to the given graph.
- *
- * @param baseGraph the base graph which does not permit custom element IDs
+ * Adds custom ID functionality to the given graph,
+ * supporting both custom vertex IDs and custom edge IDs.
*/
public IdGraph(final T baseGraph) {
- this(baseGraph, null);
- }
-
- /**
- * Adds custom ID functionality to the given graph, also specifying a factory for new element IDs.
- *
- * @param baseGraph the base graph which may or may not permit custom element IDs
- * @param idFactory a factory for new vertex and edge IDs.
- * When vertices or edges are created using null IDs, the actual IDs are chosen based on this factory.
- */
- public IdGraph(final T baseGraph, final IdFactory idFactory) {
- this(baseGraph, idFactory, idFactory);
+ this(baseGraph, true, true);
}
/**
- * Adds custom ID functionality to the given graph, also specifying (separate) factories for new vertex and edge IDs.
- *
- * @param baseGraph the base graph which may or may not permit custom element IDs
- * @param vertexIdFactory a factory for new vertex IDs.
- * When vertices are created using null IDs, the actual IDs are chosen based on this factory.
- * @param edgeIdFactory a factory for new edge IDs.
- * When edges are created using null IDs, the actual IDs are chosen based on this factory.
+ * Adds custom ID functionality to the given graph.
*/
public IdGraph(final T baseGraph,
- final IdFactory vertexIdFactory,
- final IdFactory edgeIdFactory) {
+ final boolean supportVertexIds,
+ final boolean supportEdgeIds) {
this.baseGraph = baseGraph;
this.features = this.baseGraph.getFeatures().copyFeatures();
features.isWrapper = true;
features.ignoresSuppliedIds = false;
- this.vertexIdFactory = null == vertexIdFactory ? new DefaultIdFactory() : vertexIdFactory;
- this.edgeIdFactory = null == edgeIdFactory ? new DefaultIdFactory() : edgeIdFactory;
+ this.supportVertexIds = supportVertexIds;
+ this.supportEdgeIds = supportEdgeIds;
+
+ if (!supportVertexIds && !supportEdgeIds) {
+ throw new IllegalArgumentException("if neither custom vertex IDs nor custom edge IDs are supported, IdGraph can't help you!");
+ }
createIndices();
+
+ vertexIdFactory = new DefaultIdFactory();
+ edgeIdFactory = new DefaultIdFactory();
}
+ /**
+ * @param idFactory a factory for new vertex IDs.
+ * When vertices are created using null IDs, the actual IDs are chosen based on this factory.
+ */
+ public void setVertexIdFactory(final IdFactory idFactory) {
+ vertexIdFactory = idFactory;
+ }
+
+ /**
+ * @param idFactory a factory for new edge IDs.
+ * When edges are created using null IDs, the actual IDs are chosen based on this factory.
+ */
+ public void setEdgeIdFactory(final IdFactory idFactory) {
+ edgeIdFactory = idFactory;
+ }
+
+ /**
+ * @return the factory for new vertex IDs.
+ * When vertices are created using null IDs, the actual IDs are chosen based on this factory.
+ */
public IdFactory getVertexIdFactory() {
return vertexIdFactory;
}
+ /**
+ * return the factory for new edge IDs.
+ * When edges are created using null IDs, the actual IDs are chosen based on this factory.
+ */
public IdFactory getEdgeIdFactory() {
return edgeIdFactory;
}
private void createIndices() {
- if (!baseGraph.getIndexedKeys(Vertex.class).contains(ID)) {
+ if (supportVertexIds && !baseGraph.getIndexedKeys(Vertex.class).contains(ID)) {
baseGraph.createKeyIndex(ID, Vertex.class);
}
- if (!baseGraph.getIndexedKeys(Edge.class).contains(ID)) {
+ if (supportEdgeIds && !baseGraph.getIndexedKeys(Edge.class).contains(ID)) {
baseGraph.createKeyIndex(ID, Edge.class);
}
}
@@ -109,17 +126,17 @@ public Features getFeatures() {
public Vertex addVertex(final Object id) {
if (uniqueIds && null != id && null != getVertex(id)) {
- throw new IllegalArgumentException("Vertex with given id already exists: '" + id + "'");
+ throw new IllegalArgumentException("vertex with given id already exists: '" + id + "'");
}
final Vertex base = baseGraph.addVertex(null);
- Object v = null == id ? vertexIdFactory.createId() : id;
+ if (supportVertexIds) {
+ Object v = null == id ? vertexIdFactory.createId() : id;
- if (null == v) {
- base.removeProperty(ID);
- } else {
- base.setProperty(ID, v);
+ if (null != v) {
+ base.setProperty(ID, v);
+ }
}
return new IdVertex(base, this);
@@ -127,21 +144,26 @@ public Vertex addVertex(final Object id) {
public Vertex getVertex(final Object id) {
if (null == id) {
- throw new IllegalArgumentException("Element identifier cannot be null");
+ throw new IllegalArgumentException("vertex identifier cannot be null");
}
- final Iterable<Vertex> i = baseGraph.getVertices(ID, id);
- final Iterator<Vertex> iter = i.iterator();
- if (!iter.hasNext()) {
- return null;
- } else {
- Vertex e = iter.next();
+ if (supportVertexIds) {
+ final Iterable<Vertex> i = baseGraph.getVertices(ID, id);
+ final Iterator<Vertex> iter = i.iterator();
+ if (!iter.hasNext()) {
+ return null;
+ } else {
+ Vertex e = iter.next();
- if (iter.hasNext()) {
- throw new IllegalStateException("multiple vertices exist with id '" + id + "'");
- }
+ if (iter.hasNext()) {
+ throw new IllegalStateException("multiple vertices exist with id '" + id + "'");
+ }
- return new IdVertex(e, this);
+ return new IdVertex(e, this);
+ }
+ } else {
+ Vertex base = baseGraph.getVertex(id);
+ return null == base ? null : new IdVertex(base, this);
}
}
@@ -154,17 +176,21 @@ public void removeVertex(final Vertex vertex) {
return new IdVertexIterable(baseGraph.getVertices(), this);
}
- public Iterable<Vertex> getVertices(final String key, final Object value) {
- if (key.equals(ID)) {
- throw new IllegalArgumentException("Index key " + ID + " is reserved by IdGraph");
+ public Iterable<Vertex> getVertices(final String key,
+ final Object value) {
+ if (supportVertexIds && key.equals(ID)) {
+ throw new IllegalArgumentException("index key " + ID + " is reserved by IdGraph");
} else {
return new IdVertexIterable(baseGraph.getVertices(key, value), this);
}
}
- public Edge addEdge(final Object id, final Vertex outVertex, final Vertex inVertex, final String label) {
+ public Edge addEdge(final Object id,
+ final Vertex outVertex,
+ final Vertex inVertex,
+ final String label) {
if (uniqueIds && null != id && null != getEdge(id)) {
- throw new IllegalArgumentException("Edge with given id already exists: " + id);
+ throw new IllegalArgumentException("edge with given id already exists: " + id);
}
verifyNativeElement(outVertex);
@@ -172,12 +198,12 @@ public Edge addEdge(final Object id, final Vertex outVertex, final Vertex inVert
Edge base = baseGraph.addEdge(null, ((IdVertex) outVertex).getBaseVertex(), ((IdVertex) inVertex).getBaseVertex(), label);
- Object v = null == id ? edgeIdFactory.createId() : id;
+ if (supportEdgeIds) {
+ Object v = null == id ? edgeIdFactory.createId() : id;
- if (null == v) {
- base.removeProperty(ID);
- } else {
- base.setProperty(ID, v);
+ if (null != v) {
+ base.setProperty(ID, v);
+ }
}
return new IdEdge(base, this);
@@ -185,21 +211,26 @@ public Edge addEdge(final Object id, final Vertex outVertex, final Vertex inVert
public Edge getEdge(final Object id) {
if (null == id) {
- throw new IllegalArgumentException("Element identifier cannot be null");
+ throw new IllegalArgumentException("edge identifier cannot be null");
}
- Iterable<Edge> i = baseGraph.getEdges(ID, id);
- Iterator<Edge> iter = i.iterator();
- if (!iter.hasNext()) {
- return null;
- } else {
- Edge e = iter.next();
+ if (supportEdgeIds) {
+ Iterable<Edge> i = baseGraph.getEdges(ID, id);
+ Iterator<Edge> iter = i.iterator();
+ if (!iter.hasNext()) {
+ return null;
+ } else {
+ Edge e = iter.next();
- if (iter.hasNext()) {
- throw new IllegalStateException("Multiple edges exist with id " + id);
- }
+ if (iter.hasNext()) {
+ throw new IllegalStateException("multiple edges exist with id " + id);
+ }
- return new IdEdge(e, this);
+ return new IdEdge(e, this);
+ }
+ } else {
+ Edge base = baseGraph.getEdge(id);
+ return null == base ? null : new IdEdge(base, this);
}
}
@@ -213,9 +244,10 @@ public void removeEdge(final Edge edge) {
return new IdEdgeIterable(baseGraph.getEdges(), this);
}
- public Iterable<Edge> getEdges(final String key, final Object value) {
- if (key.equals(ID)) {
- throw new IllegalArgumentException("Index key " + ID + " is reserved by IdGraph");
+ public Iterable<Edge> getEdges(final String key,
+ final Object value) {
+ if (supportEdgeIds && key.equals(ID)) {
+ throw new IllegalArgumentException("index key " + ID + " is reserved by IdGraph");
} else {
return new IdEdgeIterable(baseGraph.getEdges(key, value), this);
}
@@ -247,7 +279,7 @@ public void shutdown() {
private static void verifyNativeElement(final Element e) {
if (!(e instanceof IdElement)) {
- throw new IllegalArgumentException("Given element was not created in this graph");
+ throw new IllegalArgumentException("given element was not created in this graph");
}
}
@@ -257,26 +289,41 @@ public String toString() {
}
public <T extends Element> void dropKeyIndex(final String key, final Class<T> elementClass) {
- if (key.equals(ID)) {
- throw new IllegalArgumentException("Index key " + ID + " is reserved by IdGraph");
+ boolean v = isVertexClass(elementClass);
+ boolean supported = ((v && supportVertexIds) || (!v && supportEdgeIds));
+
+ if (supported && key.equals(ID)) {
+ throw new IllegalArgumentException("index key " + ID + " is reserved by IdGraph");
} else {
baseGraph.dropKeyIndex(key, elementClass);
}
}
- public <T extends Element> void createKeyIndex(final String key, final Class<T> elementClass, final Parameter... indexParameters) {
- if (key.equals(ID)) {
- throw new IllegalArgumentException("Index key " + ID + " is reserved by IdGraph");
+ public <T extends Element> void createKeyIndex(final String key,
+ final Class<T> elementClass,
+ final Parameter... indexParameters) {
+ boolean v = isVertexClass(elementClass);
+ boolean supported = ((v && supportVertexIds) || (!v && supportEdgeIds));
+
+ if (supported && key.equals(ID)) {
+ throw new IllegalArgumentException("index key " + ID + " is reserved by IdGraph");
} else {
baseGraph.createKeyIndex(key, elementClass, indexParameters);
}
}
public <T extends Element> Set<String> getIndexedKeys(final Class<T> elementClass) {
- final Set<String> keys = new HashSet<String>();
- keys.addAll(baseGraph.getIndexedKeys(elementClass));
- keys.remove(ID);
- return keys;
+ boolean v = isVertexClass(elementClass);
+ boolean supported = ((v && supportVertexIds) || (!v && supportEdgeIds));
+
+ if (supported) {
+ Set<String> keys = new HashSet<String>();
+ keys.addAll(baseGraph.getIndexedKeys(elementClass));
+ keys.remove(ID);
+ return keys;
+ } else {
+ return baseGraph.getIndexedKeys(elementClass);
+ }
}
public T getBaseGraph() {
@@ -345,6 +392,14 @@ public GraphQuery query() {
};
}
+ public boolean getSupportVertexIds() {
+ return supportVertexIds;
+ }
+
+ public boolean getSupportEdgeIds() {
+ return supportEdgeIds;
+ }
+
/**
* A factory for IDs of newly-created vertices and edges (where an ID is not otherwise specified).
*/
View
5 blueprints-core/src/main/java/com/tinkerpop/blueprints/util/wrappers/id/IdVertex.java
@@ -12,8 +12,9 @@
*/
public class IdVertex extends IdElement implements Vertex {
- protected IdVertex(final Vertex baseVertex, final IdGraph idGraph) {
- super(baseVertex, idGraph);
+ protected IdVertex(final Vertex baseVertex,
+ final IdGraph idGraph) {
+ super(baseVertex, idGraph, idGraph.getSupportVertexIds());
}
public Vertex getBaseVertex() {
View
46 blueprints-test/src/test/java/com/tinkerpop/blueprints/util/wrappers/id/IdGraphTest.java
@@ -126,6 +126,52 @@ public void testUnenforcedUniqueIds() throws Exception {
graph.addVertex("whop");
}
+ public void testCustomIdFactory() throws Exception {
+ IdGraph.IdFactory f = new IdGraph.IdFactory() {
+ private int count = 0;
+ public Object createId() {
+ return "vertex" + ++count;
+ }
+ };
+
+ IdGraph graph = (IdGraph) this.generateGraph();
+ graph.setVertexIdFactory(f);
+
+ Vertex v = graph.addVertex(null);
+ assertEquals("vertex1", v.getId());
+ }
+
+ public void testUnsupportCustomVertexOrEdgeIds() throws Exception {
+ TinkerGraph baseGraph = new TinkerGraph();
+ IdGraph<TinkerGraph> graph = new IdGraph<TinkerGraph>(baseGraph, true, false);
+
+ IdGraph.IdFactory vFactory = new IdGraph.IdFactory() {
+ private int count = 0;
+ public Object createId() {
+ return "vertex" + ++count;
+ }
+ };
+
+ IdGraph.IdFactory eFactory = new IdGraph.IdFactory() {
+ private int count = 0;
+ public Object createId() {
+ return "vertex" + ++count;
+ }
+ };
+
+ graph.setVertexIdFactory(vFactory);
+ graph.setEdgeIdFactory(eFactory);
+
+ Vertex v1 = graph.addVertex(null);
+ assertEquals("vertex1", v1.getId());
+ Vertex v2 = graph.addVertex(null);
+ assertEquals("vertex2", v2.getId());
+
+ Edge e1 = graph.addEdge(null, v1, v2, "connected-to");
+ // the custom id factory for edges is not used, because the base graph's ids are used instead
+ assertFalse(e1.getId().equals("edge1"));
+ }
+
public void testVertexTestSuite() throws Exception {
this.stopWatch();
doTestSuite(new VertexTestSuite(this));

0 comments on commit ca64cf8

Please sign in to comment.
Something went wrong with that request. Please try again.