diff --git a/janusgraph-dist/src/assembly/descriptor/archive.xml b/janusgraph-dist/src/assembly/descriptor/archive.xml
index c6be10d7d7..ec8830c51b 100644
--- a/janusgraph-dist/src/assembly/descriptor/archive.xml
+++ b/janusgraph-dist/src/assembly/descriptor/archive.xml
@@ -12,4 +12,15 @@
${assembly.descriptor.dir}/htmldocs.component.xml
${assembly.descriptor.dir}/readmes.component.xml
+
+
+
+ ${top.level.basedir}/janusgraph-examples
+ /examples
+
+ **/target/**
+
+
+
+
diff --git a/janusgraph-examples/README.md b/janusgraph-examples/README.md
new file mode 100644
index 0000000000..7890429e20
--- /dev/null
+++ b/janusgraph-examples/README.md
@@ -0,0 +1,39 @@
+# JanusGraph Examples
+
+The JanusGraph examples show the basics of how to configure and construct
+a graph application. It uses [Apache Maven](https://maven.apache.org) to
+manage the numerous dependencies required to build the application. The common
+application will:
+
+* Open and initialize the graph
+* Define the schema
+* Build the graph
+* Run traversal queries to get data from the graph
+* Make updates to the graph
+* Close the graph
+
+By using different graph configurations, the same example code can run against
+the various supported storage and indexing backends.
+
+## Prerequisites
+
+* Java 8 Developer Kit, update 40 or higher
+* Apache Maven, version 3.3 or higher
+
+## Building the Examples
+
+```
+mvn clean install
+```
+
+## Running the Examples
+
+Refer to the directions in each sub-directory.
+
+* [Common](example-common/README.md)
+* [BerkeleyJE](example-berkeleyje/README.md)
+* [Cassandra](example-cassandra/README.md)
+* [CQL](example-cql/README.md)
+* [HBase](example-hbase/README.md)
+* [RemoteGraph](example-remotegraph/README.md)
+* [TinkerGraph](example-tinkergraph/README.md)
diff --git a/janusgraph-examples/example-berkeleyje/.gitignore b/janusgraph-examples/example-berkeleyje/.gitignore
new file mode 100644
index 0000000000..f87a0f249c
--- /dev/null
+++ b/janusgraph-examples/example-berkeleyje/.gitignore
@@ -0,0 +1 @@
+jgex/
diff --git a/janusgraph-examples/example-berkeleyje/README.md b/janusgraph-examples/example-berkeleyje/README.md
new file mode 100644
index 0000000000..7a62c4bfdc
--- /dev/null
+++ b/janusgraph-examples/example-berkeleyje/README.md
@@ -0,0 +1,48 @@
+# BerkeleyJE Storage, Lucene Index
+
+## About BerkeleyJE and Lucene
+
+[Oracle Berkeley DB Java Edition](http://www.oracle.com/technetwork/database/berkeleydb/overview/index-093405.html)
+is an embedded database, so it runs within your application rather than as
+a standalone server. By including the `janusgraph-berkeleyje` dependency,
+the required jar files are pulled in. The data is stored in a directory on
+the file system.
+
+[Apache Lucene](http://lucene.apache.org/) is an embedded index, so it runs
+within your application rather than as a standalone server. By including the
+`janusgraph-lucene` dependency, the required jar files are pulled in. The
+data is stored in a directory on the file system.
+
+## JanusGraph configuration
+
+[`jgex-berkeleyje.properties`](conf/jgex-berkeleyje.properties) contains
+the directory locations for BerkeleyJE and Lucene.
+
+Refer to the JanusGraph [configuration reference](http://docs.janusgraph.org/latest/config-ref.html)
+for additional properties.
+
+## Running the example
+
+Use [Apache Maven](http://maven.apache.org/) and the
+[exec-maven-plugin](http://www.mojohaus.org/exec-maven-plugin/java-mojo.html)
+to pull in the required jar files onto the runtime classpath.
+
+```
+$ cd $JANUSGRAPH_HOME/janusgraph-examples/example-berkeleyje
+
+$ mvn exec:java -Dexec.mainClass="org.janusgraph.example.JanusGraphApp" -Dexec.args="conf/jgex-berkeleyje.properties"
+```
+
+## Drop the graph
+
+Make sure to stop the application before dropping the graph. The configuration
+uses the application name `jgex` as the root directory for the BerkeleyJE
+and Lucene directories.
+
+```
+$ cd $JANUSGRAPH_HOME/janusgraph-examples/example-berkeleyje
+
+$ mvn exec:java -Dexec.mainClass="org.janusgraph.example.JanusGraphApp" -Dexec.args="conf/jgex-berkeleyje.properties drop"
+
+$ rm -rf jgex/
+```
diff --git a/janusgraph-examples/example-berkeleyje/conf/jgex-berkeleyje.properties b/janusgraph-examples/example-berkeleyje/conf/jgex-berkeleyje.properties
new file mode 100644
index 0000000000..1a1e88a644
--- /dev/null
+++ b/janusgraph-examples/example-berkeleyje/conf/jgex-berkeleyje.properties
@@ -0,0 +1,7 @@
+gremlin.graph=org.janusgraph.core.JanusGraphFactory
+
+storage.backend=berkeleyje
+storage.directory=jgex/berkeleyje
+
+index.jgex.backend=lucene
+index.jgex.directory=jgex/lucene
diff --git a/janusgraph-examples/example-berkeleyje/pom.xml b/janusgraph-examples/example-berkeleyje/pom.xml
new file mode 100644
index 0000000000..d355eda854
--- /dev/null
+++ b/janusgraph-examples/example-berkeleyje/pom.xml
@@ -0,0 +1,37 @@
+
+ 4.0.0
+
+ org.janusgraph
+ janusgraph-examples
+ 0.2.0-SNAPSHOT
+ ../pom.xml
+
+ example-berkeleyje
+ pom
+ Example-BerkeleyJE: BerkeleyJE Storage, Lucene Index
+ http://janusgraph.org
+
+
+
+
+ org.janusgraph
+ example-common
+ ${project.version}
+ runtime
+
+
+ org.janusgraph
+ janusgraph-berkeleyje
+ ${project.version}
+ runtime
+
+
+ org.janusgraph
+ janusgraph-lucene
+ ${project.version}
+ runtime
+
+
+
+
diff --git a/janusgraph-examples/example-cassandra/README.md b/janusgraph-examples/example-cassandra/README.md
new file mode 100644
index 0000000000..aeea5e6955
--- /dev/null
+++ b/janusgraph-examples/example-cassandra/README.md
@@ -0,0 +1,53 @@
+# Cassandra Thrift Storage, Elasticsearch Index
+
+## About Cassandra and Elasticsearch
+
+[Apache Cassandra](http://cassandra.apache.org/) is a distributed database
+designed for scalability and high availability. Cassandra supports two
+protocols for communications, Thrift (legacy RPC protocol) and CQL (native
+protocol). Depending on the Cassandra version, Thrift may not be started by
+default. Make sure that [Thrift is started](http://docs.datastax.com/en/cassandra/2.1/cassandra/tools/toolsStatusThrift.html)
+when using this example.
+
+[Elasticsearch](https://www.elastic.co/products/elasticsearch) is a scalable,
+distributed search engine.
+
+> Check the JanusGraph [version compatibility](http://docs.janusgraph.org/latest/version-compat.html)
+to ensure you select versions of Cassandra and Elasticsearch compatible with
+this JanusGraph release.
+
+## JanusGraph configuration
+
+* [`jgex-cassandra.properties`](conf/jgex-cassandra.properties) contains the
+Cassandra and Elasticsearch server locations. By providing different values
+for `storage.cassandra.keyspace` and `index.jgex.index-name`, you can store
+multiple graphs on the same Cassandra and Elasticsearch servers. Refer to
+the JanusGraph [configuration reference](http://docs.janusgraph.org/latest/config-ref.html)
+for additional properties.
+
+* [`logback.xml`](conf/logback.xml) configures logging with [Logback](https://logback.qos.ch/),
+which is the logger used by Cassandra. The example configuration logs to the
+console and adjusts the logging level for some noisier packages. Refer to
+the Logback [manual](https://logback.qos.ch/manual/index.html) for additional
+details.
+
+## Run the example
+
+Use [Apache Maven](http://maven.apache.org/) and the [exec-maven-plugin](http://www.mojohaus.org/exec-maven-plugin/java-mojo.html)
+to pull in the required jar files onto the runtime classpath.
+
+```
+$ cd $JANUSGRAPH_HOME/janusgraph-examples/example-cassandra
+
+$ mvn exec:java -Dexec.mainClass="org.janusgraph.example.JanusGraphApp" -Dlogback.configurationFile="conf/logback.xml" -Dexec.args="conf/jgex-cassandra.properties"
+```
+
+## Drop the graph
+
+Make sure to stop the application before dropping the graph.
+
+```
+$ cd $JANUSGRAPH_HOME/janusgraph-examples/example-cassandra
+
+$ mvn exec:java -Dexec.mainClass="org.janusgraph.example.JanusGraphApp" -Dlogback.configurationFile="conf/logback.xml" -Dexec.args="conf/jgex-cassandra.properties drop"
+```
diff --git a/janusgraph-examples/example-cassandra/conf/jgex-cassandra.properties b/janusgraph-examples/example-cassandra/conf/jgex-cassandra.properties
new file mode 100644
index 0000000000..98204b76ca
--- /dev/null
+++ b/janusgraph-examples/example-cassandra/conf/jgex-cassandra.properties
@@ -0,0 +1,9 @@
+gremlin.graph=org.janusgraph.core.JanusGraphFactory
+
+storage.backend=cassandra
+storage.cassandra.keyspace=jgex
+storage.hostname=127.0.0.1
+
+index.jgex.backend=elasticsearch
+index.jgex.index-name=jgex
+index.jgex.hostname=127.0.0.1
diff --git a/janusgraph-examples/example-cassandra/conf/logback.xml b/janusgraph-examples/example-cassandra/conf/logback.xml
new file mode 100644
index 0000000000..a6e60f82a6
--- /dev/null
+++ b/janusgraph-examples/example-cassandra/conf/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %d{HH:mm:ss} %-5level %logger - %msg%n
+
+
+
+
+
+
+
diff --git a/janusgraph-examples/example-cassandra/pom.xml b/janusgraph-examples/example-cassandra/pom.xml
new file mode 100644
index 0000000000..81f858dbff
--- /dev/null
+++ b/janusgraph-examples/example-cassandra/pom.xml
@@ -0,0 +1,37 @@
+
+ 4.0.0
+
+ org.janusgraph
+ janusgraph-examples
+ 0.2.0-SNAPSHOT
+ ../pom.xml
+
+ example-cassandra
+ pom
+ Example-Cassandra: C* Thrift Storage, ES Index
+ http://janusgraph.org
+
+
+
+
+ org.janusgraph
+ example-common
+ ${project.version}
+ runtime
+
+
+ org.janusgraph
+ janusgraph-cassandra
+ ${project.version}
+ runtime
+
+
+ org.janusgraph
+ janusgraph-es
+ ${project.version}
+ runtime
+
+
+
+
diff --git a/janusgraph-examples/example-common/README.md b/janusgraph-examples/example-common/README.md
new file mode 100644
index 0000000000..c929353f88
--- /dev/null
+++ b/janusgraph-examples/example-common/README.md
@@ -0,0 +1,24 @@
+# Common Example
+
+## About the common example
+
+`GraphApp` is an abstract class that defines a basic structure for a graph
+application. It contains methods for configuring a graph instance, defining
+a graph schema, creating a graph structure, and querying a graph.
+
+`JanusGraphApp` is a subclass of `GraphApp` using JanusGraph-specific methods
+to create the schema.
+
+## In-Memory configuration
+
+[`jgex-inmemory.properties`](conf/jgex-inmemory.properties) contains the
+settings for the JanusGraph [in-memory storage backend](http://docs.janusgraph.org/latest/inmemorystorage.html).
+This backend is primarily for testing purposes.
+
+## Running the example
+
+```
+$ cd $JANUSGRAPH_HOME/janusgraph-examples/example-common
+
+$ mvn exec:java -Dexec.mainClass="org.janusgraph.example.JanusGraphApp" -Dexec.args="conf/jgex-inmemory.properties"
+```
diff --git a/janusgraph-examples/example-common/conf/jgex-inmemory.properties b/janusgraph-examples/example-common/conf/jgex-inmemory.properties
new file mode 100644
index 0000000000..9608404cfb
--- /dev/null
+++ b/janusgraph-examples/example-common/conf/jgex-inmemory.properties
@@ -0,0 +1,3 @@
+gremlin.graph=org.janusgraph.core.JanusGraphFactory
+
+storage.backend=inmemory
diff --git a/janusgraph-examples/example-common/pom.xml b/janusgraph-examples/example-common/pom.xml
new file mode 100644
index 0000000000..27e864144a
--- /dev/null
+++ b/janusgraph-examples/example-common/pom.xml
@@ -0,0 +1,22 @@
+
+ 4.0.0
+
+ org.janusgraph
+ janusgraph-examples
+ 0.2.0-SNAPSHOT
+ ../pom.xml
+
+ example-common
+ Example-Common: Common Graph Code for Examples
+ http://janusgraph.org
+
+
+
+ org.janusgraph
+ janusgraph-core
+ ${project.version}
+
+
+
+
diff --git a/janusgraph-examples/example-common/src/main/java/org/janusgraph/example/GraphApp.java b/janusgraph-examples/example-common/src/main/java/org/janusgraph/example/GraphApp.java
new file mode 100644
index 0000000000..0ac284e884
--- /dev/null
+++ b/janusgraph-examples/example-common/src/main/java/org/janusgraph/example/GraphApp.java
@@ -0,0 +1,326 @@
+// Copyright 2017 JanusGraph Authors
+//
+// Licensed 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.janusgraph.example;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.GraphFactory;
+import org.janusgraph.core.attribute.Geoshape;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GraphApp {
+ private static final Logger LOGGER = LoggerFactory.getLogger(GraphApp.class);
+
+ protected String propFileName;
+ protected Configuration conf;
+ protected Graph graph;
+ protected GraphTraversalSource g;
+ protected boolean supportsTransactions;
+ protected boolean supportsSchema;
+ protected boolean supportsGeoshape;
+
+ /**
+ * Constructs a graph app using the given properties.
+ * @param fileName location of the properties file
+ */
+ public GraphApp(final String fileName) {
+ propFileName = fileName;
+ }
+
+ /**
+ * Opens the graph instance. If the graph instance does not exist, a new
+ * graph instance is initialized.
+ */
+ public GraphTraversalSource openGraph() throws ConfigurationException {
+ LOGGER.info("opening graph");
+ conf = new PropertiesConfiguration(propFileName);
+ graph = GraphFactory.open(conf);
+ g = graph.traversal();
+ return g;
+ }
+
+ /**
+ * Closes the graph instance.
+ */
+ public void closeGraph() throws Exception {
+ LOGGER.info("closing graph");
+ try {
+ if (g != null) {
+ g.close();
+ }
+ if (graph != null) {
+ graph.close();
+ }
+ } finally {
+ g = null;
+ graph = null;
+ }
+ }
+
+ /**
+ * Drops the graph instance. The default implementation does nothing.
+ */
+ public void dropGraph() throws Exception {
+ }
+
+ /**
+ * Creates the graph schema. The default implementation does nothing.
+ */
+ public void createSchema() {
+ }
+
+ /**
+ * Adds the vertices, edges, and properties to the graph.
+ */
+ public void createElements() {
+ try {
+ // naive check if the graph was previously created
+ if (g.V().has("name", "saturn").hasNext()) {
+ if (supportsTransactions) {
+ g.tx().rollback();
+ }
+ return;
+ }
+ LOGGER.info("creating elements");
+
+ // see GraphOfTheGodsFactory.java
+
+ Vertex saturn = g.addV("titan").property("name", "saturn").property("age", 10000).next();
+ Vertex sky = g.addV("location").property("name", "sky").next();
+ Vertex sea = g.addV("location").property("name", "sea").next();
+ Vertex jupiter = g.addV("god").property("name", "jupiter").property("age", 5000).next();
+ Vertex neptune = g.addV("god").property("name", "neptune").property("age", 4500).next();
+ Vertex hercules = g.addV("demigod").property("name", "hercules").property("age", 30).next();
+ Vertex alcmene = g.addV("human").property("name", "alcmene").property("age", 45).next();
+ Vertex pluto = g.addV("god").property("name", "pluto").property("age", 4000).next();
+ Vertex nemean = g.addV("monster").property("name", "nemean").next();
+ Vertex hydra = g.addV("monster").property("name", "hydra").next();
+ Vertex cerberus = g.addV("monster").property("name", "cerberus").next();
+ Vertex tartarus = g.addV("location").property("name", "tartarus").next();
+
+ g.V(jupiter).as("a").V(saturn).addE("father").from("a").next();
+ g.V(jupiter).as("a").V(sky).addE("lives").property("reason", "loves fresh breezes").from("a").next();
+ g.V(jupiter).as("a").V(neptune).addE("brother").from("a").next();
+ g.V(jupiter).as("a").V(pluto).addE("brother").from("a").next();
+
+ g.V(neptune).as("a").V(sea).addE("lives").property("reason", "loves waves").from("a").next();
+ g.V(neptune).as("a").V(jupiter).addE("brother").from("a").next();
+ g.V(neptune).as("a").V(pluto).addE("brother").from("a").next();
+
+ g.V(hercules).as("a").V(jupiter).addE("father").from("a").next();
+ g.V(hercules).as("a").V(alcmene).addE("mother").from("a").next();
+
+ if (supportsGeoshape) {
+ g.V(hercules).as("a").V(nemean).addE("battled").property("time", 1)
+ .property("place", Geoshape.point(38.1f, 23.7f)).from("a").next();
+ g.V(hercules).as("a").V(hydra).addE("battled").property("time", 2)
+ .property("place", Geoshape.point(37.7f, 23.9f)).from("a").next();
+ g.V(hercules).as("a").V(cerberus).addE("battled").property("time", 12)
+ .property("place", Geoshape.point(39f, 22f)).from("a").next();
+ } else {
+ g.V(hercules).as("a").V(nemean).addE("battled").property("time", 1)
+ .property("place", getGeoFloatArray(38.1f, 23.7f)).from("a").next();
+ g.V(hercules).as("a").V(hydra).addE("battled").property("time", 2)
+ .property("place", getGeoFloatArray(37.7f, 23.9f)).from("a").next();
+ g.V(hercules).as("a").V(cerberus).addE("battled").property("time", 12)
+ .property("place", getGeoFloatArray(39f, 22f)).from("a").next();
+ }
+
+ g.V(pluto).as("a").V(jupiter).addE("brother").from("a").next();
+ g.V(pluto).as("a").V(neptune).addE("brother").from("a").next();
+ g.V(pluto).as("a").V(tartarus).addE("lives").property("reason", "no fear of death").from("a").next();
+ g.V(pluto).as("a").V(cerberus).addE("pet").from("a").next();
+
+ g.V(cerberus).as("a").V(tartarus).addE("lives").from("a").next();
+
+ if (supportsTransactions) {
+ g.tx().commit();
+ }
+
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage(), e);
+ if (supportsTransactions) {
+ g.tx().rollback();
+ }
+ }
+ }
+
+ /**
+ * Returns the geographical coordinates as a float array.
+ */
+ protected float[] getGeoFloatArray(final float lat, final float lon) {
+ final float[] fa = { lat, lon };
+ return fa;
+ }
+
+ /**
+ * Runs some traversal queries to get data from the graph.
+ */
+ public void readElements() {
+ try {
+ if (g == null) {
+ return;
+ }
+
+ LOGGER.info("reading elements");
+
+ // look up vertex by name can use a composite index in JanusGraph
+ Optional> v = g.V().has("name", "jupiter").valueMap(true).tryNext();
+ if (v.isPresent()) {
+ LOGGER.info(v.get().toString());
+ } else {
+ LOGGER.warn("jupiter not found");
+ }
+
+ // look up an incident edge
+ Optional> edge = g.V().has("name", "hercules").outE("battled").as("e").inV()
+ .has("name", "hydra").select("e").valueMap(true).tryNext();
+ if (edge.isPresent()) {
+ LOGGER.info(edge.get().toString());
+ } else {
+ LOGGER.warn("hercules battled hydra not found");
+ }
+
+ // numerical range query can use a mixed index in JanusGraph
+ List list = g.V().has("age", P.gte(5000)).values("age").toList();
+ LOGGER.info(list.toString());
+
+ // pluto might be deleted
+ boolean plutoExists = g.V().has("name", "pluto").hasNext();
+ if (plutoExists) {
+ LOGGER.info("pluto exists");
+ } else {
+ LOGGER.warn("pluto not found");
+ }
+
+ // look up jupiter's brothers
+ List brothers = g.V().has("name", "jupiter").both("brother").values("name").dedup().toList();
+ LOGGER.info("jupiter's brothers: " + brothers.toString());
+
+ } finally {
+ // the default behavior automatically starts a transaction for
+ // any graph interaction, so it is best to finish the transaction
+ // even for read-only graph query operations
+ if (supportsTransactions) {
+ g.tx().rollback();
+ }
+ }
+ }
+
+ /**
+ * Makes an update to the existing graph structure. Does not create any
+ * new vertices or edges.
+ */
+ public void updateElements() {
+ try {
+ if (g == null) {
+ return;
+ }
+ LOGGER.info("updating elements");
+ final long ts = System.currentTimeMillis();
+ g.V().has("name", "jupiter").property("ts", ts).iterate();
+ if (supportsTransactions) {
+ g.tx().commit();
+ }
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage(), e);
+ if (supportsTransactions) {
+ g.tx().rollback();
+ }
+ }
+ }
+
+ /**
+ * Deletes elements from the graph structure. When a vertex is deleted,
+ * its incident edges are also deleted.
+ */
+ public void deleteElements() {
+ try {
+ if (g == null) {
+ return;
+ }
+ LOGGER.info("deleting elements");
+ // note that this will succeed whether or not pluto exists
+ g.V().has("name", "pluto").drop().iterate();
+ if (supportsTransactions) {
+ g.tx().commit();
+ }
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage(), e);
+ if (supportsTransactions) {
+ g.tx().rollback();
+ }
+ }
+ }
+
+ /**
+ * Run the entire application:
+ * 1. Open and initialize the graph
+ * 2. Define the schema
+ * 3. Build the graph
+ * 4. Run traversal queries to get data from the graph
+ * 5. Make updates to the graph
+ * 6. Close the graph
+ */
+ public void runApp() {
+ try {
+ // open and initialize the graph
+ openGraph();
+
+ // define the schema before loading data
+ if (supportsSchema) {
+ createSchema();
+ }
+
+ // build the graph structure
+ createElements();
+ // read to see they were made
+ readElements();
+
+ for (int i = 0; i < 3; i++) {
+ try {
+ Thread.sleep((long) (Math.random() * 500) + 500);
+ } catch (InterruptedException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ // update some graph elements with changes
+ updateElements();
+ // read to see the changes were made
+ readElements();
+ }
+
+ // delete some graph elements
+ deleteElements();
+ // read to see the changes were made
+ readElements();
+
+ // close the graph
+ closeGraph();
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+
+}
diff --git a/janusgraph-examples/example-common/src/main/java/org/janusgraph/example/JanusGraphApp.java b/janusgraph-examples/example-common/src/main/java/org/janusgraph/example/JanusGraphApp.java
new file mode 100644
index 0000000000..c751c96f15
--- /dev/null
+++ b/janusgraph-examples/example-common/src/main/java/org/janusgraph/example/JanusGraphApp.java
@@ -0,0 +1,244 @@
+// Copyright 2017 JanusGraph Authors
+//
+// Licensed 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.janusgraph.example;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.janusgraph.core.JanusGraph;
+import org.janusgraph.core.JanusGraphFactory;
+import org.janusgraph.core.Multiplicity;
+import org.janusgraph.core.RelationType;
+import org.janusgraph.core.attribute.Geoshape;
+import org.janusgraph.core.schema.JanusGraphManagement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JanusGraphApp extends GraphApp {
+ private static final Logger LOGGER = LoggerFactory.getLogger(JanusGraphApp.class);
+
+ protected static final String APP_NAME = "jgex";
+ protected static final String MIXED_INDEX_CONFIG_NAME = "jgex";
+
+ // Storage backends
+
+ protected static final String BERKELEYJE = "berkeleyje";
+ protected static final String CASSANDRA = "cassandra";
+ protected static final String CQL = "cql";
+ protected static final String HBASE = "hbase";
+ protected static final String INMEMORY = "inmemory";
+
+ // Index backends
+
+ protected static final String LUCENE = "lucene";
+ protected static final String ELASTICSEARCH = "elasticsearch";
+ protected static final String SOLR = "solr";
+
+ protected boolean useMixedIndex;
+ protected String mixedIndexConfigName;
+
+ /**
+ * Constructs a graph app using the given properties.
+ * @param fileName location of the properties file
+ */
+ public JanusGraphApp(final String fileName) {
+ super(fileName);
+ this.supportsSchema = true;
+ this.supportsTransactions = true;
+ this.supportsGeoshape = true;
+ this.useMixedIndex = true;
+ this.mixedIndexConfigName = MIXED_INDEX_CONFIG_NAME;
+ }
+
+ @Override
+ public GraphTraversalSource openGraph() throws ConfigurationException {
+ super.openGraph();
+ useMixedIndex = useMixedIndex && conf.containsKey("index." + mixedIndexConfigName + ".backend");
+ return g;
+ }
+
+ @Override
+ public void dropGraph() throws Exception {
+ if (graph != null) {
+ JanusGraphFactory.drop(getJanusGraph());
+ }
+ }
+
+ @Override
+ public void createElements() {
+ super.createElements();
+ if (useMixedIndex) {
+ try {
+ // mixed indexes typically have a delayed refresh interval
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ LOGGER.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * Returns the JanusGraph instance.
+ */
+ protected JanusGraph getJanusGraph() {
+ return (JanusGraph) graph;
+ }
+
+ @Override
+ public void createSchema() {
+ final JanusGraphManagement mgmt = getJanusGraph().openManagement();
+ try {
+ // naive check if the schema was previously created
+ if (mgmt.getRelationTypes(RelationType.class).iterator().hasNext()) {
+ mgmt.rollback();
+ return;
+ }
+ LOGGER.info("creating schema");
+ createProperties(mgmt);
+ createVertexLabels(mgmt);
+ createEdgeLabels(mgmt);
+ createCompositeIndexes(mgmt);
+ createMixedIndexes(mgmt);
+ mgmt.commit();
+ } catch (Exception e) {
+ mgmt.rollback();
+ }
+ }
+
+ /**
+ * Creates the vertex labels.
+ */
+ protected void createVertexLabels(final JanusGraphManagement mgmt) {
+ mgmt.makeVertexLabel("titan").make();
+ mgmt.makeVertexLabel("location").make();
+ mgmt.makeVertexLabel("god").make();
+ mgmt.makeVertexLabel("demigod").make();
+ mgmt.makeVertexLabel("human").make();
+ mgmt.makeVertexLabel("monster").make();
+ }
+
+ /**
+ * Creates the edge labels.
+ */
+ protected void createEdgeLabels(final JanusGraphManagement mgmt) {
+ mgmt.makeEdgeLabel("father").multiplicity(Multiplicity.MANY2ONE).make();
+ mgmt.makeEdgeLabel("mother").multiplicity(Multiplicity.MANY2ONE).make();
+ mgmt.makeEdgeLabel("lives").signature(mgmt.getPropertyKey("reason")).make();
+ mgmt.makeEdgeLabel("pet").make();
+ mgmt.makeEdgeLabel("brother").make();
+ mgmt.makeEdgeLabel("battled").make();
+ }
+
+ /**
+ * Creates the properties for vertices, edges, and meta-properties.
+ */
+ protected void createProperties(final JanusGraphManagement mgmt) {
+ mgmt.makePropertyKey("name").dataType(String.class).make();
+ mgmt.makePropertyKey("age").dataType(Integer.class).make();
+ mgmt.makePropertyKey("time").dataType(Integer.class).make();
+ mgmt.makePropertyKey("reason").dataType(String.class).make();
+ mgmt.makePropertyKey("place").dataType(Geoshape.class).make();
+ }
+
+ /**
+ * Creates the composite indexes. A composite index is best used for
+ * exact match lookups.
+ */
+ protected void createCompositeIndexes(final JanusGraphManagement mgmt) {
+ mgmt.buildIndex("nameIndex", Vertex.class).addKey(mgmt.getPropertyKey("name")).buildCompositeIndex();
+ }
+
+ /**
+ * Creates the mixed indexes. A mixed index requires that an external
+ * indexing backend is configured on the graph instance. A mixed index
+ * is best for full text search, numerical range, and geospatial queries.
+ */
+ protected void createMixedIndexes(final JanusGraphManagement mgmt) {
+ if (useMixedIndex) {
+ mgmt.buildIndex("vAge", Vertex.class).addKey(mgmt.getPropertyKey("age"))
+ .buildMixedIndex(mixedIndexConfigName);
+ mgmt.buildIndex("eReasonPlace", Edge.class).addKey(mgmt.getPropertyKey("reason"))
+ .addKey(mgmt.getPropertyKey("place")).buildMixedIndex(mixedIndexConfigName);
+ }
+ }
+
+ /**
+ * Returns a string representation of the schema generation code. This
+ * request string is submitted to the Gremlin Server via a client
+ * connection to create the schema on the graph instance running on the
+ * server.
+ */
+ protected String createSchemaRequest() {
+ final StringBuilder s = new StringBuilder();
+
+ s.append("JanusGraphManagement mgmt = graph.openManagement(); ");
+ s.append("boolean created = false; ");
+
+ // naive check if the schema was previously created
+ s.append(
+ "if (mgmt.getRelationTypes(RelationType.class).iterator().hasNext()) { mgmt.rollback(); created = false; } else { ");
+
+ // properties
+ s.append("PropertyKey name = mgmt.makePropertyKey(\"name\").dataType(String.class).make(); ");
+ s.append("PropertyKey age = mgmt.makePropertyKey(\"age\").dataType(Integer.class).make(); ");
+ s.append("PropertyKey time = mgmt.makePropertyKey(\"time\").dataType(Integer.class).make(); ");
+ s.append("PropertyKey reason = mgmt.makePropertyKey(\"reason\").dataType(String.class).make(); ");
+ s.append("PropertyKey place = mgmt.makePropertyKey(\"place\").dataType(Geoshape.class).make(); ");
+
+ // vertex labels
+ s.append("mgmt.makeVertexLabel(\"titan\").make(); ");
+ s.append("mgmt.makeVertexLabel(\"location\").make(); ");
+ s.append("mgmt.makeVertexLabel(\"god\").make(); ");
+ s.append("mgmt.makeVertexLabel(\"demigod\").make(); ");
+ s.append("mgmt.makeVertexLabel(\"human\").make(); ");
+ s.append("mgmt.makeVertexLabel(\"monster\").make(); ");
+
+ // edge labels
+ s.append("mgmt.makeEdgeLabel(\"father\").multiplicity(Multiplicity.MANY2ONE).make(); ");
+ s.append("mgmt.makeEdgeLabel(\"mother\").multiplicity(Multiplicity.MANY2ONE).make(); ");
+ s.append("mgmt.makeEdgeLabel(\"lives\").signature(reason).make(); ");
+ s.append("mgmt.makeEdgeLabel(\"pet\").make(); ");
+ s.append("mgmt.makeEdgeLabel(\"brother\").make(); ");
+ s.append("mgmt.makeEdgeLabel(\"battled\").make(); ");
+
+ // composite indexes
+ s.append("mgmt.buildIndex(\"nameIndex\", Vertex.class).addKey(name).buildCompositeIndex(); ");
+
+ // mixed indexes
+ if (useMixedIndex) {
+ s.append("mgmt.buildIndex(\"vAge\", Vertex.class).addKey(age).buildMixedIndex(\"" + mixedIndexConfigName
+ + "\"); ");
+ s.append("mgmt.buildIndex(\"eReasonPlace\", Edge.class).addKey(reason).addKey(place).buildMixedIndex(\""
+ + mixedIndexConfigName + "\"); ");
+ }
+
+ s.append("mgmt.commit(); created = true; }");
+
+ return s.toString();
+ }
+
+ public static void main(String[] args) throws Exception {
+ final String fileName = (args != null && args.length > 0) ? args[0] : null;
+ final boolean drop = (args != null && args.length > 1) ? "drop".equalsIgnoreCase(args[1]) : false;
+ final JanusGraphApp app = new JanusGraphApp(fileName);
+ if (drop) {
+ app.openGraph();
+ app.dropGraph();
+ } else {
+ app.runApp();
+ }
+ }
+}
diff --git a/janusgraph-examples/example-common/src/test/java/org/janusgraph/example/GraphAppTest.java b/janusgraph-examples/example-common/src/test/java/org/janusgraph/example/GraphAppTest.java
new file mode 100644
index 0000000000..b5ce2dc544
--- /dev/null
+++ b/janusgraph-examples/example-common/src/test/java/org/janusgraph/example/GraphAppTest.java
@@ -0,0 +1,114 @@
+// Copyright 2017 JanusGraph Authors
+//
+// Licensed 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.janusgraph.example;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class GraphAppTest {
+ protected static final String CONF_FILE = "conf/jgex-inmemory.properties";
+
+ protected static GraphApp app;
+ protected static GraphTraversalSource g;
+
+ @BeforeClass
+ public static void setUpClass() throws ConfigurationException {
+ app = new GraphApp(CONF_FILE);
+ g = app.openGraph();
+ }
+
+ @Before
+ public void setUp() {
+ g.V().drop().iterate();
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws Exception {
+ if (app != null) {
+ app.closeGraph();
+ }
+ app = null;
+ }
+
+ @Test
+ public void openGraph() throws ConfigurationException {
+ assertNotNull(g);
+ }
+
+ @Test(expected = ConfigurationException.class)
+ public void openGraphNullConfig() throws ConfigurationException {
+ new GraphApp(null).openGraph();
+ }
+
+ @Test(expected = ConfigurationException.class)
+ public void openGraphConfigNotFound() throws ConfigurationException {
+ new GraphApp("conf/foobar").openGraph();
+ }
+
+ @Test
+ public void createElements() throws ConfigurationException {
+ app.createElements();
+
+ assertEquals(12L, ((Long) g.V().count().next()).longValue());
+ assertEquals(1L, ((Long) g.V().hasLabel("titan").count().next()).longValue());
+ assertEquals(1L, ((Long) g.V().hasLabel("demigod").count().next()).longValue());
+ assertEquals(1L, ((Long) g.V().hasLabel("human").count().next()).longValue());
+ assertEquals(3L, ((Long) g.V().hasLabel("location").count().next()).longValue());
+ assertEquals(3L, ((Long) g.V().hasLabel("god").count().next()).longValue());
+ assertEquals(3L, ((Long) g.V().hasLabel("monster").count().next()).longValue());
+
+ assertEquals(17L, ((Long) g.E().count().next()).longValue());
+ assertEquals(2L, ((Long) g.E().hasLabel("father").count().next()).longValue());
+ assertEquals(1L, ((Long) g.E().hasLabel("mother").count().next()).longValue());
+ assertEquals(6L, ((Long) g.E().hasLabel("brother").count().next()).longValue());
+ assertEquals(1L, ((Long) g.E().hasLabel("pet").count().next()).longValue());
+ assertEquals(4L, ((Long) g.E().hasLabel("lives").count().next()).longValue());
+ assertEquals(3L, ((Long) g.E().hasLabel("battled").count().next()).longValue());
+ final float[] place = (float[]) g.V().has("name", "hercules").outE("battled").has("time", 12).values("place")
+ .next();
+ assertNotNull(place);
+ assertEquals(2, place.length);
+ assertEquals(Float.valueOf(39f), Float.valueOf(place[0]));
+ assertEquals(Float.valueOf(22f), Float.valueOf(place[1]));
+ }
+
+ @Test
+ public void updateElements() throws ConfigurationException {
+ app.createElements();
+ assertFalse(g.V().has("name", "jupiter").has("ts").hasNext());
+ app.updateElements();
+ final long ts1 = (long) g.V().has("name", "jupiter").values("ts").next();
+ app.updateElements();
+ final long ts2 = (long) g.V().has("name", "jupiter").values("ts").next();
+ assertTrue(ts2 > ts1);
+ }
+
+ @Test
+ public void deleteElements() {
+ app.createElements();
+ app.deleteElements();
+ assertFalse(g.V().has("name", "pluto").hasNext());
+ assertFalse(g.V().has("name", "jupiter").both("brother").has("name", "pluto").hasNext());
+ }
+}
diff --git a/janusgraph-examples/example-common/src/test/java/org/janusgraph/example/JanusGraphAppTest.java b/janusgraph-examples/example-common/src/test/java/org/janusgraph/example/JanusGraphAppTest.java
new file mode 100644
index 0000000000..355e231510
--- /dev/null
+++ b/janusgraph-examples/example-common/src/test/java/org/janusgraph/example/JanusGraphAppTest.java
@@ -0,0 +1,86 @@
+// Copyright 2017 JanusGraph Authors
+//
+// Licensed 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.janusgraph.example;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.janusgraph.core.Cardinality;
+import org.janusgraph.core.EdgeLabel;
+import org.janusgraph.core.JanusGraph;
+import org.janusgraph.core.JanusGraphVertex;
+import org.janusgraph.core.Multiplicity;
+import org.janusgraph.core.PropertyKey;
+import org.janusgraph.core.attribute.Geoshape;
+import org.janusgraph.core.schema.JanusGraphIndex;
+import org.janusgraph.core.schema.JanusGraphManagement;
+import org.junit.Test;
+
+public class JanusGraphAppTest {
+ protected static final String CONF_FILE = "conf/jgex-inmemory.properties";
+
+ @Test
+ public void createSchema() throws ConfigurationException {
+ final JanusGraphApp app = new JanusGraphApp(CONF_FILE);
+ final GraphTraversalSource g = app.openGraph();
+ app.createSchema();
+ final JanusGraph janusGraph = (JanusGraph) g.getGraph();
+ final JanusGraphManagement mgmt = janusGraph.openManagement();
+
+ final List vertexLabels = StreamSupport.stream(mgmt.getVertexLabels().spliterator(), false)
+ .map(l -> l.name()).collect(Collectors.toList());
+ final List expectedVertexLabels = Stream.of("titan", "location", "god", "demigod", "human", "monster")
+ .collect(Collectors.toList());
+ assertTrue(vertexLabels.containsAll(expectedVertexLabels));
+
+ final List edgeLabels = StreamSupport
+ .stream(mgmt.getRelationTypes(EdgeLabel.class).spliterator(), false).map(l -> l.name())
+ .collect(Collectors.toList());
+ final List expectedEdgeLabels = Stream.of("father", "mother", "brother", "pet", "lives", "battled")
+ .collect(Collectors.toList());
+ assertTrue(edgeLabels.containsAll(expectedEdgeLabels));
+
+ final EdgeLabel father = mgmt.getEdgeLabel("father");
+ assertTrue(father.isDirected());
+ assertFalse(father.isUnidirected());
+ assertEquals(Multiplicity.MANY2ONE, father.multiplicity());
+
+ final List propertyKeys = StreamSupport
+ .stream(mgmt.getRelationTypes(PropertyKey.class).spliterator(), false).map(l -> l.name())
+ .collect(Collectors.toList());
+ final List expectedPropertyKeys = Stream.of("name", "age", "time", "place", "reason")
+ .collect(Collectors.toList());
+ assertTrue(propertyKeys.containsAll(expectedPropertyKeys));
+
+ final PropertyKey place = mgmt.getPropertyKey("place");
+ assertEquals(Cardinality.SINGLE, place.cardinality());
+ assertEquals(Geoshape.class, place.dataType());
+
+ final JanusGraphIndex nameIndex = mgmt.getGraphIndex("nameIndex");
+ assertTrue(nameIndex.isCompositeIndex());
+ assertTrue(nameIndex.getIndexedElement().equals(JanusGraphVertex.class));
+ final PropertyKey[] nameIndexKeys = nameIndex.getFieldKeys();
+ assertEquals(1, nameIndexKeys.length);
+ assertEquals("name", nameIndexKeys[0].name());
+ }
+}
diff --git a/janusgraph-examples/example-common/src/test/resources/log4j.properties b/janusgraph-examples/example-common/src/test/resources/log4j.properties
new file mode 100644
index 0000000000..45af6eb2ab
--- /dev/null
+++ b/janusgraph-examples/example-common/src/test/resources/log4j.properties
@@ -0,0 +1,9 @@
+# A1 is set to be a ConsoleAppender.
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+
+# A1 uses PatternLayout.
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
+
+# Set root logger level to the designated level and its only appender to A1.
+log4j.rootLogger=INFO, A1
diff --git a/janusgraph-examples/example-cql/README.md b/janusgraph-examples/example-cql/README.md
new file mode 100644
index 0000000000..661fc4ab24
--- /dev/null
+++ b/janusgraph-examples/example-cql/README.md
@@ -0,0 +1,51 @@
+# Cassandra CQL Storage, Elasticsearch Index
+
+## About Cassandra and Elasticsearch
+
+[Apache Cassandra](http://cassandra.apache.org/) is a distributed database
+designed for scalability and high availability. Cassandra supports two
+protocols for communications, Thrift (legacy RPC protocol) and CQL (native
+protocol).
+
+[Elasticsearch](https://www.elastic.co/products/elasticsearch) is a scalable,
+distributed search engine.
+
+> Check the JanusGraph [version compatibility](http://docs.janusgraph.org/latest/version-compat.html)
+to ensure you select versions of Cassandra and Elasticsearch compatible with
+this JanusGraph release.
+
+## JanusGraph configuration
+
+* [`jgex-cql.properties`](conf/jgex-cql.properties) contains the Cassandra
+and Elasticsearch server locations. By providing different values for
+`storage.cql.keyspace` and `index.jgex.index-name`, you can store multiple
+graphs on the same Cassandra and Elasticsearch servers. Refer to the JanusGraph
+[configuration reference](http://docs.janusgraph.org/latest/config-ref.html)
+for additional properties.
+
+* [`logback.xml`](conf/logback.xml) configures logging with [Logback](https://logback.qos.ch/),
+which is the logger used by Cassandra. The example configuration logs to the
+console and adjusts the logging level for some noisier packages. Refer to
+the Logback [manual](https://logback.qos.ch/manual/index.html) for additional
+details.
+
+## Run the example
+
+Use [Apache Maven](http://maven.apache.org/) and the [exec-maven-plugin](http://www.mojohaus.org/exec-maven-plugin/java-mojo.html)
+to pull in the required jar files onto the runtime classpath.
+
+```
+$ cd $JANUSGRAPH_HOME/janusgraph-examples/example-cql
+
+$ mvn exec:java -Dexec.mainClass="org.janusgraph.example.JanusGraphApp" -Dlogback.configurationFile="conf/logback.xml" -Dexec.args="conf/jgex-cql.properties"
+```
+
+## Drop the graph
+
+Make sure to stop the application before dropping the graph.
+
+```
+$ cd $JANUSGRAPH_HOME/janusgraph-examples/example-cql
+
+$ mvn exec:java -Dexec.mainClass="org.janusgraph.example.JanusGraphApp" -Dlogback.configurationFile="conf/logback.xml" -Dexec.args="conf/jgex-cql.properties drop"
+```
diff --git a/janusgraph-examples/example-cql/conf/jgex-cql.properties b/janusgraph-examples/example-cql/conf/jgex-cql.properties
new file mode 100644
index 0000000000..77c2965a18
--- /dev/null
+++ b/janusgraph-examples/example-cql/conf/jgex-cql.properties
@@ -0,0 +1,9 @@
+gremlin.graph=org.janusgraph.core.JanusGraphFactory
+
+storage.backend=cql
+storage.cql.keyspace=jgex
+storage.hostname=127.0.0.1
+
+index.jgex.backend=elasticsearch
+index.jgex.index-name=jgex
+index.jgex.hostname=127.0.0.1
diff --git a/janusgraph-examples/example-cql/conf/logback.xml b/janusgraph-examples/example-cql/conf/logback.xml
new file mode 100644
index 0000000000..2bb203a6b0
--- /dev/null
+++ b/janusgraph-examples/example-cql/conf/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %d{HH:mm:ss} %-5level %logger - %msg%n
+
+
+
+
+
+
+
diff --git a/janusgraph-examples/example-cql/pom.xml b/janusgraph-examples/example-cql/pom.xml
new file mode 100644
index 0000000000..87a905aef6
--- /dev/null
+++ b/janusgraph-examples/example-cql/pom.xml
@@ -0,0 +1,37 @@
+
+ 4.0.0
+
+ org.janusgraph
+ janusgraph-examples
+ 0.2.0-SNAPSHOT
+ ../pom.xml
+
+ example-cql
+ pom
+ Example-Cql: C* CQL Storage, ES Index
+ http://janusgraph.org
+
+
+
+
+ org.janusgraph
+ example-common
+ ${project.version}
+ runtime
+
+
+ org.janusgraph
+ janusgraph-cql
+ ${project.version}
+ runtime
+
+
+ org.janusgraph
+ janusgraph-es
+ ${project.version}
+ runtime
+
+
+
+
diff --git a/janusgraph-examples/example-hbase/README.md b/janusgraph-examples/example-hbase/README.md
new file mode 100644
index 0000000000..76133c786b
--- /dev/null
+++ b/janusgraph-examples/example-hbase/README.md
@@ -0,0 +1,172 @@
+# HBase Storage, Solr Index
+
+## About HBase and Solr
+
+[Apache HBase](http://hbase.apache.org/) is a scalable, distributed big data
+store.
+
+[Apache Solr](http://lucene.apache.org/solr/) is a scalable, distributed
+search engine.
+
+> Check the JanusGraph [version compatibility](http://docs.janusgraph.org/latest/version-compat.html)
+to ensure you select versions of HBase and Solr compatible with this
+JanusGraph release.
+
+## JanusGraph configuration
+
+* Be aware that Solr has two configuration options: SolrCloud or HTTP. With
+either option, there is manual configuration required for the Solr cores (config
+sets). Refer to the JanusGraph [Solr documentation](http://docs.janusgraph.org/latest/solr.html)
+for additional details.
+
+ * [`jgex-hbase-solr-cloud.properties`](conf/jgex-hbase-solr-cloud.properties)
+ contains the HBase and SolrCloud server locations.
+
+ * [`jgex-hbase-solr-http.properties`](conf/jgex-hbase-solr-http.properties)
+ contains the HBase and Solr HTTP server locations
+
+* By providing different values for `storage.hbase.table` and `index.jgex.index-name`,
+you can store multiple graphs on the same HBase and Solr servers. Refer to
+the JanusGraph [configuration reference](http://docs.janusgraph.org/latest/config-ref.html)
+for additional properties.
+
+* [`logback.xml`](conf/logback.xml) configures logging with [Logback](https://logback.qos.ch/).
+The example configuration logs to the console and adjusts the logging level
+for some noisier packages. Refer to the Logback [manual](https://logback.qos.ch/manual/index.html)
+for additional details.
+
+## Run the example
+
+Use [Apache Maven](http://maven.apache.org/) and the [exec-maven-plugin](http://www.mojohaus.org/exec-maven-plugin/java-mojo.html)
+to pull in the required jar files onto the runtime classpath.
+
+
+## HBase and SolrCloud
+
+### Upload the configset to Zookeeper
+
+Using a configset makes it possible to reuse the same configuration for new
+cores. The configset is stored in Zookeeper under `/configs/jgex` where the
+name `jgex` matches the properties file value for `index.jgex.solr.configset`.
+Make sure the Zookeeper url matches the properties value for `index.jgex.solr.zookeeper-url`.
+
+```
+$ cd $SOLR_HOME
+
+$ server/scripts/cloud-scripts/zkcli.sh -z 127.0.0.1:9983 -cmd upconfig -d $JANUSGRAPH_HOME/conf/solr -n jgex
+```
+
+### Run the program
+
+```
+$ cd $JANUSGRAPH_HOME/janusgraph-examples/example-hbase
+
+$ mvn exec:java -Dexec.mainClass="org.janusgraph.example.JanusGraphApp" -Dlogback.configurationFile="conf/logback.xml" -Dexec.args="conf/jgex-hbase-solr-cloud.properties"
+```
+
+### Drop the graph
+
+Make sure to stop the application before dropping the graph.
+
+```
+$ cd $JANUSGRAPH_HOME/janusgraph-examples/example-hbase
+
+$ mvn exec:java -Dexec.mainClass="org.janusgraph.example.JanusGraphApp" -Dlogback.configurationFile="conf/logback.xml" -Dexec.args="conf/jgex-hbase-solr-cloud.properties drop"
+```
+
+### Remove the configset from Zookeeper
+
+The configset is stored in Zookeeper under `/configs/jgex` where the name
+`jgex` matches the properties file value for `index.jgex.solr.configset`.
+Make sure the Zookeeper url matches the properties value for `index.jgex.solr.zookeeper-url`.
+
+```
+$ cd $SOLR_HOME
+
+$ server/scripts/cloud-scripts/zkcli.sh -z 127.0.0.1:9983 -cmd clear /configs/jgex
+```
+
+
+## HBase and Solr HTTP
+
+### Create the Solr cores
+
+The core names match the `vAge` or `eReasonPlace` values when `mgmt.buildIndex()`
+defines the mixed indexes in `JanusGraphApp.createMixedIndexes()`
+
+```
+$ cd $SOLR_HOME
+
+$ bin/solr create_core -d $JANUSGRAPH_HOME/conf/solr -c vAge
+
+Copying configuration to new core instance directory:
+/usr/lib/solr-5.5.4/server/solr/vAge
+
+Creating new core 'vAge' using command:
+http://localhost:8983/solr/admin/cores?action=CREATE&name=vAge&instanceDir=vAge
+
+{
+ "responseHeader":{
+ "status":0,
+ "QTime":577},
+ "core":"vAge"}
+
+$ bin/solr create_core -d $JANUSGRAPH_HOME/conf/solr -c eReasonPlace
+
+Copying configuration to new core instance directory:
+/usr/lib/solr-5.5.4/server/solr/eReasonPlace
+
+Creating new core 'eReasonPlace' using command:
+http://localhost:8983/solr/admin/cores?action=CREATE&name=eReasonPlace&instanceDir=eReasonPlace
+
+{
+ "responseHeader":{
+ "status":0,
+ "QTime":116},
+ "core":"eReasonPlace"}
+```
+
+### Run the program
+
+```
+$ cd $JANUSGRAPH_HOME/janusgraph-examples/example-hbase
+
+$ mvn exec:java -Dexec.mainClass="org.janusgraph.example.JanusGraphApp" -Dlogback.configurationFile="conf/logback.xml" -Dexec.args="conf/jgex-hbase-solr-http.properties"
+```
+
+### Drop the graph
+
+Make sure to stop the application before dropping the graph.
+
+```
+$ cd $JANUSGRAPH_HOME/janusgraph-examples/example-hbase
+
+$ mvn exec:java -Dexec.mainClass="org.janusgraph.example.JanusGraphApp" -Dlogback.configurationFile="conf/logback.xml" -Dexec.args="conf/jgex-hbase-solr-http.properties drop"
+```
+
+### Drop the Solr cores
+
+The core names match the `vAge` or `eReasonPlace` values when `mgmt.buildIndex()`
+defines the mixed indexes in `JanusGraphApp.createMixedIndexes()`
+
+```
+$ cd $SOLR_HOME
+
+$ bin/solr delete -c vAge
+
+Deleting core 'vAge' using command:
+http://localhost:8983/solr/admin/cores?action=UNLOAD&core=vAge&deleteIndex=true&deleteDataDir=true&deleteInstanceDir=true
+
+{"responseHeader":{
+ "status":0,
+ "QTime":7}}
+
+$ bin/solr delete -c eReasonPlace
+
+Deleting core 'eReasonPlace' using command:
+http://localhost:8983/solr/admin/cores?action=UNLOAD&core=eReasonPlace&deleteIndex=true&deleteDataDir=true&deleteInstanceDir=true
+
+{"responseHeader":{
+ "status":0,
+ "QTime":9}}
+```
diff --git a/janusgraph-examples/example-hbase/conf/jgex-hbase-solr-cloud.properties b/janusgraph-examples/example-hbase/conf/jgex-hbase-solr-cloud.properties
new file mode 100644
index 0000000000..f1ef6ee676
--- /dev/null
+++ b/janusgraph-examples/example-hbase/conf/jgex-hbase-solr-cloud.properties
@@ -0,0 +1,20 @@
+gremlin.graph=org.janusgraph.core.JanusGraphFactory
+
+storage.backend=hbase
+storage.hbase.table=jgex
+storage.hostname=127.0.0.1
+#storage.hbase.ext.hbase.zookeeper.property.clientPort=2181
+# Some HBase installations may have this set to another value,
+# such as /hbase-unsecure or /hbase-secure
+#storage.hbase.ext.zookeeper.znode.parent=/hbase
+
+index.jgex.backend=solr
+index.jgex.index-name=jgex
+index.jgex.hostname=127.0.0.1
+
+index.jgex.solr.mode=cloud
+index.jgex.solr.configset=jgex
+# Make sure the port matches the Zookeeper that SolrCloud is using.
+# If using Solr's embedded Zookeeper, the default port is 9983.
+# If using an external Zookeeper, the default port is 2181.
+index.jgex.solr.zookeeper-url=127.0.0.1:9983
diff --git a/janusgraph-examples/example-hbase/conf/jgex-hbase-solr-http.properties b/janusgraph-examples/example-hbase/conf/jgex-hbase-solr-http.properties
new file mode 100644
index 0000000000..4c58e0cb69
--- /dev/null
+++ b/janusgraph-examples/example-hbase/conf/jgex-hbase-solr-http.properties
@@ -0,0 +1,16 @@
+gremlin.graph=org.janusgraph.core.JanusGraphFactory
+
+storage.backend=hbase
+storage.hbase.table=jgex
+storage.hostname=127.0.0.1
+#storage.hbase.ext.hbase.zookeeper.property.clientPort=2181
+# Some HBase installations may have this set to another value,
+# such as /hbase-unsecure or /hbase-secure
+#storage.hbase.ext.zookeeper.znode.parent=/hbase
+
+index.jgex.backend=solr
+index.jgex.index-name=jgex
+index.jgex.hostname=127.0.0.1
+
+index.jgex.solr.mode=http
+index.jgex.solr.http-urls=http://127.0.0.1:8983/solr
diff --git a/janusgraph-examples/example-hbase/conf/logback.xml b/janusgraph-examples/example-hbase/conf/logback.xml
new file mode 100644
index 0000000000..9221a400b3
--- /dev/null
+++ b/janusgraph-examples/example-hbase/conf/logback.xml
@@ -0,0 +1,17 @@
+
+
+
+
+ %d{HH:mm:ss} %-5level %logger - %msg%n
+
+
+
+
+
+
+
+
+
+
+
diff --git a/janusgraph-examples/example-hbase/pom.xml b/janusgraph-examples/example-hbase/pom.xml
new file mode 100644
index 0000000000..ce4e0b8e10
--- /dev/null
+++ b/janusgraph-examples/example-hbase/pom.xml
@@ -0,0 +1,43 @@
+
+ 4.0.0
+
+ org.janusgraph
+ janusgraph-examples
+ 0.2.0-SNAPSHOT
+ ../pom.xml
+
+ example-hbase
+ pom
+ Example-HBase: HBase Storage, Solr Index
+ http://janusgraph.org
+
+
+
+
+ org.janusgraph
+ example-common
+ ${project.version}
+ runtime
+
+
+ org.janusgraph
+ janusgraph-hbase
+ ${project.version}
+ runtime
+
+
+ org.apache.hbase
+ hbase-client
+ ${hbase100.version}
+ runtime
+
+
+ org.janusgraph
+ janusgraph-solr
+ ${project.version}
+ runtime
+
+
+
+
diff --git a/janusgraph-examples/example-remotegraph/README.md b/janusgraph-examples/example-remotegraph/README.md
new file mode 100644
index 0000000000..ce545d1322
--- /dev/null
+++ b/janusgraph-examples/example-remotegraph/README.md
@@ -0,0 +1,75 @@
+# Remote Graph
+
+## About Remote Graph
+
+[Gremlin Server](http://tinkerpop.apache.org/docs/3.2.6/reference/#gremlin-server)
+allows a JanusGraph instance to run on a standalone server. This enables
+multiple clients to connect to the same JanusGraph instance. It also allows
+clients to connect via non-JVM languages. By default, the Gremlin Server
+communicates over WebSocket.
+
+A Java program can connect to the Gremlin Server in two ways:
+* [Gremlin Driver](http://tinkerpop.apache.org/docs/3.2.6/reference/#connecting-via-java)
+client. Sumbit scripts as a `String` for evaluation on the server.
+* [Remote Graph](http://tinkerpop.apache.org/docs/3.2.6/reference/#connecting-via-remotegraph)
+uses the same client connection but enables you to compose queries as code.
+
+## JanusGraph configuration
+
+### Gremlin Server configuration
+
+* Select a specific storage backend to use, then copy its configuration into
+the `$JANUSGRAPH_HOME/conf/gremlin-server/` directory
+
+* Update the `$JANUSGRAPH_HOME/conf/gremlin-server/gremlin-server.yaml` to
+use the configuration file
+
+ ```
+ graphs: {
+ graph: conf/gremlin-server/jgex-cql.properties
+ }
+ ```
+
+* Note the default `$JANUSGRAPH_HOME/conf/gremlin-server/gremlin-server.yaml`
+uses the script `scripts/empty-graph.groovy` to define the graph traversal source
+`g` for the graph `g: graph.traversal()`
+
+### Remote Graph configuration
+
+* [`jgex-remote.properties`](conf/jgex-remote.properties) contains the remote
+connection class, the Gremlin Driver configuration file location, and the graph
+traversal source name. Refer to the [Remote Graph documentation](http://tinkerpop.apache.org/docs/3.2.6/reference/#connecting-via-remotegraph)
+for additional details.
+
+* [`remote-objects.yaml`](conf/remote-objects.yaml) contains server location
+and serializer options. The default serializer is Gryo, and it is important
+that the server is configured with the same serializer. Refer to the
+[Gremlin Driver documentation](http://tinkerpop.apache.org/docs/3.2.6/reference/#_configuration)
+for additional properties.
+
+## Running the example
+
+### Starting the Gremlin Server
+
+Start the Gremlin Server with the preferred storage configuration. The graph
+instance will be created if it did not previously exist. Make sure to check
+the server logs for errors.
+
+```
+$ cd $JANUSGRAPH_HOME
+
+$ bin/gremlin-server.sh conf/gremlin-server/gremlin-server.yaml
+```
+
+### Running the remote graph example
+
+```
+$ cd $JANUSGRAPH_HOME/janusgraph-examples/example-remotegraph
+
+$ mvn exec:java -Dexec.mainClass="org.janusgraph.example.RemoteGraphApp" -Dexec.args="conf/jgex-remote.properties"
+```
+
+## Drop the graph
+
+Make sure to stop the Gremlin Server before dropping the graph. Follow the
+directions for the specific storage backend.
diff --git a/janusgraph-examples/example-remotegraph/conf/jgex-remote.properties b/janusgraph-examples/example-remotegraph/conf/jgex-remote.properties
new file mode 100644
index 0000000000..6963e9b128
--- /dev/null
+++ b/janusgraph-examples/example-remotegraph/conf/jgex-remote.properties
@@ -0,0 +1,5 @@
+gremlin.remote.remoteConnectionClass=org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection
+# cluster file has the remote server configuration
+gremlin.remote.driver.clusterFile=conf/remote-objects.yaml
+# source name is the global graph traversal source defined on the server
+gremlin.remote.driver.sourceName=g
diff --git a/janusgraph-examples/example-remotegraph/conf/remote-objects.yaml b/janusgraph-examples/example-remotegraph/conf/remote-objects.yaml
new file mode 100644
index 0000000000..e68afdfafb
--- /dev/null
+++ b/janusgraph-examples/example-remotegraph/conf/remote-objects.yaml
@@ -0,0 +1,8 @@
+hosts: [127.0.0.1]
+port: 8182
+serializer: {
+ className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0,
+ config: {
+ ioRegistries: [org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry]
+ }
+}
diff --git a/janusgraph-examples/example-remotegraph/pom.xml b/janusgraph-examples/example-remotegraph/pom.xml
new file mode 100644
index 0000000000..5feb9b2690
--- /dev/null
+++ b/janusgraph-examples/example-remotegraph/pom.xml
@@ -0,0 +1,33 @@
+
+ 4.0.0
+
+ org.janusgraph
+ janusgraph-examples
+ 0.2.0-SNAPSHOT
+ ../pom.xml
+
+ example-remotegraph
+ Example-RemoteGraph: Example with RemoteGraph
+ http://janusgraph.org
+
+
+
+ org.janusgraph
+ example-common
+ ${project.version}
+
+
+ org.apache.tinkerpop
+ gremlin-driver
+ ${tinkerpop.version}
+
+
+ org.apache.tinkerpop
+ gremlin-server
+ ${tinkerpop.version}
+ test
+
+
+
+
diff --git a/janusgraph-examples/example-remotegraph/src/main/java/org/janusgraph/example/RemoteGraphApp.java b/janusgraph-examples/example-remotegraph/src/main/java/org/janusgraph/example/RemoteGraphApp.java
new file mode 100644
index 0000000000..899af41bb5
--- /dev/null
+++ b/janusgraph-examples/example-remotegraph/src/main/java/org/janusgraph/example/RemoteGraphApp.java
@@ -0,0 +1,196 @@
+// Copyright 2017 JanusGraph Authors
+//
+// Licensed 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.janusgraph.example;
+
+import java.util.stream.Stream;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.tinkerpop.gremlin.driver.Client;
+import org.apache.tinkerpop.gremlin.driver.Cluster;
+import org.apache.tinkerpop.gremlin.driver.Result;
+import org.apache.tinkerpop.gremlin.driver.ResultSet;
+import org.apache.tinkerpop.gremlin.process.traversal.Bindings;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.janusgraph.core.JanusGraph;
+import org.janusgraph.core.attribute.Geoshape;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RemoteGraphApp extends JanusGraphApp {
+ private static final Logger LOGGER = LoggerFactory.getLogger(RemoteGraphApp.class);
+
+ // used for bindings
+ private static final String NAME = "name";
+ private static final String AGE = "age";
+ private static final String TIME = "time";
+ private static final String REASON = "reason";
+ private static final String PLACE = "place";
+ private static final String LABEL = "label";
+ private static final String OUT_V = "outV";
+ private static final String IN_V = "inV";
+
+ protected JanusGraph janusgraph;
+ protected Cluster cluster;
+ protected Client client;
+ protected Configuration conf;
+
+ /**
+ * Constructs a graph app using the given properties.
+ * @param fileName location of the properties file
+ */
+ public RemoteGraphApp(final String fileName) {
+ super(fileName);
+ // the server auto-commits per request, so the application code doesn't
+ // need to explicitly commit transactions
+ this.supportsTransactions = false;
+ }
+
+ @Override
+ public GraphTraversalSource openGraph() throws ConfigurationException {
+ LOGGER.info("opening graph");
+ conf = new PropertiesConfiguration(propFileName);
+
+ // using the remote driver for schema
+ try {
+ cluster = Cluster.open(conf.getString("gremlin.remote.driver.clusterFile"));
+ client = cluster.connect();
+ } catch (Exception e) {
+ throw new ConfigurationException(e);
+ }
+
+ // using the remote graph for queries
+ graph = EmptyGraph.instance();
+ g = graph.traversal().withRemote(conf);
+ return g;
+ }
+
+ @Override
+ public void createElements() {
+ LOGGER.info("creating elements");
+
+ // Use bindings to allow the Gremlin Server to cache traversals that
+ // will be reused with different parameters. This minimizes the
+ // number of scripts that need to be compiled and cached on the server.
+ // http://tinkerpop.apache.org/docs/3.2.6/reference/#parameterized-scripts
+ final Bindings b = Bindings.instance();
+
+ // see GraphOfTheGodsFactory.java
+
+ Vertex saturn = g.addV(b.of(LABEL, "titan")).property(NAME, b.of(NAME, "saturn"))
+ .property(AGE, b.of(AGE, 10000)).next();
+ Vertex sky = g.addV(b.of(LABEL, "location")).property(NAME, b.of(NAME, "sky")).next();
+ Vertex sea = g.addV(b.of(LABEL, "location")).property(NAME, b.of(NAME, "sea")).next();
+ Vertex jupiter = g.addV(b.of(LABEL, "god")).property(NAME, b.of(NAME, "jupiter")).property(AGE, b.of(AGE, 5000))
+ .next();
+ Vertex neptune = g.addV(b.of(LABEL, "god")).property(NAME, b.of(NAME, "neptune")).property(AGE, b.of(AGE, 4500))
+ .next();
+ Vertex hercules = g.addV(b.of(LABEL, "demigod")).property(NAME, b.of(NAME, "hercules"))
+ .property(AGE, b.of(AGE, 30)).next();
+ Vertex alcmene = g.addV(b.of(LABEL, "human")).property(NAME, b.of(NAME, "alcmene")).property(AGE, b.of(AGE, 45))
+ .next();
+ Vertex pluto = g.addV(b.of(LABEL, "god")).property(NAME, b.of(NAME, "pluto")).property(AGE, b.of(AGE, 4000))
+ .next();
+ Vertex nemean = g.addV(b.of(LABEL, "monster")).property(NAME, b.of(NAME, "nemean")).next();
+ Vertex hydra = g.addV(b.of(LABEL, "monster")).property(NAME, b.of(NAME, "hydra")).next();
+ Vertex cerberus = g.addV(b.of(LABEL, "monster")).property(NAME, b.of(NAME, "cerberus")).next();
+ Vertex tartarus = g.addV(b.of(LABEL, "location")).property(NAME, b.of(NAME, "tartarus")).next();
+
+ g.V(b.of(OUT_V, jupiter)).as("a").V(b.of(IN_V, saturn)).addE(b.of(LABEL, "father")).from("a").next();
+ g.V(b.of(OUT_V, jupiter)).as("a").V(b.of(IN_V, sky)).addE(b.of(LABEL, "lives"))
+ .property(REASON, b.of(REASON, "loves fresh breezes")).from("a").next();
+ g.V(b.of(OUT_V, jupiter)).as("a").V(b.of(IN_V, neptune)).addE(b.of(LABEL, "brother")).from("a").next();
+ g.V(b.of(OUT_V, jupiter)).as("a").V(b.of(IN_V, pluto)).addE(b.of(LABEL, "brother")).from("a").next();
+
+ g.V(b.of(OUT_V, neptune)).as("a").V(b.of(IN_V, sea)).addE(b.of(LABEL, "lives"))
+ .property(REASON, b.of(REASON, "loves waves")).from("a").next();
+ g.V(b.of(OUT_V, neptune)).as("a").V(b.of(IN_V, jupiter)).addE(b.of(LABEL, "brother")).from("a").next();
+ g.V(b.of(OUT_V, neptune)).as("a").V(b.of(IN_V, pluto)).addE(b.of(LABEL, "brother")).from("a").next();
+
+ g.V(b.of(OUT_V, hercules)).as("a").V(b.of(IN_V, jupiter)).addE(b.of(LABEL, "father")).from("a").next();
+ g.V(b.of(OUT_V, hercules)).as("a").V(b.of(IN_V, alcmene)).addE(b.of(LABEL, "mother")).from("a").next();
+
+ if (supportsGeoshape) {
+ g.V(b.of(OUT_V, hercules)).as("a").V(b.of(IN_V, nemean)).addE(b.of(LABEL, "battled"))
+ .property(TIME, b.of(TIME, 1)).property(PLACE, b.of(PLACE, Geoshape.point(38.1f, 23.7f))).from("a")
+ .next();
+ g.V(b.of(OUT_V, hercules)).as("a").V(b.of(IN_V, hydra)).addE(b.of(LABEL, "battled"))
+ .property(TIME, b.of(TIME, 2)).property(PLACE, b.of(PLACE, Geoshape.point(37.7f, 23.9f))).from("a")
+ .next();
+ g.V(b.of(OUT_V, hercules)).as("a").V(b.of(IN_V, cerberus)).addE(b.of(LABEL, "battled"))
+ .property(TIME, b.of(TIME, 12)).property(PLACE, b.of(PLACE, Geoshape.point(39f, 22f))).from("a")
+ .next();
+ } else {
+ g.V(b.of(OUT_V, hercules)).as("a").V(b.of(IN_V, nemean)).addE(b.of(LABEL, "battled"))
+ .property(TIME, b.of(TIME, 1)).property(PLACE, b.of(PLACE, getGeoFloatArray(38.1f, 23.7f)))
+ .from("a").next();
+ g.V(b.of(OUT_V, hercules)).as("a").V(b.of(IN_V, hydra)).addE(b.of(LABEL, "battled"))
+ .property(TIME, b.of(TIME, 2)).property(PLACE, b.of(PLACE, getGeoFloatArray(37.7f, 23.9f)))
+ .from("a").next();
+ g.V(b.of(OUT_V, hercules)).as("a").V(b.of(IN_V, cerberus)).addE(b.of(LABEL, "battled"))
+ .property(TIME, b.of(TIME, 12)).property(PLACE, b.of(PLACE, getGeoFloatArray(39f, 22f))).from("a")
+ .next();
+ }
+
+ g.V(b.of(OUT_V, pluto)).as("a").V(b.of(IN_V, jupiter)).addE(b.of(LABEL, "brother")).from("a").next();
+ g.V(b.of(OUT_V, pluto)).as("a").V(b.of(IN_V, neptune)).addE(b.of(LABEL, "brother")).from("a").next();
+ g.V(b.of(OUT_V, pluto)).as("a").V(b.of(IN_V, tartarus)).addE(b.of(LABEL, "lives"))
+ .property(REASON, b.of(REASON, "no fear of death")).from("a").next();
+ g.V(b.of(OUT_V, pluto)).as("a").V(b.of(IN_V, cerberus)).addE(b.of(LABEL, "pet")).from("a").next();
+
+ g.V(b.of(OUT_V, cerberus)).as("a").V(b.of(IN_V, tartarus)).addE(b.of(LABEL, "lives")).from("a").next();
+ }
+
+ @Override
+ public void closeGraph() throws Exception {
+ LOGGER.info("closing graph");
+ try {
+ if (g != null) {
+ // this closes the remote, no need to close the empty graph
+ g.close();
+ }
+ if (cluster != null) {
+ // the cluster closes all of its clients
+ cluster.close();
+ }
+ } finally {
+ g = null;
+ graph = null;
+ client = null;
+ cluster = null;
+ }
+ }
+
+ @Override
+ public void createSchema() {
+ LOGGER.info("creating schema");
+ // get the schema request as a string
+ final String req = createSchemaRequest();
+ // submit the request to the server
+ final ResultSet resultSet = client.submit(req);
+ // drain the results completely
+ Stream futureList = resultSet.stream();
+ futureList.map(result -> result.toString()).forEach(LOGGER::info);
+ }
+
+ public static void main(String[] args) {
+ final String fileName = (args != null && args.length > 0) ? args[0] : null;
+ final RemoteGraphApp app = new RemoteGraphApp(fileName);
+ app.runApp();
+ }
+}
diff --git a/janusgraph-examples/example-tinkergraph/README.md b/janusgraph-examples/example-tinkergraph/README.md
new file mode 100644
index 0000000000..295aaed9ff
--- /dev/null
+++ b/janusgraph-examples/example-tinkergraph/README.md
@@ -0,0 +1,26 @@
+# TinkerGraph
+
+## About TinkerGraph
+
+[TinkerGraph](http://tinkerpop.apache.org/docs/3.2.6/reference/#tinkergraph-gremlin)
+is the in-memory reference implementation of the Apache TinkerPop Graph API.
+It can be useful with small graphs to prototype out a graph structure and
+queries against it. It can also be useful as a comparison when debugging to
+help determine whether a particular issue is in the graph traversal logic
+or whether it is a JanusGraph-specific issue.
+
+## TinkerGraph configuration
+
+[`jgex-tinkergraph.properties`](conf/jgex-tinkergraph.properties) contains
+the id manager settings for the graph.
+
+Refer to the TinkerGraph [configuration reference](http://tinkerpop.apache.org/docs/3.2.6/reference/#_configuration_3)
+for additional properties.
+
+## Running the example
+
+```
+$ cd $JANUSGRAPH_HOME/janusgraph-examples/example-tinkergraph
+
+$ mvn exec:java -Dexec.mainClass="org.janusgraph.example.TinkerGraphApp" -Dexec.args="conf/jgex-tinkergraph.properties"
+```
diff --git a/janusgraph-examples/example-tinkergraph/conf/jgex-tinkergraph.properties b/janusgraph-examples/example-tinkergraph/conf/jgex-tinkergraph.properties
new file mode 100644
index 0000000000..cf06ea7ec2
--- /dev/null
+++ b/janusgraph-examples/example-tinkergraph/conf/jgex-tinkergraph.properties
@@ -0,0 +1,6 @@
+gremlin.graph=org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph
+
+# DefaultIdManager types: INTEGER, LONG, UUID, ANY
+gremlin.tinkergraph.edgeIdManager=INTEGER
+gremlin.tinkergraph.vertexIdManager=INTEGER
+gremlin.tinkergraph.vertexPropertyIdManager=INTEGER
diff --git a/janusgraph-examples/example-tinkergraph/pom.xml b/janusgraph-examples/example-tinkergraph/pom.xml
new file mode 100644
index 0000000000..d9a150bfc7
--- /dev/null
+++ b/janusgraph-examples/example-tinkergraph/pom.xml
@@ -0,0 +1,27 @@
+
+ 4.0.0
+
+ org.janusgraph
+ janusgraph-examples
+ 0.2.0-SNAPSHOT
+ ../pom.xml
+
+ example-tinkergraph
+ Example-TinkerGraph: Example with TinkerGraph
+ http://janusgraph.org
+
+
+
+ org.janusgraph
+ example-common
+ ${project.version}
+
+
+ org.apache.tinkerpop
+ tinkergraph-gremlin
+ ${tinkerpop.version}
+
+
+
+
diff --git a/janusgraph-examples/example-tinkergraph/src/main/java/org/janusgraph/example/TinkerGraphApp.java b/janusgraph-examples/example-tinkergraph/src/main/java/org/janusgraph/example/TinkerGraphApp.java
new file mode 100644
index 0000000000..2cc2de3190
--- /dev/null
+++ b/janusgraph-examples/example-tinkergraph/src/main/java/org/janusgraph/example/TinkerGraphApp.java
@@ -0,0 +1,51 @@
+// Copyright 2017 JanusGraph Authors
+//
+// Licensed 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.janusgraph.example;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TinkerGraphApp extends GraphApp {
+ private static final Logger LOGGER = LoggerFactory.getLogger(TinkerGraphApp.class);
+
+ /**
+ * Constructs a graph app using the given properties.
+ * @param fileName location of the properties file
+ */
+ public TinkerGraphApp(final String fileName) {
+ super(fileName);
+ this.supportsSchema = true;
+ this.supportsTransactions = false;
+ this.supportsGeoshape = false;
+ }
+
+ @Override
+ public void createSchema() {
+ LOGGER.info("creating schema");
+ final TinkerGraph tinkerGraph = (TinkerGraph) graph;
+ // naive check if the schema was previously created
+ if (!tinkerGraph.getIndexedKeys(Vertex.class).iterator().hasNext()) {
+ tinkerGraph.createIndex("name", Vertex.class);
+ }
+ }
+
+ public static void main(String[] args) {
+ final String fileName = (args != null && args.length > 0) ? args[0] : null;
+ final TinkerGraphApp app = new TinkerGraphApp(fileName);
+ app.runApp();
+ }
+}
diff --git a/janusgraph-examples/example-tinkergraph/src/test/java/org/janusgraph/example/TinkerGraphAppTest.java b/janusgraph-examples/example-tinkergraph/src/test/java/org/janusgraph/example/TinkerGraphAppTest.java
new file mode 100644
index 0000000000..f9c6e6b9f7
--- /dev/null
+++ b/janusgraph-examples/example-tinkergraph/src/test/java/org/janusgraph/example/TinkerGraphAppTest.java
@@ -0,0 +1,44 @@
+// Copyright 2017 JanusGraph Authors
+//
+// Licensed 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.janusgraph.example;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Set;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerEdge;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerVertex;
+import org.junit.Test;
+
+public class TinkerGraphAppTest {
+ protected static final String CONF_FILE = "conf/jgex-tinkergraph.properties";
+
+ @Test
+ public void createSchema() throws ConfigurationException {
+ final TinkerGraphApp app = new TinkerGraphApp(CONF_FILE);
+ final GraphTraversalSource g = app.openGraph();
+ app.createSchema();
+ final TinkerGraph tinkerGraph = (TinkerGraph) g.getGraph();
+ final Set vertexIndexes = tinkerGraph.getIndexedKeys(TinkerVertex.class);
+ assertEquals(1, vertexIndexes.size());
+ assertEquals("name", vertexIndexes.toArray()[0]);
+ final Set edgeIndexes = tinkerGraph.getIndexedKeys(TinkerEdge.class);
+ assertTrue(edgeIndexes.isEmpty());
+ }
+}
diff --git a/janusgraph-examples/example-tinkergraph/src/test/resources/log4j.properties b/janusgraph-examples/example-tinkergraph/src/test/resources/log4j.properties
new file mode 100644
index 0000000000..45af6eb2ab
--- /dev/null
+++ b/janusgraph-examples/example-tinkergraph/src/test/resources/log4j.properties
@@ -0,0 +1,9 @@
+# A1 is set to be a ConsoleAppender.
+log4j.appender.A1=org.apache.log4j.ConsoleAppender
+
+# A1 uses PatternLayout.
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
+
+# Set root logger level to the designated level and its only appender to A1.
+log4j.rootLogger=INFO, A1
diff --git a/janusgraph-examples/pom.xml b/janusgraph-examples/pom.xml
new file mode 100644
index 0000000000..45ac5ffe8b
--- /dev/null
+++ b/janusgraph-examples/pom.xml
@@ -0,0 +1,34 @@
+
+ 4.0.0
+
+ org.janusgraph
+ janusgraph
+ 0.2.0-SNAPSHOT
+ ../pom.xml
+
+ janusgraph-examples
+ pom
+ JanusGraph-Examples: Examples for JanusGraph
+ http://janusgraph.org
+
+
+ example-common
+ example-berkeleyje
+ example-cassandra
+ example-cql
+ example-hbase
+ example-remotegraph
+ example-tinkergraph
+
+
+
+
+ org.janusgraph
+ janusgraph-test
+ ${project.version}
+ test
+
+
+
+
diff --git a/pom.xml b/pom.xml
index 51af770398..9a15194372 100644
--- a/pom.xml
+++ b/pom.xml
@@ -136,6 +136,7 @@
janusgraph-dist
janusgraph-doc
janusgraph-solr
+ janusgraph-examples