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 2016/01/22 20:18:34 UTC

incubator-tinkerpop git commit: Added alias support for sessions in Gremlin Server/Driver.

Repository: incubator-tinkerpop
Updated Branches:
  refs/heads/TINKERPOP-1096 [created] 02181880a


Added alias support for sessions in Gremlin Server/Driver.

Also added support for sessions in the console - TINKERPOP-1097


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

Branch: refs/heads/TINKERPOP-1096
Commit: 02181880a655a0e9baf7fd0c996c4dfc985ee7a1
Parents: 1d8642b
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Jan 22 14:17:01 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Jan 22 14:17:01 2016 -0500

----------------------------------------------------------------------
 .../groovy/plugin/DriverRemoteAcceptor.java     |  24 ++-
 .../DriverRemoteAcceptorIntegrateTest.java      |  18 ++
 .../apache/tinkerpop/gremlin/driver/Client.java | 214 ++++++++-----------
 .../server/op/AbstractEvalOpProcessor.java      |   1 -
 .../server/op/session/SessionOpProcessor.java   |  78 ++++++-
 .../server/GremlinDriverIntegrateTest.java      |  55 +++++
 6 files changed, 251 insertions(+), 139 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/02181880/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 2be8b23..593ca6e 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
@@ -38,6 +38,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.stream.Stream;
@@ -51,15 +52,17 @@ import java.util.stream.Stream;
  */
 public class DriverRemoteAcceptor implements RemoteAcceptor {
     private Cluster currentCluster;
-    private Client.ClusteredClient currentClient;
+    private Client currentClient;
     private int timeout = 180000;
     private Map<String,String> aliases = new HashMap<>();
+    private Optional<String> session = Optional.empty();
 
     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 String TOKEN_ALIAS = "alias";
+    private static final String TOKEN_SESSION = "session";
     private static final List<String> POSSIBLE_TOKENS = Arrays.asList(TOKEN_TIMEOUT, TOKEN_ALIAS);
 
     private final Groovysh shell;
@@ -70,13 +73,20 @@ public class DriverRemoteAcceptor implements RemoteAcceptor {
 
     @Override
     public Object connect(final List<String> args) throws RemoteException {
-        if (args.size() != 1) throw new RemoteException("Expects the location of a configuration file as an argument");
+        if (args.size() < 1) throw new RemoteException("Expects the location of a configuration file as an argument");
 
         try {
             this.currentCluster = Cluster.open(args.get(0));
-            this.currentClient = this.currentCluster.connect();
+            final boolean useSession = args.size() >= 2 && args.get(1).equals(TOKEN_SESSION);
+            if (useSession) {
+                final String sessionName = args.size() == 3 ? args.get(2) : UUID.randomUUID().toString();
+                session = Optional.of(sessionName);
+                this.currentClient = this.currentCluster.connect(sessionName);
+            } else {
+                this.currentClient = this.currentCluster.connect();
+            }
             this.currentClient.init();
-            return String.format("Connected - " + this.currentCluster);
+            return String.format("Connected - %s", this.currentCluster) + getSessionStringSegment();
         } catch (final FileNotFoundException ignored) {
             throw new RemoteException("The 'connect' option must be accompanied by a valid configuration file");
         } catch (final Exception ex) {
@@ -178,7 +188,7 @@ public class DriverRemoteAcceptor implements RemoteAcceptor {
 
     @Override
     public String toString() {
-        return "Gremlin Server - [" + this.currentCluster + "]";
+        return "Gremlin Server - [" + this.currentCluster + "]" + getSessionStringSegment();
     }
 
     private Optional<ResponseException> findResponseException(final Throwable ex) {
@@ -190,4 +200,8 @@ public class DriverRemoteAcceptor implements RemoteAcceptor {
 
         return findResponseException(ex.getCause());
     }
+
+    private String getSessionStringSegment() {
+        return session.isPresent() ? String.format("-[%s]", session.get()) : "";
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/02181880/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 b41432e..823d345 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
@@ -118,4 +118,22 @@ public class DriverRemoteAcceptorIntegrateTest extends AbstractGremlinServerInte
         assertThat(IteratorUtils.list(((Iterator<String>) acceptor.submit(Arrays.asList("g.traversal().V().drop().iterate();null")))), contains("null"));
         assertThat(((List<Result>) groovysh.getInterp().getContext().getProperty(DriverRemoteAcceptor.RESULT)).stream().map(Result::getObject).collect(Collectors.toList()), contains("null"));
     }
+
+    @Test
+    public void shouldConnectAndSubmitInSession() throws Exception {
+        assertThat(acceptor.connect(Arrays.asList(TestHelper.generateTempFileFromResource(this.getClass(), "remote.yaml", ".tmp").getAbsolutePath(), "session")).toString(), startsWith("Connected - "));
+        assertEquals("2", ((Iterator) acceptor.submit(Arrays.asList("x=1+1"))).next());
+        assertEquals("2", ((List<Result>) groovysh.getInterp().getContext().getProperty(DriverRemoteAcceptor.RESULT)).iterator().next().getString());
+        assertEquals("4", ((Iterator) acceptor.submit(Arrays.asList("x+2"))).next());
+        assertEquals("4", ((List<Result>) groovysh.getInterp().getContext().getProperty(DriverRemoteAcceptor.RESULT)).iterator().next().getString());
+    }
+
+    @Test
+    public void shouldConnectAndSubmitInNamedSession() throws Exception {
+        assertThat(acceptor.connect(Arrays.asList(TestHelper.generateTempFileFromResource(this.getClass(), "remote.yaml", ".tmp").getAbsolutePath(), "session", "AAA")).toString(), startsWith("Connected - "));
+        assertEquals("2", ((Iterator) acceptor.submit(Arrays.asList("x=1+1"))).next());
+        assertEquals("2", ((List<Result>) groovysh.getInterp().getContext().getProperty(DriverRemoteAcceptor.RESULT)).iterator().next().getString());
+        assertEquals("4", ((Iterator) acceptor.submit(Arrays.asList("x+2"))).next());
+        assertEquals("4", ((List<Result>) groovysh.getInterp().getContext().getProperty(DriverRemoteAcceptor.RESULT)).iterator().next().getString());
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/02181880/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 8c80b8a..fb110ae 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
@@ -91,8 +91,9 @@ public abstract class Client {
      * @deprecated As of release 3.1.0, replaced by {@link #alias(String)}
      */
     @Deprecated
-    public abstract Client rebind(final String graphOrTraversalSource);
-
+    public Client rebind(final String graphOrTraversalSource) {
+        return alias(graphOrTraversalSource);
+    }
 
     /**
      * Create a new {@code Client} that aliases the specified {@link Graph} or {@link TraversalSource} name on the
@@ -100,7 +101,28 @@ public abstract class Client {
      *
      * @param graphOrTraversalSource rebinds the specified global Gremlin Server variable to "g"
      */
-    public abstract Client alias(final String graphOrTraversalSource);
+    public Client alias(String graphOrTraversalSource) {
+        return new AliasClusteredClient(this, graphOrTraversalSource);
+    }
+
+    /**
+     * Creates a {@code Client} that supplies the specified set of aliases, thus allowing the user to re-name
+     * one or more globally defined {@link Graph} or {@link TraversalSource} server bindings for the context of
+     * the created {@code Client}.
+     */
+    @Deprecated
+    public Client rebind(final Map<String,String> rebindings) {
+        return alias(rebindings);
+    }
+
+    /**
+     * Creates a {@code Client} that supplies the specified set of aliases, thus allowing the user to re-name
+     * one or more globally defined {@link Graph} or {@link TraversalSource} server bindings for the context of
+     * the created {@code Client}.
+     */
+    public Client alias(final Map<String,String> aliases) {
+        return new AliasClusteredClient(this, aliases);
+    }
 
     /**
      * Initializes the client which typically means that a connection is established to the server.  Depending on the
@@ -175,6 +197,52 @@ 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 graphOrTraversalSource rebinds the specified global Gremlin Server variable to "g"
+     */
+    public CompletableFuture<ResultSet> submitAsync(final String gremlin, final String graphOrTraversalSource,
+                                                    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 (graphOrTraversalSource != null && !graphOrTraversalSource.isEmpty())
+            request.addArg(Tokens.ARGS_ALIASES, makeAliases(graphOrTraversalSource));
+
+        return submitAsync(buildMessage(request));
+    }
+
+    /**
+     * 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_ALIASES, aliases);
+
+        return submitAsync(buildMessage(request));
+    }
+
+    /**
      * A low-level method that allows the submission of a manually constructed {@link RequestMessage}.
      */
     public CompletableFuture<ResultSet> submitAsync(final RequestMessage msg) {
@@ -209,6 +277,12 @@ public abstract class Client {
         closeAsync().join();
     }
 
+    private Map<String,String> makeAliases(final String graphOrTraversalSource) {
+        final Map<String,String> aliases = new HashMap<>();
+        aliases.put("g", graphOrTraversalSource);
+        return aliases;
+    }
+
     /**
      * A {@code Client} implementation that does not operate in a session.  Requests are sent to multiple servers
      * given a {@link LoadBalancingStrategy}.  Transactions are automatically committed
@@ -251,88 +325,6 @@ 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 graphOrTraversalSource rebinds the specified global Gremlin Server variable to "g"
-         */
-        public CompletableFuture<ResultSet> submitAsync(final String gremlin, final String graphOrTraversalSource,
-                                                        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 (graphOrTraversalSource != null && !graphOrTraversalSource.isEmpty())
-                request.addArg(Tokens.ARGS_ALIASES, makeRebindings(graphOrTraversalSource));
-
-            return submitAsync(buildMessage(request));
-        }
-
-        /**
-         * 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_ALIASES, aliases);
-
-            return submitAsync(buildMessage(request));
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        @Deprecated
-        public Client rebind(final String graphOrTraversalSource) {
-            return alias(graphOrTraversalSource);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public Client alias(String graphOrTraversalSource) {
-            return new AliasClusteredClient(this, graphOrTraversalSource);
-        }
-
-        /**
-         * Creates a {@code Client} that supplies the specified set of aliases, thus allowing the user to re-name
-         * one or more globally defined {@link Graph} or {@link TraversalSource} server bindings for the context of
-         * the created {@code Client}.
-         */
-        @Deprecated
-        public Client rebind(final Map<String,String> rebindings) {
-            return alias(rebindings);
-        }
-
-        /**
-         * Creates a {@code Client} that supplies the specified set of aliases, thus allowing the user to re-name
-         * one or more globally defined {@link Graph} or {@link TraversalSource} server bindings for the context of
-         * the created {@code Client}.
-         */
-        public Client alias(final Map<String,String> aliases) {
-            return new AliasClusteredClient(this, aliases);
-        }
-
-        /**
          * Uses a {@link LoadBalancingStrategy} to choose the best {@link Host} and then selects the best connection
          * from that host's connection pool.
          */
@@ -374,12 +366,6 @@ public abstract class Client {
             hostConnectionPools.values().stream().map(ConnectionPool::closeAsync).collect(Collectors.toList()).toArray(poolCloseFutures);
             return CompletableFuture.allOf(poolCloseFutures);
         }
-
-        private Map<String,String> makeRebindings(final String graphOrTraversalSource) {
-            final Map<String,String> rebindings = new HashMap<>();
-            rebindings.put("g", graphOrTraversalSource);
-            return rebindings;
-        }
     }
 
     /**
@@ -387,11 +373,11 @@ public abstract class Client {
      * specified {@link Graph} or {@link TraversalSource} instances on the server-side.
      */
     public final static class AliasClusteredClient extends ReboundClusteredClient {
-        public AliasClusteredClient(ClusteredClient clusteredClient, String graphOrTraversalSource) {
+        public AliasClusteredClient(Client clusteredClient, String graphOrTraversalSource) {
             super(clusteredClient, graphOrTraversalSource);
         }
 
-        public AliasClusteredClient(ClusteredClient clusteredClient, Map<String, String> rebindings) {
+        public AliasClusteredClient(Client clusteredClient, Map<String, String> rebindings) {
             super(clusteredClient, rebindings);
         }
     }
@@ -404,19 +390,19 @@ public abstract class Client {
      */
     @Deprecated
     public static class ReboundClusteredClient extends Client {
-        private final ClusteredClient clusteredClient;
+        private final Client client;
         private final Map<String,String> aliases = new HashMap<>();
         final CompletableFuture<Void> close = new CompletableFuture<>();
 
-        ReboundClusteredClient(final ClusteredClient clusteredClient, final String graphOrTraversalSource) {
-            super(clusteredClient.cluster);
-            this.clusteredClient = clusteredClient;
+        ReboundClusteredClient(final Client client, final String graphOrTraversalSource) {
+            super(client.cluster);
+            this.client = client;
             aliases.put("g", graphOrTraversalSource);
         }
 
-        ReboundClusteredClient(final ClusteredClient clusteredClient, final Map<String,String> rebindings) {
-            super(clusteredClient.cluster);
-            this.clusteredClient = clusteredClient;
+        ReboundClusteredClient(final Client client, final Map<String,String> rebindings) {
+            super(client.cluster);
+            this.client = client;
             this.aliases.putAll(rebindings);
         }
 
@@ -425,7 +411,7 @@ public abstract class Client {
             if (close.isDone()) throw new IllegalStateException("Client is closed");
 
             // the underlying client may not have been init'd
-            clusteredClient.init();
+            client.init();
 
             return this;
         }
@@ -451,7 +437,7 @@ public abstract class Client {
         @Override
         protected Connection chooseConnection(final RequestMessage msg) throws TimeoutException, ConnectionException {
             if (close.isDone()) throw new IllegalStateException("Client is closed");
-            return clusteredClient.chooseConnection(msg);
+            return client.chooseConnection(msg);
         }
 
         /**
@@ -479,7 +465,7 @@ public abstract class Client {
         @Override
         public Client alias(String graphOrTraversalSource) {
             if (close.isDone()) throw new IllegalStateException("Client is closed");
-            return new AliasClusteredClient(clusteredClient, graphOrTraversalSource);
+            return new AliasClusteredClient(client, graphOrTraversalSource);
         }
     }
 
@@ -503,28 +489,6 @@ public abstract class Client {
         }
 
         /**
-         * The sessioned client does not support this feature.
-         *
-         * @throws UnsupportedOperationException
-         * @deprecated As of release 3.1.0, replaced by {@link #alias(String)}
-         */
-        @Deprecated
-        @Override
-        public Client rebind(final String graphOrTraversalSourceName){
-            throw new UnsupportedOperationException("Sessioned client does not support aliasing");
-        }
-
-        /**
-         * The sessioned client does not support this feature.
-         *
-         * @throws UnsupportedOperationException
-         */
-        @Override
-        public Client alias(String graphOrTraversalSource) {
-            throw new UnsupportedOperationException("Sessioned client does not support aliasing");
-        }
-
-        /**
          * Adds the {@link Tokens#ARGS_SESSION} value to every {@link RequestMessage}.
          */
         @Override

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/02181880/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
index aab9950..dceb7fb 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/AbstractEvalOpProcessor.java
@@ -57,7 +57,6 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.function.Supplier;
 import java.util.regex.Pattern;
-import java.util.stream.Collectors;
 
 import static com.codahale.metrics.MetricRegistry.name;
 

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/02181880/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/SessionOpProcessor.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/SessionOpProcessor.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/SessionOpProcessor.java
index d5e5e7c..916d82b 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/SessionOpProcessor.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/session/SessionOpProcessor.java
@@ -22,6 +22,7 @@ import org.apache.tinkerpop.gremlin.driver.Tokens;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 import org.apache.tinkerpop.gremlin.server.Context;
 import org.apache.tinkerpop.gremlin.server.GremlinServer;
 import org.apache.tinkerpop.gremlin.server.Settings;
@@ -29,6 +30,7 @@ import org.apache.tinkerpop.gremlin.server.handler.StateKey;
 import org.apache.tinkerpop.gremlin.server.op.AbstractEvalOpProcessor;
 import org.apache.tinkerpop.gremlin.server.op.OpProcessorException;
 import org.apache.tinkerpop.gremlin.server.util.MetricManager;
+import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.util.function.ThrowingConsumer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,6 +40,8 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Supplier;
 
 import static com.codahale.metrics.MetricRegistry.name;
 
@@ -148,14 +152,7 @@ public class SessionOpProcessor extends AbstractEvalOpProcessor {
         // is important given the threadlocal nature of Graph implementation transactions.
         context.getChannelHandlerContext().channel().attr(StateKey.SESSION).set(session);
 
-        evalOpInternal(context, session::getGremlinExecutor, () -> {
-            final Bindings bindings = session.getBindings();
-
-            // parameter bindings override session bindings if present
-            Optional.ofNullable((Map<String, Object>) msg.getArgs().get(Tokens.ARGS_BINDINGS)).ifPresent(bindings::putAll);
-
-            return bindings;
-        });
+        evalOpInternal(context, session::getGremlinExecutor, getBindingMaker(session).apply(context));
     }
 
     /**
@@ -172,4 +169,69 @@ public class SessionOpProcessor extends AbstractEvalOpProcessor {
         session.touch();
         return session;
     }
+
+    /**
+     * A useful method for those extending this class, where the means for binding construction can be supplied
+     * to this class.  This function is used in {@link #evalOp(Context)} to create the final argument to
+     * {@link AbstractEvalOpProcessor#evalOpInternal(Context, Supplier, org.apache.tinkerpop.gremlin.server.op.AbstractEvalOpProcessor.BindingSupplier)}.
+     * In this way an extending class can use the default {@link org.apache.tinkerpop.gremlin.server.op.AbstractEvalOpProcessor.BindingSupplier}
+     * which carries a lot of re-usable functionality or provide a new one to override the existing approach.
+     */
+    protected Function<Context, BindingSupplier> getBindingMaker(final Session session) {
+        return context -> () -> {
+            final RequestMessage msg = context.getRequestMessage();
+            final Bindings bindings = session.getBindings();
+
+            // don't allow both rebindings and aliases parameters as they are the same thing. aliases were introduced
+            // as of 3.1.0 as a replacement for rebindings. this check can be removed when rebindings are completely
+            // removed from the protocol
+            final boolean hasRebindings = msg.getArgs().containsKey(Tokens.ARGS_REBINDINGS);
+            final boolean hasAliases = msg.getArgs().containsKey(Tokens.ARGS_ALIASES);
+            if (hasRebindings && hasAliases) {
+                final String error = "Prefer use of the 'aliases' parameter over 'rebindings' and do not use both";
+                throw new OpProcessorException(error, ResponseMessage.build(msg)
+                        .code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(error).create());
+            }
+
+            final String rebindingOrAliasParameter = hasRebindings ? Tokens.ARGS_REBINDINGS : Tokens.ARGS_ALIASES;
+
+            // alias any global bindings to a different variable
+            if (msg.getArgs().containsKey(rebindingOrAliasParameter)) {
+                final Map<String, String> aliases = (Map<String, String>) msg.getArgs().get(rebindingOrAliasParameter);
+                for (Map.Entry<String,String> aliasKv : aliases.entrySet()) {
+                    boolean found = false;
+
+                    // first check if the alias refers to a Graph instance
+                    final Map<String, Graph> graphs = context.getGraphManager().getGraphs();
+                    if (graphs.containsKey(aliasKv.getValue())) {
+                        bindings.put(aliasKv.getKey(), graphs.get(aliasKv.getValue()));
+                        found = true;
+                    }
+
+                    // if the alias wasn't found as a Graph then perhaps it is a TraversalSource - it needs to be
+                    // something
+                    if (!found) {
+                        final Map<String, TraversalSource> traversalSources = context.getGraphManager().getTraversalSources();
+                        if (traversalSources.containsKey(aliasKv.getValue())) {
+                            bindings.put(aliasKv.getKey(), traversalSources.get(aliasKv.getValue()));
+                            found = true;
+                        }
+                    }
+
+                    // this validation is important to calls to GraphManager.commit() and rollback() as they both
+                    // expect that the aliases supplied are valid
+                    if (!found) {
+                        final String error = String.format("Could not alias [%s] to [%s] as [%s] not in the Graph or TraversalSource global bindings",
+                                aliasKv.getKey(), aliasKv.getValue(), aliasKv.getValue());
+                        throw new OpProcessorException(error, ResponseMessage.build(msg)
+                                .code(ResponseStatusCode.REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS).statusMessage(error).create());
+                    }
+                }
+            }
+
+            // add any bindings to override any other supplied
+            Optional.ofNullable((Map<String, Object>) msg.getArgs().get(Tokens.ARGS_BINDINGS)).ifPresent(bindings::putAll);
+            return bindings;
+        };
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/02181880/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
index a0d06f1..bce6bfa 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
@@ -86,6 +86,7 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration
 
         switch (nameOfTest) {
             case "shouldAliasTraversalSourceVariables":
+            case "shouldAliasTraversalSourceVariablesInSession":
                 try {
                     final String p = TestHelper.generateTempFileFromResource(
                             GremlinDriverIntegrateTest.class, "generate-shouldRebindTraversalSourceVariables.groovy", "").getAbsolutePath();
@@ -1006,4 +1007,58 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration
 
         cluster.close();
     }
+
+    @Test
+    public void shouldAliasGraphVariablesInSession() throws Exception {
+        final Cluster cluster = Cluster.build().create();
+        final Client client = cluster.connect(name.getMethodName());
+
+        try {
+            client.submit("g.addVertex('name','stephen');").all().get().get(0).getVertex();
+            fail("Should have tossed an exception because \"g\" does not have the addVertex method under default config");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root, instanceOf(ResponseException.class));
+            final ResponseException re = (ResponseException) root;
+            assertEquals(ResponseStatusCode.SERVER_ERROR_SCRIPT_EVALUATION, re.getResponseStatusCode());
+        }
+
+        // keep the testing here until "rebind" is completely removed
+        final Client reboundLegacy = cluster.connect().rebind("graph");
+        final Vertex vLegacy = reboundLegacy.submit("g.addVertex('name','stephen')").all().get().get(0).getVertex();
+        assertEquals("stephen", vLegacy.value("name"));
+
+        final Client rebound = cluster.connect().alias("graph");
+        final Vertex v = rebound.submit("g.addVertex('name','jason')").all().get().get(0).getVertex();
+        assertEquals("jason", v.value("name"));
+
+        cluster.close();
+    }
+
+    @Test
+    public void shouldAliasTraversalSourceVariablesInSession() throws Exception {
+        final Cluster cluster = Cluster.build().create();
+        final Client client = cluster.connect(name.getMethodName());
+
+        try {
+            client.submit("g.addV('name','stephen')").all().get().get(0).getVertex();
+            fail("Should have tossed an exception because \"g\" is readonly in this context");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root, instanceOf(ResponseException.class));
+            final ResponseException re = (ResponseException) root;
+            assertEquals(ResponseStatusCode.SERVER_ERROR, re.getResponseStatusCode());
+        }
+
+        // keep the testing here until "rebind" is completely removed
+        final Client clientLegacy = client.rebind("g1");
+        final Vertex vLegacy = clientLegacy.submit("g.addV('name','stephen')").all().get().get(0).getVertex();
+        assertEquals("stephen", vLegacy.value("name"));
+
+        final Client clientAliased = client.alias("g1");
+        final Vertex v = clientAliased.submit("g.addV('name','jason')").all().get().get(0).getVertex();
+        assertEquals("jason", v.value("name"));
+
+        cluster.close();
+    }
 }