You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2015/05/28 21:43:32 UTC

incubator-tinkerpop git commit: Added willAllowId() for features related to vertex, vertexproperty and edge TINKERPOP3-695

Repository: incubator-tinkerpop
Updated Branches:
  refs/heads/master 852627770 -> c1006eeaf


Added willAllowId() for features related to vertex, vertexproperty and edge TINKERPOP3-695

Needed a way to separate what a graph internalizes an id as and what a graph will accept as an id value.


Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/c1006eea
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/c1006eea
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/c1006eea

Branch: refs/heads/master
Commit: c1006eeaf0a329a4a0b0d3cd6886fac0c2fac7a5
Parents: 8526277
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu May 28 15:41:27 2015 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu May 28 15:43:24 2015 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |   1 +
 .../tinkerpop/gremlin/structure/Graph.java      |  53 +++++++++
 .../structure/io/graphml/GraphMLReader.java     |  18 +--
 .../structure/io/graphson/GraphSONReader.java   |   4 +-
 .../io/graphson/LegacyGraphSONReader.java       |  21 ++--
 .../gremlin/structure/io/gryo/GryoReader.java   |   4 +-
 .../gremlin/structure/util/Attachable.java      |  31 ++++--
 .../gremlin/structure/util/star/StarGraph.java  | 111 +++++++++++++++++++
 .../gremlin/structure/FeatureSupportTest.java   |  27 ++++-
 .../gremlin/hadoop/structure/HadoopGraph.java   |   5 +
 .../tinkergraph/structure/TinkerGraph.java      |  84 +++++++++++---
 11 files changed, 307 insertions(+), 52 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/c1006eea/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 62e22d5..09760b3 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -25,6 +25,7 @@ image::http://www.tinkerpop.com/docs/current/images/gremlin-hindu.png[width=225]
 TinkerPop 3.0.0.GA (NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* Added `willAllowId` method to features related to vertices, edges and vertex properties to test if an identifier can be use when `supportsUserSuppliedIds` is `true`.
 * Fixed a bug in `GraphTraversal.choose(predicate,trueTraversal,falseTraversal)`.
 * Removed `MapTraversal`, `MapTraverserTraversal`, `FilterTraversal`, and `FilterTraverserTraversal` as these are simply `__.map(function)` and `__.filter(predicate)`.
 * Include `hadoop-gremlin` Hadoop configuration sample files in Gremlin Console distribution.

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/c1006eea/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
index 10ca2a6..7ef6d1b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
@@ -44,6 +44,7 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Optional;
 import java.util.Set;
+import java.util.UUID;
 import java.util.stream.Collectors;
 
 /**
@@ -602,6 +603,32 @@ public interface Graph extends AutoCloseable, Host {
             public default boolean supportsAnyIds() {
                 return true;
             }
+
+            /**
+             * Determines if an identifier will be accepted by the {@link Graph}.  This check is different than
+             * what identifier internally supports as defined in methods like {@link #supportsNumericIds()}.  Those
+             * refer to internal representation of the identifier.  A {@link Graph} may accept an identifier that
+             * is not of those types and internally transform it to a native representation.
+             * <p/>
+             * Note that this method only applies if {@link #supportsUserSuppliedIds()} is {@code true}. Those that
+             * return {@code false} for that method can immediately return false for this one as it allows no ids
+             * of any type (it generates them all).
+             * <p/>
+             * The default implementation will immediately return {@code false} if {@link #supportsUserSuppliedIds()}
+             * is {@code false}.  If custom identifiers are supported then it will throw an exception.  Those that
+             * return {@code true} for {@link #supportsCustomIds()} should override this method. If
+             * {@link #supportsAnyIds()} is {@code true} then the identifier will immediately be allowed.  Finally,
+             * if any of the other types are supported, they will be typed checked against the class of the supplied
+             * identifier.
+             */
+            public default boolean willAllowId(final Object id) {
+                if (!supportsUserSuppliedIds()) return false;
+                if (supportsCustomIds())
+                    throw new UnsupportedOperationException("The default implementation is not capable of validating custom ids - please override");
+
+                return supportsAnyIds() || (supportsStringIds() && id instanceof String)
+                        || (supportsNumericIds() && id instanceof Number) || (supportsUuidIds() && id instanceof UUID);
+            }
         }
 
         /**
@@ -681,6 +708,32 @@ public interface Graph extends AutoCloseable, Host {
             public default boolean supportsAnyIds() {
                 return true;
             }
+
+            /**
+             * Determines if an identifier will be accepted by the {@link Graph}.  This check is different than
+             * what identifier internally supports as defined in methods like {@link #supportsNumericIds()}.  Those
+             * refer to internal representation of the identifier.  A {@link Graph} may accept an identifier that
+             * is not of those types and internally transform it to a native representation.
+             * <p/>
+             * Note that this method only applies if {@link #supportsUserSuppliedIds()} is {@code true}. Those that
+             * return {@code false} for that method can immediately return false for this one as it allows no ids
+             * of any type (it generates them all).
+             * <p/>
+             * The default implementation will immediately return {@code false} if {@link #supportsUserSuppliedIds()}
+             * is {@code false}.  If custom identifiers are supported then it will throw an exception.  Those that
+             * return {@code true} for {@link #supportsCustomIds()} should override this method. If
+             * {@link #supportsAnyIds()} is {@code true} then the identifier will immediately be allowed.  Finally,
+             * if any of the other types are supported, they will be typed checked against the class of the supplied
+             * identifier.
+             */
+            public default boolean willAllowId(final Object id) {
+                if (!supportsUserSuppliedIds()) return false;
+                if (supportsCustomIds())
+                    throw new UnsupportedOperationException("The default implementation is not capable of validating custom ids - please override");
+
+                return supportsAnyIds() || (supportsStringIds() && id instanceof String)
+                        || (supportsNumericIds() && id instanceof Number) || (supportsUuidIds() && id instanceof UUID);
+            }
         }
 
         /**

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/c1006eea/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLReader.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLReader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLReader.java
index f8d3aee..ca6f76d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLReader.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLReader.java
@@ -74,8 +74,8 @@ public class GraphMLReader implements GraphReader {
         final Map<Object,Vertex> cache = new HashMap<>();
         final AtomicLong counter = new AtomicLong(0);
         final boolean supportsTx = graphToWriteTo.features().graph().supportsTransactions();
-        final boolean supportsEdgeIds = graphToWriteTo.features().edge().supportsUserSuppliedIds();
-        final boolean supportsVertexIds = graphToWriteTo.features().vertex().supportsUserSuppliedIds();
+        final Graph.Features.EdgeFeatures edgeFeatures = graphToWriteTo.features().edge();
+        final Graph.Features.VertexFeatures vertexFeatures = graphToWriteTo.features().vertex();
 
         try {
             final XMLStreamReader reader = inputFactory.createXMLStreamReader(graphInputStream);
@@ -123,8 +123,8 @@ public class GraphMLReader implements GraphReader {
                             // graphml allows edges and vertices to be mixed in terms of how they are positioned
                             // in the xml therefore it is possible that an edge is created prior to its definition
                             // as a vertex.
-                            edgeOutVertex = findOrCreate(vertexIdOut, graphToWriteTo, supportsVertexIds, cache, false);
-                            edgeInVertex = findOrCreate(vertexIdIn, graphToWriteTo, supportsVertexIds, cache, false);
+                            edgeOutVertex = findOrCreate(vertexIdOut, graphToWriteTo, vertexFeatures, cache, false);
+                            edgeInVertex = findOrCreate(vertexIdIn, graphToWriteTo, vertexFeatures, cache, false);
 
                             if (supportsTx && counter.incrementAndGet() % batchSize == 0)
                                 graphToWriteTo.tx().commit();
@@ -163,7 +163,8 @@ public class GraphMLReader implements GraphReader {
                         final String currentVertexLabel = Optional.ofNullable(vertexLabel).orElse(Vertex.DEFAULT_LABEL);
                         final Object[] propsAsArray = vertexProps.entrySet().stream().flatMap(e -> Stream.of(e.getKey(), e.getValue())).toArray();
 
-                        findOrCreate(currentVertexId, graphToWriteTo, supportsVertexIds, cache, true, ElementHelper.upsert(propsAsArray, T.label, currentVertexLabel));
+                        findOrCreate(currentVertexId, graphToWriteTo, vertexFeatures, cache,
+                                true, ElementHelper.upsert(propsAsArray, T.label, currentVertexLabel));
 
                         if (supportsTx && counter.incrementAndGet() % batchSize == 0)
                             graphToWriteTo.tx().commit();
@@ -174,7 +175,7 @@ public class GraphMLReader implements GraphReader {
                         isInVertex = false;
                     } else if (elementName.equals(GraphMLTokens.EDGE)) {
                         final Object[] propsAsArray = edgeProps.entrySet().stream().flatMap(e -> Stream.of(e.getKey(), e.getValue())).toArray();
-                        final Object[] propsReady = supportsEdgeIds ? ElementHelper.upsert(propsAsArray, T.id, edgeId) : propsAsArray;
+                        final Object[] propsReady = edgeFeatures.willAllowId(edgeId) ? ElementHelper.upsert(propsAsArray, T.id, edgeId) : propsAsArray;
                         edgeOutVertex.addEdge(edgeLabel, edgeInVertex, propsReady);
 
                         if (supportsTx && counter.incrementAndGet() % batchSize == 0)
@@ -277,7 +278,8 @@ public class GraphMLReader implements GraphReader {
         throw Io.Exceptions.readerFormatIsForFullGraphSerializationOnly(this.getClass());
     }
 
-    private static Vertex findOrCreate(final Object id, final Graph graphToWriteTo, final boolean supportsIds,
+    private static Vertex findOrCreate(final Object id, final Graph graphToWriteTo,
+                                       final Graph.Features.VertexFeatures features,
                                        final Map<Object,Vertex> cache, final boolean asVertex, final Object... args) {
         if (cache.containsKey(id)) {
             // if the request to findOrCreate come from a vertex then AND the vertex was already created, that means
@@ -292,7 +294,7 @@ public class GraphMLReader implements GraphReader {
                 return cache.get(id);
             }
         } else {
-            final Object [] argsReady = supportsIds ? ElementHelper.upsert(args, T.id, id) : args;
+            final Object [] argsReady = features.willAllowId(id) ? ElementHelper.upsert(args, T.id, id) : args;
             final Vertex v = graphToWriteTo.addVertex(argsReady);
             cache.put(id, v);
             return v;

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/c1006eea/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java
index 26b88d6..76594ab 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java
@@ -91,7 +91,7 @@ public class GraphSONReader implements GraphReader {
         final AtomicLong counter = new AtomicLong(0);
 
         final boolean supportsTx = graphToWriteTo.features().graph().supportsTransactions();
-        final boolean supportsUserSuppliedIdsOnEdge = graphToWriteTo.features().edge().supportsUserSuppliedIds();
+        final Graph.Features.EdgeFeatures edgeFeatures = graphToWriteTo.features().edge();
 
         final BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
         br.lines().<Vertex>map(FunctionUtils.wrapFunction(line -> readVertex(new ByteArrayInputStream(line.getBytes()), null, null, Direction.OUT))).forEach(vertex -> {
@@ -106,7 +106,7 @@ public class GraphSONReader implements GraphReader {
             // StarAdjacentVertex whose equality should match StarVertex.
             final Vertex cachedOutV = cache.get(e.outVertex());
             final Vertex cachedInV = cache.get(e.inVertex());
-            final Edge newEdge = supportsUserSuppliedIdsOnEdge ? cachedOutV.addEdge(e.label(), cachedInV, T.id, e.id()) : cachedOutV.addEdge(e.label(), cachedInV);
+            final Edge newEdge = edgeFeatures.willAllowId(e.id()) ? cachedOutV.addEdge(e.label(), cachedInV, T.id, e.id()) : cachedOutV.addEdge(e.label(), cachedInV);
             e.properties().forEachRemaining(p -> newEdge.property(p.key(), p.value()));
             if (supportsTx && counter.incrementAndGet() % batchSize == 0)
                 graphToWriteTo.tx().commit();

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/c1006eea/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/LegacyGraphSONReader.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/LegacyGraphSONReader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/LegacyGraphSONReader.java
index 935e2f0..a8d1929 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/LegacyGraphSONReader.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/LegacyGraphSONReader.java
@@ -67,11 +67,11 @@ public class LegacyGraphSONReader implements GraphReader {
         final Map<Object,Vertex> cache = new HashMap<>();
         final AtomicLong counter = new AtomicLong(0);
         final boolean supportsTx = graphToWriteTo.features().graph().supportsTransactions();
-        final boolean supportsEdgeIds = graphToWriteTo.features().edge().supportsUserSuppliedIds();
-        final boolean supportsVertexIds = graphToWriteTo.features().vertex().supportsUserSuppliedIds();
+        final Graph.Features.EdgeFeatures edgeFeatures = graphToWriteTo.features().edge();
+        final Graph.Features.VertexFeatures vertexFeatures = graphToWriteTo.features().vertex();
 
         final JsonFactory factory = mapper.getFactory();
-        final LegacyGraphSONUtility graphson = new LegacyGraphSONUtility(graphToWriteTo, supportsVertexIds, supportsEdgeIds, cache);
+        final LegacyGraphSONUtility graphson = new LegacyGraphSONUtility(graphToWriteTo, vertexFeatures, edgeFeatures, cache);
 
         try (JsonParser parser = factory.createParser(inputStream)) {
             if (parser.nextToken() != JsonToken.START_OBJECT)
@@ -247,15 +247,16 @@ public class LegacyGraphSONReader implements GraphReader {
     static class LegacyGraphSONUtility {
         private static final String EMPTY_STRING = "";
         private final Graph g;
-        private final boolean supportsVertexIds;
-        private final boolean supportsEdgeIds;
+        private final Graph.Features.VertexFeatures vertexFeatures;
+        private final Graph.Features.EdgeFeatures edgeFeatures;
         private final Map<Object,Vertex> cache;
 
-        public LegacyGraphSONUtility(final Graph g, final boolean supportsVertexIds, final boolean supportsEdgeIds,
+        public LegacyGraphSONUtility(final Graph g, final Graph.Features.VertexFeatures vertexFeatures,
+                                     final Graph.Features.EdgeFeatures edgeFeatures,
                                      final Map<Object, Vertex> cache) {
             this.g = g;
-            this.supportsVertexIds = supportsVertexIds;
-            this.supportsEdgeIds = supportsEdgeIds;
+            this.vertexFeatures = vertexFeatures;
+            this.edgeFeatures = edgeFeatures;
             this.cache = cache;
         }
 
@@ -263,7 +264,7 @@ public class LegacyGraphSONReader implements GraphReader {
             final Map<String, Object> props = readProperties(json);
 
             final Object vertexId = getTypedValueFromJsonNode(json.get(GraphSONTokens._ID));
-            final Vertex v = supportsVertexIds ? g.addVertex(T.id, vertexId) : g.addVertex();
+            final Vertex v = vertexFeatures.willAllowId(vertexId) ? g.addVertex(T.id, vertexId) : g.addVertex();
             cache.put(vertexId, v);
 
             for (Map.Entry<String, Object> entry : props.entrySet()) {
@@ -280,7 +281,7 @@ public class LegacyGraphSONReader implements GraphReader {
             final JsonNode nodeLabel = json.get(GraphSONTokens._LABEL);
             final String label = nodeLabel == null ? EMPTY_STRING : nodeLabel.textValue();
 
-            final Edge e = supportsEdgeIds ? out.addEdge(label, in, T.id, edgeId) : out.addEdge(label, in) ;
+            final Edge e = edgeFeatures.willAllowId(edgeId) ? out.addEdge(label, in, T.id, edgeId) : out.addEdge(label, in) ;
             for (Map.Entry<String, Object> entry : props.entrySet()) {
                 e.property(entry.getKey(), entry.getValue());
             }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/c1006eea/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoReader.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoReader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoReader.java
index 359fe79..a208e2f 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoReader.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoReader.java
@@ -84,7 +84,7 @@ public class GryoReader implements GraphReader {
         final Map<StarGraph.StarVertex,Vertex> cache = new HashMap<>();
         final AtomicLong counter = new AtomicLong(0);
 
-        final boolean supportsUserSuppliedIdsOnEdge = graphToWriteTo.features().edge().supportsUserSuppliedIds();
+        final Graph.Features.EdgeFeatures edgeFeatures = graphToWriteTo.features().edge();
         final boolean supportsTx = graphToWriteTo.features().graph().supportsTransactions();
 
         IteratorUtils.iterate(new VertexInputIterator(new Input(inputStream), attachable -> {
@@ -99,7 +99,7 @@ public class GryoReader implements GraphReader {
             // StarAdjacentVertex whose equality should match StarVertex.
             final Vertex cachedOutV = cache.get(e.outVertex());
             final Vertex cachedInV = cache.get(e.inVertex());
-            final Edge newEdge = supportsUserSuppliedIdsOnEdge ? cachedOutV.addEdge(e.label(), cachedInV, T.id, e.id()) : cachedOutV.addEdge(e.label(), cachedInV);
+            final Edge newEdge = edgeFeatures.willAllowId(e.id()) ? cachedOutV.addEdge(e.label(), cachedInV, T.id, e.id()) : cachedOutV.addEdge(e.label(), cachedInV);
             e.properties().forEachRemaining(p -> newEdge.property(p.key(), p.value()));
             if (supportsTx && counter.incrementAndGet() % batchSize == 0)
                 graphToWriteTo.tx().commit();

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/c1006eea/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/Attachable.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/Attachable.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/Attachable.java
index 0049877..4489191 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/Attachable.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/Attachable.java
@@ -49,10 +49,25 @@ public interface Attachable<V> {
      */
     public V get();
 
+    /**
+     * Provide a way to attach an {@link Attachable} implementation to a host.  Note that the context of the host
+     * is not defined by way of the attachment method itself that is supplied as an argument.  It is up to the
+     * implementer to supply that context.
+     *
+     * @param method a {@link Function} that takes an {@link Attachable} and returns the "re-attached" object
+     * @return the return value of the {@code method}
+     * @throws IllegalStateException if the {@link Attachable} is not a "graph" object (i.e. host or
+     * attachable don't work together)
+     */
     public default V attach(final Function<Attachable<V>, V> method) throws IllegalStateException {
         return method.apply(this);
     }
 
+    /**
+     * A collection of general methods of attachment. Note that more efficient methods of attachment might exist
+     * if the user knows the source data being attached and the features of the graph that the data is being
+     * attached to.
+     */
     public static class Method {
         public static <V> Function<Attachable<V>, V> get(final Host hostVertexOrGraph) {
             return (Attachable<V> attachable) -> {
@@ -272,12 +287,11 @@ public interface Attachable<V> {
 
         public static Vertex createVertex(final Attachable<Vertex> attachableVertex, final Graph hostGraph) {
             final Vertex baseVertex = attachableVertex.get();
-            final Vertex vertex = hostGraph.features().vertex().supportsUserSuppliedIds() ?
+            final Vertex vertex = hostGraph.features().vertex().willAllowId(baseVertex.id()) ?
                     hostGraph.addVertex(T.id, baseVertex.id(), T.label, baseVertex.label()) :
                     hostGraph.addVertex(T.label, baseVertex.label());
-            final boolean supportsUserSuppliedIds = hostGraph.features().vertex().properties().supportsUserSuppliedIds();
             baseVertex.properties().forEachRemaining(vp -> {
-                final VertexProperty vertexProperty = supportsUserSuppliedIds ?
+                final VertexProperty vertexProperty = hostGraph.features().vertex().properties().willAllowId(vp.id()) ?
                         vertex.property(hostGraph.features().vertex().getCardinality(vp.key()), vp.key(), vp.value(), T.id, vp.id()) :
                         vertex.property(hostGraph.features().vertex().getCardinality(vp.key()), vp.key(), vp.value());
                 vp.properties().forEachRemaining(p -> vertexProperty.property(p.key(), p.value()));
@@ -290,12 +304,11 @@ public interface Attachable<V> {
         }
 
         public static Edge createEdge(final Attachable<Edge> attachableEdge, final Graph hostGraph) {
-            final boolean supportsUserSuppliedIds = hostGraph.features().vertex().supportsUserSuppliedIds();
             final Edge baseEdge = attachableEdge.get();
             Iterator<Vertex> vertices = hostGraph.vertices(baseEdge.outVertex().id());
-            final Vertex outV = vertices.hasNext() ? vertices.next() : supportsUserSuppliedIds ? hostGraph.addVertex(T.id, baseEdge.outVertex().id()) : hostGraph.addVertex();
+            final Vertex outV = vertices.hasNext() ? vertices.next() : hostGraph.features().vertex().willAllowId(baseEdge.outVertex().id()) ? hostGraph.addVertex(T.id, baseEdge.outVertex().id()) : hostGraph.addVertex();
             vertices = hostGraph.vertices(baseEdge.inVertex().id());
-            final Vertex inV = vertices.hasNext() ? vertices.next() : supportsUserSuppliedIds ? hostGraph.addVertex(T.id, baseEdge.inVertex().id()) : hostGraph.addVertex();
+            final Vertex inV = vertices.hasNext() ? vertices.next() : hostGraph.features().vertex().willAllowId(baseEdge.inVertex().id()) ? hostGraph.addVertex(T.id, baseEdge.inVertex().id()) : hostGraph.addVertex();
             if (ElementHelper.areEqual(outV, inV)) {
                 final Iterator<Edge> itty = outV.edges(Direction.OUT, baseEdge.label());
                 while (itty.hasNext()) {
@@ -304,7 +317,7 @@ public interface Attachable<V> {
                         return e;
                 }
             }
-            final Edge e = hostGraph.features().edge().supportsUserSuppliedIds() ? outV.addEdge(baseEdge.label(), inV, T.id, baseEdge.id()) : outV.addEdge(baseEdge.label(), inV);
+            final Edge e = hostGraph.features().edge().willAllowId(baseEdge.id()) ? outV.addEdge(baseEdge.label(), inV, T.id, baseEdge.id()) : outV.addEdge(baseEdge.label(), inV);
             baseEdge.properties().forEachRemaining(p -> e.property(p.key(), p.value()));
             return e;
         }
@@ -317,7 +330,7 @@ public interface Attachable<V> {
             final VertexProperty<Object> baseVertexProperty = attachableVertexProperty.get();
             final Iterator<Vertex> vertexIterator = hostGraph.vertices(baseVertexProperty.element().id());
             if (vertexIterator.hasNext()) {
-                final VertexProperty vertexProperty = hostGraph.features().vertex().properties().supportsUserSuppliedIds() ?
+                final VertexProperty vertexProperty = hostGraph.features().vertex().properties().willAllowId(baseVertexProperty.id()) ?
                         vertexIterator.next().property(hostGraph.features().vertex().getCardinality(baseVertexProperty.key()), baseVertexProperty.key(), baseVertexProperty.value(), T.id, baseVertexProperty.id()) :
                         vertexIterator.next().property(hostGraph.features().vertex().getCardinality(baseVertexProperty.key()), baseVertexProperty.key(), baseVertexProperty.value());
                 baseVertexProperty.properties().forEachRemaining(p -> vertexProperty.property(p.key(), p.value()));
@@ -328,7 +341,7 @@ public interface Attachable<V> {
 
         public static VertexProperty createVertexProperty(final Attachable<VertexProperty> attachableVertexProperty, final Vertex hostVertex) {
             final VertexProperty<Object> baseVertexProperty = attachableVertexProperty.get();
-            final VertexProperty vertexProperty = hostVertex.graph().features().vertex().properties().supportsUserSuppliedIds() ?
+            final VertexProperty vertexProperty = hostVertex.graph().features().vertex().properties().willAllowId(baseVertexProperty.id()) ?
                     hostVertex.property(hostVertex.graph().features().vertex().getCardinality(baseVertexProperty.key()), baseVertexProperty.key(), baseVertexProperty.value(), T.id, baseVertexProperty.id()) :
                     hostVertex.property(hostVertex.graph().features().vertex().getCardinality(baseVertexProperty.key()), baseVertexProperty.key(), baseVertexProperty.value());
             baseVertexProperty.properties().forEachRemaining(p -> vertexProperty.property(p.key(), p.value()));

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/c1006eea/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java
index 50c3a79..9541cdf 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java
@@ -158,6 +158,11 @@ public final class StarGraph implements Graph, Serializable {
     }
 
     @Override
+    public Features features() {
+        return StarGraphFeatures.INSTANCE;
+    }
+
+    @Override
     public void close() throws Exception {
 
     }
@@ -713,4 +718,110 @@ public final class StarGraph implements Graph, Serializable {
             return this;
         }
     }
+
+    public static class StarGraphFeatures implements Features {
+        public static final StarGraphFeatures INSTANCE = new StarGraphFeatures();
+
+        private StarGraphFeatures() {
+        }
+
+        @Override
+        public GraphFeatures graph() {
+            return StarGraphGraphFeatures.INSTANCE;
+        }
+
+        @Override
+        public EdgeFeatures edge() {
+            return StarGraphEdgeFeatures.INSTANCE;
+        }
+
+        @Override
+        public VertexFeatures vertex() {
+            return StarGraphVertexFeatures.INSTANCE;
+        }
+
+        @Override
+        public String toString() {
+            return StringFactory.featureString(this);
+        }
+    }
+
+    static class StarGraphVertexFeatures implements Features.VertexFeatures {
+        public static final StarGraphVertexFeatures INSTANCE = new StarGraphVertexFeatures();
+
+        private StarGraphVertexFeatures() {
+        }
+
+        @Override
+        public Features.VertexPropertyFeatures properties() {
+            return StarGraphVertexPropertyFeatures.INSTANCE;
+        }
+
+        @Override
+        public boolean supportsCustomIds() {
+            return false;
+        }
+
+        @Override
+        public boolean willAllowId(final Object id) {
+            return true;
+        }
+    }
+
+    static class StarGraphEdgeFeatures implements Features.EdgeFeatures {
+        public static final StarGraphEdgeFeatures INSTANCE = new StarGraphEdgeFeatures();
+
+        private StarGraphEdgeFeatures() {
+        }
+
+        @Override
+        public boolean supportsCustomIds() {
+            return false;
+        }
+
+        @Override
+        public boolean willAllowId(final Object id) {
+            return true;
+        }
+    }
+
+    static class StarGraphGraphFeatures implements Features.GraphFeatures {
+        public static final StarGraphGraphFeatures INSTANCE = new StarGraphGraphFeatures();
+
+        private StarGraphGraphFeatures() {
+        }
+
+        @Override
+        public boolean supportsTransactions() {
+            return false;
+        }
+
+        @Override
+        public boolean supportsPersistence() {
+            return false;
+        }
+
+        @Override
+        public boolean supportsThreadedTransactions() {
+            return false;
+        }
+    }
+
+    static class StarGraphVertexPropertyFeatures implements Features.VertexPropertyFeatures {
+        public static final StarGraphVertexPropertyFeatures INSTANCE = new StarGraphVertexPropertyFeatures();
+
+        private StarGraphVertexPropertyFeatures() {
+        }
+
+        @Override
+        public boolean supportsCustomIds() {
+            return false;
+        }
+
+        @Override
+        public boolean willAllowId(final Object id) {
+            return true;
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/c1006eea/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/FeatureSupportTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/FeatureSupportTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/FeatureSupportTest.java
index ed7190c..40b6694 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/FeatureSupportTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/structure/FeatureSupportTest.java
@@ -22,7 +22,6 @@ import org.apache.tinkerpop.gremlin.AbstractGremlinTest;
 import org.apache.tinkerpop.gremlin.ExceptionCoverage;
 import org.apache.tinkerpop.gremlin.FeatureRequirement;
 import org.apache.tinkerpop.gremlin.FeatureRequirementSet;
-import org.apache.tinkerpop.gremlin.GraphManager;
 import org.apache.tinkerpop.gremlin.structure.Graph.Features.EdgeFeatures;
 import org.apache.tinkerpop.gremlin.structure.Graph.Features.EdgePropertyFeatures;
 import org.apache.tinkerpop.gremlin.structure.Graph.Features.GraphFeatures;
@@ -182,7 +181,7 @@ public class FeatureSupportTest {
         @FeatureRequirement(featureClass = VertexFeatures.class, feature = FEATURE_USER_SUPPLIED_IDS, supported = false)
         public void shouldSupportUserSuppliedIdsIfAnIdCanBeAssignedToVertex() throws Exception {
             try {
-                graph.addVertex(T.id, GraphManager.getGraphProvider().convertId(99999943835l, Vertex.class));
+                graph.addVertex(T.id, graphProvider.convertId(99999943835l, Vertex.class));
                 fail(String.format(INVALID_FEATURE_SPECIFICATION, VertexFeatures.class.getSimpleName(), FEATURE_USER_SUPPLIED_IDS));
             } catch (Exception e) {
                 validateException(Vertex.Exceptions.userSuppliedIdsNotSupported(), e);
@@ -190,6 +189,12 @@ public class FeatureSupportTest {
         }
 
         @Test
+        @FeatureRequirement(featureClass = VertexFeatures.class, feature = FEATURE_USER_SUPPLIED_IDS, supported = false)
+        public void shouldNotAllowAnyIdsIfUserSuppliedIdsIsFalse() throws Exception {
+            assertFalse(graph.features().vertex().willAllowId(graphProvider.convertId(99999943835l, Vertex.class)));
+        }
+
+        @Test
         @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
         @FeatureRequirement(featureClass = VertexFeatures.class, feature = FEATURE_USER_SUPPLIED_IDS)
         @FeatureRequirement(featureClass = VertexFeatures.class, feature = FEATURE_STRING_IDS, supported = false)
@@ -357,7 +362,7 @@ public class FeatureSupportTest {
         public void shouldSupportUserSuppliedIdsIfAnIdCanBeAssignedToEdge() throws Exception {
             try {
                 final Vertex v = graph.addVertex();
-                v.addEdge("friend", v, T.id, GraphManager.getGraphProvider().convertId(99999943835l, Edge.class));
+                v.addEdge("friend", v, T.id, graphProvider.convertId(99999943835l, Edge.class));
                 fail(String.format(INVALID_FEATURE_SPECIFICATION, VertexFeatures.class.getSimpleName(), EdgeFeatures.FEATURE_USER_SUPPLIED_IDS));
             } catch (Exception e) {
                 validateException(Edge.Exceptions.userSuppliedIdsNotSupported(), e);
@@ -365,6 +370,12 @@ public class FeatureSupportTest {
         }
 
         @Test
+        @FeatureRequirement(featureClass = EdgeFeatures.class, feature = EdgeFeatures.FEATURE_USER_SUPPLIED_IDS, supported = false)
+        public void shouldNotAllowAnyIdsIfUserSuppliedIdsIsFalse() throws Exception {
+            assertFalse(graph.features().edge().willAllowId(graphProvider.convertId(99999943835l, Edge.class)));
+        }
+
+        @Test
         @FeatureRequirement(featureClass = Graph.Features.EdgeFeatures.class, feature = Graph.Features.EdgeFeatures.FEATURE_ADD_EDGES)
         @FeatureRequirement(featureClass = Graph.Features.VertexFeatures.class, feature = Graph.Features.VertexFeatures.FEATURE_ADD_VERTICES)
         @FeatureRequirement(featureClass = EdgeFeatures.class, feature = FEATURE_USER_SUPPLIED_IDS, supported = false)
@@ -562,7 +573,7 @@ public class FeatureSupportTest {
         private Edge createEdgeForPropertyFeatureTests() {
             final Vertex vertexA = graph.addVertex();
             final Vertex vertexB = graph.addVertex();
-            return vertexA.addEdge(GraphManager.getGraphProvider().convertLabel("knows"), vertexB);
+            return vertexA.addEdge(graphProvider.convertLabel("knows"), vertexB);
         }
     }
 
@@ -623,7 +634,7 @@ public class FeatureSupportTest {
         public void shouldSupportUserSuppliedIdsIfAnIdCanBeAssigned() throws Exception {
             try {
                 final Vertex v = graph.addVertex();
-                v.property(VertexProperty.Cardinality.single, "name", "me", T.id, GraphManager.getGraphProvider().convertId(99999943835l, VertexProperty.class));
+                v.property(VertexProperty.Cardinality.single, "name", "me", T.id, graphProvider.convertId(99999943835l, VertexProperty.class));
                 fail(String.format(INVALID_FEATURE_SPECIFICATION, VertexFeatures.class.getSimpleName(), VertexPropertyFeatures.FEATURE_USER_SUPPLIED_IDS));
             } catch (Exception ex) {
                 validateException(VertexProperty.Exceptions.userSuppliedIdsNotSupported(), ex);
@@ -631,6 +642,12 @@ public class FeatureSupportTest {
         }
 
         @Test
+        @FeatureRequirement(featureClass = VertexPropertyFeatures.class, feature = FEATURE_USER_SUPPLIED_IDS, supported = false)
+        public void shouldNotAllowAnyIdsIfUserSuppliedIdsIsFalse() throws Exception {
+            assertFalse(graph.features().vertex().properties().willAllowId(graphProvider.convertId(99999943835l, VertexProperty.class)));
+        }
+
+        @Test
         @FeatureRequirementSet(FeatureRequirementSet.Package.VERTICES_ONLY)
         @FeatureRequirement(featureClass = VertexPropertyFeatures.class, feature = FEATURE_USER_SUPPLIED_IDS)
         @FeatureRequirement(featureClass = VertexPropertyFeatures.class, feature = FEATURE_STRING_IDS, supported = false)

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/c1006eea/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopGraph.java
----------------------------------------------------------------------
diff --git a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopGraph.java b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopGraph.java
index 48b6092..469785f 100644
--- a/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopGraph.java
+++ b/hadoop-gremlin/src/main/java/org/apache/tinkerpop/gremlin/hadoop/structure/HadoopGraph.java
@@ -441,6 +441,11 @@ public final class HadoopGraph implements Graph {
                         public boolean supportsRemoveProperty() {
                             return false;
                         }
+
+                        @Override
+                        public boolean supportsCustomIds() {
+                            return false;
+                        }
                     };
                 }
             };

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/c1006eea/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
----------------------------------------------------------------------
diff --git a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
index af9ec79..bb127c4 100644
--- a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
+++ b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
@@ -77,6 +77,8 @@ public final class TinkerGraph implements Graph {
     public static final String CONFIG_EDGE_ID = "gremlin.tinkergraph.edgeIdManager";
     public static final String CONFIG_VERTEX_PROPERTY_ID = "gremlin.tinkergraph.vertexPropertyIdManager";
 
+    private final TinkerGraphFeatures features = new TinkerGraphFeatures();
+
     protected AtomicLong currentId = new AtomicLong(-1l);
     protected Map<Object, Vertex> vertices = new ConcurrentHashMap<>();
     protected Map<Object, Edge> edges = new ConcurrentHashMap<>();
@@ -255,55 +257,62 @@ public final class TinkerGraph implements Graph {
      */
     @Override
     public Features features() {
-        return TinkerGraphFeatures.INSTANCE;
+        return features;
     }
 
-    public static class TinkerGraphFeatures implements Features {
+    public class TinkerGraphFeatures implements Features {
 
-        static final TinkerGraphFeatures INSTANCE = new TinkerGraphFeatures();
+        private final TinkerGraphGraphFeatures graphFeatures = new TinkerGraphGraphFeatures();
+        private final TinkerGraphEdgeFeatures edgeFeatures = new TinkerGraphEdgeFeatures();
+        private final TinkerGraphVertexFeatures vertexFeatures = new TinkerGraphVertexFeatures();
 
         private TinkerGraphFeatures() {
         }
 
         @Override
         public GraphFeatures graph() {
-            return TinkerGraphGraphFeatures.INSTANCE;
+            return graphFeatures;
         }
 
         @Override
         public EdgeFeatures edge() {
-            return TinkerGraphEdgeFeatures.INSTANCE;
+            return edgeFeatures;
         }
 
         @Override
         public VertexFeatures vertex() {
-            return TinkerGraphVertexFeatures.INSTANCE;
+            return vertexFeatures;
         }
 
         @Override
         public String toString() {
             return StringFactory.featureString(this);
         }
-
     }
 
-    public static class TinkerGraphVertexFeatures implements Features.VertexFeatures {
-
-        static final TinkerGraphVertexFeatures INSTANCE = new TinkerGraphVertexFeatures();
+    public class TinkerGraphVertexFeatures implements Features.VertexFeatures {
+        private final TinkerGraphVertexPropertyFeatures vertexPropertyFeatures = new TinkerGraphVertexPropertyFeatures();
 
         private TinkerGraphVertexFeatures() {
         }
 
         @Override
+        public Features.VertexPropertyFeatures properties() {
+            return vertexPropertyFeatures;
+        }
+
+        @Override
         public boolean supportsCustomIds() {
             return false;
         }
 
+        @Override
+        public boolean willAllowId(final Object id) {
+            return vertexIdManager.allow(id);
+        }
     }
 
-    public static class TinkerGraphEdgeFeatures implements Features.EdgeFeatures {
-
-        static final TinkerGraphEdgeFeatures INSTANCE = new TinkerGraphEdgeFeatures();
+    public class TinkerGraphEdgeFeatures implements Features.EdgeFeatures {
 
         private TinkerGraphEdgeFeatures() {
         }
@@ -313,11 +322,13 @@ public final class TinkerGraph implements Graph {
             return false;
         }
 
+        @Override
+        public boolean willAllowId(final Object id) {
+            return edgeIdManager.allow(id);
+        }
     }
 
-    public static class TinkerGraphGraphFeatures implements Features.GraphFeatures {
-
-        static final TinkerGraphGraphFeatures INSTANCE = new TinkerGraphGraphFeatures();
+    public class TinkerGraphGraphFeatures implements Features.GraphFeatures {
 
         private TinkerGraphGraphFeatures() {
         }
@@ -339,6 +350,22 @@ public final class TinkerGraph implements Graph {
 
     }
 
+    public class TinkerGraphVertexPropertyFeatures implements Features.VertexPropertyFeatures {
+
+        private TinkerGraphVertexPropertyFeatures() {
+        }
+
+        @Override
+        public boolean supportsCustomIds() {
+            return false;
+        }
+
+        @Override
+        public boolean willAllowId(final Object id) {
+            return vertexIdManager.allow(id);
+        }
+    }
+
     ///////////// GRAPH SPECIFIC INDEXING METHODS ///////////////
 
     /**
@@ -431,6 +458,11 @@ public final class TinkerGraph implements Graph {
          * Convert an identifier to the type required by the manager.
          */
         T convert(final Object id);
+
+        /**
+         * Determine if an identifier is allowed by this manager given its type.
+         */
+        boolean allow(final Object id);
     }
 
     /**
@@ -460,6 +492,11 @@ public final class TinkerGraph implements Graph {
                 else
                     throw new IllegalArgumentException(String.format("Expected an id that is convertible to Long but received %s", id.getClass()));
             }
+
+            @Override
+            public boolean allow(final Object id) {
+                return id instanceof Number || id instanceof String;
+            }
         },
 
         /**
@@ -485,6 +522,11 @@ public final class TinkerGraph implements Graph {
                 else
                     throw new IllegalArgumentException(String.format("Expected an id that is convertible to Integer but received %s", id.getClass()));
             }
+
+            @Override
+            public boolean allow(final Object id) {
+                return id instanceof Number || id instanceof String;
+            }
         },
 
         /**
@@ -508,6 +550,11 @@ public final class TinkerGraph implements Graph {
                 else
                     throw new IllegalArgumentException(String.format("Expected an id that is convertible to UUID but received %s", id.getClass()));
             }
+
+            @Override
+            public boolean allow(final Object id) {
+                return id instanceof UUID || id instanceof String;
+            }
         },
 
         /**
@@ -526,6 +573,11 @@ public final class TinkerGraph implements Graph {
             public Object convert(final Object id) {
                 return id;
             }
+
+            @Override
+            public boolean allow(final Object id) {
+                return true;
+            }
         }
     }
 }