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

[1/2] incubator-tinkerpop git commit: Neo4j-Gremlin back in the mix -- All Apache2. Builds -- tests fail cause it can't find impl classes.

Repository: incubator-tinkerpop
Updated Branches:
  refs/heads/neo4j-gremlin-apache [created] b2c49ddd3


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertex.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertex.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertex.java
new file mode 100644
index 0000000..ed148ef
--- /dev/null
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertex.java
@@ -0,0 +1,283 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.structure;
+
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.apache.tinkerpop.gremlin.structure.util.wrapped.WrappedVertex;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.neo4j.tinkerpop.api.Neo4jDirection;
+import org.neo4j.tinkerpop.api.Neo4jNode;
+import org.neo4j.tinkerpop.api.Neo4jRelationship;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Optional;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.stream.Stream;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class Neo4jVertex extends Neo4jElement implements Vertex, WrappedVertex<Neo4jNode> {
+
+    protected static final String LABEL_DELIMINATOR = "::";
+
+    public Neo4jVertex(final Neo4jNode node, final Neo4jGraph graph) {
+        super(node, graph);
+    }
+
+    @Override
+    public <V> VertexProperty<V> property(final String key) {
+        if (this.removed) throw Element.Exceptions.elementAlreadyRemoved(Vertex.class, this.getBaseVertex().getId());
+        this.graph.tx().readWrite();
+        if (!this.graph.supportsMultiProperties) {
+            return existsInNeo4j(key) ? new Neo4jVertexProperty<V>(this, key, (V) this.getBaseVertex().getProperty(key)) : VertexProperty.<V>empty();
+        } else {
+            if (existsInNeo4j(key)) {
+                if (this.getBaseVertex().getProperty(key).equals(Neo4jVertexProperty.VERTEX_PROPERTY_TOKEN)) {
+                    if (this.getBaseVertex().degree(Neo4jDirection.OUTGOING, Neo4jVertexProperty.VERTEX_PROPERTY_PREFIX.concat(key)) > 1)
+                        throw Vertex.Exceptions.multiplePropertiesExistForProvidedKey(key);
+                    else
+                        return new Neo4jVertexProperty<>(this, this.getBaseVertex().relationships(
+                                Neo4jDirection.OUTGOING,
+                                Neo4jVertexProperty.VERTEX_PROPERTY_PREFIX.concat(key))
+                                .iterator().next().end());
+                } else {
+                    return new Neo4jVertexProperty<>(this, key, (V) this.getBaseVertex().getProperty(key));
+                }
+            } else
+                return VertexProperty.<V>empty();
+        }
+    }
+
+    @Override
+    public <V> VertexProperty<V> property(final String key, final V value) {
+        return this.property(VertexProperty.Cardinality.single, key, value);
+    }
+
+    // TODO:?
+    @Override
+    public <V> VertexProperty<V> property(String key, V value, Object... keyValues) {
+        return this.property(VertexProperty.Cardinality.single, key, value, keyValues);
+    }
+
+    @Override
+    public <V> VertexProperty<V> property(final VertexProperty.Cardinality cardinality, final String key, final V value, final Object... keyValues) {
+        if (this.removed) throw Element.Exceptions.elementAlreadyRemoved(Vertex.class, this.getBaseVertex().getId());
+        ElementHelper.validateProperty(key, value);
+        if (ElementHelper.getIdValue(keyValues).isPresent())
+            throw VertexProperty.Exceptions.userSuppliedIdsNotSupported();
+        this.graph.tx().readWrite();
+        try {
+            if (!this.graph.supportsMultiProperties) {
+                this.getBaseVertex().setProperty(key, value);
+                return new Neo4jVertexProperty<>(this, key, value);
+            } else {
+                final Optional<VertexProperty<V>> optionalVertexProperty = ElementHelper.stageVertexProperty(this, cardinality, key, value, keyValues);
+                if (optionalVertexProperty.isPresent()) return optionalVertexProperty.get();
+
+                final String prefixedKey = Neo4jVertexProperty.VERTEX_PROPERTY_PREFIX.concat(key);
+                if (this.getBaseVertex().hasProperty(key)) {
+                    if (this.getBaseVertex().getProperty(key).equals(Neo4jVertexProperty.VERTEX_PROPERTY_TOKEN)) {
+                        final Neo4jNode node = this.graph.getBaseGraph().createNode(Neo4jVertexProperty.VERTEX_PROPERTY_LABEL, key);
+                        node.setProperty(T.key.getAccessor(), key);
+                        node.setProperty(T.value.getAccessor(), value);
+                        this.getBaseVertex().connectTo(node, prefixedKey);
+                        final Neo4jVertexProperty<V> property = new Neo4jVertexProperty<>(this, node);
+                        ElementHelper.attachProperties(property, keyValues); // TODO: make this inlined
+                        return property;
+                    } else {
+                        Neo4jNode node = this.graph.getBaseGraph().createNode(Neo4jVertexProperty.VERTEX_PROPERTY_LABEL, key);
+                        node.setProperty(T.key.getAccessor(), key);
+                        node.setProperty(T.value.getAccessor(), this.getBaseVertex().removeProperty(key));
+                        this.getBaseVertex().connectTo(node, prefixedKey);
+                        this.getBaseVertex().setProperty(key, Neo4jVertexProperty.VERTEX_PROPERTY_TOKEN);
+                        node = this.graph.getBaseGraph().createNode(Neo4jVertexProperty.VERTEX_PROPERTY_LABEL, key);
+                        node.setProperty(T.key.getAccessor(), key);
+                        node.setProperty(T.value.getAccessor(), value);
+                        this.getBaseVertex().connectTo(node, prefixedKey);
+                        final Neo4jVertexProperty<V> property = new Neo4jVertexProperty<>(this, node);
+                        ElementHelper.attachProperties(property, keyValues); // TODO: make this inlined
+                        return property;
+                    }
+                } else {
+                    this.getBaseVertex().setProperty(key, value);
+                    final Neo4jVertexProperty<V> property = new Neo4jVertexProperty<>(this, key, value);
+                    ElementHelper.attachProperties(property, keyValues); // TODO: make this inlined
+                    return property;
+                }
+            }
+        } catch (IllegalArgumentException iae) {
+            throw Property.Exceptions.dataTypeOfPropertyValueNotSupported(value);
+        }
+    }
+
+    @Override
+    public void remove() {
+        if (this.removed) throw Element.Exceptions.elementAlreadyRemoved(Vertex.class, this.getBaseVertex().getId());
+        this.removed = true;
+        this.graph.tx().readWrite();
+        try {
+            final Neo4jNode node = this.getBaseVertex();
+            for (final Neo4jRelationship relationship : node.relationships(Neo4jDirection.BOTH)) {
+                final Neo4jNode otherNode = relationship.other(node);
+                if (otherNode.hasLabel(Neo4jVertexProperty.VERTEX_PROPERTY_LABEL)) {
+                    otherNode.relationships(null).forEach(Neo4jRelationship::delete);
+                    otherNode.delete(); // meta property node
+                } else
+                    relationship.delete();
+            }
+            node.delete();
+        } catch (final IllegalStateException ignored) {
+            // this one happens if the vertex is still chilling in the tx
+        } catch (final RuntimeException ex) {
+            if (!Neo4jHelper.isNotFound(ex)) throw ex;
+            // this one happens if the vertex is committed
+        }
+    }
+
+    @Override
+    public Edge addEdge(final String label, final Vertex inVertex, final Object... keyValues) {
+        if (null == inVertex) throw Graph.Exceptions.argumentCanNotBeNull("vertex");
+        if (this.removed) throw Element.Exceptions.elementAlreadyRemoved(Vertex.class, this.getBaseVertex().getId());
+        ElementHelper.validateLabel(label);
+        ElementHelper.legalPropertyKeyValueArray(keyValues);
+        if (ElementHelper.getIdValue(keyValues).isPresent())
+            throw Edge.Exceptions.userSuppliedIdsNotSupported();
+
+        this.graph.tx().readWrite();
+        final Neo4jNode node = (Neo4jNode) this.baseElement;
+        final Neo4jEdge edge = new Neo4jEdge(node.connectTo(((Neo4jVertex) inVertex).getBaseVertex(),
+                label), this.graph);
+        ElementHelper.attachProperties(edge, keyValues);
+        return edge;
+    }
+
+    @Override
+    public Neo4jNode getBaseVertex() {
+        return (Neo4jNode) this.baseElement;
+    }
+
+    @Override
+    public String label() {
+        this.graph.tx().readWrite();
+        return String.join(LABEL_DELIMINATOR, this.labels());
+    }
+
+    /////////////// Neo4jVertex Specific Methods for Multi-Label Support ///////////////
+    public Set<String> labels() {
+        this.graph.tx().readWrite();
+        final Set<String> labels = new TreeSet<>(this.getBaseVertex().labels());
+        return Collections.unmodifiableSet(labels);
+    }
+
+    public void addLabel(final String label) {
+        this.graph.tx().readWrite();
+        this.getBaseVertex().addLabel(label);
+    }
+
+    public void removeLabel(final String label) {
+        this.graph.tx().readWrite();
+        this.getBaseVertex().removeLabel(label);
+    }
+    //////////////////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public String toString() {
+        return StringFactory.vertexString(this);
+    }
+
+    @Override
+    public Iterator<Vertex> vertices(final Direction direction, final String... edgeLabels) {
+        this.graph.tx().readWrite();
+        return new Iterator<Vertex>() {
+            final Iterator<Neo4jRelationship> relationshipIterator = IteratorUtils.filter(0 == edgeLabels.length ?
+                    getBaseVertex().relationships(Neo4jHelper.mapDirection(direction)).iterator() :
+                    getBaseVertex().relationships(Neo4jHelper.mapDirection(direction), (edgeLabels)).iterator(), r -> !r.type().startsWith(Neo4jVertexProperty.VERTEX_PROPERTY_PREFIX));
+
+            @Override
+            public boolean hasNext() {
+                return this.relationshipIterator.hasNext();
+            }
+
+            @Override
+            public Neo4jVertex next() {
+                return new Neo4jVertex(this.relationshipIterator.next().other(getBaseVertex()), graph);
+            }
+        };
+    }
+
+    @Override
+    public Iterator<Edge> edges(final Direction direction, final String... edgeLabels) {
+        this.graph.tx().readWrite();
+        return new Iterator<Edge>() {
+            final Iterator<Neo4jRelationship> relationshipIterator = IteratorUtils.filter(0 == edgeLabels.length ?
+                    getBaseVertex().relationships(Neo4jHelper.mapDirection(direction)).iterator() :
+                    getBaseVertex().relationships(Neo4jHelper.mapDirection(direction), (edgeLabels)).iterator(), r -> !r.type().startsWith(Neo4jVertexProperty.VERTEX_PROPERTY_PREFIX));
+
+            @Override
+            public boolean hasNext() {
+                return this.relationshipIterator.hasNext();
+            }
+
+            @Override
+            public Neo4jEdge next() {
+                return new Neo4jEdge(this.relationshipIterator.next(), graph);
+            }
+        };
+    }
+
+    @Override
+    public <V> Iterator<VertexProperty<V>> properties(final String... propertyKeys) {
+        this.graph.tx().readWrite();
+        return IteratorUtils.stream(getBaseVertex().getKeys())
+                .filter(key -> ElementHelper.keyExists(key, propertyKeys))
+                .flatMap(key -> {
+                    if (getBaseVertex().getProperty(key).equals(Neo4jVertexProperty.VERTEX_PROPERTY_TOKEN))
+                        return IteratorUtils.stream(getBaseVertex().relationships(Neo4jDirection.OUTGOING, (Neo4jVertexProperty.VERTEX_PROPERTY_PREFIX.concat(key))))
+                                .map(relationship -> (VertexProperty<V>) new Neo4jVertexProperty(Neo4jVertex.this, relationship.end()));
+                    else
+                        return Stream.of(new Neo4jVertexProperty<>(Neo4jVertex.this, key, (V) this.getBaseVertex().getProperty(key)));
+                }).iterator();
+    }
+
+    private boolean existsInNeo4j(final String key) {
+        try {
+            return this.getBaseVertex().hasProperty(key);
+        } catch (IllegalStateException ex) {
+            // if vertex is removed before/after transaction close
+            throw Element.Exceptions.elementAlreadyRemoved(Vertex.class, this.id());
+        } catch (RuntimeException ex) {
+            // if vertex is removed before/after transaction close
+            if (Neo4jHelper.isNotFound(ex))
+                throw Element.Exceptions.elementAlreadyRemoved(Vertex.class, this.id());
+            throw ex;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertexProperty.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertexProperty.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertexProperty.java
new file mode 100644
index 0000000..1c538b8
--- /dev/null
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jVertexProperty.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.structure;
+
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.apache.tinkerpop.gremlin.structure.util.wrapped.WrappedVertex;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.neo4j.tinkerpop.api.Neo4jDirection;
+import org.neo4j.tinkerpop.api.Neo4jNode;
+import org.neo4j.tinkerpop.api.Neo4jRelationship;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public final class Neo4jVertexProperty<V> implements VertexProperty<V>, WrappedVertex<Neo4jNode> {
+
+    public static final String VERTEX_PROPERTY_LABEL = "vertexProperty";
+    public static final String VERTEX_PROPERTY_PREFIX = Graph.Hidden.hide("");
+    public static final String VERTEX_PROPERTY_TOKEN = Graph.Hidden.hide("vertexProperty");
+
+
+    private Neo4jNode node;
+    private final Neo4jVertex vertex;
+    private final String key;
+    private final V value;
+
+
+    public Neo4jVertexProperty(final Neo4jVertex vertex, final String key, final V value) {
+        this.vertex = vertex;
+        this.key = key;
+        this.value = value;
+        this.node = null;
+    }
+
+    public Neo4jVertexProperty(final Neo4jVertex vertex, final Neo4jNode node) {
+        this.vertex = vertex;
+        this.node = node;
+        this.key = (String) node.getProperty(T.key.getAccessor());
+        this.value = (V) node.getProperty(T.value.getAccessor());
+    }
+
+    @Override
+    public Vertex element() {
+        return this.vertex;
+    }
+
+    @Override
+    public Object id() {
+        // TODO: Neo4j needs a better ID system for VertexProperties
+        return (long) (this.key.hashCode() + this.value.hashCode() + this.vertex.id().hashCode());
+    }
+
+    @Override
+    public boolean equals(final Object object) {
+        return ElementHelper.areEqual(this, object);
+    }
+
+    @Override
+    public int hashCode() {
+        return ElementHelper.hashCode((Element) this);
+    }
+
+    @Override
+    public Neo4jNode getBaseVertex() {
+        return this.node;
+    }
+
+    @Override
+    public <U> Property<U> property(String key, U value) {
+        if (!this.vertex.graph.supportsMetaProperties)
+            throw VertexProperty.Exceptions.metaPropertiesNotSupported();
+
+        ElementHelper.validateProperty(key, value);
+        this.vertex.graph.tx().readWrite();
+        if (isNode()) {
+            this.node.setProperty(key, value);
+            return new Neo4jProperty<>(this, key, value);
+        } else {
+            this.node = this.vertex.graph.getBaseGraph().createNode(VERTEX_PROPERTY_LABEL, this.label());
+            this.node.setProperty(T.key.getAccessor(), this.key);
+            this.node.setProperty(T.value.getAccessor(), this.value);
+            this.node.setProperty(key, value);
+            this.vertex.getBaseVertex().connectTo(this.node, VERTEX_PROPERTY_PREFIX.concat(this.key));
+            this.vertex.getBaseVertex().setProperty(this.key, VERTEX_PROPERTY_TOKEN);
+            return new Neo4jProperty<>(this, key, value);
+        }
+    }
+
+    @Override
+    public <U> Property<U> property(final String key) {
+        if (!this.vertex.graph.supportsMetaProperties)
+            throw VertexProperty.Exceptions.metaPropertiesNotSupported();
+
+        this.vertex.graph.tx().readWrite();
+        try {
+            if (isNode() && this.node.hasProperty(key))
+                return new Neo4jProperty<>(this, key, (U) this.node.getProperty(key));
+            else
+                return Property.empty();
+        } catch (IllegalStateException ex) {
+            throw Element.Exceptions.elementAlreadyRemoved(this.getClass(), this.id());
+        } catch (RuntimeException ex) {
+            if (Neo4jHelper.isNotFound(ex))
+                throw Element.Exceptions.elementAlreadyRemoved(this.getClass(), this.id());
+            throw ex;
+        }
+    }
+
+    @Override
+    public String key() {
+        return this.key;
+    }
+
+    @Override
+    public V value() throws NoSuchElementException {
+        return this.value;
+    }
+
+    @Override
+    public Set<String> keys() {
+        if (!this.vertex.graph.supportsMetaProperties)
+            throw VertexProperty.Exceptions.metaPropertiesNotSupported();
+
+        if (isNode()) {
+            this.vertex.graph.tx().readWrite();
+            final Set<String> keys = new HashSet<>();
+            for (final String key : this.node.getKeys()) {
+                if (!Graph.Hidden.isHidden(key))
+                    keys.add(key);
+            }
+            return keys;
+        } else {
+            return Collections.emptySet();
+        }
+    }
+
+    @Override
+    public boolean isPresent() {
+        return null != this.value;
+    }
+
+    @Override
+    public void remove() {
+        this.vertex.graph.tx().readWrite();
+        if (!this.vertex.graph.supportsMetaProperties) {
+            if (this.vertex.getBaseVertex().hasProperty(this.key))
+                this.vertex.getBaseVertex().removeProperty(this.key);
+        } else {
+            if (isNode()) {
+                this.node.relationships(null).forEach(Neo4jRelationship::delete);
+                this.node.delete();
+                if (this.vertex.getBaseVertex().degree(Neo4jDirection.OUTGOING, VERTEX_PROPERTY_PREFIX.concat(this.key)) == 0) {
+                    if (this.vertex.getBaseVertex().hasProperty(this.key))
+                        this.vertex.getBaseVertex().removeProperty(this.key);
+                }
+            } else {
+                if (this.vertex.getBaseVertex().degree(Neo4jDirection.OUTGOING, VERTEX_PROPERTY_PREFIX.concat(this.key)) == 0) {
+                    if (this.vertex.getBaseVertex().hasProperty(this.key))
+                        this.vertex.getBaseVertex().removeProperty(this.key);
+                }
+            }
+        }
+    }
+
+    private boolean isNode() {
+        return null != this.node;
+    }
+
+    @Override
+    public String toString() {
+        return StringFactory.propertyString(this);
+    }
+
+    @Override
+    public <U> Iterator<Property<U>> properties(final String... propertyKeys) {
+        if (!isNode()) return Collections.emptyIterator();
+        else {
+            this.vertex.graph().tx().readWrite();
+            return IteratorUtils.map(IteratorUtils.filter(this.node.getKeys().iterator(), key -> !key.equals(T.key.getAccessor()) && !key.equals(T.value.getAccessor()) && ElementHelper.keyExists(key, propertyKeys)), key -> (Property<U>) new Neo4jProperty<>(Neo4jVertexProperty.this, key, (V) this.node.getProperty(key)));
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.groovy.plugin.GremlinPlugin
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.groovy.plugin.GremlinPlugin b/neo4j-gremlin/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.groovy.plugin.GremlinPlugin
new file mode 100644
index 0000000..f4cbea8
--- /dev/null
+++ b/neo4j-gremlin/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.groovy.plugin.GremlinPlugin
@@ -0,0 +1 @@
+org.apache.tinkerpop.gremlin.neo4j.groovy.plugin.Neo4jGremlinPlugin
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/AbstractNeo4jGraphProvider.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/AbstractNeo4jGraphProvider.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/AbstractNeo4jGraphProvider.java
new file mode 100644
index 0000000..b96c52a
--- /dev/null
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/AbstractNeo4jGraphProvider.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j;
+
+import org.apache.tinkerpop.gremlin.AbstractGraphProvider;
+import org.apache.tinkerpop.gremlin.LoadGraphWith;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jEdge;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jElement;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraphVariables;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jProperty;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertex;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertexProperty;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.commons.configuration.Configuration;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public abstract class AbstractNeo4jGraphProvider extends AbstractGraphProvider {
+    private static final Set<Class> IMPLEMENTATIONS = new HashSet<Class>() {{
+        add(Neo4jEdge.class);
+        add(Neo4jElement.class);
+        add(Neo4jGraph.class);
+        add(Neo4jGraphVariables.class);
+        add(Neo4jProperty.class);
+        add(Neo4jVertex.class);
+        add(Neo4jVertexProperty.class);
+    }};
+
+    @Override
+    public void clear(final Graph graph, final Configuration configuration) throws Exception {
+        if (null != graph) {
+            if (graph.features().graph().supportsTransactions() && graph.tx().isOpen())
+                graph.tx().rollback();
+            graph.close();
+        }
+
+        if (configuration.containsKey("gremlin.neo4j.directory")) {
+            // this is a non-in-sideEffects configuration so blow away the directory
+            final File graphDirectory = new File(configuration.getString("gremlin.neo4j.directory"));
+            deleteDirectory(graphDirectory);
+        }
+    }
+
+    @Override
+    public void loadGraphData(final Graph graph, final LoadGraphWith loadGraphWith, final Class testClass, final String testName) {
+        if (loadGraphWith != null) this.createIndices((Neo4jGraph) graph, loadGraphWith.value());
+        super.loadGraphData(graph, loadGraphWith, testClass, testName);
+    }
+
+    private void createIndices(final Neo4jGraph g, final LoadGraphWith.GraphData graphData) {
+        final Random random = new Random();
+        final int pick = random.nextInt(3);
+        //final int pick = 2;
+        if (graphData.equals(LoadGraphWith.GraphData.GRATEFUL)) {
+            if (pick == 1) {
+                g.tx().readWrite();
+                if (random.nextBoolean())
+                    createIndex(g, "CREATE INDEX ON :artist(name)");
+                if (random.nextBoolean())
+                    createIndex(g, "CREATE INDEX ON :song(name)");
+                if (random.nextBoolean())
+                    createIndex(g, "CREATE INDEX ON :song(songType)");
+                if (random.nextBoolean())
+                    createIndex(g, "CREATE INDEX ON :song(performances)");
+                g.tx().commit();
+            } else if (pick == 2) {
+                g.tx().readWrite();
+                if (random.nextBoolean())
+                    g.getBaseGraph().autoIndexProperties(true, "name");
+                if (random.nextBoolean())
+                    g.getBaseGraph().autoIndexProperties(true, "songType");
+                if (random.nextBoolean())
+                    g.getBaseGraph().autoIndexProperties(true, "performances");
+                g.tx().commit();
+            }
+        } else if (graphData.equals(LoadGraphWith.GraphData.MODERN)) {
+            if (pick == 1) {
+                g.tx().readWrite();
+                if (random.nextBoolean())
+                    createIndex(g, "CREATE INDEX ON :person(name)");
+                if (random.nextBoolean())
+                    createIndex(g, "CREATE INDEX ON :person(age)");
+                if (random.nextBoolean())
+                    createIndex(g, "CREATE INDEX ON :software(name)");
+                if (random.nextBoolean()) {
+                    createIndex(g, "CREATE INDEX ON :software(lang)");
+                }
+                g.tx().commit();
+            } else if (pick == 2) {
+                g.tx().readWrite();
+                if (random.nextBoolean())
+                    g.getBaseGraph().autoIndexProperties(true, "name");
+                if (random.nextBoolean())
+                    g.getBaseGraph().autoIndexProperties(true, "age");
+                if (random.nextBoolean())
+                    g.getBaseGraph().autoIndexProperties(true, "lang");
+                g.tx().commit();
+            }
+        } else if (graphData.equals(LoadGraphWith.GraphData.CLASSIC)) {
+            if (pick == 1) {
+                g.tx().readWrite();
+                if (random.nextBoolean())
+                    createIndex(g, "CREATE INDEX ON :vertex(name)");
+                if (random.nextBoolean())
+                    createIndex(g, "CREATE INDEX ON :vertex(age)");
+                if (random.nextBoolean())
+                    createIndex(g, "CREATE INDEX ON :vertex(lang)");
+                g.tx().commit();
+            } else if (pick == 2) {
+                g.tx().readWrite();
+                if (random.nextBoolean())
+                    g.getBaseGraph().autoIndexProperties(true, "name");
+                if (random.nextBoolean())
+                    g.getBaseGraph().autoIndexProperties(true, "age");
+                if (random.nextBoolean())
+                    g.getBaseGraph().autoIndexProperties(true, "lang");
+                g.tx().commit();
+            }
+        } else {
+            // TODO: add CREW work here.
+            // TODO: add meta_property indices when meta_property graph is provided
+            //throw new RuntimeException("Could not load graph with " + graphData);
+        }
+    }
+
+    private void createIndex(Neo4jGraph g, String indexQuery) {
+        Iterator<Map<String, Object>> it = g.getBaseGraph().execute(indexQuery, null);
+        while (it.hasNext()) it.next();
+    }
+
+    @Override
+    public Set<Class> getImplementations() {
+        return IMPLEMENTATIONS;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/BaseNeo4jGraphTest.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/BaseNeo4jGraphTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/BaseNeo4jGraphTest.java
new file mode 100644
index 0000000..f283898
--- /dev/null
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/BaseNeo4jGraphTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestName;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * This should only be used for Neo4j-specific testing that is not related to the Gremlin test suite.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class BaseNeo4jGraphTest {
+    protected Configuration conf;
+    protected final DefaultNeo4jGraphProvider graphProvider = new DefaultNeo4jGraphProvider();
+    protected Neo4jGraph graph;
+    protected GraphTraversalSource g;
+
+    @Rule
+    public TestName name = new TestName();
+
+    /*@Before
+    public void before() throws Exception {
+        // tests that involve legacy indices need legacy indices turned on at startup of the graph.
+        final Map<String, Object> neo4jSettings = new HashMap<>();
+        if (name.getMethodName().contains("NoMultiProperties"))
+            neo4jSettings.put(Neo4jGraph.CONFIG_MULTI_PROPERTIES, false);
+        if (name.getMethodName().contains("NoMetaProperties"))
+            neo4jSettings.put(Neo4jGraph.CONFIG_META_PROPERTIES, false);
+        if (name.getMethodName().contains("Legacy")) {
+            neo4jSettings.put("gremlin.neo4j.conf.node_auto_indexing", "true");
+            neo4jSettings.put("gremlin.neo4j.conf.relationship_auto_indexing", "true");
+        }
+
+        this.conf = neo4jSettings.size() == 0 ?
+                this.graphProvider.newGraphConfiguration("standard", this.getClass(), name.getMethodName()) :
+                this.graphProvider.newGraphConfiguration("standard", this.getClass(), name.getMethodName(), neo4jSettings);
+
+        this.graphProvider.clear(this.conf);
+        this.graph = Neo4jGraph.open(this.conf);
+        this.g = this.graph.traversal();
+
+    }*/
+
+    @After
+    public void after() throws Exception {
+        this.graphProvider.clear(this.graph, this.conf);
+    }
+
+    protected void tryCommit(final Neo4jGraph g, final Consumer<Neo4jGraph> assertFunction) {
+        assertFunction.accept(g);
+        if (g.features().graph().supportsTransactions()) {
+            g.tx().commit();
+            assertFunction.accept(g);
+        }
+    }
+
+    protected static int countIterable(final Iterable iterable) {
+        int count = 0;
+        for (Object object : iterable) {
+            count++;
+        }
+        return count;
+    }
+
+    protected static void validateCounts(final Neo4jGraph graph, int gV, int gE, int gN, int gR) {
+        assertEquals(gV, IteratorUtils.count(graph.vertices()));
+        assertEquals(gE, IteratorUtils.count(graph.edges()));
+        assertEquals(gN, countIterable(graph.getBaseGraph().allNodes()));
+        assertEquals(gR, countIterable(graph.getBaseGraph().allRelationships()));
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/DefaultNeo4jGraphProvider.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/DefaultNeo4jGraphProvider.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/DefaultNeo4jGraphProvider.java
new file mode 100644
index 0000000..7430b96
--- /dev/null
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/DefaultNeo4jGraphProvider.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j;
+
+import org.apache.tinkerpop.gremlin.LoadGraphWith;
+import org.apache.tinkerpop.gremlin.TestHelper;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class DefaultNeo4jGraphProvider extends AbstractNeo4jGraphProvider {
+    @Override
+    public Map<String, Object> getBaseConfiguration(final String graphName, final Class<?> test, final String testMethodName, final LoadGraphWith.GraphData graphData) {
+        return new HashMap<String, Object>() {{
+            put(Graph.GRAPH, Neo4jGraph.class.getName());
+            String directory = getWorkingDirectory() + File.separator + TestHelper.cleanPathSegment(graphName) + File.separator + cleanParameters(TestHelper.cleanPathSegment(testMethodName));
+            put(Neo4jGraph.CONFIG_DIRECTORY, directory);
+            put(Neo4jGraph.CONFIG_META_PROPERTIES, true);
+            put(Neo4jGraph.CONFIG_MULTI_PROPERTIES, true);
+            put(Neo4jGraph.CONFIG_CHECK_ELEMENTS_IN_TRANSACTION, true);
+        }};
+    }
+
+    private String cleanParameters(String methodName) {
+        int random = (int) (Math.random() * Integer.MAX_VALUE);
+        return methodName.replaceAll("[0-9, -]+$", String.valueOf(random));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/Neo4jCypherStartTest.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/Neo4jCypherStartTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/Neo4jCypherStartTest.java
new file mode 100644
index 0000000..aab5ea0
--- /dev/null
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/Neo4jCypherStartTest.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.process;
+
+import org.apache.tinkerpop.gremlin.neo4j.BaseNeo4jGraphTest;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class Neo4jCypherStartTest extends BaseNeo4jGraphTest {
+    @Test
+    public void shouldExecuteCypher() throws Exception {
+        this.graph.addVertex("name", "marko");
+        this.graph.tx().commit();
+        final Iterator<Map<String, Object>> result = graph.cypher("MATCH (a {name:\"marko\"}) RETURN a", Collections.emptyMap());
+        assertNotNull(result);
+        assertTrue(result.hasNext());
+    }
+
+    @Test
+    public void shouldExecuteCypherWithArgs() throws Exception {
+        this.graph.addVertex("name", "marko");
+        this.graph.tx().commit();
+        final Map<String, Object> bindings = new HashMap<>();
+        bindings.put("n", "marko");
+        final Iterator<Map<String, Object>> result = graph.cypher("MATCH (a {name:{n}}) RETURN a", bindings);
+        assertNotNull(result);
+        assertTrue(result.hasNext());
+    }
+
+    @Test
+    public void shouldExecuteCypherWithArgsUsingVertexIdList() throws Exception {
+        final Vertex v = this.graph.addVertex("name", "marko");
+        final List<Object> idList = Arrays.asList(v.id());
+        this.graph.tx().commit();
+
+        final Map<String, Object> bindings = new HashMap<>();
+        bindings.put("ids", idList);
+        final Iterator<String> result = graph.cypher("START n=node({ids}) RETURN n", bindings).select("n").values("name");
+        assertNotNull(result);
+        assertTrue(result.hasNext());
+        assertEquals("marko", result.next());
+    }
+
+    @Test
+    public void shouldExecuteCypherAndBackToGremlin() throws Exception {
+        this.graph.addVertex("name", "marko", "age", 29, "color", "red");
+        this.graph.addVertex("name", "marko", "age", 30, "color", "yellow");
+
+        this.graph.tx().commit();
+        final Traversal result = graph.cypher("MATCH (a {name:\"marko\"}) RETURN a").select("a").has("age", 29).values("color");
+        assertNotNull(result);
+        assertTrue(result.hasNext());
+        assertEquals("red", result.next().toString());
+    }
+
+    @Test
+    public void shouldExecuteMultiIdWhereCypher() throws Exception {
+        this.graph.addVertex("name", "marko", "age", 29, "color", "red");
+        this.graph.addVertex("name", "marko", "age", 30, "color", "yellow");
+        this.graph.addVertex("name", "marko", "age", 30, "color", "orange");
+        this.graph.tx().commit();
+
+        final List<Object> result = graph.cypher("MATCH n WHERE id(n) IN [1,2] RETURN n").select("n").id().toList();
+        assertNotNull(result);
+        assertEquals(2, result.size());
+        assertTrue(result.contains(1l));
+        assertTrue(result.contains(2l));
+    }
+
+    @Test
+    public void shouldExecuteMultiIdWhereWithParamCypher() throws Exception {
+        final Vertex v1 = this.graph.addVertex("name", "marko", "age", 29, "color", "red");
+        final Vertex v2 = this.graph.addVertex("name", "marko", "age", 30, "color", "yellow");
+        this.graph.addVertex("name", "marko", "age", 30, "color", "orange");
+        this.graph.tx().commit();
+
+        final List<Object> ids = Arrays.asList(v1.id(), v2.id());
+        final Map<String, Object> m = new HashMap<>();
+        m.put("ids", ids);
+        final List<Object> result = graph.cypher("MATCH n WHERE id(n) IN {ids} RETURN n", m).select("n").id().toList();
+        assertNotNull(result);
+        assertEquals(2, result.size());
+        assertTrue(result.contains(v1.id()));
+        assertTrue(result.contains(v2.id()));
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/Neo4jGraphProcessStandardTest.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/Neo4jGraphProcessStandardTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/Neo4jGraphProcessStandardTest.java
new file mode 100644
index 0000000..4c8a011
--- /dev/null
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/Neo4jGraphProcessStandardTest.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.process;
+
+import org.apache.tinkerpop.gremlin.GraphProviderClass;
+import org.apache.tinkerpop.gremlin.neo4j.DefaultNeo4jGraphProvider;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
+import org.apache.tinkerpop.gremlin.process.ProcessStandardSuite;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Executes the Standard Gremlin Structure Test Suite using Neo4j.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+@RunWith(ProcessStandardSuite.class)
+@GraphProviderClass(provider = DefaultNeo4jGraphProvider.class, graph = Neo4jGraph.class)
+public class Neo4jGraphProcessStandardTest {
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/groovy/Neo4jGraphGroovyProcessStandardTest.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/groovy/Neo4jGraphGroovyProcessStandardTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/groovy/Neo4jGraphGroovyProcessStandardTest.java
new file mode 100644
index 0000000..db63d38
--- /dev/null
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/groovy/Neo4jGraphGroovyProcessStandardTest.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.process.groovy;
+
+import org.apache.tinkerpop.gremlin.GraphProviderClass;
+import org.apache.tinkerpop.gremlin.neo4j.DefaultNeo4jGraphProvider;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
+import org.apache.tinkerpop.gremlin.process.GroovyProcessStandardSuite;
+import org.junit.runner.RunWith;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+@RunWith(GroovyProcessStandardSuite.class)
+@GraphProviderClass(provider = DefaultNeo4jGraphProvider.class, graph = Neo4jGraph.class)
+public class Neo4jGraphGroovyProcessStandardTest {
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraphStructureStandardTest.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraphStructureStandardTest.java b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraphStructureStandardTest.java
new file mode 100644
index 0000000..fca281e
--- /dev/null
+++ b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraphStructureStandardTest.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.structure;
+
+import org.apache.tinkerpop.gremlin.GraphProviderClass;
+import org.apache.tinkerpop.gremlin.neo4j.DefaultNeo4jGraphProvider;
+import org.apache.tinkerpop.gremlin.structure.StructureStandardSuite;
+import org.junit.runner.RunWith;
+
+
+/**
+ * Executes the Standard Gremlin Structure Test Suite using Neo4j.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+@RunWith(StructureStandardSuite.class)
+@GraphProviderClass(provider = DefaultNeo4jGraphProvider.class, graph = Neo4jGraph.class)
+public class Neo4jGraphStructureStandardTest {
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index efe30db..76bccae 100644
--- a/pom.xml
+++ b/pom.xml
@@ -82,6 +82,7 @@ limitations under the License.
         <module>gremlin-groovy-test</module>
         <module>tinkergraph-gremlin</module>
         <module>hadoop-gremlin</module>
+        <module>neo4j-gremlin</module>
         <module>gremlin-driver</module>
         <module>gremlin-console</module>
         <module>gremlin-server</module>


[2/2] incubator-tinkerpop git commit: Neo4j-Gremlin back in the mix -- All Apache2. Builds -- tests fail cause it can't find impl classes.

Posted by ok...@apache.org.
Neo4j-Gremlin back in the mix -- All Apache2. Builds -- tests fail cause it can't find impl classes.


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

Branch: refs/heads/neo4j-gremlin-apache
Commit: b2c49ddd378eca1231875781d1dcef7499d4863f
Parents: 19bc349
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Thu May 28 09:56:05 2015 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Thu May 28 09:56:05 2015 -0600

----------------------------------------------------------------------
 .../gremlin/util/iterator/IteratorUtils.java    |   9 +-
 neo4j-gremlin/pom.xml                           | 141 +++++
 .../neo4j/groovy/plugin/Neo4jGremlinPlugin.java |  53 ++
 .../step/sideEffect/Neo4jGraphStep.java         | 226 +++++++
 .../optimization/Neo4jGraphStepStrategy.java    |  70 +++
 .../neo4j/process/util/Neo4jCypherIterator.java |  64 ++
 .../gremlin/neo4j/structure/Neo4jEdge.java      |  91 +++
 .../gremlin/neo4j/structure/Neo4jElement.java   | 113 ++++
 .../gremlin/neo4j/structure/Neo4jGraph.java     | 584 +++++++++++++++++++
 .../neo4j/structure/Neo4jGraphVariables.java    | 176 ++++++
 .../gremlin/neo4j/structure/Neo4jHelper.java    |  63 ++
 .../gremlin/neo4j/structure/Neo4jProperty.java  |  99 ++++
 .../gremlin/neo4j/structure/Neo4jVertex.java    | 283 +++++++++
 .../neo4j/structure/Neo4jVertexProperty.java    | 211 +++++++
 ...inkerpop.gremlin.groovy.plugin.GremlinPlugin |   1 +
 .../neo4j/AbstractNeo4jGraphProvider.java       | 156 +++++
 .../gremlin/neo4j/BaseNeo4jGraphTest.java       | 100 ++++
 .../neo4j/DefaultNeo4jGraphProvider.java        |  50 ++
 .../neo4j/process/Neo4jCypherStartTest.java     | 117 ++++
 .../process/Neo4jGraphProcessStandardTest.java  |  36 ++
 .../Neo4jGraphGroovyProcessStandardTest.java    |  33 ++
 .../Neo4jGraphStructureStandardTest.java        |  35 ++
 pom.xml                                         |   1 +
 23 files changed, 2710 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtils.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtils.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtils.java
index d9d54cb..6937bf4 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtils.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtils.java
@@ -44,7 +44,8 @@ import java.util.stream.StreamSupport;
  */
 public final class IteratorUtils {
 
-    private IteratorUtils() {}
+    private IteratorUtils() {
+    }
 
     public static final <S> Iterator<S> of(final S a) {
         return new SingleIterator<>(a);
@@ -64,7 +65,7 @@ public final class IteratorUtils {
     }
 
     public static void iterate(final Iterator iterator) {
-        while(iterator.hasNext()) {
+        while (iterator.hasNext()) {
             iterator.next();
         }
     }
@@ -339,4 +340,8 @@ public final class IteratorUtils {
     public static <T> Stream<T> stream(final Iterator<T> iterator) {
         return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.IMMUTABLE | Spliterator.SIZED), false);
     }
+
+    public static <T> Stream<T> stream(final Iterable<T> iterable) {
+        return IteratorUtils.stream(iterable.iterator());
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/pom.xml
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/pom.xml b/neo4j-gremlin/pom.xml
new file mode 100644
index 0000000..b93e840
--- /dev/null
+++ b/neo4j-gremlin/pom.xml
@@ -0,0 +1,141 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.tinkerpop</groupId>
+        <artifactId>tinkerpop</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>neo4j-gremlin</artifactId>
+    <name>Apache TinkerPop :: Neo4j Gremlin</name>
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.tinkerpop</groupId>
+            <artifactId>gremlin-core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tinkerpop</groupId>
+            <artifactId>gremlin-groovy</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.neo4j</groupId>
+            <artifactId>neo4j-tinkerpop-api</artifactId>
+            <version>0.1</version>
+        </dependency>
+        <!-- TESTING -->
+        <dependency>
+            <groupId>org.apache.tinkerpop</groupId>
+            <artifactId>gremlin-test</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tinkerpop</groupId>
+            <artifactId>gremlin-groovy-test</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <directory>${basedir}/target</directory>
+        <finalName>${project.artifactId}-${project.version}</finalName>
+        <resources>
+            <resource>
+                <directory>${basedir}/src/main/resources
+                </directory>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-failsafe-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.gmavenplus</groupId>
+                <artifactId>gmavenplus-plugin</artifactId>
+                <version>1.2</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>addSources</goal>
+                            <goal>addTestSources</goal>
+                            <goal>generateStubs</goal>
+                            <goal>compile</goal>
+                            <goal>testGenerateStubs</goal>
+                            <goal>testCompile</goal>
+                            <goal>removeStubs</goal>
+                            <goal>removeTestStubs</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <invokeDynamic>true</invokeDynamic>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.6</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+    <profiles>
+        <profile>
+            <id>lucky</id>
+            <activation>
+                <activeByDefault>false</activeByDefault>
+                <property>
+                    <name>feelingLucky</name>
+                </property>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <skipTests>true</skipTests>
+                        </configuration>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <configuration>
+                            <skipTests>true</skipTests>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/groovy/plugin/Neo4jGremlinPlugin.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/groovy/plugin/Neo4jGremlinPlugin.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/groovy/plugin/Neo4jGremlinPlugin.java
new file mode 100644
index 0000000..b112e43
--- /dev/null
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/groovy/plugin/Neo4jGremlinPlugin.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.groovy.plugin;
+
+import org.apache.tinkerpop.gremlin.groovy.plugin.AbstractGremlinPlugin;
+import org.apache.tinkerpop.gremlin.groovy.plugin.IllegalEnvironmentException;
+import org.apache.tinkerpop.gremlin.groovy.plugin.PluginAcceptor;
+import org.apache.tinkerpop.gremlin.groovy.plugin.PluginInitializationException;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class Neo4jGremlinPlugin extends AbstractGremlinPlugin {
+
+    private static final Set<String> IMPORTS = new HashSet<String>() {{
+        add(IMPORT_SPACE + Neo4jGraph.class.getPackage().getName() + DOT_STAR);
+    }};
+
+    @Override
+    public String getName() {
+        return "tinkerpop.neo4j";
+    }
+
+    @Override
+    public void pluginTo(final PluginAcceptor pluginAcceptor) throws PluginInitializationException, IllegalEnvironmentException {
+        pluginAcceptor.addImports(IMPORTS);
+    }
+
+    @Override
+    public void afterPluginTo(final PluginAcceptor pluginAcceptor) throws IllegalEnvironmentException, PluginInitializationException {
+
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
new file mode 100644
index 0000000..aafad32
--- /dev/null
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/step/sideEffect/Neo4jGraphStep.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.process.traversal.step.sideEffect;
+
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jEdge;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertex;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertexProperty;
+import org.apache.tinkerpop.gremlin.process.traversal.Compare;
+import org.apache.tinkerpop.gremlin.process.traversal.Contains;
+import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GraphStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.HasContainer;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.T;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.javatuples.Pair;
+import org.neo4j.tinkerpop.api.Neo4jDirection;
+import org.neo4j.tinkerpop.api.Neo4jGraphAPI;
+import org.neo4j.tinkerpop.api.Neo4jNode;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Stream;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ * @author Pieter Martin
+ */
+public final class Neo4jGraphStep<S extends Element> extends GraphStep<S> {
+
+    public final List<HasContainer> hasContainers = new ArrayList<>();
+
+    public Neo4jGraphStep(final GraphStep<S> originalGraphStep) {
+        super(originalGraphStep.getTraversal(), originalGraphStep.getReturnClass(), originalGraphStep.getIds());
+        originalGraphStep.getLabels().forEach(this::addLabel);
+        //No need to do anything if the first element is an Element, all elements are guaranteed to be an element and will be return as is
+        if ((this.ids.length == 0 || !(this.ids[0] instanceof Element)))
+            this.setIteratorSupplier(() -> (Iterator<S>) (Vertex.class.isAssignableFrom(this.returnClass) ? this.vertices() : this.edges()));
+    }
+
+    private Iterator<? extends Edge> edges() {
+        final Neo4jGraph graph = (Neo4jGraph) this.getTraversal().getGraph().get();
+        graph.tx().readWrite();
+        // ids are present, filter on them first
+        if (this.ids != null && this.ids.length > 0)
+            return IteratorUtils.filter(graph.edges(this.ids), edge -> HasContainer.testAll((Edge) edge, this.hasContainers));
+        final HasContainer hasContainer = this.getHasContainerForAutomaticIndex(Edge.class);
+        return (null == hasContainer) ?
+                IteratorUtils.filter(graph.edges(), edge -> HasContainer.testAll((Edge) edge, this.hasContainers)) :
+                getEdgesUsingAutomaticIndex(hasContainer).filter(edge -> HasContainer.testAll((Edge) edge, this.hasContainers)).iterator();
+    }
+
+    private Iterator<? extends Vertex> vertices() {
+        final Neo4jGraph graph = (Neo4jGraph) this.getTraversal().getGraph().get();
+        graph.tx().readWrite();
+        // ids are present, filter on them first
+        if (this.ids != null && this.ids.length > 0)
+            return IteratorUtils.filter(graph.vertices(this.ids), vertex -> HasContainer.testAll((Vertex) vertex, this.hasContainers));
+        // a label and a property
+        final Pair<String, HasContainer> labelHasPair = this.getHasContainerForLabelIndex();
+        if (null != labelHasPair)
+            return this.getVerticesUsingLabelAndProperty(labelHasPair.getValue0(), labelHasPair.getValue1())
+                    .filter(vertex -> HasContainer.testAll((Vertex) vertex, this.hasContainers)).iterator();
+        // use automatic indices
+        final HasContainer hasContainer = this.getHasContainerForAutomaticIndex(Vertex.class);
+        if (null != hasContainer)
+            return this.getVerticesUsingAutomaticIndex(hasContainer)
+                    .filter(vertex -> HasContainer.testAll((Vertex) vertex, this.hasContainers)).iterator();
+        // only labels
+        final List<String> labels = this.getInternalLabels();
+        if (null != labels)
+            return this.getVerticesUsingOnlyLabels(labels).filter(vertex -> HasContainer.testAll((Vertex) vertex, this.hasContainers)).iterator();
+        // linear scan
+        return IteratorUtils.filter(graph.vertices(), vertex -> HasContainer.testAll((Vertex) vertex, this.hasContainers));
+    }
+
+
+    private Stream<Neo4jVertex> getVerticesUsingLabelAndProperty(final String label, final HasContainer hasContainer) {
+        //System.out.println("labelProperty: " + label + ":" + hasContainer);
+        final Neo4jGraph graph = (Neo4jGraph) this.getTraversal().getGraph().get();
+        final Iterable<Neo4jNode> iterator1 = graph.getBaseGraph().findNodes(label, hasContainer.getKey(), hasContainer.getValue());
+        final Iterable<Neo4jNode> iterator2 = graph.getBaseGraph().findNodes(hasContainer.getKey(), T.value.getAccessor(), hasContainer.getValue());
+        final Stream<Neo4jVertex> stream1 = IteratorUtils.stream(iterator1)
+                .filter(node -> ElementHelper.idExists(node.getId(), this.ids))
+                .map(node -> new Neo4jVertex(node, graph));
+        final Stream<Neo4jVertex> stream2 = IteratorUtils.stream(iterator2)
+                .filter(node -> ElementHelper.idExists(node.getId(), this.ids))
+                .filter(node -> node.getProperty(T.key.getAccessor()).equals(hasContainer.getKey()))
+                .map(node -> node.relationships(Neo4jDirection.INCOMING).iterator().next().start())
+                .map(node -> new Neo4jVertex(node, graph));
+        return Stream.concat(stream1, stream2);
+    }
+
+    private Stream<Neo4jVertex> getVerticesUsingOnlyLabels(final List<String> labels) {
+        //System.out.println("labels: " + labels);
+        final Neo4jGraph graph = (Neo4jGraph) this.getTraversal().getGraph().get();
+        return labels.stream()
+                .filter(label -> !label.equals(Neo4jVertexProperty.VERTEX_PROPERTY_LABEL))
+                .flatMap(label -> IteratorUtils.stream(graph.getBaseGraph().findNodes(label)))
+                .filter(node -> !node.hasLabel(Neo4jVertexProperty.VERTEX_PROPERTY_LABEL))
+                .filter(node -> ElementHelper.idExists(node.getId(), this.ids))
+                .map(node -> new Neo4jVertex(node, graph));
+    }
+
+    private Stream<Neo4jVertex> getVerticesUsingAutomaticIndex(final HasContainer hasContainer) {
+        //System.out.println("automatic index: " + hasContainer);
+        final Neo4jGraph graph = (Neo4jGraph) this.getTraversal().getGraph().get();
+        return IteratorUtils.stream(graph.getBaseGraph().findNodes(hasContainer.getKey(), hasContainer.getValue()).iterator())
+                .map(node -> node.hasLabel(Neo4jVertexProperty.VERTEX_PROPERTY_LABEL) ?
+                        node.relationships(Neo4jDirection.INCOMING).iterator().next().start() :
+                        node)
+                .filter(node -> ElementHelper.idExists(node.getId(), this.ids))
+                .map(node -> new Neo4jVertex(node, graph));
+    }
+
+    private Stream<Neo4jEdge> getEdgesUsingAutomaticIndex(final HasContainer hasContainer) {
+        final Neo4jGraph graph = (Neo4jGraph) this.getTraversal().getGraph().get();
+        return IteratorUtils.stream(graph.getBaseGraph().findRelationships(hasContainer.getKey(), hasContainer.getValue()).iterator())
+                .filter(relationship -> ElementHelper.idExists(relationship.getId(), this.ids))
+                .filter(relationship -> !relationship.type().startsWith(Neo4jVertexProperty.VERTEX_PROPERTY_PREFIX))
+                .map(relationship -> new Neo4jEdge(relationship, graph));
+    }
+
+    private Pair<String, HasContainer> getHasContainerForLabelIndex() {
+        final Neo4jGraph graph = (Neo4jGraph) this.getTraversal().getGraph().get();
+        Neo4jGraphAPI baseGraph = graph.getBaseGraph();
+        for (final HasContainer hasContainer : this.hasContainers) {
+            if (hasContainer.getKey().equals(T.label.getAccessor()) && hasContainer.getBiPredicate().equals(Compare.eq)) {
+                if (baseGraph.hasSchemaIndex(
+                        (String) hasContainer.getValue(), hasContainer.getKey())) {
+                    return Pair.with((String) hasContainer.getValue(), hasContainer);
+                }
+            }
+        }
+        return null;
+    }
+
+    private List<String> getInternalLabels() {
+        for (final HasContainer hasContainer : this.hasContainers) {
+            if (hasContainer.getKey().equals(T.label.getAccessor()) && hasContainer.getBiPredicate().equals(Compare.eq))
+                return Arrays.asList(((String) hasContainer.getValue()));
+            else if (hasContainer.getKey().equals(T.label.getAccessor()) && hasContainer.getBiPredicate().equals(Contains.within))
+                return new ArrayList<>((Collection<String>) hasContainer.getValue());
+        }
+        return null;
+    }
+
+    private HasContainer getHasContainerForAutomaticIndex(final Class<? extends Element> elementClass) {
+        final Neo4jGraph graph = (Neo4jGraph) this.getTraversal().getGraph().get();
+        Neo4jGraphAPI baseGraph = graph.getBaseGraph();
+        boolean isNode = elementClass.equals(Vertex.class);
+        for (final HasContainer hasContainer : this.hasContainers) {
+            if (hasContainer.getBiPredicate().equals(Compare.eq) &&
+                    baseGraph.hasAutoIndex(isNode, hasContainer.getKey())) {
+                return hasContainer;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        if (this.hasContainers.isEmpty())
+            return super.toString();
+        else
+            return 0 == this.ids.length ?
+                    StringFactory.stepString(this, this.hasContainers) :
+                    StringFactory.stepString(this, Arrays.toString(this.ids), this.hasContainers);
+    }
+
+    /*private String makeCypherQuery() {
+        final StringBuilder builder = new StringBuilder("MATCH node WHERE ");
+        int counter = 0;
+        for (final HasContainer hasContainer : this.hasContainers) {
+            if (hasContainer.key.equals(T.label.getAccessor()) && hasContainer.predicate.equals(Compare.EQUAL)) {
+                if (counter++ > 0) builder.append(" AND ");
+                builder.append("node:").append(hasContainer.value);
+            } else {
+                if (counter++ > 0) builder.append(" AND ");
+                builder.append("node.").append(hasContainer.key).append(" ");
+                if (hasContainer.predicate instanceof Compare) {
+                    builder.append(((Compare) hasContainer.predicate).asString()).append(" ").append(toStringOfValue(hasContainer.value));
+                } else if (hasContainer.predicate.equals(Contains.IN)) {
+                    builder.append("IN [");
+                    for (Object object : (Collection) hasContainer.value) {
+                        builder.append(toStringOfValue(object)).append(",");
+                    }
+                    builder.replace(builder.length() - 1, builder.length(), "").append("]");
+                }
+            }
+
+        }
+        System.out.println(builder);
+        return builder.toString();
+    }
+
+    private String toStringOfValue(final Object value) {
+        if (value instanceof String)
+            return "'" + value + "'";
+        else return value.toString();
+    }*/
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/strategy/optimization/Neo4jGraphStepStrategy.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/strategy/optimization/Neo4jGraphStepStrategy.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/strategy/optimization/Neo4jGraphStepStrategy.java
new file mode 100644
index 0000000..eb98825
--- /dev/null
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/traversal/strategy/optimization/Neo4jGraphStepStrategy.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.process.traversal.strategy.optimization;
+
+import org.apache.tinkerpop.gremlin.neo4j.process.traversal.step.sideEffect.Neo4jGraphStep;
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.step.HasContainerHolder;
+import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.GraphStep;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
+
+/**
+ * @author Pieter Martin
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public final class Neo4jGraphStepStrategy extends AbstractTraversalStrategy<TraversalStrategy.VendorOptimizationStrategy> {
+
+    private static final Neo4jGraphStepStrategy INSTANCE = new Neo4jGraphStepStrategy();
+
+    private Neo4jGraphStepStrategy() {
+    }
+
+    @Override
+    public void apply(final Traversal.Admin<?, ?> traversal) {
+        if (traversal.getEngine().isComputer())
+            return;
+
+        final Step<?, ?> startStep = traversal.getStartStep();
+        if (startStep instanceof GraphStep) {
+            final GraphStep<?> originalGraphStep = (GraphStep) startStep;
+            final Neo4jGraphStep<?> neo4jGraphStep = new Neo4jGraphStep<>(originalGraphStep);
+            TraversalHelper.replaceStep(startStep, (Step) neo4jGraphStep, traversal);
+
+            Step<?, ?> currentStep = neo4jGraphStep.getNextStep();
+            while (true) {
+                if (currentStep instanceof HasContainerHolder) {
+                    neo4jGraphStep.hasContainers.addAll(((HasContainerHolder) currentStep).getHasContainers());
+                    currentStep.getLabels().forEach(neo4jGraphStep::addLabel);
+                    traversal.removeStep(currentStep);
+                } else {
+                    break;
+                }
+                currentStep = currentStep.getNextStep();
+            }
+        }
+    }
+
+    public static Neo4jGraphStepStrategy instance() {
+        return INSTANCE;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/util/Neo4jCypherIterator.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/util/Neo4jCypherIterator.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/util/Neo4jCypherIterator.java
new file mode 100644
index 0000000..9117ab2
--- /dev/null
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/process/util/Neo4jCypherIterator.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.process.util;
+
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jEdge;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
+import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jVertex;
+import org.neo4j.tinkerpop.api.Neo4jNode;
+import org.neo4j.tinkerpop.api.Neo4jRelationship;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class Neo4jCypherIterator<T> implements Iterator<Map<String, T>> {
+
+    private final Iterator<Map<String, T>> iterator;
+    private final Neo4jGraph graph;
+
+    public Neo4jCypherIterator(final Iterator<Map<String, T>> iterator, final Neo4jGraph graph) {
+        this.iterator = iterator;
+        this.graph = graph;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return this.iterator.hasNext();
+    }
+
+    @Override
+    public Map<String, T> next() {
+        return this.iterator.next().entrySet().stream().collect(Collectors.toMap(
+                Map.Entry::getKey,
+                entry -> {
+                    final T val = entry.getValue();
+                    if (Neo4jNode.class.isAssignableFrom(val.getClass())) {
+                        return (T) new Neo4jVertex((Neo4jNode) val, this.graph);
+                    } else if (Neo4jRelationship.class.isAssignableFrom(val.getClass())) {
+                        return (T) new Neo4jEdge((Neo4jRelationship) val, this.graph);
+                    } else {
+                        return val;
+                    }
+                }));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jEdge.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jEdge.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jEdge.java
new file mode 100644
index 0000000..a08fd8d
--- /dev/null
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jEdge.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.structure;
+
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.apache.tinkerpop.gremlin.structure.util.wrapped.WrappedEdge;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.neo4j.tinkerpop.api.Neo4jRelationship;
+
+import java.util.Iterator;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class Neo4jEdge extends Neo4jElement implements Edge, WrappedEdge<Neo4jRelationship> {
+
+    public Neo4jEdge(final Neo4jRelationship relationship, final Neo4jGraph graph) {
+        super(relationship, graph);
+    }
+
+    @Override
+    public void remove() {
+        if (this.removed) throw Element.Exceptions.elementAlreadyRemoved(Edge.class, this.getBaseEdge().getId());
+        this.removed = true;
+        this.graph.tx().readWrite();
+        try {
+            ((Neo4jRelationship) this.baseElement).delete();
+        } catch (IllegalStateException ignored) {
+            // NotFoundException happens if the edge is committed
+            // IllegalStateException happens if the edge is still chilling in the tx
+        } catch (RuntimeException e) {
+            if (!Neo4jHelper.isNotFound(e)) throw e;
+            // NotFoundException happens if the edge is committed
+            // IllegalStateException happens if the edge is still chilling in the tx
+        }
+    }
+
+    public String toString() {
+        return StringFactory.edgeString(this);
+    }
+
+    @Override
+    public String label() {
+        this.graph.tx().readWrite();
+        return this.getBaseEdge().type();
+    }
+
+    @Override
+    public Neo4jRelationship getBaseEdge() {
+        return (Neo4jRelationship) this.baseElement;
+    }
+
+    @Override
+    public <V> Iterator<Property<V>> properties(final String... propertyKeys) {
+        return (Iterator) super.properties(propertyKeys);
+    }
+
+    @Override
+    public Iterator<Vertex> vertices(final Direction direction) {
+        this.graph.tx().readWrite();
+        switch (direction) {
+            case OUT:
+                return IteratorUtils.of(new Neo4jVertex(this.getBaseEdge().start(), this.graph));
+            case IN:
+                return IteratorUtils.of(new Neo4jVertex(this.getBaseEdge().end(), this.graph));
+            default:
+                return IteratorUtils.of(new Neo4jVertex(this.getBaseEdge().start(), this.graph), new Neo4jVertex(this.getBaseEdge().end(), this.graph));
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jElement.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jElement.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jElement.java
new file mode 100644
index 0000000..770d763
--- /dev/null
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jElement.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.structure;
+
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
+import org.apache.tinkerpop.gremlin.structure.util.wrapped.WrappedElement;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.neo4j.tinkerpop.api.Neo4jEntity;
+
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public abstract class Neo4jElement implements Element, WrappedElement<Neo4jEntity> {
+    protected final Neo4jGraph graph;
+    protected final Neo4jEntity baseElement;
+    protected boolean removed = false;
+
+    public Neo4jElement(final Neo4jEntity baseElement, final Neo4jGraph graph) {
+        this.baseElement = baseElement;
+        this.graph = graph;
+    }
+
+    @Override
+    public Graph graph() {
+        return this.graph;
+    }
+
+    @Override
+    public Object id() {
+        this.graph.tx().readWrite();
+        return this.baseElement.getId();
+    }
+
+    @Override
+    public Set<String> keys() {
+        this.graph.tx().readWrite();
+        return Element.super.keys();
+    }
+
+    @Override
+    public <V> Property<V> property(final String key) {
+        this.graph.tx().readWrite();
+        try {
+            if (this.baseElement.hasProperty(key))
+                return new Neo4jProperty<>(this, key, (V) this.baseElement.getProperty(key));
+            else
+                return Property.empty();
+        } catch (final IllegalStateException e) {
+            throw Element.Exceptions.elementAlreadyRemoved(this.getClass(), this.id());
+        }
+    }
+
+    @Override
+    public <V> Property<V> property(final String key, final V value) {
+        ElementHelper.validateProperty(key, value);
+        this.graph.tx().readWrite();
+
+        try {
+            this.baseElement.setProperty(key, value);
+            return new Neo4jProperty<>(this, key, value);
+        } catch (final IllegalArgumentException e) {
+            throw Property.Exceptions.dataTypeOfPropertyValueNotSupported(value);
+        }
+    }
+
+    @Override
+    public boolean equals(final Object object) {
+        return ElementHelper.areEqual(this, object);
+    }
+
+    @Override
+    public int hashCode() {
+        return ElementHelper.hashCode(this);
+    }
+
+    @Override
+    public Neo4jEntity getBaseElement() {
+        return this.baseElement;
+    }
+
+    @Override
+    public <V> Iterator<? extends Property<V>> properties(final String... propertyKeys) {
+        this.graph.tx().readWrite();
+        Iterable<String> keys = this.baseElement.getKeys();
+        Iterator<String> filter = IteratorUtils.filter(keys.iterator(),
+                key -> ElementHelper.keyExists(key, propertyKeys));
+        return IteratorUtils.map(filter,
+                key -> new Neo4jProperty<>(this, key, (V) this.baseElement.getProperty(key)));
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraph.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraph.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraph.java
new file mode 100644
index 0000000..e1ff965
--- /dev/null
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraph.java
@@ -0,0 +1,584 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.structure;
+
+import org.apache.commons.configuration.BaseConfiguration;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationConverter;
+import org.apache.tinkerpop.gremlin.neo4j.process.traversal.strategy.optimization.Neo4jGraphStepStrategy;
+import org.apache.tinkerpop.gremlin.neo4j.process.util.Neo4jCypherIterator;
+import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.StartStep;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Transaction;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.AbstractTransaction;
+import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.apache.tinkerpop.gremlin.structure.util.wrapped.WrappedGraph;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.neo4j.tinkerpop.api.Neo4jFactory;
+import org.neo4j.tinkerpop.api.Neo4jGraphAPI;
+import org.neo4j.tinkerpop.api.Neo4jTx;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Pieter Martin
+ */
+@Graph.OptIn(Graph.OptIn.SUITE_STRUCTURE_STANDARD)
+@Graph.OptIn(Graph.OptIn.SUITE_STRUCTURE_INTEGRATE)
+@Graph.OptIn(Graph.OptIn.SUITE_STRUCTURE_PERFORMANCE)
+@Graph.OptIn(Graph.OptIn.SUITE_PROCESS_STANDARD)
+@Graph.OptIn(Graph.OptIn.SUITE_PROCESS_PERFORMANCE)
+@Graph.OptIn(Graph.OptIn.SUITE_GROOVY_PROCESS_STANDARD)
+@Graph.OptIn(Graph.OptIn.SUITE_GROOVY_ENVIRONMENT)
+@Graph.OptIn(Graph.OptIn.SUITE_GROOVY_ENVIRONMENT_INTEGRATE)
+@Graph.OptIn(Graph.OptIn.SUITE_GROOVY_ENVIRONMENT_PERFORMANCE)
+/*@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.structure.VertexTest$ExceptionConsistencyWhenVertexRemovedTest",
+        method = "shouldThrowExceptionIfVertexWasRemovedWhenCallingProperty",
+        specific = "property(single,k,v)",
+        reason = "Neo4j throws a NodeNotFoundException instead of the desired IllegalStateException.")
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.AddVertexTest$Traversals",
+        method = "g_V_addVXlabel_animal_age_0X",
+        reason = "Neo4j global graph operators stream created vertices created after the access to the global iterator."
+)
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.GroovyAddVertexTest$StandardTraversals",
+        method = "g_V_addVXlabel_animal_age_0X",
+        reason = "Neo4j global graph operators stream created vertices created after the access to the global iterator."
+)
+@Graph.OptOut(
+        test = "org.apache.tinkerpop.gremlin.structure.GraphTest",
+        method = "shouldRemoveEdgesWithoutConcurrentModificationException",
+        reason = "Neo4j global graph operators stream removes edges after access to the global iterator."
+)*/
+public final class Neo4jGraph implements Graph, WrappedGraph<Neo4jGraphAPI> {
+
+    static {
+        TraversalStrategies.GlobalCache.registerStrategies(Neo4jGraph.class, TraversalStrategies.GlobalCache.getStrategies(Graph.class).clone().addStrategies(Neo4jGraphStepStrategy.instance()));
+    }
+
+    private static final Configuration EMPTY_CONFIGURATION = new BaseConfiguration() {{
+        this.setProperty(Graph.GRAPH, Neo4jGraph.class.getName());
+    }};
+
+    private final Features features = new Neo4jGraphFeatures();
+
+    private Neo4jGraphAPI baseGraph;
+    private BaseConfiguration configuration = new BaseConfiguration();
+
+    public static final String CONFIG_DIRECTORY = "gremlin.neo4j.directory";
+    public static final String CONFIG_CONF = "gremlin.neo4j.conf";
+    public static final String CONFIG_META_PROPERTIES = "gremlin.neo4j.metaProperties";
+    public static final String CONFIG_MULTI_PROPERTIES = "gremlin.neo4j.multiProperties";
+    public static final String CONFIG_CHECK_ELEMENTS_IN_TRANSACTION = "gremlin.neo4j.checkElementsInTransaction";
+
+    private final Neo4jTransaction neo4jTransaction = new Neo4jTransaction();
+    private final Neo4jGraphVariables neo4jGraphVariables;
+
+    protected final boolean supportsMetaProperties;
+    protected final boolean supportsMultiProperties;
+    protected boolean checkElementsInTransaction = false;
+
+    private Neo4jGraph(final Neo4jGraphAPI baseGraph) {
+        this.configuration.copy(EMPTY_CONFIGURATION);
+        this.baseGraph = baseGraph;
+        this.neo4jGraphVariables = new Neo4jGraphVariables(this);
+
+        ///////////
+        final Optional<Boolean> metaProperties = this.neo4jGraphVariables.get(Hidden.hide(CONFIG_META_PROPERTIES));
+        if (metaProperties.isPresent()) {
+            this.supportsMetaProperties = metaProperties.get();
+        } else {
+            this.supportsMetaProperties = false;
+            this.neo4jGraphVariables.set(Hidden.hide(CONFIG_META_PROPERTIES), false);
+        }
+        final Optional<Boolean> multiProperties = this.neo4jGraphVariables.get(Hidden.hide(CONFIG_MULTI_PROPERTIES));
+        if (multiProperties.isPresent()) {
+            this.supportsMultiProperties = multiProperties.get();
+        } else {
+            this.supportsMultiProperties = false;
+            this.neo4jGraphVariables.set(Hidden.hide(CONFIG_MULTI_PROPERTIES), false);
+        }
+        if ((this.supportsMetaProperties && !this.supportsMultiProperties) || (!this.supportsMetaProperties && this.supportsMultiProperties)) {
+            tx().rollback();
+            throw new UnsupportedOperationException("Neo4jGraph currently requires either both meta- and multi-properties activated or neither activated");
+        }
+        final Optional<Boolean> elementsInTransaction = this.neo4jGraphVariables.get(Hidden.hide(CONFIG_CHECK_ELEMENTS_IN_TRANSACTION));
+        if (elementsInTransaction.isPresent()) {
+            this.checkElementsInTransaction = elementsInTransaction.get();
+        } else {
+            this.checkElementsInTransaction = false;
+            this.neo4jGraphVariables.set(Hidden.hide(CONFIG_CHECK_ELEMENTS_IN_TRANSACTION), false);
+        }
+        tx().commit();
+        ///////////
+    }
+
+    private Neo4jGraph(final Configuration configuration) {
+        try {
+            this.configuration.copy(EMPTY_CONFIGURATION);
+            this.configuration.copy(configuration);
+            final String directory = this.configuration.getString(CONFIG_DIRECTORY);
+            final Map neo4jSpecificConfig = ConfigurationConverter.getMap(this.configuration.subset(CONFIG_CONF));
+            this.baseGraph = Neo4jFactory.Builder.open(directory, neo4jSpecificConfig);
+            this.neo4jGraphVariables = new Neo4jGraphVariables(this);
+            ///////////
+            if (!this.neo4jGraphVariables.get(Hidden.hide(CONFIG_META_PROPERTIES)).isPresent())
+                this.neo4jGraphVariables.set(Hidden.hide(CONFIG_META_PROPERTIES), this.configuration.getBoolean(CONFIG_META_PROPERTIES, false));
+            // TODO: Logger saying the configuration properties are ignored if already in Graph.Variables
+            if (!this.neo4jGraphVariables.get(Hidden.hide(CONFIG_MULTI_PROPERTIES)).isPresent())
+                this.neo4jGraphVariables.set(Hidden.hide(CONFIG_MULTI_PROPERTIES), this.configuration.getBoolean(CONFIG_MULTI_PROPERTIES, false));
+            // TODO: Logger saying the configuration properties are ignored if already in Graph.Variables
+            this.supportsMetaProperties = this.neo4jGraphVariables.<Boolean>get(Hidden.hide(CONFIG_META_PROPERTIES)).get();
+            this.supportsMultiProperties = this.neo4jGraphVariables.<Boolean>get(Hidden.hide(CONFIG_MULTI_PROPERTIES)).get();
+            if ((this.supportsMetaProperties && !this.supportsMultiProperties) || (!this.supportsMetaProperties && this.supportsMultiProperties)) {
+                tx().rollback();
+                throw new UnsupportedOperationException("Neo4jGraph currently requires either both meta- and multi-properties activated or neither activated");
+            }
+            //
+            // TODO: Logger saying the configuration properties are ignored if already in Graph.Variables
+            if (!this.neo4jGraphVariables.get(Hidden.hide(CONFIG_CHECK_ELEMENTS_IN_TRANSACTION)).isPresent())
+                this.neo4jGraphVariables.set(Hidden.hide(CONFIG_CHECK_ELEMENTS_IN_TRANSACTION), this.configuration.getBoolean(CONFIG_CHECK_ELEMENTS_IN_TRANSACTION, false));
+            this.checkElementsInTransaction = this.neo4jGraphVariables.<Boolean>get(Hidden.hide(CONFIG_CHECK_ELEMENTS_IN_TRANSACTION)).get();
+            tx().commit();
+            ///////////
+        } catch (Exception e) {
+            if (this.baseGraph != null)
+                this.baseGraph.shutdown();
+            throw new RuntimeException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Open a new {@link Neo4jGraph} instance.
+     *
+     * @param configuration the configuration for the instance
+     * @return a newly opened {@link org.apache.tinkerpop.gremlin.structure.Graph}
+     */
+    public static Neo4jGraph open(final Configuration configuration) {
+        if (null == configuration) throw Graph.Exceptions.argumentCanNotBeNull("configuration");
+        if (!configuration.containsKey(CONFIG_DIRECTORY))
+            throw new IllegalArgumentException(String.format("Neo4j configuration requires that the %s be set", CONFIG_DIRECTORY));
+
+        return new Neo4jGraph(configuration);
+    }
+
+    /**
+     * Construct a Neo4jGraph instance by specifying the directory to create the database in..
+     */
+    public static Neo4jGraph open(final String directory) {
+        final Configuration config = new BaseConfiguration();
+        config.setProperty(CONFIG_DIRECTORY, directory);
+        return open(config);
+    }
+
+    /**
+     * Construct a Neo4jGraph instance using an existing Neo4j raw instance.
+     */
+    public static Neo4jGraph open(final Neo4jGraphAPI baseGraph) {
+        return new Neo4jGraph(Optional.ofNullable(baseGraph).orElseThrow(() -> Graph.Exceptions.argumentCanNotBeNull("baseGraph")));
+    }
+
+    @Override
+    public Vertex addVertex(final Object... keyValues) {
+        ElementHelper.legalPropertyKeyValueArray(keyValues);
+        if (ElementHelper.getIdValue(keyValues).isPresent())
+            throw Vertex.Exceptions.userSuppliedIdsNotSupported();
+
+        final String label = ElementHelper.getLabelValue(keyValues).orElse(Vertex.DEFAULT_LABEL);
+
+        this.tx().readWrite();
+        final Neo4jVertex vertex = new Neo4jVertex(this.baseGraph.createNode(label.split(Neo4jVertex.LABEL_DELIMINATOR)), this);
+        ElementHelper.attachProperties(vertex, VertexProperty.Cardinality.list, keyValues);
+        return vertex;
+    }
+
+    @Override
+    public <C extends GraphComputer> C compute(final Class<C> graphComputerClass) {
+        throw Graph.Exceptions.graphComputerNotSupported();
+    }
+
+    @Override
+    public GraphComputer compute() {
+        throw Graph.Exceptions.graphComputerNotSupported();
+    }
+
+    @Override
+    public Transaction tx() {
+        return this.neo4jTransaction;
+    }
+
+    @Override
+    public Variables variables() {
+        return this.neo4jGraphVariables;
+    }
+
+    @Override
+    public Configuration configuration() {
+        return this.configuration;
+    }
+
+    @Override
+    public Iterator<Vertex> vertices(final Object... vertexIds) {
+        this.tx().readWrite();
+        if (0 == vertexIds.length) {
+            return IteratorUtils.stream(this.getBaseGraph().allNodes())
+                    .filter(node -> !this.checkElementsInTransaction || !Neo4jHelper.isDeleted(node))
+                    .filter(node -> !node.hasLabel(Neo4jVertexProperty.VERTEX_PROPERTY_LABEL))
+                    .map(node -> (Vertex) new Neo4jVertex(node, this)).iterator();
+        } else {
+            return Stream.of(vertexIds)
+                    .filter(id -> id instanceof Number)
+                    .flatMap(id -> {
+                        try {
+                            return Stream.of((Vertex) new Neo4jVertex(this.getBaseGraph().getNodeById(((Number) id).longValue()), this));
+                        } catch (final RuntimeException e) {
+                            if (Neo4jHelper.isNotFound(e)) return Stream.empty();
+                            throw e;
+                        }
+                    }).iterator();
+        }
+    }
+
+    @Override
+    public Iterator<Edge> edges(final Object... edgeIds) {
+        this.tx().readWrite();
+        if (0 == edgeIds.length) {
+            return IteratorUtils.stream(this.getBaseGraph().allRelationships())
+                    .filter(relationship -> !this.checkElementsInTransaction || !Neo4jHelper.isDeleted(relationship))
+                    .filter(relationship -> !relationship.type().startsWith(Neo4jVertexProperty.VERTEX_PROPERTY_PREFIX))
+                    .map(relationship -> (Edge) new Neo4jEdge(relationship, this)).iterator();
+        } else {
+            return Stream.of(edgeIds)
+                    .filter(id -> id instanceof Number)
+                    .flatMap(id -> {
+                        try {
+                            return Stream.of((Edge) new Neo4jEdge(this.getBaseGraph().getRelationshipById(((Number) id).longValue()), this));
+                        } catch (final RuntimeException e) {
+                            if (Neo4jHelper.isNotFound(e)) return Stream.empty();
+                            throw e;
+                        }
+                    }).iterator();
+        }
+
+    }
+
+    /**
+     * This implementation of {@code close} will also close the current transaction on the the thread, but it
+     * is up to the caller to deal with dangling transactions in other threads prior to calling this method.
+     */
+    @Override
+    public void close() throws Exception {
+        this.tx().close();
+        if (this.baseGraph != null) this.baseGraph.shutdown();
+    }
+
+    public String toString() {
+        return StringFactory.graphString(this, baseGraph.toString());
+    }
+
+    @Override
+    public Features features() {
+        return features;
+    }
+
+    @Override
+    public Neo4jGraphAPI getBaseGraph() {
+        return this.baseGraph;
+    }
+
+    /**
+     * Neo4j's transactions are not consistent between the graph and the graph
+     * indices. Moreover, global graph operations are not consistent. For
+     * example, if a vertex is removed and then an index is queried in the same
+     * transaction, the removed vertex can be returned. This method allows the
+     * developer to turn on/off a Neo4jGraph 'hack' that ensures transactional
+     * consistency. The default behavior for Neo4jGraph is {@code true}.
+     *
+     * @param checkElementsInTransaction check whether an element is in the transaction between
+     *                                   returning it
+     */
+    public void checkElementsInTransaction(final boolean checkElementsInTransaction) {
+        this.checkElementsInTransaction = checkElementsInTransaction;
+    }
+
+    /**
+     * Execute the Cypher query and get the result set as a {@link GraphTraversal}.
+     *
+     * @param query the Cypher query to execute
+     * @return a fluent Gremlin traversal
+     */
+    public <S, E> GraphTraversal<S, E> cypher(final String query) {
+        return cypher(query, Collections.emptyMap());
+    }
+
+    /**
+     * Execute the Cypher query with provided parameters and get the result set as a {@link GraphTraversal}.
+     *
+     * @param query      the Cypher query to execute
+     * @param parameters the parameters of the Cypher query
+     * @return a fluent Gremlin traversal
+     */
+    public <S, E> GraphTraversal<S, E> cypher(final String query, final Map<String, Object> parameters) {
+        this.tx().readWrite();
+        final GraphTraversal.Admin<S, E> traversal = new DefaultGraphTraversal<>(this);
+        Iterator result = this.baseGraph.execute(query, parameters);
+        traversal.addStep(new StartStep(traversal, new Neo4jCypherIterator<S>(result, this)));
+        return traversal;
+    }
+
+    public Iterator<Map<String, Object>> execute(String query, Map<String, Object> params) {
+        return new Neo4jCypherIterator(baseGraph.execute(query, params), this);
+    }
+
+    class Neo4jTransaction extends AbstractTransaction {
+
+        protected final ThreadLocal<Neo4jTx> threadLocalTx = ThreadLocal.withInitial(() -> null);
+
+        public Neo4jTransaction() {
+            super(Neo4jGraph.this);
+        }
+
+        @Override
+        public void doOpen() {
+            threadLocalTx.set(getBaseGraph().tx());
+        }
+
+        @Override
+        public void doCommit() throws TransactionException {
+            try {
+                threadLocalTx.get().success();
+            } catch (Exception ex) {
+                throw new TransactionException(ex);
+            } finally {
+                threadLocalTx.get().close();
+                threadLocalTx.remove();
+            }
+        }
+
+        @Override
+        public void doRollback() throws TransactionException {
+            try {
+//                javax.transaction.Transaction t = transactionManager.getTransaction();
+//                if (null == t || t.getStatus() == javax.transaction.Status.STATUS_ROLLEDBACK)
+//                    return;
+
+                threadLocalTx.get().failure();
+            } catch (Exception e) {
+                throw new TransactionException(e);
+            } finally {
+                threadLocalTx.get().close();
+                threadLocalTx.remove();
+            }
+        }
+
+        @Override
+        public boolean isOpen() {
+            return (threadLocalTx.get() != null);
+        }
+    }
+
+    public class Neo4jGraphFeatures implements Features {
+        private final GraphFeatures graphFeatures = new Neo4jGraphGraphFeatures();
+        private final VertexFeatures vertexFeatures = new Neo4jVertexFeatures();
+        private final EdgeFeatures edgeFeatures = new Neo4jEdgeFeatures();
+
+        @Override
+        public GraphFeatures graph() {
+            return graphFeatures;
+        }
+
+        @Override
+        public VertexFeatures vertex() {
+            return vertexFeatures;
+        }
+
+        @Override
+        public EdgeFeatures edge() {
+            return edgeFeatures;
+        }
+
+        @Override
+        public String toString() {
+            return StringFactory.featureString(this);
+        }
+
+        public class Neo4jGraphGraphFeatures implements GraphFeatures {
+
+            private VariableFeatures variableFeatures = new Neo4jGraphVariables.Neo4jVariableFeatures();
+
+            Neo4jGraphGraphFeatures() {
+            }
+
+            @Override
+            public boolean supportsComputer() {
+                return false;
+            }
+
+            @Override
+            public VariableFeatures variables() {
+                return variableFeatures;
+            }
+
+            @Override
+            public boolean supportsThreadedTransactions() {
+                return false;
+            }
+        }
+
+        public class Neo4jVertexFeatures extends Neo4jElementFeatures implements VertexFeatures {
+
+            private final VertexPropertyFeatures vertexPropertyFeatures = new Neo4jVertexPropertyFeatures();
+
+            Neo4jVertexFeatures() {
+            }
+
+            @Override
+            public VertexPropertyFeatures properties() {
+                return vertexPropertyFeatures;
+            }
+
+            @Override
+            public boolean supportsMetaProperties() {
+                return Neo4jGraph.this.supportsMetaProperties;
+            }
+
+            @Override
+            public boolean supportsMultiProperties() {
+                return Neo4jGraph.this.supportsMultiProperties;
+            }
+        }
+
+        public class Neo4jEdgeFeatures extends Neo4jElementFeatures implements EdgeFeatures {
+
+            private final EdgePropertyFeatures edgePropertyFeatures = new Neo4jEdgePropertyFeatures();
+
+            Neo4jEdgeFeatures() {
+            }
+
+            @Override
+            public EdgePropertyFeatures properties() {
+                return edgePropertyFeatures;
+            }
+        }
+
+        public class Neo4jElementFeatures implements ElementFeatures {
+
+            Neo4jElementFeatures() {
+            }
+
+            @Override
+            public boolean supportsUserSuppliedIds() {
+                return false;
+            }
+
+            @Override
+            public boolean supportsStringIds() {
+                return false;
+            }
+
+            @Override
+            public boolean supportsUuidIds() {
+                return false;
+            }
+
+            @Override
+            public boolean supportsAnyIds() {
+                return false;
+            }
+
+            @Override
+            public boolean supportsCustomIds() {
+                return false;
+            }
+        }
+
+        public class Neo4jVertexPropertyFeatures implements VertexPropertyFeatures {
+
+            Neo4jVertexPropertyFeatures() {
+            }
+
+            @Override
+            public boolean supportsMapValues() {
+                return false;
+            }
+
+            @Override
+            public boolean supportsMixedListValues() {
+                return false;
+            }
+
+            @Override
+            public boolean supportsSerializableValues() {
+                return false;
+            }
+
+            @Override
+            public boolean supportsUniformListValues() {
+                return false;
+            }
+
+            @Override
+            public boolean supportsUserSuppliedIds() {
+                return false;
+            }
+        }
+
+        public class Neo4jEdgePropertyFeatures implements EdgePropertyFeatures {
+
+            Neo4jEdgePropertyFeatures() {
+            }
+
+            @Override
+            public boolean supportsMapValues() {
+                return false;
+            }
+
+            @Override
+            public boolean supportsMixedListValues() {
+                return false;
+            }
+
+            @Override
+            public boolean supportsSerializableValues() {
+                return false;
+            }
+
+            @Override
+            public boolean supportsUniformListValues() {
+                return false;
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraphVariables.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraphVariables.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraphVariables.java
new file mode 100644
index 0000000..9eef1ed
--- /dev/null
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jGraphVariables.java
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.structure;
+
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.util.GraphVariableHelper;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.neo4j.tinkerpop.api.Neo4jGraphAPI;
+
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public final class Neo4jGraphVariables implements Graph.Variables {
+
+    private final Neo4jGraph graph;
+    private final Neo4jGraphAPI baseGraph;
+
+    protected Neo4jGraphVariables(final Neo4jGraph graph) {
+        this.graph = graph;
+        baseGraph = graph.getBaseGraph();
+    }
+
+    @Override
+    public Set<String> keys() {
+        this.graph.tx().readWrite();
+        final Set<String> keys = new HashSet<>();
+        for (final String key : this.baseGraph.getKeys()) {
+            if (!Graph.Hidden.isHidden(key))
+                keys.add(key);
+        }
+        return keys;
+    }
+
+    @Override
+    public <R> Optional<R> get(final String key) {
+        this.graph.tx().readWrite();
+        return this.baseGraph.hasProperty(key) ?
+                Optional.of((R) this.baseGraph.getProperty(key)) :
+                Optional.<R>empty();
+    }
+
+    @Override
+    public void set(final String key, final Object value) {
+        GraphVariableHelper.validateVariable(key, value);
+        this.graph.tx().readWrite();
+        try {
+            this.baseGraph.setProperty(key, value);
+        } catch (final IllegalArgumentException e) {
+            throw Graph.Variables.Exceptions.dataTypeOfVariableValueNotSupported(value);
+        }
+    }
+
+    @Override
+    public void remove(final String key) {
+        this.graph.tx().readWrite();
+        if (this.baseGraph.hasProperty(key))
+            this.baseGraph.removeProperty(key);
+    }
+
+    @Override
+    public String toString() {
+        return StringFactory.graphVariablesString(this);
+    }
+
+    public static class Neo4jVariableFeatures implements Graph.Features.VariableFeatures {
+        @Override
+        public boolean supportsBooleanValues() {
+            return true;
+        }
+
+        @Override
+        public boolean supportsDoubleValues() {
+            return true;
+        }
+
+        @Override
+        public boolean supportsFloatValues() {
+            return true;
+        }
+
+        @Override
+        public boolean supportsIntegerValues() {
+            return true;
+        }
+
+        @Override
+        public boolean supportsLongValues() {
+            return true;
+        }
+
+        @Override
+        public boolean supportsMapValues() {
+            return false;
+        }
+
+        @Override
+        public boolean supportsMixedListValues() {
+            return false;
+        }
+
+        @Override
+        public boolean supportsByteValues() {
+            return false;
+        }
+
+        @Override
+        public boolean supportsBooleanArrayValues() {
+            return true;
+        }
+
+        @Override
+        public boolean supportsByteArrayValues() {
+            return false;
+        }
+
+        @Override
+        public boolean supportsDoubleArrayValues() {
+            return true;
+        }
+
+        @Override
+        public boolean supportsFloatArrayValues() {
+            return true;
+        }
+
+        @Override
+        public boolean supportsIntegerArrayValues() {
+            return true;
+        }
+
+        @Override
+        public boolean supportsLongArrayValues() {
+            return true;
+        }
+
+        @Override
+        public boolean supportsStringArrayValues() {
+            return true;
+        }
+
+        @Override
+        public boolean supportsSerializableValues() {
+            return false;
+        }
+
+        @Override
+        public boolean supportsStringValues() {
+            return true;
+        }
+
+        @Override
+        public boolean supportsUniformListValues() {
+            return false;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jHelper.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jHelper.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jHelper.java
new file mode 100644
index 0000000..e5de427
--- /dev/null
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jHelper.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.structure;
+
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.neo4j.tinkerpop.api.Neo4jNode;
+import org.neo4j.tinkerpop.api.Neo4jRelationship;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public final class Neo4jHelper {
+
+    private Neo4jHelper() {
+    }
+
+    public static org.neo4j.tinkerpop.api.Neo4jDirection mapDirection(final Direction direction) {
+        if (direction.equals(Direction.OUT))
+            return org.neo4j.tinkerpop.api.Neo4jDirection.OUTGOING;
+        else if (direction.equals(Direction.IN))
+            return org.neo4j.tinkerpop.api.Neo4jDirection.INCOMING;
+        else
+            return org.neo4j.tinkerpop.api.Neo4jDirection.BOTH;
+    }
+
+    public static boolean isDeleted(final Neo4jNode node) {
+        try {
+            node.getKeys();
+            return false;
+        } catch (final IllegalStateException e) {
+            return true;
+        }
+    }
+
+    public static boolean isDeleted(final Neo4jRelationship relationship) {
+        try {
+            relationship.type();
+            return false;
+        } catch (final IllegalStateException e) {
+            return true;
+        }
+    }
+
+    public static boolean isNotFound(RuntimeException ex) {
+        return ex.getClass().getSimpleName().equals("NotFoundException");
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/b2c49ddd/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jProperty.java
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jProperty.java b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jProperty.java
new file mode 100644
index 0000000..69705ab
--- /dev/null
+++ b/neo4j-gremlin/src/main/java/org/apache/tinkerpop/gremlin/neo4j/structure/Neo4jProperty.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.neo4j.structure;
+
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
+import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.neo4j.tinkerpop.api.Neo4jEntity;
+import org.neo4j.tinkerpop.api.Neo4jNode;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class Neo4jProperty<V> implements Property<V> {
+
+    private final Element element;
+    private final String key;
+    private final Neo4jGraph graph;
+    private V value;
+
+    public Neo4jProperty(final Element element, final String key, final V value) {
+        this.element = element;
+        this.key = key;
+        this.value = value;
+        this.graph = element instanceof Neo4jVertexProperty ?
+                ((Neo4jVertex) (((Neo4jVertexProperty) element).element())).graph :
+                ((Neo4jElement) element).graph;
+    }
+
+    @Override
+    public Element element() {
+        return this.element;
+    }
+
+    @Override
+    public String key() {
+        return this.key;
+    }
+
+    @Override
+    public V value() {
+        return this.value;
+    }
+
+    @Override
+    public boolean isPresent() {
+        return null != this.value;
+    }
+
+    @Override
+    public String toString() {
+        return StringFactory.propertyString(this);
+    }
+
+    @Override
+    public boolean equals(final Object object) {
+        return ElementHelper.areEqual(this, object);
+    }
+
+    @Override
+    public int hashCode() {
+        return ElementHelper.hashCode(this);
+    }
+
+    @Override
+    public void remove() {
+        this.graph.tx().readWrite();
+        if (this.element instanceof VertexProperty) {
+            final Neo4jNode node = ((Neo4jVertexProperty) this.element).getBaseVertex();
+            if (null != node && node.hasProperty(this.key)) {
+                node.removeProperty(this.key);
+            }
+        } else {
+            final Neo4jEntity entity = ((Neo4jElement) this.element).getBaseElement();
+            if (entity.hasProperty(this.key)) {
+                entity.removeProperty(this.key);
+            }
+        }
+    }
+
+}
\ No newline at end of file