You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2015/02/12 14:01:38 UTC

[12/77] [partial] incubator-tinkerpop git commit: moved com/tinkerpop directories to org/apache/tinkerpop

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Direction.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Direction.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Direction.java
new file mode 100644
index 0000000..9a95932
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Direction.java
@@ -0,0 +1,51 @@
+/*
+ * 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 com.tinkerpop.gremlin.structure;
+
+/**
+ * {@link Direction} is used to denote the direction of an {@link Edge} or location of a {@link Vertex} on an
+ * {@link Edge}. For example:
+ * <p/>
+ * <pre>
+ * gremlin--knows-->rexster
+ * </pre>
+ * is an {@link Direction#OUT} {@link Edge} for Gremlin and an {@link Direction#IN} edge for Rexster. Moreover, given
+ * that {@link Edge}, Gremlin is the {@link Direction#OUT} {@link Vertex} and Rexster is the {@link Direction#IN}
+ * {@link Vertex}.
+ *
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public enum Direction {
+
+    OUT, IN, BOTH;
+
+    public static final Direction[] proper = new Direction[]{OUT, IN};
+
+    /**
+     * Produce the opposite representation of the current {@code Direction} enum.
+     */
+    public Direction opposite() {
+        if (this.equals(OUT))
+            return IN;
+        else if (this.equals(IN))
+            return OUT;
+        else
+            return BOTH;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Edge.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Edge.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Edge.java
new file mode 100644
index 0000000..6551fb9
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Edge.java
@@ -0,0 +1,96 @@
+/*
+ * 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 com.tinkerpop.gremlin.structure;
+
+import com.tinkerpop.gremlin.process.graph.traversal.EdgeTraversal;
+
+import java.util.Iterator;
+
+/**
+ * An {@link Edge} links two {@link Vertex} objects. Along with its {@link Property} objects, an {@link Edge} has both
+ * a {@link Direction} and a {@code label}. The {@link Direction} determines which {@link Vertex} is the tail
+ * {@link Vertex} (out {@link Vertex}) and which {@link Vertex} is the head {@link Vertex}
+ * (in {@link Vertex}). The {@link Edge} {@code label} determines the type of relationship that exists between the
+ * two vertices.
+ * <p/>
+ * Diagrammatically:
+ * <pre>
+ * outVertex ---label---> inVertex.
+ * </pre>
+ *
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public interface Edge extends Element, EdgeTraversal {
+
+    /**
+     * The default label to use for an edge.
+     * This is typically never used as when an edge is created, an edge label is required to be specified.
+     */
+    public static final String DEFAULT_LABEL = "edge";
+
+    /**
+     * Gets the {@link Edge.Iterators} set.
+     * <p/>
+     * {@inheritDoc}
+     */
+    @Override
+    public Edge.Iterators iterators();
+
+    /**
+     * An interface that provides access to iterators over properties and vertices, without constructing a
+     * {@link com.tinkerpop.gremlin.process.Traversal} object.
+     */
+    public interface Iterators extends Element.Iterators {
+
+        /**
+         * Retrieve the vertex (or vertices) associated with this edge as defined by the direction.
+         * If the direction is {@link Direction#BOTH} then the iterator order is: {@link Direction#OUT} then {@link Direction#IN}.
+         *
+         * @param direction Get the incoming vertex, outgoing vertex, or both vertices
+         * @return An iterator with 1 or 2 vertices
+         */
+        public Iterator<Vertex> vertexIterator(final Direction direction);
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public <V> Iterator<Property<V>> propertyIterator(final String... propertyKeys);
+
+    }
+
+    /**
+     * Common exceptions to use with an edge.
+     */
+    public static class Exceptions extends Element.Exceptions {
+
+        public static UnsupportedOperationException userSuppliedIdsNotSupported() {
+            return new UnsupportedOperationException("Edge does not support user supplied identifiers");
+        }
+
+        public static UnsupportedOperationException userSuppliedIdsOfThisTypeNotSupported() {
+            return new UnsupportedOperationException("Edge does not support user supplied identifiers of this type");
+        }
+
+        public static IllegalStateException edgeRemovalNotSupported() {
+            return new IllegalStateException("Edge removal are not supported");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Element.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Element.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Element.java
new file mode 100644
index 0000000..86f4a1d
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Element.java
@@ -0,0 +1,168 @@
+/*
+ * 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 com.tinkerpop.gremlin.structure;
+
+import com.tinkerpop.gremlin.util.iterator.IteratorUtils;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * An {@link Element} is the base class for both {@link Vertex} and {@link Edge}. An {@link Element} has an identifier
+ * that must be unique to its inheriting classes ({@link Vertex} or {@link Edge}). An {@link Element} can maintain a
+ * collection of {@link Property} objects.  Typically, objects are Java primitives (e.g. String, long, int, boolean,
+ * etc.)
+ *
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public abstract interface Element {
+
+    /**
+     * Gets the unique identifier for the graph {@code Element}.
+     *
+     * @return The id of the element
+     */
+    public Object id();
+
+    /**
+     * Gets the label for the graph {@code Element} which helps categorize it.
+     *
+     * @return The label of the element
+     */
+    public String label();
+
+    /**
+     * Get the graph that this element is within.
+     *
+     * @return the graph of this element
+     */
+    public Graph graph();
+
+    /**
+     * Get the keys of the properties associated with this element.
+     * The default implementation iterators the properties and stores the keys into a {@link HashSet}.
+     *
+     * @return The property key set
+     */
+    public default Set<String> keys() {
+        final Set<String> keys = new HashSet<>();
+        this.iterators().propertyIterator().forEachRemaining(property -> keys.add(property.key()));
+        return Collections.unmodifiableSet(keys);
+    }
+
+    /**
+     * Get a {@link Property} for the {@code Element} given its key.
+     * The default implementation calls the raw {@link Element#iterators#propertyIterator}.
+     */
+    public default <V> Property<V> property(final String key) {
+        final Iterator<? extends Property<V>> iterator = this.iterators().propertyIterator(key);
+        return iterator.hasNext() ? iterator.next() : Property.<V>empty();
+    }
+
+    /**
+     * Add or set a property value for the {@code Element} given its key.
+     */
+    public <V> Property<V> property(final String key, final V value);
+
+    /**
+     * Get the value of a {@link Property} given it's key.
+     * The default implementation calls {@link Element#property} and then returns the associated value.
+     *
+     * @throws NoSuchElementException if the property does not exist on the {@code Element}.
+     */
+    @Graph.Helper
+    public default <V> V value(final String key) throws NoSuchElementException {
+        final Property<V> property = this.property(key);
+        return property.orElseThrow(() -> Property.Exceptions.propertyDoesNotExist(key));
+    }
+
+    /**
+     * Removes the {@code Element} from the graph.
+     */
+    public void remove();
+
+    /**
+     * Gets the iterators for the {@code Element}.  Iterators provide low-level access to the data associated with
+     * an {@code Element} as they do not come with the overhead of {@link com.tinkerpop.gremlin.process.Traversal}
+     * construction.  Use iterators in places where performance is most crucial.
+     */
+    public Element.Iterators iterators();
+
+    /**
+     * An interface that provides access to iterators over properties of an {@code Element}, without constructing a
+     * {@link com.tinkerpop.gremlin.process.Traversal} object.
+     */
+    public interface Iterators {
+
+        /**
+         * Get the values of properties as an {@link Iterator}.
+         */
+        @Graph.Helper
+        public default <V> Iterator<V> valueIterator(final String... propertyKeys) {
+            return IteratorUtils.map(this.<V>propertyIterator(propertyKeys), property -> property.value());
+        }
+
+        /**
+         * Get an {@link Iterator} of properties.
+         */
+        public <V> Iterator<? extends Property<V>> propertyIterator(final String... propertyKeys);
+    }
+
+    /**
+     * Common exceptions to use with an element.
+     */
+    public static class Exceptions {
+
+        public static IllegalArgumentException providedKeyValuesMustBeAMultipleOfTwo() {
+            return new IllegalArgumentException("The provided key/value array must be a multiple of two");
+        }
+
+        public static IllegalArgumentException providedKeyValuesMustHaveALegalKeyOnEvenIndices() {
+            return new IllegalArgumentException("The provided key/value array must have a String or T on even array indices");
+        }
+
+        public static IllegalStateException propertyAdditionNotSupported() {
+            return new IllegalStateException("Property addition is not supported");
+        }
+
+        public static IllegalStateException propertyRemovalNotSupported() {
+            return new IllegalStateException("Property removal is not supported");
+        }
+
+        public static IllegalArgumentException labelCanNotBeNull() {
+            return new IllegalArgumentException("Label can not be null");
+        }
+
+        public static IllegalArgumentException labelCanNotBeEmpty() {
+            return new IllegalArgumentException("Label can not be empty");
+        }
+
+        public static IllegalArgumentException labelCanNotBeAHiddenKey(final String label) {
+            return new IllegalArgumentException("Label can not be a hidden key: " + label);
+        }
+
+        public static IllegalStateException elementAlreadyRemoved(final Class<? extends Element> clazz, final Object id) {
+            return new IllegalStateException(String.format("%s with id %s was removed.", clazz.getSimpleName(), id));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
new file mode 100644
index 0000000..c663af2
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
@@ -0,0 +1,1193 @@
+/*
+ * 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 com.tinkerpop.gremlin.structure;
+
+import com.tinkerpop.gremlin.process.T;
+import com.tinkerpop.gremlin.process.Traversal;
+import com.tinkerpop.gremlin.process.computer.GraphComputer;
+import com.tinkerpop.gremlin.process.graph.traversal.GraphTraversal;
+import com.tinkerpop.gremlin.process.graph.traversal.step.sideEffect.GraphStep;
+import com.tinkerpop.gremlin.process.graph.traversal.DefaultGraphTraversal;
+import com.tinkerpop.gremlin.structure.io.DefaultIo;
+import com.tinkerpop.gremlin.structure.io.graphml.GraphMLReader;
+import com.tinkerpop.gremlin.structure.io.graphml.GraphMLWriter;
+import com.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
+import com.tinkerpop.gremlin.structure.io.graphson.GraphSONReader;
+import com.tinkerpop.gremlin.structure.io.graphson.GraphSONWriter;
+import com.tinkerpop.gremlin.structure.io.kryo.KryoMapper;
+import com.tinkerpop.gremlin.structure.io.kryo.KryoReader;
+import com.tinkerpop.gremlin.structure.io.kryo.KryoWriter;
+import com.tinkerpop.gremlin.structure.strategy.GraphStrategy;
+import com.tinkerpop.gremlin.structure.strategy.SequenceStrategy;
+import com.tinkerpop.gremlin.structure.strategy.StrategyGraph;
+import com.tinkerpop.gremlin.structure.util.FeatureDescriptor;
+import org.apache.commons.configuration.Configuration;
+import org.javatuples.Pair;
+
+import java.io.IOException;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * A {@link Graph} is a container object for a collection of {@link Vertex}, {@link Edge}, {@link VertexProperty},
+ * and {@link Property} objects.
+ *
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public interface Graph extends AutoCloseable {
+
+    public static final String GRAPH = "gremlin.graph";
+
+    /**
+     * This should only be used by vendors to create keys, labels, etc. in a namespace safe from users.
+     * Users are not allowed to generate property keys, step labels, etc. that are key'd "hidden".
+     */
+    public static class Hidden {
+
+        /**
+         * The prefix to denote that a key is a hidden key.
+         */
+        private static final String HIDDEN_PREFIX = "~";
+        private static final int HIDDEN_PREFIX_LENGTH = HIDDEN_PREFIX.length();
+
+        /**
+         * Turn the provided key into a hidden key. If the key is already a hidden key, return key.
+         *
+         * @param key The key to make a hidden key
+         * @return The hidden key
+         */
+        public static String hide(final String key) {
+            return isHidden(key) ? key : HIDDEN_PREFIX.concat(key);
+        }
+
+        /**
+         * Turn the provided hidden key into an non-hidden key. If the key is not a hidden key, return key.
+         *
+         * @param key The hidden key
+         * @return The non-hidden representation of the key
+         */
+        public static String unHide(final String key) {
+            return isHidden(key) ? key.substring(HIDDEN_PREFIX_LENGTH) : key;
+        }
+
+        /**
+         * Determines whether the provided key is a hidden key or not.
+         *
+         * @param key The key to check for hidden status
+         * @return Whether the provided key is a hidden key or not
+         */
+        public static boolean isHidden(final String key) {
+            return key.startsWith(HIDDEN_PREFIX);
+        }
+    }
+
+    /**
+     * Add a {@link Vertex} to the graph given an optional series of key/value pairs.  These key/values
+     * must be provided in an even number where the odd numbered arguments are {@link String} property keys and the
+     * even numbered arguments are the related property values.
+     *
+     * @param keyValues The key/value pairs to turn into vertex properties
+     * @return The newly created vertex
+     */
+    public Vertex addVertex(final Object... keyValues);
+
+    /**
+     * Add a {@link Vertex} to the graph with provided vertex label.
+     *
+     * @param label the label of the vertex
+     * @return The newly created labeled vertex
+     */
+    @Graph.Helper
+    public default Vertex addVertex(final String label) {
+        return this.addVertex(T.label, label);
+    }
+
+    /**
+     * Starts a {@link GraphTraversal} over the vertices in the graph.
+     * If vertexIds are provided, then the traversal starts at those vertices, else all vertices in the graph.
+     *
+     * @param vertexIds the ids of the vertices to get (if none are provided, get all vertices)
+     * @return a graph traversal over the vertices of the graph
+     */
+    public default GraphTraversal<Vertex, Vertex> V(final Object... vertexIds) {
+        final GraphTraversal.Admin<Vertex, Vertex> traversal = new DefaultGraphTraversal<>(this.getClass());
+        return traversal.addStep(new GraphStep<>(traversal, this, Vertex.class, vertexIds));
+    }
+
+    /**
+     * Starts a {@link GraphTraversal} over the edges in the graph.
+     * If edgeIds are provided, then the traversal starts at those edges, else all edges in the graph.
+     *
+     * @param edgeIds the ids of the edges to get (if none are provided, get all edges)
+     * @return a graph traversal over the edges of the graph
+     */
+    public default GraphTraversal<Edge, Edge> E(final Object... edgeIds) {
+        final GraphTraversal.Admin<Edge, Edge> traversal = new DefaultGraphTraversal<>(this.getClass());
+        return traversal.addStep(new GraphStep<>(traversal, this, Edge.class, edgeIds));
+    }
+
+    /**
+     * Constructs a new domain specific {@link Traversal} for this graph.
+     *
+     * @param traversalClass the domain specific {@link Traversal} bound to this graph
+     */
+    public default <T extends Traversal<S, S>, S> T of(final Class<T> traversalClass) {
+        try {
+            return (T) traversalClass.getMethod(Traversal.OF, Graph.class).invoke(null, this);
+        } catch (final Exception e) {
+            throw new IllegalStateException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Create an OLAP {@link GraphComputer} to execute a vertex program over this graph.
+     * If the graph does not support graph computer then an {@link java.lang.UnsupportedOperationException} is thrown.
+     * The provided arguments can be of either length 0 or 1. A graph can support multiple graph computers.
+     *
+     * @param graphComputerClass The graph computer class to use (if no argument, then a default is selected by the graph)
+     * @return A graph computer for processing this graph
+     */
+    public GraphComputer compute(final Class... graphComputerClass);
+
+    /**
+     * Configure and control the transactions for those graphs that support this feature.
+     */
+    public Transaction tx();
+
+    /**
+     * Provide input/output methods for serializing graph data.
+     */
+    public default Io io() {
+        return new DefaultIo(this);
+    }
+
+    /**
+     * Constructs a {@link StrategyGraph} from one or more {@link GraphStrategy} objects.  If more than one
+     * {@link GraphStrategy} is supplied they are folded into a single {@link SequenceStrategy}.
+     */
+    @Graph.Helper
+    public default StrategyGraph strategy(final GraphStrategy... strategies) {
+        if (strategies.length == 0)
+            throw new IllegalArgumentException("Provide at least one GraphStrategy implementation.");
+        final GraphStrategy graphStrategy = strategies.length == 1 ? strategies[0] : SequenceStrategy.build().sequence(strategies).create();
+        return new StrategyGraph(this, graphStrategy);
+    }
+
+    /**
+     * A collection of global {@link Variables} associated with the graph.
+     * Variables are used for storing metadata about the graph.
+     *
+     * @return The variables associated with this graph
+     */
+    public Variables variables();
+
+    /**
+     * Get the {@link org.apache.commons.configuration.Configuration} associated with the construction of this graph.
+     * Whatever configuration was passed to {@link com.tinkerpop.gremlin.structure.util.GraphFactory#open(org.apache.commons.configuration.Configuration)}
+     * is what should be returned by this method.
+     *
+     * @return the configuration used during graph construction.
+     */
+    public Configuration configuration();
+
+    /**
+     * Get the {@link Graph.Iterators} associated with this graph.
+     *
+     * @return the graph iterators of this graph
+     */
+    public Iterators iterators();
+
+    /**
+     * An interface that provides access to iterators over {@link Vertex} objects and {@link Edge} objects of the graph
+     * without constructing a {@link com.tinkerpop.gremlin.process.Traversal} object.
+     */
+    public interface Iterators {
+        /**
+         * Get the {@link Vertex} objects in this graph with the provided vertex ids. If no ids are provided, get all vertices.
+         *
+         * @param vertexIds the ids of the vertices to get
+         * @return an {@link Iterator} of vertices that match the provided vertex ids
+         */
+        public Iterator<Vertex> vertexIterator(final Object... vertexIds);
+
+        /**
+         * Get the {@link Edge} objects in this graph with the provided edge ids. If no ids are provided, get all edges.
+         *
+         * @param edgeIds the ids of the edges to get
+         * @return an {@link Iterator} of edges that match the provided edge ids
+         */
+        public Iterator<Edge> edgeIterator(final Object... edgeIds);
+    }
+
+    /**
+     * Provides access to functions related to reading and writing graph data.  Implementers can override these
+     * methods to provider mapper configurations to the default {@link com.tinkerpop.gremlin.structure.io.GraphReader}
+     * and {@link com.tinkerpop.gremlin.structure.io.GraphWriter} implementations (i.e. to register mapper
+     * serialization classes).
+     */
+    public interface Io {
+        /**
+         * Creates a {@link com.tinkerpop.gremlin.structure.io.GraphReader} builder for Kryo serializations. This
+         * method calls the {@link Io#kryoMapper} method to supply to
+         * {@link com.tinkerpop.gremlin.structure.io.kryo.KryoReader.Builder#mapper} which means that implementers
+         * should usually just override {@link Io#kryoMapper} to append in their mapper classes.
+         */
+        public default KryoReader.Builder kryoReader() {
+            return KryoReader.build().mapper(kryoMapper().create());
+        }
+
+        /**
+         * Creates a {@link com.tinkerpop.gremlin.structure.io.GraphWriter} builder for Kryo serializations. This
+         * method calls the {@link Io#kryoMapper} method to supply to
+         * {@link com.tinkerpop.gremlin.structure.io.kryo.KryoWriter.Builder#mapper} which means that implementers
+         * should usually just override {@link Io#kryoMapper} to append in their mapper classes.
+         */
+        public default KryoWriter.Builder kryoWriter() {
+            return KryoWriter.build().mapper(kryoMapper().create());
+        }
+
+        /**
+         * Write a kryo file using the default configuration of the {@link KryoWriter}.
+         */
+        public void writeKryo(final String file) throws IOException;
+
+        /**
+         * Read a kryo file using the default configuration of the {@link KryoReader}.
+         */
+        public void readKryo(final String file) throws IOException;
+
+        /**
+         * By default, this method creates an instance of the most current version of {@link com.tinkerpop.gremlin.structure.io.kryo.KryoMapper} which is
+         * used to serialize data to and from the graph.   Implementers with mapper classes (e.g. a non-primitive
+         * class returned from {@link Element#id}) should override this method with those classes automatically
+         * registered to the returned {@link com.tinkerpop.gremlin.structure.io.kryo.KryoMapper}.
+         * <br/>
+         * Implementers should respect versions.  Once a class is registered, the order of its registration should be
+         * maintained. Note that registering such classes will reduce the portability of the graph data as data
+         * written with {@link com.tinkerpop.gremlin.structure.io.kryo.KryoMapper} will not be readable without this serializer configuration.  It is
+         * considered good practice to make serialization classes generally available so that users may
+         * register these classes themselves if necessary when building up a mapper {@link com.tinkerpop.gremlin.structure.io.kryo.KryoMapper}
+         * instance.
+         * <br/>
+         * Note that this method is meant to return current versions for serialization operations.  Users wishing
+         * to use an "older" version should construct this instance as well as their readers and writers manually.
+         */
+        public default KryoMapper.Builder kryoMapper() {
+            return KryoMapper.build();
+        }
+
+        /**
+         * Creates a {@link com.tinkerpop.gremlin.structure.io.GraphReader} builder for GraphML serializations. GraphML
+         * is the most portable of all the formats, but comes at the price of the least flexibility.
+         * {@code Graph} implementations that have mapper classes that need to be serialized will not be able
+         * to properly use this format effectively.
+         */
+        public default GraphMLReader.Builder graphMLReader() {
+            return GraphMLReader.build();
+        }
+
+        /**
+         * Creates a {@link com.tinkerpop.gremlin.structure.io.GraphWriter} builder for GraphML serializations. GraphML
+         * is the most portable of all the formats, but comes at the price of the least flexibility.
+         * {@code Graph} implementations that have mapper classes that need to be serialized will not be able
+         * to properly use this format effectively.
+         */
+        public default GraphMLWriter.Builder graphMLWriter() {
+            return GraphMLWriter.build();
+        }
+
+        /**
+         * Write a GraphML file using the default configuration of the {@link GraphMLWriter}.
+         */
+        public void writeGraphML(final String file) throws IOException;
+
+        /**
+         * Read a GraphML file using the default configuration of the {@link GraphMLReader}.
+         */
+        public void readGraphML(final String file) throws IOException;
+
+        /**
+         * Creates a {@link com.tinkerpop.gremlin.structure.io.GraphReader} builder for GraphSON serializations.
+         * GraphSON is forgiving for implementers and will typically do a "reasonable" job in serializing most
+         * mapper classes.  This method by default uses the {@link com.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper} created by
+         * {@link #graphSONMapper}.  That method enables implementers to register mapper serialization
+         * modules for classes that do not serialize nicely by the default JSON serializers or completely
+         * fail to do so.
+         */
+        public default GraphSONReader.Builder graphSONReader() {
+            return GraphSONReader.build().mapper(graphSONMapper().create());
+        }
+
+        /**
+         * Creates a {@link com.tinkerpop.gremlin.structure.io.GraphWriter} builder for GraphML serializations.
+         * GraphSON is forgiving for implementers and will typically do a "reasonable" job in serializing most
+         * mapper classes.  This method by default uses the {@link com.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper} created by
+         * {@link #graphSONMapper}. That method enables implementers to register mapper serialization
+         * modules for classes that do not serialize nicely by the default JSON serializers or completely
+         * fail to do so.
+         */
+        public default GraphSONWriter.Builder graphSONWriter() {
+            return GraphSONWriter.build().mapper(graphSONMapper().create());
+        }
+
+        /**
+         * Write a GraphSON file using the default configuration of the {@link GraphSONWriter}.
+         */
+        public void writeGraphSON(final String file) throws IOException;
+
+        /**
+         * Read a GraphSON file using the default configuration of the {@link GraphSONReader}.
+         */
+        public void readGraphSON(final String file) throws IOException;
+
+        /**
+         * By default, this method creates an instance of the most current version of
+         * {@link com.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper.Builder} which is can produce a
+         * {@link com.tinkerpop.gremlin.structure.io.Mapper} implementation for GraphSON to
+         * serialize data to and from the graph.   Implementers with custom classes (e.g. a
+         * non-primitive class returned from {@link Element#id}) should override this method with serialization
+         * modules added.
+         * <br/>
+         * It is considered good practice to make serialization classes generally available so that users may
+         * register these classes themselves if necessary when building up a mapper {@link com.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper}
+         * instance.
+         * <br/>
+         * Note that this method is meant to return a {@link com.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper.Builder} with default configuration
+         * for the current {@link Graph}.  Users can adjust and override such settings by altering the builder
+         * settings.
+         */
+        public default GraphSONMapper.Builder graphSONMapper() {
+            return GraphSONMapper.build();
+        }
+    }
+
+    /**
+     * Graph variables are a set of key/value pairs associated with the graph.The keys are String and the values
+     * are Objects.
+     */
+    public interface Variables {
+
+        /**
+         * Keys set for the available variables.
+         */
+        public Set<String> keys();
+
+        /**
+         * Gets a variable.
+         */
+        public <R> Optional<R> get(final String key);
+
+        /**
+         * Sets a variable.
+         */
+        public void set(final String key, Object value);
+
+        /**
+         * Removes a variable.
+         */
+        public void remove(final String key);
+
+        /**
+         * Gets the variables of the {@link Graph} as a {@code Map}.
+         */
+        @Graph.Helper
+        public default Map<String, Object> asMap() {
+            final Map<String, Object> map = keys().stream()
+                    .map(key -> Pair.with(key, get(key).get()))
+                    .collect(Collectors.toMap(Pair::getValue0, Pair::getValue1));
+            return Collections.unmodifiableMap(map);
+        }
+
+        public static class Exceptions {
+
+            public static IllegalArgumentException variableKeyCanNotBeEmpty() {
+                return new IllegalArgumentException("Graph variable key can not be the empty string");
+            }
+
+            public static IllegalArgumentException variableKeyCanNotBeNull() {
+                return new IllegalArgumentException("Graph variable key can not be null");
+            }
+
+            public static IllegalArgumentException variableValueCanNotBeNull() {
+                return new IllegalArgumentException("Graph variable value can not be null");
+            }
+
+            public static UnsupportedOperationException dataTypeOfVariableValueNotSupported(final Object val) {
+                return new UnsupportedOperationException(String.format("Graph variable value [%s] is of type %s is not supported", val, val.getClass()));
+            }
+        }
+
+    }
+
+    /**
+     * Gets the {@link Features} exposed by the underlying {@code Graph} implementation.
+     */
+    public default Features features() {
+        return new Features() {
+        };
+    }
+
+    /**
+     * An interface that represents the capabilities of a {@code Graph} implementation.  By default all methods
+     * of features return {@code true} and it is up to implementers to disable feature they don't support.  Users
+     * should check features prior to using various functions of TinkerPop to help ensure code portability
+     * across implementations.  For example, a common usage would be to check if a graph supports transactions prior
+     * to calling the commit method on {@link #tx()}.
+     */
+    public interface Features {
+
+        /**
+         * Gets the features related to "graph" operation.
+         */
+        public default GraphFeatures graph() {
+            return new GraphFeatures() {
+            };
+        }
+
+        /**
+         * Gets the features related to "vertex" operation.
+         */
+        public default VertexFeatures vertex() {
+            return new VertexFeatures() {
+            };
+        }
+
+        /**
+         * Gets the features related to "edge" operation.
+         */
+        public default EdgeFeatures edge() {
+            return new EdgeFeatures() {
+            };
+        }
+
+        /**
+         * Features specific to a operations of a "graph".
+         */
+        public interface GraphFeatures extends FeatureSet {
+            public static final String FEATURE_COMPUTER = "Computer";
+            public static final String FEATURE_TRANSACTIONS = "Transactions";
+            public static final String FEATURE_PERSISTENCE = "Persistence";
+            public static final String FEATURE_THREADED_TRANSACTIONS = "ThreadedTransactions";
+
+            /**
+             * Determines if the {@code Graph} implementation supports
+             * {@link com.tinkerpop.gremlin.process.computer.GraphComputer} based processing.
+             */
+            @FeatureDescriptor(name = FEATURE_COMPUTER)
+            public default boolean supportsComputer() {
+                return true;
+            }
+
+            /**
+             * Determines if the {@code Graph} implementation supports persisting it's contents natively to disk.
+             * This feature does not refer to every graph's ability to write to disk via the Gremlin IO packages
+             * (.e.g. GraphML), unless the graph natively persists to disk via those options somehow.  For example,
+             * TinkerGraph does not support this feature as it is a pure in-sideEffects graph.
+             */
+            @FeatureDescriptor(name = FEATURE_PERSISTENCE)
+            public default boolean supportsPersistence() {
+                return true;
+            }
+
+            /**
+             * Determines if the {@code Graph} implementations supports transactions.
+             */
+            @FeatureDescriptor(name = FEATURE_TRANSACTIONS)
+            public default boolean supportsTransactions() {
+                return true;
+            }
+
+            /**
+             * Determines if the {@code Graph} implementation supports threaded transactions which allow a transaction
+             * to be executed across multiple threads via {@link com.tinkerpop.gremlin.structure.Transaction#create()}.
+             */
+            @FeatureDescriptor(name = FEATURE_THREADED_TRANSACTIONS)
+            public default boolean supportsThreadedTransactions() {
+                return true;
+            }
+
+            /**
+             * Gets the features related to "graph sideEffects" operation.
+             */
+            public default VariableFeatures variables() {
+                return new VariableFeatures() {
+                };
+            }
+        }
+
+        /**
+         * Features that are related to {@link Vertex} operations.
+         */
+        public interface VertexFeatures extends ElementFeatures {
+            public static final String FEATURE_ADD_VERTICES = "AddVertices";
+            public static final String FEATURE_MULTI_PROPERTIES = "MultiProperties";
+            public static final String FEATURE_META_PROPERTIES = "MetaProperties";
+            public static final String FEATURE_REMOVE_VERTICES = "RemoveVertices";
+
+            /**
+             * Determines if a {@link Vertex} can be added to the {@code Graph}.
+             */
+            @FeatureDescriptor(name = FEATURE_ADD_VERTICES)
+            public default boolean supportsAddVertices() {
+                return true;
+            }
+
+            /**
+             * Determines if a {@link Vertex} can be removed from the {@code Graph}.
+             */
+            @FeatureDescriptor(name = FEATURE_REMOVE_VERTICES)
+            public default boolean supportsRemoveVertices() {
+                return true;
+            }
+
+            /**
+             * Determines if a {@link Vertex} can support multiple properties with the same key.
+             */
+            @FeatureDescriptor(name = FEATURE_MULTI_PROPERTIES)
+            public default boolean supportsMultiProperties() {
+                return true;
+            }
+
+            /**
+             * Determines if a {@link Vertex} can support properties on vertex properties.  It is assumed that a
+             * graph will support all the same data types for meta-properties that are supported for regular
+             * properties.
+             */
+            @FeatureDescriptor(name = FEATURE_META_PROPERTIES)
+            public default boolean supportsMetaProperties() {
+                return true;
+            }
+
+            /**
+             * Gets features related to "properties" on a {@link Vertex}.
+             */
+            public default VertexPropertyFeatures properties() {
+                return new VertexPropertyFeatures() {
+                };
+            }
+        }
+
+        /**
+         * Features that are related to {@link Edge} operations.
+         */
+        public interface EdgeFeatures extends ElementFeatures {
+            public static final String FEATURE_ADD_EDGES = "AddEdges";
+            public static final String FEATURE_REMOVE_EDGES = "RemoveEdges";
+
+            /**
+             * Determines if an {@link Edge} can be added to a {@code Vertex}.
+             */
+            @FeatureDescriptor(name = FEATURE_ADD_EDGES)
+            public default boolean supportsAddEdges() {
+                return true;
+            }
+
+            /**
+             * Determines if an {@link Edge} can be removed from a {@code Vertex}.
+             */
+            @FeatureDescriptor(name = FEATURE_REMOVE_EDGES)
+            public default boolean supportsRemoveEdges() {
+                return true;
+            }
+
+            /**
+             * Gets features related to "properties" on an {@link Edge}.
+             */
+            public default EdgePropertyFeatures properties() {
+                return new EdgePropertyFeatures() {
+                };
+            }
+        }
+
+        /**
+         * Features that are related to {@link Element} objects.  This is a base interface.
+         */
+        public interface ElementFeatures extends FeatureSet {
+            public static final String FEATURE_USER_SUPPLIED_IDS = "UserSuppliedIds";
+            public static final String FEATURE_NUMERIC_IDS = "NumericIds";
+            public static final String FEATURE_STRING_IDS = "StringIds";
+            public static final String FEATURE_UUID_IDS = "UuidIds";
+            public static final String FEATURE_CUSTOM_IDS = "CustomIds";
+            public static final String FEATURE_ANY_IDS = "AnyIds";
+            public static final String FEATURE_ADD_PROPERTY = "AddProperty";
+            public static final String FEATURE_REMOVE_PROPERTY = "RemoveProperty";
+
+            /**
+             * Determines if an {@link Element} allows properties to be added.  This feature is set independently from
+             * supporting "data types" and refers to support of calls to {@link Element#property(String, Object)}.
+             */
+            @FeatureDescriptor(name = FEATURE_ADD_PROPERTY)
+            public default boolean supportsAddProperty() {
+                return true;
+            }
+
+            /**
+             * Determines if an {@link Element} allows properties to be removed.
+             */
+            @FeatureDescriptor(name = FEATURE_REMOVE_PROPERTY)
+            public default boolean supportsRemoveProperty() {
+                return true;
+            }
+
+            /**
+             * Determines if an {@link Element} can have a user defined identifier.  Implementation that do not support
+             * this feature will be expected to auto-generate unique identifiers.
+             */
+            @FeatureDescriptor(name = FEATURE_USER_SUPPLIED_IDS)
+            public default boolean supportsUserSuppliedIds() {
+                return true;
+            }
+
+            /**
+             * Determines if an {@link Element} has numeric identifiers.
+             */
+            @FeatureDescriptor(name = FEATURE_NUMERIC_IDS)
+            public default boolean supportsNumericIds() {
+                return true;
+            }
+
+            /**
+             * Determines if an {@link Element} has string identifiers.
+             */
+            @FeatureDescriptor(name = FEATURE_STRING_IDS)
+            public default boolean supportsStringIds() {
+                return true;
+            }
+
+            /**
+             * Determines if an {@link Element} has UUID identifiers.
+             */
+            @FeatureDescriptor(name = FEATURE_UUID_IDS)
+            public default boolean supportsUuidIds() {
+                return true;
+            }
+
+            /**
+             * Determines if an {@link Element} has mapper identifiers where "mapper" refers to an implementation
+             * defined object.
+             */
+            @FeatureDescriptor(name = FEATURE_CUSTOM_IDS)
+            public default boolean supportsCustomIds() {
+                return true;
+            }
+
+            /**
+             * Determines if an {@link Element} any Java object is a suitable identifier.
+             */
+            @FeatureDescriptor(name = FEATURE_ANY_IDS)
+            public default boolean supportsAnyIds() {
+                return true;
+            }
+        }
+
+        /**
+         * Features that are related to {@link Vertex} {@link Property} objects.
+         */
+        public interface VertexPropertyFeatures extends PropertyFeatures {
+            public static final String FEATURE_ADD_PROPERTY = "AddProperty";
+            public static final String FEATURE_REMOVE_PROPERTY = "RemoveProperty";
+            public static final String FEATURE_USER_SUPPLIED_IDS = "UserSuppliedIds";
+            public static final String FEATURE_NUMERIC_IDS = "NumericIds";
+            public static final String FEATURE_STRING_IDS = "StringIds";
+            public static final String FEATURE_UUID_IDS = "UuidIds";
+            public static final String FEATURE_CUSTOM_IDS = "CustomIds";
+            public static final String FEATURE_ANY_IDS = "AnyIds";
+
+            /**
+             * Determines if a {@link VertexProperty} allows properties to be added.
+             */
+            @FeatureDescriptor(name = FEATURE_ADD_PROPERTY)
+            public default boolean supportsAddProperty() {
+                return true;
+            }
+
+            /**
+             * Determines if a {@link VertexProperty} allows properties to be removed.
+             */
+            @FeatureDescriptor(name = FEATURE_REMOVE_PROPERTY)
+            public default boolean supportsRemoveProperty() {
+                return true;
+            }
+
+            /**
+             * Determines if a {@link VertexProperty} allows an identifier to be assigned to it.
+             */
+            @FeatureDescriptor(name = FEATURE_USER_SUPPLIED_IDS)
+            public default boolean supportsUserSuppliedIds() {
+                return true;
+            }
+
+            /**
+             * Determines if an {@link VertexProperty} has numeric identifiers.
+             */
+            @FeatureDescriptor(name = FEATURE_NUMERIC_IDS)
+            public default boolean supportsNumericIds() {
+                return true;
+            }
+
+            /**
+             * Determines if an {@link VertexProperty} has string identifiers.
+             */
+            @FeatureDescriptor(name = FEATURE_STRING_IDS)
+            public default boolean supportsStringIds() {
+                return true;
+            }
+
+            /**
+             * Determines if an {@link VertexProperty} has UUID identifiers.
+             */
+            @FeatureDescriptor(name = FEATURE_UUID_IDS)
+            public default boolean supportsUuidIds() {
+                return true;
+            }
+
+            /**
+             * Determines if an {@link VertexProperty} has mapper identifiers where "mapper" refers to an implementation
+             * defined object.
+             */
+            @FeatureDescriptor(name = FEATURE_CUSTOM_IDS)
+            public default boolean supportsCustomIds() {
+                return true;
+            }
+
+            /**
+             * Determines if an {@link VertexProperty} any Java object is a suitable identifier.
+             */
+            @FeatureDescriptor(name = FEATURE_ANY_IDS)
+            public default boolean supportsAnyIds() {
+                return true;
+            }
+        }
+
+        /**
+         * Features that are related to {@link Edge} {@link Property} objects.
+         */
+        public interface EdgePropertyFeatures extends PropertyFeatures {
+        }
+
+        /**
+         * A base interface for {@link Edge} or {@link Vertex} {@link Property} features.
+         */
+        public interface PropertyFeatures extends DataTypeFeatures {
+            public static final String FEATURE_PROPERTIES = "Properties";
+
+            /**
+             * Determines if an {@link Element} allows for the processing of at least one data type defined by the
+             * features.  In this case "processing" refers to at least "reading" the data type. If any of the
+             * features on {@link PropertyFeatures} is true then this value must be true.
+             */
+            @FeatureDescriptor(name = FEATURE_PROPERTIES)
+            public default boolean supportsProperties() {
+                return supportsBooleanValues() || supportsByteValues() || supportsDoubleValues() || supportsFloatValues()
+                        || supportsIntegerValues() || supportsLongValues() || supportsMapValues()
+                        || supportsMixedListValues() || supportsSerializableValues()
+                        || supportsStringValues() || supportsUniformListValues() || supportsBooleanArrayValues()
+                        || supportsByteArrayValues() || supportsDoubleArrayValues() || supportsFloatArrayValues()
+                        || supportsIntegerArrayValues() || supportsLongArrayValues() || supportsStringArrayValues();
+            }
+        }
+
+        /**
+         * Features for {@link com.tinkerpop.gremlin.structure.Graph.Variables}.
+         */
+        public interface VariableFeatures extends DataTypeFeatures {
+            public static final String FEATURE_VARIABLES = "Variables";
+
+            /**
+             * If any of the features on {@link com.tinkerpop.gremlin.structure.Graph.Features.VariableFeatures} is
+             * true then this value must be true.
+             */
+            @FeatureDescriptor(name = FEATURE_VARIABLES)
+            public default boolean supportsVariables() {
+                return supportsBooleanValues() || supportsByteValues() || supportsDoubleValues() || supportsFloatValues()
+                        || supportsIntegerValues() || supportsLongValues() || supportsMapValues()
+                        || supportsMixedListValues() || supportsSerializableValues()
+                        || supportsStringValues() || supportsUniformListValues() || supportsBooleanArrayValues()
+                        || supportsByteArrayValues() || supportsDoubleArrayValues() || supportsFloatArrayValues()
+                        || supportsIntegerArrayValues() || supportsLongArrayValues() || supportsStringArrayValues();
+            }
+        }
+
+        /**
+         * Base interface for features that relate to supporting different data types.
+         */
+        public interface DataTypeFeatures extends FeatureSet {
+            public static final String FEATURE_BOOLEAN_VALUES = "BooleanValues";
+            public static final String FEATURE_BYTE_VALUES = "ByteValues";
+            public static final String FEATURE_DOUBLE_VALUES = "DoubleValues";
+            public static final String FEATURE_FLOAT_VALUES = "FloatValues";
+            public static final String FEATURE_INTEGER_VALUES = "IntegerValues";
+            public static final String FEATURE_LONG_VALUES = "LongValues";
+            public static final String FEATURE_MAP_VALUES = "MapValues";
+            public static final String FEATURE_MIXED_LIST_VALUES = "MixedListValues";
+            public static final String FEATURE_BOOLEAN_ARRAY_VALUES = "BooleanArrayValues";
+            public static final String FEATURE_BYTE_ARRAY_VALUES = "ByteArrayValues";
+            public static final String FEATURE_DOUBLE_ARRAY_VALUES = "DoubleArrayValues";
+            public static final String FEATURE_FLOAT_ARRAY_VALUES = "FloatArrayValues";
+            public static final String FEATURE_INTEGER_ARRAY_VALUES = "IntegerArrayValues";
+            public static final String FEATURE_LONG_ARRAY_VALUES = "LongArrayValues";
+            public static final String FEATURE_SERIALIZABLE_VALUES = "SerializableValues";
+            public static final String FEATURE_STRING_ARRAY_VALUES = "StringArrayValues";
+            public static final String FEATURE_STRING_VALUES = "StringValues";
+            public static final String FEATURE_UNIFORM_LIST_VALUES = "UniformListValues";
+
+            /**
+             * Supports setting of a boolean value.
+             */
+            @FeatureDescriptor(name = FEATURE_BOOLEAN_VALUES)
+            public default boolean supportsBooleanValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of a byte value.
+             */
+            @FeatureDescriptor(name = FEATURE_BYTE_VALUES)
+            public default boolean supportsByteValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of a double value.
+             */
+            @FeatureDescriptor(name = FEATURE_DOUBLE_VALUES)
+            public default boolean supportsDoubleValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of a float value.
+             */
+            @FeatureDescriptor(name = FEATURE_FLOAT_VALUES)
+            public default boolean supportsFloatValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of a integer value.
+             */
+            @FeatureDescriptor(name = FEATURE_INTEGER_VALUES)
+            public default boolean supportsIntegerValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of a long value.
+             */
+            @FeatureDescriptor(name = FEATURE_LONG_VALUES)
+            public default boolean supportsLongValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of a {@code Map} value.  The assumption is that the {@code Map} can contain
+             * arbitrary serializable values that may or may not be defined as a feature itself.
+             */
+            @FeatureDescriptor(name = FEATURE_MAP_VALUES)
+            public default boolean supportsMapValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of a {@code List} value.  The assumption is that the {@code List} can contain
+             * arbitrary serializable values that may or may not be defined as a feature itself.  As this
+             * {@code List} is "mixed" it does not need to contain objects of the same type.
+             *
+             * @see #supportsMixedListValues()
+             */
+            @FeatureDescriptor(name = FEATURE_MIXED_LIST_VALUES)
+            public default boolean supportsMixedListValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of an array of boolean values.
+             */
+            @FeatureDescriptor(name = FEATURE_BOOLEAN_ARRAY_VALUES)
+            public default boolean supportsBooleanArrayValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of an array of byte values.
+             */
+            @FeatureDescriptor(name = FEATURE_BYTE_ARRAY_VALUES)
+            public default boolean supportsByteArrayValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of an array of double values.
+             */
+            @FeatureDescriptor(name = FEATURE_DOUBLE_ARRAY_VALUES)
+            public default boolean supportsDoubleArrayValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of an array of float values.
+             */
+            @FeatureDescriptor(name = FEATURE_FLOAT_ARRAY_VALUES)
+            public default boolean supportsFloatArrayValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of an array of integer values.
+             */
+            @FeatureDescriptor(name = FEATURE_INTEGER_ARRAY_VALUES)
+            public default boolean supportsIntegerArrayValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of an array of string values.
+             */
+            @FeatureDescriptor(name = FEATURE_STRING_ARRAY_VALUES)
+            public default boolean supportsStringArrayValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of an array of long values.
+             */
+            @FeatureDescriptor(name = FEATURE_LONG_ARRAY_VALUES)
+            public default boolean supportsLongArrayValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of a Java serializable value.
+             */
+            @FeatureDescriptor(name = FEATURE_SERIALIZABLE_VALUES)
+            public default boolean supportsSerializableValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of a long value.
+             */
+            @FeatureDescriptor(name = FEATURE_STRING_VALUES)
+            public default boolean supportsStringValues() {
+                return true;
+            }
+
+            /**
+             * Supports setting of a {@code List} value.  The assumption is that the {@code List} can contain
+             * arbitrary serializable values that may or may not be defined as a feature itself.  As this
+             * {@code List} is "uniform" it must contain objects of the same type.
+             *
+             * @see #supportsMixedListValues()
+             */
+            @FeatureDescriptor(name = FEATURE_UNIFORM_LIST_VALUES)
+            public default boolean supportsUniformListValues() {
+                return true;
+            }
+        }
+
+        /**
+         * A marker interface to identify any set of Features. There is no need to implement this interface.
+         */
+        public interface FeatureSet {
+        }
+
+        /**
+         * Implementers should not override this method. Note that this method utilizes reflection to check for
+         * feature support.
+         */
+        default boolean supports(final Class<? extends FeatureSet> featureClass, final String feature)
+                throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+            final Object instance;
+            if (featureClass.equals(GraphFeatures.class))
+                instance = this.graph();
+            else if (featureClass.equals(VariableFeatures.class))
+                instance = this.graph().variables();
+            else if (featureClass.equals(VertexFeatures.class))
+                instance = this.vertex();
+            else if (featureClass.equals(VertexPropertyFeatures.class))
+                instance = this.vertex().properties();
+            else if (featureClass.equals(EdgeFeatures.class))
+                instance = this.edge();
+            else if (featureClass.equals(EdgePropertyFeatures.class))
+                instance = this.edge().properties();
+            else if (featureClass.equals(PropertyFeatures.class))
+                throw new IllegalArgumentException(String.format(
+                        "Do not reference PropertyFeatures directly in tests, utilize a specific instance: %s, %s",
+                        EdgePropertyFeatures.class, VertexPropertyFeatures.class));
+            else
+                throw new IllegalArgumentException(String.format(
+                        "Expecting featureClass to be a valid Feature instance and not %s", featureClass));
+
+            return (Boolean) featureClass.getMethod("supports" + feature).invoke(instance);
+        }
+    }
+
+    /**
+     * Common exceptions to use with a graph.
+     */
+    public static class Exceptions {
+
+        private static final boolean debug = Boolean.parseBoolean(java.lang.System.getenv().getOrDefault("gremlin.structure.debug", "false"));
+
+        public static UnsupportedOperationException variablesNotSupported() {
+            return new UnsupportedOperationException("Graph does not support graph variables");
+        }
+
+        public static UnsupportedOperationException transactionsNotSupported() {
+            return new UnsupportedOperationException("Graph does not support transactions");
+        }
+
+        public static UnsupportedOperationException graphComputerNotSupported() {
+            return new UnsupportedOperationException("Graph does not support graph computer");
+        }
+
+        public static IllegalArgumentException graphDoesNotSupportProvidedGraphComputer(final Class graphComputerClass) {
+            return new IllegalArgumentException("Graph does not support the provided graph computer: " + graphComputerClass.getSimpleName());
+        }
+
+        public static UnsupportedOperationException vertexAdditionsNotSupported() {
+            return new UnsupportedOperationException("Graph does not support adding vertices");
+        }
+
+        public static IllegalArgumentException vertexWithIdAlreadyExists(final Object id) {
+            return new IllegalArgumentException(String.format("Vertex with id already exists: %s", id));
+        }
+
+        public static IllegalArgumentException edgeWithIdAlreadyExists(final Object id) {
+            return new IllegalArgumentException(String.format("Edge with id already exists: %s", id));
+        }
+
+        public static IllegalArgumentException argumentCanNotBeNull(final String argument) {
+            return new IllegalArgumentException(String.format("The provided argument can not be null: %s", argument));
+        }
+
+        public static NoSuchElementException elementNotFound(final Class<? extends Element> elementClass, final Object id) {
+            return (null == id) ?
+                    new NoSuchElementException("The " + elementClass.getSimpleName().toLowerCase() + " with id null does not exist in the graph") :
+                    new NoSuchElementException("The " + elementClass.getSimpleName().toLowerCase() + " with id " + id + " of type " + id.getClass().getSimpleName() + " does not exist in the graph");
+        }
+
+        public static IllegalArgumentException onlyOneOrNoGraphComputerClass() {
+            return new IllegalArgumentException("Provide either one or no graph computer class");
+        }
+    }
+
+    /**
+     * Defines the test suite that the implementer has decided to support and represents publicly as "passing".
+     * Marking the {@link Graph} instance with this class allows that particular test suite to run.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    @Repeatable(OptIns.class)
+    @Inherited
+    public @interface OptIn {
+        public static String SUITE_STRUCTURE_STANDARD = "com.tinkerpop.gremlin.structure.StructureStandardSuite";
+        public static String SUITE_STRUCTURE_PERFORMANCE = "com.tinkerpop.gremlin.structure.StructurePerformanceSuite";
+        public static String SUITE_PROCESS_COMPUTER = "com.tinkerpop.gremlin.process.ProcessComputerSuite";
+        public static String SUITE_PROCESS_STANDARD = "com.tinkerpop.gremlin.process.ProcessStandardSuite";
+        public static String SUITE_PROCESS_PERFORMANCE = "com.tinkerpop.gremlin.process.ProcessPerformanceSuite";
+        public static String SUITE_GROOVY_PROCESS_STANDARD = "com.tinkerpop.gremlin.process.GroovyProcessStandardSuite";
+        public static String SUITE_GROOVY_PROCESS_COMPUTER = "com.tinkerpop.gremlin.process.GroovyProcessComputerSuite";
+        public static String SUITE_GROOVY_ENVIRONMENT = "com.tinkerpop.gremlin.groovy.GroovyEnvironmentSuite";
+        public static String SUITE_GROOVY_ENVIRONMENT_INTEGRATE = "com.tinkerpop.gremlin.groovy.GroovyEnvironmentIntegrateSuite";
+        public static String SUITE_GROOVY_ENVIRONMENT_PERFORMANCE = "com.tinkerpop.gremlin.groovy.GroovyEnvironmentPerformanceSuite";
+
+        /**
+         * The test suite class to opt in to.
+         */
+        public String value();
+    }
+
+    /**
+     * Holds a collection of {@link OptIn} enabling multiple {@link OptIn} to be applied to a
+     * single suite.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    @Inherited
+    public @interface OptIns {
+        OptIn[] value();
+    }
+
+    /**
+     * Defines a test in the suite that the implementer does not want to run.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    @Repeatable(OptOuts.class)
+    @Inherited
+    public @interface OptOut {
+        /**
+         * The test class to opt out of.
+         */
+        public String test();
+
+        /**
+         * The specific name of the test method to opt out of or asterisk to opt out of all methods in a
+         * {@link #test}.
+         */
+        public String method();
+
+        /**
+         * The reason the implementation is opting out of this test.
+         */
+        public String reason();
+
+        /**
+         * For parameterized tests specify the name of the test itself without its "square brackets".
+         */
+        public String specific() default "";
+    }
+
+    /**
+     * Holds a collection of {@link OptOut} enabling multiple {@link OptOut} to be applied to a
+     * single suite.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.TYPE)
+    @Inherited
+    public @interface OptOuts {
+        OptOut[] value();
+    }
+
+    /**
+     * Defines a method as a "helper method".  These methods will usually be default methods in the
+     * core structure interfaces.  Any method marked with this annotation represent methods that should not
+     * be implemented by vendors.  The test suite will enforce this convention and create a failure situation
+     * if violated.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    @Inherited
+    public @interface Helper {
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Operator.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Operator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Operator.java
new file mode 100644
index 0000000..f3c2bd3
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Operator.java
@@ -0,0 +1,125 @@
+/*
+ * 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 com.tinkerpop.gremlin.structure;
+
+import java.util.function.BinaryOperator;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public enum Operator implements BinaryOperator<Number> {
+
+
+    sum {
+        public Number apply(final Number a, final Number b) {
+            final Class<? extends Number> numberClass = a.getClass();
+            if (numberClass.equals(Integer.class)) {
+                return a.intValue() + b.intValue();
+            } else if (numberClass.equals(Long.class)) {
+                return a.longValue() + b.longValue();
+            } else if (numberClass.equals(Float.class)) {
+                return a.floatValue() + b.floatValue();
+            } else if (numberClass.equals(Double.class)) {
+                return a.doubleValue() + b.doubleValue();
+            } else {
+                throw new IllegalArgumentException("This operator only supports int, long, float, or double: " + numberClass);
+            }
+        }
+    },
+    minus {
+        public Number apply(final Number a, final Number b) {
+            final Class<? extends Number> numberClass = a.getClass();
+            if (numberClass.equals(Integer.class)) {
+                return a.intValue() - b.intValue();
+            } else if (numberClass.equals(Long.class)) {
+                return a.longValue() - b.longValue();
+            } else if (numberClass.equals(Float.class)) {
+                return a.floatValue() - b.floatValue();
+            } else if (numberClass.equals(Double.class)) {
+                return a.doubleValue() - b.doubleValue();
+            } else {
+                throw new IllegalArgumentException("This operator only supports int, long, float, or double: " + numberClass);
+            }
+        }
+    },
+    mult {
+        public Number apply(final Number a, final Number b) {
+            final Class<? extends Number> numberClass = a.getClass();
+            if (numberClass.equals(Integer.class)) {
+                return a.intValue() * b.intValue();
+            } else if (numberClass.equals(Long.class)) {
+                return a.longValue() * b.longValue();
+            } else if (numberClass.equals(Float.class)) {
+                return a.floatValue() * b.floatValue();
+            } else if (numberClass.equals(Double.class)) {
+                return a.doubleValue() * b.doubleValue();
+            } else {
+                throw new IllegalArgumentException("This operator only supports int, long, float, or double: " + numberClass);
+            }
+        }
+    },
+    div {
+        public Number apply(final Number a, final Number b) {
+            final Class<? extends Number> numberClass = a.getClass();
+            if (numberClass.equals(Integer.class)) {
+                return a.intValue() / b.intValue();
+            } else if (numberClass.equals(Long.class)) {
+                return a.longValue() / b.longValue();
+            } else if (numberClass.equals(Float.class)) {
+                return a.floatValue() / b.floatValue();
+            } else if (numberClass.equals(Double.class)) {
+                return a.doubleValue() / b.doubleValue();
+            } else {
+                throw new IllegalArgumentException("This operator only supports int, long, float, or double: " + numberClass);
+            }
+        }
+    },
+    min {
+        public Number apply(final Number a, final Number b) {
+            final Class<? extends Number> numberClass = a.getClass();
+            if (numberClass.equals(Integer.class)) {
+                return Math.min(a.intValue(), b.intValue());
+            } else if (numberClass.equals(Long.class)) {
+                return Math.min(a.longValue(), b.longValue());
+            } else if (numberClass.equals(Float.class)) {
+                return Math.min(a.floatValue(), b.floatValue());
+            } else if (numberClass.equals(Double.class)) {
+                return Math.min(a.doubleValue(), b.doubleValue());
+            } else {
+                throw new IllegalArgumentException("This operator only supports int, long, float, or double: " + numberClass);
+            }
+        }
+    },
+    max {
+        public Number apply(final Number a, final Number b) {
+            final Class<? extends Number> numberClass = a.getClass();
+            if (numberClass.equals(Integer.class)) {
+                return Math.max(a.intValue(), b.intValue());
+            } else if (numberClass.equals(Long.class)) {
+                return Math.max(a.longValue(), b.longValue());
+            } else if (numberClass.equals(Float.class)) {
+                return Math.max(a.floatValue(), b.floatValue());
+            } else if (numberClass.equals(Double.class)) {
+                return Math.max(a.doubleValue(), b.doubleValue());
+            } else {
+                throw new IllegalArgumentException("This operator only supports int, long, float, or double: " + numberClass);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Order.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Order.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Order.java
new file mode 100644
index 0000000..a15ea55
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Order.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 com.tinkerpop.gremlin.structure;
+
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Random;
+
+/**
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public enum Order implements Comparator<Object> {
+
+    incr {
+        @Override
+        public int compare(final Object first, final Object second) {
+            return Comparator.<Comparable>naturalOrder().compare((Comparable) first, (Comparable) second);
+        }
+
+        @Override
+        public Order opposite() {
+            return decr;
+        }
+    }, decr {
+        @Override
+        public int compare(final Object first, final Object second) {
+            return Comparator.<Comparable>reverseOrder().compare((Comparable) first, (Comparable) second);
+        }
+
+        @Override
+        public Order opposite() {
+            return incr;
+        }
+    }, keyIncr {
+        @Override
+        public int compare(final Object first, final Object second) {
+            return Comparator.<Comparable>naturalOrder().compare(((Map.Entry<Comparable, ?>) first).getKey(), ((Map.Entry<Comparable, ?>) second).getKey());
+        }
+
+        @Override
+        public Order opposite() {
+            return keyDecr;
+        }
+    }, valueIncr {
+        @Override
+        public int compare(final Object first, final Object second) {
+            return Comparator.<Comparable>naturalOrder().compare(((Map.Entry<?, Comparable>) first).getValue(), ((Map.Entry<?, Comparable>) second).getValue());
+        }
+
+        @Override
+        public Order opposite() {
+            return valueDecr;
+        }
+    }, keyDecr {
+        @Override
+        public int compare(final Object first, final Object second) {
+            return Comparator.<Comparable>reverseOrder().compare(((Map.Entry<Comparable, ?>) first).getKey(), ((Map.Entry<Comparable, ?>) second).getKey());
+        }
+
+        @Override
+        public Order opposite() {
+            return keyIncr;
+        }
+    }, valueDecr {
+        @Override
+        public int compare(final Object first, final Object second) {
+            return Comparator.<Comparable>reverseOrder().compare(((Map.Entry<?, Comparable>) first).getValue(), ((Map.Entry<?, Comparable>) second).getValue());
+        }
+
+        @Override
+        public Order opposite() {
+            return valueIncr;
+        }
+    }, shuffle {
+        @Override
+        public int compare(final Object first, final Object second) {
+            return RANDOM.nextBoolean() ? -1 : 1;
+        }
+
+        @Override
+        public Order opposite() {
+            return shuffle;
+        }
+    };
+
+    private static final Random RANDOM = new Random();
+
+    /**
+     * {@inheritDoc}
+     */
+    public abstract int compare(final Object first, final Object second);
+
+    /**
+     * Produce the opposite representation of the current {@code Order} enum.
+     */
+    public abstract Order opposite();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Property.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Property.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Property.java
new file mode 100644
index 0000000..db5a610
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Property.java
@@ -0,0 +1,164 @@
+/*
+ * 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 com.tinkerpop.gremlin.structure;
+
+import com.tinkerpop.gremlin.structure.util.empty.EmptyProperty;
+
+import java.util.NoSuchElementException;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * A {@link Property} denotes a key/value pair associated with an {@link Edge}. A property is much like a Java8
+ * {@link java.util.Optional} in that a property can be not present (i.e. empty). The key of a property is always a
+ * String and the value of a property is an arbitrary Java object. Each underlying graph engine will typically have
+ * constraints on what Java objects are allowed to be used as values.
+ *
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public interface Property<V> {
+
+    /**
+     * The key of the property.
+     *
+     * @return The property key
+     */
+    public String key();
+
+    /**
+     * The value of the property.
+     *
+     * @return The property value
+     * @throws NoSuchElementException thrown if the property is empty
+     */
+    public V value() throws NoSuchElementException;
+
+    /**
+     * Whether the property is empty or not.
+     *
+     * @return True if the property exists, else false
+     */
+    public boolean isPresent();
+
+    /**
+     * If the property is present, the consume the value as specified by the {@link Consumer}.
+     *
+     * @param consumer The consumer to process the existing value.
+     */
+    @Graph.Helper
+    public default void ifPresent(final Consumer<? super V> consumer) {
+        if (this.isPresent())
+            consumer.accept(this.value());
+    }
+
+    /**
+     * If the value is present, return the value, else return the provided value.
+     *
+     * @param otherValue The value to return if the property is not present
+     * @return A value
+     */
+    @Graph.Helper
+    public default V orElse(final V otherValue) {
+        return this.isPresent() ? this.value() : otherValue;
+    }
+
+    /**
+     * If the value is present, return the value, else generate a value given the {@link Supplier}.
+     *
+     * @param valueSupplier The supplier to use to generate a value if the property is not present
+     * @return A value
+     */
+    @Graph.Helper
+    public default V orElseGet(final Supplier<? extends V> valueSupplier) {
+        return this.isPresent() ? this.value() : valueSupplier.get();
+    }
+
+    /**
+     * If the value is present, return the value, else throw the exception generated by the {@link Supplier}.
+     *
+     * @param exceptionSupplier The supplier to generate an exception if the property is not present
+     * @param <E>               The exception type
+     * @return A value
+     * @throws E if the property is not present, the exception is thrown
+     */
+    @Graph.Helper
+    public default <E extends Throwable> V orElseThrow(final Supplier<? extends E> exceptionSupplier) throws E {
+        if (this.isPresent()) return this.value();
+        else
+            throw exceptionSupplier.get();
+    }
+
+    /**
+     * Get the element that this property is associated with.
+     *
+     * @return The element associated with this property (i.e. {@link Vertex}, {@link Edge}, or {@link VertexProperty}).
+     */
+    public Element element();
+
+    /**
+     * Remove the property from the associated element.
+     */
+    public void remove();
+
+    /**
+     * Create an empty property that is not present.
+     *
+     * @param <V> The value class of the empty property
+     * @return A property that is not present
+     */
+    public static <V> Property<V> empty() {
+        return EmptyProperty.instance();
+    }
+
+    /**
+     * Common exceptions to use with a property.
+     */
+    public static class Exceptions {
+
+        public static IllegalArgumentException propertyKeyCanNotBeEmpty() {
+            return new IllegalArgumentException("Property key can not be the empty string");
+        }
+
+        public static IllegalArgumentException propertyKeyCanNotBeNull() {
+            return new IllegalArgumentException("Property key can not be null");
+        }
+
+        public static IllegalArgumentException propertyValueCanNotBeNull() {
+            return new IllegalArgumentException("Property value can not be null");
+        }
+
+        public static IllegalArgumentException propertyKeyCanNotBeAHiddenKey(final String key) {
+            return new IllegalArgumentException("Property key can not be a hidden key: " + key);
+        }
+
+        public static IllegalStateException propertyDoesNotExist() {
+            return new IllegalStateException("The property does not exist as it has no key, value, or associated element");
+        }
+
+        public static IllegalStateException propertyDoesNotExist(final String key) {
+            return new IllegalStateException("The property does not exist as the key has no associated value: " + key);
+        }
+
+        public static IllegalArgumentException dataTypeOfPropertyValueNotSupported(final Object val) {
+            return new IllegalArgumentException(String.format("Property value [%s] is of type %s is not supported", val, val.getClass()));
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/1545201f/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/PropertyType.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/PropertyType.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/PropertyType.java
new file mode 100644
index 0000000..4caced6
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/PropertyType.java
@@ -0,0 +1,56 @@
+/*
+ * 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 com.tinkerpop.gremlin.structure;
+
+/**
+ * This enumeration allows for the specification of the type of a {@link Property}.
+ * Properties can either be their standard form or value form. Note that this is different than a property
+ * class like {@link Property} or {@link VertexProperty}. This enumeration is used to denote those aspects of a
+ * property that can not be realized by class alone.
+ *
+ * @author Marko A. Rodriguez (http://markorodriguez.com)
+ */
+public enum PropertyType {
+    PROPERTY {
+        @Override
+        public final boolean forProperties() {
+            return true;
+        }
+
+        @Override
+        public final boolean forValues() {
+            return false;
+        }
+
+    }, VALUE {
+        @Override
+        public final boolean forProperties() {
+            return false;
+        }
+
+        @Override
+        public final boolean forValues() {
+            return true;
+        }
+    };
+
+    public abstract boolean forProperties();
+
+    public abstract boolean forValues();
+}