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/11/05 17:53:47 UTC

incubator-tinkerpop git commit: TINKERPOP3-914 Gremlin Console :remote to Gremlin Server supports alias

Repository: incubator-tinkerpop
Updated Branches:
  refs/heads/TINKERPOP3-914 [created] 2c7823e8a


TINKERPOP3-914 Gremlin Console :remote to Gremlin Server supports alias

Added a "alias" option to :remote config that lets the user supply key/value pairs representing the aliases.  Included "show" and "reset" options as well.  Updated docs which generate nicely.


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

Branch: refs/heads/TINKERPOP3-914
Commit: 2c7823e8abc9dc3214c33296b58182a9bf961882
Parents: e30b70e
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Nov 5 11:52:55 2015 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Nov 5 11:52:55 2015 -0500

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 docs/src/gremlin-applications.asciidoc          | 27 +++++++++++++
 .../upgrade-release-3.1.x-incubating.asciidoc   | 23 ++++++++++-
 .../groovy/plugin/DriverRemoteAcceptor.java     | 38 +++++++++++++++++--
 .../DriverRemoteAcceptorIntegrateTest.java      |  8 ++++
 .../groovy/plugin/DriverRemoteAcceptorTest.java | 40 ++++++++++++++++++++
 .../apache/tinkerpop/gremlin/driver/Client.java | 24 ++++++++++++
 .../tinkerpop/gremlin/driver/Cluster.java       |  8 ++--
 8 files changed, 159 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2c7823e8/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 9f0e18e..1d51d48 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -27,6 +27,7 @@ TinkerPop 3.1.0 (NOT OFFICIALLY RELEASED YET)
 
 * Optimized `BulkLoaderVertexProgram`. It now uses `EventStrategy` to monitor what the underlying `BulkLoader` implementation does (e.g. whether it creates a new vertex or returns an existing).
 * Integrated `NumberHelper` in `SumStep`, `MinStep`, `MaxStep` and `MeanStep` (local and global step variants).
+* Gremlin Console remoting to Gremlin Server now supports a configuration option for assigning aliases.
 * `CountMatchAlgorithm`, in OLAP, now biases traversal selection towards those traversals that start at the current traverser location to reduce message passing.
 * Fixed a file stream bug in Hadoop OLTP that showed up if the streamed file was more than 2G of data.
 * Added the ability to set thread local properties in `SparkGraphComputer` when using a persistent context.

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2c7823e8/docs/src/gremlin-applications.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/gremlin-applications.asciidoc b/docs/src/gremlin-applications.asciidoc
index 88684ab..798ff81 100644
--- a/docs/src/gremlin-applications.asciidoc
+++ b/docs/src/gremlin-applications.asciidoc
@@ -438,6 +438,33 @@ submitting `:> graph` will return a `Graph` instance and in most cases those are
 and will return a serialization error.  It should be noted that `TinkerGraph`, as a convenience for shipping around
 small sub-graphs, is serializable from Gremlin Server.
 
+The Gremlin Server `:remote` command has the following configuration options:
+
+[width="100%",cols="3,10a",options="header"]
+|=========================================================
+|Command |Description
+|alias |
+[width="100%",cols="3,10",options="header"]
+!=========================================================
+!Option !Description
+! _pairs_ !A set of key/value alias/binding pairs to apply to requests.
+!`reset` !Clears any aliases that were supplied in previous configurations of the remote.
+!`show` !Shows the current set of aliases which is returned as a `Map`
+!=========================================================
+|timeout |Specifies the length of time in milliseconds that the remote will wait for a response from the server.
+|=========================================================
+
+The `alias` configuration command for the Gremlin Server `:remote` can be useful in situations where there are
+multiple `Graph` or `TraversalSource` instances on the server, as it becomes possible to rename them from the client
+for purposes of execution within the context of a script.  Therefore, it becomes possible to submit commands this way:
+
+[gremlin-groovy]
+----
+:remote connect tinkerpop.server conf/remote-objects.yaml
+:remote config alias x g
+:> x.E().label().groupCount()
+----
+
 Connecting via Java
 ~~~~~~~~~~~~~~~~~~~
 

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2c7823e8/docs/src/upgrade-release-3.1.x-incubating.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/upgrade-release-3.1.x-incubating.asciidoc b/docs/src/upgrade-release-3.1.x-incubating.asciidoc
index ada54f9..b0601b2 100644
--- a/docs/src/upgrade-release-3.1.x-incubating.asciidoc
+++ b/docs/src/upgrade-release-3.1.x-incubating.asciidoc
@@ -85,7 +85,6 @@ TinkerGraph-Gremlin Updates
 
 * The `public static String` configurations have been renamed. The old `public static` variables have been deprecated.
 
-
 Gremlin Process
 ^^^^^^^^^^^^^^^
 
@@ -108,12 +107,32 @@ Graph Traversal Updates
 ** Use `select(keys)` and `select(columns)`. However, note that `select()` will not unroll the keys/values. Thus, `mapKeys()` => `select(keys).unfold()`.
 
 Gremlin-Groovy Updates
-++++++++++++++++++++++
+^^^^^^^^^^^^^^^^^^^^^^
 
 * The closure wrappers classes `GFunction`, `GSupplier`, `GConsumer` have been deprecated.
 ** In Groovy, a closure can be specified using `as Function` and thus, these wrappers are not needed.
 * The `GremlinExecutor.promoteBindings()` method which was previously deprecated has been removed.
 
+
+Gremlin Console
+^^^^^^^^^^^^^^^
+
+Aliasing Remotes
+++++++++++++++++
+
+The `:remote` command in Gremlin Console has a new `alias` configuration option.  This `alias` option allows
+specification of a set of key/value alias/binding pairs to apply to the remote.  In this way, it becomes possible
+to refer to a variable on the server as something other than what it is referred to for purpose of the submitted
+script.  For example once a `:remote` is created, this command:
+
+[source,text]
+:remote alias x g
+
+would allow "g" on the server to be referred to as "x".
+
+[source,text]
+:> x.E().label().groupCount()
+
 Upgrading for Providers
 ~~~~~~~~~~~~~~~~~~~~~~~
 

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2c7823e8/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptor.java
----------------------------------------------------------------------
diff --git a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptor.java b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptor.java
index 55f77cc..2be8b23 100644
--- a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptor.java
+++ b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptor.java
@@ -26,29 +26,41 @@ import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.groovy.plugin.RemoteAcceptor;
 import org.apache.tinkerpop.gremlin.groovy.plugin.RemoteException;
 import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
 import org.codehaus.groovy.tools.shell.Groovysh;
 
 import javax.security.sasl.SaslException;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.stream.Stream;
 
 /**
+ * A {@link RemoteAcceptor} that takes input from the console and sends it to Gremlin Server over the standard
+ * Java driver.
+ *
  * @author Stephen Mallette (http://stephen.genoprime.com)
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
 public class DriverRemoteAcceptor implements RemoteAcceptor {
     private Cluster currentCluster;
-    private Client currentClient;
+    private Client.ClusteredClient currentClient;
     private int timeout = 180000;
+    private Map<String,String> aliases = new HashMap<>();
 
+    private static final String TOKEN_RESET = "reset";
+    private static final String TOKEN_SHOW = "show";
+    private static final String TOKEN_MAX = "max";
     private static final String TOKEN_TIMEOUT = "timeout";
-    private static final List<String> POSSIBLE_TOKENS = Arrays.asList(TOKEN_TIMEOUT);
+    private static final String TOKEN_ALIAS = "alias";
+    private static final List<String> POSSIBLE_TOKENS = Arrays.asList(TOKEN_TIMEOUT, TOKEN_ALIAS);
 
     private final Groovysh shell;
 
@@ -84,13 +96,30 @@ public class DriverRemoteAcceptor implements RemoteAcceptor {
             final String errorMessage = "The timeout option expects a positive integer representing milliseconds or 'max' as an argument";
             if (arguments.size() != 1) throw new RemoteException(errorMessage);
             try {
-                final int to = arguments.get(0).equals("max") ? Integer.MAX_VALUE : Integer.parseInt(arguments.get(0));
+                final int to = arguments.get(0).equals(TOKEN_MAX) ? Integer.MAX_VALUE : Integer.parseInt(arguments.get(0));
                 if (to <= 0) throw new RemoteException(errorMessage);
                 this.timeout = to;
                 return "Set remote timeout to " + to + "ms";
             } catch (Exception ignored) {
                 throw new RemoteException(errorMessage);
             }
+        } else if (option.equals(TOKEN_ALIAS)) {
+            if (arguments.size() == 1 && arguments.get(0).equals(TOKEN_RESET)) {
+                aliases.clear();
+                return "Aliases cleared";
+            }
+
+            if (arguments.size() == 1 && arguments.get(0).equals(TOKEN_SHOW)) {
+                return aliases;
+            }
+
+            if (arguments.size() % 2 != 0)
+                throw new RemoteException("Arguments to alias must be 'reset' to clear any existing alias settings or key/value alias/binding pairs");
+
+            final Map<String,Object> aliasMap = ElementHelper.asMap(arguments.toArray());
+            aliases.clear();
+            aliasMap.forEach((k,v) -> aliases.put(k, v.toString()));
+            return aliases;
         }
 
         return this.toString();
@@ -133,7 +162,8 @@ public class DriverRemoteAcceptor implements RemoteAcceptor {
 
     private List<Result> send(final String gremlin) throws SaslException {
         try {
-            return this.currentClient.submit(gremlin).all().get(this.timeout, TimeUnit.MILLISECONDS);
+            return this.currentClient.submitAsync(gremlin, aliases, Collections.emptyMap()).get()
+                    .all().get(this.timeout, TimeUnit.MILLISECONDS);
         } catch(TimeoutException ignored) {
             throw new IllegalStateException("Request timed out while processing - increase the timeout with the :remote command");
         } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2c7823e8/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptorIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptorIntegrateTest.java b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptorIntegrateTest.java
index 267538f..b41432e 100644
--- a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptorIntegrateTest.java
+++ b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptorIntegrateTest.java
@@ -105,6 +105,14 @@ public class DriverRemoteAcceptorIntegrateTest extends AbstractGremlinServerInte
     }
 
     @Test
+    public void shouldConnectAndReturnVerticesWithAnAlias() throws Exception {
+        assertThat(acceptor.connect(Arrays.asList(TestHelper.generateTempFileFromResource(this.getClass(), "remote.yaml", ".tmp").getAbsolutePath())).toString(), startsWith("Connected - "));
+        acceptor.configure(Arrays.asList("alias", "x", "g"));
+        assertThat(IteratorUtils.list(((Iterator<String>) acceptor.submit(Arrays.asList("x.addVertex('name','stephen');x.addVertex('name','marko');x.traversal().V()")))), hasSize(2));
+        assertThat(((List<Result>) groovysh.getInterp().getContext().getProperty(DriverRemoteAcceptor.RESULT)).stream().map(Result::getString).collect(Collectors.toList()), hasSize(2));
+    }
+
+    @Test
     public void shouldConnectAndSubmitForNull() throws Exception {
         assertThat(acceptor.connect(Arrays.asList(TestHelper.generateTempFileFromResource(this.getClass(), "remote.yaml", ".tmp").getAbsolutePath())).toString(), startsWith("Connected - "));
         assertThat(IteratorUtils.list(((Iterator<String>) acceptor.submit(Arrays.asList("g.traversal().V().drop().iterate();null")))), contains("null"));

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2c7823e8/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptorTest.java
----------------------------------------------------------------------
diff --git a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptorTest.java b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptorTest.java
index cea92e5..d341098 100644
--- a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptorTest.java
+++ b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptorTest.java
@@ -27,8 +27,10 @@ import org.junit.Test;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Map;
 
 import static org.hamcrest.CoreMatchers.startsWith;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
 
 /**
@@ -54,6 +56,44 @@ public class DriverRemoteAcceptorTest {
     }
 
     @Test(expected = RemoteException.class)
+    public void shouldNotConfigureWithBadCommand() throws Exception {
+        acceptor.configure(Arrays.asList("test"));
+    }
+
+    @Test(expected = RemoteException.class)
+    public void shouldNotConfigureWithUnevenPairsOfAliases() throws Exception {
+        acceptor.configure(Arrays.asList("alias g social x"));
+    }
+
+    @Test
+    public void shouldResetAliases() throws Exception {
+        final Map<String,String> resetAliases = (Map<String,String>) acceptor.configure(Arrays.asList("alias", "g", "main.social"));
+        assertEquals(1, resetAliases.size());
+        assertEquals("main.social", resetAliases.get("g"));
+
+        assertEquals("Aliases cleared", acceptor.configure(Arrays.asList("alias", "reset")));
+
+        final Map<String,String> shownAliases = (Map<String,String>) acceptor.configure(Arrays.asList("alias", "show"));
+        assertEquals(0, shownAliases.size());
+    }
+
+    @Test
+    public void shouldAddOverwriteAndShowAliases() throws Exception {
+        final Map<String,String> aliases = (Map<String,String>) acceptor.configure(Arrays.asList("alias", "g", "social", "graph", "main"));
+        assertEquals(2, aliases.size());
+        assertEquals("social", aliases.get("g"));
+        assertEquals("main", aliases.get("graph"));
+
+        final Map<String,String> resetAliases = (Map<String,String>) acceptor.configure(Arrays.asList("alias", "g", "main.social"));
+        assertEquals(1, resetAliases.size());
+        assertEquals("main.social", resetAliases.get("g"));
+
+        final Map<String,String> shownAliases = (Map<String,String>) acceptor.configure(Arrays.asList("alias", "show"));
+        assertEquals(1, shownAliases.size());
+        assertEquals("main.social", shownAliases.get("g"));
+    }
+
+    @Test(expected = RemoteException.class)
     public void shouldNotConnectWithEmptyArgs() throws Exception {
         acceptor.connect(new ArrayList<>());
     }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2c7823e8/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
index b54d6dc..ae8c0bf 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
@@ -262,6 +262,30 @@ public abstract class Client {
         }
 
         /**
+         * The asynchronous version of {@link #submit(String, Map)}} where the returned future will complete when the
+         * write of the request completes.
+         *
+         * @param gremlin the gremlin script to execute
+         * @param parameters a map of parameters that will be bound to the script on execution
+         * @param aliases aliases the specified global Gremlin Server variable some other name that then be used in the
+         *                script where the key is the alias name and the value represents the global variable on the
+         *                server
+         */
+        public CompletableFuture<ResultSet> submitAsync(final String gremlin, final Map<String,String> aliases,
+                                                        final Map<String, Object> parameters) {
+            final RequestMessage.Builder request = RequestMessage.build(Tokens.OPS_EVAL)
+                    .add(Tokens.ARGS_GREMLIN, gremlin)
+                    .add(Tokens.ARGS_BATCH_SIZE, cluster.connectionPoolSettings().resultIterationBatchSize);
+
+            Optional.ofNullable(parameters).ifPresent(params -> request.addArg(Tokens.ARGS_BINDINGS, parameters));
+
+            if (aliases != null && !aliases.isEmpty())
+                request.addArg(Tokens.ARGS_REBINDINGS, aliases);
+
+            return submitAsync(buildMessage(request));
+        }
+
+        /**
          * {@inheritDoc}
          */
         @Override

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/2c7823e8/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
index 6c8a2f4..315ab0b 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
@@ -77,8 +77,8 @@ public final class Cluster {
      * error will not be raised at this point.  Connections get initialized in the {@link Client} when a request is
      * submitted or can be directly initialized via {@link Client#init()}.
      */
-    public Client connect() {
-        return new Client.ClusteredClient(this);
+    public <T extends Client> T connect() {
+        return (T) new Client.ClusteredClient(this);
     }
 
     /**
@@ -94,10 +94,10 @@ public final class Cluster {
      *
      * @param sessionId user supplied id for the session which should be unique (a UUID is ideal).
      */
-    public Client connect(final String sessionId) {
+    public <T extends Client> T connect(final String sessionId) {
         if (null == sessionId || sessionId.isEmpty())
             throw new IllegalArgumentException("sessionId cannot be null or empty");
-        return new Client.SessionedClient(this, sessionId);
+        return (T) new Client.SessionedClient(this, sessionId);
     }
 
     @Override